Merge "x86_64: Fix wide argument increment"
diff --git a/Android.mk b/Android.mk
index 593ee04..18e1c64 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,13 +17,13 @@
 LOCAL_PATH := $(call my-dir)
 
 art_path := $(LOCAL_PATH)
-art_build_path := $(art_path)/build
-include $(art_build_path)/Android.common.mk
 
 ########################################################################
-# clean-oat targets
+# clean-oat rules
 #
 
+include $(art_path)/build/Android.common_path.mk
+
 # following the example of build's dont_bother for clean targets
 ifneq (,$(filter clean-oat,$(MAKECMDGOALS)))
 art_dont_bother := true
@@ -45,6 +45,11 @@
 	rm -f $(HOST_CORE_IMG_OUT)
 	rm -f $(HOST_CORE_OAT_OUT)
 	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
@@ -67,9 +72,9 @@
 .PHONY: clean-oat-target
 clean-oat-target:
 	adb remount
-	adb shell rm -rf $(ART_NATIVETEST_DIR)
-	adb shell rm -rf $(ART_TEST_DIR)
-	adb shell rm -rf $(ART_DALVIK_CACHE_DIR)/*
+	adb shell rm -rf $(ART_TARGET_NATIVETEST_DIR)
+	adb shell rm -rf $(ART_TARGET_TEST_DIR)
+	adb shell rm -rf $(ART_TARGET_DALVIK_CACHE_DIR)/*/*
 	adb shell rm -rf $(DEXPREOPT_BOOT_JAR_DIR)/$(DEX2OAT_TARGET_ARCH)
 	adb shell rm -rf system/app/$(DEX2OAT_TARGET_ARCH)
 ifdef TARGET_2ND_ARCH
@@ -81,7 +86,13 @@
 ifneq ($(art_dont_bother),true)
 
 ########################################################################
-# product targets
+# cpplint rules to style check art source files
+
+include $(art_path)/build/Android.cpplint.mk
+
+########################################################################
+# product rules
+
 include $(art_path)/runtime/Android.mk
 include $(art_path)/compiler/Android.mk
 include $(art_path)/dex2oat/Android.mk
@@ -89,251 +100,203 @@
 include $(art_path)/oatdump/Android.mk
 include $(art_path)/dalvikvm/Android.mk
 include $(art_path)/tools/Android.mk
-include $(art_build_path)/Android.oat.mk
+include $(art_path)/build/Android.oat.mk
 include $(art_path)/sigchainlib/Android.mk
 
 
-
-
 # ART_HOST_DEPENDENCIES depends on Android.executable.mk above for ART_HOST_EXECUTABLES
-ART_HOST_DEPENDENCIES := $(ART_HOST_EXECUTABLES) $(HOST_OUT_JAVA_LIBRARIES)/core-libart-hostdex.jar
-ART_HOST_DEPENDENCIES += $(HOST_LIBRARY_PATH)/libjavacore$(ART_HOST_SHLIB_EXTENSION)
-ART_TARGET_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_JAVA_LIBRARIES)/core-libart.jar $(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
+ART_HOST_DEPENDENCIES := $(ART_HOST_EXECUTABLES) $(HOST_OUT_JAVA_LIBRARIES)/core-libart-hostdex.jar \
+	$(HOST_LIBRARY_PATH)/libjavacore$(ART_HOST_SHLIB_EXTENSION)
+ART_TARGET_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_JAVA_LIBRARIES)/core-libart.jar \
+	$(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
 ifdef TARGET_2ND_ARCH
 ART_TARGET_DEPENDENCIES += $(2ND_TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
 endif
 
 ########################################################################
-# test targets
+# test rules
 
-include $(art_path)/test/Android.mk
-include $(art_build_path)/Android.gtest.mk
+# All the dependencies that must be built ahead of sync-ing them onto the target device.
+TEST_ART_TARGET_SYNC_DEPS :=
 
-$(eval $(call combine-art-multi-target-var,ART_TARGET_GTEST_TARGETS))
-$(eval $(call combine-art-multi-target-var,ART_TARGET_GTEST_EXECUTABLES))
+include $(art_path)/build/Android.common_test.mk
+include $(art_path)/build/Android.gtest.mk
+include $(art_path)/test/Android.oat.mk
+include $(art_path)/test/Android.run-test.mk
 
-# The ART_*_TEST_DEPENDENCIES definitions:
-# - depend on Android.oattest.mk above for ART_TEST_*_DEX_FILES
-# - depend on Android.gtest.mk above for ART_*_GTEST_EXECUTABLES
-ART_HOST_TEST_DEPENDENCIES   := $(ART_HOST_DEPENDENCIES)   $(ART_HOST_GTEST_EXECUTABLES)   $(ART_TEST_HOST_DEX_FILES)   $(HOST_CORE_IMG_OUT)
+# Sync test files to the target, depends upon all things that must be pushed to the target.
+.PHONY: test-art-target-sync
+test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS)
+	adb remount
+	adb sync
+	adb shell mkdir -p $(ART_TARGET_TEST_DIR)
 
-define declare-art-target-test-dependencies-var
-ART_TARGET_TEST_DEPENDENCIES$(1) := $(ART_TARGET_DEPENDENCIES) $(ART_TARGET_GTEST_EXECUTABLES$(1)) $(ART_TEST_TARGET_DEX_FILES$(1)) $(TARGET_CORE_IMG_OUT$(1))
-endef
-$(eval $(call call-art-multi-target-var,declare-art-target-test-dependencies-var,ART_TARGET_TEST_DEPENDENCIES))
-
-include $(art_build_path)/Android.libarttest.mk
+# Undefine variable now its served its purpose.
+TEST_ART_TARGET_SYNC_DEPS :=
 
 # "mm test-art" to build and run all tests on host and device
 .PHONY: test-art
 test-art: test-art-host test-art-target
-	@echo test-art PASSED
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-gtest
 test-art-gtest: test-art-host-gtest test-art-target-gtest
-	@echo test-art-gtest PASSED
-
-.PHONY: test-art-oat
-test-art-oat: test-art-host-oat test-art-target-oat
-	@echo test-art-oat PASSED
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-run-test
 test-art-run-test: test-art-host-run-test test-art-target-run-test
-	@echo test-art-run-test PASSED
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 ########################################################################
-# host test targets
+# host test rules
 
-.PHONY: test-art-host-vixl
 VIXL_TEST_DEPENDENCY :=
 # We can only run the vixl tests on 64-bit hosts (vixl testing issue) when its a
 # top-level build (to declare the vixl test rule).
-ifneq ($(HOST_IS_64_BIT),)
+ifneq ($(HOST_PREFER_32_BIT),true)
 ifeq ($(ONE_SHOT_MAKEFILE),)
 VIXL_TEST_DEPENDENCY := run-vixl-tests
 endif
 endif
 
+.PHONY: test-art-host-vixl
 test-art-host-vixl: $(VIXL_TEST_DEPENDENCY)
 
-# "mm test-art-host" to build and run all host tests
+# "mm test-art-host" to build and run all host tests.
 .PHONY: test-art-host
 test-art-host: test-art-host-gtest test-art-host-oat test-art-host-run-test test-art-host-vixl
-	@echo test-art-host PASSED
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
+# All host tests that run solely with the default compiler.
+.PHONY: test-art-host-default
+test-art-host-default: test-art-host-oat-default test-art-host-run-test-default
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+# All host tests that run solely with the optimizing compiler.
+.PHONY: test-art-host-optimizing
+test-art-host-optimizing: test-art-host-oat-optimizing test-art-host-run-test-optimizing
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+# All host tests that run solely on the interpreter.
 .PHONY: test-art-host-interpreter
 test-art-host-interpreter: test-art-host-oat-interpreter test-art-host-run-test-interpreter
-	@echo test-art-host-interpreter PASSED
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
-.PHONY: test-art-host-dependencies
-test-art-host-dependencies: $(ART_HOST_TEST_DEPENDENCIES) $(HOST_LIBRARY_PATH)/libarttest$(ART_HOST_SHLIB_EXTENSION) $(HOST_CORE_DEX_LOCATIONS)
+# Primary host architecture variants:
+.PHONY: test-art-host$(ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host$(ART_PHONY_TEST_HOST_SUFFIX): test-art-host-gtest$(ART_PHONY_TEST_HOST_SUFFIX) \
+    test-art-host-oat$(ART_PHONY_TEST_HOST_SUFFIX) test-art-host-run-test$(ART_PHONY_TEST_HOST_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
-.PHONY: test-art-host-gtest
-test-art-host-gtest: $(ART_HOST_GTEST_TARGETS)
-	@echo test-art-host-gtest PASSED
+.PHONY: test-art-host-default$(ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-default$(ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-default$(ART_PHONY_TEST_HOST_SUFFIX) \
+    test-art-host-run-test-default$(ART_PHONY_TEST_HOST_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
-# "mm valgrind-test-art-host-gtest" to build and run the host gtests under valgrind.
-.PHONY: valgrind-test-art-host-gtest
-valgrind-test-art-host-gtest: $(ART_HOST_VALGRIND_GTEST_TARGETS)
-	@echo valgrind-test-art-host-gtest PASSED
+.PHONY: test-art-host-optimizing$(ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-optimizing$(ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-optimizing$(ART_PHONY_TEST_HOST_SUFFIX) \
+    test-art-host-run-test-optimizing$(ART_PHONY_TEST_HOST_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
-.PHONY: test-art-host-oat-default
-test-art-host-oat-default: $(ART_TEST_HOST_OAT_DEFAULT_TARGETS)
-	@echo test-art-host-oat-default PASSED
+.PHONY: test-art-host-interpreter$(ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-interpreter$(ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-interpreter$(ART_PHONY_TEST_HOST_SUFFIX) \
+    test-art-host-run-test-interpreter$(ART_PHONY_TEST_HOST_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
-.PHONY: test-art-host-oat-interpreter
-test-art-host-oat-interpreter: $(ART_TEST_HOST_OAT_INTERPRETER_TARGETS)
-	@echo test-art-host-oat-interpreter PASSED
+# Secondary host architecture variants:
+ifneq ($(HOST_PREFER_32_BIT),true)
+.PHONY: test-art-host$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host$(2ND_ART_PHONY_TEST_HOST_SUFFIX): test-art-host-gtest$(2ND_ART_PHONY_TEST_HOST_SUFFIX) \
+    test-art-host-oat$(2ND_ART_PHONY_TEST_HOST_SUFFIX) test-art-host-run-test$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
-.PHONY: test-art-host-oat
-test-art-host-oat: test-art-host-oat-default test-art-host-oat-interpreter
-	@echo test-art-host-oat PASSED
+.PHONY: test-art-host-default$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-default$(2ND_ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-default$(2ND_ART_PHONY_TEST_HOST_SUFFIX) \
+    test-art-host-run-test-default$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
-FAILING_OPTIMIZING_MESSAGE := failed with the optimizing compiler. If the test passes \
-  with Quick and interpreter, it is probably just a bug in the optimizing compiler. Please \
-  add the test name to the FAILING_OPTIMIZING_TESTS Makefile variable in art/Android.mk, \
-  and file a bug.
+.PHONY: test-art-host-optimizing$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-optimizing$(2ND_ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-optimizing$(2ND_ART_PHONY_TEST_HOST_SUFFIX) \
+    test-art-host-run-test-optimizing$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
-# Placeholder for failing tests on the optimizing compiler.
-
-define declare-test-art-host-run-test
-.PHONY: test-art-host-run-test-default-$(1)
-test-art-host-run-test-default-$(1): test-art-host-dependencies $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
-	DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test $(addprefix --runtime-option ,$(DALVIKVM_FLAGS)) --host $(1)
-	@echo test-art-host-run-test-default-$(1) PASSED
-
-TEST_ART_HOST_RUN_TEST_DEFAULT_TARGETS += test-art-host-run-test-default-$(1)
-
-.PHONY: test-art-host-run-test-optimizing-$(1)
-test-art-host-run-test-optimizing-$(1): test-art-host-dependencies $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
-	DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test -Xcompiler-option --compiler-backend=Optimizing $(addprefix --runtime-option ,$(DALVIKVM_FLAGS)) --host $(1) \
-	|| (echo -e "\x1b[31;01mTest $(1) $(FAILING_OPTIMIZING_MESSAGE)\x1b[0m" && exit 1)
-	@echo test-art-host-run-test-optimizing-$(1) PASSED
-
-TEST_ART_HOST_RUN_TEST_OPTIMIZING_TARGETS += test-art-host-run-test-optimizing-$(1)
-
-.PHONY: test-art-host-run-test-interpreter-$(1)
-test-art-host-run-test-interpreter-$(1): test-art-host-dependencies $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
-	DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test $(addprefix --runtime-option ,$(DALVIKVM_FLAGS)) --host --interpreter $(1)
-	@echo test-art-host-run-test-interpreter-$(1) PASSED
-
-TEST_ART_HOST_RUN_TEST_INTERPRETER_TARGETS += test-art-host-run-test-interpreter-$(1)
-
-.PHONY: test-art-host-run-test-$(1)
-test-art-host-run-test-$(1): test-art-host-run-test-default-$(1) test-art-host-run-test-interpreter-$(1) test-art-host-run-test-optimizing-$(1)
-
-endef
-
-$(foreach test, $(TEST_ART_RUN_TESTS), $(eval $(call declare-test-art-host-run-test,$(test))))
-
-.PHONY: test-art-host-run-test-default
-test-art-host-run-test-default: $(TEST_ART_HOST_RUN_TEST_DEFAULT_TARGETS)
-	@echo test-art-host-run-test-default PASSED
-
-FAILING_OPTIMIZING_TESTS :=
-$(foreach test, $(FAILING_OPTIMIZING_TESTS), \
-	$(eval TEST_ART_HOST_RUN_TEST_OPTIMIZING_TARGETS := $(filter-out test-art-host-run-test-optimizing-$(test), $(TEST_ART_HOST_RUN_TEST_OPTIMIZING_TARGETS))))
-
-.PHONY: test-art-host-run-test-optimizing
-test-art-host-run-test-optimizing: $(TEST_ART_HOST_RUN_TEST_OPTIMIZING_TARGETS)
-	$(foreach test, $(FAILING_OPTIMIZING_TESTS), $(info Optimizing compiler has skipped $(test)))
-	@echo test-art-host-run-test-optimizing PASSED
-
-.PHONY: test-art-host-run-test-interpreter
-test-art-host-run-test-interpreter: $(TEST_ART_HOST_RUN_TEST_INTERPRETER_TARGETS)
-	@echo test-art-host-run-test-interpreter PASSED
-
-.PHONY: test-art-host-run-test
-test-art-host-run-test: test-art-host-run-test-default test-art-host-run-test-interpreter test-art-host-run-test-optimizing
-	@echo test-art-host-run-test PASSED
-
-########################################################################
-# target test targets
-
-# "mm test-art-target" to build and run all target tests
-define declare-test-art-target
-.PHONY: test-art-target$(1)
-test-art-target$(1): test-art-target-gtest$(1) test-art-target-oat$(1) test-art-target-run-test$(1)
-	@echo test-art-target$(1) PASSED
-endef
-$(eval $(call call-art-multi-target-rule,declare-test-art-target,test-art-target))
-
-define declare-test-art-target-dependencies
-.PHONY: test-art-target-dependencies$(1)
-test-art-target-dependencies$(1): $(ART_TARGET_TEST_DEPENDENCIES$(1)) $(ART_TARGET_LIBARTTEST_$(1))
-endef
-$(eval $(call call-art-multi-target-rule,declare-test-art-target-dependencies,test-art-target-dependencies))
-
-
-.PHONY: test-art-target-sync
-test-art-target-sync: test-art-target-dependencies$(ART_PHONY_TEST_TARGET_SUFFIX) test-art-target-dependencies$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
-	adb remount
-	adb sync
-	adb shell mkdir -p $(ART_TEST_DIR)
-
-
-define declare-test-art-target-gtest
-.PHONY: test-art-target-gtest$(1)
-test-art-target-gtest$(1): $(ART_TARGET_GTEST_TARGETS$(1))
-	@echo test-art-target-gtest$(1) PASSED
-endef
-$(eval $(call call-art-multi-target-rule,declare-test-art-target-gtest,test-art-target-gtest))
-
-
-define declare-test-art-target-oat
-.PHONY: test-art-target-oat$(1)
-test-art-target-oat$(1): $(ART_TEST_TARGET_OAT_TARGETS$(1))
-	@echo test-art-target-oat$(1) PASSED
-endef
-$(eval $(call call-art-multi-target-rule,declare-test-art-target-oat,test-art-target-oat))
-
-
-define declare-test-art-target-run-test-impl
-$(2)run_test_$(1) :=
-ifeq ($($(2)ART_PHONY_TEST_TARGET_SUFFIX),64)
- $(2)run_test_$(1) := --64
+.PHONY: test-art-host-interpreter$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-interpreter$(2ND_ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-interpreter$(2ND_ART_PHONY_TEST_HOST_SUFFIX) \
+    test-art-host-run-test-interpreter$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 endif
-.PHONY: test-art-target-run-test-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
-test-art-target-run-test-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-sync $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
-	DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test $(addprefix --runtime-option ,$(DALVIKVM_FLAGS)) $$($(2)run_test_$(1)) $(1)
-	@echo test-art-target-run-test-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX) PASSED
-endef
-
-define declare-test-art-target-run-test
-
-  ifdef TARGET_2ND_ARCH
-    $(call declare-test-art-target-run-test-impl,$(1),2ND_)
-    
-    TEST_ART_TARGET_RUN_TEST_TARGETS$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) += test-art-target-run-test-$(1)$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
-
-    ifneq ($(ART_PHONY_TEST_TARGET_SUFFIX),)
-      # Link primary to non-suffix
-test-art-target-run-test-$(1): test-art-target-run-test-$(1)$(ART_PHONY_TEST_TARGET_SUFFIX)
-    endif
-  endif
-  $(call declare-test-art-target-run-test-impl,$(1),)
-
-  TEST_ART_TARGET_RUN_TEST_TARGETS$(ART_PHONY_TEST_TARGET_SUFFIX) += test-art-target-run-test-$(1)$(ART_PHONY_TEST_TARGET_SUFFIX)
-
-test-art-run-test-$(1): test-art-host-run-test-$(1) test-art-target-run-test-$(1)
-
-endef
-
-$(foreach test, $(TEST_ART_RUN_TESTS), $(eval $(call declare-test-art-target-run-test,$(test))))
-
-
-define declare-test-art-target-run-test
-.PHONY: test-art-target-run-test$(1)
-test-art-target-run-test$(1): $(TEST_ART_TARGET_RUN_TEST_TARGETS$(1))
-	@echo test-art-target-run-test$(1) PASSED
-endef
-$(eval $(call call-art-multi-target-rule,declare-test-art-target-run-test,test-art-target-run-test))
-
 
 ########################################################################
-# oat-target and oat-target-sync targets
+# target test rules
 
-OAT_TARGET_TARGETS :=
+# "mm test-art-target" to build and run all target tests.
+.PHONY: test-art-target
+test-art-target: test-art-target-gtest test-art-target-oat test-art-target-run-test
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+# All target tests that run solely with the default compiler.
+.PHONY: test-art-target-default
+test-art-target-default: test-art-target-oat-default test-art-target-run-test-default
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+# All target tests that run solely with the optimizing compiler.
+.PHONY: test-art-target-optimizing
+test-art-target-optimizing: test-art-target-oat-optimizing test-art-target-run-test-optimizing
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+# All target tests that run solely on the interpreter.
+.PHONY: test-art-target-interpreter
+test-art-target-interpreter: test-art-target-oat-interpreter test-art-target-run-test-interpreter
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+# Primary target architecture variants:
+.PHONY: test-art-target$(ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target$(ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-gtest$(ART_PHONY_TEST_TARGET_SUFFIX) \
+    test-art-target-oat$(ART_PHONY_TEST_TARGET_SUFFIX) test-art-target-run-test$(ART_PHONY_TEST_TARGET_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+.PHONY: test-art-target-default$(ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-default$(ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-default$(ART_PHONY_TEST_TARGET_SUFFIX) \
+    test-art-target-run-test-default$(ART_PHONY_TEST_TARGET_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+.PHONY: test-art-target-optimizing$(ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-optimizing$(ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-optimizing$(ART_PHONY_TEST_TARGET_SUFFIX) \
+    test-art-target-run-test-optimizing$(ART_PHONY_TEST_TARGET_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+.PHONY: test-art-target-interpreter$(ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-interpreter$(ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-interpreter$(ART_PHONY_TEST_TARGET_SUFFIX) \
+    test-art-target-run-test-interpreter$(ART_PHONY_TEST_TARGET_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+# Secondary target architecture variants:
+ifdef TARGET_2ND_ARCH
+.PHONY: test-art-target$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target$(2ND_ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-gtest$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) \
+    test-art-target-oat$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) test-art-target-run-test$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+.PHONY: test-art-target-default$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-default$(2ND_ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-default$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) \
+    test-art-target-run-test-default$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+.PHONY: test-art-target-optimizing$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-optimizing$(2ND_ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-optimizing$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) \
+    test-art-target-run-test-optimizing$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+
+.PHONY: test-art-target-interpreter$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-interpreter$(2ND_ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-interpreter$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) \
+    test-art-target-run-test-interpreter$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
+endif
+
+########################################################################
+# oat-target and oat-target-sync rules
+
+OAT_TARGET_RULES :=
 
 # $(1): input jar or apk target location
 define declare-oat-target-target
@@ -365,7 +328,7 @@
 
 endif
 
-OAT_TARGET_TARGETS += oat-target-$(1)
+OAT_TARGET_RULES += oat-target-$(1)
 endef
 
 $(foreach file,\
@@ -375,7 +338,7 @@
   $(eval $(call declare-oat-target-target,$(subst $(PRODUCT_OUT)/,,$(file)))))
 
 .PHONY: oat-target
-oat-target: $(ART_TARGET_DEPENDENCIES) $(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE) $(OAT_TARGET_TARGETS)
+oat-target: $(ART_TARGET_DEPENDENCIES) $(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE) $(OAT_TARGET_RULES)
 
 .PHONY: oat-target-sync
 oat-target-sync: oat-target
@@ -396,73 +359,16 @@
 ########################################################################
 # "m art-host" for just building the files needed to run the art script
 .PHONY: art-host
-art-host:   $(HOST_OUT_EXECUTABLES)/art $(HOST_OUT)/bin/dalvikvm $(HOST_OUT)/lib/libart.so $(HOST_OUT)/bin/dex2oat $(HOST_CORE_IMG_OUT) $(HOST_OUT)/lib/libjavacore.so
+ifeq ($(HOST_PREFER_32_BIT),true)
+art-host:   $(HOST_OUT_EXECUTABLES)/art $(HOST_OUT)/bin/dalvikvm32 $(HOST_OUT)/lib/libart.so $(HOST_OUT)/bin/dex2oat $(HOST_CORE_IMG_OUT) $(HOST_OUT)/lib/libjavacore.so
+else
+art-host:   $(HOST_OUT_EXECUTABLES)/art $(HOST_OUT)/bin/dalvikvm64 $(HOST_OUT)/bin/dalvikvm32 $(HOST_OUT)/lib/libart.so $(HOST_OUT)/bin/dex2oat $(HOST_CORE_IMG_OUT) $(HOST_OUT)/lib/libjavacore.so
+endif
 
 .PHONY: art-host-debug
 art-host-debug:   art-host $(HOST_OUT)/lib/libartd.so $(HOST_OUT)/bin/dex2oatd
 
 ########################################################################
-# oatdump targets
-
-ART_DUMP_OAT_PATH ?= $(OUT_DIR)
-
-OATDUMP := $(HOST_OUT_EXECUTABLES)/oatdump$(HOST_EXECUTABLE_SUFFIX)
-OATDUMPD := $(HOST_OUT_EXECUTABLES)/oatdumpd$(HOST_EXECUTABLE_SUFFIX)
-# TODO: for now, override with debug version for better error reporting
-OATDUMP := $(OATDUMPD)
-
-.PHONY: dump-oat
-dump-oat: dump-oat-core dump-oat-boot
-
-.PHONY: dump-oat-core
-dump-oat-core: dump-oat-core-host dump-oat-core-target
-
-.PHONY: dump-oat-core-host
-ifeq ($(ART_BUILD_HOST),true)
-dump-oat-core-host: $(HOST_CORE_IMG_OUT) $(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)
-	$(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
-endif
-
-.PHONY: dump-oat-boot-$(TARGET_ARCH)
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-dump-oat-boot-$(TARGET_ARCH): $(DEFAULT_DEX_PREOPT_BUILT_IMAGE_FILENAME) $(OATDUMP)
-	$(OATDUMP) --image=$(DEFAULT_DEX_PREOPT_BUILT_IMAGE_LOCATION) --output=$(ART_DUMP_OAT_PATH)/boot.$(TARGET_ARCH).oatdump.txt --instruction-set=$(TARGET_ARCH)
-	@echo Output in $(ART_DUMP_OAT_PATH)/boot.$(TARGET_ARCH).oatdump.txt
-endif
-
-ifdef TARGET_2ND_ARCH
-dump-oat-boot-$(TARGET_2ND_ARCH): $(2ND_DEFAULT_DEX_PREOPT_BUILT_IMAGE_FILENAME) $(OATDUMP)
-	$(OATDUMP) --image=$(2ND_DEFAULT_DEX_PREOPT_BUILT_IMAGE_LOCATION) --output=$(ART_DUMP_OAT_PATH)/boot.$(TARGET_2ND_ARCH).oatdump.txt --instruction-set=$(TARGET_2ND_ARCH)
-	@echo Output in $(ART_DUMP_OAT_PATH)/boot.$(TARGET_2ND_ARCH).oatdump.txt
-endif
-
-.PHONY: dump-oat-boot
-dump-oat-boot: dump-oat-boot-$(TARGET_ARCH)
-ifdef TARGET_2ND_ARCH
-dump-oat-boot: dump-oat-boot-$(TARGET_2ND_ARCH)
-endif
-
-.PHONY: dump-oat-Calculator
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-dump-oat-Calculator: $(TARGET_OUT_APPS)/Calculator.odex $(DEFAULT_DEX_PREOPT_BUILT_IMAGE) $(OATDUMP)
-	$(OATDUMP) --oat-file=$< --output=$(ART_DUMP_OAT_PATH)/Calculator.oatdump.txt
-	@echo Output in $(ART_DUMP_OAT_PATH)/Calculator.oatdump.txt
-endif
-
-########################################################################
-# cpplint targets to style check art source files
-
-include $(art_build_path)/Android.cpplint.mk
-
-########################################################################
 # targets to switch back and forth from libdvm to libart
 
 .PHONY: use-art
diff --git a/build/Android.common.mk b/build/Android.common.mk
index f916e1e..150b404 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -17,156 +17,22 @@
 ifndef ANDROID_COMMON_MK
 ANDROID_COMMON_MK = true
 
-ART_SUPPORTED_ARCH := arm arm64 mips x86 x86_64
+ART_TARGET_SUPPORTED_ARCH := arm arm64 mips x86 x86_64
+ART_HOST_SUPPORTED_ARCH := x86 x86_64
 
-ifeq (,$(filter $(TARGET_ARCH),$(ART_SUPPORTED_ARCH)))
+ifeq (,$(filter $(TARGET_ARCH),$(ART_TARGET_SUPPORTED_ARCH)))
 $(warning unsupported TARGET_ARCH=$(TARGET_ARCH))
 endif
-
-# These can be overridden via the environment or by editing to
-# enable/disable certain build configuration.
-#
-# For example, to disable everything but the host debug build you use:
-#
-# (export ART_BUILD_TARGET_NDEBUG=false && export ART_BUILD_TARGET_DEBUG=false && export ART_BUILD_HOST_NDEBUG=false && ...)
-#
-# Beware that tests may use the non-debug build for performance, notable 055-enum-performance
-#
-ART_BUILD_TARGET_NDEBUG ?= true
-ART_BUILD_TARGET_DEBUG ?= true
-ART_BUILD_HOST_NDEBUG ?= true
-ART_BUILD_HOST_DEBUG ?= true
-
-ifeq ($(HOST_PREFER_32_BIT),true)
-ART_HOST_ARCH := $(HOST_2ND_ARCH)
-else
-ART_HOST_ARCH := $(HOST_ARCH)
+ifeq (,$(filter $(HOST_ARCH),$(ART_HOST_SUPPORTED_ARCH)))
+$(warning unsupported HOST_ARCH=$(HOST_ARCH))
 endif
 
-ifeq ($(ART_BUILD_TARGET_NDEBUG),false)
-$(info Disabling ART_BUILD_TARGET_NDEBUG)
-endif
-ifeq ($(ART_BUILD_TARGET_DEBUG),false)
-$(info Disabling ART_BUILD_TARGET_DEBUG)
-endif
-ifeq ($(ART_BUILD_HOST_NDEBUG),false)
-$(info Disabling ART_BUILD_HOST_NDEBUG)
-endif
-ifeq ($(ART_BUILD_HOST_DEBUG),false)
-$(info Disabling ART_BUILD_HOST_DEBUG)
-endif
-
-#
-# Used to enable smart mode
-#
-ART_SMALL_MODE := false
-ifneq ($(wildcard art/SMALL_ART),)
-$(info Enabling ART_SMALL_MODE because of existence of art/SMALL_ART)
-ART_SMALL_MODE := true
-endif
-ifeq ($(WITH_ART_SMALL_MODE), true)
-ART_SMALL_MODE := true
-endif
-
-#
-# 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)
-
-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
-
-# Clang build support.
-
-# Host.
-ART_HOST_CLANG := false
-ifneq ($(WITHOUT_HOST_CLANG),true)
-  # By default, host builds use clang for better warnings.
-  ART_HOST_CLANG := true
-endif
-
-# Clang on the target: only enabled for ARM64. Target builds use GCC by default.
-ART_TARGET_CLANG :=
-ART_TARGET_CLANG_arm :=
-ART_TARGET_CLANG_arm64 :=
-ART_TARGET_CLANG_mips :=
-ART_TARGET_CLANG_x86 :=
-ART_TARGET_CLANG_x86_64 :=
-
-define set-target-local-clang-vars
-    LOCAL_CLANG := $(ART_TARGET_CLANG)
-    $(foreach arch,$(ART_SUPPORTED_ARCH),
-    	ifneq ($$(ART_TARGET_CLANG_$(arch)),)
-        LOCAL_CLANG_$(arch) := $$(ART_TARGET_CLANG_$(arch))
-      endif)
-endef
-
-# directory used for dalvik-cache on device
-ART_DALVIK_CACHE_DIR := /data/dalvik-cache
-
-# directory used for gtests on device
-ART_NATIVETEST_DIR := /data/nativetest/art
-ART_NATIVETEST_OUT := $(TARGET_OUT_DATA_NATIVE_TESTS)/art
-
-# directory used for oat tests on device
-ART_TEST_DIR := /data/art-test
-ART_TEST_OUT := $(TARGET_OUT_DATA)/art-test
-
 # Primary vs. secondary
 2ND_TARGET_ARCH := $(TARGET_2ND_ARCH)
-ART_PHONY_TEST_TARGET_SUFFIX :=
-2ND_ART_PHONY_TEST_TARGET_SUFFIX :=
+TARGET_INSTRUCTION_SET_FEATURES := $(DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES)
+2ND_TARGET_INSTRUCTION_SET_FEATURES := $($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES)
 ifdef TARGET_2ND_ARCH
-  art_test_primary_suffix :=
-  art_test_secondary_suffix :=
   ifneq ($(filter %64,$(TARGET_ARCH)),)
-    art_test_primary_suffix := 64
     ART_PHONY_TEST_TARGET_SUFFIX := 64
     2ND_ART_PHONY_TEST_TARGET_SUFFIX := 32
     ART_TARGET_ARCH_32 := $(TARGET_2ND_ARCH)
@@ -176,268 +42,38 @@
     $(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 :=
 endif
 
-ART_CPP_EXTENSION := .cc
-
 ART_HOST_SHLIB_EXTENSION := $(HOST_SHLIB_SUFFIX)
 ART_HOST_SHLIB_EXTENSION ?= .so
-
-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
-
-ART_TARGET_CLANG_CFLAGS :=
-ART_TARGET_CLANG_CFLAGS_arm :=
-ART_TARGET_CLANG_CFLAGS_arm64 :=
-ART_TARGET_CLANG_CFLAGS_mips :=
-ART_TARGET_CLANG_CFLAGS_x86 :=
-ART_TARGET_CLANG_CFLAGS_x86_64 :=
-
-# these are necessary for Clang ARM64 ART builds
-ART_TARGET_CLANG_CFLAGS_arm64  += \
-	-Wno-implicit-exception-spec-mismatch \
-	-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
-
-ifeq ($(HOST_OS),linux)
-  art_non_debug_cflags += \
-	-Wframe-larger-than=1728
-endif
-
-# FIXME: upstream LLVM has a vectorizer bug that needs to be fixed
-ART_TARGET_CLANG_CFLAGS_arm64 += \
-	-fno-vectorize
-
-art_debug_cflags := \
-	-O1 \
-	-DDYNAMIC_ANNOTATIONS_ENABLED=1 \
-	-UNDEBUG
-
-ART_HOST_CFLAGS := $(art_cflags) -DANDROID_SMP=1 -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS)
-ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default
-ART_HOST_CFLAGS += $(ART_DEFAULT_GC_TYPE_CFLAGS)
-
-ART_TARGET_CFLAGS := $(art_cflags) -DART_TARGET -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS)
-ifeq ($(TARGET_CPU_SMP),true)
-  ART_TARGET_CFLAGS += -DANDROID_SMP=1
+ifeq ($(HOST_PREFER_32_BIT),true)
+  ART_PHONY_TEST_HOST_SUFFIX := 32
+  2ND_ART_PHONY_TEST_HOST_SUFFIX :=
+  ART_HOST_ARCH_32 := x86
+  ART_HOST_ARCH_64 :=
+  ART_HOST_ARCH := x86
+  2ND_ART_HOST_ARCH :=
+  2ND_HOST_ARCH :=
+  ART_HOST_LIBRARY_PATH := $(HOST_LIBRARY_PATH)
+  2ND_ART_HOST_LIBRARY_PATH :=
+  ART_HOST_OUT_SHARED_LIBRARIES := $(2ND_HOST_OUT_SHARED_LIBRARIES)
+  2ND_ART_HOST_OUT_SHARED_LIBRARIES :=
 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
+  ART_PHONY_TEST_HOST_SUFFIX := 64
+  2ND_ART_PHONY_TEST_HOST_SUFFIX := 32
+  ART_HOST_ARCH_32 := x86
+  ART_HOST_ARCH_64 := x86_64
+  ART_HOST_ARCH := x86_64
+  2ND_ART_HOST_ARCH := x86
+  2ND_HOST_ARCH := x86
+  ART_HOST_LIBRARY_PATH := $(HOST_LIBRARY_PATH)
+  2ND_ART_HOST_LIBRARY_PATH := $(HOST_LIBRARY_PATH)32
+  ART_HOST_OUT_SHARED_LIBRARIES := $(HOST_OUT_SHARED_LIBRARIES)
+  2ND_ART_HOST_OUT_SHARED_LIBRARIES := $(2ND_HOST_OUT_SHARED_LIBRARIES)
 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 suport 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
-endif
-
-ART_HOST_NON_DEBUG_CFLAGS := $(art_non_debug_cflags)
-ART_TARGET_NON_DEBUG_CFLAGS := $(art_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)
-
-# $(1): ndebug_or_debug
-define set-target-local-cflags-vars
-    LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
-    LOCAL_CFLAGS_x86 += $(ART_TARGET_CFLAGS_x86)
-    art_target_cflags_ndebug_or_debug := $(1)
-    ifeq ($$(art_target_cflags_ndebug_or_debug),debug)
-      LOCAL_CFLAGS += $(ART_TARGET_DEBUG_CFLAGS)
-    else
-      LOCAL_CFLAGS += $(ART_TARGET_NON_DEBUG_CFLAGS)
-    endif
-
-    # TODO: Also set when ART_TARGET_CLANG_$(arch)!=false and ART_TARGET_CLANG==true
-    $(foreach arch,$(ART_SUPPORTED_ARCH),
-    	ifeq ($$(ART_TARGET_CLANG_$(arch)),true)
-        LOCAL_CFLAGS_$(arch) += $$(ART_TARGET_CLANG_CFLAGS_$(arch))
-      endif)
-endef
-
-ART_BUILD_TARGET := false
-ART_BUILD_HOST := false
-ART_BUILD_NDEBUG := false
-ART_BUILD_DEBUG := false
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-  ART_BUILD_TARGET := true
-  ART_BUILD_NDEBUG := true
-endif
-ifeq ($(ART_BUILD_TARGET_DEBUG),true)
-  ART_BUILD_TARGET := true
-  ART_BUILD_DEBUG := true
-endif
-ifeq ($(ART_BUILD_HOST_NDEBUG),true)
-  ART_BUILD_HOST := true
-  ART_BUILD_NDEBUG := true
-endif
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
-  ART_BUILD_HOST := true
-  ART_BUILD_DEBUG := true
-endif
-
-# Helper function to call a function twice with a target suffix
-# $(1): The generator function for the rules
-#         Has one argument, the suffix
-define call-art-multi-target
-  $(call $(1),$(ART_PHONY_TEST_TARGET_SUFFIX))
-
-  ifdef TARGET_2ND_ARCH
-    $(call $(1),$(2ND_ART_PHONY_TEST_TARGET_SUFFIX))
-  endif
-endef
-
-# Helper function to combine two variables with suffixes together.
-# $(1): The base name.
-define combine-art-multi-target-var
-  ifdef TARGET_2ND_ARCH
-    ifneq ($(ART_PHONY_TEST_TARGET_SUFFIX),)
-      ifneq ($(2ND_ART_PHONY_TEST_TARGET_SUFFIX),)
-$(1) := $($(1)$(ART_PHONY_TEST_TARGET_SUFFIX)) $($(1)$(2ND_ART_PHONY_TEST_TARGET_SUFFIX))
-      endif
-    endif
-  endif
-endef
-
-
-# Helper function to define a variable twice with a target suffix. Assume the name generated is
-# derived from $(2) so we can create a combined var.
-# $(1): The generator function for the rules
-#         Has one argument, the suffix
-define call-art-multi-target-var
-  $(call $(1),$(ART_PHONY_TEST_TARGET_SUFFIX))
-
-  ifdef TARGET_2ND_ARCH
-    $(call $(1),$(2ND_ART_PHONY_TEST_TARGET_SUFFIX))
-
-    # Link both together, if it makes sense
-    ifneq ($(ART_PHONY_TEST_TARGET_SUFFIX),)
-      ifneq ($(2ND_ART_PHONY_TEST_TARGET_SUFFIX),)
-$(2) := $(2)$(ART_PHONY_TEST_TARGET_SUFFIX) $(2)$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
-      endif
-    endif
-
-  endif
-endef
-
-# Helper function to call a function twice with a target suffix. Assume it generates make rules
-# with the given name, and link them.
-# $(1): The generator function for the rules
-#         Has one argument, the suffix
-# $(2): The base rule name, necessary for the link
-#       We assume we can link the names together easily...
-define call-art-multi-target-rule
-  $(call $(1),$(ART_PHONY_TEST_TARGET_SUFFIX))
-
-  ifdef TARGET_2ND_ARCH
-    $(call $(1),$(2ND_ART_PHONY_TEST_TARGET_SUFFIX))
-
-    # Link both together, if it makes sense
-    ifneq ($(ART_PHONY_TEST_TARGET_SUFFIX),)
-      ifneq ($(2ND_ART_PHONY_TEST_TARGET_SUFFIX),)
-.PHONY: $(2)
-$(2): $(2)$(ART_PHONY_TEST_TARGET_SUFFIX) $(2)$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
-      endif
-    endif
-  endif
-endef
-
-HOST_CORE_OAT := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core.oat
-TARGET_CORE_OAT := $(ART_TEST_DIR)/$(DEX2OAT_TARGET_ARCH)/core.oat
-ifdef TARGET_2ND_ARCH
-2ND_TARGET_CORE_OAT := $(2ND_ART_TEST_DIR)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core.oat
-endif
-
-HOST_CORE_OAT_OUT := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core.oat
-TARGET_CORE_OAT_OUT := $(ART_TEST_OUT)/$(DEX2OAT_TARGET_ARCH)/core.oat
-ifdef TARGET_2ND_ARCH
-2ND_TARGET_CORE_OAT_OUT := $(ART_TEST_OUT)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core.oat
-endif
-
-HOST_CORE_IMG_OUT := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core.art
-TARGET_CORE_IMG_OUT := $(ART_TEST_OUT)/$(DEX2OAT_TARGET_ARCH)/core.art
-ifdef TARGET_2ND_ARCH
-2ND_TARGET_CORE_IMG_OUT := $(ART_TEST_OUT)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core.art
-endif
-
-HOST_CORE_IMG_LOCATION := $(HOST_OUT_JAVA_LIBRARIES)/core.art
-TARGET_CORE_IMG_LOCATION := $(ART_TEST_OUT)/core.art
 
 endif # ANDROID_COMMON_MK
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
new file mode 100644
index 0000000..21ba962
--- /dev/null
+++ b/build/Android.common_build.mk
@@ -0,0 +1,323 @@
+#
+# 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 ANDROID_COMMON_BUILD_MK
+ANDROID_COMMON_BUILD_MK = true
+
+include art/build/Android.common.mk
+
+# These can be overridden via the environment or by editing to
+# enable/disable certain build configuration.
+#
+# For example, to disable everything but the host debug build you use:
+#
+# (export ART_BUILD_TARGET_NDEBUG=false && export ART_BUILD_TARGET_DEBUG=false && export ART_BUILD_HOST_NDEBUG=false && ...)
+#
+# Beware that tests may use the non-debug build for performance, notable 055-enum-performance
+#
+ART_BUILD_TARGET_NDEBUG ?= true
+ART_BUILD_TARGET_DEBUG ?= true
+ART_BUILD_HOST_NDEBUG ?= true
+ART_BUILD_HOST_DEBUG ?= true
+
+ifeq ($(ART_BUILD_TARGET_NDEBUG),false)
+$(info Disabling ART_BUILD_TARGET_NDEBUG)
+endif
+ifeq ($(ART_BUILD_TARGET_DEBUG),false)
+$(info Disabling ART_BUILD_TARGET_DEBUG)
+endif
+ifeq ($(ART_BUILD_HOST_NDEBUG),false)
+$(info Disabling ART_BUILD_HOST_NDEBUG)
+endif
+ifeq ($(ART_BUILD_HOST_DEBUG),false)
+$(info Disabling ART_BUILD_HOST_DEBUG)
+endif
+
+#
+# Used to enable smart mode
+#
+ART_SMALL_MODE := false
+ifneq ($(wildcard art/SMALL_ART),)
+$(info Enabling ART_SMALL_MODE because of existence of art/SMALL_ART)
+ART_SMALL_MODE := true
+endif
+ifeq ($(WITH_ART_SMALL_MODE), true)
+ART_SMALL_MODE := true
+endif
+
+#
+# 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)
+
+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
+
+# Clang build support.
+
+# Host.
+ART_HOST_CLANG := false
+ifneq ($(WITHOUT_HOST_CLANG),true)
+  # By default, host builds use clang for better warnings.
+  ART_HOST_CLANG := true
+endif
+
+# Clang on the target: only enabled for ARM64. Target builds use GCC by default.
+ART_TARGET_CLANG :=
+ART_TARGET_CLANG_arm :=
+ART_TARGET_CLANG_arm64 := true
+ART_TARGET_CLANG_mips :=
+ART_TARGET_CLANG_x86 :=
+ART_TARGET_CLANG_x86_64 :=
+
+define set-target-local-clang-vars
+    LOCAL_CLANG := $(ART_TARGET_CLANG)
+    $(foreach arch,$(ART_TARGET_SUPPORTED_ARCH),
+      ifneq ($$(ART_TARGET_CLANG_$(arch)),)
+        LOCAL_CLANG_$(arch) := $$(ART_TARGET_CLANG_$(arch))
+      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
+
+ART_TARGET_CLANG_CFLAGS :=
+ART_TARGET_CLANG_CFLAGS_arm :=
+ART_TARGET_CLANG_CFLAGS_arm64 :=
+ART_TARGET_CLANG_CFLAGS_mips :=
+ART_TARGET_CLANG_CFLAGS_x86 :=
+ART_TARGET_CLANG_CFLAGS_x86_64 :=
+
+# these are necessary for Clang ARM64 ART builds
+ART_TARGET_CLANG_CFLAGS_arm64  += \
+  -Wno-implicit-exception-spec-mismatch \
+  -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
+
+ifeq ($(HOST_OS),linux)
+  art_non_debug_cflags += -Wframe-larger-than=1728
+endif
+
+# FIXME: upstream LLVM has a vectorizer bug that needs to be fixed
+ART_TARGET_CLANG_CFLAGS_arm64 += \
+  -fno-vectorize
+
+art_debug_cflags := \
+  -O1 \
+  -DDYNAMIC_ANNOTATIONS_ENABLED=1 \
+  -UNDEBUG
+
+ifndef LIBART_IMG_HOST_BASE_ADDRESS
+  $(error LIBART_IMG_HOST_BASE_ADDRESS unset)
+endif
+ART_HOST_CFLAGS := $(art_cflags) -DANDROID_SMP=1 -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS)
+ART_HOST_CFLAGS += -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)
+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
+endif
+
+ART_HOST_NON_DEBUG_CFLAGS := $(art_non_debug_cflags)
+ART_TARGET_NON_DEBUG_CFLAGS := $(art_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)
+
+# $(1): ndebug_or_debug
+define set-target-local-cflags-vars
+  LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
+  LOCAL_CFLAGS_x86 += $(ART_TARGET_CFLAGS_x86)
+  art_target_cflags_ndebug_or_debug := $(1)
+  ifeq ($$(art_target_cflags_ndebug_or_debug),debug)
+    LOCAL_CFLAGS += $(ART_TARGET_DEBUG_CFLAGS)
+  else
+    LOCAL_CFLAGS += $(ART_TARGET_NON_DEBUG_CFLAGS)
+  endif
+
+  # TODO: Also set when ART_TARGET_CLANG_$(arch)!=false and ART_TARGET_CLANG==true
+  $(foreach arch,$(ART_SUPPORTED_ARCH),
+    ifeq ($$(ART_TARGET_CLANG_$(arch)),true)
+      LOCAL_CFLAGS_$(arch) += $$(ART_TARGET_CLANG_CFLAGS_$(arch))
+  endif)
+
+  # Clear locally used variables.
+  art_target_cflags_ndebug_or_debug :=
+endef
+
+ART_BUILD_TARGET := false
+ART_BUILD_HOST := false
+ART_BUILD_NDEBUG := false
+ART_BUILD_DEBUG := false
+ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
+  ART_BUILD_TARGET := true
+  ART_BUILD_NDEBUG := true
+endif
+ifeq ($(ART_BUILD_TARGET_DEBUG),true)
+  ART_BUILD_TARGET := true
+  ART_BUILD_DEBUG := true
+endif
+ifeq ($(ART_BUILD_HOST_NDEBUG),true)
+  ART_BUILD_HOST := true
+  ART_BUILD_NDEBUG := true
+endif
+ifeq ($(ART_BUILD_HOST_DEBUG),true)
+  ART_BUILD_HOST := true
+  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 :=
+
+endif # ANDROID_COMMON_BUILD_MK
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
new file mode 100644
index 0000000..d672393
--- /dev/null
+++ b/build/Android.common_path.mk
@@ -0,0 +1,76 @@
+#
+# 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 ANDROID_COMMON_PATH_MK
+ANDROID_COMMON_PATH_MK := true
+
+include art/build/Android.common.mk
+
+# Directory used for dalvik-cache on device.
+ART_TARGET_DALVIK_CACHE_DIR := /data/dalvik-cache
+
+# Directory used for gtests on device.
+ART_TARGET_NATIVETEST_DIR := /data/nativetest/art
+ART_TARGET_NATIVETEST_OUT := $(TARGET_OUT_DATA_NATIVE_TESTS)/art
+
+# Directory used for oat tests on device.
+ART_TARGET_TEST_DIR := /data/art-test
+ART_TARGET_TEST_OUT := $(TARGET_OUT_DATA)/art-test
+
+# Directory used for temporary test files on the host.
+ART_HOST_TEST_DIR := /tmp/test-art-$(shell echo $$PPID)
+
+# Core.oat location on the device.
+TARGET_CORE_OAT := $(ART_TARGET_TEST_DIR)/$(DEX2OAT_TARGET_ARCH)/core.oat
+ifdef TARGET_2ND_ARCH
+2ND_TARGET_CORE_OAT := $(ART_TARGET_TEST_DIR)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core.oat
+endif
+
+# Core.oat locations under the out directory.
+HOST_CORE_OAT_OUT := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core.oat
+ifneq ($(HOST_PREFER_32_BIT),true)
+2ND_HOST_CORE_OAT_OUT := $(HOST_OUT_JAVA_LIBRARIES)/$(2ND_ART_HOST_ARCH)/core.oat
+endif
+TARGET_CORE_OAT_OUT := $(ART_TARGET_TEST_OUT)/$(DEX2OAT_TARGET_ARCH)/core.oat
+ifdef TARGET_2ND_ARCH
+2ND_TARGET_CORE_OAT_OUT := $(ART_TARGET_TEST_OUT)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core.oat
+endif
+
+# Core.art locations under the out directory.
+HOST_CORE_IMG_OUT := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core.art
+ifneq ($(HOST_PREFER_32_BIT),true)
+2ND_HOST_CORE_IMG_OUT := $(HOST_OUT_JAVA_LIBRARIES)/$(2ND_ART_HOST_ARCH)/core.art
+endif
+TARGET_CORE_IMG_OUT := $(ART_TARGET_TEST_OUT)/$(DEX2OAT_TARGET_ARCH)/core.art
+ifdef TARGET_2ND_ARCH
+2ND_TARGET_CORE_IMG_OUT := $(ART_TARGET_TEST_OUT)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core.art
+endif
+
+# Oat location of core.art.
+HOST_CORE_IMG_LOCATION := $(HOST_OUT_JAVA_LIBRARIES)/core.art
+TARGET_CORE_IMG_LOCATION := $(ART_TARGET_TEST_OUT)/core.art
+
+# Jar files for core.art.
+TARGET_CORE_JARS := core-libart conscrypt okhttp core-junit bouncycastle
+HOST_CORE_JARS := $(addsuffix -hostdex,$(TARGET_CORE_JARS))
+
+HOST_CORE_DEX_LOCATIONS   := $(foreach jar,$(HOST_CORE_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
+TARGET_CORE_DEX_LOCATIONS := $(foreach jar,$(TARGET_CORE_JARS),/$(DEXPREOPT_BOOT_JAR_DIR)/$(jar).jar)
+
+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
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
new file mode 100644
index 0000000..1815f50
--- /dev/null
+++ b/build/Android.common_test.mk
@@ -0,0 +1,117 @@
+#
+# 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 ANDROID_COMMON_TEST_MK
+ANDROID_COMMON_TEST_MK = true
+
+include art/build/Android.common_path.mk
+
+# 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 :=
+
+# List of known failing tests that when executed won't cause test execution to finish. The test name
+# must be the full rule name such as test-art-host-oat-optimizing-HelloWorld64.
+ART_TEST_KNOWN_FAILING := $(ART_TEST_KNOWN_BROKEN)
+
+# Keep going after encountering a test failure?
+ART_TEST_KEEP_GOING ?= false
+
+# Define the command run on test failure. $(1) is the name of the test. Executed by the shell.
+define ART_TEST_FAILED
+  ( [ -f $(ART_HOST_TEST_DIR)/skipped/$(1) ] || \
+    (mkdir -p $(ART_HOST_TEST_DIR)/failed/ && touch $(ART_HOST_TEST_DIR)/failed/$(1) && \
+      echo $(ART_TEST_KNOWN_FAILING) | grep -q $(1) \
+        && (echo -e "$(1) \e[91mKNOWN FAILURE\e[0m") \
+        || (echo -e "$(1) \e[91mFAILED\e[0m")))
+endef
+
+# Define the command run on test success. $(1) is the name of the test. Executed by the shell.
+# The command checks prints "PASSED" then checks to see if this was a top-level make target (e.g.
+# "mm test-art-host-oat-HelloWorld32"), if it was then it does nothing, otherwise it creates a file
+# to be printed in the passing test summary.
+define ART_TEST_PASSED
+  ( echo -e "$(1) \e[92mPASSED\e[0m" && \
+    (echo $(MAKECMDGOALS) | grep -q $(1) || \
+      (mkdir -p $(ART_HOST_TEST_DIR)/passed/ && touch $(ART_HOST_TEST_DIR)/passed/$(1))))
+endef
+
+# Define the command run on test success of multiple prerequisites. $(1) is the name of the test.
+# When the test is a top-level make target then a summary of the ran tests is produced. Executed by
+# the shell.
+define ART_TEST_PREREQ_FINISHED
+  (echo -e "$(1) \e[32mCOMPLETE\e[0m" && \
+    (echo $(MAKECMDGOALS) | grep -q -v $(1) || \
+      (([ -d $(ART_HOST_TEST_DIR)/passed/ ] \
+        && (echo -e "\e[92mPASSING TESTS\e[0m" && ls -1 $(ART_HOST_TEST_DIR)/passed/) \
+        || (echo -e "\e[91mNO TESTS PASSED\e[0m")) && \
+      ([ -d $(ART_HOST_TEST_DIR)/skipped/ ] \
+        && (echo -e "\e[93mSKIPPED TESTS\e[0m" && ls -1 $(ART_HOST_TEST_DIR)/skipped/) \
+        || (echo -e "\e[92mNO TESTS SKIPPED\e[0m")) && \
+      ([ -d $(ART_HOST_TEST_DIR)/failed/ ] \
+        && (echo -e "\e[91mFAILING TESTS\e[0m" && ls -1 $(ART_HOST_TEST_DIR)/failed/) \
+        || (echo -e "\e[92mNO TESTS FAILED\e[0m")) \
+      && ([ ! -d $(ART_HOST_TEST_DIR)/failed/ ] && rm -r $(ART_HOST_TEST_DIR) \
+          || (rm -r $(ART_HOST_TEST_DIR) && false)))))
+endef
+
+# Define the command executed by the shell ahead of running an art test. $(1) is the name of the
+# test.
+define ART_TEST_SKIP
+  ((echo $(ART_TEST_KNOWN_BROKEN) | grep -q -v $(1) \
+     && ([ ! -d $(ART_HOST_TEST_DIR)/failed/ ] || [ $(ART_TEST_KEEP_GOING) = true ])\
+     && echo -e "$(1) \e[95mRUNNING\e[0m") \
+   || ((mkdir -p $(ART_HOST_TEST_DIR)/skipped/ && touch $(ART_HOST_TEST_DIR)/skipped/$(1) \
+     && ([ -d $(ART_HOST_TEST_DIR)/failed/ ] \
+       && echo -e "$(1) \e[93mSKIPPING DUE TO EARLIER FAILURE\e[0m") \
+     || echo -e "$(1) \e[93mSKIPPING BROKEN TEST\e[0m") && false))
+endef
+
+# Create a build rule to create the dex file for a test.
+# $(1): module prefix, e.g. art-test-dex
+# $(2): input test directory in art/test, e.g. HelloWorld
+# $(3): target output module path (default module path is used on host)
+# $(4): additional dependencies
+# $(5): a make variable used to collate dependencies
+define build-art-test-dex
+  ifeq ($(ART_BUILD_TARGET),true)
+    include $(CLEAR_VARS)
+    LOCAL_MODULE := $(1)-$(2)
+    LOCAL_SRC_FILES := $(call all-java-files-under, $(2))
+    LOCAL_NO_STANDARD_LIBRARIES := true
+    LOCAL_DEX_PREOPT := false
+    LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_test.mk $(4)
+    LOCAL_MODULE_TAGS := tests
+    LOCAL_JAVA_LIBRARIES := $(TARGET_CORE_JARS)
+    LOCAL_MODULE_PATH := $(3)
+    LOCAL_DEX_PREOPT_IMAGE_LOCATION := $(TARGET_CORE_IMG_OUT)
+    include $(BUILD_JAVA_LIBRARY)
+  endif
+  ifeq ($(ART_BUILD_HOST),true)
+    include $(CLEAR_VARS)
+    LOCAL_MODULE := $(1)-$(2)
+    LOCAL_SRC_FILES := $(call all-java-files-under, $(2))
+    LOCAL_NO_STANDARD_LIBRARIES := true
+    LOCAL_DEX_PREOPT := false
+    LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_test.mk $(4)
+    LOCAL_JAVA_LIBRARIES := $(HOST_CORE_JARS)
+    LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_LOCATION)
+    include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
+  endif
+  $(5) := $$(LOCAL_INSTALLED_MODULE)
+endef
+
+endif # ANDROID_COMMON_TEST_MK
diff --git a/build/Android.cpplint.mk b/build/Android.cpplint.mk
index 1ecad21..7abf863 100644
--- a/build/Android.cpplint.mk
+++ b/build/Android.cpplint.mk
@@ -14,6 +14,8 @@
 # limitations under the License.
 #
 
+include art/build/Android.common_build.mk
+
 ART_CPPLINT := art/tools/cpplint.py
 ART_CPPLINT_FILTER := --filter=-whitespace/line_length,-build/include,-readability/function,-readability/streams,-readability/todo,-runtime/references,-runtime/sizeof,-runtime/threadsafe_fn,-runtime/printf
 ART_CPPLINT_SRC := $(shell find art -name "*.h" -o -name "*$(ART_CPP_EXTENSION)" | grep -v art/compiler/llvm/generated/)
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index 49e7384..d887acd 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -14,7 +14,7 @@
 # limitations under the License.
 #
 
-include art/build/Android.common.mk
+include art/build/Android.common_build.mk
 
 ART_HOST_EXECUTABLES ?=
 ART_TARGET_EXECUTABLES ?=
@@ -85,13 +85,13 @@
     LOCAL_SHARED_LIBRARIES += libartd
   endif
 
-  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
+  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
   LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.executable.mk
 
   ifeq ($$(art_target_or_host),target)
     LOCAL_MODULE_TARGET_ARCH := $(ART_SUPPORTED_ARCH)
-    LOCAL_MULTILIB := $$(art_multilib)
   endif
+  LOCAL_MULTILIB := $$(art_multilib)
 
   include external/libcxx/libcxx.mk
   ifeq ($$(art_target_or_host),target)
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 4c2cda4..a6f6298 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -14,147 +14,257 @@
 # limitations under the License.
 #
 
+# The path for which all the dex files are relative, not actually the current directory.
+LOCAL_PATH := art/test
+
+include art/build/Android.common_test.mk
+include art/build/Android.common_path.mk
+
+# Subdirectories in art/test which contain dex files used as inputs for gtests.
+GTEST_DEX_DIRECTORIES := \
+  AbstractMethod \
+  AllFields \
+  ExceptionHandle \
+  GetMethodSignature \
+  Interfaces \
+  Main \
+  MyClass \
+  MyClassNatives \
+  Nested \
+  NonStaticLeafMethods \
+  ProtoCompare \
+  ProtoCompare2 \
+  StaticLeafMethods \
+  Statics \
+  StaticsFromCode \
+  Transaction \
+  XandY
+
+# Create build rules for each dex file recording the dependency.
+$(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval $(call build-art-test-dex,art-gtest,$(dir), \
+  $(ART_TARGET_NATIVETEST_OUT),art/build/Android.gtest.mk,ART_GTEST_$(dir)_DEX)))
+
+# Dex file dependencies for each gtest.
+ART_GTEST_class_linker_test_DEPS := $(ART_GTEST_Interfaces_DEX) $(ART_GTEST_MyClass_DEX) \
+  $(ART_GTEST_Nested_DEX) $(ART_GTEST_Statics_DEX) $(ART_GTEST_StaticsFromCode_DEX)
+ART_GTEST_compiler_driver_test_DEPS := $(ART_GTEST_AbstractMethod_DEX)
+ART_GTEST_dex_file_test_DEPS := $(ART_GTEST_GetMethodSignature_DEX)
+ART_GTEST_exception_test_DEPS := $(ART_GTEST_ExceptionHandle_DEX)
+ART_GTEST_jni_compiler_test_DEPS := $(ART_GTEST_MyClassNatives_DEX)
+ART_GTEST_jni_internal_test_DEPS := $(ART_GTEST_AllFields_DEX)
+ART_GTEST_object_test_DEPS := $(ART_GTEST_ProtoCompare_DEX) $(ART_GTEST_ProtoCompare2_DEX) \
+   $(ART_GTEST_StaticsFromCode_DEX) $(ART_GTEST_XandY_DEX)
+ART_GTEST_proxy_test_DEPS := $(ART_GTEST_Interfaces_DEX)
+ART_GTEST_reflection_test_DEPS := $(ART_GTEST_Main_DEX) $(ART_GTEST_NonStaticLeafMethods_DEX) \
+  $(ART_GTEST_StaticLeafMethods_DEX)
+ART_GTEST_stub_test_DEPS := $(ART_GTEST_AllFields_DEX)
+ART_GTEST_transaction_test_DEPS := $(ART_GTEST_Transaction_DEX)
+
+# The elf writer test has dependencies on core.oat.
+ART_GTEST_elf_writer_test_DEPS := $(HOST_CORE_OAT_OUT) $(2ND_HOST_CORE_OAT_OUT) \
+  $(TARGET_CORE_OAT_OUT) $(2ND_TARGET_CORE_OAT_OUT)
+
+# The path for which all the source files are relative, not actually the current directory.
 LOCAL_PATH := art
 
 RUNTIME_GTEST_COMMON_SRC_FILES := \
-	runtime/arch/arch_test.cc \
-	runtime/arch/stub_test.cc \
-	runtime/barrier_test.cc \
-	runtime/base/bit_field_test.cc \
-	runtime/base/bit_vector_test.cc \
-	runtime/base/hex_dump_test.cc \
-	runtime/base/histogram_test.cc \
-	runtime/base/mutex_test.cc \
-	runtime/base/scoped_flock_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 \
-	runtime/dex_instruction_visitor_test.cc \
-	runtime/dex_method_iterator_test.cc \
-	runtime/entrypoints/math_entrypoints_test.cc \
-	runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc \
-	runtime/entrypoints_order_test.cc \
-	runtime/exception_test.cc \
-	runtime/gc/accounting/space_bitmap_test.cc \
-	runtime/gc/heap_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 \
-	runtime/gc/space/rosalloc_space_base_test.cc \
-	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/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/leb128_test.cc \
-	runtime/mem_map_test.cc \
-	runtime/mirror/dex_cache_test.cc \
-	runtime/mirror/object_test.cc \
-	runtime/parsed_options_test.cc \
-	runtime/reference_table_test.cc \
-	runtime/thread_pool_test.cc \
-	runtime/transaction_test.cc \
-	runtime/utils_test.cc \
-	runtime/verifier/method_verifier_test.cc \
-	runtime/verifier/reg_type_test.cc \
-	runtime/zip_archive_test.cc
+  runtime/arch/arch_test.cc \
+  runtime/arch/stub_test.cc \
+  runtime/barrier_test.cc \
+  runtime/base/bit_field_test.cc \
+  runtime/base/bit_vector_test.cc \
+  runtime/base/hex_dump_test.cc \
+  runtime/base/histogram_test.cc \
+  runtime/base/mutex_test.cc \
+  runtime/base/scoped_flock_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 \
+  runtime/dex_instruction_visitor_test.cc \
+  runtime/dex_method_iterator_test.cc \
+  runtime/entrypoints/math_entrypoints_test.cc \
+  runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc \
+  runtime/entrypoints_order_test.cc \
+  runtime/exception_test.cc \
+  runtime/gc/accounting/space_bitmap_test.cc \
+  runtime/gc/heap_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 \
+  runtime/gc/space/rosalloc_space_base_test.cc \
+  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/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/leb128_test.cc \
+  runtime/mem_map_test.cc \
+  runtime/mirror/dex_cache_test.cc \
+  runtime/mirror/object_test.cc \
+  runtime/parsed_options_test.cc \
+  runtime/reference_table_test.cc \
+  runtime/thread_pool_test.cc \
+  runtime/transaction_test.cc \
+  runtime/utils_test.cc \
+  runtime/verifier/method_verifier_test.cc \
+  runtime/verifier/reg_type_test.cc \
+  runtime/zip_archive_test.cc
 
 COMPILER_GTEST_COMMON_SRC_FILES := \
-	runtime/jni_internal_test.cc \
-	runtime/proxy_test.cc \
-	runtime/reflection_test.cc \
-	compiler/dex/local_value_numbering_test.cc \
-	compiler/dex/mir_optimization_test.cc \
-	compiler/driver/compiler_driver_test.cc \
-	compiler/elf_writer_test.cc \
-	compiler/image_test.cc \
-	compiler/jni/jni_compiler_test.cc \
-	compiler/oat_test.cc \
-	compiler/optimizing/codegen_test.cc \
-	compiler/optimizing/dominator_test.cc \
-	compiler/optimizing/find_loops_test.cc \
-	compiler/optimizing/graph_test.cc \
-	compiler/optimizing/linearize_test.cc \
-	compiler/optimizing/liveness_test.cc \
-	compiler/optimizing/live_interval_test.cc \
-	compiler/optimizing/live_ranges_test.cc \
-	compiler/optimizing/parallel_move_test.cc \
-	compiler/optimizing/pretty_printer_test.cc \
-	compiler/optimizing/register_allocator_test.cc \
-	compiler/optimizing/ssa_test.cc \
-	compiler/output_stream_test.cc \
-	compiler/utils/arena_allocator_test.cc \
-	compiler/utils/dedupe_set_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 \
+  runtime/jni_internal_test.cc \
+  runtime/proxy_test.cc \
+  runtime/reflection_test.cc \
+  compiler/dex/local_value_numbering_test.cc \
+  compiler/dex/mir_optimization_test.cc \
+  compiler/driver/compiler_driver_test.cc \
+  compiler/elf_writer_test.cc \
+  compiler/image_test.cc \
+  compiler/jni/jni_compiler_test.cc \
+  compiler/oat_test.cc \
+  compiler/optimizing/codegen_test.cc \
+  compiler/optimizing/dominator_test.cc \
+  compiler/optimizing/find_loops_test.cc \
+  compiler/optimizing/graph_test.cc \
+  compiler/optimizing/linearize_test.cc \
+  compiler/optimizing/liveness_test.cc \
+  compiler/optimizing/live_interval_test.cc \
+  compiler/optimizing/live_ranges_test.cc \
+  compiler/optimizing/parallel_move_test.cc \
+  compiler/optimizing/pretty_printer_test.cc \
+  compiler/optimizing/register_allocator_test.cc \
+  compiler/optimizing/ssa_test.cc \
+  compiler/output_stream_test.cc \
+  compiler/utils/arena_allocator_test.cc \
+  compiler/utils/dedupe_set_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
+  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)
+  $(RUNTIME_GTEST_COMMON_SRC_FILES)
 
 RUNTIME_GTEST_HOST_SRC_FILES := \
-	$(RUNTIME_GTEST_COMMON_SRC_FILES)
+  $(RUNTIME_GTEST_COMMON_SRC_FILES)
 
 COMPILER_GTEST_TARGET_SRC_FILES := \
-	$(COMPILER_GTEST_COMMON_SRC_FILES)
+  $(COMPILER_GTEST_COMMON_SRC_FILES)
 
 COMPILER_GTEST_HOST_SRC_FILES := \
-	$(COMPILER_GTEST_COMMON_SRC_FILES) \
-	compiler/utils/x86/assembler_x86_test.cc \
-	compiler/utils/x86_64/assembler_x86_64_test.cc
-
-ART_HOST_GTEST_EXECUTABLES :=
-ART_TARGET_GTEST_EXECUTABLES$(ART_PHONY_TEST_TARGET_SUFFIX) :=
-ART_TARGET_GTEST_EXECUTABLES$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) :=
-ART_HOST_GTEST_TARGETS :=
-ART_HOST_VALGRIND_GTEST_TARGETS :=
-ART_TARGET_GTEST_TARGETS$(ART_PHONY_TEST_TARGET_SUFFIX) :=
-ART_TARGET_GTEST_TARGETS$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) :=
+  $(COMPILER_GTEST_COMMON_SRC_FILES) \
+  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
 
-# Build a make target for a target test.
-# (1) Prefix for variables
-define build-art-test-make-target
-.PHONY: $$(art_gtest_target)$($(1)ART_PHONY_TEST_TARGET_SUFFIX)
-$$(art_gtest_target)$($(1)ART_PHONY_TEST_TARGET_SUFFIX): $(ART_NATIVETEST_OUT)/$(TARGET_$(1)ARCH)/$$(LOCAL_MODULE) test-art-target-sync
-	adb shell touch $(ART_TEST_DIR)/$(TARGET_$(1)ARCH)/$$@
-	adb shell rm $(ART_TEST_DIR)/$(TARGET_$(1)ARCH)/$$@
-	adb shell chmod 755 $(ART_NATIVETEST_DIR)/$(TARGET_$(1)ARCH)/$$(notdir $$<)
-	adb shell sh -c "$(ART_NATIVETEST_DIR)/$(TARGET_$(1)ARCH)/$$(notdir $$<) && touch $(ART_TEST_DIR)/$(TARGET_$(1)ARCH)/$$@"
-	$(hide) (adb pull $(ART_TEST_DIR)/$(TARGET_$(1)ARCH)/$$@ /tmp/ && echo $$@ PASSED) || (echo $$@ FAILED && exit 1)
-	$(hide) rm /tmp/$$@
+# Variables holding collections of gtest pre-requisits used to run a number of gtests.
+ART_TEST_HOST_GTEST$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_GTEST$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_GTEST_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST_RULES :=
+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_TARGET_GTEST_TARGETS$($(1)ART_PHONY_TEST_TARGET_SUFFIX) += $$(art_gtest_target)$($(1)ART_PHONY_TEST_TARGET_SUFFIX)
-endef
+# 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.
+define define-art-gtest-rule-target
+  gtest_rule := test-art-target-gtest-$(1)$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
+
+  # Add the test dependencies to test-art-target-sync, which will be a prerequisit for the test
+  # to ensure files are pushed to the device.
+  TEST_ART_TARGET_SYNC_DEPS += \
+    $$(ART_GTEST_$(1)_DEPS) \
+    $$(ART_TARGET_NATIVETEST_OUT)/$$(TARGET_$(2)ARCH)/$(1) \
+    $$(TARGET_CORE_DEX_LOCATIONS) \
+    $$($(2)TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
+
+.PHONY: $$(gtest_rule)
+$$(gtest_rule): test-art-target-sync
+	$(hide) adb shell touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID
+	$(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 sh -c "$(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
+
+  ART_TEST_TARGET_GTEST$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(gtest_rule)
+  ART_TEST_TARGET_GTEST_RULES += $$(gtest_rule)
+  ART_TEST_TARGET_GTEST_$(1)_RULES += $$(gtest_rule)
+
+  # Clear locally defined variables.
+  gtest_rule :=
+endef  # define-art-gtest-rule-target
+
+# Define make rules for a host gtests.
+# $(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.
+define define-art-gtest-rule-host
+  gtest_rule := test-art-host-gtest-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
+  gtest_exe := $$(HOST_OUT_EXECUTABLES)/$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
+  # Dependencies for all host gtests.
+  gtest_deps := $$(HOST_CORE_DEX_LOCATIONS) \
+    $$($(2)ART_HOST_LIBRARY_PATH)/libjavacore$$(ART_HOST_SHLIB_EXTENSION)
 
 
+.PHONY: $$(gtest_rule)
+$$(gtest_rule): $$(gtest_exe) $$(ART_GTEST_$(1)_DEPS) $$(gtest_deps)
+	$(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)
+  ART_TEST_HOST_GTEST_RULES += $$(gtest_rule)
+  ART_TEST_HOST_GTEST_$(1)_RULES += $$(gtest_rule)
+
+.PHONY: valgrind-$$(gtest_rule)
+valgrind-$$(gtest_rule): $$(gtest_exe) $$(ART_GTEST_$(1)_DEPS) $$(gtest_deps)
+	$(hide) $$(call ART_TEST_SKIP,$$@) && \
+	  valgrind --leak-check=full --error-exitcode=1 $$< && $$(call ART_TEST_PASSED,$$@) \
+	    || $$(call ART_TEST_FAILED,$$@)
+
+  ART_TEST_HOST_VALGRIND_GTEST$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += valgrind-$$(gtest_rule)
+  ART_TEST_HOST_VALGRIND_GTEST_RULES += valgrind-$$(gtest_rule)
+  ART_TEST_HOST_VALGRIND_GTEST_$(1)_RULES += valgrind-$$(gtest_rule)
+
+  # Clear locally defined variables.
+  valgrind_gtest_rule :=
+  gtest_rule :=
+  gtest_exe :=
+  gtest_deps :=
+endef  # define-art-gtest-rule-host
+
+# Define the rules to build and run host and target gtests.
 # $(1): target or host
 # $(2): file name
 # $(3): extra C includes
 # $(4): extra shared libraries
-define build-art-test
+define define-art-gtest
   ifneq ($(1),target)
     ifneq ($(1),host)
       $$(error expected target or host for argument 1, received $(1))
@@ -166,94 +276,103 @@
   art_gtest_extra_c_includes := $(3)
   art_gtest_extra_shared_libraries := $(4)
 
+  include $$(CLEAR_VARS)
   art_gtest_name := $$(notdir $$(basename $$(art_gtest_filename)))
-
-  include $(CLEAR_VARS)
-  LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
   LOCAL_MODULE := $$(art_gtest_name)
   ifeq ($$(art_target_or_host),target)
     LOCAL_MODULE_TAGS := tests
   endif
+  LOCAL_CPP_EXTENSION := $$(ART_CPP_EXTENSION)
   LOCAL_SRC_FILES := $$(art_gtest_filename) runtime/common_runtime_test.cc
-  LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime $(3)
-  LOCAL_SHARED_LIBRARIES += libartd $(4)
-  # dex2oatd is needed to go with libartd
-  LOCAL_REQUIRED_MODULES := dex2oatd
+  LOCAL_C_INCLUDES += $$(ART_C_INCLUDES) art/runtime $$(art_gtest_extra_c_includes)
+  LOCAL_SHARED_LIBRARIES += libartd $$(art_gtest_extra_shared_libraries)
 
-  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
-  LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk
+  # LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
+  # LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk
 
   # Mac OS linker doesn't understand --export-dynamic.
-  ifneq ($(HOST_OS)-$$(art_target_or_host),darwin-host)
+  ifneq ($$(HOST_OS)-$$(art_target_or_host),darwin-host)
     # Allow jni_compiler_test to find Java_MyClassNatives_bar within itself using dlopen(NULL, ...).
     LOCAL_LDFLAGS := -Wl,--export-dynamic -Wl,-u,Java_MyClassNatives_bar -Wl,-u,Java_MyClassNatives_sbar
   endif
 
-  LOCAL_CFLAGS := $(ART_TEST_CFLAGS)
+  LOCAL_CFLAGS := $$(ART_TEST_CFLAGS)
   include external/libcxx/libcxx.mk
   ifeq ($$(art_target_or_host),target)
-  	$(call set-target-local-clang-vars)
-  	$(call set-target-local-cflags-vars,debug)
+    $$(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_STATIC_LIBRARIES += libgtest_libc++
-    LOCAL_MODULE_PATH_32 := $(ART_NATIVETEST_OUT)/$(ART_TARGET_ARCH_32)
-    LOCAL_MODULE_PATH_64 := $(ART_NATIVETEST_OUT)/$(ART_TARGET_ARCH_64)
+    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)
+    include $$(BUILD_EXECUTABLE)
 
-    ART_TARGET_GTEST_EXECUTABLES$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_NATIVETEST_OUT)/$(TARGET_ARCH)/$$(LOCAL_MODULE)
-    art_gtest_target := test-art-$$(art_target_or_host)-gtest-$$(art_gtest_name)
-
+    ART_TEST_TARGET_GTEST_$$(art_gtest_name)_RULES :=
     ifdef TARGET_2ND_ARCH
-      $(call build-art-test-make-target,2ND_)
-
-      ART_TARGET_GTEST_EXECUTABLES$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_NATIVETEST_OUT)/$(TARGET_2ND_ARCH)/$$(LOCAL_MODULE)
-
-      # Bind the primary to the non-suffix rule
-      ifneq ($(ART_PHONY_TEST_TARGET_SUFFIX),)
-$$(art_gtest_target): $$(art_gtest_target)$(ART_PHONY_TEST_TARGET_SUFFIX)
-      endif
+      $$(eval $$(call define-art-gtest-rule-target,$$(art_gtest_name),2ND_))
     endif
-    $(call build-art-test-make-target,)
+    $$(eval $$(call define-art-gtest-rule-target,$$(art_gtest_name),))
 
+    # A rule to run the different architecture versions of the gtest.
+.PHONY: test-art-target-gtest-$$(art_gtest_name)
+test-art-target-gtest-$$(art_gtest_name): $$(ART_TEST_TARGET_GTEST_$$(art_gtest_name)_RULES)
+	$$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
+
+    # Clear locally defined variables.
+    ART_TEST_TARGET_GTEST_$$(art_gtest_name)_RULES :=
   else # host
-    LOCAL_CLANG := $(ART_HOST_CLANG)
-    LOCAL_CFLAGS += $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
+    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
-    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
+    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_LDLIBS += -lpthread -ldl
     LOCAL_IS_HOST_MODULE := true
-    include $(BUILD_HOST_EXECUTABLE)
-    art_gtest_exe := $(HOST_OUT_EXECUTABLES)/$$(LOCAL_MODULE)
-    ART_HOST_GTEST_EXECUTABLES += $$(art_gtest_exe)
-    art_gtest_target := test-art-$$(art_target_or_host)-gtest-$$(art_gtest_name)
-.PHONY: $$(art_gtest_target)
-$$(art_gtest_target): $$(art_gtest_exe) test-art-host-dependencies
-	$$<
-	@echo $$@ PASSED
+    LOCAL_MULTILIB := both
+    LOCAL_MODULE_STEM_32 := $$(art_gtest_name)32
+    LOCAL_MODULE_STEM_64 := $$(art_gtest_name)64
+    include $$(BUILD_HOST_EXECUTABLE)
 
-    ART_HOST_GTEST_TARGETS += $$(art_gtest_target)
+    ART_TEST_HOST_GTEST_$$(art_gtest_name)_RULES :=
+    ART_TEST_HOST_VALGRIND_GTEST_$$(art_gtest_name)_RULES :=
+    ifneq ($$(HOST_PREFER_32_BIT),true)
+      $$(eval $$(call define-art-gtest-rule-host,$$(art_gtest_name),2ND_))
+    endif
+    $$(eval $$(call define-art-gtest-rule-host,$$(art_gtest_name),))
 
-.PHONY: valgrind-$$(art_gtest_target)
-valgrind-$$(art_gtest_target): $$(art_gtest_exe) test-art-host-dependencies
-	valgrind --leak-check=full --error-exitcode=1 $$<
-	@echo $$@ PASSED
+    # Rules to run the different architecture versions of the gtest.
+.PHONY: test-art-host-gtest-$$(art_gtest_name)
+test-art-host-gtest-$$(art_gtest_name): $$(ART_TEST_HOST_GTEST_$$(art_gtest_name)_RULES)
+	$$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
 
-    ART_HOST_VALGRIND_GTEST_TARGETS += valgrind-$$(art_gtest_target)
-  endif
-endef
+.PHONY: valgrind-test-art-host-gtest-$$(art_gtest_name)
+valgrind-test-art-host-gtest-$$(art_gtest_name): $$(ART_TEST_HOST_VALGRIND_GTEST_$$(art_gtest_name)_RULES)
+	$$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
+
+    # Clear locally defined variables.
+    ART_TEST_HOST_GTEST_$$(art_gtest_name)_RULES :=
+    ART_TEST_HOST_VALGRIND_GTEST_$$(art_gtest_name)_RULES :=
+  endif  # host_or_target
+
+  # Clear locally defined variables.
+  art_target_or_host :=
+  art_gtest_filename :=
+  art_gtest_extra_c_includes :=
+  art_gtest_extra_shared_libraries :=
+  art_gtest_name :=
+endef  # define-art-gtest
 
 ifeq ($(ART_BUILD_TARGET),true)
-  $(foreach file,$(RUNTIME_GTEST_TARGET_SRC_FILES), $(eval $(call build-art-test,target,$(file),,)))
-  $(foreach file,$(COMPILER_GTEST_TARGET_SRC_FILES), $(eval $(call build-art-test,target,$(file),art/compiler,libartd-compiler)))
+  $(foreach file,$(RUNTIME_GTEST_TARGET_SRC_FILES), $(eval $(call define-art-gtest,target,$(file),,)))
+  $(foreach file,$(COMPILER_GTEST_TARGET_SRC_FILES), $(eval $(call define-art-gtest,target,$(file),art/compiler,libartd-compiler)))
 endif
 ifeq ($(ART_BUILD_HOST),true)
-  $(foreach file,$(RUNTIME_GTEST_HOST_SRC_FILES), $(eval $(call build-art-test,host,$(file),,)))
-  $(foreach file,$(COMPILER_GTEST_HOST_SRC_FILES), $(eval $(call build-art-test,host,$(file),art/compiler,libartd-compiler)))
+  $(foreach file,$(RUNTIME_GTEST_HOST_SRC_FILES), $(eval $(call define-art-gtest,host,$(file),,)))
+  $(foreach file,$(COMPILER_GTEST_HOST_SRC_FILES), $(eval $(call define-art-gtest,host,$(file),art/compiler,libartd-compiler)))
 endif
 
 # Used outside the art project to get a list of the current tests
@@ -261,3 +380,85 @@
 $(foreach file, $(RUNTIME_GTEST_TARGET_SRC_FILES), $(eval RUNTIME_TARGET_GTEST_MAKE_TARGETS += $$(notdir $$(basename $$(file)))))
 COMPILER_TARGET_GTEST_MAKE_TARGETS :=
 $(foreach file, $(COMPILER_GTEST_TARGET_SRC_FILES), $(eval COMPILER_TARGET_GTEST_MAKE_TARGETS += $$(notdir $$(basename $$(file)))))
+
+# Define all the combinations of host/target, valgrind and suffix such as:
+# test-art-host-gtest or valgrind-test-art-host-gtest64
+# $(1): host or target
+# $(2): HOST or TARGET
+# $(3): valgrind- or undefined
+# $(4): undefined, 32 or 64
+define define-test-art-gtest-combination
+  ifeq ($(1),host)
+    ifneq ($(2),HOST)
+      $$(error argument mismatch $(1) and ($2))
+    endif
+  else
+    ifneq ($(1),target)
+      $$(error found $(1) expected host or target)
+    endif
+    ifneq ($(2),TARGET)
+      $$(error argument mismatch $(1) and ($2))
+    endif
+  endif
+
+  rule_name := $(3)test-art-$(1)-gtest$(4)
+  dependencies := $$(ART_TEST_$(2)_GTEST$(4)_RULES)
+
+.PHONY: $$(rule_name)
+$$(rule_name): $$(dependencies)
+	$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
+
+  # Clear locally defined variables.
+  rule_name :=
+  dependencies :=
+endef  # define-test-art-gtest-combination
+
+$(eval $(call define-test-art-gtest-combination,target,TARGET,,))
+$(eval $(call define-test-art-gtest-combination,target,TARGET,,$(ART_PHONY_TEST_TARGET_SUFFIX)))
+ifdef TARGET_2ND_ARCH
+$(eval $(call define-test-art-gtest-combination,target,TARGET,,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
+endif
+$(eval $(call define-test-art-gtest-combination,host,HOST,,))
+$(eval $(call define-test-art-gtest-combination,host,HOST,valgrind-,))
+$(eval $(call define-test-art-gtest-combination,host,HOST,,$(ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-gtest-combination,host,HOST,valgrind-,$(ART_PHONY_TEST_HOST_SUFFIX)))
+ifneq ($(HOST_PREFER_32_BIT),true)
+$(eval $(call define-test-art-gtest-combination,host,HOST,,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-gtest-combination,host,HOST,valgrind-,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
+endif
+
+# Clear locally defined variables.
+define-art-gtest-rule-target :=
+define-art-gtest-rule-host :=
+define-art-gtest :=
+define-test-art-gtest-combination :=
+RUNTIME_GTEST_COMMON_SRC_FILES :=
+COMPILER_GTEST_COMMON_SRC_FILES :=
+RUNTIME_GTEST_TARGET_SRC_FILES :=
+RUNTIME_GTEST_HOST_SRC_FILES :=
+COMPILER_GTEST_TARGET_SRC_FILES :=
+COMPILER_GTEST_HOST_SRC_FILES :=
+ART_TEST_CFLAGS :=
+ART_TEST_HOST_GTEST$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_GTEST$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_GTEST_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_VALGRIND_GTEST_RULES :=
+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_class_linker_test_DEPS :=
+ART_GTEST_compiler_driver_test_DEPS :=
+ART_GTEST_dex_file_test_DEPS :=
+ART_GTEST_exception_test_DEPS :=
+ART_GTEST_jni_compiler_test_DEPS :=
+ART_GTEST_jni_internal_test_DEPS :=
+ART_GTEST_object_test_DEPS :=
+ART_GTEST_proxy_test_DEPS :=
+ART_GTEST_reflection_test_DEPS :=
+ART_GTEST_stub_test_DEPS :=
+ART_GTEST_transaction_test_DEPS :=
+$(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval ART_GTEST_TEST_$(dir)_DEX :=))
+GTEST_DEX_DIRECTORIES :=
+LOCAL_PATH :=
\ No newline at end of file
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index c67a815..3117f71 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -20,53 +20,62 @@
 #
 # The main rules to build the default "boot" image are in
 # build/core/dex_preopt_libart.mk
-TARGET_CORE_JARS := core-libart conscrypt okhttp core-junit bouncycastle
-HOST_CORE_JARS := $(addsuffix -hostdex,$(TARGET_CORE_JARS))
 
-HOST_CORE_DEX_LOCATIONS   := $(foreach jar,$(HOST_CORE_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
-TARGET_CORE_DEX_LOCATIONS := $(foreach jar,$(TARGET_CORE_JARS),/$(DEXPREOPT_BOOT_JAR_DIR)/$(jar).jar)
-
-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)
-
-TARGET_INSTRUCTION_SET_FEATURES := $(DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES)
+include art/build/Android.common_path.mk
 
 # Use dex2oat debug version for better error reporting
-$(HOST_CORE_IMG_OUT): $(HOST_CORE_DEX_FILES) $(DEX2OATD_DEPENDENCY)
-	@echo "host dex2oat: $@ ($?)"
-	@mkdir -p $(dir $@)
-	$(hide) $(DEX2OATD) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix \
-		--dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) \
-		--oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(LIBART_IMG_HOST_BASE_ADDRESS) \
-		--instruction-set=$(ART_HOST_ARCH) --host --android-root=$(HOST_OUT)
+# $(1): 2ND_ or undefined, 2ND_ for 32-bit host builds.
+define create-core-oat-host-rules
+$$($(1)HOST_CORE_IMG_OUT): $$($(1)HOST_CORE_DEX_FILES) $$(DEX2OATD_DEPENDENCY)
+	@echo "host dex2oat: $$@ ($$?)"
+	@mkdir -p $$(dir $$@)
+	$$(hide) $$(DEX2OATD) --runtime-arg -Xms16m --runtime-arg -Xmx16m \
+	  --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)
 
-$(HOST_CORE_OAT_OUT): $(HOST_CORE_IMG_OUT)
+# This "renaming" eases declaration in art/Android.mk
+HOST_CORE_IMG_OUT$($(1)ART_PHONY_TEST_HOST_SUFFIX) := $($(1)HOST_CORE_IMG_OUT)
+
+$$($(1)HOST_CORE_OAT_OUT): $$($(1)HOST_CORE_IMG_OUT)
+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
 
 IMPLICIT_CHECKS_arm := null,stack
 IMPLICIT_CHECKS_arm64 := none
 IMPLICIT_CHECKS_x86 := none
 IMPLICIT_CHECKS_x86_64 := none
 IMPLICIT_CHECKS_mips := none
-define create-oat-target-targets
+define create-core-oat-target-rules
 $$($(1)TARGET_CORE_IMG_OUT): $$($(1)TARGET_CORE_DEX_FILES) $$(DEX2OATD_DEPENDENCY)
 	@echo "target dex2oat: $$@ ($$?)"
 	@mkdir -p $$(dir $$@)
-	$$(hide) $$(DEX2OATD) --runtime-arg -Xms16m --runtime-arg -Xmx16m --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) \
-		--implicit-checks=$(IMPLICIT_CHECKS_$($(1)TARGET_ARCH)) \
-		--instruction-set=$$($(1)TARGET_ARCH) --instruction-set-features=$$(TARGET_INSTRUCTION_SET_FEATURES) --android-root=$$(PRODUCT_OUT)/system
+	$$(hide) $$(DEX2OATD) --runtime-arg -Xms16m --runtime-arg -Xmx16m \
+	  --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) \
+	  --implicit-checks=$(IMPLICIT_CHECKS_$($(1)TARGET_ARCH)) \
+	  --android-root=$$(PRODUCT_OUT)/system
 
 # This "renaming" eases declaration in art/Android.mk
 TARGET_CORE_IMG_OUT$($(1)ART_PHONY_TEST_TARGET_SUFFIX) := $($(1)TARGET_CORE_IMG_OUT)
 
 $$($(1)TARGET_CORE_OAT_OUT): $$($(1)TARGET_CORE_IMG_OUT)
-endef
+endef  # create-core-oat-target-rules
 
 ifdef TARGET_2ND_ARCH
-  $(eval $(call create-oat-target-targets,2ND_))
+$(eval $(call create-core-oat-target-rules,2ND_))
 endif
-$(eval $(call create-oat-target-targets,))
+$(eval $(call create-core-oat-target-rules,))
 
 
 ifeq ($(ART_BUILD_HOST),true)
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 6d2f5d1..e197c97 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -16,7 +16,7 @@
 
 LOCAL_PATH := $(call my-dir)
 
-include art/build/Android.common.mk
+include art/build/Android.common_build.mk
 
 LIBART_COMPILER_SRC_FILES := \
 	compiled_method.cc \
@@ -249,13 +249,14 @@
   ifeq ($$(art_target_or_host),host)
     LOCAL_LDLIBS += -ldl -lpthread
   endif
-  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
+  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
   LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
   ifeq ($$(art_target_or_host),target)
     LOCAL_SHARED_LIBRARIES += libcutils libvixl
     include $(BUILD_SHARED_LIBRARY)
   else # host
     LOCAL_STATIC_LIBRARIES += libcutils libvixl
+    LOCAL_MULTILIB := both
     include $(BUILD_HOST_SHARED_LIBRARY)
   endif
 
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 5050d4e..45cf2fb 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -371,10 +371,10 @@
   void CompileMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     CHECK(method != nullptr);
     TimingLogger timings("CommonTest::CompileMethod", false, false);
-    timings.StartSplit("CompileOne");
+    TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
     compiler_driver_->CompileOne(method, &timings);
+    TimingLogger::ScopedTiming t2("MakeExecutable", &timings);
     MakeExecutable(method);
-    timings.EndSplit();
   }
 
   void CompileDirectMethod(Handle<mirror::ClassLoader> class_loader, const char* class_name,
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index de9ac4b..caecb7a 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -527,6 +527,13 @@
 
 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);
+
 }  // namespace art
 
 #endif  // ART_COMPILER_DEX_COMPILER_ENUMS_H_
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 0845656..72990b4 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -114,19 +114,20 @@
 
 void CompilationUnit::StartTimingSplit(const char* label) {
   if (compiler_driver->GetDumpPasses()) {
-    timings.StartSplit(label);
+    timings.StartTiming(label);
   }
 }
 
 void CompilationUnit::NewTimingSplit(const char* label) {
   if (compiler_driver->GetDumpPasses()) {
-    timings.NewSplit(label);
+    timings.EndTiming();
+    timings.StartTiming(label);
   }
 }
 
 void CompilationUnit::EndTiming() {
   if (compiler_driver->GetDumpPasses()) {
-    timings.EndSplit();
+    timings.EndTiming();
     if (enable_debug & (1 << kDebugTimings)) {
       LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file);
       LOG(INFO) << Dumpable<TimingLogger>(timings);
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 590c767..04d6898 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -316,9 +316,9 @@
   int ex_offset = Thread::ExceptionOffset<4>().Int32Value();
   RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
   RegStorage reset_reg = AllocTempRef();
-  LoadRefDisp(rs_rARM_SELF, ex_offset, rl_result.reg);
+  LoadRefDisp(rs_rARM_SELF, ex_offset, rl_result.reg, kNotVolatile);
   LoadConstant(reset_reg, 0);
-  StoreRefDisp(rs_rARM_SELF, ex_offset, reset_reg);
+  StoreRefDisp(rs_rARM_SELF, ex_offset, reset_reg, kNotVolatile);
   FreeTemp(reset_reg);
   StoreValue(rl_dest, rl_result);
 }
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 4499862..70dce7f 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -33,20 +33,16 @@
     LIR* CheckSuspendUsingLoad() OVERRIDE;
     RegStorage LoadHelper(ThreadOffset<4> offset) OVERRIDE;
     RegStorage LoadHelper(ThreadOffset<8> offset) OVERRIDE;
-    LIR* LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
-                              OpSize size) OVERRIDE;
     LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
-                      OpSize size) OVERRIDE;
+                      OpSize size, VolatileKind is_volatile) OVERRIDE;
     LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
                          OpSize size) OVERRIDE;
     LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
                              RegStorage r_dest, OpSize size) OVERRIDE;
     LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
     LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
-    LIR* StoreBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_src,
-                               OpSize size) OVERRIDE;
     LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
-                       OpSize size) OVERRIDE;
+                       OpSize size, VolatileKind is_volatile) OVERRIDE;
     LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
                           OpSize size) OVERRIDE;
     LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 916c528..e34d944 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -723,7 +723,7 @@
   } else {
     DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
     // Unaligned load with LDR and LDRSH is allowed on ARMv7 with SCTLR.A set to 0.
-    LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size);
+    LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
     StoreValue(rl_dest, rl_result);
   }
   return true;
@@ -737,13 +737,13 @@
   if (size == k64) {
     // Fake unaligned STRD by two unaligned STR instructions on ARMv7 with SCTLR.A set to 0.
     RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
-    StoreBaseDisp(rl_address.reg, 0, rl_value.reg.GetLow(), k32);
-    StoreBaseDisp(rl_address.reg, 4, rl_value.reg.GetHigh(), k32);
+    StoreBaseDisp(rl_address.reg, 0, rl_value.reg.GetLow(), k32, kNotVolatile);
+    StoreBaseDisp(rl_address.reg, 4, rl_value.reg.GetHigh(), k32, kNotVolatile);
   } else {
     DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
     // Unaligned store with STR and STRSH is allowed on ARMv7 with SCTLR.A set to 0.
     RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
-    StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size);
+    StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
   }
   return true;
 }
@@ -1230,7 +1230,7 @@
       }
       FreeTemp(reg_len);
     }
-    LoadBaseDisp(reg_ptr, data_offset, rl_result.reg, size);
+    LoadBaseDisp(reg_ptr, data_offset, rl_result.reg, size, kNotVolatile);
     MarkPossibleNullPointerException(opt_flags);
     if (!constant_index) {
       FreeTemp(reg_ptr);
@@ -1330,7 +1330,7 @@
       FreeTemp(reg_len);
     }
 
-    StoreBaseDisp(reg_ptr, data_offset, rl_src.reg, size);
+    StoreBaseDisp(reg_ptr, data_offset, rl_src.reg, size, kNotVolatile);
     MarkPossibleNullPointerException(opt_flags);
   } else {
     /* reg_ptr -> array data */
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index b236f99..bc8f95b 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -961,31 +961,37 @@
   return load;
 }
 
-LIR* ArmMir2Lir::LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
-                                      OpSize size) {
-  // Only 64-bit load needs special handling.
-  if (UNLIKELY(size == k64 || size == kDouble)) {
-    DCHECK(!r_dest.IsFloat());  // See RegClassForFieldLoadSave().
-    // If the cpu supports LPAE, aligned LDRD is atomic - fall through to LoadBaseDisp().
-    if (!cu_->compiler_driver->GetInstructionSetFeatures().HasLpae()) {
-      // 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());
-      FreeTemp(r_ptr);
-      return lir;
-    }
-  }
-  return LoadBaseDisp(r_base, displacement, r_dest, size);
-}
-
 LIR* ArmMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
-                              OpSize size) {
+                              OpSize size, VolatileKind is_volatile) {
   // TODO: base this on target.
   if (size == kWord) {
     size = k32;
   }
-  return LoadBaseDispBody(r_base, displacement, r_dest, size);
+  LIR* load;
+  if (UNLIKELY(is_volatile == kVolatile &&
+               (size == k64 || size == kDouble) &&
+               !cu_->compiler_driver->GetInstructionSetFeatures().HasLpae())) {
+    // Only 64-bit load needs special handling.
+    // If the cpu supports LPAE, aligned LDRD is atomic - fall through to LoadBaseDisp().
+    DCHECK(!r_dest.IsFloat());  // See RegClassForFieldLoadSave().
+    // 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());
+    FreeTemp(r_ptr);
+    return lir;
+  } else {
+    load = LoadBaseDispBody(r_base, displacement, r_dest, size);
+  }
+
+  if (UNLIKELY(is_volatile == kVolatile)) {
+    // Without context sensitive analysis, we must issue the most conservative barriers.
+    // In this case, either a load or store may follow so we issue both barriers.
+    GenMemBarrier(kLoadLoad);
+    GenMemBarrier(kLoadStore);
+  }
+
+  return load;
 }
 
 
@@ -1081,49 +1087,58 @@
   return store;
 }
 
-LIR* ArmMir2Lir::StoreBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_src,
-                                       OpSize size) {
-  // Only 64-bit store needs special handling.
-  if (UNLIKELY(size == k64 || size == kDouble)) {
-    DCHECK(!r_src.IsFloat());  // See RegClassForFieldLoadSave().
-    // If the cpu supports LPAE, aligned STRD is atomic - fall through to StoreBaseDisp().
-    if (!cu_->compiler_driver->GetInstructionSetFeatures().HasLpae()) {
-      // Use STREXD for the atomic store. (Expect displacement > 0, don't optimize for == 0.)
-      RegStorage r_ptr = AllocTemp();
-      OpRegRegImm(kOpAdd, r_ptr, r_base, displacement);
-      LIR* fail_target = NewLIR0(kPseudoTargetLabel);
-      // We have only 5 temporary registers available and if r_base, r_src and r_ptr already
-      // take 4, we can't directly allocate 2 more for LDREXD temps. In that case clobber r_ptr
-      // in LDREXD and recalculate it from r_base.
-      RegStorage r_temp = AllocTemp();
-      RegStorage r_temp_high = AllocFreeTemp();  // We may not have another temp.
-      if (r_temp_high.Valid()) {
-        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());
-        FreeTemp(r_temp);  // May need the temp for kOpAdd.
-        OpRegRegImm(kOpAdd, r_ptr, r_base, displacement);
-      }
-      LIR* lir = NewLIR4(kThumb2Strexd, r_temp.GetReg(), r_src.GetLowReg(), r_src.GetHighReg(),
-                         r_ptr.GetReg());
-      OpCmpImmBranch(kCondNe, r_temp, 0, fail_target);
-      FreeTemp(r_ptr);
-      return lir;
-    }
-  }
-  return StoreBaseDisp(r_base, displacement, r_src, size);
-}
-
 LIR* ArmMir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
-                               OpSize size) {
-  // TODO: base this on target.
-  if (size == kWord) {
-    size = k32;
+                               OpSize size, VolatileKind is_volatile) {
+  if (UNLIKELY(is_volatile == kVolatile)) {
+    // There might have been a store before this volatile one so insert StoreStore barrier.
+    GenMemBarrier(kStoreStore);
   }
-  return StoreBaseDispBody(r_base, displacement, r_src, size);
+
+  LIR* store;
+  if (UNLIKELY(is_volatile == kVolatile &&
+               (size == k64 || size == kDouble) &&
+               !cu_->compiler_driver->GetInstructionSetFeatures().HasLpae())) {
+    // Only 64-bit store needs special handling.
+    // If the cpu supports LPAE, aligned STRD is atomic - fall through to StoreBaseDisp().
+    // Use STREXD for the atomic store. (Expect displacement > 0, don't optimize for == 0.)
+    DCHECK(!r_src.IsFloat());  // See RegClassForFieldLoadSave().
+    RegStorage r_ptr = AllocTemp();
+    OpRegRegImm(kOpAdd, r_ptr, r_base, displacement);
+    LIR* fail_target = NewLIR0(kPseudoTargetLabel);
+    // We have only 5 temporary registers available and if r_base, r_src and r_ptr already
+    // take 4, we can't directly allocate 2 more for LDREXD temps. In that case clobber r_ptr
+    // in LDREXD and recalculate it from r_base.
+    RegStorage r_temp = AllocTemp();
+    RegStorage r_temp_high = AllocFreeTemp();  // We may not have another temp.
+    if (r_temp_high.Valid()) {
+      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());
+      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());
+    OpCmpImmBranch(kCondNe, r_temp, 0, fail_target);
+    FreeTemp(r_ptr);
+  } else {
+    // TODO: base this on target.
+    if (size == kWord) {
+      size = k32;
+    }
+
+    store = StoreBaseDispBody(r_base, displacement, r_src, size);
+  }
+
+  if (UNLIKELY(is_volatile == kVolatile)) {
+    // A load might follow the volatile store so insert a StoreLoad barrier.
+    GenMemBarrier(kStoreLoad);
+  }
+
+  return store;
 }
 
 LIR* ArmMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index 3f32c51..1f1a252 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -101,6 +101,7 @@
 // Temporary macros, used to mark code which wants to distinguish betweek zr/sp.
 #define A64_REG_IS_SP(reg_num) ((reg_num) == rwsp || (reg_num) == rsp)
 #define A64_REG_IS_ZR(reg_num) ((reg_num) == rwzr || (reg_num) == rxzr)
+#define A64_REGSTORAGE_IS_SP_OR_ZR(rs) (((rs).GetRegNum() & 0x1f) == 0x1f)
 
 enum Arm64ResourceEncodingPos {
   kArm64GPReg0   = 0,
diff --git a/compiler/dex/quick/arm64/assemble_arm64.cc b/compiler/dex/quick/arm64/assemble_arm64.cc
index 2a8da24..bee64f1 100644
--- a/compiler/dex/quick/arm64/assemble_arm64.cc
+++ b/compiler/dex/quick/arm64/assemble_arm64.cc
@@ -632,19 +632,19 @@
           if (static_cast<unsigned>(kind) < kFmtBitBlt) {
             bool is_zero = A64_REG_IS_ZR(operand);
 
-            if (kIsDebugBuild) {
+            if (kIsDebugBuild && (kFailOnSizeError || kReportSizeError)) {
               // Register usage checks: First establish register usage requirements based on the
               // format in `kind'.
               bool want_float = false;
               bool want_64_bit = false;
-              bool want_size_match = false;
+              bool want_var_size = true;
               bool want_zero = false;
               switch (kind) {
                 case kFmtRegX:
                   want_64_bit = true;
                   // Intentional fall-through.
                 case kFmtRegW:
-                  want_size_match = true;
+                  want_var_size = false;
                   // Intentional fall-through.
                 case kFmtRegR:
                   want_zero = true;
@@ -653,7 +653,7 @@
                   want_64_bit = true;
                   // Intentional fall-through.
                 case kFmtRegWOrSp:
-                  want_size_match = true;
+                  want_var_size = false;
                   break;
                 case kFmtRegROrSp:
                   break;
@@ -661,7 +661,7 @@
                   want_64_bit = true;
                   // Intentional fall-through.
                 case kFmtRegS:
-                  want_size_match = true;
+                  want_var_size = false;
                   // Intentional fall-through.
                 case kFmtRegF:
                   want_float = true;
@@ -672,21 +672,27 @@
                   break;
               }
 
+              // want_var_size == true means kind == kFmtReg{R,F}. In these two cases, we want
+              // the register size to be coherent with the instruction width.
+              if (want_var_size) {
+                want_64_bit = opcode_is_wide;
+              }
+
               // Now check that the requirements are satisfied.
               RegStorage reg(operand | RegStorage::kValid);
               const char *expected = nullptr;
               if (want_float) {
                 if (!reg.IsFloat()) {
                   expected = "float register";
-                } else if (want_size_match && (reg.IsDouble() != want_64_bit)) {
+                } else if (reg.IsDouble() != want_64_bit) {
                   expected = (want_64_bit) ? "double register" : "single register";
                 }
               } else {
                 if (reg.IsFloat()) {
                   expected = "core register";
-                } else if (want_size_match && (reg.Is64Bit() != want_64_bit)) {
+                } else if (reg.Is64Bit() != want_64_bit) {
                   expected = (want_64_bit) ? "x-register" : "w-register";
-                } else if (reg.GetRegNum() == 31 && is_zero != want_zero) {
+                } else if (A64_REGSTORAGE_IS_SP_OR_ZR(reg) && is_zero != want_zero) {
                   expected = (want_zero) ? "zero-register" : "sp-register";
                 }
               }
@@ -698,8 +704,13 @@
               if (expected != nullptr) {
                 LOG(WARNING) << "Method: " << PrettyMethod(cu_->method_idx, *cu_->dex_file)
                              << " @ 0x" << std::hex << lir->dalvik_offset;
-                LOG(FATAL) << "Bad argument n. " << i << " of " << encoder->name
-                           << ". Expected " << expected << ", got 0x" << std::hex << operand;
+                if (kFailOnSizeError) {
+                  LOG(FATAL) << "Bad argument n. " << i << " of " << encoder->name
+                             << ". Expected " << expected << ", got 0x" << std::hex << operand;
+                } else {
+                  LOG(WARNING) << "Bad argument n. " << i << " of " << encoder->name
+                               << ". Expected " << expected << ", got 0x" << std::hex << operand;
+                }
               }
             }
 
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index 1df576b..c3f4711 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -267,7 +267,7 @@
   MarkPossibleNullPointerException(opt_flags);
   LIR* slow_unlock_branch = OpCmpBranch(kCondNe, rs_w1, rs_w2, NULL);
   GenMemBarrier(kStoreLoad);
-  Store32Disp(rs_x0, mirror::Object::MonitorOffset().Int32Value(), rs_xzr);
+  Store32Disp(rs_x0, mirror::Object::MonitorOffset().Int32Value(), rs_wzr);
   LIR* unlock_success_branch = OpUnconditionalBranch(NULL);
 
   LIR* slow_path_target = NewLIR0(kPseudoTargetLabel);
@@ -289,8 +289,8 @@
 void Arm64Mir2Lir::GenMoveException(RegLocation rl_dest) {
   int ex_offset = Thread::ExceptionOffset<8>().Int32Value();
   RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
-  LoadRefDisp(rs_rA64_SELF, ex_offset, rl_result.reg);
-  StoreRefDisp(rs_rA64_SELF, ex_offset, rs_xzr);
+  LoadRefDisp(rs_rA64_SELF, ex_offset, rl_result.reg, kNotVolatile);
+  StoreRefDisp(rs_rA64_SELF, ex_offset, rs_xzr, kNotVolatile);
   StoreValue(rl_dest, rl_result);
 }
 
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index f1270ec..68fa6f4 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -26,6 +26,11 @@
 
 class Arm64Mir2Lir : public Mir2Lir {
  protected:
+  // If we detect a size error, FATAL out.
+  static constexpr bool kFailOnSizeError = false && kIsDebugBuild;
+  // If we detect a size error, report to LOG.
+  static constexpr bool kReportSizeError = false && kIsDebugBuild;
+
   // TODO: consolidate 64-bit target support.
   class InToRegStorageMapper {
    public:
@@ -69,22 +74,25 @@
     LIR* CheckSuspendUsingLoad() OVERRIDE;
     RegStorage LoadHelper(ThreadOffset<4> offset) OVERRIDE;
     RegStorage LoadHelper(ThreadOffset<8> offset) OVERRIDE;
-    LIR* LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
-                              OpSize size) OVERRIDE;
     LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
-                      OpSize size) OVERRIDE;
+                      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) OVERRIDE;
     LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
                              RegStorage r_dest, OpSize size) OVERRIDE;
     LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
     LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
-    LIR* StoreBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
-                               OpSize size) OVERRIDE;
     LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
-                       OpSize size) OVERRIDE;
+                       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) OVERRIDE;
     LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
                               RegStorage r_src, OpSize size) OVERRIDE;
     void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) OVERRIDE;
@@ -283,8 +291,15 @@
      * @see As64BitReg
      */
     RegStorage As32BitReg(RegStorage reg) {
-      DCHECK(reg.Is64Bit());
       DCHECK(!reg.IsPair());
+      if ((kFailOnSizeError || kReportSizeError) && !reg.Is64Bit()) {
+        if (kFailOnSizeError) {
+          LOG(FATAL) << "Expected 64b register";
+        } else {
+          LOG(WARNING) << "Expected 64b register";
+          return reg;
+        }
+      }
       RegStorage ret_val = RegStorage(RegStorage::k32BitSolo,
                                       reg.GetRawBits() & RegStorage::kRegTypeMask);
       DCHECK_EQ(GetRegInfo(reg)->FindMatchingView(RegisterInfo::k32SoloStorageMask)
@@ -293,6 +308,18 @@
       return ret_val;
     }
 
+    RegStorage Check32BitReg(RegStorage reg) {
+      if ((kFailOnSizeError || kReportSizeError) && !reg.Is32Bit()) {
+        if (kFailOnSizeError) {
+          LOG(FATAL) << "Checked for 32b register";
+        } else {
+          LOG(WARNING) << "Checked for 32b register";
+          return As32BitReg(reg);
+        }
+      }
+      return reg;
+    }
+
     /**
      * @brief Given register wNN (sNN), returns register xNN (dNN).
      * @param reg #RegStorage containing a Solo32 input register (e.g. @c w1 or @c s2).
@@ -300,8 +327,15 @@
      * @see As32BitReg
      */
     RegStorage As64BitReg(RegStorage reg) {
-      DCHECK(reg.Is32Bit());
       DCHECK(!reg.IsPair());
+      if ((kFailOnSizeError || kReportSizeError) && !reg.Is32Bit()) {
+        if (kFailOnSizeError) {
+          LOG(FATAL) << "Expected 32b register";
+        } else {
+          LOG(WARNING) << "Expected 32b register";
+          return reg;
+        }
+      }
       RegStorage ret_val = RegStorage(RegStorage::k64BitSolo,
                                       reg.GetRawBits() & RegStorage::kRegTypeMask);
       DCHECK_EQ(GetRegInfo(reg)->FindMatchingView(RegisterInfo::k64SoloStorageMask)
@@ -310,6 +344,18 @@
       return ret_val;
     }
 
+    RegStorage Check64BitReg(RegStorage reg) {
+      if ((kFailOnSizeError || kReportSizeError) && !reg.Is64Bit()) {
+        if (kFailOnSizeError) {
+          LOG(FATAL) << "Checked for 64b register";
+        } else {
+          LOG(WARNING) << "Checked for 64b register";
+          return As64BitReg(reg);
+        }
+      }
+      return reg;
+    }
+
     LIR* LoadFPConstantValue(RegStorage r_dest, int32_t value);
     LIR* LoadFPConstantValueWide(RegStorage r_dest, int64_t value);
     void ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index 2ac4adb..1fdbe2d 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -410,7 +410,7 @@
   RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);   // kRefReg
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
 
-  LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size);
+  LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
   if (size == k64) {
     StoreValueWide(rl_dest, rl_result);
   } else {
@@ -433,7 +433,7 @@
     DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
     rl_value = LoadValue(rl_src_value, kCoreReg);
   }
-  StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size);
+  StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
   return true;
 }
 
@@ -747,7 +747,11 @@
       }
       FreeTemp(reg_len);
     }
-    LoadBaseDisp(reg_ptr, data_offset, rl_result.reg, size);
+    if (rl_result.ref) {
+      LoadRefDisp(reg_ptr, 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);
@@ -768,7 +772,11 @@
       GenArrayBoundsCheck(rl_index.reg, reg_len);
       FreeTemp(reg_len);
     }
-    LoadBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_result.reg, scale, size);
+    if (rl_result.ref) {
+      LoadRefIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_result.reg);
+    } else {
+      LoadBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_result.reg, scale, size);
+    }
     MarkPossibleNullPointerException(opt_flags);
     FreeTemp(reg_ptr);
     StoreValue(rl_dest, rl_result);
@@ -847,8 +855,11 @@
       }
       FreeTemp(reg_len);
     }
-
-    StoreBaseDisp(reg_ptr, data_offset, rl_src.reg, size);
+    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 */
@@ -858,7 +869,11 @@
       GenArrayBoundsCheck(rl_index.reg, reg_len);
       FreeTemp(reg_len);
     }
-    StoreBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_src.reg, scale, size);
+    if (rl_src.ref) {
+      StoreRefIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_src.reg);
+    } else {
+      StoreBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_src.reg, scale, size);
+    }
     MarkPossibleNullPointerException(opt_flags);
   }
   if (allocated_reg_ptr_temp) {
diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc
index 06e1cda..dfaa483 100644
--- a/compiler/dex/quick/arm64/target_arm64.cc
+++ b/compiler/dex/quick/arm64/target_arm64.cc
@@ -789,7 +789,7 @@
 RegStorage Arm64Mir2Lir::LoadHelper(ThreadOffset<8> offset) {
   // TODO(Arm64): use LoadWordDisp instead.
   //   e.g. LoadWordDisp(rs_rA64_SELF, offset.Int32Value(), rs_rA64_LR);
-  LoadBaseDisp(rs_rA64_SELF, offset.Int32Value(), rs_rA64_LR, k64);
+  LoadBaseDisp(rs_rA64_SELF, offset.Int32Value(), rs_rA64_LR, k64, kNotVolatile);
   return rs_rA64_LR;
 }
 
@@ -949,7 +949,7 @@
   StoreValue(rl_method, rl_src);
   // If Method* has been promoted, explicitly flush
   if (rl_method.location == kLocPhysReg) {
-    StoreRefDisp(TargetReg(kSp), 0, TargetReg(kArg0));
+    StoreRefDisp(TargetReg(kSp), 0, TargetReg(kArg0), kNotVolatile);
   }
 
   if (cu_->num_ins == 0) {
@@ -971,7 +971,7 @@
       } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
         OpRegCopy(RegStorage::Solo32(v_map->FpReg), reg);
       } else {
-        StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i), reg, op_size);
+        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";
@@ -1057,14 +1057,14 @@
         loc = UpdateLocWide(loc);
         if (loc.location == kLocPhysReg) {
           ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-          StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64);
+          StoreBaseDisp(TargetReg(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);
-          StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k32);
+          StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k32, kNotVolatile);
         }
         next_arg++;
       }
@@ -1122,18 +1122,27 @@
           ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
           if (rl_arg.wide) {
             if (rl_arg.location == kLocPhysReg) {
-              StoreBaseDisp(TargetReg(kSp), out_offset, rl_arg.reg, k64);
+              StoreBaseDisp(TargetReg(kSp), out_offset, rl_arg.reg, k64, kNotVolatile);
             } else {
               LoadValueDirectWideFixed(rl_arg, regWide);
-              StoreBaseDisp(TargetReg(kSp), out_offset, regWide, k64);
+              StoreBaseDisp(TargetReg(kSp), out_offset, regWide, k64, kNotVolatile);
             }
             i++;
           } else {
             if (rl_arg.location == kLocPhysReg) {
-              StoreBaseDisp(TargetReg(kSp), out_offset, rl_arg.reg, k32);
+              if (rl_arg.ref) {
+                StoreRefDisp(TargetReg(kSp), out_offset, rl_arg.reg, kNotVolatile);
+              } else {
+                StoreBaseDisp(TargetReg(kSp), out_offset, rl_arg.reg, k32, kNotVolatile);
+              }
             } else {
-              LoadValueDirectFixed(rl_arg, regSingle);
-              StoreBaseDisp(TargetReg(kSp), out_offset, regSingle, k32);
+              if (rl_arg.ref) {
+                LoadValueDirectFixed(rl_arg, regSingle);
+                StoreRefDisp(TargetReg(kSp), out_offset, regSingle, kNotVolatile);
+              } else {
+                LoadValueDirectFixed(rl_arg, As32BitReg(regSingle));
+                StoreBaseDisp(TargetReg(kSp), out_offset, As32BitReg(regSingle), k32, kNotVolatile);
+              }
             }
           }
         }
diff --git a/compiler/dex/quick/arm64/utility_arm64.cc b/compiler/dex/quick/arm64/utility_arm64.cc
index 672aa88..12c2f41 100644
--- a/compiler/dex/quick/arm64/utility_arm64.cc
+++ b/compiler/dex/quick/arm64/utility_arm64.cc
@@ -893,9 +893,7 @@
   ArmOpcode opcode = kA64Brk1d;
   DCHECK(r_base.Is64Bit());
   // TODO: need a cleaner handling of index registers here and throughout.
-  if (r_index.Is32Bit()) {
-    r_index = As64BitReg(r_index);
-  }
+  r_index = Check32BitReg(r_index);
 
   if (r_dest.IsFloat()) {
     if (r_dest.IsDouble()) {
@@ -918,12 +916,14 @@
     case kDouble:
     case kWord:
     case k64:
+      r_dest = Check64BitReg(r_dest);
       opcode = WIDE(kA64Ldr4rXxG);
       expected_scale = 3;
       break;
     case kSingle:
     case k32:
     case kReference:
+      r_dest = Check32BitReg(r_dest);
       opcode = kA64Ldr4rXxG;
       expected_scale = 2;
       break;
@@ -959,6 +959,10 @@
   return load;
 }
 
+LIR* Arm64Mir2Lir::LoadRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest) {
+  return LoadBaseIndexed(r_base, r_index, As32BitReg(r_dest), 2, kReference);
+}
+
 LIR* Arm64Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
                                     int scale, OpSize size) {
   LIR* store;
@@ -966,9 +970,7 @@
   ArmOpcode opcode = kA64Brk1d;
   DCHECK(r_base.Is64Bit());
   // TODO: need a cleaner handling of index registers here and throughout.
-  if (r_index.Is32Bit()) {
-    r_index = As64BitReg(r_index);
-  }
+  r_index = Check32BitReg(r_index);
 
   if (r_src.IsFloat()) {
     if (r_src.IsDouble()) {
@@ -991,12 +993,14 @@
     case kDouble:     // Intentional fall-trough.
     case kWord:       // Intentional fall-trough.
     case k64:
+      r_src = Check64BitReg(r_src);
       opcode = WIDE(kA64Str4rXxG);
       expected_scale = 3;
       break;
     case kSingle:     // Intentional fall-trough.
     case k32:         // Intentional fall-trough.
     case kReference:
+      r_src = Check32BitReg(r_src);
       opcode = kA64Str4rXxG;
       expected_scale = 2;
       break;
@@ -1026,6 +1030,10 @@
   return store;
 }
 
+LIR* Arm64Mir2Lir::StoreRefIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src) {
+  return StoreBaseIndexed(r_base, r_index, As32BitReg(r_src), 2, kReference);
+}
+
 /*
  * Load value from base + displacement.  Optionally perform null check
  * on base (which must have an associated s_reg and MIR).  If not
@@ -1042,6 +1050,7 @@
     case kDouble:     // Intentional fall-through.
     case kWord:       // Intentional fall-through.
     case k64:
+      r_dest = Check64BitReg(r_dest);
       scale = 3;
       if (r_dest.IsFloat()) {
         DCHECK(r_dest.IsDouble());
@@ -1055,6 +1064,7 @@
     case kSingle:     // Intentional fall-through.
     case k32:         // Intentional fall-trough.
     case kReference:
+      r_dest = Check32BitReg(r_dest);
       scale = 2;
       if (r_dest.IsFloat()) {
         DCHECK(r_dest.IsSingle());
@@ -1106,19 +1116,28 @@
   return load;
 }
 
-LIR* Arm64Mir2Lir::LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
-                                        OpSize size) {
+LIR* Arm64Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
+                                OpSize size, VolatileKind is_volatile) {
   // LoadBaseDisp() will emit correct insn for atomic load on arm64
   // assuming r_dest is correctly prepared using RegClassForFieldLoadStore().
-  return LoadBaseDisp(r_base, displacement, r_dest, size);
+
+  LIR* load = LoadBaseDispBody(r_base, displacement, r_dest, size);
+
+  if (UNLIKELY(is_volatile == kVolatile)) {
+    // Without context sensitive analysis, we must issue the most conservative barriers.
+    // In this case, either a load or store may follow so we issue both barriers.
+    GenMemBarrier(kLoadLoad);
+    GenMemBarrier(kLoadStore);
+  }
+
+  return load;
 }
 
-LIR* Arm64Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
-                                OpSize size) {
-  return LoadBaseDispBody(r_base, displacement, r_dest, size);
+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;
@@ -1130,6 +1149,7 @@
     case kDouble:     // Intentional fall-through.
     case kWord:       // Intentional fall-through.
     case k64:
+      r_src = Check64BitReg(r_src);
       scale = 3;
       if (r_src.IsFloat()) {
         DCHECK(r_src.IsDouble());
@@ -1143,6 +1163,7 @@
     case kSingle:     // Intentional fall-through.
     case k32:         // Intentional fall-trough.
     case kReference:
+      r_src = Check32BitReg(r_src);
       scale = 2;
       if (r_src.IsFloat()) {
         DCHECK(r_src.IsSingle());
@@ -1188,16 +1209,29 @@
   return store;
 }
 
-LIR* Arm64Mir2Lir::StoreBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_src,
-                                         OpSize size) {
+LIR* Arm64Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
+                                 OpSize size, VolatileKind is_volatile) {
+  if (UNLIKELY(is_volatile == kVolatile)) {
+    // There might have been a store before this volatile one so insert StoreStore barrier.
+    GenMemBarrier(kStoreStore);
+  }
+
   // StoreBaseDisp() will emit correct insn for atomic store on arm64
   // assuming r_dest is correctly prepared using RegClassForFieldLoadStore().
-  return StoreBaseDisp(r_base, displacement, r_src, size);
+
+  LIR* store = StoreBaseDispBody(r_base, displacement, r_src, size);
+
+  if (UNLIKELY(is_volatile == kVolatile)) {
+    // A load might follow the volatile store so insert a StoreLoad barrier.
+    GenMemBarrier(kStoreLoad);
+  }
+
+  return store;
 }
 
-LIR* Arm64Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
-                                 OpSize size) {
-  return StoreBaseDispBody(r_base, displacement, r_src, size);
+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) {
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index ec0fb43..f31b670 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -79,6 +79,20 @@
   DCHECK(safepoint_pc->u.m.def_mask->Equals(kEncodeAll));
 }
 
+void Mir2Lir::MarkSafepointPCAfter(LIR* after) {
+  DCHECK(!after->flags.use_def_invalid);
+  after->u.m.def_mask = &kEncodeAll;
+  // As NewLIR0 uses Append, we need to create the LIR by hand.
+  LIR* safepoint_pc = RawLIR(current_dalvik_offset_, kPseudoSafepointPC);
+  if (after->next == nullptr) {
+    DCHECK_EQ(after, last_lir_insn_);
+    AppendLIR(safepoint_pc);
+  } else {
+    InsertLIRAfter(after, safepoint_pc);
+  }
+  DCHECK(safepoint_pc->u.m.def_mask->Equals(kEncodeAll));
+}
+
 /* Remove a LIR from the list. */
 void Mir2Lir::UnlinkLIR(LIR* lir) {
   if (UNLIKELY(lir == first_lir_insn_)) {
@@ -1112,7 +1126,7 @@
 
 /*
  * Insert an LIR instruction after the current instruction, which cannot be the
- * first instruction.
+ * last instruction.
  *
  * current_lir -> new_lir -> old_next
  */
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index e36b592..b00cbeb 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -196,6 +196,15 @@
   }
 }
 
+void Mir2Lir::MarkPossibleNullPointerExceptionAfter(int opt_flags, LIR* after) {
+  if (!cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+    if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
+      return;
+    }
+    MarkSafepointPCAfter(after);
+  }
+}
+
 void Mir2Lir::MarkPossibleStackOverflowException() {
   if (!cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
     MarkSafepointPC(last_lir_insn_);
@@ -506,7 +515,7 @@
     for (int i = 0; i < elems; i++) {
       RegLocation rl_arg = LoadValue(info->args[i], kCoreReg);
       Store32Disp(TargetReg(kRet0),
-                    mirror::Array::DataOffset(component_size).Int32Value() + i * 4, rl_arg.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);
@@ -575,7 +584,8 @@
       // Fast path, static storage base is this method's class
       RegLocation rl_method = LoadCurrMethod();
       r_base = AllocTempRef();
-      LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), r_base);
+      LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), r_base,
+                  kNotVolatile);
       if (IsTemp(rl_method.reg)) {
         FreeTemp(rl_method.reg);
       }
@@ -592,9 +602,10 @@
       LoadCurrMethodDirect(r_method);
       r_base = TargetReg(kArg0);
       LockTemp(r_base);
-      LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base);
+      LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base,
+                  kNotVolatile);
       int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value();
-      LoadRefDisp(r_base, offset_of_field, r_base);
+      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) {
@@ -626,14 +637,12 @@
     } else {
       rl_src = LoadValue(rl_src, reg_class);
     }
-    if (field_info.IsVolatile()) {
-      // There might have been a store before this volatile one so insert StoreStore barrier.
-      GenMemBarrier(kStoreStore);
-      StoreBaseDispVolatile(r_base, field_info.FieldOffset().Int32Value(), rl_src.reg, store_size);
-      // A load might follow the volatile store so insert a StoreLoad barrier.
-      GenMemBarrier(kStoreLoad);
+    if (is_object) {
+      StoreRefDisp(r_base, field_info.FieldOffset().Int32Value(), rl_src.reg,
+                   field_info.IsVolatile() ? kVolatile : kNotVolatile);
     } else {
-      StoreBaseDisp(r_base, field_info.FieldOffset().Int32Value(), rl_src.reg, store_size);
+      StoreBaseDisp(r_base, field_info.FieldOffset().Int32Value(), rl_src.reg, store_size,
+                    field_info.IsVolatile() ? kVolatile : kNotVolatile);
     }
     if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) {
       MarkGCCard(rl_src.reg, r_base);
@@ -672,7 +681,8 @@
       // Fast path, static storage base is this method's class
       RegLocation rl_method  = LoadCurrMethod();
       r_base = AllocTempRef();
-      LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), r_base);
+      LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), r_base,
+                  kNotVolatile);
     } else {
       // Medium path, static storage base in a different class which requires checks that the other
       // class is initialized
@@ -685,9 +695,10 @@
       LoadCurrMethodDirect(r_method);
       r_base = TargetReg(kArg0);
       LockTemp(r_base);
-      LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base);
+      LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base,
+                  kNotVolatile);
       int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value();
-      LoadRefDisp(r_base, offset_of_field, r_base);
+      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) {
@@ -717,14 +728,12 @@
     RegLocation rl_result = EvalLoc(rl_dest, reg_class, true);
 
     int field_offset = field_info.FieldOffset().Int32Value();
-    if (field_info.IsVolatile()) {
-      LoadBaseDispVolatile(r_base, field_offset, rl_result.reg, load_size);
-      // Without context sensitive analysis, we must issue the most conservative barriers.
-      // In this case, either a load or store may follow so we issue both barriers.
-      GenMemBarrier(kLoadLoad);
-      GenMemBarrier(kLoadStore);
+    if (is_object) {
+      LoadRefDisp(r_base, field_offset, rl_result.reg, field_info.IsVolatile() ? kVolatile :
+          kNotVolatile);
     } else {
-      LoadBaseDisp(r_base, field_offset, rl_result.reg, load_size);
+      LoadBaseDisp(r_base, field_offset, rl_result.reg, load_size, field_info.IsVolatile() ?
+          kVolatile : kNotVolatile);
     }
     FreeTemp(r_base);
 
@@ -785,17 +794,15 @@
     GenNullCheck(rl_obj.reg, opt_flags);
     RegLocation rl_result = EvalLoc(rl_dest, reg_class, true);
     int field_offset = field_info.FieldOffset().Int32Value();
-    if (field_info.IsVolatile()) {
-      LoadBaseDispVolatile(rl_obj.reg, field_offset, rl_result.reg, load_size);
-      MarkPossibleNullPointerException(opt_flags);
-      // Without context sensitive analysis, we must issue the most conservative barriers.
-      // In this case, either a load or store may follow so we issue both barriers.
-      GenMemBarrier(kLoadLoad);
-      GenMemBarrier(kLoadStore);
+    LIR* load_lir;
+    if (is_object) {
+      load_lir = LoadRefDisp(rl_obj.reg, field_offset, rl_result.reg, field_info.IsVolatile() ?
+          kVolatile : kNotVolatile);
     } else {
-      LoadBaseDisp(rl_obj.reg, field_offset, rl_result.reg, load_size);
-      MarkPossibleNullPointerException(opt_flags);
+      load_lir = LoadBaseDisp(rl_obj.reg, field_offset, rl_result.reg, load_size,
+                              field_info.IsVolatile() ? kVolatile : kNotVolatile);
     }
+    MarkPossibleNullPointerExceptionAfter(opt_flags, load_lir);
     if (is_long_or_double) {
       StoreValueWide(rl_dest, rl_result);
     } else {
@@ -847,17 +854,15 @@
     }
     GenNullCheck(rl_obj.reg, opt_flags);
     int field_offset = field_info.FieldOffset().Int32Value();
-    if (field_info.IsVolatile()) {
-      // There might have been a store before this volatile one so insert StoreStore barrier.
-      GenMemBarrier(kStoreStore);
-      StoreBaseDispVolatile(rl_obj.reg, field_offset, rl_src.reg, store_size);
-      MarkPossibleNullPointerException(opt_flags);
-      // A load might follow the volatile store so insert a StoreLoad barrier.
-      GenMemBarrier(kStoreLoad);
+    LIR* store;
+    if (is_object) {
+      store = StoreRefDisp(rl_obj.reg, field_offset, rl_src.reg, field_info.IsVolatile() ?
+          kVolatile : kNotVolatile);
     } else {
-      StoreBaseDisp(rl_obj.reg, field_offset, rl_src.reg, store_size);
-      MarkPossibleNullPointerException(opt_flags);
+      store = StoreBaseDisp(rl_obj.reg, field_offset, rl_src.reg, store_size,
+                            field_info.IsVolatile() ? kVolatile : kNotVolatile);
     }
+    MarkPossibleNullPointerExceptionAfter(opt_flags, store);
     if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) {
       MarkGCCard(rl_src.reg, rl_obj.reg);
     }
@@ -916,9 +921,9 @@
     // We're don't need access checks, load type from dex cache
     int32_t dex_cache_offset =
         mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value();
-    LoadRefDisp(rl_method.reg, dex_cache_offset, res_reg);
+    LoadRefDisp(rl_method.reg, dex_cache_offset, res_reg, kNotVolatile);
     int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
-    LoadRefDisp(res_reg, offset_of_type, rl_result.reg);
+    LoadRefDisp(res_reg, offset_of_type, rl_result.reg, kNotVolatile);
     if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file,
         type_idx) || SLOW_TYPE_PATH) {
       // Slow path, at runtime test if type is null and if so initialize
@@ -989,10 +994,10 @@
       LoadCurrMethodDirect(r_method);
     }
     LoadRefDisp(r_method, mirror::ArtMethod::DexCacheStringsOffset().Int32Value(),
-                TargetReg(kArg0));
+                TargetReg(kArg0), kNotVolatile);
 
     // Might call out to helper, which will return resolved string in kRet0
-    LoadRefDisp(TargetReg(kArg0), offset_of_string, TargetReg(kRet0));
+    LoadRefDisp(TargetReg(kArg0), offset_of_string, TargetReg(kRet0), kNotVolatile);
     LIR* fromfast = OpCmpImmBranch(kCondEq, TargetReg(kRet0), 0, NULL);
     LIR* cont = NewLIR0(kPseudoTargetLabel);
 
@@ -1031,8 +1036,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(res_reg, offset_of_string, rl_result.reg);
+    LoadRefDisp(rl_method.reg, mirror::ArtMethod::DexCacheStringsOffset().Int32Value(), res_reg,
+                kNotVolatile);
+    LoadRefDisp(res_reg, offset_of_string, rl_result.reg, kNotVolatile);
     StoreValue(rl_dest, rl_result);
   }
 }
@@ -1133,14 +1139,17 @@
 
   LoadCurrMethodDirect(check_class);
   if (use_declaring_class) {
-    LoadRefDisp(check_class, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), check_class);
-    LoadRefDisp(object.reg,  mirror::Object::ClassOffset().Int32Value(), object_class);
+    LoadRefDisp(check_class, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), check_class,
+                kNotVolatile);
+    LoadRefDisp(object.reg,  mirror::Object::ClassOffset().Int32Value(), object_class,
+                kNotVolatile);
   } else {
     LoadRefDisp(check_class, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
-                check_class);
-    LoadRefDisp(object.reg,  mirror::Object::ClassOffset().Int32Value(), object_class);
+                check_class, kNotVolatile);
+    LoadRefDisp(object.reg,  mirror::Object::ClassOffset().Int32Value(), object_class,
+                kNotVolatile);
     int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
-    LoadRefDisp(check_class, offset_of_type, check_class);
+    LoadRefDisp(check_class, offset_of_type, check_class, kNotVolatile);
   }
 
   LIR* ne_branchover = NULL;
@@ -1196,14 +1205,14 @@
   } else if (use_declaring_class) {
     LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
     LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
-                 class_reg);
+                class_reg, kNotVolatile);
   } else {
     // Load dex cache entry into class_reg (kArg2)
     LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
     LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
-                class_reg);
+                class_reg, kNotVolatile);
     int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
-    LoadRefDisp(class_reg, offset_of_type, class_reg);
+    LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile);
     if (!can_assume_type_is_in_dex_cache) {
       // Need to test presence of type in dex cache at runtime
       LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
@@ -1231,7 +1240,8 @@
 
   /* load object->klass_ */
   DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
-  LoadRefDisp(TargetReg(kArg0),  mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
+  LoadRefDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1),
+              kNotVolatile);
   /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
   LIR* branchover = NULL;
   if (type_known_final) {
@@ -1344,13 +1354,13 @@
     OpRegCopy(class_reg, TargetReg(kRet0));  // Align usage with fast path
   } else if (use_declaring_class) {
     LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
-                class_reg);
+                class_reg, kNotVolatile);
   } else {
     // Load dex cache entry into class_reg (kArg2)
     LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
-                class_reg);
+                class_reg, kNotVolatile);
     int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
-    LoadRefDisp(class_reg, offset_of_type, class_reg);
+    LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile);
     if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx)) {
       // Need to test presence of type in dex cache at runtime
       LIR* hop_branch = OpCmpImmBranch(kCondEq, class_reg, 0, NULL);
@@ -1405,7 +1415,7 @@
 
       if (load_) {
         m2l_->LoadRefDisp(m2l_->TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(),
-                          m2l_->TargetReg(kArg1));
+                          m2l_->TargetReg(kArg1), kNotVolatile);
       }
       if (m2l_->cu_->target64) {
         m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(8, pCheckCast), m2l_->TargetReg(kArg2),
@@ -1436,7 +1446,8 @@
     LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
     /* load object->klass_ */
     DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
-    LoadRefDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
+    LoadRefDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1),
+                kNotVolatile);
 
     LIR* branch2 = OpCmpBranch(kCondNe, TargetReg(kArg1), class_reg, NULL);
     LIR* cont = NewLIR0(kPseudoTargetLabel);
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 638c590..008ebfb 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -501,7 +501,7 @@
   StoreValue(rl_method, rl_src);
   // If Method* has been promoted, explicitly flush
   if (rl_method.location == kLocPhysReg) {
-    StoreRefDisp(TargetReg(kSp), 0, TargetReg(kArg0));
+    StoreRefDisp(TargetReg(kSp), 0, TargetReg(kArg0), kNotVolatile);
   }
 
   if (cu_->num_ins == 0) {
@@ -616,7 +616,8 @@
     case 1:  // Get method->dex_cache_resolved_methods_
       cg->LoadRefDisp(cg->TargetReg(kArg0),
                       mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
-                      cg->TargetReg(kArg0));
+                      cg->TargetReg(kArg0),
+                      kNotVolatile);
       // Set up direct code if known.
       if (direct_code != 0) {
         if (direct_code != static_cast<uintptr_t>(-1)) {
@@ -631,7 +632,8 @@
       CHECK_EQ(cu->dex_file, target_method.dex_file);
       cg->LoadRefDisp(cg->TargetReg(kArg0),
                       ObjArray::OffsetOfElement(target_method.dex_method_index).Int32Value(),
-                      cg->TargetReg(kArg0));
+                      cg->TargetReg(kArg0),
+                      kNotVolatile);
       break;
     case 3:  // Grab the code from the method*
       if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
@@ -676,17 +678,20 @@
       cg->GenNullCheck(cg->TargetReg(kArg1), info->opt_flags);
       // get this->klass_ [use kArg1, set kInvokeTgt]
       cg->LoadRefDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
-                      cg->TargetReg(kInvokeTgt));
+                      cg->TargetReg(kInvokeTgt),
+                      kNotVolatile);
       cg->MarkPossibleNullPointerException(info->opt_flags);
       break;
     case 2:  // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
       cg->LoadRefDisp(cg->TargetReg(kInvokeTgt), mirror::Class::VTableOffset().Int32Value(),
-                      cg->TargetReg(kInvokeTgt));
+                      cg->TargetReg(kInvokeTgt),
+                      kNotVolatile);
       break;
     case 3:  // Get target method [use kInvokeTgt, set kArg0]
       cg->LoadRefDisp(cg->TargetReg(kInvokeTgt),
                       ObjArray::OffsetOfElement(method_idx).Int32Value(),
-                      cg->TargetReg(kArg0));
+                      cg->TargetReg(kArg0),
+                      kNotVolatile);
       break;
     case 4:  // Get the compiled code address [uses kArg0, sets kInvokeTgt]
       if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
@@ -731,19 +736,22 @@
       cg->GenNullCheck(cg->TargetReg(kArg1), info->opt_flags);
       // Get this->klass_ [use kArg1, set kInvokeTgt]
       cg->LoadRefDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
-                      cg->TargetReg(kInvokeTgt));
+                      cg->TargetReg(kInvokeTgt),
+                      kNotVolatile);
       cg->MarkPossibleNullPointerException(info->opt_flags);
       break;
     case 3:  // Get this->klass_->imtable [use kInvokeTgt, set kInvokeTgt]
       // NOTE: native pointer.
       cg->LoadRefDisp(cg->TargetReg(kInvokeTgt), mirror::Class::ImTableOffset().Int32Value(),
-                      cg->TargetReg(kInvokeTgt));
+                      cg->TargetReg(kInvokeTgt),
+                      kNotVolatile);
       break;
     case 4:  // Get target method [use kInvokeTgt, set kArg0]
       // NOTE: native pointer.
       cg->LoadRefDisp(cg->TargetReg(kInvokeTgt),
                        ObjArray::OffsetOfElement(method_idx % ClassLinker::kImtSize).Int32Value(),
-                       cg->TargetReg(kArg0));
+                       cg->TargetReg(kArg0),
+                       kNotVolatile);
       break;
     case 5:  // Get the compiled code address [use kArg0, set kInvokeTgt]
       if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
@@ -967,7 +975,7 @@
       {
         ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
         if (rl_arg.wide) {
-          StoreBaseDisp(TargetReg(kSp), outs_offset, arg_reg, k64);
+          StoreBaseDisp(TargetReg(kSp), outs_offset, arg_reg, k64, kNotVolatile);
           next_use += 2;
         } else {
           Store32Disp(TargetReg(kSp), outs_offset, arg_reg);
@@ -1037,7 +1045,7 @@
       loc = UpdateLocWide(loc);
       if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
         ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-        StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64);
+        StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64, kNotVolatile);
       }
       next_arg += 2;
     } else {
@@ -1307,7 +1315,7 @@
     reg_off = AllocTemp();
     reg_ptr = AllocTempRef();
     Load32Disp(rl_obj.reg, offset_offset, reg_off);
-    LoadRefDisp(rl_obj.reg, value_offset, reg_ptr);
+    LoadRefDisp(rl_obj.reg, value_offset, reg_ptr, kNotVolatile);
   }
   if (rl_idx.is_const) {
     OpRegImm(kOpAdd, reg_off, mir_graph_->ConstantValue(rl_idx.orig_sreg));
@@ -1672,7 +1680,7 @@
     } else {
       RegStorage rl_temp_offset = AllocTemp();
       OpRegRegReg(kOpAdd, rl_temp_offset, rl_object.reg, rl_offset.reg);
-      LoadBaseDisp(rl_temp_offset, 0, rl_result.reg, k64);
+      LoadBaseDisp(rl_temp_offset, 0, rl_result.reg, k64, kNotVolatile);
       FreeTemp(rl_temp_offset);
     }
   } else {
@@ -1719,7 +1727,7 @@
     } else {
       RegStorage rl_temp_offset = AllocTemp();
       OpRegRegReg(kOpAdd, rl_temp_offset, rl_object.reg, rl_offset.reg);
-      StoreBaseDisp(rl_temp_offset, 0, rl_value.reg, k64);
+      StoreBaseDisp(rl_temp_offset, 0, rl_value.reg, k64, kNotVolatile);
       FreeTemp(rl_temp_offset);
     }
   } else {
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index d6f6ea1..bfb77fc 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -66,7 +66,7 @@
       } else {
         // Lives in the frame, need to store.
         ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-        StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), temp_reg, k32);
+        StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), temp_reg, k32, kNotVolatile);
       }
       if (!zero_reg.Valid()) {
         FreeTemp(temp_reg);
@@ -93,7 +93,7 @@
            (rl_src.location == kLocCompilerTemp));
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
     if (rl_src.ref) {
-      LoadRefDisp(TargetReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest);
+      LoadRefDisp(TargetReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest, kNotVolatile);
     } else {
       Load32Disp(TargetReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest);
     }
@@ -126,7 +126,7 @@
     DCHECK((rl_src.location == kLocDalvikFrame) ||
            (rl_src.location == kLocCompilerTemp));
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-    LoadBaseDisp(TargetReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest, k64);
+    LoadBaseDisp(TargetReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest, k64, kNotVolatile);
   }
 }
 
@@ -215,7 +215,7 @@
     def_start = last_lir_insn_;
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
     if (rl_dest.ref) {
-      StoreRefDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg);
+      StoreRefDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg, kNotVolatile);
     } else {
       Store32Disp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg);
     }
@@ -305,7 +305,7 @@
     DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1),
               mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low)));
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-    StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg, k64);
+    StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg, k64, kNotVolatile);
     MarkClean(rl_dest);
     def_end = last_lir_insn_;
     MarkDefWide(rl_dest, def_start, def_end);
@@ -369,7 +369,7 @@
     DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1),
               mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low)));
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-    StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg, k64);
+    StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg, k64, kNotVolatile);
     MarkClean(rl_dest);
     LIR *def_end = last_lir_insn_;
     MarkDefWide(rl_dest, def_start, def_end);
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index e53105f..26ea6a8 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -264,9 +264,9 @@
   int ex_offset = Thread::ExceptionOffset<4>().Int32Value();
   RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
   RegStorage reset_reg = AllocTempRef();
-  LoadRefDisp(rs_rMIPS_SELF, ex_offset, rl_result.reg);
+  LoadRefDisp(rs_rMIPS_SELF, ex_offset, rl_result.reg, kNotVolatile);
   LoadConstant(reset_reg, 0);
-  StoreRefDisp(rs_rMIPS_SELF, ex_offset, reset_reg);
+  StoreRefDisp(rs_rMIPS_SELF, ex_offset, reset_reg, kNotVolatile);
   FreeTemp(reset_reg);
   StoreValue(rl_dest, rl_result);
 }
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 571adac..c0ad916 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -33,20 +33,16 @@
     LIR* CheckSuspendUsingLoad() OVERRIDE;
     RegStorage LoadHelper(ThreadOffset<4> offset) OVERRIDE;
     RegStorage LoadHelper(ThreadOffset<8> offset) OVERRIDE;
-    LIR* LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
-                              OpSize size) OVERRIDE;
     LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
-                      OpSize size) OVERRIDE;
+                      OpSize size, VolatileKind is_volatile) OVERRIDE;
     LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
                          OpSize size) OVERRIDE;
     LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
                              RegStorage r_dest, OpSize size) OVERRIDE;
     LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
     LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
-    LIR* StoreBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_src,
-                               OpSize size) OVERRIDE;
     LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
-                       OpSize size) OVERRIDE;
+                       OpSize size, VolatileKind is_volatile) OVERRIDE;
     LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
                           OpSize size) OVERRIDE;
     LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index beaf6bb..903a770 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -294,7 +294,7 @@
   RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   DCHECK(size == kSignedByte);
-  LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size);
+  LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
   StoreValue(rl_dest, rl_result);
   return true;
 }
@@ -310,7 +310,7 @@
   RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
   DCHECK(size == kSignedByte);
   RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
-  StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size);
+  StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
   return true;
 }
 
@@ -524,7 +524,7 @@
       GenArrayBoundsCheck(rl_index.reg, reg_len);
       FreeTemp(reg_len);
     }
-    LoadBaseDisp(reg_ptr, 0, rl_result.reg, size);
+    LoadBaseDisp(reg_ptr, 0, rl_result.reg, size, kNotVolatile);
 
     FreeTemp(reg_ptr);
     StoreValueWide(rl_dest, rl_result);
@@ -602,7 +602,7 @@
       FreeTemp(reg_len);
     }
 
-    StoreBaseDisp(reg_ptr, 0, rl_src.reg, size);
+    StoreBaseDisp(reg_ptr, 0, rl_src.reg, size, kNotVolatile);
   } else {
     rl_src = LoadValue(rl_src, reg_class);
     if (needs_range_check) {
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index 01b25f92..b49f436 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -546,23 +546,31 @@
   return load;
 }
 
-LIR* MipsMir2Lir::LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
-                                       OpSize size) {
-  DCHECK(size != k64 && size != kDouble);
-  return LoadBaseDisp(r_base, displacement, r_dest, size);
-}
-
 LIR* MipsMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
-                               OpSize size) {
+                               OpSize size, VolatileKind is_volatile) {
+  if (is_volatile == kVolatile) {
+    DCHECK(size != k64 && size != kDouble);
+  }
+
   // TODO: base this on target.
   if (size == kWord) {
     size = k32;
   }
+  LIR* load;
   if (size == k64 || size == kDouble) {
-    return LoadBaseDispBody(r_base, displacement, r_dest.GetLow(), r_dest.GetHigh(), size);
+    load = LoadBaseDispBody(r_base, displacement, r_dest.GetLow(), r_dest.GetHigh(), size);
   } else {
-    return LoadBaseDispBody(r_base, displacement, r_dest, RegStorage::InvalidReg(), size);
+    load = LoadBaseDispBody(r_base, displacement, r_dest, RegStorage::InvalidReg(), size);
   }
+
+  if (UNLIKELY(is_volatile == kVolatile)) {
+    // Without context sensitive analysis, we must issue the most conservative barriers.
+    // In this case, either a load or store may follow so we issue both barriers.
+    GenMemBarrier(kLoadLoad);
+    GenMemBarrier(kLoadStore);
+  }
+
+  return load;
 }
 
 // FIXME: don't split r_dest into 2 containers.
@@ -648,23 +656,31 @@
   return res;
 }
 
-LIR* MipsMir2Lir::StoreBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_src,
-                                        OpSize size) {
-  DCHECK(size != k64 && size != kDouble);
-  return StoreBaseDisp(r_base, displacement, r_src, size);
-}
-
 LIR* MipsMir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
-                                OpSize size) {
+                                OpSize size, VolatileKind is_volatile) {
+  if (is_volatile == kVolatile) {
+    DCHECK(size != k64 && size != kDouble);
+    // There might have been a store before this volatile one so insert StoreStore barrier.
+    GenMemBarrier(kStoreStore);
+  }
+
   // TODO: base this on target.
   if (size == kWord) {
     size = k32;
   }
+  LIR* store;
   if (size == k64 || size == kDouble) {
-    return StoreBaseDispBody(r_base, displacement, r_src.GetLow(), r_src.GetHigh(), size);
+    store = StoreBaseDispBody(r_base, displacement, r_src.GetLow(), r_src.GetHigh(), size);
   } else {
-    return StoreBaseDispBody(r_base, displacement, r_src, RegStorage::InvalidReg(), size);
+    store = StoreBaseDispBody(r_base, displacement, r_src, RegStorage::InvalidReg(), size);
   }
+
+  if (UNLIKELY(is_volatile == kVolatile)) {
+    // A load might follow the volatile store so insert a StoreLoad barrier.
+    GenMemBarrier(kStoreLoad);
+  }
+
+  return store;
 }
 
 LIR* MipsMir2Lir::OpThreadMem(OpKind op, ThreadOffset<4> thread_offset) {
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 1fc4163..5d68187 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -92,7 +92,7 @@
     if (!reg_arg.Valid()) {
       RegStorage new_reg =
           wide ?  AllocTypedTempWide(false, reg_class) : AllocTypedTemp(false, reg_class);
-      LoadBaseDisp(TargetReg(kSp), offset, new_reg, wide ? k64 : k32);
+      LoadBaseDisp(TargetReg(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.
@@ -120,7 +120,7 @@
     // 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(TargetReg(kSp), offset, new_regs, k64);
+      LoadBaseDisp(TargetReg(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,
@@ -193,7 +193,7 @@
       if (reg.Valid()) {
         OpRegCopy(rl_dest.reg, reg);
       } else {
-        LoadBaseDisp(TargetReg(kSp), offset, rl_dest.reg, k64);
+        LoadBaseDisp(TargetReg(kSp), offset, rl_dest.reg, k64, kNotVolatile);
       }
       return;
     }
@@ -211,7 +211,7 @@
       OpRegCopy(rl_dest.reg.GetHigh(), reg_arg_high);
       Load32Disp(TargetReg(kSp), offset, rl_dest.reg.GetLow());
     } else {
-      LoadBaseDisp(TargetReg(kSp), offset, rl_dest.reg, k64);
+      LoadBaseDisp(TargetReg(kSp), offset, rl_dest.reg, k64, kNotVolatile);
     }
   }
 }
@@ -243,14 +243,11 @@
     r_result = wide ? AllocTypedTempWide(rl_dest.fp, reg_class)
                     : AllocTypedTemp(rl_dest.fp, reg_class);
   }
-  if (data.is_volatile) {
-    LoadBaseDispVolatile(reg_obj, data.field_offset, r_result, size);
-    // Without context sensitive analysis, we must issue the most conservative barriers.
-    // In this case, either a load or store may follow so we issue both barriers.
-    GenMemBarrier(kLoadLoad);
-    GenMemBarrier(kLoadStore);
+  if (ref) {
+    LoadRefDisp(reg_obj, data.field_offset, r_result, data.is_volatile ? kVolatile : kNotVolatile);
   } else {
-    LoadBaseDisp(reg_obj, data.field_offset, r_result, size);
+    LoadBaseDisp(reg_obj, data.field_offset, r_result, size, data.is_volatile ? kVolatile :
+        kNotVolatile);
   }
   if (r_result != rl_dest.reg) {
     if (wide) {
@@ -288,14 +285,11 @@
   RegStorage reg_obj = LoadArg(data.object_arg, kRefReg);
   RegisterClass reg_class = RegClassForFieldLoadStore(size, data.is_volatile);
   RegStorage reg_src = LoadArg(data.src_arg, reg_class, wide);
-  if (data.is_volatile) {
-    // There might have been a store before this volatile one so insert StoreStore barrier.
-    GenMemBarrier(kStoreStore);
-    StoreBaseDispVolatile(reg_obj, data.field_offset, reg_src, size);
-    // A load might follow the volatile store so insert a StoreLoad barrier.
-    GenMemBarrier(kStoreLoad);
+  if (ref) {
+    StoreRefDisp(reg_obj, data.field_offset, reg_src, data.is_volatile ? kVolatile : kNotVolatile);
   } else {
-    StoreBaseDisp(reg_obj, data.field_offset, reg_src, size);
+    StoreBaseDisp(reg_obj, data.field_offset, reg_src, size, data.is_volatile ? kVolatile :
+        kNotVolatile);
   }
   if (ref) {
     MarkGCCard(reg_src, reg_obj);
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index f70087d..b07c85e 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -663,6 +663,7 @@
     virtual void Materialize();
     virtual CompiledMethod* GetCompiledMethod();
     void MarkSafepointPC(LIR* inst);
+    void MarkSafepointPCAfter(LIR* after);
     void SetupResourceMasks(LIR* lir);
     void SetMemRefType(LIR* lir, bool is_load, int mem_type);
     void AnnotateDalvikRegAccess(LIR* lir, int reg_id, bool is_load, bool is64bit);
@@ -830,6 +831,7 @@
     void GenArrayBoundsCheck(int32_t index, RegStorage length);
     LIR* GenNullCheck(RegStorage reg);
     void MarkPossibleNullPointerException(int opt_flags);
+    void MarkPossibleNullPointerExceptionAfter(int opt_flags, LIR* after);
     void MarkPossibleStackOverflowException();
     void ForceImplicitNullCheck(RegStorage reg, int opt_flags);
     LIR* GenImmedCheck(ConditionCode c_code, RegStorage reg, int imm_val, ThrowKind kind);
@@ -1007,15 +1009,20 @@
     virtual LIR* LoadConstant(RegStorage r_dest, int value);
     // Natural word size.
     virtual LIR* LoadWordDisp(RegStorage r_base, int displacement, RegStorage r_dest) {
-      return LoadBaseDisp(r_base, displacement, r_dest, kWord);
+      return LoadBaseDisp(r_base, displacement, r_dest, kWord, kNotVolatile);
     }
     // Load 32 bits, regardless of target.
     virtual LIR* Load32Disp(RegStorage r_base, int displacement, RegStorage r_dest)  {
-      return LoadBaseDisp(r_base, displacement, r_dest, k32);
+      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) {
-      return LoadBaseDisp(r_base, displacement, r_dest, kReference);
+    virtual 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) {
+      return LoadBaseIndexed(r_base, r_index, r_dest, 2, kReference);
     }
     // Load Dalvik value with 32-bit memory storage.  If compressed object reference, decompress.
     virtual RegLocation LoadValue(RegLocation rl_src, RegisterClass op_kind);
@@ -1033,15 +1040,20 @@
     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) {
-      return StoreBaseDisp(r_base, displacement, r_src, kWord);
+      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) {
-      return StoreBaseDisp(r_base, displacement, r_src, kReference);
+    virtual 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) {
+      return StoreBaseIndexed(r_base, r_index, r_src, 2, kReference);
     }
     // Store 32 bits, regardless of target.
     virtual LIR* Store32Disp(RegStorage r_base, int displacement, RegStorage r_src) {
-      return StoreBaseDisp(r_base, displacement, r_src, k32);
+      return StoreBaseDisp(r_base, displacement, r_src, k32, kNotVolatile);
     }
 
     /**
@@ -1144,20 +1156,16 @@
     virtual RegStorage LoadHelper(ThreadOffset<4> offset) = 0;
     virtual RegStorage LoadHelper(ThreadOffset<8> offset) = 0;
 
-    virtual LIR* LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
-                                      OpSize size) = 0;
     virtual LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
-                              OpSize size) = 0;
+                              OpSize size, VolatileKind is_volatile) = 0;
     virtual LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
                                  int scale, OpSize size) = 0;
     virtual LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
                                      int displacement, RegStorage r_dest, OpSize size) = 0;
     virtual LIR* LoadConstantNoClobber(RegStorage r_dest, int value) = 0;
     virtual LIR* LoadConstantWide(RegStorage r_dest, int64_t value) = 0;
-    virtual LIR* StoreBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_src,
-                                       OpSize size) = 0;
     virtual LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
-                               OpSize size) = 0;
+                               OpSize size, VolatileKind is_volatile) = 0;
     virtual LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
                                   int scale, OpSize size) = 0;
     virtual LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index 5bb0ee0..60eebe4 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -735,7 +735,7 @@
       }
       int v_reg = mir_graph_->SRegToVReg(info1->SReg());
       ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-      StoreBaseDisp(TargetReg(kSp), VRegOffset(v_reg), reg, k64);
+      StoreBaseDisp(TargetReg(kSp), VRegOffset(v_reg), reg, k64, kNotVolatile);
     }
   } else {
     RegisterInfo* info = GetRegInfo(reg);
@@ -743,7 +743,7 @@
       info->SetIsDirty(false);
       int v_reg = mir_graph_->SRegToVReg(info->SReg());
       ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-      StoreBaseDisp(TargetReg(kSp), VRegOffset(v_reg), reg, k64);
+      StoreBaseDisp(TargetReg(kSp), VRegOffset(v_reg), reg, k64, kNotVolatile);
     }
   }
 }
@@ -755,7 +755,7 @@
     info->SetIsDirty(false);
     int v_reg = mir_graph_->SRegToVReg(info->SReg());
     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-    StoreBaseDisp(TargetReg(kSp), VRegOffset(v_reg), reg, kWord);
+    StoreBaseDisp(TargetReg(kSp), VRegOffset(v_reg), reg, kWord, kNotVolatile);
   }
 }
 
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index f06f08e..3f362f2 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -423,11 +423,11 @@
   { kX86Fld64M,   kMem,     IS_LOAD    | IS_UNARY_OP | REG_USE0 | USE_FP_STACK, { 0x0,  0,    0xDD, 0x00, 0, 0, 0, 0, false }, "Fld64M",   "[!0r,!1d]" },
   { kX86Fstp32M,  kMem,     IS_STORE   | IS_UNARY_OP | REG_USE0 | USE_FP_STACK, { 0x0,  0,    0xD9, 0x00, 0, 3, 0, 0, false }, "Fstps32M", "[!0r,!1d]" },
   { kX86Fstp64M,  kMem,     IS_STORE   | IS_UNARY_OP | REG_USE0 | USE_FP_STACK, { 0x0,  0,    0xDD, 0x00, 0, 3, 0, 0, false }, "Fstpd64M", "[!0r,!1d]" },
-  { kX86Fst32M,   kMem,     IS_STORE   | IS_UNARY_OP | REG_USE0,                { 0x0,  0,    0xD9, 0x00, 0, 2, 0, 0, false }, "Fsts32M",  "[!0r,!1d]" },
-  { kX86Fst64M,   kMem,     IS_STORE   | IS_UNARY_OP | REG_USE0,                { 0x0,  0,    0xDD, 0x00, 0, 2, 0, 0, false }, "Fstd64M",  "[!0r,!1d]" },
+  { kX86Fst32M,   kMem,     IS_STORE   | IS_UNARY_OP | REG_USE0 | USE_FP_STACK, { 0x0,  0,    0xD9, 0x00, 0, 2, 0, 0, false }, "Fsts32M",  "[!0r,!1d]" },
+  { kX86Fst64M,   kMem,     IS_STORE   | IS_UNARY_OP | REG_USE0 | USE_FP_STACK, { 0x0,  0,    0xDD, 0x00, 0, 2, 0, 0, false }, "Fstd64M",  "[!0r,!1d]" },
   { kX86Fprem,    kNullary, NO_OPERAND | USE_FP_STACK,                          { 0xD9, 0,    0xF8, 0,    0, 0, 0, 0, false }, "Fprem64",  "" },
   { kX86Fucompp,  kNullary, NO_OPERAND | USE_FP_STACK,                          { 0xDA, 0,    0xE9, 0,    0, 0, 0, 0, false }, "Fucompp",  "" },
-  { kX86Fstsw16R, kNullary, NO_OPERAND,                                         { 0x9B, 0xDF, 0xE0, 0,    0, 0, 0, 0, false }, "Fstsw16R", "ax" },
+  { kX86Fstsw16R, kNullary, NO_OPERAND | USE_FP_STACK,                          { 0x9B, 0xDF, 0xE0, 0,    0, 0, 0, 0, false }, "Fstsw16R", "ax" },
 
   EXT_0F_ENCODING_MAP(Mova128,    0x66, 0x6F, REG_DEF0),
   { kX86Mova128MR, kMemReg,   IS_STORE | IS_TERTIARY_OP | REG_USE02,  { 0x66, 0, 0x0F, 0x6F, 0, 0, 0, 0, false }, "Mova128MR", "[!0r+!1d],!2r" },
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 28195ab..425caec 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -295,7 +295,8 @@
     setup_method_address_[0] = NewLIR1(kX86StartOfMethod, rs_rX86_ARG0.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, rs_rX86_ARG0, Gen64Bit() ? k64 : k32);
+    setup_method_address_[1] = StoreBaseDisp(rs_rX86_SP, displacement, rs_rX86_ARG0,
+                                             Gen64Bit() ? k64 : k32, kNotVolatile);
   }
 
   FreeTemp(rs_rX86_ARG0);
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index d482e58..70382c7 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -68,20 +68,16 @@
   LIR* CheckSuspendUsingLoad() OVERRIDE;
   RegStorage LoadHelper(ThreadOffset<4> offset) OVERRIDE;
   RegStorage LoadHelper(ThreadOffset<8> offset) OVERRIDE;
-  LIR* LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
-                            OpSize size) OVERRIDE;
   LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
-                    OpSize size) OVERRIDE;
+                    OpSize size, VolatileKind is_volatile) OVERRIDE;
   LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
                        OpSize size) OVERRIDE;
   LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
                            RegStorage r_dest, OpSize size) OVERRIDE;
   LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
   LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
-  LIR* StoreBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_src,
-                             OpSize size) OVERRIDE;
   LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
-                     OpSize size) OVERRIDE;
+                     OpSize size, VolatileKind is_volatile) OVERRIDE;
   LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
                         OpSize size) OVERRIDE;
   LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc
index 5082d60..f854adb 100644
--- a/compiler/dex/quick/x86/fp_x86.cc
+++ b/compiler/dex/quick/x86/fp_x86.cc
@@ -144,7 +144,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(TargetReg(kSp), src_v_reg_offset, rl_src.reg, k64);
+      StoreBaseDisp(TargetReg(kSp), src_v_reg_offset, rl_src.reg, k64, kNotVolatile);
     }
   }
 
@@ -178,7 +178,7 @@
      */
     rl_result = EvalLoc(rl_dest, kFPReg, true);
     if (is_double) {
-      LoadBaseDisp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg, k64);
+      LoadBaseDisp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
 
       StoreFinalValueWide(rl_dest, rl_result);
     } else {
@@ -363,7 +363,8 @@
     } 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(TargetReg(kSp), src1_v_reg_offset, rl_src1.reg, is_double ? k64 : k32);
+      StoreBaseDisp(TargetReg(kSp), src1_v_reg_offset, rl_src1.reg, is_double ? k64 : k32,
+                    kNotVolatile);
     }
   }
 
@@ -373,7 +374,8 @@
       FlushSpecificReg(reg_info);
       ResetDef(rl_src2.reg);
     } else {
-      StoreBaseDisp(TargetReg(kSp), src2_v_reg_offset, rl_src2.reg, is_double ? k64 : k32);
+      StoreBaseDisp(TargetReg(kSp), src2_v_reg_offset, rl_src2.reg, is_double ? k64 : k32,
+                    kNotVolatile);
     }
   }
 
@@ -433,7 +435,7 @@
   if (rl_result.location == kLocPhysReg) {
     rl_result = EvalLoc(rl_dest, kFPReg, true);
     if (is_double) {
-      LoadBaseDisp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg, k64);
+      LoadBaseDisp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
       StoreFinalValueWide(rl_dest, rl_result);
     } else {
       Load32Disp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 2f914c1..fd20a81 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -754,7 +754,7 @@
   RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   // Unaligned access is allowed on x86.
-  LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size);
+  LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
   if (size == k64) {
     StoreValueWide(rl_dest, rl_result);
   } else {
@@ -772,12 +772,12 @@
   if (size == k64) {
     // Unaligned access is allowed on x86.
     RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
-    StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size);
+    StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
   } else {
     DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
     // Unaligned access is allowed on x86.
     RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
-    StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size);
+    StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
   }
   return true;
 }
@@ -1138,7 +1138,7 @@
       NewLIR2(kX86Xor32RR, dest.GetReg(), dest.GetReg());
       break;
     case 1:
-      LoadBaseDisp(rs_rX86_SP, displacement, dest, k32);
+      LoadBaseDisp(rs_rX86_SP, displacement, dest, k32, kNotVolatile);
       break;
     default:
       m = NewLIR4(IS_SIMM8(val) ? kX86Imul32RMI8 : kX86Imul32RMI, dest.GetReg(),
@@ -1294,7 +1294,8 @@
   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_rX86_SP, SRegOffset(rl_src1.s_reg_low) + HIWORD_OFFSET, rs_r1, k32,
+                 kNotVolatile);
   }
 
   if (is_square) {
@@ -1317,7 +1318,8 @@
     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_rX86_SP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, rs_r0, k32,
+                   kNotVolatile);
     }
 
     // EAX <- EAX * 1L  (2H * 1L)
@@ -1350,7 +1352,8 @@
   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_rX86_SP, SRegOffset(rl_src2.s_reg_low) + LOWORD_OFFSET, rs_r0, k32,
+                 kNotVolatile);
   }
 
   // EDX:EAX <- 2L * 1L (double precision)
@@ -2289,21 +2292,21 @@
   if (rl_method.location == kLocPhysReg) {
     if (use_declaring_class) {
       LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
-                   check_class);
+                  check_class, kNotVolatile);
     } else {
       LoadRefDisp(rl_method.reg, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
-                   check_class);
-      LoadRefDisp(check_class, offset_of_type, check_class);
+                  check_class, kNotVolatile);
+      LoadRefDisp(check_class, offset_of_type, check_class, kNotVolatile);
     }
   } else {
     LoadCurrMethodDirect(check_class);
     if (use_declaring_class) {
       LoadRefDisp(check_class, mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
-                   check_class);
+                  check_class, kNotVolatile);
     } else {
       LoadRefDisp(check_class, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
-                   check_class);
-      LoadRefDisp(check_class, offset_of_type, check_class);
+                  check_class, kNotVolatile);
+      LoadRefDisp(check_class, offset_of_type, check_class, kNotVolatile);
     }
   }
 
@@ -2350,16 +2353,16 @@
   } else if (use_declaring_class) {
     LoadValueDirectFixed(rl_src, TargetReg(kArg0));
     LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DeclaringClassOffset().Int32Value(),
-                 class_reg);
+                class_reg, kNotVolatile);
   } else {
     // Load dex cache entry into class_reg (kArg2).
     LoadValueDirectFixed(rl_src, TargetReg(kArg0));
     LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
-                 class_reg);
+                class_reg, kNotVolatile);
     int32_t offset_of_type =
         mirror::Array::DataOffset(sizeof(mirror::HeapReference<mirror::Class*>)).Int32Value() +
         (sizeof(mirror::HeapReference<mirror::Class*>) * type_idx);
-    LoadRefDisp(class_reg, offset_of_type, class_reg);
+    LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile);
     if (!can_assume_type_is_in_dex_cache) {
       // Need to test presence of type in dex cache at runtime.
       LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
@@ -2392,7 +2395,8 @@
 
   /* Load object->klass_. */
   DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
-  LoadRefDisp(TargetReg(kArg0),  mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
+  LoadRefDisp(TargetReg(kArg0),  mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1),
+              kNotVolatile);
   /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class. */
   LIR* branchover = nullptr;
   if (type_known_final) {
@@ -2684,7 +2688,7 @@
     Mir2Lir::GenIntToLong(rl_dest, rl_src);
     return;
   }
-  rl_src = UpdateLoc(rl_src);
+  rl_src = UpdateLocTyped(rl_src, kCoreReg);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (rl_src.location == kLocPhysReg) {
     NewLIR2(kX86MovsxdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 45e5d8a..408a40a 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -1866,7 +1866,7 @@
   StoreValue(rl_method, rl_src);
   // If Method* has been promoted, explicitly flush
   if (rl_method.location == kLocPhysReg) {
-    StoreRefDisp(TargetReg(kSp), 0, TargetReg(kArg0));
+    StoreRefDisp(TargetReg(kSp), 0, TargetReg(kArg0), kNotVolatile);
   }
 
   if (cu_->num_ins == 0) {
@@ -1916,11 +1916,11 @@
       }
       if (need_flush) {
         if (t_loc->wide && t_loc->fp) {
-          StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i), reg, k64);
+          StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i), reg, k64, kNotVolatile);
           // Increment i to skip the next one
           i++;
         } else if (t_loc->wide && !t_loc->fp) {
-          StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i), reg, k64);
+          StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i), reg, k64, kNotVolatile);
           // Increment i to skip the next one
           i++;
         } else {
@@ -2018,14 +2018,14 @@
         loc = UpdateLocWide(loc);
         if (loc.location == kLocPhysReg) {
           ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
-          StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64);
+          StoreBaseDisp(TargetReg(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);
-          StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k32);
+          StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k32, kNotVolatile);
         }
         next_arg++;
       }
@@ -2162,17 +2162,17 @@
           ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
           if (rl_arg.wide) {
             if (rl_arg.location == kLocPhysReg) {
-              StoreBaseDisp(TargetReg(kSp), out_offset, rl_arg.reg, k64);
+              StoreBaseDisp(TargetReg(kSp), out_offset, rl_arg.reg, k64, kNotVolatile);
             } else {
               LoadValueDirectWideFixed(rl_arg, regWide);
-              StoreBaseDisp(TargetReg(kSp), out_offset, regWide, k64);
+              StoreBaseDisp(TargetReg(kSp), out_offset, regWide, k64, kNotVolatile);
             }
           } else {
             if (rl_arg.location == kLocPhysReg) {
-              StoreBaseDisp(TargetReg(kSp), out_offset, rl_arg.reg, k32);
+              StoreBaseDisp(TargetReg(kSp), out_offset, rl_arg.reg, k32, kNotVolatile);
             } else {
               LoadValueDirectFixed(rl_arg, regSingle);
-              StoreBaseDisp(TargetReg(kSp), out_offset, regSingle, k32);
+              StoreBaseDisp(TargetReg(kSp), out_offset, regSingle, k32, kNotVolatile);
             }
           }
         }
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index ac5162e..0352808 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -585,7 +585,7 @@
         // value.
         ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
         res = LoadBaseDisp(rl_method.reg, 256 /* bogus */, RegStorage::FloatSolo64(low_reg_val),
-                           kDouble);
+                           kDouble, kNotVolatile);
         res->target = data_target;
         res->flags.fixup = kFixupLoad;
         store_method_addr_used_ = true;
@@ -756,17 +756,22 @@
   return LoadBaseIndexedDisp(r_base, r_index, scale, 0, r_dest, size);
 }
 
-LIR* X86Mir2Lir::LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest,
-                                      OpSize size) {
+LIR* X86Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
+                              OpSize size, VolatileKind is_volatile) {
   // LoadBaseDisp() will emit correct insn for atomic load on x86
   // assuming r_dest is correctly prepared using RegClassForFieldLoadStore().
-  return LoadBaseDisp(r_base, displacement, r_dest, size);
-}
 
-LIR* X86Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
-                              OpSize size) {
-  return LoadBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_dest,
-                             size);
+  LIR* load = LoadBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_dest,
+                                  size);
+
+  if (UNLIKELY(is_volatile == kVolatile)) {
+    // Without context sensitive analysis, we must issue the most conservative barriers.
+    // In this case, either a load or store may follow so we issue both barriers.
+    GenMemBarrier(kLoadLoad);
+    GenMemBarrier(kLoadStore);
+  }
+
+  return load;
 }
 
 LIR* X86Mir2Lir::StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
@@ -854,20 +859,28 @@
 
 /* store value base base + scaled index. */
 LIR* X86Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
-                      int scale, OpSize size) {
+                                  int scale, OpSize size) {
   return StoreBaseIndexedDisp(r_base, r_index, scale, 0, r_src, size);
 }
 
-LIR* X86Mir2Lir::StoreBaseDispVolatile(RegStorage r_base, int displacement,
-                                       RegStorage r_src, OpSize size) {
+LIR* X86Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size,
+                               VolatileKind is_volatile) {
+  if (UNLIKELY(is_volatile == kVolatile)) {
+    // There might have been a store before this volatile one so insert StoreStore barrier.
+    GenMemBarrier(kStoreStore);
+  }
+
   // StoreBaseDisp() will emit correct insn for atomic store on x86
   // assuming r_dest is correctly prepared using RegClassForFieldLoadStore().
-  return StoreBaseDisp(r_base, displacement, r_src, size);
-}
 
-LIR* X86Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement,
-                               RegStorage r_src, OpSize size) {
-  return StoreBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_src, size);
+  LIR* store = StoreBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_src, size);
+
+  if (UNLIKELY(is_volatile == kVolatile)) {
+    // A load might follow the volatile store so insert a StoreLoad barrier.
+    GenMemBarrier(kStoreLoad);
+  }
+
+  return store;
 }
 
 LIR* X86Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 4a331fc..96625c5 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -697,7 +697,7 @@
     return;
   }
 
-  timings->NewSplit("LoadImageClasses");
+  TimingLogger::ScopedTiming t("LoadImageClasses", timings);
   // Make a first class to load all classes explicitly listed in the file
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
@@ -794,8 +794,7 @@
 
 void CompilerDriver::UpdateImageClasses(TimingLogger* timings) {
   if (IsImage()) {
-    timings->NewSplit("UpdateImageClasses");
-
+    TimingLogger::ScopedTiming t("UpdateImageClasses", timings);
     // Update image_classes_ with classes for objects created by <clinit> methods.
     Thread* self = Thread::Current();
     const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
@@ -1606,11 +1605,11 @@
   if (IsImage()) {
     // For images we resolve all types, such as array, whereas for applications just those with
     // classdefs are resolved by ResolveClassFieldsAndMethods.
-    timings->NewSplit("Resolve Types");
+    TimingLogger::ScopedTiming t("Resolve Types", timings);
     context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_);
   }
 
-  timings->NewSplit("Resolve MethodsAndFields");
+  TimingLogger::ScopedTiming t("Resolve MethodsAndFields", timings);
   context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_);
 }
 
@@ -1672,7 +1671,7 @@
 
 void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file,
                                    ThreadPool* thread_pool, TimingLogger* timings) {
-  timings->NewSplit("Verify Dex File");
+  TimingLogger::ScopedTiming t("Verify Dex File", timings);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool);
   context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
@@ -1765,7 +1764,7 @@
 
 void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
                                        ThreadPool* thread_pool, TimingLogger* timings) {
-  timings->NewSplit("InitializeNoClinit");
+  TimingLogger::ScopedTiming t("InitializeNoClinit", timings);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, thread_pool);
   size_t thread_count;
@@ -1877,7 +1876,7 @@
 
 void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file,
                                     ThreadPool* thread_pool, TimingLogger* timings) {
-  timings->NewSplit("Compile Dex File");
+  TimingLogger::ScopedTiming t("Compile Dex File", timings);
   ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this,
                                      &dex_file, thread_pool);
   context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index ca956aa..5325a68 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -38,12 +38,12 @@
  protected:
   void CompileAll(jobject class_loader) LOCKS_EXCLUDED(Locks::mutator_lock_) {
     TimingLogger timings("CompilerDriverTest::CompileAll", false, false);
-    timings.StartSplit("CompileAll");
+    TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
     compiler_driver_->CompileAll(class_loader,
                                  Runtime::Current()->GetCompileTimeClassPath(class_loader),
                                  &timings);
+    t.NewTiming("MakeAllExecutable");
     MakeAllExecutable(class_loader);
-    timings.EndSplit();
   }
 
   void EnsureCompiled(jobject class_loader, const char* class_name, const char* method,
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 92be147..e8bbaef 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -64,7 +64,7 @@
       jobject class_loader = NULL;
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
       TimingLogger timings("ImageTest::WriteRead", false, false);
-      timings.StartSplit("CompileAll");
+      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.
@@ -75,6 +75,7 @@
       }
       compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
 
+      t.NewTiming("WriteElf");
       ScopedObjectAccess soa(Thread::Current());
       OatWriter oat_writer(class_linker->GetBootClassPath(),
                            0, 0, "", compiler_driver_.get(), &timings);
@@ -84,7 +85,6 @@
                                                 &oat_writer,
                                                 oat_file.GetFile());
       ASSERT_TRUE(success);
-      timings.EndSplit();
     }
   }
   // Workound bug that mcld::Linker::emit closes oat_file by reopening as dup_oat.
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index ca1239f..6e5f19a 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -263,7 +263,11 @@
   }
   mirror::String* string = obj->AsString();
   const uint16_t* utf16_string = string->GetCharArray()->GetData() + string->GetOffset();
-  for (DexCache* dex_cache : Runtime::Current()->GetClassLinker()->GetDexCaches()) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+  size_t dex_cache_count = class_linker->GetDexCacheCount();
+  for (size_t i = 0; i < dex_cache_count; ++i) {
+    DexCache* dex_cache = class_linker->GetDexCache(i);
     const DexFile& dex_file = *dex_cache->GetDexFile();
     const DexFile::StringId* string_id;
     if (UNLIKELY(string->GetLength() == 0)) {
@@ -316,7 +320,10 @@
 
   // Clear references to removed classes from the DexCaches.
   ArtMethod* resolution_method = runtime->GetResolutionMethod();
-  for (DexCache* dex_cache : class_linker->GetDexCaches()) {
+  ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+  size_t dex_cache_count = class_linker->GetDexCacheCount();
+  for (size_t idx = 0; idx < dex_cache_count; ++idx) {
+    DexCache* dex_cache = class_linker->GetDexCache(idx);
     for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
       Class* klass = dex_cache->GetResolvedType(i);
       if (klass != NULL && !IsImageClass(klass)) {
@@ -408,13 +415,27 @@
   Handle<Class> object_array_class(hs.NewHandle(
       class_linker->FindSystemClass(self, "[Ljava/lang/Object;")));
 
-  // build an Object[] of all the DexCaches used in the source_space_
+  // build an Object[] of all the DexCaches used in the source_space_.
+  // Since we can't hold the dex lock when allocating the dex_caches
+  // ObjectArray, we lock the dex lock twice, first to get the number
+  // of dex caches first and then lock it again to copy the dex
+  // caches. We check that the number of dex caches does not change.
+  size_t dex_cache_count;
+  {
+    ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+    dex_cache_count = class_linker->GetDexCacheCount();
+  }
   Handle<ObjectArray<Object>> dex_caches(
       hs.NewHandle(ObjectArray<Object>::Alloc(self, object_array_class.Get(),
-                                              class_linker->GetDexCaches().size())));
-  int i = 0;
-  for (DexCache* dex_cache : class_linker->GetDexCaches()) {
-    dex_caches->Set<false>(i++, dex_cache);
+                                              dex_cache_count)));
+  CHECK(dex_caches.Get() != nullptr) << "Failed to allocate a dex cache array.";
+  {
+    ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+    CHECK_EQ(dex_cache_count, class_linker->GetDexCacheCount())
+        << "The number of dex caches changed.";
+    for (size_t i = 0; i < dex_cache_count; ++i) {
+      dex_caches->Set<false>(i, class_linker->GetDexCache(i));
+    }
   }
 
   // build an Object[] of the roots needed to restore the runtime
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 4590880..e1b6992 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -91,31 +91,31 @@
     size_oat_class_method_offsets_(0) {
   size_t offset;
   {
-    TimingLogger::ScopedSplit split("InitOatHeader", timings);
+    TimingLogger::ScopedTiming split("InitOatHeader", timings);
     offset = InitOatHeader();
   }
   {
-    TimingLogger::ScopedSplit split("InitOatDexFiles", timings);
+    TimingLogger::ScopedTiming split("InitOatDexFiles", timings);
     offset = InitOatDexFiles(offset);
   }
   {
-    TimingLogger::ScopedSplit split("InitDexFiles", timings);
+    TimingLogger::ScopedTiming split("InitDexFiles", timings);
     offset = InitDexFiles(offset);
   }
   {
-    TimingLogger::ScopedSplit split("InitOatClasses", timings);
+    TimingLogger::ScopedTiming split("InitOatClasses", timings);
     offset = InitOatClasses(offset);
   }
   {
-    TimingLogger::ScopedSplit split("InitOatMaps", timings);
+    TimingLogger::ScopedTiming split("InitOatMaps", timings);
     offset = InitOatMaps(offset);
   }
   {
-    TimingLogger::ScopedSplit split("InitOatCode", timings);
+    TimingLogger::ScopedTiming split("InitOatCode", timings);
     offset = InitOatCode(offset);
   }
   {
-    TimingLogger::ScopedSplit split("InitOatCodeDexFiles", timings);
+    TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings);
     offset = InitOatCodeDexFiles(offset);
   }
   size_ = offset;
diff --git a/dalvikvm/Android.mk b/dalvikvm/Android.mk
index 31fcd17..5d838c0 100644
--- a/dalvikvm/Android.mk
+++ b/dalvikvm/Android.mk
@@ -33,7 +33,7 @@
 include external/libcxx/libcxx.mk
 include $(BUILD_EXECUTABLE)
 
-# create symlink for the primary version target.
+# Create symlink for the primary version target.
 include  $(BUILD_SYSTEM)/executable_prefer_symlink.mk
 
 ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$(LOCAL_MODULE)
@@ -50,6 +50,13 @@
 LOCAL_LDFLAGS := -ldl -lpthread
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_IS_HOST_MODULE := true
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := dalvikvm32
+LOCAL_MODULE_STEM_64 := dalvikvm64
 include external/libcxx/libcxx.mk
 include $(BUILD_HOST_EXECUTABLE)
-ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)
+
+ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)32
+ifneq ($(HOST_PREFER_32_BIT),true)
+  ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)64
+endif
\ No newline at end of file
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 38051ea..2d55140 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -367,12 +367,12 @@
 
     driver->CompileAll(class_loader, dex_files, &timings);
 
-    timings.NewSplit("dex2oat OatWriter");
+    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;
     if (!driver->IsImage()) {
-      TimingLogger::ScopedSplit split("Loading image checksum", &timings);
+      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 =
@@ -380,14 +380,13 @@
       image_file_location = image_space->GetImageFilename();
     }
 
-    OatWriter oat_writer(dex_files,
-                         image_file_location_oat_checksum,
+    OatWriter oat_writer(dex_files, image_file_location_oat_checksum,
                          image_file_location_oat_data_begin,
                          image_file_location,
                          driver.get(),
                          &timings);
 
-    TimingLogger::ScopedSplit split("Writing ELF", &timings);
+    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 nullptr;
@@ -1213,7 +1212,7 @@
     return EXIT_FAILURE;
   }
 
-  timings.StartSplit("dex2oat Setup");
+  timings.StartTiming("dex2oat Setup");
   LOG(INFO) << CommandLine();
 
   Runtime::Options runtime_options;
@@ -1448,7 +1447,7 @@
   // Elf32_Phdr.p_vaddr values by the desired base address.
   //
   if (image) {
-    timings.NewSplit("dex2oat ImageWriter");
+    TimingLogger::ScopedTiming t("dex2oat ImageWriter", &timings);
     bool image_creation_success = dex2oat->CreateImageFile(image_filename,
                                                            image_base,
                                                            oat_unstripped,
@@ -1461,6 +1460,7 @@
   }
 
   if (is_host) {
+    timings.EndTiming();
     if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
       LOG(INFO) << Dumpable<TimingLogger>(timings);
     }
@@ -1473,7 +1473,7 @@
   // 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) {
-    timings.NewSplit("dex2oat OatFile copy");
+    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()));
@@ -1508,7 +1508,7 @@
   }
 #endif  // ART_USE_PORTABLE_COMPILER
 
-  timings.EndSplit();
+  timings.EndTiming();
 
   if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
     LOG(INFO) << Dumpable<TimingLogger>(timings);
diff --git a/disassembler/Android.mk b/disassembler/Android.mk
index feacbde..a0abc9e 100644
--- a/disassembler/Android.mk
+++ b/disassembler/Android.mk
@@ -16,7 +16,7 @@
 
 LOCAL_PATH := $(call my-dir)
 
-include art/build/Android.common.mk
+include art/build/Android.common_build.mk
 
 LIBART_DISASSEMBLER_SRC_FILES := \
 	disassembler.cc \
@@ -80,7 +80,7 @@
 
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
 
-  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
+  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
   LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
   include external/libcxx/libcxx.mk
   ifeq ($$(art_target_or_host),target)
diff --git a/oatdump/Android.mk b/oatdump/Android.mk
index ecf6a0b..c35ff85 100644
--- a/oatdump/Android.mk
+++ b/oatdump/Android.mk
@@ -16,11 +16,11 @@
 
 LOCAL_PATH := $(call my-dir)
 
+include art/build/Android.executable.mk
+
 OATDUMP_SRC_FILES := \
 	oatdump.cc
 
-include art/build/Android.executable.mk
-
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
   $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libcutils libart-disassembler,art/disassembler,target,ndebug))
 endif
@@ -34,3 +34,62 @@
 ifeq ($(ART_BUILD_HOST_DEBUG),true)
   $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libartd-disassembler,art/disassembler,host,debug))
 endif
+
+########################################################################
+# oatdump targets
+
+ART_DUMP_OAT_PATH ?= $(OUT_DIR)
+
+OATDUMP := $(HOST_OUT_EXECUTABLES)/oatdump$(HOST_EXECUTABLE_SUFFIX)
+OATDUMPD := $(HOST_OUT_EXECUTABLES)/oatdumpd$(HOST_EXECUTABLE_SUFFIX)
+# TODO: for now, override with debug version for better error reporting
+OATDUMP := $(OATDUMPD)
+
+.PHONY: dump-oat
+dump-oat: dump-oat-core dump-oat-boot
+
+.PHONY: dump-oat-core
+dump-oat-core: dump-oat-core-host dump-oat-core-target
+
+.PHONY: dump-oat-core-host
+ifeq ($(ART_BUILD_HOST),true)
+dump-oat-core-host: $(HOST_CORE_IMG_OUT) $(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)
+	$(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
+endif
+
+.PHONY: dump-oat-boot-$(TARGET_ARCH)
+ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
+dump-oat-boot-$(TARGET_ARCH): $(DEFAULT_DEX_PREOPT_BUILT_IMAGE_FILENAME) $(OATDUMP)
+	$(OATDUMP) --image=$(DEFAULT_DEX_PREOPT_BUILT_IMAGE_LOCATION) \
+	  --output=$(ART_DUMP_OAT_PATH)/boot.$(TARGET_ARCH).oatdump.txt --instruction-set=$(TARGET_ARCH)
+	@echo Output in $(ART_DUMP_OAT_PATH)/boot.$(TARGET_ARCH).oatdump.txt
+endif
+
+ifdef TARGET_2ND_ARCH
+dump-oat-boot-$(TARGET_2ND_ARCH): $(2ND_DEFAULT_DEX_PREOPT_BUILT_IMAGE_FILENAME) $(OATDUMP)
+	$(OATDUMP) --image=$(2ND_DEFAULT_DEX_PREOPT_BUILT_IMAGE_LOCATION) \
+	  --output=$(ART_DUMP_OAT_PATH)/boot.$(TARGET_2ND_ARCH).oatdump.txt --instruction-set=$(TARGET_2ND_ARCH)
+	@echo Output in $(ART_DUMP_OAT_PATH)/boot.$(TARGET_2ND_ARCH).oatdump.txt
+endif
+
+.PHONY: dump-oat-boot
+dump-oat-boot: dump-oat-boot-$(TARGET_ARCH)
+ifdef TARGET_2ND_ARCH
+dump-oat-boot: dump-oat-boot-$(TARGET_2ND_ARCH)
+endif
+
+.PHONY: dump-oat-Calculator
+ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
+dump-oat-Calculator: $(TARGET_OUT_APPS)/Calculator.odex $(DEFAULT_DEX_PREOPT_BUILT_IMAGE) $(OATDUMP)
+	$(OATDUMP) --oat-file=$< --output=$(ART_DUMP_OAT_PATH)/Calculator.oatdump.txt
+	@echo Output in $(ART_DUMP_OAT_PATH)/Calculator.oatdump.txt
+endif
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 992202a..c6ac9ca 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -16,7 +16,7 @@
 
 LOCAL_PATH := $(call my-dir)
 
-include art/build/Android.common.mk
+include art/build/Android.common_build.mk
 
 LIBART_COMMON_SRC_FILES := \
 	atomic.cc.arm \
@@ -268,10 +268,6 @@
 $(info TODOMips64: $(LOCAL_PATH)/Android.mk Add mips64 specific runtime files)
 endif # TARGET_ARCH != mips64
 
-ifeq (,$(filter $(TARGET_ARCH),$(ART_SUPPORTED_ARCH)))
-$(warning unsupported TARGET_ARCH=$(TARGET_ARCH))
-endif
-
 LIBART_HOST_SRC_FILES := \
 	$(LIBART_COMMON_SRC_FILES) \
 	base/logging_linux.cc \
@@ -335,8 +331,8 @@
   art_target_or_host := $(1)
   art_ndebug_or_debug := $(2)
 
-  include $(CLEAR_VARS)
-  LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
+  include $$(CLEAR_VARS)
+  LOCAL_CPP_EXTENSION := $$(ART_CPP_EXTENSION)
   ifeq ($$(art_ndebug_or_debug),ndebug)
     LOCAL_MODULE := libart
   else # debug
@@ -347,13 +343,13 @@
   LOCAL_MODULE_CLASS := SHARED_LIBRARIES
 
   ifeq ($$(art_target_or_host),target)
-    LOCAL_SRC_FILES := $(LIBART_TARGET_SRC_FILES)
-    $(foreach arch,$(ART_SUPPORTED_ARCH),
-      LOCAL_SRC_FILES_$(arch) := $$(LIBART_TARGET_SRC_FILES_$(arch)))
+    LOCAL_SRC_FILES := $$(LIBART_TARGET_SRC_FILES)
+    $$(foreach arch,$$(ART_TARGET_SUPPORTED_ARCH), \
+      $$(eval LOCAL_SRC_FILES_$$(arch) := $$$$(LIBART_TARGET_SRC_FILES_$$(arch))))
   else # host
-    LOCAL_SRC_FILES := $(LIBART_HOST_SRC_FILES)
-    LOCAL_SRC_FILES_32 := $(LIBART_HOST_SRC_FILES_32)
-    LOCAL_SRC_FILES_64 := $(LIBART_HOST_SRC_FILES_64)
+    LOCAL_SRC_FILES := $$(LIBART_HOST_SRC_FILES)
+    LOCAL_SRC_FILES_32 := $$(LIBART_HOST_SRC_FILES_32)
+    LOCAL_SRC_FILES_64 := $$(LIBART_HOST_SRC_FILES_64)
     LOCAL_IS_HOST_MODULE := true
   endif
 
@@ -368,43 +364,43 @@
 
   LOCAL_GENERATED_SOURCES += $$(ENUM_OPERATOR_OUT_GEN)
 
-  LOCAL_CFLAGS := $(LIBART_CFLAGS)
-  LOCAL_LDFLAGS := $(LIBART_LDFLAGS)
+  LOCAL_CFLAGS := $$(LIBART_CFLAGS)
+  LOCAL_LDFLAGS := $$(LIBART_LDFLAGS)
   ifeq ($$(art_target_or_host),target)
-    LOCAL_LDFLAGS += $(LIBART_TARGET_LDFLAGS)
+    LOCAL_LDFLAGS += $$(LIBART_TARGET_LDFLAGS)
   else
-    LOCAL_LDFLAGS += $(LIBART_HOST_LDFLAGS)
+    LOCAL_LDFLAGS += $$(LIBART_HOST_LDFLAGS)
   endif
-  $(foreach arch,$(ART_SUPPORTED_ARCH),
-    LOCAL_LDFLAGS_$(arch) := $$(LIBART_TARGET_LDFLAGS_$(arch)))
+  $$(foreach arch,$$(ART_TARGET_SUPPORTED_ARCH), \
+    $$(eval LOCAL_LDFLAGS_$$(arch) := $$(LIBART_TARGET_LDFLAGS_$$(arch))))
 
   # Clang usage
   ifeq ($$(art_target_or_host),target)
-    $(call set-target-local-clang-vars)
-    $(call set-target-local-cflags-vars,$(2))
+    $$(eval $$(call set-target-local-clang-vars))
+    $$(eval $$(call set-target-local-cflags-vars,$(2)))
     # TODO: Loop with ifeq, ART_TARGET_CLANG
-    ifneq ($$(ART_TARGET_CLANG_$(TARGET_ARCH)),true)
-      LOCAL_SRC_FILES_$(TARGET_ARCH) += $(LIBART_GCC_ONLY_SRC_FILES)
+    ifneq ($$(ART_TARGET_CLANG_$$(TARGET_ARCH)),true)
+      LOCAL_SRC_FILES_$$(TARGET_ARCH) += $$(LIBART_GCC_ONLY_SRC_FILES)
     endif
-    ifneq ($$(ART_TARGET_CLANG_$(TARGET_2ND_ARCH)),true)
-      LOCAL_SRC_FILES_$(TARGET_2ND_ARCH) += $(LIBART_GCC_ONLY_SRC_FILES)
+    ifneq ($$(ART_TARGET_CLANG_$$(TARGET_2ND_ARCH)),true)
+      LOCAL_SRC_FILES_$$(TARGET_2ND_ARCH) += $$(LIBART_GCC_ONLY_SRC_FILES)
     endif
   else # host
-    LOCAL_CLANG := $(ART_HOST_CLANG)
-    ifeq ($(ART_HOST_CLANG),false)
-      LOCAL_SRC_FILES += $(LIBART_GCC_ONLY_SRC_FILES)
+    LOCAL_CLANG := $$(ART_HOST_CLANG)
+    ifeq ($$(ART_HOST_CLANG),false)
+      LOCAL_SRC_FILES += $$(LIBART_GCC_ONLY_SRC_FILES)
     endif
-    LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
+    LOCAL_CFLAGS += $$(ART_HOST_CFLAGS)
     ifeq ($$(art_ndebug_or_debug),debug)
-      LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
-      LOCAL_LDLIBS += $(ART_HOST_DEBUG_LDLIBS)
+      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)
+      LOCAL_CFLAGS += $$(ART_HOST_NON_DEBUG_CFLAGS)
     endif
   endif
 
-  LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
+  LOCAL_C_INCLUDES += $$(ART_C_INCLUDES)
   LOCAL_C_INCLUDES += art/sigchainlib
 
   LOCAL_SHARED_LIBRARIES += liblog libnativehelper
@@ -416,23 +412,24 @@
   else # host
     LOCAL_STATIC_LIBRARIES += libcutils libziparchive-host libz libutils
     LOCAL_LDLIBS += -ldl -lpthread
-    ifeq ($(HOST_OS),linux)
+    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_USE_PORTABLE_COMPILER),true)
+    include $$(LLVM_GEN_INTRINSICS_MK)
     ifeq ($$(art_target_or_host),target)
-      include $(LLVM_DEVICE_BUILD_MK)
+      include $$(LLVM_DEVICE_BUILD_MK)
     else # host
-      include $(LLVM_HOST_BUILD_MK)
+      include $$(LLVM_HOST_BUILD_MK)
     endif
   endif
-  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
-  LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
+#  LOCAL_ADDITIONAL_DEPENDENCIES += $$(LOCAL_PATH)/Android.mk
 
   ifeq ($$(art_target_or_host),target)
-    LOCAL_MODULE_TARGET_ARCH := $(ART_SUPPORTED_ARCH)
+    LOCAL_MODULE_TARGET_ARCH := $$(ART_TARGET_SUPPORTED_ARCH)
   endif
 
   ifeq ($$(art_target_or_host),target)
@@ -441,10 +438,17 @@
       # produce meaningful name resolution.
       LOCAL_STRIP_MODULE := keep_symbols
     endif
-    include $(BUILD_SHARED_LIBRARY)
+    include $$(BUILD_SHARED_LIBRARY)
   else # host
-    include $(BUILD_HOST_SHARED_LIBRARY)
+    include $$(BUILD_HOST_SHARED_LIBRARY)
   endif
+
+  # Clear locally defined variables.
+  GENERATED_SRC_DIR :=
+  ENUM_OPERATOR_OUT_CC_FILES :=
+  ENUM_OPERATOR_OUT_GEN :=
+  art_target_or_host :=
+  art_ndebug_or_debug :=
 endef
 
 # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since
@@ -457,9 +461,28 @@
 endif
 
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
+#  $(error $(call build-libart,target,ndebug))
   $(eval $(call build-libart,target,ndebug))
 endif
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
   $(eval $(call build-libart,target,debug))
 endif
 
+# Clear locally defined variables.
+LOCAL_PATH :=
+LIBART_COMMON_SRC_FILES :=
+LIBART_GCC_ONLY_SRC_FILES :=
+LIBART_TARGET_LDFLAGS :=
+LIBART_HOST_LDFLAGS :=
+LIBART_TARGET_SRC_FILES :=
+LIBART_TARGET_SRC_FILES_arm :=
+LIBART_TARGET_SRC_FILES_arm64 :=
+LIBART_TARGET_SRC_FILES_x86 :=
+LIBART_TARGET_SRC_FILES_x86_64 :=
+LIBART_TARGET_SRC_FILES_mips :=
+LIBART_HOST_SRC_FILES :=
+LIBART_HOST_SRC_FILES_32 :=
+LIBART_HOST_SRC_FILES_64 :=
+LIBART_ENUM_OPERATOR_OUT_HEADER_FILES :=
+LIBART_CFLAGS :=
+build-libart :=
\ No newline at end of file
diff --git a/runtime/arch/arm64/memcmp.S b/runtime/arch/arm64/memcmp.S
new file mode 100644
index 0000000..3d08ecd
--- /dev/null
+++ b/runtime/arch/arm64/memcmp.S
@@ -0,0 +1,155 @@
+/* Copyright (c) 2014, Linaro Limited
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the Linaro nor the
+         names of its contributors may be used to endorse or promote products
+         derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64
+ */
+
+#include <private/bionic_asm.h>
+
+/* Parameters and result.  */
+#define src1		x0
+#define src2		x1
+#define limit		x2
+#define result		x0
+
+/* Internal variables.  */
+#define data1		x3
+#define data1w		w3
+#define data2		x4
+#define data2w		w4
+#define has_nul		x5
+#define diff		x6
+#define endloop		x7
+#define tmp1		x8
+#define tmp2		x9
+#define tmp3		x10
+#define pos		x11
+#define limit_wd	x12
+#define mask		x13
+
+ENTRY(memcmp)
+	cbz	limit, .Lret0
+	eor	tmp1, src1, src2
+	tst	tmp1, #7
+	b.ne	.Lmisaligned8
+	ands	tmp1, src1, #7
+	b.ne	.Lmutual_align
+	add	limit_wd, limit, #7
+	lsr	limit_wd, limit_wd, #3
+	/* Start of performance-critical section  -- one 64B cache line.  */
+.Lloop_aligned:
+	ldr	data1, [src1], #8
+	ldr	data2, [src2], #8
+.Lstart_realigned:
+	subs	limit_wd, limit_wd, #1
+	eor	diff, data1, data2	/* Non-zero if differences found.  */
+	csinv	endloop, diff, xzr, ne	/* Last Dword or differences.  */
+	cbz	endloop, .Lloop_aligned
+	/* End of performance-critical section  -- one 64B cache line.  */
+
+	/* Not reached the limit, must have found a diff.  */
+	cbnz	limit_wd, .Lnot_limit
+
+	/* Limit % 8 == 0 => all bytes significant.  */
+	ands	limit, limit, #7
+	b.eq	.Lnot_limit
+
+	lsl	limit, limit, #3	/* Bits -> bytes.  */
+	mov	mask, #~0
+#ifdef __AARCH64EB__
+	lsr	mask, mask, limit
+#else
+	lsl	mask, mask, limit
+#endif
+	bic	data1, data1, mask
+	bic	data2, data2, mask
+
+	orr	diff, diff, mask
+.Lnot_limit:
+
+#ifndef	__AARCH64EB__
+	rev	diff, diff
+	rev	data1, data1
+	rev	data2, data2
+#endif
+	/* The MS-non-zero bit of DIFF marks either the first bit
+	   that is different, or the end of the significant data.
+	   Shifting left now will bring the critical information into the
+	   top bits.  */
+	clz	pos, diff
+	lsl	data1, data1, pos
+	lsl	data2, data2, pos
+	/* But we need to zero-extend (char is unsigned) the value and then
+	   perform a signed 32-bit subtraction.  */
+	lsr	data1, data1, #56
+	sub	result, data1, data2, lsr #56
+	ret
+
+.Lmutual_align:
+	/* Sources are mutually aligned, but are not currently at an
+	   alignment boundary.  Round down the addresses and then mask off
+	   the bytes that precede the start point.  */
+	bic	src1, src1, #7
+	bic	src2, src2, #7
+	add	limit, limit, tmp1	/* Adjust the limit for the extra.  */
+	lsl	tmp1, tmp1, #3		/* Bytes beyond alignment -> bits.  */
+	ldr	data1, [src1], #8
+	neg	tmp1, tmp1		/* Bits to alignment -64.  */
+	ldr	data2, [src2], #8
+	mov	tmp2, #~0
+#ifdef __AARCH64EB__
+	/* Big-endian.  Early bytes are at MSB.  */
+	lsl	tmp2, tmp2, tmp1	/* Shift (tmp1 & 63).  */
+#else
+	/* Little-endian.  Early bytes are at LSB.  */
+	lsr	tmp2, tmp2, tmp1	/* Shift (tmp1 & 63).  */
+#endif
+	add	limit_wd, limit, #7
+	orr	data1, data1, tmp2
+	orr	data2, data2, tmp2
+	lsr	limit_wd, limit_wd, #3
+	b	.Lstart_realigned
+
+.Lret0:
+	mov	result, #0
+	ret
+
+	.p2align 6
+.Lmisaligned8:
+	sub	limit, limit, #1
+1:
+	/* Perhaps we can do better than this.  */
+	ldrb	data1w, [src1], #1
+	ldrb	data2w, [src2], #1
+	subs	limit, limit, #1
+	ccmp	data1w, data2w, #0, cs	/* NZCV = 0b0000.  */
+	b.eq	1b
+	sub	result, data1, data2
+	ret
+END(memcmp)
diff --git a/runtime/base/histogram-inl.h b/runtime/base/histogram-inl.h
index 7c09999..4c18ce4 100644
--- a/runtime/base/histogram-inl.h
+++ b/runtime/base/histogram-inl.h
@@ -164,18 +164,18 @@
 template <class Value>
 inline void Histogram<Value>::PrintConfidenceIntervals(std::ostream &os, double interval,
                                                        const CumulativeData& data) const {
+  static constexpr size_t kFractionalDigits = 3;
   DCHECK_GT(interval, 0);
   DCHECK_LT(interval, 1.0);
-
-  double per_0 = (1.0 - interval) / 2.0;
-  double per_1 = per_0 + interval;
-  TimeUnit unit = GetAppropriateTimeUnit(Mean() * kAdjust);
-  os << Name() << ":\tSum: ";
-  os << PrettyDuration(Sum() * kAdjust) << " ";
-  os << (interval * 100) << "% C.I. " << FormatDuration(Percentile(per_0, data) * kAdjust, unit);
-  os << "-" << FormatDuration(Percentile(per_1, data) * kAdjust, unit) << " ";
-  os << "Avg: " << FormatDuration(Mean() * kAdjust, unit) << " Max: ";
-  os << FormatDuration(Max() * kAdjust, unit) << "\n";
+  const double per_0 = (1.0 - interval) / 2.0;
+  const double per_1 = per_0 + interval;
+  const TimeUnit unit = GetAppropriateTimeUnit(Mean() * kAdjust);
+  os << Name() << ":\tSum: " << PrettyDuration(Sum() * kAdjust) << " "
+     << (interval * 100) << "% C.I. " << FormatDuration(Percentile(per_0, data) * kAdjust, unit,
+                                                        kFractionalDigits)
+     << "-" << FormatDuration(Percentile(per_1, data) * kAdjust, unit, kFractionalDigits) << " "
+     << "Avg: " << FormatDuration(Mean() * kAdjust, unit, kFractionalDigits) << " Max: "
+     << FormatDuration(Max() * kAdjust, unit, kFractionalDigits) << "\n";
 }
 
 template <class Value>
diff --git a/runtime/base/timing_logger.cc b/runtime/base/timing_logger.cc
index a155002..b6a2aaf 100644
--- a/runtime/base/timing_logger.cc
+++ b/runtime/base/timing_logger.cc
@@ -33,6 +33,8 @@
 
 constexpr size_t CumulativeLogger::kLowMemoryBucketCount;
 constexpr size_t CumulativeLogger::kDefaultBucketCount;
+constexpr size_t TimingLogger::kIndexNotFound;
+
 CumulativeLogger::CumulativeLogger(const std::string& name)
     : name_(name),
       lock_name_("CumulativeLoggerLock" + name),
@@ -66,10 +68,12 @@
 
 void CumulativeLogger::AddLogger(const TimingLogger &logger) {
   MutexLock mu(Thread::Current(), lock_);
-  for (const TimingLogger::SplitTiming& split : logger.GetSplits()) {
-    uint64_t split_time = split.first;
-    const char* split_name = split.second;
-    AddPair(split_name, split_time);
+  TimingLogger::TimingData timing_data(logger.CalculateTimingData());
+  const std::vector<TimingLogger::Timing>& timings = logger.GetTimings();
+  for (size_t i = 0; i < timings.size(); ++i) {
+    if (timings[i].IsStartTiming()) {
+      AddPair(timings[i].GetName(), timing_data.GetExclusiveTime(i));
+    }
   }
   ++iterations_;
 }
@@ -124,166 +128,125 @@
 }
 
 TimingLogger::TimingLogger(const char* name, bool precise, bool verbose)
-    : name_(name), precise_(precise), verbose_(verbose), current_split_(NULL) {
+    : name_(name), precise_(precise), verbose_(verbose) {
 }
 
 void TimingLogger::Reset() {
-  current_split_ = NULL;
-  splits_.clear();
+  timings_.clear();
 }
 
-void TimingLogger::StartSplit(const char* new_split_label) {
-  DCHECK(new_split_label != nullptr) << "Starting split with null label.";
-  TimingLogger::ScopedSplit* explicit_scoped_split =
-      new TimingLogger::ScopedSplit(new_split_label, this);
-  explicit_scoped_split->explicit_ = true;
+void TimingLogger::StartTiming(const char* label) {
+  DCHECK(label != nullptr);
+  timings_.push_back(Timing(NanoTime(), label));
+  ATRACE_BEGIN(label);
 }
 
-void TimingLogger::EndSplit() {
-  CHECK(current_split_ != nullptr) << "Ending a non-existent split.";
-  DCHECK(current_split_->label_ != nullptr);
-  DCHECK(current_split_->explicit_ == true)
-      << "Explicitly ending scoped split: " << current_split_->label_;
-  delete current_split_;
-  // TODO: current_split_ = nullptr;
-}
-
-// Ends the current split and starts the one given by the label.
-void TimingLogger::NewSplit(const char* new_split_label) {
-  if (current_split_ == nullptr) {
-    StartSplit(new_split_label);
-  } else {
-    DCHECK(new_split_label != nullptr) << "New split (" << new_split_label << ") with null label.";
-    current_split_->TailInsertSplit(new_split_label);
-  }
+void TimingLogger::EndTiming() {
+  timings_.push_back(Timing(NanoTime(), nullptr));
+  ATRACE_END();
 }
 
 uint64_t TimingLogger::GetTotalNs() const {
-  uint64_t total_ns = 0;
-  for (const TimingLogger::SplitTiming& split : splits_) {
-    total_ns += split.first;
+  if (timings_.size() < 2) {
+    return 0;
   }
-  return total_ns;
+  return timings_.back().GetTime() - timings_.front().GetTime();
 }
 
-void TimingLogger::Dump(std::ostream &os) const {
+size_t TimingLogger::FindTimingIndex(const char* name, size_t start_idx) const {
+  DCHECK_LT(start_idx, timings_.size());
+  for (size_t i = start_idx; i < timings_.size(); ++i) {
+    if (timings_[i].IsStartTiming() && strcmp(timings_[i].GetName(), name) == 0) {
+      return i;
+    }
+  }
+  return kIndexNotFound;
+}
+
+TimingLogger::TimingData TimingLogger::CalculateTimingData() const {
+  TimingLogger::TimingData ret;
+  ret.data_.resize(timings_.size());
+  std::vector<size_t> open_stack;
+  for (size_t i = 0; i < timings_.size(); ++i) {
+    if (timings_[i].IsEndTiming()) {
+      CHECK(!open_stack.empty()) << "No starting split for ending split at index " << i;
+      size_t open_idx = open_stack.back();
+      uint64_t time = timings_[i].GetTime() - timings_[open_idx].GetTime();
+      ret.data_[open_idx].exclusive_time += time;
+      DCHECK_EQ(ret.data_[open_idx].total_time, 0U);
+      ret.data_[open_idx].total_time += time;
+      // Each open split has exactly one end.
+      open_stack.pop_back();
+      // If there is a parent node, subtract from the exclusive time.
+      if (!open_stack.empty()) {
+        // Note this may go negative, but will work due to 2s complement when we add the value
+        // total time value later.
+        ret.data_[open_stack.back()].exclusive_time -= time;
+      }
+    } else {
+      open_stack.push_back(i);
+    }
+  }
+  CHECK(open_stack.empty()) << "Missing ending for timing "
+      << timings_[open_stack.back()].GetName() << " at index " << open_stack.back();
+  return ret;  // No need to fear, C++11 move semantics are here.
+}
+
+void TimingLogger::Dump(std::ostream &os, const char* indent_string) const {
+  static constexpr size_t kFractionalDigits = 3;
+  TimingLogger::TimingData timing_data(CalculateTimingData());
   uint64_t longest_split = 0;
-  uint64_t total_ns = 0;
-  for (const SplitTiming& split : splits_) {
-    uint64_t split_time = split.first;
-    longest_split = std::max(longest_split, split_time);
-    total_ns += split_time;
+  for (size_t i = 0; i < timings_.size(); ++i) {
+    longest_split = std::max(longest_split, timing_data.GetTotalTime(i));
   }
   // Compute which type of unit we will use for printing the timings.
   TimeUnit tu = GetAppropriateTimeUnit(longest_split);
   uint64_t divisor = GetNsToTimeUnitDivisor(tu);
+  uint64_t mod_fraction = divisor >= 1000 ? divisor / 1000 : 1;
   // Print formatted splits.
-  for (const SplitTiming& split : splits_) {
-    uint64_t split_time = split.first;
-    if (!precise_ && divisor >= 1000) {
-      // Make the fractional part 0.
-      split_time -= split_time % (divisor / 1000);
+  size_t tab_count = 1;
+  os << name_ << " [Exclusive time] [Total time]\n";
+  for (size_t i = 0; i < timings_.size(); ++i) {
+    if (timings_[i].IsStartTiming()) {
+      uint64_t exclusive_time = timing_data.GetExclusiveTime(i);
+      uint64_t total_time = timing_data.GetTotalTime(i);
+      if (!precise_) {
+        // Make the fractional part 0.
+        exclusive_time -= exclusive_time % mod_fraction;
+        total_time -= total_time % mod_fraction;
+      }
+      for (size_t j = 0; j < tab_count; ++j) {
+        os << indent_string;
+      }
+      os << FormatDuration(exclusive_time, tu, kFractionalDigits);
+      // If they are the same, just print one value to prevent spam.
+      if (exclusive_time != total_time) {
+        os << "/" << FormatDuration(total_time, tu, kFractionalDigits);
+      }
+      os << " " << timings_[i].GetName() << "\n";
+      ++tab_count;
+    } else {
+      --tab_count;
     }
-    os << name_ << ": " << std::setw(8) << FormatDuration(split_time, tu) << " "
-       << split.second << "\n";
   }
-  os << name_ << ": end, " << NsToMs(total_ns) << " ms\n";
+  os << name_ << ": end, " << PrettyDuration(GetTotalNs()) << "\n";
 }
 
-TimingLogger::ScopedSplit::ScopedSplit(const char* label, TimingLogger* timing_logger) {
-  DCHECK(label != NULL) << "New scoped split (" << label << ") with null label.";
-  CHECK(timing_logger != NULL) << "New scoped split (" << label << ") without TimingLogger.";
-  timing_logger_ = timing_logger;
-  label_ = label;
-  running_ns_ = 0;
-  explicit_ = false;
-
-  // Stash away the current split and pause it.
-  enclosing_split_ = timing_logger->current_split_;
-  if (enclosing_split_ != NULL) {
-    enclosing_split_->Pause();
+void TimingLogger::Verify() {
+  size_t counts[2] = { 0 };
+  for (size_t i = 0; i < timings_.size(); ++i) {
+    if (i > 0) {
+      CHECK_LE(timings_[i - 1].GetTime(), timings_[i].GetTime());
+    }
+    ++counts[timings_[i].IsStartTiming() ? 0 : 1];
   }
-
-  timing_logger_->current_split_ = this;
-
-  ATRACE_BEGIN(label_);
-
-  start_ns_ = NanoTime();
-  if (timing_logger_->verbose_) {
-    LOG(INFO) << "Begin: " << label_;
-  }
+  CHECK_EQ(counts[0], counts[1]) << "Number of StartTiming and EndTiming doesn't match";
 }
 
-TimingLogger::ScopedSplit::~ScopedSplit() {
-  uint64_t current_time = NanoTime();
-  uint64_t split_time = current_time - start_ns_;
-  running_ns_ += split_time;
-  ATRACE_END();
-
-  if (timing_logger_->verbose_) {
-    LOG(INFO) << "End: " << label_ << " " << PrettyDuration(split_time);
+TimingLogger::~TimingLogger() {
+  if (kIsDebugBuild) {
+    Verify();
   }
-
-  // If one or more enclosed explicitly started splits are not terminated we can
-  // either fail or "unwind" the stack of splits in the timing logger to 'this'
-  // (by deleting the intervening scoped splits). This implements the latter.
-  TimingLogger::ScopedSplit* current = timing_logger_->current_split_;
-  while ((current != NULL) && (current != this)) {
-    delete current;
-    current = timing_logger_->current_split_;
-  }
-
-  CHECK(current != NULL) << "Missing scoped split (" << this->label_
-                           << ") in timing logger (" << timing_logger_->name_ << ").";
-  CHECK(timing_logger_->current_split_ == this);
-
-  timing_logger_->splits_.push_back(SplitTiming(running_ns_, label_));
-
-  timing_logger_->current_split_ = enclosing_split_;
-  if (enclosing_split_ != NULL) {
-    enclosing_split_->Resume();
-  }
-}
-
-
-void TimingLogger::ScopedSplit::TailInsertSplit(const char* label) {
-  // Sleight of hand here: Rather than embedding a new scoped split, we're updating the current
-  // scoped split in place. Basically, it's one way to make explicit and scoped splits compose
-  // well while maintaining the current semantics of NewSplit. An alternative is to push a new split
-  // since we unwind the stack of scoped splits in the scoped split destructor. However, this implies
-  // that the current split is not ended by NewSplit (which calls TailInsertSplit), which would
-  // be different from what we had before.
-
-  uint64_t current_time = NanoTime();
-  uint64_t split_time = current_time - start_ns_;
-  ATRACE_END();
-  timing_logger_->splits_.push_back(std::pair<uint64_t, const char*>(split_time, label_));
-
-  if (timing_logger_->verbose_) {
-    LOG(INFO) << "End: " << label_ << " " << PrettyDuration(split_time) << "\n"
-              << "Begin: " << label;
-  }
-
-  label_ = label;
-  start_ns_ = current_time;
-  running_ns_ = 0;
-
-  ATRACE_BEGIN(label);
-}
-
-void TimingLogger::ScopedSplit::Pause() {
-  uint64_t current_time = NanoTime();
-  uint64_t split_time = current_time - start_ns_;
-  running_ns_ += split_time;
-  ATRACE_END();
-}
-
-
-void TimingLogger::ScopedSplit::Resume() {
-  uint64_t current_time = NanoTime();
-
-  start_ns_ = current_time;
-  ATRACE_BEGIN(label_);
 }
 
 }  // namespace art
diff --git a/runtime/base/timing_logger.h b/runtime/base/timing_logger.h
index 9b55898..b300109 100644
--- a/runtime/base/timing_logger.h
+++ b/runtime/base/timing_logger.h
@@ -77,93 +77,119 @@
 // A timing logger that knows when a split starts for the purposes of logging tools, like systrace.
 class TimingLogger {
  public:
-  // Splits are nanosecond times and split names.
-  typedef std::pair<uint64_t, const char*> SplitTiming;
-  typedef std::vector<SplitTiming> SplitTimings;
+  static constexpr size_t kIndexNotFound = static_cast<size_t>(-1);
+
+  class Timing {
+   public:
+    Timing(uint64_t time, const char* name) : time_(time), name_(name) {
+    }
+    bool IsStartTiming() const {
+      return !IsEndTiming();
+    }
+    bool IsEndTiming() const {
+      return name_ == nullptr;
+    }
+    uint64_t GetTime() const {
+      return time_;
+    }
+    const char* GetName() const {
+      return name_;
+    }
+
+   private:
+    uint64_t time_;
+    const char* name_;
+  };
+
+  // Extra data that is only calculated when you call dump to prevent excess allocation.
+  class TimingData {
+   public:
+    TimingData() = default;
+    TimingData(TimingData&& other) {
+      std::swap(data_, other.data_);
+    }
+    TimingData& operator=(TimingData&& other) {
+      std::swap(data_, other.data_);
+      return *this;
+    }
+    uint64_t GetTotalTime(size_t idx) {
+      return data_[idx].total_time;
+    }
+    uint64_t GetExclusiveTime(size_t idx) {
+      return data_[idx].exclusive_time;
+    }
+
+   private:
+    // Each begin split has a total time and exclusive time. Exclusive time is total time - total
+    // time of children nodes.
+    struct CalculatedDataPoint {
+      CalculatedDataPoint() : total_time(0), exclusive_time(0) {}
+      uint64_t total_time;
+      uint64_t exclusive_time;
+    };
+    std::vector<CalculatedDataPoint> data_;
+    friend class TimingLogger;
+  };
 
   explicit TimingLogger(const char* name, bool precise, bool verbose);
-  ~TimingLogger() {
-    // TODO: DCHECK(current_split_ == nullptr) << "Forgot to end split: " << current_split_->label_;
-  }
-  // Clears current splits and labels.
+  ~TimingLogger();
+  // Verify that all open timings have related closed timings.
+  void Verify();
+  // Clears current timings and labels.
   void Reset();
-
-  // Starts a split
-  void StartSplit(const char* new_split_label);
-
-  // Ends the current split and starts the one given by the label.
-  void NewSplit(const char* new_split_label);
-
-  // Ends the current split and records the end time.
-  void EndSplit();
-
+  // Starts a timing.
+  void StartTiming(const char* new_split_label);
+  // Ends the current timing.
+  void EndTiming();
+  // End the current timing and start a new timing. Usage not recommended.
+  void NewTiming(const char* new_split_label) {
+    EndTiming();
+    StartTiming(new_split_label);
+  }
+  // Returns the total duration of the timings (sum of total times).
   uint64_t GetTotalNs() const;
-
-  void Dump(std::ostream& os) const;
+  // Find the index of a timing by name.
+  size_t FindTimingIndex(const char* name, size_t start_idx) const;
+  void Dump(std::ostream& os, const char* indent_string = "  ") const;
 
   // Scoped timing splits that can be nested and composed with the explicit split
   // starts and ends.
-  class ScopedSplit {
-    public:
-      explicit ScopedSplit(const char* label, TimingLogger* timing_logger);
+  class ScopedTiming {
+   public:
+    explicit ScopedTiming(const char* label, TimingLogger* logger) : logger_(logger) {
+      logger_->StartTiming(label);
+    }
+    ~ScopedTiming() {
+      logger_->EndTiming();
+    }
+    // Closes the current timing and opens a new timing.
+    void NewTiming(const char* label) {
+      logger_->NewTiming(label);
+    }
 
-      ~ScopedSplit();
-
-      friend class TimingLogger;
-
-    private:
-      // Pauses timing of the split, usually due to nesting of another split.
-      void Pause();
-
-      // Resumes timing of the split, usually because a nested split has ended.
-      void Resume();
-
-      // Used by new split to swap splits in place in a ScopedSplit instance.
-      void TailInsertSplit(const char* label);
-
-      // The scoped split immediately enclosing this split. Essentially, we get a
-      // stack of nested splits through this field.
-      ScopedSplit* enclosing_split_;
-
-      // Was this created via TimingLogger's StartSplit?
-      bool explicit_;
-
-      // The split's name.
-      const char* label_;
-
-      // The current split's latest start time. (It may have been paused and restarted.)
-      uint64_t start_ns_;
-
-      // The running time, outside of pauses.
-      uint64_t running_ns_;
-
-      // The timing logger holding this split.
-      TimingLogger* timing_logger_;
-
-      DISALLOW_COPY_AND_ASSIGN(ScopedSplit);
+   private:
+    TimingLogger* const logger_;  // The timing logger which the scoped timing is associated with.
+    DISALLOW_COPY_AND_ASSIGN(ScopedTiming);
   };
 
-  const SplitTimings& GetSplits() const {
-    return splits_;
+  // Return the time points of when each start / end timings start and finish.
+  const std::vector<Timing>& GetTimings() const {
+    return timings_;
   }
 
-  friend class ScopedSplit;
+  TimingData CalculateTimingData() const;
+
  protected:
   // The name of the timing logger.
   const char* const name_;
-
   // Do we want to print the exactly recorded split (true) or round down to the time unit being
   // used (false).
   const bool precise_;
-
   // Verbose logging.
   const bool verbose_;
-
-  // The current scoped split is also the 'top' of the stack of splits in progress.
-  ScopedSplit* current_split_;
-
-  // Splits that have ended.
-  SplitTimings splits_;
+  // Timing points that are either start or end points. For each starting point ret[i] = location
+  // of end split associated with i. If it is and end split ret[i] = i.
+  std::vector<Timing> timings_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TimingLogger);
diff --git a/runtime/base/timing_logger_test.cc b/runtime/base/timing_logger_test.cc
index 0757751..35a73d0 100644
--- a/runtime/base/timing_logger_test.cc
+++ b/runtime/base/timing_logger_test.cc
@@ -26,16 +26,14 @@
 
 TEST_F(TimingLoggerTest, StartEnd) {
   const char* split1name = "First Split";
-  TimingLogger timings("StartEnd", true, false);
-
-  timings.StartSplit(split1name);
-
-  timings.EndSplit();  // Ends split1.
-
-  const TimingLogger::SplitTimings& splits = timings.GetSplits();
-
-  EXPECT_EQ(1U, splits.size());
-  EXPECT_STREQ(splits[0].second, split1name);
+  TimingLogger logger("StartEnd", true, false);
+  logger.StartTiming(split1name);
+  logger.EndTiming();  // Ends split1.
+  const auto& timings = logger.GetTimings();
+  EXPECT_EQ(2U, timings.size());  // Start, End splits
+  EXPECT_TRUE(timings[0].IsStartTiming());
+  EXPECT_STREQ(timings[0].GetName(), split1name);
+  EXPECT_TRUE(timings[1].IsEndTiming());
 }
 
 
@@ -43,56 +41,61 @@
   const char* split1name = "First Split";
   const char* split2name = "Second Split";
   const char* split3name = "Third Split";
-  TimingLogger timings("StartNewEnd", true, false);
-
-  timings.StartSplit(split1name);
-
-  timings.NewSplit(split2name);  // Ends split1.
-
-  timings.NewSplit(split3name);  // Ends split2.
-
-  timings.EndSplit();  // Ends split3.
-
-  const TimingLogger::SplitTimings& splits = timings.GetSplits();
-
-  EXPECT_EQ(3U, splits.size());
-  EXPECT_STREQ(splits[0].second, split1name);
-  EXPECT_STREQ(splits[1].second, split2name);
-  EXPECT_STREQ(splits[2].second, split3name);
+  TimingLogger logger("StartNewEnd", true, false);
+  logger.StartTiming(split1name);
+  logger.NewTiming(split2name);
+  logger.NewTiming(split3name);
+  logger.EndTiming();
+  // Get the timings and verify that they are sane.
+  const auto& timings = logger.GetTimings();
+  // 6 timings in the timing logger at this point.
+  EXPECT_EQ(6U, timings.size());
+  EXPECT_TRUE(timings[0].IsStartTiming());
+  EXPECT_STREQ(timings[0].GetName(), split1name);
+  EXPECT_TRUE(timings[1].IsEndTiming());
+  EXPECT_TRUE(timings[2].IsStartTiming());
+  EXPECT_STREQ(timings[2].GetName(), split2name);
+  EXPECT_TRUE(timings[3].IsEndTiming());
+  EXPECT_TRUE(timings[4].IsStartTiming());
+  EXPECT_STREQ(timings[4].GetName(), split3name);
+  EXPECT_TRUE(timings[5].IsEndTiming());
 }
 
 TEST_F(TimingLoggerTest, StartNewEndNested) {
-  const char* split1name = "First Split";
-  const char* split2name = "Second Split";
-  const char* split3name = "Third Split";
-  const char* split4name = "Fourth Split";
-  const char* split5name = "Fifth Split";
-  TimingLogger timings("StartNewEndNested", true, false);
-
-  timings.StartSplit(split1name);
-
-  timings.NewSplit(split2name);  // Ends split1.
-
-  timings.StartSplit(split3name);
-
-  timings.StartSplit(split4name);
-
-  timings.NewSplit(split5name);  // Ends split4.
-
-  timings.EndSplit();  // Ends split5.
-
-  timings.EndSplit();  // Ends split3.
-
-  timings.EndSplit();  // Ends split2.
-
-  const TimingLogger::SplitTimings& splits = timings.GetSplits();
-
-  EXPECT_EQ(5U, splits.size());
-  EXPECT_STREQ(splits[0].second, split1name);
-  EXPECT_STREQ(splits[1].second, split4name);
-  EXPECT_STREQ(splits[2].second, split5name);
-  EXPECT_STREQ(splits[3].second, split3name);
-  EXPECT_STREQ(splits[4].second, split2name);
+  const char* name1 = "First Split";
+  const char* name2 = "Second Split";
+  const char* name3 = "Third Split";
+  const char* name4 = "Fourth Split";
+  const char* name5 = "Fifth Split";
+  TimingLogger logger("StartNewEndNested", true, false);
+  logger.StartTiming(name1);
+  logger.NewTiming(name2);  // Ends timing1.
+  logger.StartTiming(name3);
+  logger.StartTiming(name4);
+  logger.NewTiming(name5);  // Ends timing4.
+  logger.EndTiming();  // Ends timing5.
+  logger.EndTiming();  // Ends timing3.
+  logger.EndTiming();  // Ends timing2.
+  const auto& timings = logger.GetTimings();
+  EXPECT_EQ(10U, timings.size());
+  size_t idx_1 = logger.FindTimingIndex(name1, 0);
+  size_t idx_2 = logger.FindTimingIndex(name2, 0);
+  size_t idx_3 = logger.FindTimingIndex(name3, 0);
+  size_t idx_4 = logger.FindTimingIndex(name4, 0);
+  size_t idx_5 = logger.FindTimingIndex(name5, 0);
+  size_t idx_6 = logger.FindTimingIndex("Not found", 0);
+  EXPECT_NE(idx_1, TimingLogger::kIndexNotFound);
+  EXPECT_NE(idx_2, TimingLogger::kIndexNotFound);
+  EXPECT_NE(idx_3, TimingLogger::kIndexNotFound);
+  EXPECT_NE(idx_4, TimingLogger::kIndexNotFound);
+  EXPECT_NE(idx_5, TimingLogger::kIndexNotFound);
+  EXPECT_EQ(idx_6, TimingLogger::kIndexNotFound);
+  TimingLogger::TimingData data = logger.CalculateTimingData();
+  EXPECT_STREQ(timings[idx_1].GetName(), name1);
+  EXPECT_STREQ(timings[idx_2].GetName(), name2);
+  EXPECT_STREQ(timings[idx_3].GetName(), name3);
+  EXPECT_STREQ(timings[idx_4].GetName(), name4);
+  EXPECT_STREQ(timings[idx_5].GetName(), name5);
 }
 
 
@@ -101,31 +104,32 @@
   const char* innersplit1 = "Inner Split 1";
   const char* innerinnersplit1 = "Inner Inner Split 1";
   const char* innersplit2 = "Inner Split 2";
-  TimingLogger timings("Scoped", true, false);
-
+  TimingLogger logger("Scoped", true, false);
   {
-      TimingLogger::ScopedSplit outer(outersplit, &timings);
-
+    TimingLogger::ScopedTiming outer(outersplit, &logger);
+    {
+      TimingLogger::ScopedTiming inner1(innersplit1, &logger);
       {
-          TimingLogger::ScopedSplit inner1(innersplit1, &timings);
-
-          {
-              TimingLogger::ScopedSplit innerinner1(innerinnersplit1, &timings);
-          }  // Ends innerinnersplit1.
-      }  // Ends innersplit1.
-
-      {
-          TimingLogger::ScopedSplit inner2(innersplit2, &timings);
-      }  // Ends innersplit2.
+        TimingLogger::ScopedTiming innerinner1(innerinnersplit1, &logger);
+      }  // Ends innerinnersplit1.
+    }  // Ends innersplit1.
+    {
+      TimingLogger::ScopedTiming inner2(innersplit2, &logger);
+    }  // Ends innersplit2.
   }  // Ends outersplit.
-
-  const TimingLogger::SplitTimings& splits = timings.GetSplits();
-
-  EXPECT_EQ(4U, splits.size());
-  EXPECT_STREQ(splits[0].second, innerinnersplit1);
-  EXPECT_STREQ(splits[1].second, innersplit1);
-  EXPECT_STREQ(splits[2].second, innersplit2);
-  EXPECT_STREQ(splits[3].second, outersplit);
+  const size_t idx_outersplit = logger.FindTimingIndex(outersplit, 0);
+  const size_t idx_innersplit1 = logger.FindTimingIndex(innersplit1, 0);
+  const size_t idx_innerinnersplit1 = logger.FindTimingIndex(innerinnersplit1, 0);
+  const size_t idx_innersplit2 = logger.FindTimingIndex(innersplit2, 0);
+  const auto& timings = logger.GetTimings();
+  EXPECT_EQ(8U, timings.size());  // 4 start timings and 4 end timings.
+  EXPECT_GE(timings[idx_innerinnersplit1].GetTime(), timings[idx_innersplit1].GetTime());
+  EXPECT_GE(timings[idx_innersplit2].GetTime(), timings[idx_innersplit1].GetTime());
+  TimingLogger::TimingData data(logger.CalculateTimingData());
+  EXPECT_GE(data.GetTotalTime(idx_outersplit), data.GetTotalTime(idx_innerinnersplit1));
+  EXPECT_GE(data.GetTotalTime(idx_outersplit),
+            data.GetTotalTime(idx_innersplit1) + data.GetTotalTime(idx_innersplit2));
+  EXPECT_GE(data.GetTotalTime(idx_innersplit1), data.GetTotalTime(idx_innerinnersplit1));
 }
 
 
@@ -134,27 +138,24 @@
   const char* innersplit = "Inner Split";
   const char* innerinnersplit1 = "Inner Inner Split 1";
   const char* innerinnersplit2 = "Inner Inner Split 2";
-  TimingLogger timings("Scoped", true, false);
-
-  timings.StartSplit(outersplit);
-
+  TimingLogger logger("Scoped", true, false);
+  logger.StartTiming(outersplit);
   {
-      TimingLogger::ScopedSplit inner(innersplit, &timings);
-
-      timings.StartSplit(innerinnersplit1);
-
-      timings.NewSplit(innerinnersplit2);  // Ends innerinnersplit1.
+    TimingLogger::ScopedTiming inner(innersplit, &logger);
+    logger.StartTiming(innerinnersplit1);
+    logger.NewTiming(innerinnersplit2);  // Ends innerinnersplit1.
+    logger.EndTiming();
   }  // Ends innerinnersplit2, then innersplit.
-
-  timings.EndSplit();  // Ends outersplit.
-
-  const TimingLogger::SplitTimings& splits = timings.GetSplits();
-
-  EXPECT_EQ(4U, splits.size());
-  EXPECT_STREQ(splits[0].second, innerinnersplit1);
-  EXPECT_STREQ(splits[1].second, innerinnersplit2);
-  EXPECT_STREQ(splits[2].second, innersplit);
-  EXPECT_STREQ(splits[3].second, outersplit);
+  logger.EndTiming();  // Ends outersplit.
+  const size_t idx_outersplit = logger.FindTimingIndex(outersplit, 0);
+  const size_t idx_innersplit = logger.FindTimingIndex(innersplit, 0);
+  const size_t idx_innerinnersplit1 = logger.FindTimingIndex(innerinnersplit1, 0);
+  const size_t idx_innerinnersplit2 = logger.FindTimingIndex(innerinnersplit2, 0);
+  const auto& timings = logger.GetTimings();
+  EXPECT_EQ(8U, timings.size());
+  EXPECT_LE(timings[idx_outersplit].GetTime(), timings[idx_innersplit].GetTime());
+  EXPECT_LE(timings[idx_innersplit].GetTime(), timings[idx_innerinnersplit1].GetTime());
+  EXPECT_LE(timings[idx_innerinnersplit1].GetTime(), timings[idx_innerinnersplit2].GetTime());
 }
 
 }  // namespace art
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 16e0ec3..a40a2e4 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -41,7 +41,8 @@
 inline mirror::Class* ClassLinker::FindArrayClass(Thread* self, mirror::Class** element_class) {
   for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
     // Read the cached array class once to avoid races with other threads setting it.
-    mirror::Class* array_class = find_array_class_cache_[i];
+    mirror::Class* array_class = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
+        &find_array_class_cache_[i]);
     if (array_class != nullptr && array_class->GetComponentType() == *element_class) {
       return array_class;
     }
@@ -205,11 +206,20 @@
 inline mirror::Class* ClassLinker::GetClassRoot(ClassRoot class_root)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK(class_roots_ != NULL);
-  mirror::Class* klass = class_roots_->Get(class_root);
+  mirror::ObjectArray<mirror::Class>* class_roots =
+      ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Class>, kWithReadBarrier>(
+          &class_roots_);
+  mirror::Class* klass = class_roots->Get(class_root);
   DCHECK(klass != NULL);
   return klass;
 }
 
+inline mirror::DexCache* ClassLinker::GetDexCache(size_t idx) {
+  dex_lock_.AssertSharedHeld(Thread::Current());
+  DCHECK(idx < dex_caches_.size());
+  return ReadBarrier::BarrierForRoot<mirror::DexCache, kWithReadBarrier>(&dex_caches_[idx]);
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_CLASS_LINKER_INL_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d68aca9..61f94d4 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -408,8 +408,12 @@
   CHECK(java_io_Serializable != NULL);
   // We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to
   // crawl up and explicitly list all of the supers as well.
-  array_iftable_->SetInterface(0, java_lang_Cloneable);
-  array_iftable_->SetInterface(1, java_io_Serializable);
+  {
+    mirror::IfTable* array_iftable =
+        ReadBarrier::BarrierForRoot<mirror::IfTable, kWithReadBarrier>(&array_iftable_);
+    array_iftable->SetInterface(0, java_lang_Cloneable);
+    array_iftable->SetInterface(1, java_io_Serializable);
+  }
 
   // Sanity check Class[] and Object[]'s interfaces.
   CHECK_EQ(java_lang_Cloneable, mirror::Class::GetDirectInterface(self, class_array_class, 0));
@@ -2036,17 +2040,18 @@
   RegisterDexFile(dex_file, dex_cache);
 }
 
-bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) const {
+bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) {
   dex_lock_.AssertSharedHeld(Thread::Current());
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
-    if (dex_caches_[i]->GetDexFile() == &dex_file) {
+    mirror::DexCache* dex_cache = GetDexCache(i);
+    if (dex_cache->GetDexFile() == &dex_file) {
       return true;
     }
   }
   return false;
 }
 
-bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) const {
+bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) {
   ReaderMutexLock mu(Thread::Current(), dex_lock_);
   return IsDexFileRegisteredLocked(dex_file);
 }
@@ -2094,11 +2099,11 @@
   RegisterDexFileLocked(dex_file, dex_cache);
 }
 
-mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) const {
+mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) {
   ReaderMutexLock mu(Thread::Current(), dex_lock_);
   // Search assuming unique-ness of dex file.
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
-    mirror::DexCache* dex_cache = dex_caches_[i];
+    mirror::DexCache* dex_cache = GetDexCache(i);
     if (dex_cache->GetDexFile() == &dex_file) {
       return dex_cache;
     }
@@ -2106,24 +2111,25 @@
   // Search matching by location name.
   std::string location(dex_file.GetLocation());
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
-    mirror::DexCache* dex_cache = dex_caches_[i];
+    mirror::DexCache* dex_cache = GetDexCache(i);
     if (dex_cache->GetDexFile()->GetLocation() == location) {
       return dex_cache;
     }
   }
   // Failure, dump diagnostic and abort.
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
-    mirror::DexCache* dex_cache = dex_caches_[i];
+    mirror::DexCache* dex_cache = GetDexCache(i);
     LOG(ERROR) << "Registered dex file " << i << " = " << dex_cache->GetDexFile()->GetLocation();
   }
   LOG(FATAL) << "Failed to find DexCache for DexFile " << location;
   return NULL;
 }
 
-void ClassLinker::FixupDexCaches(mirror::ArtMethod* resolution_method) const {
+void ClassLinker::FixupDexCaches(mirror::ArtMethod* resolution_method) {
   ReaderMutexLock mu(Thread::Current(), dex_lock_);
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
-    dex_caches_[i]->Fixup(resolution_method);
+    mirror::DexCache* dex_cache = GetDexCache(i);
+    dex_cache->Fixup(resolution_method);
   }
 }
 
@@ -2263,8 +2269,12 @@
 
   // Use the single, global copies of "interfaces" and "iftable"
   // (remember not to free them for arrays).
-  CHECK(array_iftable_ != nullptr);
-  new_class->SetIfTable(array_iftable_);
+  {
+    mirror::IfTable* array_iftable =
+        ReadBarrier::BarrierForRoot<mirror::IfTable, kWithReadBarrier>(&array_iftable_);
+    CHECK(array_iftable != nullptr);
+    new_class->SetIfTable(array_iftable);
+  }
 
   // Inherit access flags from the component type.
   int access_flags = new_class->GetComponentType()->GetAccessFlags();
@@ -2931,8 +2941,9 @@
     mirror::ObjectArray<mirror::Class>* resolved_types = proxy_method->GetDexCacheResolvedTypes();
     ReaderMutexLock mu(Thread::Current(), dex_lock_);
     for (size_t i = 0; i != dex_caches_.size(); ++i) {
-      if (dex_caches_[i]->GetResolvedTypes() == resolved_types) {
-        dex_cache = dex_caches_[i];
+      mirror::DexCache* a_dex_cache = GetDexCache(i);
+      if (a_dex_cache->GetResolvedTypes() == resolved_types) {
+        dex_cache = a_dex_cache;
         break;
       }
     }
@@ -4412,9 +4423,12 @@
   DCHECK(klass != NULL);
   DCHECK(klass->GetClassLoader() == NULL);
 
-  DCHECK(class_roots_ != NULL);
-  DCHECK(class_roots_->Get(class_root) == NULL);
-  class_roots_->Set<false>(class_root, klass);
+  mirror::ObjectArray<mirror::Class>* class_roots =
+      ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Class>, kWithReadBarrier>(
+          &class_roots_);
+  DCHECK(class_roots != NULL);
+  DCHECK(class_roots->Get(class_root) == NULL);
+  class_roots->Set<false>(class_root, klass);
 }
 
 }  // namespace art
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 62b5ea8..7d7bf15 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -28,6 +28,7 @@
 #include "jni.h"
 #include "oat_file.h"
 #include "object_callbacks.h"
+#include "read_barrier.h"
 
 namespace art {
 namespace gc {
@@ -252,12 +253,12 @@
   void VisitRoots(RootCallback* callback, void* arg, VisitRootFlags flags)
       LOCKS_EXCLUDED(dex_lock_);
 
-  mirror::DexCache* FindDexCache(const DexFile& dex_file) const
+  mirror::DexCache* FindDexCache(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool IsDexFileRegistered(const DexFile& dex_file) const
+  bool IsDexFileRegistered(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void FixupDexCaches(mirror::ArtMethod* resolution_method) const
+  void FixupDexCaches(mirror::ArtMethod* resolution_method)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -470,7 +471,7 @@
   void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool IsDexFileRegisteredLocked(const DexFile& dex_file) const
+  bool IsDexFileRegisteredLocked(const DexFile& dex_file)
       SHARED_LOCKS_REQUIRED(dex_lock_, Locks::mutator_lock_);
 
   bool InitializeClass(Handle<mirror::Class> klass, bool can_run_clinit,
@@ -532,9 +533,14 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // For use by ImageWriter to find DexCaches for its roots
-  const std::vector<mirror::DexCache*>& GetDexCaches() {
-    return dex_caches_;
+  ReaderWriterMutex* DexLock()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCK_RETURNED(dex_lock_) {
+    return &dex_lock_;
   }
+  size_t GetDexCacheCount() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, dex_lock_) {
+    return dex_caches_.size();
+  }
+  mirror::DexCache* GetDexCache(size_t idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, dex_lock_);
 
   const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_)
@@ -643,9 +649,12 @@
   void SetClassRoot(ClassRoot class_root, mirror::Class* klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  mirror::ObjectArray<mirror::Class>* GetClassRoots() {
-    DCHECK(class_roots_ != NULL);
-    return class_roots_;
+  mirror::ObjectArray<mirror::Class>* GetClassRoots() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ObjectArray<mirror::Class>* class_roots =
+        ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Class>, kWithReadBarrier>(
+            &class_roots_);
+    DCHECK(class_roots != NULL);
+    return class_roots;
   }
 
   static const char* class_roots_descriptors_[];
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index bac212a..044d08b 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -273,7 +273,7 @@
     } else {
       filename += "/data/nativetest/art/";
     }
-    filename += "art-test-dex-";
+    filename += "art-gtest-";
     filename += name;
     filename += ".jar";
     std::string error_msg;
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index 656c55b..09fb97a 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -529,7 +529,7 @@
 }
 
 size_t RosAlloc::Free(Thread* self, void* ptr) {
-  WriterMutexLock rmu(self, bulk_free_lock_);
+  ReaderMutexLock rmu(self, bulk_free_lock_);
   return FreeInternal(self, ptr);
 }
 
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index 8622fd6..46d79bf 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -101,6 +101,7 @@
 }
 
 void GarbageCollector::SwapBitmaps() {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   // Swap the live and mark bitmaps for each alloc space. This is needed since sweep re-swaps
   // these bitmaps. The bitmap swapping is an optimization so that we do not need to clear the live
   // bits of dead objects in the live bitmap.
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index ebd1738..4044852 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -49,7 +49,6 @@
 #include "thread-inl.h"
 #include "thread_list.h"
 
-using ::art::mirror::Class;
 using ::art::mirror::Object;
 
 namespace art {
@@ -57,7 +56,7 @@
 namespace collector {
 
 void MarkCompact::BindBitmaps() {
-  GetTimings()->StartSplit("BindBitmaps");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
   // Mark all of the spaces we never collect as immune.
   for (const auto& space : GetHeap()->GetContinuousSpaces()) {
@@ -66,7 +65,6 @@
       CHECK(immune_region_.AddContinuousSpace(space)) << "Failed to add space " << *space;
     }
   }
-  GetTimings()->EndSplit();
 }
 
 MarkCompact::MarkCompact(Heap* heap, const std::string& name_prefix)
@@ -120,7 +118,7 @@
 };
 
 void MarkCompact::CalculateObjectForwardingAddresses() {
-  GetTimings()->NewSplit(__FUNCTION__);
+  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());
   // Visit all the marked objects in the bitmap.
@@ -131,7 +129,7 @@
 }
 
 void MarkCompact::InitializePhase() {
-  TimingLogger::ScopedSplit split("InitializePhase", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   mark_stack_ = heap_->GetMarkStack();
   DCHECK(mark_stack_ != nullptr);
   immune_region_.Reset();
@@ -143,7 +141,6 @@
 }
 
 void MarkCompact::ProcessReferences(Thread* self) {
-  TimingLogger::ScopedSplit split("ProcessReferences", GetTimings());
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   heap_->GetReferenceProcessor()->ProcessReferences(
       false, GetTimings(), GetCurrentIteration()->GetClearSoftReferences(),
@@ -187,6 +184,7 @@
 }
 
 void MarkCompact::MarkingPhase() {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   Thread* self = Thread::Current();
   // Bitmap which describes which objects we have to move.
   objects_before_forwarding_.reset(accounting::ContinuousSpaceBitmap::Create(
@@ -195,21 +193,22 @@
   objects_with_lockword_.reset(accounting::ContinuousSpaceBitmap::Create(
       "objects with lock words", space_->Begin(), space_->Size()));
   CHECK(Locks::mutator_lock_->IsExclusiveHeld(self));
-  TimingLogger::ScopedSplit split("MarkingPhase", GetTimings());
   // Assume the cleared space is already empty.
   BindBitmaps();
+  t.NewTiming("ProcessCards");
   // Process dirty cards and add dirty cards to mod-union tables.
   heap_->ProcessCards(GetTimings(), false);
   // Clear the whole card table since we can not Get any additional dirty cards during the
   // paused GC. This saves memory but only works for pause the world collectors.
-  GetTimings()->NewSplit("ClearCardTable");
+  t.NewTiming("ClearCardTable");
   heap_->GetCardTable()->ClearCardTable();
   // 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.
-  GetTimings()->NewSplit("SwapStacks");
   if (kUseThreadLocalAllocationStack) {
+    t.NewTiming("RevokeAllThreadLocalAllocationStacks");
     heap_->RevokeAllThreadLocalAllocationStacks(self);
   }
+  t.NewTiming("SwapStacks");
   heap_->SwapStacks(self);
   {
     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
@@ -227,21 +226,20 @@
   // Revoke buffers before measuring how many objects were moved since the TLABs need to be revoked
   // before they are properly counted.
   RevokeAllThreadLocalBuffers();
-  GetTimings()->StartSplit("PreSweepingGcVerification");
   // Disabled due to an issue where we have objects in the bump pointer space which reference dead
   // objects.
   // heap_->PreSweepingGcVerification(this);
-  GetTimings()->EndSplit();
 }
 
 void MarkCompact::UpdateAndMarkModUnion() {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   for (auto& space : heap_->GetContinuousSpaces()) {
     // If the space is immune then we need to mark the references to other spaces.
     if (immune_region_.ContainsSpace(space)) {
       accounting::ModUnionTable* table = heap_->FindModUnionTableFromSpace(space);
       if (table != nullptr) {
         // TODO: Improve naming.
-        TimingLogger::ScopedSplit split(
+        TimingLogger::ScopedTiming t(
             space->IsZygoteSpace() ? "UpdateAndMarkZygoteModUnionTable" :
                                      "UpdateAndMarkImageModUnionTable", GetTimings());
         table->UpdateAndMarkReferences(MarkHeapReferenceCallback, this);
@@ -251,28 +249,28 @@
 }
 
 void MarkCompact::MarkReachableObjects() {
-  GetTimings()->StartSplit("MarkStackAsLive");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   accounting::ObjectStack* live_stack = heap_->GetLiveStack();
-  heap_->MarkAllocStackAsLive(live_stack);
+  {
+    TimingLogger::ScopedTiming t2("MarkAllocStackAsLive", GetTimings());
+    heap_->MarkAllocStackAsLive(live_stack);
+  }
   live_stack->Reset();
   // Recursively process the mark stack.
   ProcessMarkStack();
-  GetTimings()->EndSplit();
 }
 
 void MarkCompact::ReclaimPhase() {
-  TimingLogger::ScopedSplit split("ReclaimPhase", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
   // Reclaim unmarked objects.
   Sweep(false);
   // Swap the live and mark bitmaps for each space which we modified space. This is an
   // optimization that enables us to not clear live bits inside of the sweep. Only swaps unbound
   // bitmaps.
-  GetTimings()->StartSplit("SwapBitmapsAndUnBindBitmaps");
   SwapBitmaps();
   GetHeap()->UnBindBitmaps();  // Unbind the live and mark bitmaps.
   Compact();
-  GetTimings()->EndSplit();
 }
 
 void MarkCompact::ResizeMarkStack(size_t new_size) {
@@ -340,7 +338,7 @@
 };
 
 void MarkCompact::UpdateReferences() {
-  GetTimings()->NewSplit(__FUNCTION__);
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   Runtime* runtime = Runtime::Current();
   // Update roots.
   runtime->VisitRoots(UpdateRootCallback, this);
@@ -350,7 +348,7 @@
     accounting::ModUnionTable* table = heap_->FindModUnionTableFromSpace(space);
     if (table != nullptr) {
       // TODO: Improve naming.
-      TimingLogger::ScopedSplit split(
+      TimingLogger::ScopedTiming t(
           space->IsZygoteSpace() ? "UpdateZygoteModUnionTableReferences" :
                                    "UpdateImageModUnionTableReferences",
                                    GetTimings());
@@ -381,7 +379,7 @@
 }
 
 void MarkCompact::Compact() {
-  GetTimings()->NewSplit(__FUNCTION__);
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   CalculateObjectForwardingAddresses();
   UpdateReferences();
   MoveObjects();
@@ -389,7 +387,7 @@
   int64_t objects_freed = space_->GetObjectsAllocated() - live_objects_in_space_;
   int64_t bytes_freed = reinterpret_cast<int64_t>(space_->End()) -
       reinterpret_cast<int64_t>(bump_pointer_);
-  GetTimings()->NewSplit("RecordFree");
+  t.NewTiming("RecordFree");
   space_->RecordFree(objects_freed, bytes_freed);
   RecordFree(ObjectBytePair(objects_freed, bytes_freed));
   space_->SetEnd(bump_pointer_);
@@ -399,7 +397,7 @@
 
 // Marks all objects in the root set.
 void MarkCompact::MarkRoots() {
-  GetTimings()->NewSplit("MarkRoots");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   Runtime::Current()->VisitRoots(MarkRootCallback, this);
 }
 
@@ -483,9 +481,8 @@
 }
 
 void MarkCompact::SweepSystemWeaks() {
-  GetTimings()->StartSplit("SweepSystemWeaks");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   Runtime::Current()->SweepSystemWeaks(IsMarkedCallback, this);
-  GetTimings()->EndSplit();
 }
 
 bool MarkCompact::ShouldSweepSpace(space::ContinuousSpace* space) const {
@@ -523,7 +520,7 @@
 }
 
 void MarkCompact::MoveObjects() {
-  GetTimings()->NewSplit(__FUNCTION__);
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   // Move the objects in the before forwarding bitmap.
   MoveObjectVisitor visitor(this);
   objects_before_forwarding_->VisitMarkedRange(reinterpret_cast<uintptr_t>(space_->Begin()),
@@ -533,15 +530,15 @@
 }
 
 void MarkCompact::Sweep(bool swap_bitmaps) {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   DCHECK(mark_stack_->IsEmpty());
-  TimingLogger::ScopedSplit split("Sweep", GetTimings());
   for (const auto& space : GetHeap()->GetContinuousSpaces()) {
     if (space->IsContinuousMemMapAllocSpace()) {
       space::ContinuousMemMapAllocSpace* alloc_space = space->AsContinuousMemMapAllocSpace();
       if (!ShouldSweepSpace(alloc_space)) {
         continue;
       }
-      TimingLogger::ScopedSplit split(
+      TimingLogger::ScopedTiming t(
           alloc_space->IsZygoteSpace() ? "SweepZygoteSpace" : "SweepAllocSpace", GetTimings());
       RecordFree(alloc_space->Sweep(swap_bitmaps));
     }
@@ -550,7 +547,7 @@
 }
 
 void MarkCompact::SweepLargeObjects(bool swap_bitmaps) {
-  TimingLogger::ScopedSplit split("SweepLargeObjects", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   RecordFreeLOS(heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps));
 }
 
@@ -590,13 +587,12 @@
 
 // Scan anything that's on the mark stack.
 void MarkCompact::ProcessMarkStack() {
-  GetTimings()->StartSplit("ProcessMarkStack");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   while (!mark_stack_->IsEmpty()) {
     Object* obj = mark_stack_->PopBack();
     DCHECK(obj != nullptr);
     ScanObject(obj);
   }
-  GetTimings()->EndSplit();
 }
 
 void MarkCompact::SetSpace(space::BumpPointerSpace* space) {
@@ -605,7 +601,7 @@
 }
 
 void MarkCompact::FinishPhase() {
-  TimingLogger::ScopedSplit split("FinishPhase", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   space_ = nullptr;
   CHECK(mark_stack_->IsEmpty());
   mark_stack_->Reset();
@@ -618,9 +614,8 @@
 }
 
 void MarkCompact::RevokeAllThreadLocalBuffers() {
-  GetTimings()->StartSplit("(Paused)RevokeAllThreadLocalBuffers");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   GetHeap()->RevokeAllThreadLocalBuffers();
-  GetTimings()->EndSplit();
 }
 
 }  // namespace collector
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index d08796b..7e97b3b 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -81,7 +81,7 @@
 static constexpr bool kRevokeRosAllocThreadLocalBuffersAtCheckpoint = true;
 
 void MarkSweep::BindBitmaps() {
-  GetTimings()->StartSplit("BindBitmaps");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
   // Mark all of the spaces we never collect as immune.
   for (const auto& space : GetHeap()->GetContinuousSpaces()) {
@@ -89,7 +89,6 @@
       CHECK(immune_region_.AddContinuousSpace(space)) << "Failed to add space " << *space;
     }
   }
-  GetTimings()->EndSplit();
 }
 
 MarkSweep::MarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix)
@@ -110,7 +109,7 @@
 }
 
 void MarkSweep::InitializePhase() {
-  TimingLogger::ScopedSplit split("InitializePhase", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   mark_stack_ = heap_->GetMarkStack();
   DCHECK(mark_stack_ != nullptr);
   immune_region_.Reset();
@@ -170,7 +169,6 @@
 }
 
 void MarkSweep::ProcessReferences(Thread* self) {
-  TimingLogger::ScopedSplit split("ProcessReferences", GetTimings());
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   GetHeap()->GetReferenceProcessor()->ProcessReferences(
       true, GetTimings(), GetCurrentIteration()->GetClearSoftReferences(),
@@ -178,7 +176,7 @@
 }
 
 void MarkSweep::PausePhase() {
-  TimingLogger::ScopedSplit split("(Paused)PausePhase", GetTimings());
+  TimingLogger::ScopedTiming t("(Paused)PausePhase", GetTimings());
   Thread* self = Thread::Current();
   Locks::mutator_lock_->AssertExclusiveHeld(self);
   if (IsConcurrent()) {
@@ -190,7 +188,7 @@
     RecursiveMarkDirtyObjects(true, accounting::CardTable::kCardDirty);
   }
   {
-    TimingLogger::ScopedSplit split("SwapStacks", GetTimings());
+    TimingLogger::ScopedTiming t2("SwapStacks", GetTimings());
     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
     heap_->SwapStacks(self);
     live_stack_freeze_size_ = heap_->GetLiveStack()->Size();
@@ -198,9 +196,7 @@
     // stacks and don't want anybody to allocate into the live stack.
     RevokeAllThreadLocalAllocationStacks(self);
   }
-  GetTimings()->StartSplit("PreSweepingGcVerification");
   heap_->PreSweepingGcVerification(this);
-  GetTimings()->EndSplit();
   // Disallow new system weaks to prevent a race which occurs when someone adds a new system
   // weak before we sweep them. Since this new system weak may not be marked, the GC may
   // incorrectly sweep it. This also fixes a race where interning may attempt to return a strong
@@ -214,6 +210,7 @@
 void MarkSweep::PreCleanCards() {
   // Don't do this for non concurrent GCs since they don't have any dirty cards.
   if (kPreCleanCards && IsConcurrent()) {
+    TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
     Thread* self = Thread::Current();
     CHECK(!Locks::mutator_lock_->IsExclusiveHeld(self));
     // Process dirty cards and add dirty cards to mod union tables, also ages cards.
@@ -243,14 +240,14 @@
 
 void MarkSweep::RevokeAllThreadLocalAllocationStacks(Thread* self) {
   if (kUseThreadLocalAllocationStack) {
-    GetTimings()->NewSplit("RevokeAllThreadLocalAllocationStacks");
+    TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
     Locks::mutator_lock_->AssertExclusiveHeld(self);
     heap_->RevokeAllThreadLocalAllocationStacks(self);
   }
 }
 
 void MarkSweep::MarkingPhase() {
-  TimingLogger::ScopedSplit split("MarkingPhase", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   Thread* self = Thread::Current();
   BindBitmaps();
   FindDefaultSpaceBitmap();
@@ -268,7 +265,7 @@
     if (immune_region_.ContainsSpace(space)) {
       const char* name = space->IsZygoteSpace() ? "UpdateAndMarkZygoteModUnionTable" :
           "UpdateAndMarkImageModUnionTable";
-      TimingLogger::ScopedSplit split(name, GetTimings());
+      TimingLogger::ScopedTiming t(name, GetTimings());
       accounting::ModUnionTable* mod_union_table = heap_->FindModUnionTableFromSpace(space);
       CHECK(mod_union_table != nullptr);
       mod_union_table->UpdateAndMarkReferences(MarkHeapReferenceCallback, this);
@@ -283,7 +280,7 @@
 }
 
 void MarkSweep::ReclaimPhase() {
-  TimingLogger::ScopedSplit split("ReclaimPhase", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   Thread* self = Thread::Current();
   // Process the references concurrently.
   ProcessReferences(self);
@@ -291,25 +288,19 @@
   Runtime::Current()->AllowNewSystemWeaks();
   {
     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-
     // Reclaim unmarked objects.
     Sweep(false);
-
     // Swap the live and mark bitmaps for each space which we modified space. This is an
     // optimization that enables us to not clear live bits inside of the sweep. Only swaps unbound
     // bitmaps.
-    GetTimings()->StartSplit("SwapBitmaps");
     SwapBitmaps();
-    GetTimings()->EndSplit();
-
     // Unbind the live and mark bitmaps.
-    TimingLogger::ScopedSplit split("UnBindBitmaps", GetTimings());
     GetHeap()->UnBindBitmaps();
   }
 }
 
 void MarkSweep::FindDefaultSpaceBitmap() {
-  TimingLogger::ScopedSplit split("FindDefaultMarkBitmap", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   for (const auto& space : GetHeap()->GetContinuousSpaces()) {
     accounting::ContinuousSpaceBitmap* bitmap = space->GetMarkBitmap();
     // We want to have the main space instead of non moving if possible.
@@ -506,11 +497,10 @@
 }
 
 void MarkSweep::MarkRoots(Thread* self) {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
     // If we exclusively hold the mutator lock, all threads must be suspended.
-    GetTimings()->StartSplit("MarkRoots");
     Runtime::Current()->VisitRoots(MarkRootCallback, this);
-    GetTimings()->EndSplit();
     RevokeAllThreadLocalAllocationStacks(self);
   } else {
     MarkRootsCheckpoint(self, kRevokeRosAllocThreadLocalBuffersAtCheckpoint);
@@ -522,16 +512,14 @@
 }
 
 void MarkSweep::MarkNonThreadRoots() {
-  GetTimings()->StartSplit("MarkNonThreadRoots");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   Runtime::Current()->VisitNonThreadRoots(MarkRootCallback, this);
-  GetTimings()->EndSplit();
 }
 
 void MarkSweep::MarkConcurrentRoots(VisitRootFlags flags) {
-  GetTimings()->StartSplit("MarkConcurrentRoots");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   // Visit all runtime roots and clear dirty flags.
   Runtime::Current()->VisitConcurrentRoots(MarkRootCallback, this, flags);
-  GetTimings()->EndSplit();
 }
 
 class ScanObjectVisitor {
@@ -752,7 +740,8 @@
     Thread* self = Thread::Current();
     // Can't have a different split for each space since multiple spaces can have their cards being
     // scanned at the same time.
-    GetTimings()->StartSplit(paused ? "(Paused)ScanGrayObjects" : "ScanGrayObjects");
+    TimingLogger::ScopedTiming t(paused ? "(Paused)ScanGrayObjects" : __FUNCTION__,
+        GetTimings());
     // Try to take some of the mark stack since we can pass this off to the worker tasks.
     Object** mark_stack_begin = mark_stack_->Begin();
     Object** mark_stack_end = mark_stack_->End();
@@ -805,28 +794,28 @@
     thread_pool->StartWorkers(self);
     thread_pool->Wait(self, true, true);
     thread_pool->StopWorkers(self);
-    GetTimings()->EndSplit();
   } else {
     for (const auto& space : GetHeap()->GetContinuousSpaces()) {
       if (space->GetMarkBitmap() != nullptr) {
         // Image spaces are handled properly since live == marked for them.
+        const char* name = nullptr;
         switch (space->GetGcRetentionPolicy()) {
-          case space::kGcRetentionPolicyNeverCollect:
-            GetTimings()->StartSplit(paused ? "(Paused)ScanGrayImageSpaceObjects" :
-                "ScanGrayImageSpaceObjects");
-            break;
-          case space::kGcRetentionPolicyFullCollect:
-            GetTimings()->StartSplit(paused ? "(Paused)ScanGrayZygoteSpaceObjects" :
-                "ScanGrayZygoteSpaceObjects");
-            break;
-          case space::kGcRetentionPolicyAlwaysCollect:
-            GetTimings()->StartSplit(paused ? "(Paused)ScanGrayAllocSpaceObjects" :
-                "ScanGrayAllocSpaceObjects");
-            break;
-          }
+        case space::kGcRetentionPolicyNeverCollect:
+          name = paused ? "(Paused)ScanGrayImageSpaceObjects" : "ScanGrayImageSpaceObjects";
+          break;
+        case space::kGcRetentionPolicyFullCollect:
+          name = paused ? "(Paused)ScanGrayZygoteSpaceObjects" : "ScanGrayZygoteSpaceObjects";
+          break;
+        case space::kGcRetentionPolicyAlwaysCollect:
+          name = paused ? "(Paused)ScanGrayAllocSpaceObjects" : "ScanGrayAllocSpaceObjects";
+          break;
+        default:
+          LOG(FATAL) << "Unreachable";
+        }
+        TimingLogger::ScopedTiming t(name, GetTimings());
         ScanObjectVisitor visitor(this);
-        card_table->Scan(space->GetMarkBitmap(), space->Begin(), space->End(), visitor, minimum_age);
-        GetTimings()->EndSplit();
+        card_table->Scan(space->GetMarkBitmap(), space->Begin(), space->End(), visitor,
+                         minimum_age);
       }
     }
   }
@@ -836,9 +825,7 @@
  public:
   RecursiveMarkTask(ThreadPool* thread_pool, MarkSweep* mark_sweep,
                     accounting::ContinuousSpaceBitmap* bitmap, uintptr_t begin, uintptr_t end)
-      : MarkStackTask<false>(thread_pool, mark_sweep, 0, NULL),
-        bitmap_(bitmap),
-        begin_(begin),
+      : MarkStackTask<false>(thread_pool, mark_sweep, 0, NULL), bitmap_(bitmap), begin_(begin),
         end_(end) {
   }
 
@@ -863,7 +850,7 @@
 // Populates the mark stack based on the set of marked objects and
 // recursively marks until the mark stack is emptied.
 void MarkSweep::RecursiveMark() {
-  TimingLogger::ScopedSplit split("RecursiveMark", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   // RecursiveMark will build the lists of known instances of the Reference classes. See
   // DelayReferenceReferent for details.
   if (kUseRecursiveMark) {
@@ -930,25 +917,22 @@
 }
 
 void MarkSweep::ReMarkRoots() {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
-  GetTimings()->StartSplit("(Paused)ReMarkRoots");
   Runtime::Current()->VisitRoots(
       MarkRootCallback, this, static_cast<VisitRootFlags>(kVisitRootFlagNewRoots |
                                                           kVisitRootFlagStopLoggingNewRoots |
                                                           kVisitRootFlagClearRootLog));
-  GetTimings()->EndSplit();
   if (kVerifyRootsMarked) {
-    GetTimings()->StartSplit("(Paused)VerifyRoots");
+    TimingLogger::ScopedTiming t("(Paused)VerifyRoots", GetTimings());
     Runtime::Current()->VisitRoots(VerifyRootMarked, this);
-    GetTimings()->EndSplit();
   }
 }
 
 void MarkSweep::SweepSystemWeaks(Thread* self) {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-  GetTimings()->StartSplit("SweepSystemWeaks");
   Runtime::Current()->SweepSystemWeaks(IsMarkedCallback, this);
-  GetTimings()->EndSplit();
 }
 
 mirror::Object* MarkSweep::VerifySystemWeakIsLiveCallback(Object* obj, void* arg) {
@@ -969,6 +953,7 @@
 }
 
 void MarkSweep::VerifySystemWeaks() {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   // Verify system weaks, uses a special object visitor which returns the input object.
   Runtime::Current()->SweepSystemWeaks(VerifySystemWeakIsLiveCallback, this);
 }
@@ -1005,8 +990,8 @@
 
 void MarkSweep::MarkRootsCheckpoint(Thread* self,
                                     bool revoke_ros_alloc_thread_local_buffers_at_checkpoint) {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   CheckpointMarkThreadRoots check_point(this, revoke_ros_alloc_thread_local_buffers_at_checkpoint);
-  GetTimings()->StartSplit("MarkRootsCheckpoint");
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
   // Request the check point is run on all threads returning a count of the threads that must
   // run through the barrier including self.
@@ -1021,11 +1006,10 @@
   }
   Locks::mutator_lock_->SharedLock(self);
   Locks::heap_bitmap_lock_->ExclusiveLock(self);
-  GetTimings()->EndSplit();
 }
 
 void MarkSweep::SweepArray(accounting::ObjectStack* allocations, bool swap_bitmaps) {
-  GetTimings()->StartSplit("SweepArray");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   Thread* self = Thread::Current();
   mirror::Object** chunk_free_buffer = reinterpret_cast<mirror::Object**>(
       sweep_array_free_buffer_mem_map_->BaseBegin());
@@ -1072,10 +1056,9 @@
         // if needed.
         if (!mark_bitmap->Test(obj)) {
           if (chunk_free_pos >= kSweepArrayChunkFreeSize) {
-            GetTimings()->StartSplit("FreeList");
+            TimingLogger::ScopedTiming t("FreeList", GetTimings());
             freed.objects += chunk_free_pos;
             freed.bytes += alloc_space->FreeList(self, chunk_free_pos, chunk_free_buffer);
-            GetTimings()->EndSplit();
             chunk_free_pos = 0;
           }
           chunk_free_buffer[chunk_free_pos++] = obj;
@@ -1085,10 +1068,9 @@
       }
     }
     if (chunk_free_pos > 0) {
-      GetTimings()->StartSplit("FreeList");
+      TimingLogger::ScopedTiming t("FreeList", GetTimings());
       freed.objects += chunk_free_pos;
       freed.bytes += alloc_space->FreeList(self, chunk_free_pos, chunk_free_buffer);
-      GetTimings()->EndSplit();
       chunk_free_pos = 0;
     }
     // All of the references which space contained are no longer in the allocation stack, update
@@ -1113,31 +1095,33 @@
       freed_los.bytes += large_object_space->Free(self, obj);
     }
   }
-  GetTimings()->NewSplit("RecordFree");
-  RecordFree(freed);
-  RecordFreeLOS(freed_los);
-  GetTimings()->NewSplit("ResetStack");
-  allocations->Reset();
-  GetTimings()->EndSplit();
+  {
+    TimingLogger::ScopedTiming t("RecordFree", GetTimings());
+    RecordFree(freed);
+    RecordFreeLOS(freed_los);
+    t.NewTiming("ResetStack");
+    allocations->Reset();
+  }
   sweep_array_free_buffer_mem_map_->MadviseDontNeedAndZero();
 }
 
 void MarkSweep::Sweep(bool swap_bitmaps) {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   // Ensure that nobody inserted items in the live stack after we swapped the stacks.
   CHECK_GE(live_stack_freeze_size_, GetHeap()->GetLiveStack()->Size());
-  // Mark everything allocated since the last as GC live so that we can sweep concurrently,
-  // knowing that new allocations won't be marked as live.
-  GetTimings()->StartSplit("MarkStackAsLive");
-  accounting::ObjectStack* live_stack = heap_->GetLiveStack();
-  heap_->MarkAllocStackAsLive(live_stack);
-  live_stack->Reset();
-  GetTimings()->EndSplit();
-
-  DCHECK(mark_stack_->IsEmpty());
+  {
+    TimingLogger::ScopedTiming t2("MarkAllocStackAsLive", GetTimings());
+    // Mark everything allocated since the last as GC live so that we can sweep concurrently,
+    // knowing that new allocations won't be marked as live.
+    accounting::ObjectStack* live_stack = heap_->GetLiveStack();
+    heap_->MarkAllocStackAsLive(live_stack);
+    live_stack->Reset();
+    DCHECK(mark_stack_->IsEmpty());
+  }
   for (const auto& space : GetHeap()->GetContinuousSpaces()) {
     if (space->IsContinuousMemMapAllocSpace()) {
       space::ContinuousMemMapAllocSpace* alloc_space = space->AsContinuousMemMapAllocSpace();
-      TimingLogger::ScopedSplit split(
+      TimingLogger::ScopedTiming split(
           alloc_space->IsZygoteSpace() ? "SweepZygoteSpace" : "SweepMallocSpace", GetTimings());
       RecordFree(alloc_space->Sweep(swap_bitmaps));
     }
@@ -1146,7 +1130,7 @@
 }
 
 void MarkSweep::SweepLargeObjects(bool swap_bitmaps) {
-  TimingLogger::ScopedSplit split("SweepLargeObjects", GetTimings());
+  TimingLogger::ScopedTiming split(__FUNCTION__, GetTimings());
   RecordFreeLOS(heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps));
 }
 
@@ -1215,7 +1199,7 @@
 
 // Scan anything that's on the mark stack.
 void MarkSweep::ProcessMarkStack(bool paused) {
-  GetTimings()->StartSplit(paused ? "(Paused)ProcessMarkStack" : "ProcessMarkStack");
+  TimingLogger::ScopedTiming t(paused ? "(Paused)ProcessMarkStack" : __FUNCTION__, GetTimings());
   size_t thread_count = GetThreadCount(paused);
   if (kParallelProcessMarkStack && thread_count > 1 &&
       mark_stack_->Size() >= kMinimumParallelMarkStackSize) {
@@ -1248,7 +1232,6 @@
       ScanObject(obj);
     }
   }
-  GetTimings()->EndSplit();
 }
 
 inline bool MarkSweep::IsMarked(const Object* object) const {
@@ -1262,7 +1245,7 @@
 }
 
 void MarkSweep::FinishPhase() {
-  TimingLogger::ScopedSplit split("FinishPhase", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   if (kCountScannedTypes) {
     VLOG(gc) << "MarkSweep scanned classes=" << class_count_.LoadRelaxed()
         << " arrays=" << array_count_.LoadRelaxed() << " other=" << other_count_.LoadRelaxed();
@@ -1299,9 +1282,8 @@
     // not be in use.
     GetHeap()->AssertAllBumpPointerSpaceThreadLocalBuffersAreRevoked();
   } else {
-    GetTimings()->StartSplit("(Paused)RevokeAllThreadLocalBuffers");
+    TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
     GetHeap()->RevokeAllThreadLocalBuffers();
-    GetTimings()->EndSplit();
   }
 }
 
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index 8a3ac9d..cabfe21 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -59,7 +59,7 @@
 static constexpr size_t kLargeObjectBytesAllocatedThreshold = 16 * MB;
 
 void SemiSpace::BindBitmaps() {
-  GetTimings()->StartSplit("BindBitmaps");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   WriterMutexLock mu(self_, *Locks::heap_bitmap_lock_);
   // Mark all of the spaces we never collect as immune.
   for (const auto& space : GetHeap()->GetContinuousSpaces()) {
@@ -83,7 +83,6 @@
     // We won't collect the large object space if a bump pointer space only collection.
     is_large_object_space_immune_ = true;
   }
-  GetTimings()->EndSplit();
 }
 
 SemiSpace::SemiSpace(Heap* heap, bool generational, const std::string& name_prefix)
@@ -131,7 +130,7 @@
 }
 
 void SemiSpace::InitializePhase() {
-  TimingLogger::ScopedSplit split("InitializePhase", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   mark_stack_ = heap_->GetMarkStack();
   DCHECK(mark_stack_ != nullptr);
   immune_region_.Reset();
@@ -151,7 +150,6 @@
 }
 
 void SemiSpace::ProcessReferences(Thread* self) {
-  TimingLogger::ScopedSplit split("ProcessReferences", GetTimings());
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   GetHeap()->GetReferenceProcessor()->ProcessReferences(
       false, GetTimings(), GetCurrentIteration()->GetClearSoftReferences(),
@@ -159,6 +157,7 @@
 }
 
 void SemiSpace::MarkingPhase() {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   CHECK(Locks::mutator_lock_->IsExclusiveHeld(self_));
   if (kStoreStackTraces) {
     Locks::mutator_lock_->AssertExclusiveHeld(self_);
@@ -197,10 +196,7 @@
     // If generational, clear soft references if a whole heap collection.
     GetCurrentIteration()->SetClearSoftReferences(true);
   }
-
   Locks::mutator_lock_->AssertExclusiveHeld(self_);
-
-  TimingLogger::ScopedSplit split("MarkingPhase", GetTimings());
   if (generational_) {
     // If last_gc_to_space_end_ is out of the bounds of the from-space
     // (the to-space from last GC), then point it to the beginning of
@@ -218,12 +214,13 @@
   heap_->ProcessCards(GetTimings(), kUseRememberedSet && generational_);
   // Clear the whole card table since we can not Get any additional dirty cards during the
   // paused GC. This saves memory but only works for pause the world collectors.
-  GetTimings()->NewSplit("ClearCardTable");
+  t.NewTiming("ClearCardTable");
   heap_->GetCardTable()->ClearCardTable();
   // 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.
-  GetTimings()->NewSplit("SwapStacks");
+  t.NewTiming("SwapStacks");
   if (kUseThreadLocalAllocationStack) {
+    TimingLogger::ScopedTiming t("RevokeAllThreadLocalAllocationStacks", GetTimings());
     heap_->RevokeAllThreadLocalAllocationStacks(self_);
   }
   heap_->SwapStacks(self_);
@@ -240,7 +237,6 @@
     ReaderMutexLock mu(self_, *Locks::heap_bitmap_lock_);
     SweepSystemWeaks();
   }
-  GetTimings()->NewSplit("RecordFree");
   // Revoke buffers before measuring how many objects were moved since the TLABs need to be revoked
   // before they are properly counted.
   RevokeAllThreadLocalBuffers();
@@ -257,9 +253,7 @@
   from_space_->Clear();
   VLOG(heap) << "Protecting from_space_: " << *from_space_;
   from_space_->GetMemMap()->Protect(kProtectFromSpace ? PROT_NONE : PROT_READ);
-  GetTimings()->StartSplit("PreSweepingGcVerification");
   heap_->PreSweepingGcVerification(this);
-  GetTimings()->EndSplit();
   if (swap_semi_spaces_) {
     heap_->SwapSemiSpaces();
   }
@@ -272,7 +266,7 @@
       accounting::ModUnionTable* table = heap_->FindModUnionTableFromSpace(space);
       if (table != nullptr) {
         // TODO: Improve naming.
-        TimingLogger::ScopedSplit split(
+        TimingLogger::ScopedTiming t(
             space->IsZygoteSpace() ? "UpdateAndMarkZygoteModUnionTable" :
                                      "UpdateAndMarkImageModUnionTable",
                                      GetTimings());
@@ -354,12 +348,14 @@
 };
 
 void SemiSpace::MarkReachableObjects() {
-  GetTimings()->StartSplit("MarkStackAsLive");
-  accounting::ObjectStack* live_stack = heap_->GetLiveStack();
-  heap_->MarkAllocStackAsLive(live_stack);
-  live_stack->Reset();
-
-  GetTimings()->NewSplit("UpdateAndMarkRememberedSets");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
+  {
+    TimingLogger::ScopedTiming t2("MarkStackAsLive", GetTimings());
+    accounting::ObjectStack* live_stack = heap_->GetLiveStack();
+    heap_->MarkAllocStackAsLive(live_stack);
+    live_stack->Reset();
+  }
+  t.NewTiming("UpdateAndMarkRememberedSets");
   for (auto& space : heap_->GetContinuousSpaces()) {
     // If the space is immune and has no mod union table (the
     // non-moving space when the bump pointer space only collection is
@@ -398,7 +394,7 @@
   }
 
   if (is_large_object_space_immune_) {
-    GetTimings()->NewSplit("VisitLargeObjects");
+    TimingLogger::ScopedTiming t("VisitLargeObjects", GetTimings());
     DCHECK(generational_ && !whole_heap_collection_);
     // Delay copying the live set to the marked set until here from
     // BindBitmaps() as the large objects on the allocation stack may
@@ -416,31 +412,24 @@
                                         reinterpret_cast<uintptr_t>(large_object_space->End()),
                                         visitor);
   }
-  GetTimings()->EndSplit();
   // Recursively process the mark stack.
   ProcessMarkStack();
 }
 
 void SemiSpace::ReclaimPhase() {
-  TimingLogger::ScopedSplit split("ReclaimPhase", GetTimings());
-  {
-    WriterMutexLock mu(self_, *Locks::heap_bitmap_lock_);
-    // Reclaim unmarked objects.
-    Sweep(false);
-    // Swap the live and mark bitmaps for each space which we modified space. This is an
-    // optimization that enables us to not clear live bits inside of the sweep. Only swaps unbound
-    // bitmaps.
-    GetTimings()->StartSplit("SwapBitmaps");
-    SwapBitmaps();
-    GetTimings()->EndSplit();
-    // Unbind the live and mark bitmaps.
-    TimingLogger::ScopedSplit split("UnBindBitmaps", GetTimings());
-    GetHeap()->UnBindBitmaps();
-  }
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
+  WriterMutexLock mu(self_, *Locks::heap_bitmap_lock_);
+  // Reclaim unmarked objects.
+  Sweep(false);
+  // Swap the live and mark bitmaps for each space which we modified space. This is an
+  // optimization that enables us to not clear live bits inside of the sweep. Only swaps unbound
+  // bitmaps.
+  SwapBitmaps();
+  // Unbind the live and mark bitmaps.
+  GetHeap()->UnBindBitmaps();
   if (saved_bytes_ > 0) {
     VLOG(heap) << "Avoided dirtying " << PrettySize(saved_bytes_);
   }
-
   if (generational_) {
     // Record the end (top) of the to space so we can distinguish
     // between objects that were allocated since the last GC and the
@@ -629,8 +618,7 @@
 
 // Marks all objects in the root set.
 void SemiSpace::MarkRoots() {
-  GetTimings()->NewSplit("MarkRoots");
-  // TODO: Visit up image roots as well?
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   Runtime::Current()->VisitRoots(MarkRootCallback, this);
 }
 
@@ -655,9 +643,8 @@
 }
 
 void SemiSpace::SweepSystemWeaks() {
-  GetTimings()->StartSplit("SweepSystemWeaks");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   Runtime::Current()->SweepSystemWeaks(MarkedForwardingAddressCallback, this);
-  GetTimings()->EndSplit();
 }
 
 bool SemiSpace::ShouldSweepSpace(space::ContinuousSpace* space) const {
@@ -665,15 +652,15 @@
 }
 
 void SemiSpace::Sweep(bool swap_bitmaps) {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   DCHECK(mark_stack_->IsEmpty());
-  TimingLogger::ScopedSplit split("Sweep", GetTimings());
   for (const auto& space : GetHeap()->GetContinuousSpaces()) {
     if (space->IsContinuousMemMapAllocSpace()) {
       space::ContinuousMemMapAllocSpace* alloc_space = space->AsContinuousMemMapAllocSpace();
       if (!ShouldSweepSpace(alloc_space)) {
         continue;
       }
-      TimingLogger::ScopedSplit split(
+      TimingLogger::ScopedTiming split(
           alloc_space->IsZygoteSpace() ? "SweepZygoteSpace" : "SweepAllocSpace", GetTimings());
       RecordFree(alloc_space->Sweep(swap_bitmaps));
     }
@@ -685,7 +672,7 @@
 
 void SemiSpace::SweepLargeObjects(bool swap_bitmaps) {
   DCHECK(!is_large_object_space_immune_);
-  TimingLogger::ScopedSplit split("SweepLargeObjects", GetTimings());
+  TimingLogger::ScopedTiming split("SweepLargeObjects", GetTimings());
   RecordFreeLOS(heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps));
 }
 
@@ -726,6 +713,7 @@
 
 // Scan anything that's on the mark stack.
 void SemiSpace::ProcessMarkStack() {
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   space::MallocSpace* promo_dest_space = nullptr;
   accounting::ContinuousSpaceBitmap* live_bitmap = nullptr;
   if (generational_ && !whole_heap_collection_) {
@@ -739,7 +727,6 @@
     DCHECK(mark_bitmap != nullptr);
     DCHECK_EQ(live_bitmap, mark_bitmap);
   }
-  GetTimings()->StartSplit("ProcessMarkStack");
   while (!mark_stack_->IsEmpty()) {
     Object* obj = mark_stack_->PopBack();
     if (generational_ && !whole_heap_collection_ && promo_dest_space->HasAddress(obj)) {
@@ -750,7 +737,6 @@
     }
     ScanObject(obj);
   }
-  GetTimings()->EndSplit();
 }
 
 inline Object* SemiSpace::GetMarkedForwardAddress(mirror::Object* obj) const
@@ -781,7 +767,7 @@
 }
 
 void SemiSpace::FinishPhase() {
-  TimingLogger::ScopedSplit split("FinishPhase", GetTimings());
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   // 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;
@@ -822,9 +808,8 @@
 }
 
 void SemiSpace::RevokeAllThreadLocalBuffers() {
-  GetTimings()->StartSplit("(Paused)RevokeAllThreadLocalBuffers");
+  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   GetHeap()->RevokeAllThreadLocalBuffers();
-  GetTimings()->EndSplit();
 }
 
 }  // namespace collector
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 6c63e5f..696728b 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -866,7 +866,10 @@
     // about pauses.
     Runtime* runtime = Runtime::Current();
     runtime->GetThreadList()->SuspendAll();
-    runtime->GetMonitorList()->DeflateMonitors();
+    uint64_t start_time = NanoTime();
+    size_t count = runtime->GetMonitorList()->DeflateMonitors();
+    VLOG(heap) << "Deflating " << count << " monitors took "
+        << PrettyDuration(NanoTime() - start_time);
     runtime->GetThreadList()->ResumeAll();
     // Do a heap trim if it is needed.
     Trim();
@@ -1580,6 +1583,7 @@
 };
 
 void Heap::UnBindBitmaps() {
+  TimingLogger::ScopedTiming t("UnBindBitmaps", GetCurrentGcIteration()->GetTimings());
   for (const auto& space : GetContinuousSpaces()) {
     if (space->IsContinuousMemMapAllocSpace()) {
       space::ContinuousMemMapAllocSpace* alloc_space = space->AsContinuousMemMapAllocSpace();
@@ -1848,7 +1852,7 @@
   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
-  // (mutator time blocked >=  long_pause_log_threshold_).
+  // (mutator time blocked >= long_pause_log_threshold_).
   bool log_gc = gc_cause == kGcCauseExplicit;
   if (!log_gc && CareAboutPauseTimes()) {
     // GC for alloc pauses the allocating thread, so consider it as a pause.
@@ -2314,6 +2318,7 @@
 }
 
 void Heap::ProcessCards(TimingLogger* timings, bool use_rem_sets) {
+  TimingLogger::ScopedTiming t(__FUNCTION__, timings);
   // Clear cards and keep track of cards cleared in the mod-union table.
   for (const auto& space : continuous_spaces_) {
     accounting::ModUnionTable* table = FindModUnionTableFromSpace(space);
@@ -2321,15 +2326,15 @@
     if (table != nullptr) {
       const char* name = space->IsZygoteSpace() ? "ZygoteModUnionClearCards" :
           "ImageModUnionClearCards";
-      TimingLogger::ScopedSplit split(name, timings);
+      TimingLogger::ScopedTiming t(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::ScopedSplit split("AllocSpaceRemSetClearCards", timings);
+      TimingLogger::ScopedTiming t("AllocSpaceRemSetClearCards", timings);
       rem_set->ClearCards();
     } else if (space->GetType() != space::kSpaceTypeBumpPointerSpace) {
-      TimingLogger::ScopedSplit split("AllocSpaceClearCards", timings);
+      TimingLogger::ScopedTiming t("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)
@@ -2349,8 +2354,9 @@
 void Heap::PreGcVerificationPaused(collector::GarbageCollector* gc) {
   Thread* const self = Thread::Current();
   TimingLogger* const timings = current_gc_iteration_.GetTimings();
+  TimingLogger::ScopedTiming t(__FUNCTION__, timings);
   if (verify_pre_gc_heap_) {
-    TimingLogger::ScopedSplit split("PreGcVerifyHeapReferences", timings);
+    TimingLogger::ScopedTiming t("(Paused)PreGcVerifyHeapReferences", timings);
     ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
     size_t failures = VerifyHeapReferences();
     if (failures > 0) {
@@ -2360,7 +2366,7 @@
   }
   // Check that all objects which reference things in the live stack are on dirty cards.
   if (verify_missing_card_marks_) {
-    TimingLogger::ScopedSplit split("PreGcVerifyMissingCardMarks", timings);
+    TimingLogger::ScopedTiming t("(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.
@@ -2370,7 +2376,7 @@
     SwapStacks(self);
   }
   if (verify_mod_union_table_) {
-    TimingLogger::ScopedSplit split("PreGcVerifyModUnionTables", timings);
+    TimingLogger::ScopedTiming t("(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;
@@ -2397,10 +2403,11 @@
 void Heap::PreSweepingGcVerification(collector::GarbageCollector* gc) {
   Thread* const self = Thread::Current();
   TimingLogger* const timings = current_gc_iteration_.GetTimings();
+  TimingLogger::ScopedTiming t(__FUNCTION__, timings);
   // 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::ScopedSplit split("PostSweepingVerifyHeapReferences", timings);
+    TimingLogger::ScopedTiming t("(Paused)PostSweepingVerifyHeapReferences", timings);
     CHECK_NE(self->GetState(), kRunnable);
     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
     // Swapping bound bitmaps does nothing.
@@ -2423,16 +2430,17 @@
   // Only pause if we have to do some verification.
   Thread* const self = Thread::Current();
   TimingLogger* const timings = GetCurrentGcIteration()->GetTimings();
+  TimingLogger::ScopedTiming t(__FUNCTION__, timings);
   if (verify_system_weaks_) {
     ReaderMutexLock mu2(self, *Locks::heap_bitmap_lock_);
     collector::MarkSweep* mark_sweep = down_cast<collector::MarkSweep*>(gc);
     mark_sweep->VerifySystemWeaks();
   }
   if (verify_post_gc_rosalloc_) {
-    RosAllocVerification(timings, "PostGcRosAllocVerification");
+    RosAllocVerification(timings, "(Paused)PostGcRosAllocVerification");
   }
   if (verify_post_gc_heap_) {
-    TimingLogger::ScopedSplit split("PostGcVerifyHeapReferences", timings);
+    TimingLogger::ScopedTiming t("(Paused)PostGcVerifyHeapReferences", timings);
     ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
     size_t failures = VerifyHeapReferences();
     if (failures > 0) {
@@ -2450,7 +2458,7 @@
 }
 
 void Heap::RosAllocVerification(TimingLogger* timings, const char* name) {
-  TimingLogger::ScopedSplit split(name, timings);
+  TimingLogger::ScopedTiming t(name, timings);
   for (const auto& space : continuous_spaces_) {
     if (space->IsRosAllocSpace()) {
       VLOG(heap) << name << " : " << space->GetName();
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index 292781e..e52bc1f 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -110,6 +110,7 @@
                                            MarkObjectCallback* mark_object_callback,
                                            ProcessMarkStackCallback* process_mark_stack_callback,
                                            void* arg) {
+  TimingLogger::ScopedTiming t(concurrent ? __FUNCTION__ : "(Paused)ProcessReferences", timings);
   Thread* self = Thread::Current();
   {
     MutexLock mu(self, lock_);
@@ -118,10 +119,9 @@
     process_references_args_.arg_ = arg;
     CHECK_EQ(slow_path_enabled_, concurrent) << "Slow path must be enabled iff concurrent";
   }
-  timings->StartSplit(concurrent ? "ProcessReferences" : "(Paused)ProcessReferences");
   // Unless required to clear soft references with white references, preserve some white referents.
   if (!clear_soft_references) {
-    TimingLogger::ScopedSplit split(concurrent ? "ForwardSoftReferences" :
+    TimingLogger::ScopedTiming split(concurrent ? "ForwardSoftReferences" :
         "(Paused)ForwardSoftReferences", timings);
     if (concurrent) {
       StartPreservingReferences(self);
@@ -138,7 +138,7 @@
   soft_reference_queue_.ClearWhiteReferences(&cleared_references_, is_marked_callback, arg);
   weak_reference_queue_.ClearWhiteReferences(&cleared_references_, is_marked_callback, arg);
   {
-    TimingLogger::ScopedSplit split(concurrent ? "EnqueueFinalizerReferences" :
+    TimingLogger::ScopedTiming t(concurrent ? "EnqueueFinalizerReferences" :
         "(Paused)EnqueueFinalizerReferences", timings);
     if (concurrent) {
       StartPreservingReferences(self);
@@ -173,7 +173,6 @@
       DisableSlowPath(self);
     }
   }
-  timings->EndSplit();
 }
 
 // Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index a19445b..999a9e5 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -1115,20 +1115,29 @@
   }
 }
 
+struct MonitorDeflateArgs {
+  MonitorDeflateArgs() : self(Thread::Current()), deflate_count(0) {}
+  Thread* const self;
+  size_t deflate_count;
+};
+
 static mirror::Object* MonitorDeflateCallback(mirror::Object* object, void* arg)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (Monitor::Deflate(reinterpret_cast<Thread*>(arg), object)) {
+  MonitorDeflateArgs* args = reinterpret_cast<MonitorDeflateArgs*>(arg);
+  if (Monitor::Deflate(args->self, object)) {
     DCHECK_NE(object->GetLockWord(true).GetState(), LockWord::kFatLocked);
+    ++args->deflate_count;
     // If we deflated, return nullptr so that the monitor gets removed from the array.
     return nullptr;
   }
   return object;  // Monitor was not deflated.
 }
 
-void MonitorList::DeflateMonitors() {
-  Thread* self = Thread::Current();
-  Locks::mutator_lock_->AssertExclusiveHeld(self);
-  SweepMonitorList(MonitorDeflateCallback, reinterpret_cast<Thread*>(self));
+size_t MonitorList::DeflateMonitors() {
+  MonitorDeflateArgs args;
+  Locks::mutator_lock_->AssertExclusiveHeld(args.self);
+  SweepMonitorList(MonitorDeflateCallback, &args);
+  return args.deflate_count;
 }
 
 MonitorInfo::MonitorInfo(mirror::Object* obj) : owner_(NULL), entry_count_(0) {
diff --git a/runtime/monitor.h b/runtime/monitor.h
index a28823d..d7552a3 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -229,7 +229,8 @@
       LOCKS_EXCLUDED(monitor_list_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void DisallowNewMonitors() LOCKS_EXCLUDED(monitor_list_lock_);
   void AllowNewMonitors() LOCKS_EXCLUDED(monitor_list_lock_);
-  void DeflateMonitors() LOCKS_EXCLUDED(monitor_list_lock_)
+  // Returns how many monitors were deflated.
+  size_t DeflateMonitors() LOCKS_EXCLUDED(monitor_list_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
diff --git a/runtime/utils.cc b/runtime/utils.cc
index f60f795..e5b8b22 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -468,11 +468,12 @@
                       negative_str, byte_count / kBytesPerUnit[i], kUnitStrings[i]);
 }
 
-std::string PrettyDuration(uint64_t nano_duration) {
+std::string PrettyDuration(uint64_t nano_duration, size_t max_fraction_digits) {
   if (nano_duration == 0) {
     return "0";
   } else {
-    return FormatDuration(nano_duration, GetAppropriateTimeUnit(nano_duration));
+    return FormatDuration(nano_duration, GetAppropriateTimeUnit(nano_duration),
+                          max_fraction_digits);
   }
 }
 
@@ -509,45 +510,41 @@
   return 0;
 }
 
-std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit) {
-  const char* unit = NULL;
+std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit,
+                           size_t max_fraction_digits) {
+  const char* unit = nullptr;
   uint64_t divisor = GetNsToTimeUnitDivisor(time_unit);
-  uint32_t zero_fill = 1;
   switch (time_unit) {
     case kTimeUnitSecond:
       unit = "s";
-      zero_fill = 9;
       break;
     case kTimeUnitMillisecond:
       unit = "ms";
-      zero_fill = 6;
       break;
     case kTimeUnitMicrosecond:
       unit = "us";
-      zero_fill = 3;
       break;
     case kTimeUnitNanosecond:
       unit = "ns";
-      zero_fill = 0;
       break;
   }
-
-  uint64_t whole_part = nano_duration / divisor;
+  const uint64_t whole_part = nano_duration / divisor;
   uint64_t fractional_part = nano_duration % divisor;
   if (fractional_part == 0) {
     return StringPrintf("%" PRIu64 "%s", whole_part, unit);
   } else {
-    while ((fractional_part % 1000) == 0) {
-      zero_fill -= 3;
-      fractional_part /= 1000;
+    static constexpr size_t kMaxDigits = 30;
+    char fraction_buffer[kMaxDigits];
+    char* ptr = fraction_buffer;
+    uint64_t multiplier = 10;
+    // This infinite loops if fractional part is 0.
+    while (fractional_part * multiplier < divisor) {
+      multiplier *= 10;
+      *ptr++ = '0';
     }
-    if (zero_fill == 3) {
-      return StringPrintf("%" PRIu64 ".%03" PRIu64 "%s", whole_part, fractional_part, unit);
-    } else if (zero_fill == 6) {
-      return StringPrintf("%" PRIu64 ".%06" PRIu64 "%s", whole_part, fractional_part, unit);
-    } else {
-      return StringPrintf("%" PRIu64 ".%09" PRIu64 "%s", whole_part, fractional_part, unit);
-    }
+    sprintf(ptr, "%" PRIu64, fractional_part);
+    fraction_buffer[std::min(kMaxDigits - 1, max_fraction_digits)] = '\0';
+    return StringPrintf("%" PRIu64 ".%s%s", whole_part, fraction_buffer, unit);
   }
 }
 
diff --git a/runtime/utils.h b/runtime/utils.h
index 6d52459..a61d30f 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -265,10 +265,11 @@
 // Returns a human-readable time string which prints every nanosecond while trying to limit the
 // number of trailing zeros. Prints using the largest human readable unit up to a second.
 // e.g. "1ms", "1.000000001s", "1.001us"
-std::string PrettyDuration(uint64_t nano_duration);
+std::string PrettyDuration(uint64_t nano_duration, size_t max_fraction_digits = 3);
 
 // Format a nanosecond time to specified units.
-std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit);
+std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit,
+                           size_t max_fraction_digits);
 
 // Get the appropriate unit for a nanosecond duration.
 TimeUnit GetAppropriateTimeUnit(uint64_t nano_duration);
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 4a1e477..7cd5980 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -171,14 +171,15 @@
   EXPECT_EQ("10s", PrettyDuration(10 * one_sec));
   EXPECT_EQ("100s", PrettyDuration(100 * one_sec));
   EXPECT_EQ("1.001s", PrettyDuration(1 * one_sec + one_ms));
-  EXPECT_EQ("1.000001s", PrettyDuration(1 * one_sec + one_us));
-  EXPECT_EQ("1.000000001s", PrettyDuration(1 * one_sec + 1));
+  EXPECT_EQ("1.000001s", PrettyDuration(1 * one_sec + one_us, 6));
+  EXPECT_EQ("1.000000001s", PrettyDuration(1 * one_sec + 1, 9));
+  EXPECT_EQ("1.000s", PrettyDuration(1 * one_sec + one_us, 3));
 
   EXPECT_EQ("1ms", PrettyDuration(1 * one_ms));
   EXPECT_EQ("10ms", PrettyDuration(10 * one_ms));
   EXPECT_EQ("100ms", PrettyDuration(100 * one_ms));
   EXPECT_EQ("1.001ms", PrettyDuration(1 * one_ms + one_us));
-  EXPECT_EQ("1.000001ms", PrettyDuration(1 * one_ms + 1));
+  EXPECT_EQ("1.000001ms", PrettyDuration(1 * one_ms + 1, 6));
 
   EXPECT_EQ("1us", PrettyDuration(1 * one_us));
   EXPECT_EQ("10us", PrettyDuration(10 * one_us));
diff --git a/sigchainlib/Android.mk b/sigchainlib/Android.mk
index cb1778d..8e25339 100644
--- a/sigchainlib/Android.mk
+++ b/sigchainlib/Android.mk
@@ -16,7 +16,7 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-include art/build/Android.common.mk
+include art/build/Android.common_build.mk
 
 include $(CLEAR_VARS)
 LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
@@ -24,6 +24,7 @@
 LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
 LOCAL_SRC_FILES := sigchain.cc
 LOCAL_MODULE:= libsigchain
-LOCAL_SHARED_LIBRARIES += liblog libdl
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+LOCAL_SHARED_LIBRARIES := liblog libdl
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common_build.mk
 include $(BUILD_SHARED_LIBRARY)
diff --git a/build/Android.libarttest.mk b/test/Android.libarttest.mk
similarity index 70%
rename from build/Android.libarttest.mk
rename to test/Android.libarttest.mk
index 76e5af0..bf3e2aa 100644
--- a/build/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -14,16 +14,20 @@
 # limitations under the License.
 #
 
-LIBARTTEST_COMMON_SRC_FILES := \
-	test/JniTest/jni_test.cc \
-	test/SignalTest/signaltest.cc \
-	test/ReferenceMap/stack_walk_refmap_jni.cc \
-	test/StackWalk/stack_walk_jni.cc \
-	test/UnsafeTest/unsafe_test.cc
+LOCAL_PATH := $(call my-dir)
 
-ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
+include art/build/Android.common_build.mk
+
+LIBARTTEST_COMMON_SRC_FILES := \
+  JniTest/jni_test.cc \
+  SignalTest/signaltest.cc \
+  ReferenceMap/stack_walk_refmap_jni.cc \
+  StackWalk/stack_walk_jni.cc \
+  UnsafeTest/unsafe_test.cc
+
+ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
 ifdef TARGET_2ND_ARCH
-  ART_TARGET_LIBARTTEST_$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TEST_OUT)/$(TARGET_2ND_ARCH)/libarttest.so
+  ART_TARGET_LIBARTTEST_$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_2ND_ARCH)/libarttest.so
 endif
 
 # $(1): target or host
@@ -45,17 +49,17 @@
   LOCAL_SRC_FILES := $(LIBARTTEST_COMMON_SRC_FILES)
   LOCAL_SHARED_LIBRARIES += libartd
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
-  LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/build/Android.common.mk
-  LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/build/Android.libarttest.mk
+  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
+  LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.libarttest.mk
   include external/libcxx/libcxx.mk
   ifeq ($$(art_target_or_host),target)
-  	$(call set-target-local-clang-vars)
-  	$(call set-target-local-cflags-vars,debug)
+    $(call set-target-local-clang-vars)
+    $(call set-target-local-cflags-vars,debug)
     LOCAL_SHARED_LIBRARIES += libdl libcutils
     LOCAL_STATIC_LIBRARIES := libgtest
     LOCAL_MULTILIB := both
-    LOCAL_MODULE_PATH_32 := $(ART_TEST_OUT)/$(ART_TARGET_ARCH_32)
-    LOCAL_MODULE_PATH_64 := $(ART_TEST_OUT)/$(ART_TARGET_ARCH_64)
+    LOCAL_MODULE_PATH_32 := $(ART_TARGET_TEST_OUT)/$(ART_TARGET_ARCH_32)
+    LOCAL_MODULE_PATH_64 := $(ART_TARGET_TEST_OUT)/$(ART_TARGET_ARCH_64)
     LOCAL_MODULE_TARGET_ARCH := $(ART_SUPPORTED_ARCH)
     include $(BUILD_SHARED_LIBRARY)
   else # host
@@ -67,8 +71,12 @@
       LOCAL_LDLIBS += -lrt
     endif
     LOCAL_IS_HOST_MODULE := true
+    LOCAL_MULTILIB := both
     include $(BUILD_HOST_SHARED_LIBRARY)
   endif
+
+  # Clear locally used variables.
+  art_target_or_host :=
 endef
 
 ifeq ($(ART_BUILD_TARGET),true)
@@ -77,3 +85,7 @@
 ifeq ($(ART_BUILD_HOST),true)
   $(eval $(call build-libarttest,host))
 endif
+
+# Clear locally used variables.
+LOCAL_PATH :=
+LIBARTTEST_COMMON_SRC_FILES :=
diff --git a/test/Android.mk b/test/Android.mk
deleted file mode 100644
index 7897449..0000000
--- a/test/Android.mk
+++ /dev/null
@@ -1,220 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include art/build/Android.common.mk
-
-########################################################################
-
-# subdirectories which are used as inputs for gtests
-TEST_DEX_DIRECTORIES := \
-	AbstractMethod \
-	AllFields \
-	ExceptionHandle \
-	GetMethodSignature \
-	Interfaces \
-	Main \
-	MyClass \
-	MyClassNatives \
-	Nested \
-	NonStaticLeafMethods \
-	ProtoCompare \
-	ProtoCompare2 \
-	StaticLeafMethods \
-	Statics \
-	StaticsFromCode \
-	Transaction \
-	XandY
-
-# subdirectories of which are used with test-art-target-oat
-# Declare the simplest tests (Main, HelloWorld) first, the rest are alphabetical
-TEST_OAT_DIRECTORIES := \
-	Main \
-	HelloWorld \
-	InterfaceTest \
-	JniTest \
-	SignalTest \
-	NativeAllocations \
-	ParallelGC \
-	ReferenceMap \
-	StackWalk \
-	ThreadStress \
-	UnsafeTest
-
-# TODO: Enable when the StackWalk2 tests are passing
-#	StackWalk2 \
-
-ART_TEST_TARGET_DEX_FILES :=
-ART_TEST_TARGET_DEX_FILES$(ART_PHONY_TEST_TARGET_SUFFIX) :=
-ART_TEST_TARGET_DEX_FILES$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) :=
-ART_TEST_HOST_DEX_FILES :=
-
-# $(1): module prefix
-# $(2): input test directory
-# $(3): target output module path (default module path is used on host)
-define build-art-test-dex
-  ifeq ($(ART_BUILD_TARGET),true)
-    include $(CLEAR_VARS)
-    LOCAL_MODULE := $(1)-$(2)
-    LOCAL_MODULE_TAGS := tests
-    LOCAL_SRC_FILES := $(call all-java-files-under, $(2))
-    LOCAL_JAVA_LIBRARIES := $(TARGET_CORE_JARS)
-    LOCAL_NO_STANDARD_LIBRARIES := true
-    LOCAL_MODULE_PATH := $(3)
-    LOCAL_DEX_PREOPT_IMAGE_LOCATION := $(TARGET_CORE_IMG_OUT)
-    LOCAL_DEX_PREOPT := false
-    LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
-    LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-    include $(BUILD_JAVA_LIBRARY)
-
-    ART_TEST_TARGET_DEX_FILES += $$(LOCAL_INSTALLED_MODULE)
-    ART_TEST_TARGET_DEX_FILES$(ART_PHONY_TEST_TARGET_SUFFIX) += $$(LOCAL_INSTALLED_MODULE)
-  endif
-
-  ifeq ($(ART_BUILD_HOST),true)
-    include $(CLEAR_VARS)
-    LOCAL_MODULE := $(1)-$(2)
-    LOCAL_SRC_FILES := $(call all-java-files-under, $(2))
-    LOCAL_JAVA_LIBRARIES := $(HOST_CORE_JARS)
-    LOCAL_NO_STANDARD_LIBRARIES := true
-    LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_LOCATION)
-    LOCAL_DEX_PREOPT := false
-    LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
-    LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-    include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
-    ART_TEST_HOST_DEX_FILES += $$(LOCAL_INSTALLED_MODULE)
-  endif
-endef
-$(foreach dir,$(TEST_DEX_DIRECTORIES), $(eval $(call build-art-test-dex,art-test-dex,$(dir),$(ART_NATIVETEST_OUT))))
-$(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call build-art-test-dex,oat-test-dex,$(dir),$(ART_TEST_OUT))))
-
-# Used outside the art project to get a list of the current tests
-ART_TEST_DEX_MAKE_TARGETS := $(addprefix art-test-dex-, $(TEST_DEX_DIRECTORIES))
-ART_TEST_OAT_MAKE_TARGETS := $(addprefix oat-test-dex-, $(TEST_OAT_DIRECTORIES))
-
-########################################################################
-
-ART_TEST_TARGET_OAT_TARGETS$(ART_PHONY_TEST_TARGET_SUFFIX) :=
-ART_TEST_TARGET_OAT_TARGETS$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) :=
-ART_TEST_HOST_OAT_DEFAULT_TARGETS :=
-ART_TEST_HOST_OAT_INTERPRETER_TARGETS :=
-
-define declare-test-art-oat-targets-impl
-.PHONY: test-art-target-oat-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
-test-art-target-oat-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX): $(ART_TEST_OUT)/oat-test-dex-$(1).jar test-art-target-sync
-	adb shell touch $(ART_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@
-	adb shell rm $(ART_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@
-	adb shell sh -c "/system/bin/dalvikvm$($(2)ART_PHONY_TEST_TARGET_SUFFIX) $(DALVIKVM_FLAGS) -XXlib:libartd.so -Ximage:$(ART_TEST_DIR)/core.art -classpath $(ART_TEST_DIR)/oat-test-dex-$(1).jar -Djava.library.path=$(ART_TEST_DIR)/$(TARGET_$(2)ARCH) $(1) && touch $(ART_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@"
-	$(hide) (adb pull $(ART_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@ /tmp/ && echo $$@ PASSED) || (echo $$@ FAILED && exit 1)
-	$(hide) rm /tmp/$$@
-endef
-
-# $(1): directory
-# $(2): arguments
-define declare-test-art-oat-targets
-  ifdef TARGET_2ND_ARCH
-    $(call declare-test-art-oat-targets-impl,$(1),2ND_)
-
-    # Bind the primary to the non-suffix rule
-    ifneq ($(ART_PHONY_TEST_TARGET_SUFFIX),)
-test-art-target-oat-$(1): test-art-target-oat-$(1)$(ART_PHONY_TEST_TARGET_SUFFIX)
-    endif
-  endif
-  $(call declare-test-art-oat-targets-impl,$(1),)
-
-$(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/oat-test-dex-$(1).odex: $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar $(HOST_CORE_IMG_OUT) | $(DEX2OATD)
-	$(DEX2OATD) $(DEX2OAT_FLAGS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_LOCATION) --dex-file=$$(realpath $$<) --oat-file=$$@ --instruction-set=$(ART_HOST_ARCH) --host --android-root=$(HOST_OUT)
-
-.PHONY: test-art-host-oat-default-$(1)
-test-art-host-oat-default-$(1): $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/oat-test-dex-$(1).odex test-art-host-dependencies
-	mkdir -p /tmp/android-data/test-art-host-oat-default-$(1)
-	ANDROID_DATA=/tmp/android-data/test-art-host-oat-default-$(1) \
-	  ANDROID_ROOT=$(HOST_OUT) \
-	  LD_LIBRARY_PATH=$(HOST_LIBRARY_PATH) \
-	  $(HOST_OUT_EXECUTABLES)/dalvikvm $(DALVIKVM_FLAGS) -XXlib:libartd$(HOST_SHLIB_SUFFIX) -Ximage:$(HOST_CORE_IMG_LOCATION) -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_LIBRARY_PATH) $(1) $(2) \
-          && echo test-art-host-oat-default-$(1) PASSED || (echo test-art-host-oat-default-$(1) FAILED && exit 1)
-	$(hide) rm -r /tmp/android-data/test-art-host-oat-default-$(1)
-
-.PHONY: test-art-host-oat-interpreter-$(1)
-test-art-host-oat-interpreter-$(1): $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/oat-test-dex-$(1).odex test-art-host-dependencies
-	mkdir -p /tmp/android-data/test-art-host-oat-interpreter-$(1)
-	ANDROID_DATA=/tmp/android-data/test-art-host-oat-interpreter-$(1) \
-	  ANDROID_ROOT=$(HOST_OUT) \
-	  LD_LIBRARY_PATH=$(HOST_LIBRARY_PATH) \
-	  $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd$(HOST_SHLIB_SUFFIX) -Ximage:$(HOST_CORE_IMG_LOCATION) $(DALVIKVM_FLAGS) -Xint -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_LIBRARY_PATH) $(1) $(2) \
-          && echo test-art-host-oat-interpreter-$(1) PASSED || (echo test-art-host-oat-interpreter-$(1) FAILED && exit 1)
-	$(hide) rm -r /tmp/android-data/test-art-host-oat-interpreter-$(1)
-
-.PHONY: test-art-host-oat-$(1)
-test-art-host-oat-$(1): test-art-host-oat-default-$(1) test-art-host-oat-interpreter-$(1)
-
-.PHONY: test-art-oat-$(1)
-test-art-oat-$(1): test-art-host-oat-$(1) test-art-target-oat-$(1)
-
-ART_TEST_TARGET_OAT_TARGETS$(ART_PHONY_TEST_TARGET_SUFFIX) += test-art-target-oat-$(1)$(ART_PHONY_TEST_TARGET_SUFFIX)
-ifdef TARGET_2ND_ARCH
-  ART_TEST_TARGET_OAT_TARGETS$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) += test-art-target-oat-$(1)$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
-endif
-ART_TEST_HOST_OAT_DEFAULT_TARGETS += test-art-host-oat-default-$(1)
-ART_TEST_HOST_OAT_INTERPRETER_TARGETS += test-art-host-oat-interpreter-$(1)
-endef
-$(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call declare-test-art-oat-targets,$(dir))))
-
-########################################################################
-
-TEST_ART_RUN_TEST_MAKE_TARGETS :=
-art_run_tests_dir := $(call intermediates-dir-for,PACKAGING,art-run-tests)/DATA
-
-# Helper to create individual build targets for tests.
-# Must be called with $(eval)
-# $(1): the test number
-define declare-make-art-run-test
-dmart_target := $(art_run_tests_dir)/art-run-tests/$(1)/touch
-$$(dmart_target): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
-	$(hide) rm -rf $$(dir $$@) && mkdir -p $$(dir $$@)
-	$(hide) DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) $(LOCAL_PATH)/run-test --build-only --output-path $$(abspath $$(dir $$@)) $(1)
-	$(hide) touch $$@
-
-
-TEST_ART_RUN_TEST_MAKE_TARGETS += $$(dmart_target)
-dmart_target :=
-endef
-
-# Expand all tests.
-TEST_ART_RUN_TESTS := $(wildcard $(LOCAL_PATH)/[0-9]*)
-TEST_ART_RUN_TESTS := $(subst $(LOCAL_PATH)/,, $(TEST_ART_RUN_TESTS))
-TEST_ART_TIMING_SENSITIVE_RUN_TESTS := 053-wait-some 055-enum-performance
-ifdef dist_goal # disable timing sensitive tests on "dist" builds.
-  $(foreach test, $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), \
-    $(info Skipping $(test)) \
-    $(eval TEST_ART_RUN_TESTS := $(filter-out $(test), $(TEST_ART_RUN_TESTS))))
-endif
-$(foreach test, $(TEST_ART_RUN_TESTS), $(eval $(call declare-make-art-run-test,$(test))))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := art-run-tests
-LOCAL_ADDITIONAL_DEPENDENCIES := $(TEST_ART_RUN_TEST_MAKE_TARGETS)
-# The build system use this flag to pick up files generated by declare-make-art-run-test.
-LOCAL_PICKUP_FILES := $(art_run_tests_dir)
-
-include $(BUILD_PHONY_PACKAGE)
-
-# clear temp vars
-TEST_ART_RUN_TEST_MAKE_TARGETS :=
-declare-make-art-run-test :=
-
-########################################################################
diff --git a/test/Android.oat.mk b/test/Android.oat.mk
new file mode 100644
index 0000000..4e4f62c
--- /dev/null
+++ b/test/Android.oat.mk
@@ -0,0 +1,454 @@
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+LOCAL_PID := $(shell echo $$PPID)
+
+include art/build/Android.common_test.mk
+
+########################################################################
+
+# Subdirectories in art/test which contain dex files used as inputs for oat tests. Declare the
+# simplest tests (Main, HelloWorld) first, the rest are alphabetical.
+TEST_OAT_DIRECTORIES := \
+  Main \
+  HelloWorld \
+  InterfaceTest \
+  JniTest \
+  SignalTest \
+  NativeAllocations \
+  ParallelGC \
+  ReferenceMap \
+  StackWalk \
+  ThreadStress \
+  UnsafeTest
+
+# TODO: Enable when the StackWalk2 tests are passing
+#  StackWalk2 \
+
+# Create build rules for each dex file recording the dependency.
+$(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call build-art-test-dex,art-oat-test,$(dir), \
+  $(ART_TARGET_TEST_OUT),$(LOCAL_PATH)/Android.oat.mk,ART_OAT_TEST_$(dir)_DEX)))
+
+########################################################################
+
+include $(LOCAL_PATH)/Android.libarttest.mk
+
+ART_TEST_TARGET_OAT_DEFAULT$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_DEFAULT$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_DEFAULT_RULES :=
+ART_TEST_TARGET_OAT_OPTIMIZING$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_OPTIMIZING$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_OPTIMIZING_RULES :=
+ART_TEST_TARGET_OAT_INTERPRETER$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_INTERPRETER$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_INTERPRETER_RULES :=
+ART_TEST_TARGET_OAT$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_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)
+
+# Define rule to run an individual oat test on the host. Output from the test is written to the
+# host in /tmp/android-data in a directory named after test's rule name (its target) and the parent
+# process' PID (ie the PID of make). On failure the output is dumped to the console. To test for
+# success on the target device a file is created following a successful test and this is pulled
+# onto the host. If the pull fails then the file wasn't created because the test failed.
+# $(1): directory - the name of the test we're building such as HelloWorld.
+# $(2): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
+# $(3): the target (rule name), e.g. test-art-target-oat-default-HelloWorld64
+# $(4): -Xint or undefined - do we want to run with the interpreter or default.
+define define-test-art-oat-rule-target
+  # Add the test dependencies to test-art-target-sync, which will be a prerequisit for the test
+  # to ensure files are pushed to the device.
+  TEST_ART_TARGET_SYNC_DEPS += $$(ART_OAT_TEST_$(1)_DEX)
+
+.PHONY: $(3)
+$(3): test-art-target-sync
+	$(hide) mkdir -p $(ART_HOST_TEST_DIR)/android-data-$$@
+	$(hide) echo Running: $$@
+	$(hide) adb shell touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$(LOCAL_PID)
+	$(hide) adb shell rm $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$(LOCAL_PID)
+	$(hide) $$(call ART_TEST_SKIP,$$@) && \
+	  adb shell sh -c "/system/bin/dalvikvm$($(2)ART_PHONY_TEST_TARGET_SUFFIX) \
+	    $(DALVIKVM_FLAGS) $(4) -XXlib:libartd.so -Ximage:$(ART_TARGET_TEST_DIR)/core.art \
+	    -classpath $(ART_TARGET_TEST_DIR)/art-oat-test-$(1).jar \
+	    -Djava.library.path=$(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH) $(1) \
+	      && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$(LOCAL_PID)" \
+	        > $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt 2>&1 && \
+	  (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$(LOCAL_PID) $(ART_HOST_TEST_DIR)/android-data-$$@ \
+	    && $$(call ART_TEST_PASSED,$$@)) \
+	    || (([ ! -f $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt ] || \
+	         cat $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt) && $$(call ART_TEST_FAILED,$$@))
+	$$(hide) (echo $(MAKECMDGOALS) | grep -q $$@ && \
+	  echo "run-test run as top-level target, removing test directory $(ART_HOST_TEST_DIR)" && \
+	  rm -r $(ART_HOST_TEST_DIR)) || true
+
+endef  # define-test-art-oat-rule-target
+
+# Define rules to run oat tests on the target.
+# $(1): directory - the name of the test we're building such as HelloWorld.
+# $(2): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
+define define-test-art-oat-rules-target
+  # Define a phony rule to run a target oat test using the default compiler.
+  default_test_rule := test-art-target-oat-default-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
+  $(call define-test-art-oat-rule-target,$(1),$(2),$$(default_test_rule),)
+
+  ART_TEST_TARGET_OAT_DEFAULT$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(default_test_rule)
+  ART_TEST_TARGET_OAT_DEFAULT_RULES += $$(default_test_rule)
+  ART_TEST_TARGET_OAT_DEFAULT_$(1)_RULES += $$(default_test_rule)
+
+  optimizing_test_rule := test-art-target-oat-optimizing-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
+  $(call define-test-art-oat-rule-target,$(1),$(2),$$(optimizing_test_rule), \
+    -Xcompiler-option --compiler-backend=Optimizing)
+
+  # Mark all tests with the optimizing compiler broken. TODO: fix.
+  ART_TEST_KNOWN_BROKEN += $$(optimizing_test_rule)
+
+  ART_TEST_TARGET_OAT_OPTIMIZING$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(optimizing_test_rule)
+  ART_TEST_TARGET_OAT_OPTIMIZING_RULES += $$(optimizing_test_rule)
+  ART_TEST_TARGET_OAT_OPTIMIZING_$(1)_RULES += $$(optimizing_test_rule)
+
+  # Define a phony rule to run a target oat test using the interpeter.
+  interpreter_test_rule := test-art-target-oat-interpreter-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
+  $(call define-test-art-oat-rule-target,$(1),$(2),$$(interpreter_test_rule),-Xint)
+
+  ART_TEST_TARGET_OAT_INTERPRETER$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(interpreter_test_rule)
+  ART_TEST_TARGET_OAT_INTERPRETER_RULES += $$(interpreter_test_rule)
+  ART_TEST_TARGET_OAT_INTERPRETER_$(1)_RULES += $$(interpreter_test_rule)
+
+  # Define a phony rule to run both the default and interpreter variants.
+  all_test_rule :=  test-art-target-oat-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
+.PHONY: $$(all_test_rule)
+$$(all_test_rule): $$(default_test_rule) $$(optimizing_test_rule) $$(interpreter_test_rule)
+	$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
+
+  ART_TEST_TARGET_OAT$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(all_test_rule)
+  ART_TEST_TARGET_OAT_RULES += $$(all_test_rule)
+  ART_TEST_TARGET_OAT_$(1)_RULES += $$(all_test_rule)
+
+  # Clear locally defined variables.
+  interpreter_test_rule :=
+  default_test_rule :=
+  optimizing_test_rule :=
+  all_test_rule :=
+endef  # define-test-art-oat-rules-target
+
+ART_TEST_HOST_OAT_DEFAULT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_DEFAULT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_DEFAULT_RULES :=
+ART_TEST_HOST_OAT_OPTIMIZING$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_OPTIMIZING$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_OPTIMIZING_RULES :=
+ART_TEST_HOST_OAT_INTERPRETER$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_INTERPRETER$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_INTERPRETER_RULES :=
+ART_TEST_HOST_OAT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_RULES :=
+
+# All tests require the host executables, libarttest and the core images.
+ART_TEST_HOST_OAT_DEPENDENCIES := \
+  $(ART_HOST_EXECUTABLES) \
+  $(ART_HOST_LIBRARY_PATH)/libarttest$(ART_HOST_SHLIB_EXTENSION) \
+  $(HOST_CORE_IMG_OUT)
+
+ifneq ($(HOST_PREFER_32_BIT),true)
+ART_TEST_HOST_OAT_DEPENDENCIES += \
+  $(2ND_ART_HOST_LIBRARY_PATH)/libarttest$(ART_HOST_SHLIB_EXTENSION) \
+  $(2ND_HOST_CORE_IMG_OUT)
+endif
+
+# Define rule to run an individual oat test on the host. Output from the test is written to the
+# host in /tmp/android-data in a directory named after test's rule name (its target) and the parent
+# process' PID (ie the PID of make). On failure the output is dumped to the console.
+# $(1): directory - the name of the test we're building such as HelloWorld.
+# $(2): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
+# $(3): the target (rule name), e.g. test-art-host-oat-default-HelloWorld64
+# $(4): argument to dex2oat
+# $(5): argument to runtime, e.g. -Xint or undefined
+define define-test-art-oat-rule-host
+  # Remove the leading / from /tmp for the test directory.
+  dex_file := $$(subst /tmp,tmp,$(ART_HOST_TEST_DIR))/android-data-$(3)/oat-test-dex-$(1).jar
+  oat_file := $(ART_HOST_TEST_DIR)/android-data-$(3)/dalvik-cache/$$($(2)HOST_ARCH)/$$(subst /,@,$$(dex_file))@classes.dex
+$(3): PRIVATE_DEX_FILE := /$$(dex_file)
+$(3): PRIVATE_OAT_FILE := $$(oat_file)
+.PHONY: $(3)
+$(3): $$(ART_OAT_TEST_$(1)_DEX) $(ART_TEST_HOST_OAT_DEPENDENCIES)
+	$(hide) mkdir -p $(ART_HOST_TEST_DIR)/android-data-$$@/dalvik-cache/$$($(2)HOST_ARCH)
+	$(hide) cp $$(realpath $$<) $(ART_HOST_TEST_DIR)/android-data-$$@/oat-test-dex-$(1).jar
+	$(hide) $(DEX2OATD) $(DEX2OAT_FLAGS) --runtime-arg -Xms16m --runtime-arg -Xmx16m $(4) \
+	  --boot-image=$$(HOST_CORE_IMG_LOCATION) \
+	  --dex-file=$$(PRIVATE_DEX_FILE) --oat-file=$$(PRIVATE_OAT_FILE) \
+	  --instruction-set=$($(2)ART_HOST_ARCH) --host --android-root=$(HOST_OUT) \
+	  || $$(call ART_TEST_FAILED,$$@)
+	$(hide) $$(call ART_TEST_SKIP,$$@) && \
+	ANDROID_DATA=$(ART_HOST_TEST_DIR)/android-data-$$@/ \
+	ANDROID_ROOT=$(HOST_OUT) \
+	ANDROID_LOG_TAGS='*:d' \
+	LD_LIBRARY_PATH=$$($(2)ART_HOST_OUT_SHARED_LIBRARIES) \
+	$(HOST_OUT_EXECUTABLES)/dalvikvm$$($(2)ART_PHONY_TEST_HOST_SUFFIX) $(DALVIKVM_FLAGS) $(5) \
+	    -XXlib:libartd$(HOST_SHLIB_SUFFIX) -Ximage:$$(HOST_CORE_IMG_LOCATION) \
+	    -classpath $(ART_HOST_TEST_DIR)/android-data-$$@/oat-test-dex-$(1).jar \
+	    -Djava.library.path=$$($(2)ART_HOST_OUT_SHARED_LIBRARIES) $(1) \
+	      > $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt 2>&1 \
+	  && $$(call ART_TEST_PASSED,$$@) \
+	  || (([ ! -f $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt ] || \
+	       cat $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt) && $$(call ART_TEST_FAILED,$$@))
+	$$(hide) (echo $(MAKECMDGOALS) | grep -q $$@ && \
+	  echo "run-test run as top-level target, removing test directory $(ART_HOST_TEST_DIR)" && \
+	  rm -r $(ART_HOST_TEST_DIR)) || true
+endef  # define-test-art-oat-rule-host
+
+# Define rules to run oat tests on the host.
+# $(1): directory - the name of the test we're building such as HelloWorld.
+# $(2): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
+define define-test-art-oat-rules-host
+  # Create a rule to run the host oat test with the default compiler.
+  default_test_rule := test-art-host-oat-default-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
+  $(call define-test-art-oat-rule-host,$(1),$(2),$$(default_test_rule),,)
+
+  ART_TEST_HOST_OAT_DEFAULT$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(default_test_rule)
+  ART_TEST_HOST_OAT_DEFAULT_RULES += $$(default_test_rule)
+  ART_TEST_HOST_OAT_DEFAULT_$(1)_RULES += $$(default_test_rule)
+
+  # Create a rule to run the host oat test with the optimizing compiler.
+  optimizing_test_rule := test-art-host-oat-optimizing-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
+  $(call define-test-art-oat-rule-host,$(1),$(2),$$(optimizing_test_rule),--compiler-backend=Optimizing,)
+
+  # Mark all tests with the optimizing compiler broken. TODO: fix.
+  ART_TEST_KNOWN_BROKEN += $$(optimizing_test_rule)
+
+  ART_TEST_HOST_OAT_OPTIMIZING$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(optimizing_test_rule)
+  ART_TEST_HOST_OAT_OPTIMIZING_RULES += $$(optimizing_test_rule)
+  ART_TEST_HOST_OAT_OPTIMIZING_$(1)_RULES += $$(optimizing_test_rule)
+
+  # Create a rule to run the host oat test with the interpreter.
+  interpreter_test_rule := test-art-host-oat-interpreter-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
+  $(call define-test-art-oat-rule-host,$(1),$(2),$$(interpreter_test_rule),--compiler-filter=interpret-only,-Xint)
+
+  ART_TEST_HOST_OAT_INTERPRETER$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(interpreter_test_rule)
+  ART_TEST_HOST_OAT_INTERPRETER_RULES += $$(interpreter_test_rule)
+  ART_TEST_HOST_OAT_INTERPRETER_$(1)_RULES += $$(interpreter_test_rule)
+
+  # Define a phony rule to run both the default and interpreter variants.
+  all_test_rule :=  test-art-host-oat-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
+.PHONY: $$(all_test_rule)
+$$(all_test_rule): $$(default_test_rule) $$(interpreter_test_rule) $$(optimizing_test_rule)
+	$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
+
+  ART_TEST_HOST_OAT$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(all_test_rule)
+  ART_TEST_HOST_OAT_RULES += $$(all_test_rule)
+  ART_TEST_HOST_OAT_$(1)_RULES += $$(all_test_rule)
+
+  # Clear locally defined variables.
+  default_test_rule :=
+  optimizing_test_rule :=
+  interpreter_test_rule :=
+  all_test_rule :=
+endef  # define-test-art-oat-rules-host
+
+# For a given test create all the combinations of host/target, compiler and suffix such as:
+# test-art-host-oat-HelloWord or test-art-target-oat-interpreter-HelloWorld64
+# $(1): test name, e.g. HelloWorld
+# $(2): host or target
+# $(3): HOST or TARGET
+# $(4): undefined, -default, -optimizing or -interpreter
+# $(5): undefined, _DEFAULT, _OPTIMIZING or _INTERPRETER
+define define-test-art-oat-combination-for-test
+  ifeq ($(2),host)
+    ifneq ($(3),HOST)
+      $$(error argument mismatch $(2) and ($3))
+    endif
+  else
+    ifneq ($(2),target)
+      $$(error found $(2) expected host or target)
+    endif
+    ifneq ($(3),TARGET)
+      $$(error argument mismatch $(2) and ($3))
+    endif
+  endif
+
+  rule_name := test-art-$(2)-oat$(4)-$(1)
+  dependencies := $$(ART_TEST_$(3)_OAT$(5)_$(1)_RULES)
+
+  ifeq ($$(dependencies),)
+    ifneq ($(4),-optimizing)
+      $$(error $$(rule_name) has no dependencies)
+    endif
+  endif
+
+.PHONY: $$(rule_name)
+$$(rule_name): $$(dependencies)
+	$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
+
+  # Clear locally defined variables.
+  rule_name :=
+  dependencies :=
+endef  # define-test-art-oat-combination
+
+# Define target and host oat test rules for the differing multilib flavors and default vs
+# interpreter runs. The format of the generated rules (for running an individual test) is:
+#   test-art-(host|target)-oat-(default|interpreter)-${directory}(32|64)
+# The rules are appended to various lists to enable shorter phony build rules to be built.
+# $(1): directory
+define define-test-art-oat-rules
+  # Define target tests.
+  ART_TEST_TARGET_OAT_DEFAULT_$(1)_RULES :=
+  ART_TEST_TARGET_OAT_OPTIMIZING_$(1)_RULES :=
+  ART_TEST_TARGET_OAT_INTERPRETER_$(1)_RULES :=
+  ART_TEST_TARGET_OAT_$(1)_RULES :=
+  $(call define-test-art-oat-rules-target,$(1),)
+  ifdef TARGET_2ND_ARCH
+    $(call define-test-art-oat-rules-target,$(1),2ND_)
+  endif
+  $(call define-test-art-oat-combination-for-test,$(1),target,TARGET,,))
+  $(call define-test-art-oat-combination-for-test,$(1),target,TARGET,-default,_DEFAULT))
+  $(call define-test-art-oat-combination-for-test,$(1),target,TARGET,-optimizing,_OPTIMIZING))
+  $(call define-test-art-oat-combination-for-test,$(1),target,TARGET,-interpreter,_INTERPRETER))
+
+  # Define host tests.
+  ART_TEST_HOST_OAT_DEFAULT_$(1)_RULES :=
+  ART_TEST_HOST_OAT_OPTIMIZING_$(1)_RULES :=
+  ART_TEST_HOST_OAT_INTERPRETER_$(1)_RULES :=
+  ART_TEST_HOST_OAT_$(1)_RULES :=
+  $(call define-test-art-oat-rules-host,$(1),)
+  ifneq ($(HOST_PREFER_32_BIT),true)
+    $(call define-test-art-oat-rules-host,$(1),2ND_)
+  endif
+  $(call define-test-art-oat-combination-for-test,$(1),host,HOST,,)
+  $(call define-test-art-oat-combination-for-test,$(1),host,HOST,-default,_DEFAULT)
+  $(call define-test-art-oat-combination-for-test,$(1),host,HOST,-optimizing,_OPTIMIZING)
+  $(call define-test-art-oat-combination-for-test,$(1),host,HOST,-interpreter,_INTERPRETER)
+
+  # Clear locally defined variables.
+  ART_TEST_TARGET_OAT_DEFAULT_$(1)_RULES :=
+  ART_TEST_TARGET_OAT_OPTIMIZING_$(1)_RULES :=
+  ART_TEST_TARGET_OAT_INTERPRETER_$(1)_RULES :=
+  ART_TEST_TARGET_OAT_$(1)_RULES :=
+  ART_TEST_HOST_OAT_DEFAULT_$(1)_RULES :=
+  ART_TEST_HOST_OAT_OPTIMIZING_$(1)_RULES :=
+  ART_TEST_HOST_OAT_INTERPRETER_$(1)_RULES :=
+  ART_TEST_HOST_OAT_$(1)_RULES :=
+endef  # define-test-art-oat-rules
+$(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call define-test-art-oat-rules,$(dir))))
+
+# Define all the combinations of host/target, compiler and suffix such as:
+# test-art-host-oat or test-art-target-oat-interpreter64
+# $(1): host or target
+# $(2): HOST or TARGET
+# $(3): undefined, -default, -optimizing or -interpreter
+# $(4): undefined, _DEFAULT, _OPTIMIZING or _INTERPRETER
+# $(5): undefined, 32 or 64
+define define-test-art-oat-combination
+  ifeq ($(1),host)
+    ifneq ($(2),HOST)
+      $$(error argument mismatch $(1) and ($2))
+    endif
+  else
+    ifneq ($(1),target)
+      $$(error found $(1) expected host or target)
+    endif
+    ifneq ($(2),TARGET)
+      $$(error argument mismatch $(1) and ($2))
+    endif
+  endif
+
+  rule_name := test-art-$(1)-oat$(3)$(5)
+  dependencies := $$(ART_TEST_$(2)_OAT$(4)$(5)_RULES)
+
+  ifeq ($$(dependencies),)
+    ifneq ($(3),-optimizing)
+      $$(error $$(rule_name) has no dependencies)
+    endif
+  endif
+
+.PHONY: $$(rule_name)
+$$(rule_name): $$(dependencies)
+	$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
+
+  # Clear locally defined variables.
+  rule_name :=
+  dependencies :=
+
+endef  # define-test-art-oat-combination
+
+$(eval $(call define-test-art-oat-combination,target,TARGET,,,))
+$(eval $(call define-test-art-oat-combination,target,TARGET,-default,_DEFAULT,))
+$(eval $(call define-test-art-oat-combination,target,TARGET,-optimizing,_OPTIMIZING,))
+$(eval $(call define-test-art-oat-combination,target,TARGET,-interpreter,_INTERPRETER,))
+$(eval $(call define-test-art-oat-combination,target,TARGET,,,$(ART_PHONY_TEST_TARGET_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,target,TARGET,-default,_DEFAULT,$(ART_PHONY_TEST_TARGET_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,target,TARGET,-optimizing,_OPTIMIZING,$(ART_PHONY_TEST_TARGET_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,target,TARGET,-interpreter,_INTERPRETER,$(ART_PHONY_TEST_TARGET_SUFFIX)))
+ifdef TARGET_2ND_ARCH
+$(eval $(call define-test-art-oat-combination,target,TARGET,,,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,target,TARGET,-default,_DEFAULT,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,target,TARGET,-optimizing,_OPTIMIZING,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,target,TARGET,-interpreter,_INTERPRETER,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
+endif
+
+$(eval $(call define-test-art-oat-combination,host,HOST,,,))
+$(eval $(call define-test-art-oat-combination,host,HOST,-default,_DEFAULT,))
+$(eval $(call define-test-art-oat-combination,host,HOST,-optimizing,_OPTIMIZING,))
+$(eval $(call define-test-art-oat-combination,host,HOST,-interpreter,_INTERPRETER,))
+$(eval $(call define-test-art-oat-combination,host,HOST,,,$(ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,host,HOST,-default,_DEFAULT,$(ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,host,HOST,-optimizing,_OPTIMIZING,$(ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,host,HOST,-interpreter,_INTERPRETER,$(ART_PHONY_TEST_HOST_SUFFIX)))
+ifneq ($(HOST_PREFER_32_BIT),true)
+$(eval $(call define-test-art-oat-combination,host,HOST,,,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,host,HOST,-default,_DEFAULT,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,host,HOST,-optimizing,_OPTIMIZING,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
+$(eval $(call define-test-art-oat-combination,host,HOST,-interpreter,_INTERPRETER,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
+endif
+
+# Clear locally defined variables.
+define-test-art-oat-rule-target :=
+define-test-art-oat-rules-target :=
+define-test-art-oat-rule-host :=
+define-test-art-oat-rules-host :=
+define-test-art-oat-combination-for-test :=
+define-test-art-oat-combination :=
+ART_TEST_TARGET_OAT_DEFAULT$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_DEFAULT$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_DEFAULT_RULES :=
+ART_TEST_TARGET_OAT_OPTIMIZING$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_OPTIMIZING$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_OPTIMIZING_RULES :=
+ART_TEST_TARGET_OAT_INTERPRETER$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_INTERPRETER$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_INTERPRETER_RULES :=
+ART_TEST_TARGET_OAT$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_OAT_RULES :=
+ART_TEST_HOST_OAT_DEFAULT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_DEFAULT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_DEFAULT_RULES :=
+ART_TEST_HOST_OAT_OPTIMIZING$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_OPTIMIZING$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_OPTIMIZING_RULES :=
+ART_TEST_HOST_OAT_INTERPRETER$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_INTERPRETER$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_INTERPRETER_RULES :=
+ART_TEST_HOST_OAT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_OAT_RULES :=
+ART_TEST_HOST_OAT_DEPENDENCIES :=
+$(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval ART_OAT_TEST_$(dir)_DEX :=))
+TEST_OAT_DIRECTORIES :=
+LOCAL_PID :=
+LOCAL_PATH :=
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
new file mode 100644
index 0000000..d359fb0
--- /dev/null
+++ b/test/Android.run-test.mk
@@ -0,0 +1,347 @@
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include art/build/Android.common_test.mk
+
+# List of all tests of the form 003-omnibus-opcodes.
+TEST_ART_RUN_TESTS := $(wildcard $(LOCAL_PATH)/[0-9]*)
+TEST_ART_RUN_TESTS := $(subst $(LOCAL_PATH)/,, $(TEST_ART_RUN_TESTS))
+
+# Tests that are timing sensitive and flaky on heavily loaded systems.
+TEST_ART_TIMING_SENSITIVE_RUN_TESTS := \
+  test-art-host-default-053-wait-some32 \
+  test-art-host-default-053-wait-some64 \
+  test-art-host-interpreter-053-wait-some32 \
+  test-art-host-interpreter-053-wait-some64 \
+  test-art-host-optimizing-053-wait-some32 \
+  test-art-host-optimizing-053-wait-some64 \
+  test-art-host-default-055-enum-performance32 \
+  test-art-host-default-055-enum-performance64 \
+  test-art-host-interpreter-055-enum-performance32 \
+  test-art-host-interpreter-055-enum-performance64 \
+  test-art-host-optimizing-055-enum-performance32 \
+  test-art-host-optimizing-055-enum-performance64
+
+ # disable timing sensitive tests on "dist" builds.
+ifdef dist_goal
+  ART_TEST_KNOWN_BROKEN += $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS)
+endif
+
+# The path where build only targets will be output, e.g.
+# out/target/product/generic_x86_64/obj/PACKAGING/art-run-tests_intermediates/DATA
+art_run_tests_dir := $(call intermediates-dir-for,PACKAGING,art-run-tests)/DATA
+
+# A generated list of prerequisites that call 'run-test --build-only', the actual prerequisite is
+# an empty file touched in the intermediate directory.
+TEST_ART_RUN_TEST_BUILD_RULES :=
+
+# Helper to create individual build targets for tests. Must be called with $(eval).
+# $(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
+	$(hide) rm -rf $$(dir $$@) && mkdir -p $$(dir $$@)
+	$(hide) DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
+	  $(LOCAL_PATH)/run-test --build-only --output-path $$(abspath $$(dir $$@)) $(1)
+	$(hide) touch $$@
+
+  TEST_ART_RUN_TEST_BUILD_RULES += $$(dmart_target)
+  dmart_target :=
+endef
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := art-run-tests
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TEST_ART_RUN_TEST_BUILD_RULES)
+# The build system use this flag to pick up files generated by declare-make-art-run-test.
+LOCAL_PICKUP_FILES := $(art_run_tests_dir)
+
+include $(BUILD_PHONY_PACKAGE)
+
+# Clear temp vars.
+TEST_ART_RUN_TEST_BUILD_RULES :=
+art_run_tests_dir :=
+define-build-art-run-test :=
+
+########################################################################
+
+ART_TEST_TARGET_RUN_TEST_ALL_RULES :=
+ART_TEST_TARGET_RUN_TEST_DEFAULT_RULES :=
+ART_TEST_TARGET_RUN_TEST_INTERPRETER_RULES :=
+ART_TEST_TARGET_RUN_TEST_OPTIMIZING_RULES :=
+ART_TEST_TARGET_RUN_TEST_ALL$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_DEFAULT$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_INTERPRETER$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_OPTIMIZING$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_ALL$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_DEFAULT$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_INTERPRETER$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_OPTIMIZING$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_ALL_RULES :=
+ART_TEST_HOST_RUN_TEST_DEFAULT_RULES :=
+ART_TEST_HOST_RUN_TEST_INTERPRETER_RULES :=
+ART_TEST_HOST_RUN_TEST_OPTIMIZING_RULES :=
+ART_TEST_HOST_RUN_TEST_DEFAULT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_INTERPRETER$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_OPTIMIZING$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_DEFAULT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_INTERPRETER$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_OPTIMIZING$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_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)
+
+# All tests require the host executables and the core images.
+ART_TEST_HOST_RUN_TEST_DEPENDENCIES := \
+  $(ART_HOST_EXECUTABLES) \
+  $(HOST_CORE_IMG_OUT) \
+  $(ART_HOST_LIBRARY_PATH)/libjavacore$(ART_HOST_SHLIB_EXTENSION)
+
+ifneq ($(HOST_PREFER_32_BIT),true)
+ART_TEST_HOST_RUN_TEST_DEPENDENCIES += \
+  $(2ND_ART_HOST_LIBRARY_PATH)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \
+  $(2ND_HOST_CORE_IMG_OUT)
+endif
+
+# For a given test create all the combinations of host/target, compiler and suffix such as:
+# test-art-host-run-test-optimizing-003-omnibus-opcodes32
+# $(1): test name, e.g. 003-omnibus-opcodes
+# $(2): host or target
+# $(3): default, optimizing or interpreter
+# $(4): 32 or 64
+define define-test-art-run-test
+  run_test_options := $(addprefix --runtime-option ,$(DALVIKVM_FLAGS))
+  uc_host_or_target :=
+  prereq_rule :=
+  ifeq ($(2),host)
+    uc_host_or_target := HOST
+    run_test_options += --host
+    prereq_rule := $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES)
+  else
+    ifeq ($(2),target)
+      uc_host_or_target := TARGET
+      prereq_rule := test-art-target-sync
+    else
+      $$(error found $(2) expected host or target)
+    endif
+  endif
+  uc_compiler :=
+  ifeq ($(3),optimizing)
+    uc_compiler := OPTIMIZING
+    run_test_options += -Xcompiler-option --compiler-backend=Optimizing
+  else
+    ifeq ($(3),interpreter)
+      uc_compiler := INTERPRETER
+      run_test_options += --interpreter
+    else
+      ifeq ($(3),default)
+        uc_compiler := DEFAULT
+      else
+        $$(error found $(3) expected optimizing, interpreter or default)
+      endif
+    endif
+  endif
+  ifeq ($(4),64)
+    run_test_options += --64
+  else
+    ifneq ($(4),32)
+      $$(error found $(4) expected 32 or 64)
+    endif
+  endif
+  run_test_rule_name := test-art-$(2)-run-test-$(3)-$(1)$(4)
+  run_test_options := --output-path $(ART_HOST_TEST_DIR)/run-test-output/$$(run_test_rule_name) \
+    $$(run_test_options)
+$$(run_test_rule_name): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options)
+.PHONY: $$(run_test_rule_name)
+$$(run_test_rule_name): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $$(prereq_rule)
+	$(hide) $$(call ART_TEST_SKIP,$$@) && \
+	  DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
+	    art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(1) \
+	      && $$(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)" && \
+	  rm -r $(ART_HOST_TEST_DIR)) || true
+
+  # Mark all tests with the optimizing compiler broken. TODO: fix.
+  ifeq ($(3),optimizing)
+    ART_TEST_KNOWN_BROKEN += $$(run_test_rule_name)
+  endif
+
+  ART_TEST_$$(uc_host_or_target)_RUN_TEST_$$(uc_compiler)$(4)_RULES += $$(run_test_rule_name)
+  ART_TEST_$$(uc_host_or_target)_RUN_TEST_$$(uc_compiler)_RULES += $$(run_test_rule_name)
+  ART_TEST_$$(uc_host_or_target)_RUN_TEST_$$(uc_compiler)_$(1)_RULES += $$(run_test_rule_name)
+  ART_TEST_$$(uc_host_or_target)_RUN_TEST_$$(uc_compiler)_RULES += $$(run_test_rule_name)
+  ART_TEST_$$(uc_host_or_target)_RUN_TEST_$(1)_RULES += $$(run_test_rule_name)
+  ART_TEST_$$(uc_host_or_target)_RUN_TEST_ALL_RULES += $$(run_test_rule_name)
+  ART_TEST_$$(uc_host_or_target)_RUN_TEST_ALL$(4)_RULES += $$(run_test_rule_name)
+
+  # Clear locally defined variables.
+  run_test_options :=
+  run_test_rule_name :=
+  uc_host_or_target :=
+  prereq_rule :=
+  uc_compiler :=
+endef  # define-test-art-run-test
+
+# Define a phony rule whose purpose is to test its prerequisites.
+# $(1): rule name, e.g. test-art-host-run-test32
+# $(2): list of prerequisites
+define define-test-art-run-test-group-rule
+.PHONY: $(1)
+$(1): $(2)
+	$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
+
+endef  # define-test-art-run-test-group-rule
+
+# Create rules for a group of run tests.
+# $(1): test name, e.g. 003-omnibus-opcodes
+# $(2): host or target
+define define-test-art-run-test-group
+  group_uc_host_or_target :=
+  ifeq ($(2),host)
+    group_uc_host_or_target := HOST
+  else
+    ifeq ($(2),target)
+      group_uc_host_or_target := TARGET
+    else
+      $$(error found $(2) expected host or target)
+    endif
+  endif
+
+  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_DEFAULT_$(1)_RULES :=
+  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_INTERPRETER_$(1)_RULES :=
+  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_OPTIMIZING_$(1)_RULES :=
+  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)_RULES :=
+  $$(eval $$(call define-test-art-run-test,$(1),$(2),default,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)))
+  $$(eval $$(call define-test-art-run-test,$(1),$(2),interpreter,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)))
+  $$(eval $$(call define-test-art-run-test,$(1),$(2),optimizing,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)))
+  do_second := false
+  ifeq ($(2),host)
+    ifneq ($$(HOST_PREFER_32_BIT),true)
+      do_second := true
+    endif
+  else
+    ifdef TARGET_2ND_ARCH
+      do_second := true
+    endif
+  endif
+  ifeq (true,$$(do_second))
+    $$(eval $$(call define-test-art-run-test,$(1),$(2),default,$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)))
+    $$(eval $$(call define-test-art-run-test,$(1),$(2),interpreter,$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)))
+    $$(eval $$(call define-test-art-run-test,$(1),$(2),optimizing,$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)))
+  endif
+
+  $$(eval $$(call define-test-art-run-test-group-rule,test-art-$(2)-run-test-default-$(1), \
+    $$(ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_DEFAULT_$(1)_RULES)))
+  $$(eval $$(call define-test-art-run-test-group-rule,test-art-$(2)-run-test-interpreter-$(1), \
+    $$(ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_INTERPRETER_$(1)_RULES)))
+  $$(eval $$(call define-test-art-run-test-group-rule,test-art-$(2)-run-test-optimizing-$(1), \
+    $$(ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_OPTIMIZING_$(1)_RULES)))
+  $$(eval $$(call define-test-art-run-test-group-rule,test-art-$(2)-run-test-$(1), \
+    $$(ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)_RULES)))
+
+  # Clear locally defined variables.
+  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_DEFAULT_$(1)_RULES :=
+  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_INTERPRETER_$(1)_RULES :=
+  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_OPTIMIZING_$(1)_RULES :=
+  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)_RULES :=
+  group_uc_host_or_target :=
+  do_second :=
+endef  # define-test-art-run-test-group
+
+$(foreach test, $(TEST_ART_RUN_TESTS), $(eval $(call define-test-art-run-test-group,$(test),target)))
+$(foreach test, $(TEST_ART_RUN_TESTS), $(eval $(call define-test-art-run-test-group,$(test),host)))
+
+$(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test, \
+  $(ART_TEST_TARGET_RUN_TEST_ALL_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test-default, \
+  $(ART_TEST_TARGET_RUN_TEST_DEFAULT_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test-interpreter, \
+  $(ART_TEST_TARGET_RUN_TEST_INTERPRETER_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test-optimizing, \
+  $(ART_TEST_TARGET_RUN_TEST_OPTIMIZING_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test$(ART_PHONY_TEST_TARGET_SUFFIX), \
+  $(ART_TEST_TARGET_RUN_TEST_ALL$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test-default$(ART_PHONY_TEST_TARGET_SUFFIX), \
+  $(ART_TEST_TARGET_RUN_TEST_DEFAULT$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test-interpreter$(ART_PHONY_TEST_TARGET_SUFFIX), \
+  $(ART_TEST_TARGET_RUN_TEST_INTERPRETER$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test-optimizing$(ART_PHONY_TEST_TARGET_SUFFIX), \
+  $(ART_TEST_TARGET_RUN_TEST_OPTIMIZING$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES)))
+ifdef TARGET_2ND_ARCH
+  $(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test$(2ND_ART_PHONY_TEST_TARGET_SUFFIX), \
+    $(ART_TEST_TARGET_RUN_TEST_ALL$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES)))
+  $(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test-default$(2ND_ART_PHONY_TEST_TARGET_SUFFIX), \
+    $(ART_TEST_TARGET_RUN_TEST_DEFAULT$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES)))
+  $(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test-interpreter$(2ND_ART_PHONY_TEST_TARGET_SUFFIX), \
+    $(ART_TEST_TARGET_RUN_TEST_INTERPRETER$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES)))
+  $(eval $(call define-test-art-run-test-group-rule,test-art-target-run-test-optimizing$(2ND_ART_PHONY_TEST_TARGET_SUFFIX), \
+    $(ART_TEST_TARGET_RUN_TEST_OPTIMIZING$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES)))
+endif
+
+$(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test, \
+  $(ART_TEST_HOST_RUN_TEST_ALL_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test-default, \
+  $(ART_TEST_HOST_RUN_TEST_DEFAULT_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test-interpreter, \
+  $(ART_TEST_HOST_RUN_TEST_INTERPRETER_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test-optimizing, \
+  $(ART_TEST_HOST_RUN_TEST_OPTIMIZING_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test$(ART_PHONY_TEST_HOST_SUFFIX), \
+  $(ART_TEST_HOST_RUN_TEST_ALL$(ART_PHONY_TEST_HOST_SUFFIX)_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test-default$(ART_PHONY_TEST_HOST_SUFFIX), \
+  $(ART_TEST_HOST_RUN_TEST_DEFAULT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test-interpreter$(ART_PHONY_TEST_HOST_SUFFIX), \
+  $(ART_TEST_HOST_RUN_TEST_INTERPRETER$(ART_PHONY_TEST_HOST_SUFFIX)_RULES)))
+$(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test-optimizing$(ART_PHONY_TEST_HOST_SUFFIX), \
+  $(ART_TEST_HOST_RUN_TEST_OPTIMIZING$(ART_PHONY_TEST_HOST_SUFFIX)_RULES)))
+ifneq ($(HOST_PREFER_32_BIT),true)
+  $(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test$(2ND_ART_PHONY_TEST_HOST_SUFFIX), \
+    $(ART_TEST_HOST_RUN_TEST_ALL$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES)))
+  $(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test-default$(2ND_ART_PHONY_TEST_HOST_SUFFIX), \
+    $(ART_TEST_HOST_RUN_TEST_DEFAULT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES)))
+  $(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test-interpreter$(2ND_ART_PHONY_TEST_HOST_SUFFIX), \
+    $(ART_TEST_HOST_RUN_TEST_INTERPRETER$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES)))
+  $(eval $(call define-test-art-run-test-group-rule,test-art-host-run-test-optimizing$(2ND_ART_PHONY_TEST_HOST_SUFFIX), \
+    $(ART_TEST_HOST_RUN_TEST_OPTIMIZING$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES)))
+endif
+
+define-test-art-run-test :=
+define-test-art-run-test-group-rule :=
+define-test-art-run-test-group :=
+ART_TEST_TARGET_RUN_TEST_ALL_RULES :=
+ART_TEST_TARGET_RUN_TEST_DEFAULT_RULES :=
+ART_TEST_TARGET_RUN_TEST_INTERPRETER_RULES :=
+ART_TEST_TARGET_RUN_TEST_OPTIMIZING_RULES :=
+ART_TEST_TARGET_RUN_TEST_ALL$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_DEFAULT$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_INTERPRETER$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_OPTIMIZING$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_ALL$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_DEFAULT$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_INTERPRETER$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_TARGET_RUN_TEST_OPTIMIZING$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_ALL_RULES :=
+ART_TEST_HOST_RUN_TEST_DEFAULT_RULES :=
+ART_TEST_HOST_RUN_TEST_INTERPRETER_RULES :=
+ART_TEST_HOST_RUN_TEST_OPTIMIZING_RULES :=
+ART_TEST_HOST_RUN_TEST_DEFAULT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_INTERPRETER$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_OPTIMIZING$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_DEFAULT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_INTERPRETER$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
+ART_TEST_HOST_RUN_TEST_OPTIMIZING$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
diff --git a/test/etc/host-run-test-jar b/test/etc/host-run-test-jar
index f672974..4265f1c 100755
--- a/test/etc/host-run-test-jar
+++ b/test/etc/host-run-test-jar
@@ -18,6 +18,7 @@
 DEV_MODE="n"
 QUIET="n"
 FLAGS=""
+exe="${ANDROID_HOST_OUT}/bin/dalvikvm32"
 
 while true; do
     if [ "x$1" = "x--quiet" ]; then
@@ -63,6 +64,9 @@
     elif [ "x$1" = "x--interpreter" ]; then
         INTERPRETER="y"
         shift
+    elif [ "x$1" = "x--64" ]; then
+        exe="${ANDROID_HOST_OUT}/bin/dalvikvm64"
+        shift
     elif [ "x$1" = "x--no-verify" ]; then
         VERIFY="n"
         shift
@@ -103,8 +107,6 @@
 export LD_LIBRARY_PATH="${ANDROID_ROOT}/lib"
 export DYLD_LIBRARY_PATH="${ANDROID_ROOT}/lib"
 
-exe="${ANDROID_ROOT}/bin/dalvikvm"
-
 if [ "$DEBUGGER" = "y" ]; then
     PORT=8000
     msg "Waiting for jdb to connect:"