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:"