summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--Android.mk27
-rw-r--r--adbconnection/adbconnection.cc4
-rw-r--r--benchmark/jobject-benchmark/jobject_benchmark.cc2
-rw-r--r--build/Android.gtest.mk65
-rw-r--r--cmdline/cmdline_types.h10
-rw-r--r--compiler/driver/compiler_driver.cc2
-rw-r--r--compiler/driver/compiler_options.cc1
-rw-r--r--compiler/driver/compiler_options.h5
-rw-r--r--compiler/driver/compiler_options_map-inl.h7
-rw-r--r--compiler/driver/compiler_options_map.def1
-rw-r--r--compiler/jni/jni_compiler_test.cc4
-rw-r--r--compiler/jni/quick/jni_compiler.cc2
-rw-r--r--compiler/optimizing/code_generator.cc40
-rw-r--r--compiler/optimizing/code_generator.h10
-rw-r--r--compiler/optimizing/code_generator_arm64.cc20
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc20
-rw-r--r--compiler/optimizing/code_generator_mips.cc20
-rw-r--r--compiler/optimizing/code_generator_mips64.cc20
-rw-r--r--compiler/optimizing/code_generator_x86.cc20
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc20
-rw-r--r--compiler/optimizing/graph_visualizer.cc12
-rw-r--r--compiler/optimizing/instruction_builder.cc28
-rw-r--r--compiler/optimizing/instruction_builder.h7
-rw-r--r--compiler/optimizing/instruction_simplifier.cc4
-rw-r--r--compiler/optimizing/nodes.cc7
-rw-r--r--compiler/optimizing/nodes.h401
-rw-r--r--compiler/optimizing/nodes_mips.h4
-rw-r--r--compiler/optimizing/nodes_vector.h26
-rw-r--r--compiler/optimizing/nodes_x86.h4
-rw-r--r--compiler/optimizing/optimizing_compiler.cc2
-rw-r--r--compiler/optimizing/prepare_for_register_allocation.cc2
-rw-r--r--compiler/optimizing/reference_type_propagation.cc25
-rw-r--r--compiler/optimizing/reference_type_propagation.h4
-rw-r--r--compiler/optimizing/scheduler_arm64.h7
-rw-r--r--compiler/trampolines/trampoline_compiler.cc2
-rw-r--r--compiler/utils/arm/jni_macro_assembler_arm_vixl.cc304
-rw-r--r--compiler/utils/arm/managed_register_arm.h40
-rw-r--r--compiler/utils/arm64/managed_register_arm64.h1
-rw-r--r--compiler/utils/assembler_thumb_test_expected.cc.inc2
-rw-r--r--compiler/utils/mips/assembler_mips32r5_test.cc10
-rw-r--r--compiler/utils/mips/assembler_mips32r6_test.cc10
-rw-r--r--compiler/utils/mips/assembler_mips_test.cc10
-rw-r--r--compiler/utils/mips/managed_register_mips.h1
-rw-r--r--compiler/utils/mips64/assembler_mips64_test.cc10
-rw-r--r--compiler/utils/mips64/managed_register_mips64.h1
-rw-r--r--compiler/utils/x86/managed_register_x86.h1
-rw-r--r--compiler/utils/x86_64/managed_register_x86_64.h1
-rw-r--r--dex2oat/Android.bp2
-rw-r--r--dex2oat/dex2oat.cc9
-rw-r--r--dex2oat/linker/image_writer.cc2
-rw-r--r--dex2oat/linker/oat_writer_test.cc2
-rw-r--r--libdexfile/dex/dex_file_loader.cc2
-rw-r--r--libdexfile/dex/dex_file_loader.h2
-rw-r--r--libdexfile/dex/dex_file_verifier.cc190
-rw-r--r--libdexfile/dex/dex_file_verifier.h4
-rw-r--r--libdexfile/dex/hidden_api_access_flags.h10
-rw-r--r--libdexfile/dex/modifiers.h1
-rw-r--r--libprofile/profile/profile_compilation_info.cc12
-rw-r--r--libprofile/profile/profile_compilation_info.h3
-rw-r--r--libprofile/profile/profile_compilation_info_test.cc29
-rw-r--r--oatdump/Android.bp2
-rw-r--r--openjdkjvm/OpenjdkJvm.cc4
-rw-r--r--openjdkjvmti/OpenjdkJvmTi.cc2
-rw-r--r--openjdkjvmti/art_jvmti.h4
-rw-r--r--openjdkjvmti/deopt_manager.cc2
-rw-r--r--openjdkjvmti/events-inl.h2
-rw-r--r--openjdkjvmti/events.cc4
-rw-r--r--openjdkjvmti/jvmti_weak_table-inl.h2
-rw-r--r--openjdkjvmti/ti_breakpoint.cc2
-rw-r--r--openjdkjvmti/ti_class.cc4
-rw-r--r--openjdkjvmti/ti_class_loader-inl.h2
-rw-r--r--openjdkjvmti/ti_class_loader.cc2
-rw-r--r--openjdkjvmti/ti_class_loader.h2
-rw-r--r--openjdkjvmti/ti_field.cc2
-rw-r--r--openjdkjvmti/ti_heap.cc4
-rw-r--r--openjdkjvmti/ti_jni.cc4
-rw-r--r--openjdkjvmti/ti_method.cc2
-rw-r--r--openjdkjvmti/ti_redefine.cc2
-rw-r--r--openjdkjvmti/ti_redefine.h2
-rw-r--r--openjdkjvmti/ti_search.cc2
-rw-r--r--openjdkjvmti/ti_stack.cc4
-rw-r--r--openjdkjvmti/ti_thread.cc2
-rw-r--r--openjdkjvmti/ti_threadgroup.cc2
-rw-r--r--openjdkjvmti/transform.cc2
-rw-r--r--runtime/Android.bp13
-rw-r--r--runtime/arch/arm/instruction_set_features_arm.cc2
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S7
-rw-r--r--runtime/arch/arm64/instruction_set_features_arm64.cc2
-rw-r--r--runtime/arch/arm64/instruction_set_features_arm64_test.cc20
-rw-r--r--runtime/arch/arm64/quick_entrypoints_arm64.S7
-rw-r--r--runtime/arch/mips/entrypoints_init_mips.cc4
-rw-r--r--runtime/arch/mips/quick_entrypoints_mips.S19
-rw-r--r--runtime/arch/mips64/quick_entrypoints_mips64.S19
-rw-r--r--runtime/arch/stub_test.cc2
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S9
-rw-r--r--runtime/arch/x86_64/quick_entrypoints_x86_64.S9
-rw-r--r--runtime/art_field.h5
-rw-r--r--runtime/art_method-inl.h93
-rw-r--r--runtime/art_method.cc2
-rw-r--r--runtime/art_method.h7
-rw-r--r--runtime/asm_support.h2
-rw-r--r--runtime/base/file_utils.cc15
-rw-r--r--runtime/base/mutex.cc6
-rw-r--r--runtime/base/mutex.h23
-rw-r--r--runtime/check_jni.cc4
-rw-r--r--runtime/class_linker.cc46
-rw-r--r--runtime/class_linker.h9
-rw-r--r--runtime/class_loader_context.cc33
-rw-r--r--runtime/class_loader_context.h22
-rw-r--r--runtime/class_loader_context_test.cc44
-rw-r--r--runtime/class_loader_utils.h2
-rw-r--r--runtime/common_runtime_test.cc4
-rw-r--r--runtime/debugger.cc2
-rw-r--r--runtime/dex/art_dex_file_loader.cc5
-rw-r--r--runtime/dex/art_dex_file_loader_test.cc61
-rw-r--r--runtime/dex/dex_file_annotations.cc2
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h2
-rw-r--r--runtime/entrypoints/entrypoint_utils.cc24
-rw-r--r--runtime/entrypoints/entrypoint_utils.h11
-rw-r--r--runtime/entrypoints/jni/jni_entrypoints.cc2
-rw-r--r--runtime/entrypoints/quick/quick_default_externs.h2
-rw-r--r--runtime/entrypoints/quick/quick_default_init_entrypoints.h2
-rw-r--r--runtime/entrypoints/quick/quick_dexcache_entrypoints.cc21
-rw-r--r--runtime/entrypoints/quick/quick_entrypoints_list.h2
-rw-r--r--runtime/entrypoints_order_test.cc4
-rw-r--r--runtime/gc/collector/semi_space.cc2
-rw-r--r--runtime/gc/heap.cc2
-rw-r--r--runtime/gc/reference_processor.cc2
-rw-r--r--runtime/gc/space/region_space.h23
-rw-r--r--runtime/hidden_api.cc188
-rw-r--r--runtime/hidden_api.h107
-rw-r--r--runtime/hidden_api_test.cc97
-rw-r--r--runtime/indirect_reference_table.cc4
-rw-r--r--runtime/instrumentation_test.cc2
-rw-r--r--runtime/jdwp/object_registry.cc2
-rw-r--r--runtime/jit/jit.cc4
-rw-r--r--runtime/jit/jit.h7
-rw-r--r--runtime/jit/jit_code_cache.cc75
-rw-r--r--runtime/jit/jit_code_cache.h18
-rw-r--r--runtime/jit/profile_saver.cc42
-rw-r--r--runtime/jit/profile_saver_options.h30
-rw-r--r--runtime/jit/profiling_info.cc10
-rw-r--r--runtime/jit/profiling_info.h22
-rw-r--r--runtime/jni/java_vm_ext.cc (renamed from runtime/java_vm_ext.cc)0
-rw-r--r--runtime/jni/java_vm_ext.h (renamed from runtime/java_vm_ext.h)6
-rw-r--r--runtime/jni/java_vm_ext_test.cc (renamed from runtime/java_vm_ext_test.cc)2
-rw-r--r--runtime/jni/jni_env_ext-inl.h (renamed from runtime/jni_env_ext-inl.h)6
-rw-r--r--runtime/jni/jni_env_ext.cc (renamed from runtime/jni_env_ext.cc)0
-rw-r--r--runtime/jni/jni_env_ext.h (renamed from runtime/jni_env_ext.h)6
-rw-r--r--runtime/jni/jni_internal.cc (renamed from runtime/jni_internal.cc)6
-rw-r--r--runtime/jni/jni_internal.h (renamed from runtime/jni_internal.h)6
-rw-r--r--runtime/jni/jni_internal_test.cc (renamed from runtime/jni_internal_test.cc)0
-rw-r--r--runtime/jobject_comparator.cc56
-rw-r--r--runtime/mirror/class.h9
-rw-r--r--runtime/mirror/method_handles_lookup.cc2
-rw-r--r--runtime/mirror/var_handle.cc2
-rw-r--r--runtime/native/dalvik_system_DexFile.cc27
-rw-r--r--runtime/native/dalvik_system_VMDebug.cc24
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc16
-rw-r--r--runtime/native/dalvik_system_VMStack.cc2
-rw-r--r--runtime/native/dalvik_system_ZygoteHooks.cc21
-rw-r--r--runtime/native/java_lang_Class.cc41
-rw-r--r--runtime/native/java_lang_Object.cc2
-rw-r--r--runtime/native/java_lang_String.cc2
-rw-r--r--runtime/native/java_lang_StringFactory.cc2
-rw-r--r--runtime/native/java_lang_System.cc2
-rw-r--r--runtime/native/java_lang_Thread.cc2
-rw-r--r--runtime/native/java_lang_Throwable.cc2
-rw-r--r--runtime/native/java_lang_VMClassLoader.cc2
-rw-r--r--runtime/native/java_lang_invoke_MethodHandleImpl.cc2
-rw-r--r--runtime/native/java_lang_ref_FinalizerReference.cc2
-rw-r--r--runtime/native/java_lang_ref_Reference.cc2
-rw-r--r--runtime/native/java_lang_reflect_Array.cc2
-rw-r--r--runtime/native/java_lang_reflect_Constructor.cc2
-rw-r--r--runtime/native/java_lang_reflect_Executable.cc2
-rw-r--r--runtime/native/java_lang_reflect_Field.cc2
-rw-r--r--runtime/native/java_lang_reflect_Method.cc2
-rw-r--r--runtime/native/java_lang_reflect_Parameter.cc2
-rw-r--r--runtime/native/java_lang_reflect_Proxy.cc2
-rw-r--r--runtime/native/java_util_concurrent_atomic_AtomicLong.cc2
-rw-r--r--runtime/native/libcore_util_CharsetUtils.cc2
-rw-r--r--runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc2
-rw-r--r--runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc2
-rw-r--r--runtime/native/sun_misc_Unsafe.cc2
-rw-r--r--runtime/native_bridge_art_interface.cc2
-rw-r--r--runtime/non_debuggable_classes.cc2
-rw-r--r--runtime/oat.h4
-rw-r--r--runtime/oat_file_assistant.cc4
-rw-r--r--runtime/oat_file_manager.cc98
-rw-r--r--runtime/oat_file_manager.h26
-rw-r--r--runtime/parsed_options.cc7
-rw-r--r--runtime/proxy_test.cc99
-rw-r--r--runtime/proxy_test.h114
-rw-r--r--runtime/reflection.cc4
-rw-r--r--runtime/reflection_test.cc4
-rw-r--r--runtime/runtime.cc31
-rw-r--r--runtime/runtime.h29
-rw-r--r--runtime/runtime_options.def2
-rw-r--r--runtime/scoped_thread_state_change-inl.h2
-rw-r--r--runtime/scoped_thread_state_change.cc2
-rw-r--r--runtime/signal_catcher.cc56
-rw-r--r--runtime/signal_catcher.h19
-rw-r--r--runtime/thread-inl.h2
-rw-r--r--runtime/thread.cc4
-rw-r--r--runtime/thread_list.cc2
-rw-r--r--runtime/ti/agent.cc2
-rw-r--r--runtime/verifier/method_verifier.cc16
-rw-r--r--runtime/well_known_classes.cc2
-rw-r--r--test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc4
-rwxr-xr-xtest/172-app-image-twice/check18
-rw-r--r--test/172-app-image-twice/debug_print_class.cc33
-rw-r--r--test/172-app-image-twice/expected.txt1
-rw-r--r--test/172-app-image-twice/info.txt1
-rw-r--r--test/172-app-image-twice/profile1
-rw-r--r--test/172-app-image-twice/run28
-rw-r--r--test/172-app-image-twice/src/Main.java48
-rw-r--r--test/172-app-image-twice/src/TestClass.java18
-rw-r--r--test/1947-breakpoint-redefine-deopt/check_deopt.cc2
-rw-r--r--test/674-hiddenapi/src-art/Main.java53
-rw-r--r--test/674-hiddenapi/src-ex/ChildClass.java16
-rw-r--r--test/674-hiddenapi/src-ex/Linking.java52
-rw-r--r--test/674-hiddenapi/src/DummyClass.java26
-rw-r--r--test/674-hiddenapi/src/ParentInterface.java2
-rw-r--r--test/708-jit-cache-churn/jit.cc2
-rw-r--r--test/900-hello-plugin/load_unload.cc2
-rw-r--r--test/913-heaps/expected_d8.diff20
-rw-r--r--test/979-const-method-handle/expected.txt3
-rw-r--r--test/979-const-method-handle/src/Main.java114
-rw-r--r--test/Android.bp1
-rw-r--r--test/HiddenApiSignatures/Interface.java (renamed from runtime/jobject_comparator.h)19
-rw-r--r--test/common/stack_inspect.cc2
-rwxr-xr-xtest/etc/run-test-jar62
-rw-r--r--test/knownfailures.json6
-rwxr-xr-xtest/run-test48
-rw-r--r--test/testrunner/env.py2
-rwxr-xr-xtest/testrunner/testrunner.py3
-rwxr-xr-xtools/buildbot-build.sh4
-rwxr-xr-xtools/cleanup-buildbot-device.sh64
-rwxr-xr-xtools/run-jdwp-tests.sh17
-rwxr-xr-xtools/run-libcore-tests.sh29
-rwxr-xr-xtools/setup-buildbot-device.sh58
-rw-r--r--tools/veridex/flow_analysis.cc244
-rw-r--r--tools/veridex/flow_analysis.h122
-rw-r--r--tools/veridex/precise_hidden_api_finder.cc80
-rw-r--r--tools/veridex/precise_hidden_api_finder.h13
-rw-r--r--tools/veridex/veridex.cc12
-rw-r--r--tools/veridex/veridex.h4
248 files changed, 3333 insertions, 1474 deletions
diff --git a/Android.bp b/Android.bp
index 59f7abf138..34a646915f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -15,6 +15,7 @@ art_static_dependencies = [
"libbase",
"liblz4",
"liblzma",
+ "libmetricslogger_static",
]
subdirs = [
diff --git a/Android.mk b/Android.mk
index 64b9400f66..d6472be895 100644
--- a/Android.mk
+++ b/Android.mk
@@ -110,22 +110,33 @@ TEST_ART_ADB_ROOT_AND_REMOUNT := \
# Sync test files to the target, depends upon all things that must be pushed to the target.
.PHONY: test-art-target-sync
-# Check if we need to sync. In case ART_TEST_ANDROID_ROOT is not empty,
-# the code below uses 'adb push' instead of 'adb sync', which does not
-# check if the files on the device have changed.
+# Check if we need to sync. In case ART_TEST_CHROOT or ART_TEST_ANDROID_ROOT
+# is not empty, the code below uses 'adb push' instead of 'adb sync',
+# which does not check if the files on the device have changed.
+# TODO: Remove support for ART_TEST_ANDROID_ROOT when it is no longer needed.
ifneq ($(ART_TEST_NO_SYNC),true)
+# Sync system and data partitions.
ifeq ($(ART_TEST_ANDROID_ROOT),)
+ifeq ($(ART_TEST_CHROOT),)
test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS)
$(TEST_ART_ADB_ROOT_AND_REMOUNT)
adb sync system && adb sync data
else
test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS)
$(TEST_ART_ADB_ROOT_AND_REMOUNT)
- adb wait-for-device push $(PRODUCT_OUT)/system $(ART_TEST_ANDROID_ROOT)
-# Push the contents of the `data` dir into `/data` on the device. If
-# `/data` already exists on the device, it is not overwritten, but its
-# contents are updated.
- adb push $(PRODUCT_OUT)/data /
+ adb wait-for-device
+ adb push $(PRODUCT_OUT)/system $(ART_TEST_CHROOT)/
+ adb push $(PRODUCT_OUT)/data $(ART_TEST_CHROOT)/
+endif
+else
+test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS)
+ $(TEST_ART_ADB_ROOT_AND_REMOUNT)
+ adb wait-for-device
+ adb push $(PRODUCT_OUT)/system $(ART_TEST_CHROOT)$(ART_TEST_ANDROID_ROOT)
+# Push the contents of the `data` dir into `$(ART_TEST_CHROOT)/data` on the device (note
+# that $(ART_TEST_CHROOT) can be empty). If `$(ART_TEST_CHROOT)/data` already exists on
+# the device, it is not overwritten, but its content is updated.
+ adb push $(PRODUCT_OUT)/data $(ART_TEST_CHROOT)/
endif
endif
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index 4c2d4d72d8..8cd0d8bc9f 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -23,8 +23,8 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/mutex.h"
-#include "java_vm_ext.h"
-#include "jni_env_ext.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_env_ext.h"
#include "mirror/throwable.h"
#include "nativehelper/ScopedLocalRef.h"
#include "runtime-inl.h"
diff --git a/benchmark/jobject-benchmark/jobject_benchmark.cc b/benchmark/jobject-benchmark/jobject_benchmark.cc
index 7e0a5362c9..2f38b78eaf 100644
--- a/benchmark/jobject-benchmark/jobject_benchmark.cc
+++ b/benchmark/jobject-benchmark/jobject_benchmark.cc
@@ -16,7 +16,7 @@
#include "jni.h"
-#include "java_vm_ext.h"
+#include "jni/java_vm_ext.h"
#include "mirror/class-inl.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index b46f6771ea..3daaf0156e 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -472,17 +472,32 @@ define define-art-gtest-rule-target
$$(gtest_rule) valgrind-$$(gtest_rule): PRIVATE_TARGET_EXE := $$(gtest_target_exe)
+ifeq ($(ART_TEST_CHROOT),)
+# Non-chroot configuration.
+maybe_art_test_chroot :=
+maybe_chroot_command :=
+else
+# Chroot configuration.
+maybe_art_test_chroot := $(ART_TEST_CHROOT)/
+maybe_chroot_command := chroot $(ART_TEST_CHROOT)
+endif
+
+# File witnessing the success of the gtest, the presence of which means the gtest's success.
+gtest_witness := \
+ $(maybe_art_test_chroot)$(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$(gtest_rule)-$$$$PPID
+
+$$(gtest_rule): GTEST_WITNESS := $$(gtest_witness)
+
.PHONY: $$(gtest_rule)
$$(gtest_rule): test-art-target-sync
- $(hide) adb shell touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID
- $(hide) adb shell rm $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID
- $(hide) adb shell chmod 755 $$(PRIVATE_TARGET_EXE)
+ $(hide) adb shell touch $$(GTEST_WITNESS)
+ $(hide) adb shell rm $$(GTEST_WITNESS)
+ $(hide) adb shell chmod 755 $(maybe_art_test_chroot)$$(PRIVATE_TARGET_EXE)
$(hide) $$(call ART_TEST_SKIP,$$@) && \
- (adb shell "env $(GCOV_ENV) LD_LIBRARY_PATH=$(4) \
+ (adb shell "$(maybe_chroot_command) env $(GCOV_ENV) LD_LIBRARY_PATH=$(4) \
ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) $$(PRIVATE_TARGET_EXE) \
- && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID" \
- && (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID /tmp/ \
- && $$(call ART_TEST_PASSED,$$@)) \
+ && touch $$(GTEST_WITNESS)" \
+ && (adb pull $$(GTEST_WITNESS) /tmp/ && $$(call ART_TEST_PASSED,$$@)) \
|| $$(call ART_TEST_FAILED,$$@))
$(hide) rm -f /tmp/$$@-$$$$PPID
@@ -490,21 +505,27 @@ $$(gtest_rule): test-art-target-sync
ART_TEST_TARGET_GTEST_RULES += $$(gtest_rule)
ART_TEST_TARGET_GTEST_$(1)_RULES += $$(gtest_rule)
+# File witnessing the success of the Valgrind gtest, the presence of which means the gtest's
+# success.
+valgrind_gtest_witness := \
+ $(maybe_art_test_chroot)$(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/valgrind-$$(gtest_rule)-$$$$PPID
+
+valgrind-$$(gtest_rule): VALGRIND_GTEST_WITNESS := $$(valgrind_gtest_witness)
+
.PHONY: valgrind-$$(gtest_rule)
valgrind-$$(gtest_rule): $(ART_VALGRIND_TARGET_DEPENDENCIES) test-art-target-sync
- $(hide) adb shell touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID
- $(hide) adb shell rm $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID
- $(hide) adb shell chmod 755 $$(PRIVATE_TARGET_EXE)
+ $(hide) adb shell touch $$(VALGRIND_GTEST_WITNESS)
+ $(hide) adb shell rm $$(VALGRIND_GTEST_WITNESS)
+ $(hide) adb shell chmod 755 $(maybe_art_test_chroot)$$(PRIVATE_TARGET_EXE)
$(hide) $$(call ART_TEST_SKIP,$$@) && \
- (adb shell "env $(GCOV_ENV) LD_LIBRARY_PATH=$(4) \
+ (adb shell "$(maybe_chroot_command) env $(GCOV_ENV) LD_LIBRARY_PATH=$(4) \
ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
- $$$$ANDROID_ROOT/bin/valgrind \
+ $(ART_GTEST_TARGET_ANDROID_ROOT)/bin/valgrind \
--leak-check=full --error-exitcode=1 --workaround-gcc296-bugs=yes \
--suppressions=$(ART_TARGET_TEST_DIR)/valgrind-target-suppressions.txt \
--num-callers=50 --show-mismatched-frees=no $$(PRIVATE_TARGET_EXE) \
- && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID" \
- && (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID /tmp/ \
- && $$(call ART_TEST_PASSED,$$@)) \
+ && touch $$(VALGRIND_GTEST_WITNESS)" \
+ && (adb pull $$(VALGRIND_GTEST_WITNESS) /tmp/ && $$(call ART_TEST_PASSED,$$@)) \
|| $$(call ART_TEST_FAILED,$$@))
$(hide) rm -f /tmp/$$@-$$$$PPID
@@ -514,10 +535,13 @@ valgrind-$$(gtest_rule): $(ART_VALGRIND_TARGET_DEPENDENCIES) test-art-target-syn
ART_TEST_TARGET_VALGRIND_GTEST_$(1)_RULES += valgrind-$$(gtest_rule)
# Clear locally defined variables.
- valgrind_gtest_rule :=
- gtest_rule :=
- gtest_exe :=
+ valgrind_gtest_witness :=
+ gtest_witness :=
+ maybe_chroot_command :=
+ maybe_art_test_chroot :=
gtest_target_exe :=
+ gtest_exe :=
+ gtest_rule :=
endef # define-art-gtest-rule-target
ART_VALGRIND_DEPENDENCIES := \
@@ -595,10 +619,9 @@ valgrind-$$(gtest_rule): $$(gtest_exe) $$(gtest_deps) $(ART_VALGRIND_DEPENDENCIE
ART_TEST_HOST_VALGRIND_GTEST_$(1)_RULES += valgrind-$$(gtest_rule)
# Clear locally defined variables.
- valgrind_gtest_rule :=
- gtest_rule :=
- gtest_exe :=
gtest_deps :=
+ gtest_exe :=
+ gtest_rule :=
endef # define-art-gtest-rule-host
# Define the rules to build and run host and target gtests.
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 5a25a6ceb6..48da7551a7 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -643,6 +643,16 @@ struct CmdlineType<ProfileSaverOptions> : CmdlineTypeParser<ProfileSaverOptions>
return Result::SuccessNoValue();
}
+ if (option == "profile-aot-code") {
+ existing.profile_aot_code_ = true;
+ return Result::SuccessNoValue();
+ }
+
+ if (option == "save-without-jit-notifications") {
+ existing.wait_for_jit_notifications_to_save_ = false;
+ return Result::SuccessNoValue();
+ }
+
// The rest of these options are always the wildcard from '-Xps-*'
std::string suffix = RemovePrefix(option);
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index fbbb4e960f..39ed825001 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -57,7 +57,7 @@
#include "gc/space/space.h"
#include "handle_scope-inl.h"
#include "intrinsics_enum.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "linker/linker_patch.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 2d82d79c4a..933be4f004 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -51,6 +51,7 @@ CompilerOptions::CompilerOptions()
implicit_suspend_checks_(false),
compile_pic_(false),
dump_timings_(false),
+ dump_pass_timings_(false),
dump_stats_(false),
verbose_methods_(),
abort_on_hard_verifier_failure_(false),
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index cdd9d4de00..cee989b315 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -270,6 +270,10 @@ class CompilerOptions FINAL {
return dump_timings_;
}
+ bool GetDumpPassTimings() const {
+ return dump_pass_timings_;
+ }
+
bool GetDumpStats() const {
return dump_stats_;
}
@@ -316,6 +320,7 @@ class CompilerOptions FINAL {
bool implicit_suspend_checks_;
bool compile_pic_;
bool dump_timings_;
+ bool dump_pass_timings_;
bool dump_stats_;
// Vector of methods to have verbose output enabled for.
diff --git a/compiler/driver/compiler_options_map-inl.h b/compiler/driver/compiler_options_map-inl.h
index 3b18db09fc..32fc887b8e 100644
--- a/compiler/driver/compiler_options_map-inl.h
+++ b/compiler/driver/compiler_options_map-inl.h
@@ -85,6 +85,10 @@ inline bool ReadCompilerOptions(Base& map, CompilerOptions* options, std::string
options->dump_timings_ = true;
}
+ if (map.Exists(Base::DumpPassTimings)) {
+ options->dump_pass_timings_ = true;
+ }
+
if (map.Exists(Base::DumpStats)) {
options->dump_stats_ = true;
}
@@ -146,6 +150,9 @@ inline void AddCompilerOptionsArgumentParserOptions(Builder& b) {
.Define({"--dump-timings"})
.IntoKey(Map::DumpTimings)
+ .Define({"--dump-pass-timings"})
+ .IntoKey(Map::DumpPassTimings)
+
.Define({"--dump-stats"})
.IntoKey(Map::DumpStats)
diff --git a/compiler/driver/compiler_options_map.def b/compiler/driver/compiler_options_map.def
index acddae7299..529d43fc72 100644
--- a/compiler/driver/compiler_options_map.def
+++ b/compiler/driver/compiler_options_map.def
@@ -60,6 +60,7 @@ COMPILER_OPTIONS_KEY (ParseStringList<','>, VerboseMethods)
COMPILER_OPTIONS_KEY (bool, DeduplicateCode, true)
COMPILER_OPTIONS_KEY (Unit, CountHotnessInCompiledCode)
COMPILER_OPTIONS_KEY (Unit, DumpTimings)
+COMPILER_OPTIONS_KEY (Unit, DumpPassTimings)
COMPILER_OPTIONS_KEY (Unit, DumpStats)
#undef COMPILER_OPTIONS_KEY
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index 730a1a63e8..c643af787d 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -28,8 +28,8 @@
#include "dex/dex_file.h"
#include "gtest/gtest.h"
#include "indirect_reference_table.h"
-#include "java_vm_ext.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 8cb1998f7f..0902bf2bce 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -37,7 +37,7 @@
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
#include "entrypoints/quick/quick_entrypoints.h"
-#include "jni_env_ext.h"
+#include "jni/jni_env_ext.h"
#include "thread.h"
#include "utils/arm/managed_register_arm.h"
#include "utils/arm64/managed_register_arm64.h"
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 231017f55e..f57333741c 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -736,6 +736,46 @@ void CodeGenerator::GenerateLoadClassRuntimeCall(HLoadClass* cls) {
}
}
+void CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(
+ HLoadMethodHandle* method_handle,
+ Location runtime_proto_index_location,
+ Location runtime_return_location) {
+ DCHECK_EQ(method_handle->InputCount(), 1u);
+ LocationSummary* locations =
+ new (method_handle->GetBlock()->GetGraph()->GetAllocator()) LocationSummary(
+ method_handle, LocationSummary::kCallOnMainOnly);
+ locations->SetInAt(0, Location::NoLocation());
+ locations->AddTemp(runtime_proto_index_location);
+ locations->SetOut(runtime_return_location);
+}
+
+void CodeGenerator::GenerateLoadMethodHandleRuntimeCall(HLoadMethodHandle* method_handle) {
+ LocationSummary* locations = method_handle->GetLocations();
+ MoveConstant(locations->GetTemp(0), method_handle->GetMethodHandleIndex());
+ CheckEntrypointTypes<kQuickResolveMethodHandle, void*, uint32_t>();
+ InvokeRuntime(kQuickResolveMethodHandle, method_handle, method_handle->GetDexPc());
+}
+
+void CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(
+ HLoadMethodType* method_type,
+ Location runtime_proto_index_location,
+ Location runtime_return_location) {
+ DCHECK_EQ(method_type->InputCount(), 1u);
+ LocationSummary* locations =
+ new (method_type->GetBlock()->GetGraph()->GetAllocator()) LocationSummary(
+ method_type, LocationSummary::kCallOnMainOnly);
+ locations->SetInAt(0, Location::NoLocation());
+ locations->AddTemp(runtime_proto_index_location);
+ locations->SetOut(runtime_return_location);
+}
+
+void CodeGenerator::GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_type) {
+ LocationSummary* locations = method_type->GetLocations();
+ MoveConstant(locations->GetTemp(0), method_type->GetProtoIndex());
+ CheckEntrypointTypes<kQuickResolveMethodType, void*, uint32_t>();
+ InvokeRuntime(kQuickResolveMethodType, method_type, method_type->GetDexPc());
+}
+
static uint32_t GetBootImageOffsetImpl(const void* object, ImageHeader::ImageSections section) {
Runtime* runtime = Runtime::Current();
DCHECK(runtime->IsAotCompiler());
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index f0c4ee01cc..bcb25997f4 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -564,6 +564,16 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> {
Location runtime_return_location);
void GenerateLoadClassRuntimeCall(HLoadClass* cls);
+ static void CreateLoadMethodHandleRuntimeCallLocationSummary(HLoadMethodHandle* method_handle,
+ Location runtime_handle_index_location,
+ Location runtime_return_location);
+ void GenerateLoadMethodHandleRuntimeCall(HLoadMethodHandle* method_handle);
+
+ static void CreateLoadMethodTypeRuntimeCallLocationSummary(HLoadMethodType* method_type,
+ Location runtime_type_index_location,
+ Location runtime_return_location);
+ void GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_type);
+
uint32_t GetBootImageOffset(HLoadClass* load_class);
uint32_t GetBootImageOffset(HLoadString* load_string);
uint32_t GetBootImageOffset(HInvokeStaticOrDirect* invoke);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index d4cfab82de..6f173e19f5 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -5144,6 +5144,26 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SA
}
}
+void LocationsBuilderARM64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderARM64::VisitLoadMethodType(HLoadMethodType* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
static MemOperand GetExceptionTlsAddress() {
return MemOperand(tr, Thread::ExceptionOffset<kArm64PointerSize>().Int32Value());
}
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 58ce9aa9f0..859e1597c6 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -7527,6 +7527,26 @@ void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) NO_THREAD_
}
}
+void LocationsBuilderARMVIXL::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConventionARMVIXL calling_convention;
+ Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderARMVIXL::VisitLoadMethodType(HLoadMethodType* load) {
+ InvokeRuntimeCallingConventionARMVIXL calling_convention;
+ Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
void LocationsBuilderARMVIXL::VisitClinitCheck(HClinitCheck* check) {
LocationSummary* locations =
new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 25e2eddbfa..7f3441fdf4 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -8226,6 +8226,26 @@ void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAF
}
}
+void LocationsBuilderMIPS::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderMIPS::VisitLoadMethodType(HLoadMethodType* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
static int32_t GetExceptionTlsOffset() {
return Thread::ExceptionOffset<kMipsPointerSize>().Int32Value();
}
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 5b07b55cbb..ee32b96daf 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -6262,6 +6262,26 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) NO_THREAD_S
}
}
+void LocationsBuilderMIPS64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderMIPS64::VisitLoadMethodType(HLoadMethodType* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
static int32_t GetExceptionTlsOffset() {
return Thread::ExceptionOffset<kMips64PointerSize>().Int32Value();
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 82d1fda878..9e315381b1 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -6539,6 +6539,26 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFE
}
}
+void LocationsBuilderX86::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderX86::VisitLoadMethodType(HLoadMethodType* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
LocationSummary* locations =
new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 322b0cfc4c..f7397046d7 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -5908,6 +5908,26 @@ void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
}
}
+void LocationsBuilderX86_64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ // Custom calling convention: RAX serves as both input and output.
+ Location location = Location::RegisterLocation(RAX);
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86_64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderX86_64::VisitLoadMethodType(HLoadMethodType* load) {
+ // Custom calling convention: RAX serves as both input and output.
+ Location location = Location::RegisterLocation(RAX);
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86_64::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
// We assume the class to not be null.
SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) LoadClassSlowPathX86_64(
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 54d4644580..d65ad40565 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -386,6 +386,18 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor {
<< load_class->NeedsAccessCheck() << std::noboolalpha;
}
+ void VisitLoadMethodHandle(HLoadMethodHandle* load_method_handle) OVERRIDE {
+ StartAttributeStream("load_kind") << "RuntimeCall";
+ StartAttributeStream("method_handle_index") << load_method_handle->GetMethodHandleIndex();
+ }
+
+ void VisitLoadMethodType(HLoadMethodType* load_method_type) OVERRIDE {
+ StartAttributeStream("load_kind") << "RuntimeCall";
+ const DexFile& dex_file = load_method_type->GetDexFile();
+ const DexFile::ProtoId& proto_id = dex_file.GetProtoId(load_method_type->GetProtoIndex());
+ StartAttributeStream("method_type") << dex_file.GetProtoSignature(proto_id);
+ }
+
void VisitLoadString(HLoadString* load_string) OVERRIDE {
StartAttributeStream("load_kind") << load_string->GetLoadKind();
}
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 9647dd5d41..35a39456a2 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1896,6 +1896,20 @@ bool HInstructionBuilder::LoadClassNeedsAccessCheck(Handle<mirror::Class> klass)
}
}
+void HInstructionBuilder::BuildLoadMethodHandle(uint16_t proto_idx, uint32_t dex_pc) {
+ const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
+ HLoadMethodHandle* load_method_handle =
+ new (allocator_) HLoadMethodHandle(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc);
+ AppendInstruction(load_method_handle);
+}
+
+void HInstructionBuilder::BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc) {
+ const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
+ HLoadMethodType* load_method_type =
+ new (allocator_) HLoadMethodType(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc);
+ AppendInstruction(load_method_type);
+}
+
void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
uint8_t destination,
uint8_t reference,
@@ -2927,6 +2941,20 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
break;
}
+ case Instruction::CONST_METHOD_HANDLE: {
+ uint16_t method_handle_idx = instruction.VRegB_21c();
+ BuildLoadMethodHandle(method_handle_idx, dex_pc);
+ UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+ break;
+ }
+
+ case Instruction::CONST_METHOD_TYPE: {
+ uint16_t proto_idx = instruction.VRegB_21c();
+ BuildLoadMethodType(proto_idx, dex_pc);
+ UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+ break;
+ }
+
case Instruction::MOVE_EXCEPTION: {
AppendInstruction(new (allocator_) HLoadException(dex_pc));
UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction());
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index f78829232d..95ffa6b054 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -45,6 +45,7 @@ class VariableSizedHandleScope;
namespace mirror {
class Class;
+class MethodType;
} // namespace mirror
class HInstructionBuilder : public ValueObject {
@@ -239,6 +240,12 @@ class HInstructionBuilder : public ValueObject {
bool LoadClassNeedsAccessCheck(Handle<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Builds a `HLoadMethodHandle` loading the given `method_handle_idx`.
+ void BuildLoadMethodHandle(uint16_t method_handle_idx, uint32_t dex_pc);
+
+ // Builds a `HLoadMethodType` loading the given `proto_idx`.
+ void BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc);
+
// Returns the outer-most compiling method's class.
ObjPtr<mirror::Class> GetOutermostCompilingClass() const;
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 0fe16725f3..ca84d421a7 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -2666,10 +2666,10 @@ bool InstructionSimplifierVisitor::TryHandleAssociativeAndCommutativeOperation(
HConstant* const2;
HBinaryOperation* y;
- if (instruction->InstructionTypeEquals(left) && right->IsConstant()) {
+ if (instruction->GetKind() == left->GetKind() && right->IsConstant()) {
const2 = right->AsConstant();
y = left->AsBinaryOperation();
- } else if (left->IsConstant() && instruction->InstructionTypeEquals(right)) {
+ } else if (left->IsConstant() && instruction->GetKind() == right->GetKind()) {
const2 = left->AsConstant();
y = right->AsBinaryOperation();
} else {
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index f784f8f7f3..5f2833e9a6 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1680,10 +1680,9 @@ bool HCondition::IsBeforeWhenDisregardMoves(HInstruction* instruction) const {
}
bool HInstruction::Equals(const HInstruction* other) const {
- if (!InstructionTypeEquals(other)) return false;
- DCHECK_EQ(GetKind(), other->GetKind());
- if (!InstructionDataEquals(other)) return false;
+ if (GetKind() != other->GetKind()) return false;
if (GetType() != other->GetType()) return false;
+ if (!InstructionDataEquals(other)) return false;
HConstInputsRef inputs = GetInputs();
HConstInputsRef other_inputs = other->GetInputs();
if (inputs.size() != other_inputs.size()) return false;
@@ -1698,7 +1697,7 @@ bool HInstruction::Equals(const HInstruction* other) const {
std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs) {
#define DECLARE_CASE(type, super) case HInstruction::k##type: os << #type; break;
switch (rhs) {
- FOR_EACH_INSTRUCTION(DECLARE_CASE)
+ FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_CASE)
default:
os << "Unknown instruction kind " << static_cast<int>(rhs);
break;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 79d733060b..a7c2d0b125 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -41,6 +41,7 @@
#include "intrinsics_enum.h"
#include "locations.h"
#include "mirror/class.h"
+#include "mirror/method_type.h"
#include "offsets.h"
#include "utils/intrusive_forward_list.h"
@@ -1382,6 +1383,8 @@ class HLoopInformationOutwardIterator : public ValueObject {
M(LessThanOrEqual, Condition) \
M(LoadClass, Instruction) \
M(LoadException, Instruction) \
+ M(LoadMethodHandle, Instruction) \
+ M(LoadMethodType, Instruction) \
M(LoadString, Instruction) \
M(LongConstant, Constant) \
M(Max, Instruction) \
@@ -1525,9 +1528,6 @@ FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
H##type& operator=(const H##type&) = delete; \
public: \
const char* DebugName() const OVERRIDE { return #type; } \
- bool InstructionTypeEquals(const HInstruction* other) const OVERRIDE { \
- return other->Is##type(); \
- } \
HInstruction* Clone(ArenaAllocator* arena) const OVERRIDE { \
DCHECK(IsClonable()); \
return new (arena) H##type(*this->As##type()); \
@@ -1537,10 +1537,7 @@ FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
#define DECLARE_ABSTRACT_INSTRUCTION(type) \
private: \
H##type& operator=(const H##type&) = delete; \
- public: \
- bool Is##type() const { return As##type() != nullptr; } \
- const H##type* As##type() const { return this; } \
- H##type* As##type() { return this; }
+ public:
#define DEFAULT_COPY_CONSTRUCTOR(type) \
explicit H##type(const H##type& other) = default;
@@ -1959,12 +1956,15 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
public:
#define DECLARE_KIND(type, super) k##type,
enum InstructionKind {
- FOR_EACH_INSTRUCTION(DECLARE_KIND)
+ FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_KIND)
kLastInstructionKind
};
#undef DECLARE_KIND
HInstruction(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc)
+ : HInstruction(kind, DataType::Type::kVoid, side_effects, dex_pc) {}
+
+ HInstruction(InstructionKind kind, DataType::Type type, SideEffects side_effects, uint32_t dex_pc)
: previous_(nullptr),
next_(nullptr),
block_(nullptr),
@@ -1979,6 +1979,7 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
side_effects_(side_effects),
reference_type_handle_(ReferenceTypeInfo::CreateInvalid().GetTypeHandle()) {
SetPackedField<InstructionKindField>(kind);
+ SetPackedField<TypeField>(type);
SetPackedFlag<kFlagReferenceTypeIsExact>(ReferenceTypeInfo::CreateInvalid().IsExact());
}
@@ -2036,7 +2037,9 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
virtual void Accept(HGraphVisitor* visitor) = 0;
virtual const char* DebugName() const = 0;
- virtual DataType::Type GetType() const { return DataType::Type::kVoid; }
+ DataType::Type GetType() const {
+ return TypeField::Decode(GetPackedFields());
+ }
virtual bool NeedsEnvironment() const { return false; }
@@ -2228,19 +2231,17 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
void MoveBeforeFirstUserAndOutOfLoops();
#define INSTRUCTION_TYPE_CHECK(type, super) \
- bool Is##type() const; \
- const H##type* As##type() const; \
- H##type* As##type();
+ bool Is##type() const;
- FOR_EACH_CONCRETE_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
+ FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
#undef INSTRUCTION_TYPE_CHECK
-#define INSTRUCTION_TYPE_CHECK(type, super) \
- bool Is##type() const { return (As##type() != nullptr); } \
- virtual const H##type* As##type() const { return nullptr; } \
- virtual H##type* As##type() { return nullptr; }
- FOR_EACH_ABSTRACT_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
-#undef INSTRUCTION_TYPE_CHECK
+#define INSTRUCTION_TYPE_CAST(type, super) \
+ const H##type* As##type() const; \
+ H##type* As##type();
+
+ FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CAST)
+#undef INSTRUCTION_TYPE_CAST
// Return a clone of the instruction if it is clonable (shallow copy by default, custom copy
// if a custom copy-constructor is provided for a particular type). If IsClonable() is false for
@@ -2266,11 +2267,6 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
// meanings? split and rename?
virtual bool CanBeMoved() const { return false; }
- // Returns whether the two instructions are of the same kind.
- virtual bool InstructionTypeEquals(const HInstruction* other ATTRIBUTE_UNUSED) const {
- return false;
- }
-
// Returns whether any data encoded in the two instructions is equal.
// This method does not look at the inputs. Both instructions must be
// of the same type, otherwise the method has undefined behavior.
@@ -2342,13 +2338,18 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
static constexpr size_t kFieldInstructionKind = kFlagReferenceTypeIsExact + 1;
static constexpr size_t kFieldInstructionKindSize =
MinimumBitsToStore(static_cast<size_t>(InstructionKind::kLastInstructionKind - 1));
- static constexpr size_t kNumberOfGenericPackedBits =
+ static constexpr size_t kFieldType =
kFieldInstructionKind + kFieldInstructionKindSize;
+ static constexpr size_t kFieldTypeSize =
+ MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
+ static constexpr size_t kNumberOfGenericPackedBits = kFieldType + kFieldTypeSize;
static constexpr size_t kMaxNumberOfPackedBits = sizeof(uint32_t) * kBitsPerByte;
static_assert(kNumberOfGenericPackedBits <= kMaxNumberOfPackedBits,
"Too many generic packed fields");
+ using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>;
+
const HUserRecord<HInstruction*> InputRecordAt(size_t i) const {
return GetInputRecords()[i];
}
@@ -2595,6 +2596,15 @@ class HVariableInputSizeInstruction : public HInstruction {
ArenaAllocKind kind)
: HInstruction(inst_kind, side_effects, dex_pc),
inputs_(number_of_inputs, allocator->Adapter(kind)) {}
+ HVariableInputSizeInstruction(InstructionKind inst_kind,
+ DataType::Type type,
+ SideEffects side_effects,
+ uint32_t dex_pc,
+ ArenaAllocator* allocator,
+ size_t number_of_inputs,
+ ArenaAllocKind kind)
+ : HInstruction(inst_kind, type, side_effects, dex_pc),
+ inputs_(number_of_inputs, allocator->Adapter(kind)) {}
DEFAULT_COPY_CONSTRUCTOR(VariableInputSizeInstruction);
@@ -2602,11 +2612,16 @@ class HVariableInputSizeInstruction : public HInstruction {
};
template<size_t N>
-class HTemplateInstruction: public HInstruction {
+class HExpression : public HInstruction {
public:
- HTemplateInstruction<N>(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc)
+ HExpression<N>(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc)
: HInstruction(kind, side_effects, dex_pc), inputs_() {}
- virtual ~HTemplateInstruction() {}
+ HExpression<N>(InstructionKind kind,
+ DataType::Type type,
+ SideEffects side_effects,
+ uint32_t dex_pc)
+ : HInstruction(kind, type, side_effects, dex_pc), inputs_() {}
+ virtual ~HExpression() {}
using HInstruction::GetInputRecords; // Keep the const version visible.
ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
@@ -2614,7 +2629,7 @@ class HTemplateInstruction: public HInstruction {
}
protected:
- DEFAULT_COPY_CONSTRUCTOR(TemplateInstruction<N>);
+ DEFAULT_COPY_CONSTRUCTOR(Expression<N>);
private:
std::array<HUserRecord<HInstruction*>, N> inputs_;
@@ -2622,14 +2637,13 @@ class HTemplateInstruction: public HInstruction {
friend class SsaBuilder;
};
-// HTemplateInstruction specialization for N=0.
+// HExpression specialization for N=0.
template<>
-class HTemplateInstruction<0>: public HInstruction {
+class HExpression<0> : public HInstruction {
public:
- explicit HTemplateInstruction<0>(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc)
- : HInstruction(kind, side_effects, dex_pc) {}
+ using HInstruction::HInstruction;
- virtual ~HTemplateInstruction() {}
+ virtual ~HExpression() {}
using HInstruction::GetInputRecords; // Keep the const version visible.
ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
@@ -2637,46 +2651,18 @@ class HTemplateInstruction<0>: public HInstruction {
}
protected:
- DEFAULT_COPY_CONSTRUCTOR(TemplateInstruction<0>);
+ DEFAULT_COPY_CONSTRUCTOR(Expression<0>);
private:
friend class SsaBuilder;
};
-template<intptr_t N>
-class HExpression : public HTemplateInstruction<N> {
- public:
- using HInstruction::InstructionKind;
- HExpression<N>(InstructionKind kind,
- DataType::Type type,
- SideEffects side_effects,
- uint32_t dex_pc)
- : HTemplateInstruction<N>(kind, side_effects, dex_pc) {
- this->template SetPackedField<TypeField>(type);
- }
- virtual ~HExpression() {}
-
- DataType::Type GetType() const OVERRIDE {
- return TypeField::Decode(this->GetPackedFields());
- }
-
- protected:
- static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits;
- static constexpr size_t kFieldTypeSize =
- MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
- static constexpr size_t kNumberOfExpressionPackedBits = kFieldType + kFieldTypeSize;
- static_assert(kNumberOfExpressionPackedBits <= HInstruction::kMaxNumberOfPackedBits,
- "Too many packed fields.");
- using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>;
- DEFAULT_COPY_CONSTRUCTOR(Expression<N>);
-};
-
// Represents dex's RETURN_VOID opcode. A HReturnVoid is a control flow
// instruction that branches to the exit block.
-class HReturnVoid FINAL : public HTemplateInstruction<0> {
+class HReturnVoid FINAL : public HExpression<0> {
public:
explicit HReturnVoid(uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(kReturnVoid, SideEffects::None(), dex_pc) {
+ : HExpression(kReturnVoid, SideEffects::None(), dex_pc) {
}
bool IsControlFlow() const OVERRIDE { return true; }
@@ -2689,10 +2675,10 @@ class HReturnVoid FINAL : public HTemplateInstruction<0> {
// Represents dex's RETURN opcodes. A HReturn is a control flow
// instruction that branches to the exit block.
-class HReturn FINAL : public HTemplateInstruction<1> {
+class HReturn FINAL : public HExpression<1> {
public:
explicit HReturn(HInstruction* value, uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(kReturn, SideEffects::None(), dex_pc) {
+ : HExpression(kReturn, SideEffects::None(), dex_pc) {
SetRawInputAt(0, value);
}
@@ -2713,13 +2699,13 @@ class HPhi FINAL : public HVariableInputSizeInstruction {
uint32_t dex_pc = kNoDexPc)
: HVariableInputSizeInstruction(
kPhi,
+ ToPhiType(type),
SideEffects::None(),
dex_pc,
allocator,
number_of_inputs,
kArenaAllocPhiInputs),
reg_number_(reg_number) {
- SetPackedField<TypeField>(ToPhiType(type));
DCHECK_NE(GetType(), DataType::Type::kVoid);
// Phis are constructed live and marked dead if conflicting or unused.
// Individual steps of SsaBuilder should assume that if a phi has been
@@ -2737,7 +2723,6 @@ class HPhi FINAL : public HVariableInputSizeInstruction {
bool IsCatchPhi() const { return GetBlock()->IsCatchBlock(); }
- DataType::Type GetType() const OVERRIDE { return GetPackedField<TypeField>(); }
void SetType(DataType::Type new_type) {
// Make sure that only valid type changes occur. The following are allowed:
// (1) int -> float/ref (primitive type propagation),
@@ -2796,14 +2781,10 @@ class HPhi FINAL : public HVariableInputSizeInstruction {
DEFAULT_COPY_CONSTRUCTOR(Phi);
private:
- static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits;
- static constexpr size_t kFieldTypeSize =
- MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
- static constexpr size_t kFlagIsLive = kFieldType + kFieldTypeSize;
+ static constexpr size_t kFlagIsLive = HInstruction::kNumberOfGenericPackedBits;
static constexpr size_t kFlagCanBeNull = kFlagIsLive + 1;
static constexpr size_t kNumberOfPhiPackedBits = kFlagCanBeNull + 1;
static_assert(kNumberOfPhiPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
- using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>;
const uint32_t reg_number_;
};
@@ -2811,10 +2792,10 @@ class HPhi FINAL : public HVariableInputSizeInstruction {
// The exit instruction is the only instruction of the exit block.
// Instructions aborting the method (HThrow and HReturn) must branch to the
// exit block.
-class HExit FINAL : public HTemplateInstruction<0> {
+class HExit FINAL : public HExpression<0> {
public:
explicit HExit(uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(kExit, SideEffects::None(), dex_pc) {
+ : HExpression(kExit, SideEffects::None(), dex_pc) {
}
bool IsControlFlow() const OVERRIDE { return true; }
@@ -2826,10 +2807,10 @@ class HExit FINAL : public HTemplateInstruction<0> {
};
// Jumps from one block to another.
-class HGoto FINAL : public HTemplateInstruction<0> {
+class HGoto FINAL : public HExpression<0> {
public:
explicit HGoto(uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(kGoto, SideEffects::None(), dex_pc) {
+ : HExpression(kGoto, SideEffects::None(), dex_pc) {
}
bool IsClonable() const OVERRIDE { return true; }
@@ -3096,10 +3077,10 @@ class HDoubleConstant FINAL : public HConstant {
// Conditional branch. A block ending with an HIf instruction must have
// two successors.
-class HIf FINAL : public HTemplateInstruction<1> {
+class HIf FINAL : public HExpression<1> {
public:
explicit HIf(HInstruction* input, uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(kIf, SideEffects::None(), dex_pc) {
+ : HExpression(kIf, SideEffects::None(), dex_pc) {
SetRawInputAt(0, input);
}
@@ -3126,7 +3107,7 @@ class HIf FINAL : public HTemplateInstruction<1> {
// non-exceptional control flow.
// Normal-flow successor is stored at index zero, exception handlers under
// higher indices in no particular order.
-class HTryBoundary FINAL : public HTemplateInstruction<0> {
+class HTryBoundary FINAL : public HExpression<0> {
public:
enum class BoundaryKind {
kEntry,
@@ -3135,7 +3116,7 @@ class HTryBoundary FINAL : public HTemplateInstruction<0> {
};
explicit HTryBoundary(BoundaryKind kind, uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(kTryBoundary, SideEffects::None(), dex_pc) {
+ : HExpression(kTryBoundary, SideEffects::None(), dex_pc) {
SetPackedField<BoundaryKindField>(kind);
}
@@ -3219,6 +3200,7 @@ class HDeoptimize FINAL : public HVariableInputSizeInstruction {
uint32_t dex_pc)
: HVariableInputSizeInstruction(
kDeoptimize,
+ guard->GetType(),
SideEffects::CanTriggerGC(),
dex_pc,
allocator,
@@ -3242,10 +3224,6 @@ class HDeoptimize FINAL : public HVariableInputSizeInstruction {
DeoptimizationKind GetDeoptimizationKind() const { return GetPackedField<DeoptimizeKindField>(); }
- DataType::Type GetType() const OVERRIDE {
- return GuardsAnInput() ? GuardedInput()->GetType() : DataType::Type::kVoid;
- }
-
bool GuardsAnInput() const {
return InputCount() == 2;
}
@@ -3288,6 +3266,7 @@ class HShouldDeoptimizeFlag FINAL : public HVariableInputSizeInstruction {
// with regard to other passes.
HShouldDeoptimizeFlag(ArenaAllocator* allocator, uint32_t dex_pc)
: HVariableInputSizeInstruction(kShouldDeoptimizeFlag,
+ DataType::Type::kInt32,
SideEffects::None(),
dex_pc,
allocator,
@@ -3295,8 +3274,6 @@ class HShouldDeoptimizeFlag FINAL : public HVariableInputSizeInstruction {
kArenaAllocCHA) {
}
- DataType::Type GetType() const OVERRIDE { return DataType::Type::kInt32; }
-
// We do all CHA guard elimination/motion in a single pass, after which there is no
// further guard elimination/motion since a guard might have been used for justification
// of the elimination of another guard. Therefore, we pretend this guard cannot be moved
@@ -3360,7 +3337,7 @@ class HClassTableGet FINAL : public HExpression<1> {
DEFAULT_COPY_CONSTRUCTOR(ClassTableGet);
private:
- static constexpr size_t kFieldTableKind = kNumberOfExpressionPackedBits;
+ static constexpr size_t kFieldTableKind = kNumberOfGenericPackedBits;
static constexpr size_t kFieldTableKindSize =
MinimumBitsToStore(static_cast<size_t>(TableKind::kLast));
static constexpr size_t kNumberOfClassTableGetPackedBits = kFieldTableKind + kFieldTableKindSize;
@@ -3375,13 +3352,13 @@ class HClassTableGet FINAL : public HExpression<1> {
// PackedSwitch (jump table). A block ending with a PackedSwitch instruction will
// have one successor for each entry in the switch table, and the final successor
// will be the block containing the next Dex opcode.
-class HPackedSwitch FINAL : public HTemplateInstruction<1> {
+class HPackedSwitch FINAL : public HExpression<1> {
public:
HPackedSwitch(int32_t start_value,
uint32_t num_entries,
HInstruction* input,
uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(kPackedSwitch, SideEffects::None(), dex_pc),
+ : HExpression(kPackedSwitch, SideEffects::None(), dex_pc),
start_value_(start_value),
num_entries_(num_entries) {
SetRawInputAt(0, input);
@@ -3611,7 +3588,7 @@ class HCondition : public HBinaryOperation {
protected:
// Needed if we merge a HCompare into a HCondition.
- static constexpr size_t kFieldComparisonBias = kNumberOfExpressionPackedBits;
+ static constexpr size_t kFieldComparisonBias = kNumberOfGenericPackedBits;
static constexpr size_t kFieldComparisonBiasSize =
MinimumBitsToStore(static_cast<size_t>(ComparisonBias::kLast));
static constexpr size_t kNumberOfConditionPackedBits =
@@ -4131,7 +4108,7 @@ class HCompare FINAL : public HBinaryOperation {
DECLARE_INSTRUCTION(Compare);
protected:
- static constexpr size_t kFieldComparisonBias = kNumberOfExpressionPackedBits;
+ static constexpr size_t kFieldComparisonBias = kNumberOfGenericPackedBits;
static constexpr size_t kFieldComparisonBiasSize =
MinimumBitsToStore(static_cast<size_t>(ComparisonBias::kLast));
static constexpr size_t kNumberOfComparePackedBits =
@@ -4210,7 +4187,7 @@ class HNewInstance FINAL : public HExpression<1> {
DEFAULT_COPY_CONSTRUCTOR(NewInstance);
private:
- static constexpr size_t kFlagFinalizable = kNumberOfExpressionPackedBits;
+ static constexpr size_t kFlagFinalizable = kNumberOfGenericPackedBits;
static constexpr size_t kNumberOfNewInstancePackedBits = kFlagFinalizable + 1;
static_assert(kNumberOfNewInstancePackedBits <= kMaxNumberOfPackedBits,
"Too many packed fields.");
@@ -4251,8 +4228,6 @@ class HInvoke : public HVariableInputSizeInstruction {
// inputs at the end of their list of inputs.
uint32_t GetNumberOfArguments() const { return number_of_arguments_; }
- DataType::Type GetType() const OVERRIDE { return GetPackedField<ReturnTypeField>(); }
-
uint32_t GetDexMethodIndex() const { return dex_method_index_; }
InvokeType GetInvokeType() const {
@@ -4305,16 +4280,11 @@ class HInvoke : public HVariableInputSizeInstruction {
static constexpr size_t kFieldInvokeType = kNumberOfGenericPackedBits;
static constexpr size_t kFieldInvokeTypeSize =
MinimumBitsToStore(static_cast<size_t>(kMaxInvokeType));
- static constexpr size_t kFieldReturnType =
- kFieldInvokeType + kFieldInvokeTypeSize;
- static constexpr size_t kFieldReturnTypeSize =
- MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
- static constexpr size_t kFlagCanThrow = kFieldReturnType + kFieldReturnTypeSize;
+ static constexpr size_t kFlagCanThrow = kFieldInvokeType + kFieldInvokeTypeSize;
static constexpr size_t kFlagAlwaysThrows = kFlagCanThrow + 1;
static constexpr size_t kNumberOfInvokePackedBits = kFlagAlwaysThrows + 1;
static_assert(kNumberOfInvokePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
using InvokeTypeField = BitField<InvokeType, kFieldInvokeType, kFieldInvokeTypeSize>;
- using ReturnTypeField = BitField<DataType::Type, kFieldReturnType, kFieldReturnTypeSize>;
HInvoke(InstructionKind kind,
ArenaAllocator* allocator,
@@ -4327,6 +4297,7 @@ class HInvoke : public HVariableInputSizeInstruction {
InvokeType invoke_type)
: HVariableInputSizeInstruction(
kind,
+ return_type,
SideEffects::AllExceptGCDependency(), // Assume write/read on all fields/arrays.
dex_pc,
allocator,
@@ -4337,7 +4308,6 @@ class HInvoke : public HVariableInputSizeInstruction {
dex_method_index_(dex_method_index),
intrinsic_(Intrinsics::kNone),
intrinsic_optimizations_(0) {
- SetPackedField<ReturnTypeField>(return_type);
SetPackedField<InvokeTypeField>(invoke_type);
SetPackedFlag<kFlagCanThrow>(true);
}
@@ -4550,7 +4520,7 @@ class HInvokeStaticOrDirect FINAL : public HInvoke {
}
bool CanBeNull() const OVERRIDE {
- return GetPackedField<ReturnTypeField>() == DataType::Type::kReference && !IsStringInit();
+ return GetType() == DataType::Type::kReference && !IsStringInit();
}
// Get the index of the special input, if any.
@@ -5146,8 +5116,6 @@ class HDivZeroCheck FINAL : public HExpression<1> {
SetRawInputAt(0, value);
}
- DataType::Type GetType() const OVERRIDE { return InputAt(0)->GetType(); }
-
bool CanBeMoved() const OVERRIDE { return true; }
bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
@@ -5500,7 +5468,7 @@ class HParameterValue FINAL : public HExpression<0> {
private:
// Whether or not the parameter value corresponds to 'this' argument.
- static constexpr size_t kFlagIsThis = kNumberOfExpressionPackedBits;
+ static constexpr size_t kFlagIsThis = kNumberOfGenericPackedBits;
static constexpr size_t kFlagCanBeNull = kFlagIsThis + 1;
static constexpr size_t kNumberOfParameterValuePackedBits = kFlagCanBeNull + 1;
static_assert(kNumberOfParameterValuePackedBits <= kMaxNumberOfPackedBits,
@@ -5742,7 +5710,7 @@ class HInstanceFieldGet FINAL : public HExpression<1> {
const FieldInfo field_info_;
};
-class HInstanceFieldSet FINAL : public HTemplateInstruction<2> {
+class HInstanceFieldSet FINAL : public HExpression<2> {
public:
HInstanceFieldSet(HInstruction* object,
HInstruction* value,
@@ -5754,9 +5722,9 @@ class HInstanceFieldSet FINAL : public HTemplateInstruction<2> {
uint16_t declaring_class_def_index,
const DexFile& dex_file,
uint32_t dex_pc)
- : HTemplateInstruction(kInstanceFieldSet,
- SideEffects::FieldWriteOfType(field_type, is_volatile),
- dex_pc),
+ : HExpression(kInstanceFieldSet,
+ SideEffects::FieldWriteOfType(field_type, is_volatile),
+ dex_pc),
field_info_(field,
field_offset,
field_type,
@@ -5882,13 +5850,13 @@ class HArrayGet FINAL : public HExpression<2> {
// a particular HArrayGet is actually a String.charAt() by looking at the type
// of the input but that requires holding the mutator lock, so we prefer to use
// a flag, so that code generators don't need to do the locking.
- static constexpr size_t kFlagIsStringCharAt = kNumberOfExpressionPackedBits;
+ static constexpr size_t kFlagIsStringCharAt = kNumberOfGenericPackedBits;
static constexpr size_t kNumberOfArrayGetPackedBits = kFlagIsStringCharAt + 1;
static_assert(kNumberOfArrayGetPackedBits <= HInstruction::kMaxNumberOfPackedBits,
"Too many packed fields.");
};
-class HArraySet FINAL : public HTemplateInstruction<3> {
+class HArraySet FINAL : public HExpression<3> {
public:
HArraySet(HInstruction* array,
HInstruction* index,
@@ -5910,7 +5878,7 @@ class HArraySet FINAL : public HTemplateInstruction<3> {
DataType::Type expected_component_type,
SideEffects side_effects,
uint32_t dex_pc)
- : HTemplateInstruction(kArraySet, side_effects, dex_pc) {
+ : HExpression(kArraySet, side_effects, dex_pc) {
SetPackedField<ExpectedComponentTypeField>(expected_component_type);
SetPackedFlag<kFlagNeedsTypeCheck>(value->GetType() == DataType::Type::kReference);
SetPackedFlag<kFlagValueCanBeNull>(true);
@@ -6039,7 +6007,7 @@ class HArrayLength FINAL : public HExpression<1> {
// determine whether a particular HArrayLength is actually a String.length() by
// looking at the type of the input but that requires holding the mutator lock, so
// we prefer to use a flag, so that code generators don't need to do the locking.
- static constexpr size_t kFlagIsStringLength = kNumberOfExpressionPackedBits;
+ static constexpr size_t kFlagIsStringLength = kNumberOfGenericPackedBits;
static constexpr size_t kNumberOfArrayLengthPackedBits = kFlagIsStringLength + 1;
static_assert(kNumberOfArrayLengthPackedBits <= HInstruction::kMaxNumberOfPackedBits,
"Too many packed fields.");
@@ -6080,13 +6048,13 @@ class HBoundsCheck FINAL : public HExpression<2> {
DEFAULT_COPY_CONSTRUCTOR(BoundsCheck);
private:
- static constexpr size_t kFlagIsStringCharAt = kNumberOfExpressionPackedBits;
+ static constexpr size_t kFlagIsStringCharAt = kNumberOfGenericPackedBits;
};
-class HSuspendCheck FINAL : public HTemplateInstruction<0> {
+class HSuspendCheck FINAL : public HExpression<0> {
public:
explicit HSuspendCheck(uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(kSuspendCheck, SideEffects::CanTriggerGC(), dex_pc),
+ : HExpression(kSuspendCheck, SideEffects::CanTriggerGC(), dex_pc),
slow_path_(nullptr) {
}
@@ -6112,10 +6080,10 @@ class HSuspendCheck FINAL : public HTemplateInstruction<0> {
// Pseudo-instruction which provides the native debugger with mapping information.
// It ensures that we can generate line number and local variables at this point.
-class HNativeDebugInfo : public HTemplateInstruction<0> {
+class HNativeDebugInfo : public HExpression<0> {
public:
explicit HNativeDebugInfo(uint32_t dex_pc)
- : HTemplateInstruction<0>(kNativeDebugInfo, SideEffects::None(), dex_pc) {
+ : HExpression<0>(kNativeDebugInfo, SideEffects::None(), dex_pc) {
}
bool NeedsEnvironment() const OVERRIDE {
@@ -6174,7 +6142,10 @@ class HLoadClass FINAL : public HInstruction {
bool is_referrers_class,
uint32_t dex_pc,
bool needs_access_check)
- : HInstruction(kLoadClass, SideEffectsForArchRuntimeCalls(), dex_pc),
+ : HInstruction(kLoadClass,
+ DataType::Type::kReference,
+ SideEffectsForArchRuntimeCalls(),
+ dex_pc),
special_input_(HUserRecord<HInstruction*>(current_method)),
type_index_(type_index),
dex_file_(dex_file),
@@ -6285,10 +6256,6 @@ class HLoadClass FINAL : public HInstruction {
&special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u);
}
- DataType::Type GetType() const OVERRIDE {
- return DataType::Type::kReference;
- }
-
Handle<mirror::Class> GetClass() const {
return klass_;
}
@@ -6399,7 +6366,10 @@ class HLoadString FINAL : public HInstruction {
dex::StringIndex string_index,
const DexFile& dex_file,
uint32_t dex_pc)
- : HInstruction(kLoadString, SideEffectsForArchRuntimeCalls(), dex_pc),
+ : HInstruction(kLoadString,
+ DataType::Type::kReference,
+ SideEffectsForArchRuntimeCalls(),
+ dex_pc),
special_input_(HUserRecord<HInstruction*>(current_method)),
string_index_(string_index),
dex_file_(dex_file) {
@@ -6474,10 +6444,6 @@ class HLoadString FINAL : public HInstruction {
&special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u);
}
- DataType::Type GetType() const OVERRIDE {
- return DataType::Type::kReference;
- }
-
DECLARE_INSTRUCTION(LoadString);
protected:
@@ -6535,6 +6501,94 @@ inline void HLoadString::AddSpecialInput(HInstruction* special_input) {
special_input->AddUseAt(this, 0);
}
+class HLoadMethodHandle FINAL : public HInstruction {
+ public:
+ HLoadMethodHandle(HCurrentMethod* current_method,
+ uint16_t method_handle_idx,
+ const DexFile& dex_file,
+ uint32_t dex_pc)
+ : HInstruction(kLoadMethodHandle,
+ DataType::Type::kReference,
+ SideEffectsForArchRuntimeCalls(),
+ dex_pc),
+ special_input_(HUserRecord<HInstruction*>(current_method)),
+ method_handle_idx_(method_handle_idx),
+ dex_file_(dex_file) {
+ }
+
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
+ return ArrayRef<HUserRecord<HInstruction*>>(
+ &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u);
+ }
+
+ bool IsClonable() const OVERRIDE { return true; }
+
+ uint16_t GetMethodHandleIndex() const { return method_handle_idx_; }
+
+ const DexFile& GetDexFile() const { return dex_file_; }
+
+ static SideEffects SideEffectsForArchRuntimeCalls() {
+ return SideEffects::CanTriggerGC();
+ }
+
+ DECLARE_INSTRUCTION(LoadMethodHandle);
+
+ protected:
+ DEFAULT_COPY_CONSTRUCTOR(LoadMethodHandle);
+
+ private:
+ // The special input is the HCurrentMethod for kRuntimeCall.
+ HUserRecord<HInstruction*> special_input_;
+
+ const uint16_t method_handle_idx_;
+ const DexFile& dex_file_;
+};
+
+class HLoadMethodType FINAL : public HInstruction {
+ public:
+ HLoadMethodType(HCurrentMethod* current_method,
+ uint16_t proto_idx,
+ const DexFile& dex_file,
+ uint32_t dex_pc)
+ : HInstruction(kLoadMethodType,
+ DataType::Type::kReference,
+ SideEffectsForArchRuntimeCalls(),
+ dex_pc),
+ special_input_(HUserRecord<HInstruction*>(current_method)),
+ proto_idx_(proto_idx),
+ dex_file_(dex_file) {
+ }
+
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
+ return ArrayRef<HUserRecord<HInstruction*>>(
+ &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u);
+ }
+
+ bool IsClonable() const OVERRIDE { return true; }
+
+ uint16_t GetProtoIndex() const { return proto_idx_; }
+
+ const DexFile& GetDexFile() const { return dex_file_; }
+
+ static SideEffects SideEffectsForArchRuntimeCalls() {
+ return SideEffects::CanTriggerGC();
+ }
+
+ DECLARE_INSTRUCTION(LoadMethodType);
+
+ protected:
+ DEFAULT_COPY_CONSTRUCTOR(LoadMethodType);
+
+ private:
+ // The special input is the HCurrentMethod for kRuntimeCall.
+ HUserRecord<HInstruction*> special_input_;
+
+ const uint16_t proto_idx_;
+ const DexFile& dex_file_;
+};
+
/**
* Performs an initialization check on its Class object input.
*/
@@ -6633,7 +6687,7 @@ class HStaticFieldGet FINAL : public HExpression<1> {
const FieldInfo field_info_;
};
-class HStaticFieldSet FINAL : public HTemplateInstruction<2> {
+class HStaticFieldSet FINAL : public HExpression<2> {
public:
HStaticFieldSet(HInstruction* cls,
HInstruction* value,
@@ -6645,9 +6699,9 @@ class HStaticFieldSet FINAL : public HTemplateInstruction<2> {
uint16_t declaring_class_def_index,
const DexFile& dex_file,
uint32_t dex_pc)
- : HTemplateInstruction(kStaticFieldSet,
- SideEffects::FieldWriteOfType(field_type, is_volatile),
- dex_pc),
+ : HExpression(kStaticFieldSet,
+ SideEffects::FieldWriteOfType(field_type, is_volatile),
+ dex_pc),
field_info_(field,
field_offset,
field_type,
@@ -6714,16 +6768,14 @@ class HUnresolvedInstanceFieldGet FINAL : public HExpression<1> {
const uint32_t field_index_;
};
-class HUnresolvedInstanceFieldSet FINAL : public HTemplateInstruction<2> {
+class HUnresolvedInstanceFieldSet FINAL : public HExpression<2> {
public:
HUnresolvedInstanceFieldSet(HInstruction* obj,
HInstruction* value,
DataType::Type field_type,
uint32_t field_index,
uint32_t dex_pc)
- : HTemplateInstruction(kUnresolvedInstanceFieldSet,
- SideEffects::AllExceptGCDependency(),
- dex_pc),
+ : HExpression(kUnresolvedInstanceFieldSet, SideEffects::AllExceptGCDependency(), dex_pc),
field_index_(field_index) {
SetPackedField<FieldTypeField>(field_type);
DCHECK_EQ(DataType::Kind(field_type), DataType::Kind(value->GetType()));
@@ -6784,15 +6836,13 @@ class HUnresolvedStaticFieldGet FINAL : public HExpression<0> {
const uint32_t field_index_;
};
-class HUnresolvedStaticFieldSet FINAL : public HTemplateInstruction<1> {
+class HUnresolvedStaticFieldSet FINAL : public HExpression<1> {
public:
HUnresolvedStaticFieldSet(HInstruction* value,
DataType::Type field_type,
uint32_t field_index,
uint32_t dex_pc)
- : HTemplateInstruction(kUnresolvedStaticFieldSet,
- SideEffects::AllExceptGCDependency(),
- dex_pc),
+ : HExpression(kUnresolvedStaticFieldSet, SideEffects::AllExceptGCDependency(), dex_pc),
field_index_(field_index) {
SetPackedField<FieldTypeField>(field_type);
DCHECK_EQ(DataType::Kind(field_type), DataType::Kind(value->GetType()));
@@ -6841,10 +6891,10 @@ class HLoadException FINAL : public HExpression<0> {
// Implicit part of move-exception which clears thread-local exception storage.
// Must not be removed because the runtime expects the TLS to get cleared.
-class HClearException FINAL : public HTemplateInstruction<0> {
+class HClearException FINAL : public HExpression<0> {
public:
explicit HClearException(uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(kClearException, SideEffects::AllWrites(), dex_pc) {
+ : HExpression(kClearException, SideEffects::AllWrites(), dex_pc) {
}
DECLARE_INSTRUCTION(ClearException);
@@ -6853,10 +6903,10 @@ class HClearException FINAL : public HTemplateInstruction<0> {
DEFAULT_COPY_CONSTRUCTOR(ClearException);
};
-class HThrow FINAL : public HTemplateInstruction<1> {
+class HThrow FINAL : public HExpression<1> {
public:
HThrow(HInstruction* exception, uint32_t dex_pc)
- : HTemplateInstruction(kThrow, SideEffects::CanTriggerGC(), dex_pc) {
+ : HExpression(kThrow, SideEffects::CanTriggerGC(), dex_pc) {
SetRawInputAt(0, exception);
}
@@ -6897,6 +6947,7 @@ std::ostream& operator<<(std::ostream& os, TypeCheckKind rhs);
class HTypeCheckInstruction : public HVariableInputSizeInstruction {
public:
HTypeCheckInstruction(InstructionKind kind,
+ DataType::Type type,
HInstruction* object,
HInstruction* target_class_or_null,
TypeCheckKind check_kind,
@@ -6908,6 +6959,7 @@ class HTypeCheckInstruction : public HVariableInputSizeInstruction {
SideEffects side_effects)
: HVariableInputSizeInstruction(
kind,
+ type,
side_effects,
dex_pc,
allocator,
@@ -7010,6 +7062,7 @@ class HInstanceOf FINAL : public HTypeCheckInstruction {
HIntConstant* bitstring_path_to_root,
HIntConstant* bitstring_mask)
: HTypeCheckInstruction(kInstanceOf,
+ DataType::Type::kBool,
object,
target_class_or_null,
check_kind,
@@ -7020,8 +7073,6 @@ class HInstanceOf FINAL : public HTypeCheckInstruction {
bitstring_mask,
SideEffectsForArchRuntimeCalls(check_kind)) {}
- DataType::Type GetType() const OVERRIDE { return DataType::Type::kBool; }
-
bool NeedsEnvironment() const OVERRIDE {
return CanCallRuntime(GetTypeCheckKind());
}
@@ -7074,7 +7125,7 @@ class HBoundType FINAL : public HExpression<1> {
private:
// Represents the top constraint that can_be_null_ cannot exceed (i.e. if this
// is false then CanBeNull() cannot be true).
- static constexpr size_t kFlagUpperCanBeNull = kNumberOfExpressionPackedBits;
+ static constexpr size_t kFlagUpperCanBeNull = kNumberOfGenericPackedBits;
static constexpr size_t kFlagCanBeNull = kFlagUpperCanBeNull + 1;
static constexpr size_t kNumberOfBoundTypePackedBits = kFlagCanBeNull + 1;
static_assert(kNumberOfBoundTypePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
@@ -7099,6 +7150,7 @@ class HCheckCast FINAL : public HTypeCheckInstruction {
HIntConstant* bitstring_path_to_root,
HIntConstant* bitstring_mask)
: HTypeCheckInstruction(kCheckCast,
+ DataType::Type::kVoid,
object,
target_class_or_null,
check_kind,
@@ -7148,13 +7200,12 @@ enum MemBarrierKind {
};
std::ostream& operator<<(std::ostream& os, const MemBarrierKind& kind);
-class HMemoryBarrier FINAL : public HTemplateInstruction<0> {
+class HMemoryBarrier FINAL : public HExpression<0> {
public:
explicit HMemoryBarrier(MemBarrierKind barrier_kind, uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(
- kMemoryBarrier,
- SideEffects::AllWritesAndReads(), // Assume write/read on all fields/arrays.
- dex_pc) {
+ : HExpression(kMemoryBarrier,
+ SideEffects::AllWritesAndReads(), // Assume write/read on all fields/arrays.
+ dex_pc) {
SetPackedField<BarrierKindField>(barrier_kind);
}
@@ -7331,7 +7382,7 @@ class HConstructorFence FINAL : public HVariableInputSizeInstruction {
DEFAULT_COPY_CONSTRUCTOR(ConstructorFence);
};
-class HMonitorOperation FINAL : public HTemplateInstruction<1> {
+class HMonitorOperation FINAL : public HExpression<1> {
public:
enum class OperationKind {
kEnter,
@@ -7340,10 +7391,9 @@ class HMonitorOperation FINAL : public HTemplateInstruction<1> {
};
HMonitorOperation(HInstruction* object, OperationKind kind, uint32_t dex_pc)
- : HTemplateInstruction(
- kMonitorOperation,
- SideEffects::AllExceptGCDependency(), // Assume write/read on all fields/arrays.
- dex_pc) {
+ : HExpression(kMonitorOperation,
+ SideEffects::AllExceptGCDependency(), // Assume write/read on all fields/arrays.
+ dex_pc) {
SetPackedField<OperationKindField>(kind);
SetRawInputAt(0, object);
}
@@ -7493,10 +7543,10 @@ std::ostream& operator<<(std::ostream& os, const MoveOperands& rhs);
static constexpr size_t kDefaultNumberOfMoves = 4;
-class HParallelMove FINAL : public HTemplateInstruction<0> {
+class HParallelMove FINAL : public HExpression<0> {
public:
explicit HParallelMove(ArenaAllocator* allocator, uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(kParallelMove, SideEffects::None(), dex_pc),
+ : HExpression(kParallelMove, SideEffects::None(), dex_pc),
moves_(allocator->Adapter(kArenaAllocMoveOperands)) {
moves_.reserve(kDefaultNumberOfMoves);
}
@@ -7788,8 +7838,30 @@ inline bool IsZeroBitPattern(HInstruction* instruction) {
return instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern();
}
+// Implement HInstruction::Is##type() for concrete instructions.
+#define INSTRUCTION_TYPE_CHECK(type, super) \
+ inline bool HInstruction::Is##type() const { return GetKind() == k##type; }
+ FOR_EACH_CONCRETE_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
+#undef INSTRUCTION_TYPE_CHECK
+
+// Implement HInstruction::Is##type() for abstract instructions.
+#define INSTRUCTION_TYPE_CHECK_RESULT(type, super) \
+ std::is_base_of<BaseType, H##type>::value,
#define INSTRUCTION_TYPE_CHECK(type, super) \
- inline bool HInstruction::Is##type() const { return GetKind() == k##type; } \
+ inline bool HInstruction::Is##type() const { \
+ DCHECK_LT(GetKind(), kLastInstructionKind); \
+ using BaseType = H##type; \
+ static constexpr bool results[] = { \
+ FOR_EACH_CONCRETE_INSTRUCTION(INSTRUCTION_TYPE_CHECK_RESULT) \
+ }; \
+ return results[static_cast<size_t>(GetKind())]; \
+ }
+
+ FOR_EACH_ABSTRACT_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
+#undef INSTRUCTION_TYPE_CHECK
+#undef INSTRUCTION_TYPE_CHECK_RESULT
+
+#define INSTRUCTION_TYPE_CAST(type, super) \
inline const H##type* HInstruction::As##type() const { \
return Is##type() ? down_cast<const H##type*>(this) : nullptr; \
} \
@@ -7797,8 +7869,9 @@ inline bool IsZeroBitPattern(HInstruction* instruction) {
return Is##type() ? static_cast<H##type*>(this) : nullptr; \
}
- FOR_EACH_CONCRETE_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
-#undef INSTRUCTION_TYPE_CHECK
+ FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CAST)
+#undef INSTRUCTION_TYPE_CAST
+
// Create space in `blocks` for adding `number_of_new_blocks` entries
// starting at location `at`. Blocks after `at` are moved accordingly.
diff --git a/compiler/optimizing/nodes_mips.h b/compiler/optimizing/nodes_mips.h
index d0e0fef946..05b27a7810 100644
--- a/compiler/optimizing/nodes_mips.h
+++ b/compiler/optimizing/nodes_mips.h
@@ -39,14 +39,14 @@ class HMipsComputeBaseMethodAddress : public HExpression<0> {
};
// Mips version of HPackedSwitch that holds a pointer to the base method address.
-class HMipsPackedSwitch FINAL : public HTemplateInstruction<2> {
+class HMipsPackedSwitch FINAL : public HExpression<2> {
public:
HMipsPackedSwitch(int32_t start_value,
int32_t num_entries,
HInstruction* input,
HMipsComputeBaseMethodAddress* method_base,
uint32_t dex_pc)
- : HTemplateInstruction(kMipsPackedSwitch, SideEffects::None(), dex_pc),
+ : HExpression(kMipsPackedSwitch, SideEffects::None(), dex_pc),
start_value_(start_value),
num_entries_(num_entries) {
SetRawInputAt(0, input);
diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h
index 1a484e1944..c5e9a8d036 100644
--- a/compiler/optimizing/nodes_vector.h
+++ b/compiler/optimizing/nodes_vector.h
@@ -79,13 +79,14 @@ class HVecOperation : public HVariableInputSizeInstruction {
size_t vector_length,
uint32_t dex_pc)
: HVariableInputSizeInstruction(kind,
+ kSIMDType,
side_effects,
dex_pc,
allocator,
number_of_inputs,
kArenaAllocVectorNode),
vector_length_(vector_length) {
- SetPackedField<TypeField>(packed_type);
+ SetPackedField<PackedTypeField>(packed_type);
DCHECK_LT(1u, vector_length);
}
@@ -99,14 +100,9 @@ class HVecOperation : public HVariableInputSizeInstruction {
return vector_length_ * DataType::Size(GetPackedType());
}
- // Returns the type of the vector operation.
- DataType::Type GetType() const OVERRIDE {
- return kSIMDType;
- }
-
// Returns the true component type packed in a vector.
DataType::Type GetPackedType() const {
- return GetPackedField<TypeField>();
+ return GetPackedField<PackedTypeField>();
}
// Assumes vector nodes cannot be moved by default. Each concrete implementation
@@ -185,12 +181,12 @@ class HVecOperation : public HVariableInputSizeInstruction {
protected:
// Additional packed bits.
- static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits;
- static constexpr size_t kFieldTypeSize =
+ static constexpr size_t kFieldPackedType = HInstruction::kNumberOfGenericPackedBits;
+ static constexpr size_t kFieldPackedTypeSize =
MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
- static constexpr size_t kNumberOfVectorOpPackedBits = kFieldType + kFieldTypeSize;
+ static constexpr size_t kNumberOfVectorOpPackedBits = kFieldPackedType + kFieldPackedTypeSize;
static_assert(kNumberOfVectorOpPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
- using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>;
+ using PackedTypeField = BitField<DataType::Type, kFieldPackedType, kFieldPackedTypeSize>;
DEFAULT_COPY_CONSTRUCTOR(VecOperation);
@@ -358,11 +354,9 @@ class HVecExtractScalar FINAL : public HVecUnaryOperation {
DCHECK(HasConsistentPackedTypes(input, packed_type));
DCHECK_LT(index, vector_length);
DCHECK_EQ(index, 0u);
- }
-
- // Yields a single component in the vector.
- DataType::Type GetType() const OVERRIDE {
- return GetPackedType();
+ // Yields a single component in the vector.
+ // Overrides the kSIMDType set by the VecOperation constructor.
+ SetPackedField<TypeField>(packed_type);
}
// An extract needs to stay in place, since SIMD registers are not
diff --git a/compiler/optimizing/nodes_x86.h b/compiler/optimizing/nodes_x86.h
index 4c32be7d15..d1e7f68edb 100644
--- a/compiler/optimizing/nodes_x86.h
+++ b/compiler/optimizing/nodes_x86.h
@@ -89,14 +89,14 @@ class HX86FPNeg FINAL : public HExpression<2> {
};
// X86 version of HPackedSwitch that holds a pointer to the base method address.
-class HX86PackedSwitch FINAL : public HTemplateInstruction<2> {
+class HX86PackedSwitch FINAL : public HExpression<2> {
public:
HX86PackedSwitch(int32_t start_value,
int32_t num_entries,
HInstruction* input,
HX86ComputeBaseMethodAddress* method_base,
uint32_t dex_pc)
- : HTemplateInstruction(kX86PackedSwitch, SideEffects::None(), dex_pc),
+ : HExpression(kX86PackedSwitch, SideEffects::None(), dex_pc),
start_value_(start_value),
num_entries_(num_entries) {
SetRawInputAt(0, input);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 6e2c99444c..c4977decd9 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -109,7 +109,7 @@ class PassObserver : public ValueObject {
: graph_(graph),
last_seen_graph_size_(0),
cached_method_name_(),
- timing_logger_enabled_(compiler_driver->GetCompilerOptions().GetDumpTimings()),
+ timing_logger_enabled_(compiler_driver->GetCompilerOptions().GetDumpPassTimings()),
timing_logger_(timing_logger_enabled_ ? GetMethodName() : "", true, true),
disasm_info_(graph->GetAllocator()),
visualizer_oss_(),
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index 59733397bf..831bccc90a 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -17,7 +17,7 @@
#include "prepare_for_register_allocation.h"
#include "dex/dex_file_types.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "optimizing_compiler_stats.h"
#include "well_known_classes.h"
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index c47c69af67..ecfa790b91 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -59,6 +59,18 @@ ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetClassCla
return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_);
}
+ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetMethodHandleClassHandle() {
+ return GetRootHandle(handles_,
+ ClassLinker::kJavaLangInvokeMethodHandleImpl,
+ &method_handle_class_handle_);
+}
+
+ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetMethodTypeClassHandle() {
+ return GetRootHandle(handles_,
+ ClassLinker::kJavaLangInvokeMethodType,
+ &method_type_class_handle_);
+}
+
ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() {
return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_);
}
@@ -89,6 +101,8 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor {
void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
void VisitInstanceOf(HInstanceOf* load_class) OVERRIDE;
void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
+ void VisitLoadMethodHandle(HLoadMethodHandle* instr) OVERRIDE;
+ void VisitLoadMethodType(HLoadMethodType* instr) OVERRIDE;
void VisitLoadString(HLoadString* instr) OVERRIDE;
void VisitLoadException(HLoadException* instr) OVERRIDE;
void VisitNewArray(HNewArray* instr) OVERRIDE;
@@ -668,6 +682,17 @@ void ReferenceTypePropagation::RTPVisitor::VisitClinitCheck(HClinitCheck* instr)
instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
}
+void ReferenceTypePropagation::RTPVisitor::VisitLoadMethodHandle(HLoadMethodHandle* instr) {
+ instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(
+ handle_cache_->GetMethodHandleClassHandle(),
+ /* is_exact */ true));
+}
+
+void ReferenceTypePropagation::RTPVisitor::VisitLoadMethodType(HLoadMethodType* instr) {
+ instr->SetReferenceTypeInfo(
+ ReferenceTypeInfo::Create(handle_cache_->GetMethodTypeClassHandle(), /* is_exact */ true));
+}
+
void ReferenceTypePropagation::RTPVisitor::VisitLoadString(HLoadString* instr) {
instr->SetReferenceTypeInfo(
ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index 400852f4dc..d36d592708 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -75,6 +75,8 @@ class ReferenceTypePropagation : public HOptimization {
ReferenceTypeInfo::TypeHandle GetObjectClassHandle();
ReferenceTypeInfo::TypeHandle GetClassClassHandle();
+ ReferenceTypeInfo::TypeHandle GetMethodHandleClassHandle();
+ ReferenceTypeInfo::TypeHandle GetMethodTypeClassHandle();
ReferenceTypeInfo::TypeHandle GetStringClassHandle();
ReferenceTypeInfo::TypeHandle GetThrowableClassHandle();
@@ -83,6 +85,8 @@ class ReferenceTypePropagation : public HOptimization {
ReferenceTypeInfo::TypeHandle object_class_handle_;
ReferenceTypeInfo::TypeHandle class_class_handle_;
+ ReferenceTypeInfo::TypeHandle method_handle_class_handle_;
+ ReferenceTypeInfo::TypeHandle method_type_class_handle_;
ReferenceTypeInfo::TypeHandle string_class_handle_;
ReferenceTypeInfo::TypeHandle throwable_class_handle_;
};
diff --git a/compiler/optimizing/scheduler_arm64.h b/compiler/optimizing/scheduler_arm64.h
index f71cb5b784..4f394d5e16 100644
--- a/compiler/optimizing/scheduler_arm64.h
+++ b/compiler/optimizing/scheduler_arm64.h
@@ -68,12 +68,10 @@ class SchedulingLatencyVisitorARM64 : public SchedulingLatencyVisitor {
M(ArrayGet , unused) \
M(ArrayLength , unused) \
M(ArraySet , unused) \
- M(BinaryOperation , unused) \
M(BoundsCheck , unused) \
M(Div , unused) \
M(InstanceFieldGet , unused) \
M(InstanceOf , unused) \
- M(Invoke , unused) \
M(LoadString , unused) \
M(Mul , unused) \
M(NewArray , unused) \
@@ -108,6 +106,10 @@ class SchedulingLatencyVisitorARM64 : public SchedulingLatencyVisitor {
M(VecLoad , unused) \
M(VecStore , unused)
+#define FOR_EACH_SCHEDULED_ABSTRACT_INSTRUCTION(M) \
+ M(BinaryOperation , unused) \
+ M(Invoke , unused)
+
#define FOR_EACH_SCHEDULED_SHARED_INSTRUCTION(M) \
M(BitwiseNegatedRight, unused) \
M(MultiplyAccumulate, unused) \
@@ -119,6 +121,7 @@ class SchedulingLatencyVisitorARM64 : public SchedulingLatencyVisitor {
void Visit##type(H##type* instruction) OVERRIDE;
FOR_EACH_SCHEDULED_COMMON_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+ FOR_EACH_SCHEDULED_ABSTRACT_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_SCHEDULED_SHARED_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION)
diff --git a/compiler/trampolines/trampoline_compiler.cc b/compiler/trampolines/trampoline_compiler.cc
index 57360e74a3..26aa434c0d 100644
--- a/compiler/trampolines/trampoline_compiler.cc
+++ b/compiler/trampolines/trampoline_compiler.cc
@@ -18,7 +18,7 @@
#include "base/arena_allocator.h"
#include "base/malloc_arena_pool.h"
-#include "jni_env_ext.h"
+#include "jni/jni_env_ext.h"
#ifdef ART_ENABLE_CODEGEN_arm
#include "utils/arm/assembler_arm_vixl.h"
diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
index 065c3de23c..2c428fac7e 100644
--- a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
+++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
@@ -37,6 +37,29 @@ namespace arm {
#define ___ asm_.GetVIXLAssembler()->
#endif
+vixl::aarch32::Register AsVIXLRegister(ArmManagedRegister reg) {
+ CHECK(reg.IsCoreRegister());
+ return vixl::aarch32::Register(reg.RegId());
+}
+
+static inline vixl::aarch32::SRegister AsVIXLSRegister(ArmManagedRegister reg) {
+ CHECK(reg.IsSRegister());
+ return vixl::aarch32::SRegister(reg.RegId() - kNumberOfCoreRegIds);
+}
+
+static inline vixl::aarch32::DRegister AsVIXLDRegister(ArmManagedRegister reg) {
+ CHECK(reg.IsDRegister());
+ return vixl::aarch32::DRegister(reg.RegId() - kNumberOfCoreRegIds - kNumberOfSRegIds);
+}
+
+static inline vixl::aarch32::Register AsVIXLRegisterPairLow(ArmManagedRegister reg) {
+ return vixl::aarch32::Register(reg.AsRegisterPairLow());
+}
+
+static inline vixl::aarch32::Register AsVIXLRegisterPairHigh(ArmManagedRegister reg) {
+ return vixl::aarch32::Register(reg.AsRegisterPairHigh());
+}
+
void ArmVIXLJNIMacroAssembler::FinalizeCode() {
for (const std::unique_ptr<
ArmVIXLJNIMacroAssembler::ArmException>& exception : exception_blocks_) {
@@ -60,7 +83,7 @@ void ArmVIXLJNIMacroAssembler::BuildFrame(size_t frame_size,
ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) {
CHECK_ALIGNED(frame_size, kStackAlignment);
- CHECK(r0.Is(method_reg.AsArm().AsVIXLRegister()));
+ CHECK(r0.Is(AsVIXLRegister(method_reg.AsArm())));
// Push callee saves and link register.
RegList core_spill_mask = 1 << LR;
@@ -104,13 +127,13 @@ void ArmVIXLJNIMacroAssembler::BuildFrame(size_t frame_size,
ManagedRegisterSpill spill = entry_spills.at(i);
offset += spill.getSize();
} else if (reg.IsCoreRegister()) {
- asm_.StoreToOffset(kStoreWord, reg.AsVIXLRegister(), sp, offset);
+ asm_.StoreToOffset(kStoreWord, AsVIXLRegister(reg), sp, offset);
offset += 4;
} else if (reg.IsSRegister()) {
- asm_.StoreSToOffset(reg.AsVIXLSRegister(), sp, offset);
+ asm_.StoreSToOffset(AsVIXLSRegister(reg), sp, offset);
offset += 4;
} else if (reg.IsDRegister()) {
- asm_.StoreDToOffset(reg.AsVIXLDRegister(), sp, offset);
+ asm_.StoreDToOffset(AsVIXLDRegister(reg), sp, offset);
offset += 8;
}
}
@@ -208,76 +231,71 @@ void ArmVIXLJNIMacroAssembler::Store(FrameOffset dest, ManagedRegister m_src, si
} else if (src.IsCoreRegister()) {
CHECK_EQ(4u, size);
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(src.AsVIXLRegister());
- asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
+ temps.Exclude(AsVIXLRegister(src));
+ asm_.StoreToOffset(kStoreWord, AsVIXLRegister(src), sp, dest.Int32Value());
} else if (src.IsRegisterPair()) {
CHECK_EQ(8u, size);
- asm_.StoreToOffset(kStoreWord, src.AsVIXLRegisterPairLow(), sp, dest.Int32Value());
- asm_.StoreToOffset(kStoreWord, src.AsVIXLRegisterPairHigh(), sp, dest.Int32Value() + 4);
+ asm_.StoreToOffset(kStoreWord, AsVIXLRegisterPairLow(src), sp, dest.Int32Value());
+ asm_.StoreToOffset(kStoreWord, AsVIXLRegisterPairHigh(src), sp, dest.Int32Value() + 4);
} else if (src.IsSRegister()) {
CHECK_EQ(4u, size);
- asm_.StoreSToOffset(src.AsVIXLSRegister(), sp, dest.Int32Value());
+ asm_.StoreSToOffset(AsVIXLSRegister(src), sp, dest.Int32Value());
} else {
CHECK_EQ(8u, size);
CHECK(src.IsDRegister()) << src;
- asm_.StoreDToOffset(src.AsVIXLDRegister(), sp, dest.Int32Value());
+ asm_.StoreDToOffset(AsVIXLDRegister(src), sp, dest.Int32Value());
}
}
void ArmVIXLJNIMacroAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
- ArmManagedRegister src = msrc.AsArm();
- CHECK(src.IsCoreRegister()) << src;
+ vixl::aarch32::Register src = AsVIXLRegister(msrc.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(src.AsVIXLRegister());
- asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
+ temps.Exclude(src);
+ asm_.StoreToOffset(kStoreWord, src, sp, dest.Int32Value());
}
void ArmVIXLJNIMacroAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
- ArmManagedRegister src = msrc.AsArm();
- CHECK(src.IsCoreRegister()) << src;
+ vixl::aarch32::Register src = AsVIXLRegister(msrc.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(src.AsVIXLRegister());
- asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
+ temps.Exclude(src);
+ asm_.StoreToOffset(kStoreWord, src, sp, dest.Int32Value());
}
void ArmVIXLJNIMacroAssembler::StoreSpanning(FrameOffset dest,
ManagedRegister msrc,
FrameOffset in_off,
ManagedRegister mscratch) {
- ArmManagedRegister src = msrc.AsArm();
- ArmManagedRegister scratch = mscratch.AsArm();
- asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
+ vixl::aarch32::Register src = AsVIXLRegister(msrc.AsArm());
+ vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm());
+ asm_.StoreToOffset(kStoreWord, src, sp, dest.Int32Value());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(scratch.AsVIXLRegister());
- asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, in_off.Int32Value());
- asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, dest.Int32Value() + 4);
+ temps.Exclude(scratch);
+ asm_.LoadFromOffset(kLoadWord, scratch, sp, in_off.Int32Value());
+ asm_.StoreToOffset(kStoreWord, scratch, sp, dest.Int32Value() + 4);
}
void ArmVIXLJNIMacroAssembler::CopyRef(FrameOffset dest,
FrameOffset src,
ManagedRegister mscratch) {
- ArmManagedRegister scratch = mscratch.AsArm();
+ vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(scratch.AsVIXLRegister());
- asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, src.Int32Value());
- asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, dest.Int32Value());
+ temps.Exclude(scratch);
+ asm_.LoadFromOffset(kLoadWord, scratch, sp, src.Int32Value());
+ asm_.StoreToOffset(kStoreWord, scratch, sp, dest.Int32Value());
}
-void ArmVIXLJNIMacroAssembler::LoadRef(ManagedRegister dest,
- ManagedRegister base,
+void ArmVIXLJNIMacroAssembler::LoadRef(ManagedRegister mdest,
+ ManagedRegister mbase,
MemberOffset offs,
bool unpoison_reference) {
- ArmManagedRegister dst = dest.AsArm();
- CHECK(dst.IsCoreRegister() && dst.IsCoreRegister()) << dst;
+ vixl::aarch32::Register dest = AsVIXLRegister(mdest.AsArm());
+ vixl::aarch32::Register base = AsVIXLRegister(mbase.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(dst.AsVIXLRegister(), base.AsArm().AsVIXLRegister());
- asm_.LoadFromOffset(kLoadWord,
- dst.AsVIXLRegister(),
- base.AsArm().AsVIXLRegister(),
- offs.Int32Value());
+ temps.Exclude(dest, base);
+ asm_.LoadFromOffset(kLoadWord, dest, base, offs.Int32Value());
if (unpoison_reference) {
- asm_.MaybeUnpoisonHeapReference(dst.AsVIXLRegister());
+ asm_.MaybeUnpoisonHeapReference(dest);
}
}
@@ -294,13 +312,12 @@ void ArmVIXLJNIMacroAssembler::LoadRawPtr(ManagedRegister dest ATTRIBUTE_UNUSED,
void ArmVIXLJNIMacroAssembler::StoreImmediateToFrame(FrameOffset dest,
uint32_t imm,
- ManagedRegister scratch) {
- ArmManagedRegister mscratch = scratch.AsArm();
- CHECK(mscratch.IsCoreRegister()) << mscratch;
+ ManagedRegister mscratch) {
+ vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(mscratch.AsVIXLRegister());
- asm_.LoadImmediate(mscratch.AsVIXLRegister(), imm);
- asm_.StoreToOffset(kStoreWord, mscratch.AsVIXLRegister(), sp, dest.Int32Value());
+ temps.Exclude(scratch);
+ asm_.LoadImmediate(scratch, imm);
+ asm_.StoreToOffset(kStoreWord, scratch, sp, dest.Int32Value());
}
void ArmVIXLJNIMacroAssembler::Load(ManagedRegister m_dst, FrameOffset src, size_t size) {
@@ -313,23 +330,21 @@ void ArmVIXLJNIMacroAssembler::LoadFromThread(ManagedRegister m_dst,
return Load(m_dst.AsArm(), tr, src.Int32Value(), size);
}
-void ArmVIXLJNIMacroAssembler::LoadRawPtrFromThread(ManagedRegister m_dst, ThreadOffset32 offs) {
- ArmManagedRegister dst = m_dst.AsArm();
- CHECK(dst.IsCoreRegister()) << dst;
+void ArmVIXLJNIMacroAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) {
+ vixl::aarch32::Register dest = AsVIXLRegister(mdest.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(dst.AsVIXLRegister());
- asm_.LoadFromOffset(kLoadWord, dst.AsVIXLRegister(), tr, offs.Int32Value());
+ temps.Exclude(dest);
+ asm_.LoadFromOffset(kLoadWord, dest, tr, offs.Int32Value());
}
void ArmVIXLJNIMacroAssembler::CopyRawPtrFromThread(FrameOffset fr_offs,
ThreadOffset32 thr_offs,
ManagedRegister mscratch) {
- ArmManagedRegister scratch = mscratch.AsArm();
- CHECK(scratch.IsCoreRegister()) << scratch;
+ vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(scratch.AsVIXLRegister());
- asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), tr, thr_offs.Int32Value());
- asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, fr_offs.Int32Value());
+ temps.Exclude(scratch);
+ asm_.LoadFromOffset(kLoadWord, scratch, tr, thr_offs.Int32Value());
+ asm_.StoreToOffset(kStoreWord, scratch, sp, fr_offs.Int32Value());
}
void ArmVIXLJNIMacroAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs ATTRIBUTE_UNUSED,
@@ -341,12 +356,11 @@ void ArmVIXLJNIMacroAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs ATTRIB
void ArmVIXLJNIMacroAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs,
FrameOffset fr_offs,
ManagedRegister mscratch) {
- ArmManagedRegister scratch = mscratch.AsArm();
- CHECK(scratch.IsCoreRegister()) << scratch;
+ vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(scratch.AsVIXLRegister());
- asm_.AddConstant(scratch.AsVIXLRegister(), sp, fr_offs.Int32Value());
- asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), tr, thr_offs.Int32Value());
+ temps.Exclude(scratch);
+ asm_.AddConstant(scratch, sp, fr_offs.Int32Value());
+ asm_.StoreToOffset(kStoreWord, scratch, tr, thr_offs.Int32Value());
}
void ArmVIXLJNIMacroAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) {
@@ -363,43 +377,43 @@ void ArmVIXLJNIMacroAssembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
UNIMPLEMENTED(FATAL) << "no zero extension necessary for arm";
}
-void ArmVIXLJNIMacroAssembler::Move(ManagedRegister m_dst,
- ManagedRegister m_src,
+void ArmVIXLJNIMacroAssembler::Move(ManagedRegister mdst,
+ ManagedRegister msrc,
size_t size ATTRIBUTE_UNUSED) {
- ArmManagedRegister dst = m_dst.AsArm();
- ArmManagedRegister src = m_src.AsArm();
+ ArmManagedRegister dst = mdst.AsArm();
+ ArmManagedRegister src = msrc.AsArm();
if (!dst.Equals(src)) {
if (dst.IsCoreRegister()) {
CHECK(src.IsCoreRegister()) << src;
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(dst.AsVIXLRegister());
- ___ Mov(dst.AsVIXLRegister(), src.AsVIXLRegister());
+ temps.Exclude(AsVIXLRegister(dst));
+ ___ Mov(AsVIXLRegister(dst), AsVIXLRegister(src));
} else if (dst.IsDRegister()) {
if (src.IsDRegister()) {
- ___ Vmov(F64, dst.AsVIXLDRegister(), src.AsVIXLDRegister());
+ ___ Vmov(F64, AsVIXLDRegister(dst), AsVIXLDRegister(src));
} else {
// VMOV Dn, Rlo, Rhi (Dn = {Rlo, Rhi})
CHECK(src.IsRegisterPair()) << src;
- ___ Vmov(dst.AsVIXLDRegister(), src.AsVIXLRegisterPairLow(), src.AsVIXLRegisterPairHigh());
+ ___ Vmov(AsVIXLDRegister(dst), AsVIXLRegisterPairLow(src), AsVIXLRegisterPairHigh(src));
}
} else if (dst.IsSRegister()) {
if (src.IsSRegister()) {
- ___ Vmov(F32, dst.AsVIXLSRegister(), src.AsVIXLSRegister());
+ ___ Vmov(F32, AsVIXLSRegister(dst), AsVIXLSRegister(src));
} else {
// VMOV Sn, Rn (Sn = Rn)
CHECK(src.IsCoreRegister()) << src;
- ___ Vmov(dst.AsVIXLSRegister(), src.AsVIXLRegister());
+ ___ Vmov(AsVIXLSRegister(dst), AsVIXLRegister(src));
}
} else {
CHECK(dst.IsRegisterPair()) << dst;
CHECK(src.IsRegisterPair()) << src;
// Ensure that the first move doesn't clobber the input of the second.
if (src.AsRegisterPairHigh() != dst.AsRegisterPairLow()) {
- ___ Mov(dst.AsVIXLRegisterPairLow(), src.AsVIXLRegisterPairLow());
- ___ Mov(dst.AsVIXLRegisterPairHigh(), src.AsVIXLRegisterPairHigh());
+ ___ Mov(AsVIXLRegisterPairLow(dst), AsVIXLRegisterPairLow(src));
+ ___ Mov(AsVIXLRegisterPairHigh(dst), AsVIXLRegisterPairHigh(src));
} else {
- ___ Mov(dst.AsVIXLRegisterPairHigh(), src.AsVIXLRegisterPairHigh());
- ___ Mov(dst.AsVIXLRegisterPairLow(), src.AsVIXLRegisterPairLow());
+ ___ Mov(AsVIXLRegisterPairHigh(dst), AsVIXLRegisterPairHigh(src));
+ ___ Mov(AsVIXLRegisterPairLow(dst), AsVIXLRegisterPairLow(src));
}
}
}
@@ -407,21 +421,20 @@ void ArmVIXLJNIMacroAssembler::Move(ManagedRegister m_dst,
void ArmVIXLJNIMacroAssembler::Copy(FrameOffset dest,
FrameOffset src,
- ManagedRegister scratch,
+ ManagedRegister mscratch,
size_t size) {
- ArmManagedRegister temp = scratch.AsArm();
- CHECK(temp.IsCoreRegister()) << temp;
+ vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm());
CHECK(size == 4 || size == 8) << size;
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(temp.AsVIXLRegister());
+ temps.Exclude(scratch);
if (size == 4) {
- asm_.LoadFromOffset(kLoadWord, temp.AsVIXLRegister(), sp, src.Int32Value());
- asm_.StoreToOffset(kStoreWord, temp.AsVIXLRegister(), sp, dest.Int32Value());
+ asm_.LoadFromOffset(kLoadWord, scratch, sp, src.Int32Value());
+ asm_.StoreToOffset(kStoreWord, scratch, sp, dest.Int32Value());
} else if (size == 8) {
- asm_.LoadFromOffset(kLoadWord, temp.AsVIXLRegister(), sp, src.Int32Value());
- asm_.StoreToOffset(kStoreWord, temp.AsVIXLRegister(), sp, dest.Int32Value());
- asm_.LoadFromOffset(kLoadWord, temp.AsVIXLRegister(), sp, src.Int32Value() + 4);
- asm_.StoreToOffset(kStoreWord, temp.AsVIXLRegister(), sp, dest.Int32Value() + 4);
+ asm_.LoadFromOffset(kLoadWord, scratch, sp, src.Int32Value());
+ asm_.StoreToOffset(kStoreWord, scratch, sp, dest.Int32Value());
+ asm_.LoadFromOffset(kLoadWord, scratch, sp, src.Int32Value() + 4);
+ asm_.StoreToOffset(kStoreWord, scratch, sp, dest.Int32Value() + 4);
}
}
@@ -471,48 +484,44 @@ void ArmVIXLJNIMacroAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
FrameOffset handle_scope_offset,
ManagedRegister min_reg,
bool null_allowed) {
- ArmManagedRegister out_reg = mout_reg.AsArm();
- ArmManagedRegister in_reg = min_reg.AsArm();
- CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
- CHECK(out_reg.IsCoreRegister()) << out_reg;
+ vixl::aarch32::Register out_reg = AsVIXLRegister(mout_reg.AsArm());
+ vixl::aarch32::Register in_reg =
+ min_reg.AsArm().IsNoRegister() ? vixl::aarch32::Register() : AsVIXLRegister(min_reg.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(out_reg.AsVIXLRegister());
+ temps.Exclude(out_reg);
if (null_allowed) {
// Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
// the address in the handle scope holding the reference.
// e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
- if (in_reg.IsNoRegister()) {
- asm_.LoadFromOffset(kLoadWord,
- out_reg.AsVIXLRegister(),
- sp,
- handle_scope_offset.Int32Value());
+ if (!in_reg.IsValid()) {
+ asm_.LoadFromOffset(kLoadWord, out_reg, sp, handle_scope_offset.Int32Value());
in_reg = out_reg;
}
- temps.Exclude(in_reg.AsVIXLRegister());
- ___ Cmp(in_reg.AsVIXLRegister(), 0);
+ temps.Exclude(in_reg);
+ ___ Cmp(in_reg, 0);
if (asm_.ShifterOperandCanHold(ADD, handle_scope_offset.Int32Value())) {
- if (!out_reg.Equals(in_reg)) {
+ if (!out_reg.Is(in_reg)) {
ExactAssemblyScope guard(asm_.GetVIXLAssembler(),
3 * vixl32::kMaxInstructionSizeInBytes,
CodeBufferCheckScope::kMaximumSize);
___ it(eq, 0xc);
- ___ mov(eq, out_reg.AsVIXLRegister(), 0);
- asm_.AddConstantInIt(out_reg.AsVIXLRegister(), sp, handle_scope_offset.Int32Value(), ne);
+ ___ mov(eq, out_reg, 0);
+ asm_.AddConstantInIt(out_reg, sp, handle_scope_offset.Int32Value(), ne);
} else {
ExactAssemblyScope guard(asm_.GetVIXLAssembler(),
2 * vixl32::kMaxInstructionSizeInBytes,
CodeBufferCheckScope::kMaximumSize);
___ it(ne, 0x8);
- asm_.AddConstantInIt(out_reg.AsVIXLRegister(), sp, handle_scope_offset.Int32Value(), ne);
+ asm_.AddConstantInIt(out_reg, sp, handle_scope_offset.Int32Value(), ne);
}
} else {
// TODO: Implement this (old arm assembler would have crashed here).
UNIMPLEMENTED(FATAL);
}
} else {
- asm_.AddConstant(out_reg.AsVIXLRegister(), sp, handle_scope_offset.Int32Value());
+ asm_.AddConstant(out_reg, sp, handle_scope_offset.Int32Value());
}
}
@@ -520,31 +529,30 @@ void ArmVIXLJNIMacroAssembler::CreateHandleScopeEntry(FrameOffset out_off,
FrameOffset handle_scope_offset,
ManagedRegister mscratch,
bool null_allowed) {
- ArmManagedRegister scratch = mscratch.AsArm();
- CHECK(scratch.IsCoreRegister()) << scratch;
+ vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(scratch.AsVIXLRegister());
+ temps.Exclude(scratch);
if (null_allowed) {
- asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, handle_scope_offset.Int32Value());
+ asm_.LoadFromOffset(kLoadWord, scratch, sp, handle_scope_offset.Int32Value());
// Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
// the address in the handle scope holding the reference.
// e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
- ___ Cmp(scratch.AsVIXLRegister(), 0);
+ ___ Cmp(scratch, 0);
if (asm_.ShifterOperandCanHold(ADD, handle_scope_offset.Int32Value())) {
ExactAssemblyScope guard(asm_.GetVIXLAssembler(),
2 * vixl32::kMaxInstructionSizeInBytes,
CodeBufferCheckScope::kMaximumSize);
___ it(ne, 0x8);
- asm_.AddConstantInIt(scratch.AsVIXLRegister(), sp, handle_scope_offset.Int32Value(), ne);
+ asm_.AddConstantInIt(scratch, sp, handle_scope_offset.Int32Value(), ne);
} else {
// TODO: Implement this (old arm assembler would have crashed here).
UNIMPLEMENTED(FATAL);
}
} else {
- asm_.AddConstant(scratch.AsVIXLRegister(), sp, handle_scope_offset.Int32Value());
+ asm_.AddConstant(scratch, sp, handle_scope_offset.Int32Value());
}
- asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, out_off.Int32Value());
+ asm_.StoreToOffset(kStoreWord, scratch, sp, out_off.Int32Value());
}
void ArmVIXLJNIMacroAssembler::LoadReferenceFromHandleScope(
@@ -566,32 +574,23 @@ void ArmVIXLJNIMacroAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
void ArmVIXLJNIMacroAssembler::Call(ManagedRegister mbase,
Offset offset,
ManagedRegister mscratch) {
- ArmManagedRegister base = mbase.AsArm();
- ArmManagedRegister scratch = mscratch.AsArm();
- CHECK(base.IsCoreRegister()) << base;
- CHECK(scratch.IsCoreRegister()) << scratch;
+ vixl::aarch32::Register base = AsVIXLRegister(mbase.AsArm());
+ vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(scratch.AsVIXLRegister());
- asm_.LoadFromOffset(kLoadWord,
- scratch.AsVIXLRegister(),
- base.AsVIXLRegister(),
- offset.Int32Value());
- ___ Blx(scratch.AsVIXLRegister());
+ temps.Exclude(scratch);
+ asm_.LoadFromOffset(kLoadWord, scratch, base, offset.Int32Value());
+ ___ Blx(scratch);
// TODO: place reference map on call.
}
void ArmVIXLJNIMacroAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
- ArmManagedRegister scratch = mscratch.AsArm();
- CHECK(scratch.IsCoreRegister()) << scratch;
+ vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(scratch.AsVIXLRegister());
+ temps.Exclude(scratch);
// Call *(*(SP + base) + offset)
- asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, base.Int32Value());
- asm_.LoadFromOffset(kLoadWord,
- scratch.AsVIXLRegister(),
- scratch.AsVIXLRegister(),
- offset.Int32Value());
- ___ Blx(scratch.AsVIXLRegister());
+ asm_.LoadFromOffset(kLoadWord, scratch, sp, base.Int32Value());
+ asm_.LoadFromOffset(kLoadWord, scratch, scratch, offset.Int32Value());
+ ___ Blx(scratch);
// TODO: place reference map on call
}
@@ -602,8 +601,8 @@ void ArmVIXLJNIMacroAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UN
void ArmVIXLJNIMacroAssembler::GetCurrentThread(ManagedRegister mtr) {
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(mtr.AsArm().AsVIXLRegister());
- ___ Mov(mtr.AsArm().AsVIXLRegister(), tr);
+ temps.Exclude(AsVIXLRegister(mtr.AsArm()));
+ ___ Mov(AsVIXLRegister(mtr.AsArm()), tr);
}
void ArmVIXLJNIMacroAssembler::GetCurrentThread(FrameOffset dest_offset,
@@ -611,19 +610,19 @@ void ArmVIXLJNIMacroAssembler::GetCurrentThread(FrameOffset dest_offset,
asm_.StoreToOffset(kStoreWord, tr, sp, dest_offset.Int32Value());
}
-void ArmVIXLJNIMacroAssembler::ExceptionPoll(ManagedRegister m_scratch, size_t stack_adjust) {
+void ArmVIXLJNIMacroAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
CHECK_ALIGNED(stack_adjust, kStackAlignment);
- ArmManagedRegister scratch = m_scratch.AsArm();
+ vixl::aarch32::Register scratch = AsVIXLRegister(mscratch.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(scratch.AsVIXLRegister());
+ temps.Exclude(scratch);
exception_blocks_.emplace_back(
- new ArmVIXLJNIMacroAssembler::ArmException(scratch, stack_adjust));
+ new ArmVIXLJNIMacroAssembler::ArmException(mscratch.AsArm(), stack_adjust));
asm_.LoadFromOffset(kLoadWord,
- scratch.AsVIXLRegister(),
+ scratch,
tr,
Thread::ExceptionOffset<kArmPointerSize>().Int32Value());
- ___ Cmp(scratch.AsVIXLRegister(), 0);
+ ___ Cmp(scratch, 0);
vixl32::Label* label = exception_blocks_.back()->Entry();
___ BPreferNear(ne, label);
// TODO: think about using CBNZ here.
@@ -640,19 +639,18 @@ void ArmVIXLJNIMacroAssembler::Jump(JNIMacroLabel* label) {
void ArmVIXLJNIMacroAssembler::Jump(JNIMacroLabel* label,
JNIMacroUnaryCondition condition,
- ManagedRegister test) {
+ ManagedRegister mtest) {
CHECK(label != nullptr);
+ vixl::aarch32::Register test = AsVIXLRegister(mtest.AsArm());
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(test.AsArm().AsVIXLRegister());
+ temps.Exclude(test);
switch (condition) {
case JNIMacroUnaryCondition::kZero:
- ___ CompareAndBranchIfZero(test.AsArm().AsVIXLRegister(),
- ArmVIXLJNIMacroLabel::Cast(label)->AsArm());
+ ___ CompareAndBranchIfZero(test, ArmVIXLJNIMacroLabel::Cast(label)->AsArm());
break;
case JNIMacroUnaryCondition::kNotZero:
- ___ CompareAndBranchIfNonZero(test.AsArm().AsVIXLRegister(),
- ArmVIXLJNIMacroLabel::Cast(label)->AsArm());
+ ___ CompareAndBranchIfNonZero(test, ArmVIXLJNIMacroLabel::Cast(label)->AsArm());
break;
default:
LOG(FATAL) << "Not implemented unary condition: " << static_cast<int>(condition);
@@ -672,12 +670,13 @@ void ArmVIXLJNIMacroAssembler::EmitExceptionPoll(
DecreaseFrameSize(exception->stack_adjust_);
}
+ vixl::aarch32::Register scratch = AsVIXLRegister(exception->scratch_);
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(exception->scratch_.AsVIXLRegister());
+ temps.Exclude(scratch);
// Pass exception object as argument.
// Don't care about preserving r0 as this won't return.
- ___ Mov(r0, exception->scratch_.AsVIXLRegister());
- temps.Include(exception->scratch_.AsVIXLRegister());
+ ___ Mov(r0, scratch);
+ temps.Include(scratch);
// TODO: check that exception->scratch_ is dead by this point.
vixl32::Register temp = temps.Acquire();
___ Ldr(temp,
@@ -698,26 +697,27 @@ void ArmVIXLJNIMacroAssembler::Load(ArmManagedRegister
if (dest.IsNoRegister()) {
CHECK_EQ(0u, size) << dest;
} else if (dest.IsCoreRegister()) {
- CHECK(!dest.AsVIXLRegister().Is(sp)) << dest;
+ vixl::aarch32::Register dst = AsVIXLRegister(dest);
+ CHECK(!dst.Is(sp)) << dest;
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
- temps.Exclude(dest.AsVIXLRegister());
+ temps.Exclude(dst);
if (size == 1u) {
- ___ Ldrb(dest.AsVIXLRegister(), MemOperand(base, offset));
+ ___ Ldrb(dst, MemOperand(base, offset));
} else {
CHECK_EQ(4u, size) << dest;
- ___ Ldr(dest.AsVIXLRegister(), MemOperand(base, offset));
+ ___ Ldr(dst, MemOperand(base, offset));
}
} else if (dest.IsRegisterPair()) {
CHECK_EQ(8u, size) << dest;
- ___ Ldr(dest.AsVIXLRegisterPairLow(), MemOperand(base, offset));
- ___ Ldr(dest.AsVIXLRegisterPairHigh(), MemOperand(base, offset + 4));
+ ___ Ldr(AsVIXLRegisterPairLow(dest), MemOperand(base, offset));
+ ___ Ldr(AsVIXLRegisterPairHigh(dest), MemOperand(base, offset + 4));
} else if (dest.IsSRegister()) {
- ___ Vldr(dest.AsVIXLSRegister(), MemOperand(base, offset));
+ ___ Vldr(AsVIXLSRegister(dest), MemOperand(base, offset));
} else {
CHECK(dest.IsDRegister()) << dest;
- ___ Vldr(dest.AsVIXLDRegister(), MemOperand(base, offset));
+ ___ Vldr(AsVIXLDRegister(dest), MemOperand(base, offset));
}
}
diff --git a/compiler/utils/arm/managed_register_arm.h b/compiler/utils/arm/managed_register_arm.h
index 26f23b2ed6..e42572dc32 100644
--- a/compiler/utils/arm/managed_register_arm.h
+++ b/compiler/utils/arm/managed_register_arm.h
@@ -20,15 +20,8 @@
#include <android-base/logging.h>
#include "constants_arm.h"
-#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
-// TODO(VIXL): Make VIXL compile with -Wshadow.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wshadow"
-#include "aarch32/macro-assembler-aarch32.h"
-#pragma GCC diagnostic pop
-
namespace art {
namespace arm {
@@ -97,31 +90,16 @@ class ArmManagedRegister : public ManagedRegister {
return static_cast<Register>(id_);
}
- vixl::aarch32::Register AsVIXLRegister() const {
- CHECK(IsCoreRegister());
- return vixl::aarch32::Register(id_);
- }
-
constexpr SRegister AsSRegister() const {
CHECK(IsSRegister());
return static_cast<SRegister>(id_ - kNumberOfCoreRegIds);
}
- vixl::aarch32::SRegister AsVIXLSRegister() const {
- CHECK(IsSRegister());
- return vixl::aarch32::SRegister(id_ - kNumberOfCoreRegIds);
- }
-
constexpr DRegister AsDRegister() const {
CHECK(IsDRegister());
return static_cast<DRegister>(id_ - kNumberOfCoreRegIds - kNumberOfSRegIds);
}
- vixl::aarch32::DRegister AsVIXLDRegister() const {
- CHECK(IsDRegister());
- return vixl::aarch32::DRegister(id_ - kNumberOfCoreRegIds - kNumberOfSRegIds);
- }
-
constexpr SRegister AsOverlappingDRegisterLow() const {
CHECK(IsOverlappingDRegister());
DRegister d_reg = AsDRegister();
@@ -150,20 +128,12 @@ class ArmManagedRegister : public ManagedRegister {
return FromRegId(AllocIdLow()).AsCoreRegister();
}
- vixl::aarch32::Register AsVIXLRegisterPairLow() const {
- return vixl::aarch32::Register(AsRegisterPairLow());
- }
-
constexpr Register AsRegisterPairHigh() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdHigh().
return FromRegId(AllocIdHigh()).AsCoreRegister();
}
- vixl::aarch32::Register AsVIXLRegisterPairHigh() const {
- return vixl::aarch32::Register(AsRegisterPairHigh());
- }
-
constexpr bool IsCoreRegister() const {
CHECK(IsValidManagedRegister());
return (0 <= id_) && (id_ < kNumberOfCoreRegIds);
@@ -255,16 +225,16 @@ class ArmManagedRegister : public ManagedRegister {
return FromDRegister(static_cast<DRegister>(r));
}
- private:
- constexpr bool IsValidManagedRegister() const {
- return (0 <= id_) && (id_ < kNumberOfRegIds);
- }
-
int RegId() const {
CHECK(!IsNoRegister());
return id_;
}
+ private:
+ constexpr bool IsValidManagedRegister() const {
+ return (0 <= id_) && (id_ < kNumberOfRegIds);
+ }
+
int AllocId() const {
CHECK(IsValidManagedRegister() &&
!IsOverlappingDRegister() && !IsRegisterPair());
diff --git a/compiler/utils/arm64/managed_register_arm64.h b/compiler/utils/arm64/managed_register_arm64.h
index 9ce7ec9a97..0513890aa8 100644
--- a/compiler/utils/arm64/managed_register_arm64.h
+++ b/compiler/utils/arm64/managed_register_arm64.h
@@ -20,7 +20,6 @@
#include <android-base/logging.h>
#include "arch/arm64/registers_arm64.h"
-#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
namespace art {
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index 674dc9a78b..19c405e517 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -153,7 +153,7 @@ const char* const VixlJniHelpersResults[] = {
" 21c: f8d9 8034 ldr.w r8, [r9, #52] ; 0x34\n",
" 220: 4770 bx lr\n",
" 222: 4660 mov r0, ip\n",
- " 224: f8d9 c2c4 ldr.w ip, [r9, #708] ; 0x2c4\n",
+ " 224: f8d9 c2cc ldr.w ip, [r9, #716] ; 0x2cc\n",
" 228: 47e0 blx ip\n",
nullptr
};
diff --git a/compiler/utils/mips/assembler_mips32r5_test.cc b/compiler/utils/mips/assembler_mips32r5_test.cc
index 9a69ffd3dd..0f858926df 100644
--- a/compiler/utils/mips/assembler_mips32r5_test.cc
+++ b/compiler/utils/mips/assembler_mips32r5_test.cc
@@ -45,6 +45,16 @@ class AssemblerMIPS32r5Test : public AssemblerTest<mips::MipsAssembler,
uint32_t,
mips::VectorRegister> Base;
+ // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<>
+ // and reimplement it without the verification against `assembly_string`. b/73903608
+ void DriverStr(const std::string& assembly_string ATTRIBUTE_UNUSED,
+ const std::string& test_name ATTRIBUTE_UNUSED) {
+ GetAssembler()->FinalizeCode();
+ std::vector<uint8_t> data(GetAssembler()->CodeSize());
+ MemoryRegion code(data.data(), data.size());
+ GetAssembler()->FinalizeInstructions(code);
+ }
+
AssemblerMIPS32r5Test() :
instruction_set_features_(MipsInstructionSetFeatures::FromVariant("mips32r5", nullptr)) {
}
diff --git a/compiler/utils/mips/assembler_mips32r6_test.cc b/compiler/utils/mips/assembler_mips32r6_test.cc
index 691c33f3e7..3d876ca613 100644
--- a/compiler/utils/mips/assembler_mips32r6_test.cc
+++ b/compiler/utils/mips/assembler_mips32r6_test.cc
@@ -45,6 +45,16 @@ class AssemblerMIPS32r6Test : public AssemblerTest<mips::MipsAssembler,
uint32_t,
mips::VectorRegister> Base;
+ // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<>
+ // and reimplement it without the verification against `assembly_string`. b/73903608
+ void DriverStr(const std::string& assembly_string ATTRIBUTE_UNUSED,
+ const std::string& test_name ATTRIBUTE_UNUSED) {
+ GetAssembler()->FinalizeCode();
+ std::vector<uint8_t> data(GetAssembler()->CodeSize());
+ MemoryRegion code(data.data(), data.size());
+ GetAssembler()->FinalizeInstructions(code);
+ }
+
AssemblerMIPS32r6Test() :
instruction_set_features_(MipsInstructionSetFeatures::FromVariant("mips32r6", nullptr)) {
}
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index b027d3a549..f94d074299 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -43,6 +43,16 @@ class AssemblerMIPSTest : public AssemblerTest<mips::MipsAssembler,
mips::FRegister,
uint32_t> Base;
+ // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<>
+ // and reimplement it without the verification against `assembly_string`. b/73903608
+ void DriverStr(const std::string& assembly_string ATTRIBUTE_UNUSED,
+ const std::string& test_name ATTRIBUTE_UNUSED) {
+ GetAssembler()->FinalizeCode();
+ std::vector<uint8_t> data(GetAssembler()->CodeSize());
+ MemoryRegion code(data.data(), data.size());
+ GetAssembler()->FinalizeInstructions(code);
+ }
+
protected:
// Get the typically used name for this architecture, e.g., aarch64, x86-64, ...
std::string GetArchitectureString() OVERRIDE {
diff --git a/compiler/utils/mips/managed_register_mips.h b/compiler/utils/mips/managed_register_mips.h
index 66204e70e3..18d5821e61 100644
--- a/compiler/utils/mips/managed_register_mips.h
+++ b/compiler/utils/mips/managed_register_mips.h
@@ -18,7 +18,6 @@
#define ART_COMPILER_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_
#include "constants_mips.h"
-#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
namespace art {
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index fb5f12be93..a53ff7cc2b 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -48,6 +48,16 @@ class AssemblerMIPS64Test : public AssemblerTest<mips64::Mips64Assembler,
uint32_t,
mips64::VectorRegister> Base;
+ // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<>
+ // and reimplement it without the verification against `assembly_string`. b/73903608
+ void DriverStr(const std::string& assembly_string ATTRIBUTE_UNUSED,
+ const std::string& test_name ATTRIBUTE_UNUSED) {
+ GetAssembler()->FinalizeCode();
+ std::vector<uint8_t> data(GetAssembler()->CodeSize());
+ MemoryRegion code(data.data(), data.size());
+ GetAssembler()->FinalizeInstructions(code);
+ }
+
AssemblerMIPS64Test()
: instruction_set_features_(Mips64InstructionSetFeatures::FromVariant("default", nullptr)) {}
diff --git a/compiler/utils/mips64/managed_register_mips64.h b/compiler/utils/mips64/managed_register_mips64.h
index 3980199b1e..94166d32b7 100644
--- a/compiler/utils/mips64/managed_register_mips64.h
+++ b/compiler/utils/mips64/managed_register_mips64.h
@@ -18,7 +18,6 @@
#define ART_COMPILER_UTILS_MIPS64_MANAGED_REGISTER_MIPS64_H_
#include "constants_mips64.h"
-#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
namespace art {
diff --git a/compiler/utils/x86/managed_register_x86.h b/compiler/utils/x86/managed_register_x86.h
index c0c2b650e9..8810bfa2f1 100644
--- a/compiler/utils/x86/managed_register_x86.h
+++ b/compiler/utils/x86/managed_register_x86.h
@@ -18,7 +18,6 @@
#define ART_COMPILER_UTILS_X86_MANAGED_REGISTER_X86_H_
#include "constants_x86.h"
-#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
namespace art {
diff --git a/compiler/utils/x86_64/managed_register_x86_64.h b/compiler/utils/x86_64/managed_register_x86_64.h
index 32af672670..6760882965 100644
--- a/compiler/utils/x86_64/managed_register_x86_64.h
+++ b/compiler/utils/x86_64/managed_register_x86_64.h
@@ -18,7 +18,6 @@
#define ART_COMPILER_UTILS_X86_64_MANAGED_REGISTER_X86_64_H_
#include "constants_x86_64.h"
-#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
namespace art {
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 4fafca9e1b..18548baf7f 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -294,6 +294,8 @@ art_cc_binary {
use_clang_lld: true,
},
},
+ // b/79417743, oatdump 32-bit tests failed with clang lld
+ use_clang_lld: false,
ldflags: [
// We need this because GC stress mode makes use of
// _Unwind_GetIP and _Unwind_Backtrace and the symbols are also
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index df38ee3a34..6b65aca943 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -78,7 +78,7 @@
#include "gc/space/space-inl.h"
#include "gc/verification.h"
#include "interpreter/unstarted_runtime.h"
-#include "java_vm_ext.h"
+#include "jni/java_vm_ext.h"
#include "linker/buffered_output_stream.h"
#include "linker/elf_writer.h"
#include "linker/elf_writer_quick.h"
@@ -350,6 +350,9 @@ NO_RETURN static void Usage(const char* fmt, ...) {
UsageError("");
UsageError(" --dump-timings: display a breakdown of where time was spent");
UsageError("");
+ UsageError(" --dump-pass-timings: display a breakdown of time spent in optimization");
+ UsageError(" passes for each compiled method.");
+ UsageError("");
UsageError(" -g");
UsageError(" --generate-debug-info: Generate debug information for native debugging,");
UsageError(" such as stack unwinding information, ELF symbols and DWARF sections.");
@@ -1254,10 +1257,10 @@ class Dex2Oat FINAL {
if (stored_class_loader_context_ == nullptr) {
Usage("Option --stored-class-loader-context has an incorrect format: %s",
stored_context_arg.c_str());
- } else if (!class_loader_context_->VerifyClassLoaderContextMatch(
+ } else if (class_loader_context_->VerifyClassLoaderContextMatch(
stored_context_arg,
/*verify_names*/ false,
- /*verify_checksums*/ false)) {
+ /*verify_checksums*/ false) != ClassLoaderContext::VerificationResult::kVerifies) {
Usage(
"Option --stored-class-loader-context '%s' mismatches --class-loader-context '%s'",
stored_context_arg.c_str(),
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index bd1e6df93d..9e5cd8035c 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -52,7 +52,7 @@
#include "image.h"
#include "imt_conflict_table.h"
#include "subtype_check.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "linear_alloc.h"
#include "lock_word.h"
#include "mirror/array-inl.h"
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 1699153e7e..df0641cc7f 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -497,7 +497,7 @@ TEST_F(OatTest, OatHeaderSizeCheck) {
EXPECT_EQ(76U, sizeof(OatHeader));
EXPECT_EQ(4U, sizeof(OatMethodOffsets));
EXPECT_EQ(24U, sizeof(OatQuickMethodHeader));
- EXPECT_EQ(162 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
+ EXPECT_EQ(164 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
sizeof(QuickEntryPoints));
}
diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc
index 1e0f5ac6ae..457addf114 100644
--- a/libdexfile/dex/dex_file_loader.cc
+++ b/libdexfile/dex/dex_file_loader.cc
@@ -191,6 +191,8 @@ std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) {
std::string base_location = GetBaseLocation(dex_location);
const char* suffix = dex_location + base_location.size();
DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
+ // Warning: Bionic implementation of realpath() allocates > 12KB on the stack.
+ // Do not run this code on a small stack, e.g. in signal handler.
UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
if (path != nullptr && path.get() != base_location) {
return std::string(path.get()) + suffix;
diff --git a/libdexfile/dex/dex_file_loader.h b/libdexfile/dex/dex_file_loader.h
index 28cdfc13ce..01532203eb 100644
--- a/libdexfile/dex/dex_file_loader.h
+++ b/libdexfile/dex/dex_file_loader.h
@@ -71,7 +71,7 @@ class DexFileLoader {
// of the dex file. In the second case (oat) it will include the file name
// and possibly some multidex annotation to uniquely identify it.
// canonical_dex_location:
- // the dex_location where it's file name part has been made canonical.
+ // the dex_location where its file name part has been made canonical.
static std::string GetDexCanonicalLocation(const char* dex_location);
// For normal dex files, location and base location coincide. If a dex file is part of a multidex
diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc
index ba65fc9b28..a32f64e49f 100644
--- a/libdexfile/dex/dex_file_verifier.cc
+++ b/libdexfile/dex/dex_file_verifier.cc
@@ -1761,63 +1761,13 @@ bool DexFileVerifier::CheckIntraSectionIterate(size_t offset, uint32_t section_c
return true;
}
-bool DexFileVerifier::CheckIntraSectionIterateByType(size_t offset,
- uint32_t count,
- DexFile::MapItemType type) {
- switch (type) {
- case DexFile::kDexTypeHeaderItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeHeaderItem>(offset, count);
- case DexFile::kDexTypeStringIdItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeStringIdItem>(offset, count);
- case DexFile::kDexTypeTypeIdItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeTypeIdItem>(offset, count);
- case DexFile::kDexTypeProtoIdItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeProtoIdItem>(offset, count);
- case DexFile::kDexTypeFieldIdItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeFieldIdItem>(offset, count);
- case DexFile::kDexTypeMethodIdItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeMethodIdItem>(offset, count);
- case DexFile::kDexTypeClassDefItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeClassDefItem>(offset, count);
- case DexFile::kDexTypeCallSiteIdItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeCallSiteIdItem>(offset, count);
- case DexFile::kDexTypeMethodHandleItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeMethodHandleItem>(offset, count);
- case DexFile::kDexTypeMapList:
- return CheckIntraSectionIterate<DexFile::kDexTypeMapList>(offset, count);
- case DexFile::kDexTypeTypeList:
- return CheckIntraSectionIterate<DexFile::kDexTypeTypeList>(offset, count);
- case DexFile::kDexTypeAnnotationSetRefList:
- return CheckIntraSectionIterate<DexFile::kDexTypeAnnotationSetRefList>(offset, count);
- case DexFile::kDexTypeAnnotationSetItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeAnnotationSetItem>(offset, count);
- case DexFile::kDexTypeClassDataItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeClassDataItem>(offset, count);
- case DexFile::kDexTypeCodeItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeCodeItem>(offset, count);
- case DexFile::kDexTypeStringDataItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeStringDataItem>(offset, count);
- case DexFile::kDexTypeDebugInfoItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeDebugInfoItem>(offset, count);
- case DexFile::kDexTypeAnnotationItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeAnnotationItem>(offset, count);
- case DexFile::kDexTypeEncodedArrayItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeEncodedArrayItem>(offset, count);
- case DexFile::kDexTypeAnnotationsDirectoryItem:
- return CheckIntraSectionIterate<DexFile::kDexTypeAnnotationsDirectoryItem>(offset, count);
- }
- LOG(FATAL) << "Unreachable";
- UNREACHABLE();
-}
-
-bool DexFileVerifier::CheckIntraIdSection(size_t offset,
- uint32_t count,
- DexFile::MapItemType type) {
+template <DexFile::MapItemType kType>
+bool DexFileVerifier::CheckIntraIdSection(size_t offset, uint32_t count) {
uint32_t expected_offset;
uint32_t expected_size;
// Get the expected offset and size from the header.
- switch (type) {
+ switch (kType) {
case DexFile::kDexTypeStringIdItem:
expected_offset = header_->string_ids_off_;
expected_size = header_->string_ids_size_;
@@ -1843,7 +1793,7 @@ bool DexFileVerifier::CheckIntraIdSection(size_t offset,
expected_size = header_->class_defs_size_;
break;
default:
- ErrorStringPrintf("Bad type for id section: %x", type);
+ ErrorStringPrintf("Bad type for id section: %x", kType);
return false;
}
@@ -1857,7 +1807,7 @@ bool DexFileVerifier::CheckIntraIdSection(size_t offset,
return false;
}
- return CheckIntraSectionIterateByType(offset, count, type);
+ return CheckIntraSectionIterate<kType>(offset, count);
}
template <DexFile::MapItemType kType>
@@ -1888,7 +1838,8 @@ bool DexFileVerifier::CheckIntraDataSection(size_t offset, uint32_t count) {
}
bool DexFileVerifier::CheckIntraSection() {
- const DexFile::MapList* map = reinterpret_cast<const DexFile::MapList*>(begin_ + header_->map_off_);
+ const DexFile::MapList* map =
+ reinterpret_cast<const DexFile::MapList*>(begin_ + header_->map_off_);
const DexFile::MapItem* item = map->list_;
size_t offset = 0;
uint32_t count = map->size_;
@@ -1927,17 +1878,22 @@ bool DexFileVerifier::CheckIntraSection() {
ptr_ = begin_ + header_->header_size_;
offset = header_->header_size_;
break;
- case DexFile::kDexTypeStringIdItem:
- case DexFile::kDexTypeTypeIdItem:
- case DexFile::kDexTypeProtoIdItem:
- case DexFile::kDexTypeFieldIdItem:
- case DexFile::kDexTypeMethodIdItem:
- case DexFile::kDexTypeClassDefItem:
- if (!CheckIntraIdSection(section_offset, section_count, type)) {
- return false;
- }
- offset = ptr_ - begin_;
+
+#define CHECK_INTRA_ID_SECTION_CASE(type) \
+ case type: \
+ if (!CheckIntraIdSection<type>(section_offset, section_count)) { \
+ return false; \
+ } \
+ offset = ptr_ - begin_; \
break;
+ CHECK_INTRA_ID_SECTION_CASE(DexFile::kDexTypeStringIdItem)
+ CHECK_INTRA_ID_SECTION_CASE(DexFile::kDexTypeTypeIdItem)
+ CHECK_INTRA_ID_SECTION_CASE(DexFile::kDexTypeProtoIdItem)
+ CHECK_INTRA_ID_SECTION_CASE(DexFile::kDexTypeFieldIdItem)
+ CHECK_INTRA_ID_SECTION_CASE(DexFile::kDexTypeMethodIdItem)
+ CHECK_INTRA_ID_SECTION_CASE(DexFile::kDexTypeClassDefItem)
+#undef CHECK_INTRA_ID_SECTION_CASE
+
case DexFile::kDexTypeMapList:
if (UNLIKELY(section_count != 1)) {
ErrorStringPrintf("Multiple map list items");
@@ -1951,80 +1907,34 @@ bool DexFileVerifier::CheckIntraSection() {
ptr_ += sizeof(uint32_t) + (map->size_ * sizeof(DexFile::MapItem));
offset = section_offset + sizeof(uint32_t) + (map->size_ * sizeof(DexFile::MapItem));
break;
- case DexFile::kDexTypeMethodHandleItem:
- CheckIntraSectionIterate<DexFile::kDexTypeMethodHandleItem>(section_offset, section_count);
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeCallSiteIdItem:
- CheckIntraSectionIterate<DexFile::kDexTypeCallSiteIdItem>(section_offset, section_count);
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeTypeList:
- if (!CheckIntraDataSection<DexFile::kDexTypeTypeList>(section_offset, section_count)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeAnnotationSetRefList:
- if (!CheckIntraDataSection<DexFile::kDexTypeAnnotationSetRefList>(section_offset,
- section_count)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeAnnotationSetItem:
- if (!CheckIntraDataSection<DexFile::kDexTypeAnnotationSetItem>(section_offset,
- section_count)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeClassDataItem:
- if (!CheckIntraDataSection<DexFile::kDexTypeClassDataItem>(section_offset, section_count)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeCodeItem:
- if (!CheckIntraDataSection<DexFile::kDexTypeCodeItem>(section_offset, section_count)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeStringDataItem:
- if (!CheckIntraDataSection<DexFile::kDexTypeStringDataItem>(section_offset,
- section_count)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeDebugInfoItem:
- if (!CheckIntraDataSection<DexFile::kDexTypeDebugInfoItem>(section_offset, section_count)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeAnnotationItem:
- if (!CheckIntraDataSection<DexFile::kDexTypeAnnotationItem>(section_offset,
- section_count)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeEncodedArrayItem:
- if (!CheckIntraDataSection<DexFile::kDexTypeEncodedArrayItem>(section_offset,
- section_count)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeAnnotationsDirectoryItem:
- if (!CheckIntraDataSection<DexFile::kDexTypeAnnotationsDirectoryItem>(section_offset,
- section_count)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
+
+#define CHECK_INTRA_SECTION_ITERATE_CASE(type) \
+ case type: \
+ CheckIntraSectionIterate<type>(section_offset, section_count); \
+ offset = ptr_ - begin_; \
+ break;
+ CHECK_INTRA_SECTION_ITERATE_CASE(DexFile::kDexTypeMethodHandleItem)
+ CHECK_INTRA_SECTION_ITERATE_CASE(DexFile::kDexTypeCallSiteIdItem)
+#undef CHECK_INTRA_SECTION_ITERATE_CASE
+
+#define CHECK_INTRA_DATA_SECTION_CASE(type) \
+ case type: \
+ if (!CheckIntraDataSection<type>(section_offset, section_count)) { \
+ return false; \
+ } \
+ offset = ptr_ - begin_; \
+ break;
+ CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeTypeList)
+ CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeAnnotationSetRefList)
+ CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeAnnotationSetItem)
+ CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeClassDataItem)
+ CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeCodeItem)
+ CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeStringDataItem)
+ CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeDebugInfoItem)
+ CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeAnnotationItem)
+ CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeEncodedArrayItem)
+ CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeAnnotationsDirectoryItem)
+#undef CHECK_INTRA_DATA_SECTION_CASE
}
if (offset == current_offset) {
diff --git a/libdexfile/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h
index eaffc6240a..04d8d71fa8 100644
--- a/libdexfile/dex/dex_file_verifier.h
+++ b/libdexfile/dex/dex_file_verifier.h
@@ -126,8 +126,8 @@ class DexFileVerifier {
template <DexFile::MapItemType kType>
bool CheckIntraSectionIterate(size_t offset, uint32_t count);
- bool CheckIntraSectionIterateByType(size_t offset, uint32_t count, DexFile::MapItemType type);
- bool CheckIntraIdSection(size_t offset, uint32_t count, DexFile::MapItemType type);
+ template <DexFile::MapItemType kType>
+ bool CheckIntraIdSection(size_t offset, uint32_t count);
template <DexFile::MapItemType kType>
bool CheckIntraDataSection(size_t offset, uint32_t count);
bool CheckIntraSection();
diff --git a/libdexfile/dex/hidden_api_access_flags.h b/libdexfile/dex/hidden_api_access_flags.h
index b62d044c6a..1aaeabd783 100644
--- a/libdexfile/dex/hidden_api_access_flags.h
+++ b/libdexfile/dex/hidden_api_access_flags.h
@@ -86,12 +86,10 @@ class HiddenApiAccessFlags {
}
static ALWAYS_INLINE ApiList DecodeFromRuntime(uint32_t runtime_access_flags) {
- if ((runtime_access_flags & kAccIntrinsic) != 0) {
- return kWhitelist;
- } else {
- uint32_t int_value = (runtime_access_flags & kAccHiddenApiBits) >> kAccFlagsShift;
- return static_cast<ApiList>(int_value);
- }
+ // This is used in the fast path, only DCHECK here.
+ DCHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
+ uint32_t int_value = (runtime_access_flags & kAccHiddenApiBits) >> kAccFlagsShift;
+ return static_cast<ApiList>(int_value);
}
static ALWAYS_INLINE uint32_t EncodeForRuntime(uint32_t runtime_access_flags, ApiList value) {
diff --git a/libdexfile/dex/modifiers.h b/libdexfile/dex/modifiers.h
index 2425a588df..be82fff65c 100644
--- a/libdexfile/dex/modifiers.h
+++ b/libdexfile/dex/modifiers.h
@@ -58,6 +58,7 @@ static constexpr uint32_t kAccObsoleteMethod = 0x00040000; // method (ru
static constexpr uint32_t kAccSkipAccessChecks = 0x00080000; // method (runtime, not native)
// Used by a class to denote that the verifier has attempted to check it at least once.
static constexpr uint32_t kAccVerificationAttempted = 0x00080000; // class (runtime)
+static constexpr uint32_t kAccSkipHiddenApiChecks = 0x00100000; // class (runtime)
// This is set by the class linker during LinkInterfaceMethods. It is used by a method to represent
// that it was copied from its declaring class into another class. All methods marked kAccMiranda
// and kAccDefaultConflict will have this bit set. Any kAccDefault method contained in the methods_
diff --git a/libprofile/profile/profile_compilation_info.cc b/libprofile/profile/profile_compilation_info.cc
index 0e0c3c5116..748e24e27c 100644
--- a/libprofile/profile/profile_compilation_info.cc
+++ b/libprofile/profile/profile_compilation_info.cc
@@ -96,9 +96,7 @@ ProfileCompilationInfo::ProfileCompilationInfo()
ProfileCompilationInfo::~ProfileCompilationInfo() {
VLOG(profiler) << Dumpable<MemStats>(allocator_.GetMemStats());
- for (DexFileData* data : info_) {
- delete data;
- }
+ ClearData();
}
void ProfileCompilationInfo::DexPcData::AddClass(uint16_t dex_profile_idx,
@@ -2106,4 +2104,12 @@ bool ProfileCompilationInfo::ProfileFilterFnAcceptAll(
return true;
}
+void ProfileCompilationInfo::ClearData() {
+ for (DexFileData* data : info_) {
+ delete data;
+ }
+ info_.clear();
+ profile_key_map_.clear();
+}
+
} // namespace art
diff --git a/libprofile/profile/profile_compilation_info.h b/libprofile/profile/profile_compilation_info.h
index 32c796c363..e28c5f17b6 100644
--- a/libprofile/profile/profile_compilation_info.h
+++ b/libprofile/profile/profile_compilation_info.h
@@ -445,6 +445,9 @@ class ProfileCompilationInfo {
// Checks if the profile is empty.
bool IsEmpty() const;
+ // Clears all the data from the profile.
+ void ClearData();
+
private:
enum ProfileLoadStatus {
kProfileLoadWouldOverwiteData,
diff --git a/libprofile/profile/profile_compilation_info_test.cc b/libprofile/profile/profile_compilation_info_test.cc
index b0f96492df..b3262a7a14 100644
--- a/libprofile/profile/profile_compilation_info_test.cc
+++ b/libprofile/profile/profile_compilation_info_test.cc
@@ -1339,4 +1339,33 @@ TEST_F(ProfileCompilationInfoTest, FilteredLoadingWithClasses) {
ASSERT_TRUE(loaded_info.Equals(expected_info));
}
+
+TEST_F(ProfileCompilationInfoTest, ClearData) {
+ ProfileCompilationInfo info;
+ for (uint16_t i = 0; i < 10; i++) {
+ ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &info));
+ }
+ ASSERT_FALSE(IsEmpty(info));
+ info.ClearData();
+ ASSERT_TRUE(IsEmpty(info));
+}
+
+TEST_F(ProfileCompilationInfoTest, ClearDataAndSave) {
+ ProfileCompilationInfo info;
+ for (uint16_t i = 0; i < 10; i++) {
+ ASSERT_TRUE(AddMethod("dex_location1", /* checksum */ 1, /* method_idx */ i, &info));
+ }
+ info.ClearData();
+
+ ScratchFile profile;
+ ASSERT_TRUE(info.Save(GetFd(profile)));
+ ASSERT_EQ(0, profile.GetFile()->Flush());
+
+ // Check that we get back what we saved.
+ ProfileCompilationInfo loaded_info;
+ ASSERT_TRUE(profile.GetFile()->ResetOffset());
+ ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
+ ASSERT_TRUE(loaded_info.Equals(info));
+}
+
} // namespace art
diff --git a/oatdump/Android.bp b/oatdump/Android.bp
index be12c8e406..535acdff62 100644
--- a/oatdump/Android.bp
+++ b/oatdump/Android.bp
@@ -24,6 +24,8 @@ cc_defaults {
shared_libs: ["libcutils"],
},
},
+ // b/79417743, oatdump 32-bit tests failed with clang lld
+ use_clang_lld: false,
header_libs: [
"art_cmdlineparser_headers",
],
diff --git a/openjdkjvm/OpenjdkJvm.cc b/openjdkjvm/OpenjdkJvm.cc
index 975d1948fe..be1ab7812a 100644
--- a/openjdkjvm/OpenjdkJvm.cc
+++ b/openjdkjvm/OpenjdkJvm.cc
@@ -48,8 +48,8 @@
#include "common_throws.h"
#include "gc/heap.h"
#include "handle_scope-inl.h"
-#include "java_vm_ext.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/string-inl.h"
#include "monitor.h"
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index ef5151990c..59f61e2ee4 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -43,7 +43,7 @@
#include "base/logging.h" // For gLogVerbosity.
#include "base/mutex.h"
#include "events-inl.h"
-#include "jni_env_ext-inl.h"
+#include "jni/jni_env_ext-inl.h"
#include "obj_ptr-inl.h"
#include "object_tagging.h"
#include "runtime.h"
diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h
index 73cc601e3e..82f3866c65 100644
--- a/openjdkjvmti/art_jvmti.h
+++ b/openjdkjvmti/art_jvmti.h
@@ -47,8 +47,8 @@
#include "base/strlcpy.h"
#include "base/mutex.h"
#include "events.h"
-#include "java_vm_ext.h"
-#include "jni_env_ext.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_env_ext.h"
#include "jvmti.h"
#include "ti_breakpoint.h"
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc
index d4e5df1d67..2f24d7ea3d 100644
--- a/openjdkjvmti/deopt_manager.cc
+++ b/openjdkjvmti/deopt_manager.cc
@@ -41,7 +41,7 @@
#include "dex/modifiers.h"
#include "events-inl.h"
#include "jit/jit.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object_array-inl.h"
#include "nativehelper/scoped_local_ref.h"
diff --git a/openjdkjvmti/events-inl.h b/openjdkjvmti/events-inl.h
index 74ffb84579..6a8ba48109 100644
--- a/openjdkjvmti/events-inl.h
+++ b/openjdkjvmti/events-inl.h
@@ -23,7 +23,7 @@
#include "base/mutex-inl.h"
#include "events.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "nativehelper/scoped_local_ref.h"
#include "scoped_thread_state_change-inl.h"
#include "ti_breakpoint.h"
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index de678711fc..5cb4299293 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -44,8 +44,8 @@
#include "gc/scoped_gc_critical_section.h"
#include "handle_scope-inl.h"
#include "instrumentation.h"
-#include "jni_env_ext-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_env_ext-inl.h"
+#include "jni/jni_internal.h"
#include "mirror/class.h"
#include "mirror/object-inl.h"
#include "monitor.h"
diff --git a/openjdkjvmti/jvmti_weak_table-inl.h b/openjdkjvmti/jvmti_weak_table-inl.h
index 699004298e..d9b8a84e55 100644
--- a/openjdkjvmti/jvmti_weak_table-inl.h
+++ b/openjdkjvmti/jvmti_weak_table-inl.h
@@ -41,7 +41,7 @@
#include "art_jvmti.h"
#include "gc/allocation_listener.h"
#include "instrumentation.h"
-#include "jni_env_ext-inl.h"
+#include "jni/jni_env_ext-inl.h"
#include "jvmti_allocator.h"
#include "mirror/class.h"
#include "mirror/object.h"
diff --git a/openjdkjvmti/ti_breakpoint.cc b/openjdkjvmti/ti_breakpoint.cc
index 136b1d3e1a..813aa8eb83 100644
--- a/openjdkjvmti/ti_breakpoint.cc
+++ b/openjdkjvmti/ti_breakpoint.cc
@@ -41,7 +41,7 @@
#include "dex/dex_file_annotations.h"
#include "dex/modifiers.h"
#include "events-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object_array-inl.h"
#include "nativehelper/scoped_local_ref.h"
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index 261fe3e810..c9d71b4857 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -54,8 +54,8 @@
#include "gc/heap.h"
#include "gc_root.h"
#include "handle.h"
-#include "jni_env_ext-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_env_ext-inl.h"
+#include "jni/jni_internal.h"
#include "mirror/array-inl.h"
#include "mirror/class-inl.h"
#include "mirror/class_ext.h"
diff --git a/openjdkjvmti/ti_class_loader-inl.h b/openjdkjvmti/ti_class_loader-inl.h
index 95278f4b2d..9b04841eb3 100644
--- a/openjdkjvmti/ti_class_loader-inl.h
+++ b/openjdkjvmti/ti_class_loader-inl.h
@@ -36,7 +36,7 @@
#include "art_field-inl.h"
#include "handle.h"
#include "handle_scope.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/object.h"
#include "mirror/object_array-inl.h"
#include "well_known_classes.h"
diff --git a/openjdkjvmti/ti_class_loader.cc b/openjdkjvmti/ti_class_loader.cc
index 3df5de909d..9a32849ed0 100644
--- a/openjdkjvmti/ti_class_loader.cc
+++ b/openjdkjvmti/ti_class_loader.cc
@@ -46,7 +46,7 @@
#include "instrumentation.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
-#include "jni_env_ext-inl.h"
+#include "jni/jni_env_ext-inl.h"
#include "jvmti_allocator.h"
#include "mirror/class.h"
#include "mirror/class_ext.h"
diff --git a/openjdkjvmti/ti_class_loader.h b/openjdkjvmti/ti_class_loader.h
index 142e2e1588..a3857e595a 100644
--- a/openjdkjvmti/ti_class_loader.h
+++ b/openjdkjvmti/ti_class_loader.h
@@ -45,7 +45,7 @@
#include "dex/dex_file.h"
#include "dex/utf.h"
#include "gc_root-inl.h"
-#include "jni_env_ext-inl.h"
+#include "jni/jni_env_ext-inl.h"
#include "jvmti.h"
#include "linear_alloc.h"
#include "mirror/array-inl.h"
diff --git a/openjdkjvmti/ti_field.cc b/openjdkjvmti/ti_field.cc
index c016966d21..328e2a1e40 100644
--- a/openjdkjvmti/ti_field.cc
+++ b/openjdkjvmti/ti_field.cc
@@ -36,7 +36,7 @@
#include "base/enums.h"
#include "dex/dex_file_annotations.h"
#include "dex/modifiers.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/object_array-inl.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-current-inl.h"
diff --git a/openjdkjvmti/ti_heap.cc b/openjdkjvmti/ti_heap.cc
index d0a7cf0657..d23370bc5c 100644
--- a/openjdkjvmti/ti_heap.cc
+++ b/openjdkjvmti/ti_heap.cc
@@ -26,8 +26,8 @@
#include "gc/heap.h"
#include "gc_root-inl.h"
#include "java_frame_root_info.h"
-#include "jni_env_ext.h"
-#include "jni_internal.h"
+#include "jni/jni_env_ext.h"
+#include "jni/jni_internal.h"
#include "jvmti_weak_table-inl.h"
#include "mirror/class.h"
#include "mirror/object-inl.h"
diff --git a/openjdkjvmti/ti_jni.cc b/openjdkjvmti/ti_jni.cc
index dd2dda118a..b655d6a8e1 100644
--- a/openjdkjvmti/ti_jni.cc
+++ b/openjdkjvmti/ti_jni.cc
@@ -35,8 +35,8 @@
#include "art_jvmti.h"
#include "base/mutex.h"
-#include "java_vm_ext.h"
-#include "jni_env_ext.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_env_ext.h"
#include "runtime.h"
#include "thread-current-inl.h"
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index b83310dc85..c0c312c490 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -44,7 +44,7 @@
#include "events-inl.h"
#include "gc_root-inl.h"
#include "jit/jit.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index a23baa5095..8a726bca14 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -58,7 +58,7 @@
#include "jdwp/object_registry.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
-#include "jni_env_ext-inl.h"
+#include "jni/jni_env_ext-inl.h"
#include "jvmti_allocator.h"
#include "mirror/class-inl.h"
#include "mirror/class_ext.h"
diff --git a/openjdkjvmti/ti_redefine.h b/openjdkjvmti/ti_redefine.h
index e14b7ae1c8..227eacd180 100644
--- a/openjdkjvmti/ti_redefine.h
+++ b/openjdkjvmti/ti_redefine.h
@@ -45,7 +45,7 @@
#include "dex/dex_file.h"
#include "dex/utf.h"
#include "gc_root-inl.h"
-#include "jni_env_ext-inl.h"
+#include "jni/jni_env_ext-inl.h"
#include "jvmti.h"
#include "linear_alloc.h"
#include "mirror/array-inl.h"
diff --git a/openjdkjvmti/ti_search.cc b/openjdkjvmti/ti_search.cc
index cbb7b53bff..bcbab14cdd 100644
--- a/openjdkjvmti/ti_search.cc
+++ b/openjdkjvmti/ti_search.cc
@@ -41,7 +41,7 @@
#include "dex/art_dex_file_loader.h"
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object.h"
#include "mirror/string.h"
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index 4526be4cbe..eee8108b01 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -50,8 +50,8 @@
#include "dex/dex_file_types.h"
#include "gc_root.h"
#include "handle_scope-inl.h"
-#include "jni_env_ext.h"
-#include "jni_internal.h"
+#include "jni/jni_env_ext.h"
+#include "jni/jni_internal.h"
#include "mirror/class.h"
#include "mirror/dex_cache.h"
#include "nativehelper/scoped_local_ref.h"
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index 414139c7b4..cabf9e8b09 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -43,7 +43,7 @@
#include "gc/gc_cause.h"
#include "gc/scoped_gc_critical_section.h"
#include "gc_root-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class.h"
#include "mirror/object-inl.h"
#include "mirror/string.h"
diff --git a/openjdkjvmti/ti_threadgroup.cc b/openjdkjvmti/ti_threadgroup.cc
index c0597ad0cc..e17e61fe62 100644
--- a/openjdkjvmti/ti_threadgroup.cc
+++ b/openjdkjvmti/ti_threadgroup.cc
@@ -37,7 +37,7 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "handle_scope-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class.h"
#include "mirror/object-inl.h"
#include "mirror/string.h"
diff --git a/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc
index 29a9b10ca2..8797553b07 100644
--- a/openjdkjvmti/transform.cc
+++ b/openjdkjvmti/transform.cc
@@ -48,7 +48,7 @@
#include "events-inl.h"
#include "fault_handler.h"
#include "gc_root-inl.h"
-#include "jni_env_ext-inl.h"
+#include "jni/jni_env_ext-inl.h"
#include "jvalue.h"
#include "jvmti.h"
#include "linear_alloc.h"
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 28bee3d67e..64e6796ba0 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -100,7 +100,6 @@ cc_defaults {
"interpreter/shadow_frame.cc",
"interpreter/unstarted_runtime.cc",
"java_frame_root_info.cc",
- "java_vm_ext.cc",
"jdwp/jdwp_event.cc",
"jdwp/jdwp_expand_buf.cc",
"jdwp/jdwp_handler.cc",
@@ -108,14 +107,14 @@ cc_defaults {
"jdwp/jdwp_request.cc",
"jdwp/jdwp_socket.cc",
"jdwp/object_registry.cc",
- "jni_env_ext.cc",
"jit/debugger_interface.cc",
"jit/jit.cc",
"jit/jit_code_cache.cc",
"jit/profiling_info.cc",
"jit/profile_saver.cc",
- "jni_internal.cc",
- "jobject_comparator.cc",
+ "jni/java_vm_ext.cc",
+ "jni/jni_env_ext.cc",
+ "jni/jni_internal.cc",
"linear_alloc.cc",
"managed_stack.cc",
"method_handles.cc",
@@ -397,6 +396,7 @@ cc_defaults {
"libbacktrace",
"liblz4",
"liblog",
+ "libmetricslogger",
// For atrace, properties, ashmem, set_sched_policy and socket_peer_is_trusted.
"libcutils",
// For common macros.
@@ -422,6 +422,7 @@ gensrcs {
srcs: [
"arch/instruction_set.h",
"base/mutex.h",
+ "class_loader_context.h",
"class_status.h",
"debugger.h",
"gc_root.h",
@@ -580,7 +581,7 @@ art_cc_test {
"interpreter/safe_math_test.cc",
"interpreter/unstarted_runtime_test.cc",
"jdwp/jdwp_options_test.cc",
- "java_vm_ext_test.cc",
+ "jni/java_vm_ext_test.cc",
"method_handles_test.cc",
"mirror/dex_cache_test.cc",
"mirror/method_type_test.cc",
@@ -620,7 +621,7 @@ art_cc_test {
"art_gtest_defaults",
],
srcs: [
- "jni_internal_test.cc",
+ "jni/jni_internal_test.cc",
"proxy_test.cc",
"reflection_test.cc",
],
diff --git a/runtime/arch/arm/instruction_set_features_arm.cc b/runtime/arch/arm/instruction_set_features_arm.cc
index 801254fd30..608999b3bf 100644
--- a/runtime/arch/arm/instruction_set_features_arm.cc
+++ b/runtime/arch/arm/instruction_set_features_arm.cc
@@ -46,9 +46,11 @@ ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromVariant(
"cortex-a53",
"cortex-a53.a57",
"cortex-a53.a72",
+ "cortex-a55",
"cortex-a57",
"cortex-a72",
"cortex-a73",
+ "cortex-a75",
"exynos-m1",
"denver",
"kryo"
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index a930cc494e..cd00125de5 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1015,7 +1015,10 @@ ENTRY \name
END \name
.endm
-// Macro for string and type resolution and initialization.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings.
+ */
.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
.extern \entrypoint
ENTRY \name
@@ -1040,6 +1043,8 @@ END \name
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
// Note: Functions `art{Get,Set}<Kind>{Static,Instance}FromCompiledCode` are
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.cc b/runtime/arch/arm64/instruction_set_features_arm64.cc
index 42c9a846d0..d0f61c946c 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64.cc
+++ b/runtime/arch/arm64/instruction_set_features_arm64.cc
@@ -52,6 +52,8 @@ Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromVariant(
// Check to see if this is an expected variant.
static const char* arm64_known_variants[] = {
"cortex-a35",
+ "cortex-a55",
+ "cortex-a75",
"exynos-m1",
"exynos-m2",
"exynos-m3",
diff --git a/runtime/arch/arm64/instruction_set_features_arm64_test.cc b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
index 7fd39b6b1b..b946f4f637 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64_test.cc
+++ b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
@@ -64,6 +64,26 @@ TEST(Arm64InstructionSetFeaturesTest, Arm64Features) {
EXPECT_FALSE(kryo_features->Equals(cortex_a57_features.get()));
EXPECT_STREQ("-a53", kryo_features->GetFeatureString().c_str());
EXPECT_EQ(kryo_features->AsBitmap(), 0U);
+
+ std::unique_ptr<const InstructionSetFeatures> cortex_a55_features(
+ InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "cortex-a55", &error_msg));
+ ASSERT_TRUE(cortex_a55_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(cortex_a55_features->GetInstructionSet(), InstructionSet::kArm64);
+ EXPECT_TRUE(cortex_a55_features->Equals(cortex_a55_features.get()));
+ EXPECT_TRUE(cortex_a55_features->Equals(cortex_a35_features.get()));
+ EXPECT_FALSE(cortex_a55_features->Equals(cortex_a57_features.get()));
+ EXPECT_STREQ("-a53", cortex_a55_features->GetFeatureString().c_str());
+ EXPECT_EQ(cortex_a55_features->AsBitmap(), 0U);
+
+ std::unique_ptr<const InstructionSetFeatures> cortex_a75_features(
+ InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "cortex-a75", &error_msg));
+ ASSERT_TRUE(cortex_a75_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(cortex_a75_features->GetInstructionSet(), InstructionSet::kArm64);
+ EXPECT_TRUE(cortex_a75_features->Equals(cortex_a75_features.get()));
+ EXPECT_TRUE(cortex_a75_features->Equals(cortex_a35_features.get()));
+ EXPECT_FALSE(cortex_a75_features->Equals(cortex_a57_features.get()));
+ EXPECT_STREQ("-a53", cortex_a75_features->GetFeatureString().c_str());
+ EXPECT_EQ(cortex_a75_features->AsBitmap(), 0U);
}
} // namespace art
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 9ff5ebede3..ac5b2b8b88 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1533,7 +1533,10 @@ ENTRY \name
END \name
.endm
-// Macro for string and type resolution and initialization.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings.
+ */
.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
.extern \entrypoint
ENTRY \name
@@ -1577,6 +1580,8 @@ TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode,
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
// Note: Functions `art{Get,Set}<Kind>{Static,Instance}FromCompiledCode` are
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 9418caf98c..5d6e410101 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -203,6 +203,10 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) {
static_assert(!IsDirectEntrypoint(kQuickInitializeType), "Non-direct C stub marked direct.");
qpoints->pResolveString = art_quick_resolve_string;
static_assert(!IsDirectEntrypoint(kQuickResolveString), "Non-direct C stub marked direct.");
+ qpoints->pResolveMethodHandle = art_quick_resolve_method_handle;
+ static_assert(!IsDirectEntrypoint(kQuickResolveMethodHandle), "Non-direct C stub marked direct.");
+ qpoints->pResolveMethodType = art_quick_resolve_method_type;
+ static_assert(!IsDirectEntrypoint(kQuickResolveMethodType), "Non-direct C stub marked direct.");
// Field
qpoints->pSet8Instance = art_quick_set8_instance;
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index d8fe480719..c367ea60c2 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -2027,8 +2027,11 @@ GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_tlab, artAllocArrayFr
GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_32
GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_64
-// Macro for string and type resolution and initialization.
-// $a0 is both input and output.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings. $a0 is both input and
+ * output.
+ */
.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
.extern \entrypoint
ENTRY_NO_GP \name
@@ -2053,6 +2056,18 @@ END \name
.endm
/*
+ * Entry from managed code to resolve a method handle. On entry, A0 holds the method handle
+ * index. On success the MethodHandle is returned, otherwise an exception is raised.
+ */
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+
+ /*
+ * Entry from managed code to resolve a method type. On entry, A0 holds the method type index.
+ * On success the MethodType is returned, otherwise an exception is raised.
+ */
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
+
+ /*
* Entry from managed code to resolve a string, this stub will allocate a String and deliver an
* exception on error. On success the String is returned. A0 holds the string index. The fast
* path check for hit in strings cache has already been performed.
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index 8d2a7bd6c1..1f4f174e26 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -1930,8 +1930,11 @@ GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_tlab, artAllocArrayFr
GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_32
GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_64
-// Macro for string and type resolution and initialization.
-// $a0 is both input and output.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings. $a0 is both input and
+ * output.
+ */
.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
.extern \entrypoint
ENTRY_NO_GP \name
@@ -1953,6 +1956,18 @@ END \name
.endm
/*
+ * Entry from managed code to resolve a method handle. On entry, A0 holds the method handle
+ * index. On success the MethodHandle is returned, otherwise an exception is raised.
+ */
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+
+ /*
+ * Entry from managed code to resolve a method type. On entry, A0 holds the method type index.
+ * On success the MethodType is returned, otherwise an exception is raised.
+ */
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
+
+ /*
* Entry from managed code to resolve a string, this stub will allocate a String and deliver an
* exception on error. On success the String is returned. A0 holds the string index. The fast
* path check for hit in strings cache has already been performed.
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 4be4b12611..78516e3aeb 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -24,7 +24,7 @@
#include "common_runtime_test.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "imt_conflict_table.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "linear_alloc.h"
#include "mirror/class-inl.h"
#include "mirror/string-inl.h"
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index df43aef94b..8ab4ce160f 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -923,7 +923,10 @@ MACRO3(THREE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
END_FUNCTION VAR(c_name)
END_MACRO
-// Macro for string and type resolution and initialization.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings.
+ */
MACRO3(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
DEFINE_FUNCTION VAR(c_name)
SETUP_SAVE_EVERYTHING_FRAME ebx, ebx, \runtime_method_offset // save ref containing registers for GC
@@ -932,7 +935,7 @@ MACRO3(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name, runtime_method_offset
CFI_ADJUST_CFA_OFFSET(8)
pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
CFI_ADJUST_CFA_OFFSET(4)
- PUSH eax // pass arg1
+ PUSH eax // pass the index of the constant as arg1
call CALLVAR(cxx_name) // cxx_name(arg1, Thread*)
addl MACRO_LITERAL(16), %esp // pop arguments
CFI_ADJUST_CFA_OFFSET(-16)
@@ -1278,6 +1281,8 @@ GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFr
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 4f941e1c48..eb945ed366 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -951,12 +951,15 @@ MACRO3(THREE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
END_FUNCTION VAR(c_name)
END_MACRO
-// Macro for string and type resolution and initialization.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings.
+ */
MACRO3(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
DEFINE_FUNCTION VAR(c_name)
SETUP_SAVE_EVERYTHING_FRAME \runtime_method_offset // save everything for GC
// Outgoing argument set up
- movl %eax, %edi // pass string index
+ movl %eax, %edi // pass the index of the constant as arg0
movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
call CALLVAR(cxx_name) // cxx_name(arg0, Thread*)
testl %eax, %eax // If result is null, deliver the OOME.
@@ -1298,6 +1301,8 @@ END_FUNCTION art_quick_alloc_object_initialized_region_tlab
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO
diff --git a/runtime/art_field.h b/runtime/art_field.h
index 29d71af358..f39af3900c 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -20,6 +20,7 @@
#include <jni.h>
#include "dex/dex_file_types.h"
+#include "dex/hidden_api_access_flags.h"
#include "dex/modifiers.h"
#include "dex/primitive.h"
#include "gc_root.h"
@@ -179,6 +180,10 @@ class ArtField FINAL {
return (GetAccessFlags() & kAccVolatile) != 0;
}
+ HiddenApiAccessFlags::ApiList GetHiddenApiAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return HiddenApiAccessFlags::DecodeFromRuntime(GetAccessFlags());
+ }
+
// Returns an instance field with this offset in the given class or null if not found.
// If kExactOffset is true then we only find the matching offset, not the field containing the
// offset.
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 1565644380..c1fac364bb 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -384,19 +384,68 @@ inline bool ArtMethod::HasSingleImplementation() {
return (GetAccessFlags<kReadBarrierOption>() & kAccSingleImplementation) != 0;
}
-inline bool ArtMethod::IsHiddenIntrinsic(uint32_t ordinal) {
- switch (static_cast<Intrinsics>(ordinal)) {
- case Intrinsics::kReferenceGetReferent:
- case Intrinsics::kSystemArrayCopyChar:
- case Intrinsics::kStringGetCharsNoCheck:
- case Intrinsics::kVarHandleFullFence:
- case Intrinsics::kVarHandleAcquireFence:
- case Intrinsics::kVarHandleReleaseFence:
- case Intrinsics::kVarHandleLoadLoadFence:
- case Intrinsics::kVarHandleStoreStoreFence:
- return true;
- default:
- return false;
+inline HiddenApiAccessFlags::ApiList ArtMethod::GetHiddenApiAccessFlags()
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (UNLIKELY(IsIntrinsic())) {
+ switch (static_cast<Intrinsics>(GetIntrinsic())) {
+ case Intrinsics::kSystemArrayCopyChar:
+ case Intrinsics::kStringGetCharsNoCheck:
+ case Intrinsics::kReferenceGetReferent:
+ // These intrinsics are on the light greylist and will fail a DCHECK in
+ // SetIntrinsic() if their flags change on the respective dex methods.
+ // Note that the DCHECK currently won't fail if the dex methods are
+ // whitelisted, e.g. in the core image (b/77733081). As a result, we
+ // might print warnings but we won't change the semantics.
+ return HiddenApiAccessFlags::kLightGreylist;
+ case Intrinsics::kVarHandleFullFence:
+ case Intrinsics::kVarHandleAcquireFence:
+ case Intrinsics::kVarHandleReleaseFence:
+ case Intrinsics::kVarHandleLoadLoadFence:
+ case Intrinsics::kVarHandleStoreStoreFence:
+ case Intrinsics::kVarHandleCompareAndExchange:
+ case Intrinsics::kVarHandleCompareAndExchangeAcquire:
+ case Intrinsics::kVarHandleCompareAndExchangeRelease:
+ case Intrinsics::kVarHandleCompareAndSet:
+ case Intrinsics::kVarHandleGet:
+ case Intrinsics::kVarHandleGetAcquire:
+ case Intrinsics::kVarHandleGetAndAdd:
+ case Intrinsics::kVarHandleGetAndAddAcquire:
+ case Intrinsics::kVarHandleGetAndAddRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseAnd:
+ case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseOr:
+ case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseXor:
+ case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
+ case Intrinsics::kVarHandleGetAndSet:
+ case Intrinsics::kVarHandleGetAndSetAcquire:
+ case Intrinsics::kVarHandleGetAndSetRelease:
+ case Intrinsics::kVarHandleGetOpaque:
+ case Intrinsics::kVarHandleGetVolatile:
+ case Intrinsics::kVarHandleSet:
+ case Intrinsics::kVarHandleSetOpaque:
+ case Intrinsics::kVarHandleSetRelease:
+ case Intrinsics::kVarHandleSetVolatile:
+ case Intrinsics::kVarHandleWeakCompareAndSet:
+ case Intrinsics::kVarHandleWeakCompareAndSetAcquire:
+ case Intrinsics::kVarHandleWeakCompareAndSetPlain:
+ case Intrinsics::kVarHandleWeakCompareAndSetRelease:
+ // These intrinsics are on the blacklist and will fail a DCHECK in
+ // SetIntrinsic() if their flags change on the respective dex methods.
+ // Note that the DCHECK currently won't fail if the dex methods are
+ // whitelisted, e.g. in the core image (b/77733081). Given that they are
+ // exclusively VarHandle intrinsics, they should not be used outside
+ // tests that do not enable hidden API checks.
+ return HiddenApiAccessFlags::kBlacklist;
+ default:
+ // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
+ return HiddenApiAccessFlags::kWhitelist;
+ }
+ } else {
+ return HiddenApiAccessFlags::DecodeFromRuntime(GetAccessFlags());
}
}
@@ -422,7 +471,7 @@ inline void ArtMethod::SetIntrinsic(uint32_t intrinsic) {
bool is_default_conflict = IsDefaultConflicting();
bool is_compilable = IsCompilable();
bool must_count_locks = MustCountLocks();
- HiddenApiAccessFlags::ApiList hidden_api_list = GetHiddenApiAccessFlags();
+ HiddenApiAccessFlags::ApiList hidden_api_flags = GetHiddenApiAccessFlags();
SetAccessFlags(new_value);
DCHECK_EQ(java_flags, (GetAccessFlags() & kAccJavaFlagsMask));
DCHECK_EQ(is_constructor, IsConstructor());
@@ -436,14 +485,14 @@ inline void ArtMethod::SetIntrinsic(uint32_t intrinsic) {
DCHECK_EQ(is_default_conflict, IsDefaultConflicting());
DCHECK_EQ(is_compilable, IsCompilable());
DCHECK_EQ(must_count_locks, MustCountLocks());
- if (kIsDebugBuild) {
- if (IsHiddenIntrinsic(intrinsic)) {
- // Special case some of our intrinsics because the access flags clash
- // with the intrinsics ordinal.
- DCHECK_EQ(HiddenApiAccessFlags::kWhitelist, GetHiddenApiAccessFlags());
- } else {
- DCHECK_EQ(hidden_api_list, GetHiddenApiAccessFlags());
- }
+ // Only DCHECK that we have preserved the hidden API access flags if the
+ // original method was not on the whitelist. This is because the core image
+ // does not have the access flags set (b/77733081). It is fine to hard-code
+ // these because (a) warnings on greylist do not change semantics, and
+ // (b) only VarHandle intrinsics are blacklisted at the moment and they
+ // should not be used outside tests with disabled API checks.
+ if (hidden_api_flags != HiddenApiAccessFlags::kWhitelist) {
+ DCHECK_EQ(hidden_api_flags, GetHiddenApiAccessFlags());
}
} else {
SetAccessFlags(new_value);
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 41b01c251b..87fcb20698 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -35,7 +35,7 @@
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
#include "jit/profiling_info.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/class_ext.h"
#include "mirror/executable.h"
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 64d293200f..acaa4a68a1 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -341,9 +341,7 @@ class ArtMethod FINAL {
AddAccessFlags(kAccMustCountLocks);
}
- HiddenApiAccessFlags::ApiList GetHiddenApiAccessFlags() {
- return HiddenApiAccessFlags::DecodeFromRuntime(GetAccessFlags());
- }
+ HiddenApiAccessFlags::ApiList GetHiddenApiAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_);
// Returns true if this method could be overridden by a default method.
bool IsOverridableByDefaultMethod() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -873,9 +871,6 @@ class ArtMethod FINAL {
} while (!access_flags_.compare_exchange_weak(old_access_flags, new_access_flags));
}
- // Returns true if the given intrinsic is considered hidden.
- bool IsHiddenIntrinsic(uint32_t ordinal);
-
DISALLOW_COPY_AND_ASSIGN(ArtMethod); // Need to use CopyFrom to deal with 32 vs 64 bits.
};
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 2f7d6ab98f..70ff40d32c 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -73,7 +73,7 @@ ADD_TEST_EQ(THREAD_LOCAL_OBJECTS_OFFSET,
// Offset of field Thread::tlsPtr_.mterp_current_ibase.
#define THREAD_CURRENT_IBASE_OFFSET \
- (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__ + (1 + 162) * __SIZEOF_POINTER__)
+ (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__ + (1 + 164) * __SIZEOF_POINTER__)
ADD_TEST_EQ(THREAD_CURRENT_IBASE_OFFSET,
art::Thread::MterpCurrentIBaseOffset<POINTER_SIZE>().Int32Value())
// Offset of field Thread::tlsPtr_.mterp_default_ibase.
diff --git a/runtime/base/file_utils.cc b/runtime/base/file_utils.cc
index 7921985b15..537216c198 100644
--- a/runtime/base/file_utils.cc
+++ b/runtime/base/file_utils.cc
@@ -261,12 +261,12 @@ std::string ReplaceFileExtension(const std::string& filename, const std::string&
}
}
-bool LocationIsOnSystem(const char* location) {
- UniqueCPtr<const char[]> path(realpath(location, nullptr));
- return path != nullptr && android::base::StartsWith(path.get(), GetAndroidRoot().c_str());
+bool LocationIsOnSystem(const char* path) {
+ UniqueCPtr<const char[]> full_path(realpath(path, nullptr));
+ return path != nullptr && android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str());
}
-bool LocationIsOnSystemFramework(const char* location) {
+bool LocationIsOnSystemFramework(const char* full_path) {
std::string error_msg;
std::string root_path = GetAndroidRootSafe(&error_msg);
if (root_path.empty()) {
@@ -275,12 +275,7 @@ bool LocationIsOnSystemFramework(const char* location) {
return false;
}
std::string framework_path = root_path + "/framework/";
-
- // Warning: Bionic implementation of realpath() allocates > 12KB on the stack.
- // Do not run this code on a small stack, e.g. in signal handler.
- UniqueCPtr<const char[]> path(realpath(location, nullptr));
- return path != nullptr &&
- android::base::StartsWith(path.get(), framework_path.c_str());
+ return android::base::StartsWith(full_path, framework_path);
}
} // namespace art
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 73b464119e..da286d7e41 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -195,8 +195,8 @@ class ScopedContentionRecorder FINAL : public ValueObject {
};
BaseMutex::BaseMutex(const char* name, LockLevel level)
- : level_(level),
- name_(name),
+ : name_(name),
+ level_(level),
should_respond_to_empty_checkpoint_request_(false) {
if (kLogLockContentions) {
ScopedAllMutexesLock mu(this);
@@ -386,7 +386,7 @@ void BaseMutex::DumpContention(std::ostream& os) const {
Mutex::Mutex(const char* name, LockLevel level, bool recursive)
- : BaseMutex(name, level), exclusive_owner_(0), recursive_(recursive), recursion_count_(0) {
+ : BaseMutex(name, level), exclusive_owner_(0), recursion_count_(0), recursive_(recursive) {
#if ART_USE_FUTEXES
DCHECK_EQ(0, state_.load(std::memory_order_relaxed));
DCHECK_EQ(0, num_contenders_.load(std::memory_order_relaxed));
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 1cf4ddded4..602d183bbb 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -57,7 +57,7 @@ class Mutex;
// partial ordering and thereby cause deadlock situations to fail checks.
//
// [1] http://www.drdobbs.com/parallel/use-lock-hierarchies-to-avoid-deadlock/204801163
-enum LockLevel {
+enum LockLevel : uint8_t {
kLoggingLock = 0,
kSwapMutexesLock,
kUnexpectedSignalLock,
@@ -142,20 +142,20 @@ enum LockLevel {
};
std::ostream& operator<<(std::ostream& os, const LockLevel& rhs);
-const bool kDebugLocking = kIsDebugBuild;
+constexpr bool kDebugLocking = kIsDebugBuild;
// Record Log contention information, dumpable via SIGQUIT.
#ifdef ART_USE_FUTEXES
// To enable lock contention logging, set this to true.
-const bool kLogLockContentions = false;
+constexpr bool kLogLockContentions = false;
#else
// Keep this false as lock contention logging is supported only with
// futex.
-const bool kLogLockContentions = false;
+constexpr bool kLogLockContentions = false;
#endif
-const size_t kContentionLogSize = 4;
-const size_t kContentionLogDataSize = kLogLockContentions ? 1 : 0;
-const size_t kAllMutexDataSize = kLogLockContentions ? 1 : 0;
+constexpr size_t kContentionLogSize = 4;
+constexpr size_t kContentionLogDataSize = kLogLockContentions ? 1 : 0;
+constexpr size_t kAllMutexDataSize = kLogLockContentions ? 1 : 0;
// Base class for all Mutex implementations
class BaseMutex {
@@ -196,9 +196,7 @@ class BaseMutex {
void RecordContention(uint64_t blocked_tid, uint64_t owner_tid, uint64_t nano_time_blocked);
void DumpContention(std::ostream& os) const;
- const LockLevel level_; // Support for lock hierarchy.
const char* const name_;
- bool should_respond_to_empty_checkpoint_request_;
// A log entry that records contention but makes no guarantee that either tid will be held live.
struct ContentionLogEntry {
@@ -221,6 +219,9 @@ class BaseMutex {
};
ContentionLogData contention_log_data_[kContentionLogDataSize];
+ const LockLevel level_; // Support for lock hierarchy.
+ bool should_respond_to_empty_checkpoint_request_;
+
public:
bool HasEverContended() const {
if (kLogLockContentions) {
@@ -307,8 +308,10 @@ class LOCKABLE Mutex : public BaseMutex {
pthread_mutex_t mutex_;
Atomic<pid_t> exclusive_owner_; // Guarded by mutex_. Asynchronous reads are OK.
#endif
- const bool recursive_; // Can the lock be recursively held?
+
unsigned int recursion_count_;
+ const bool recursive_; // Can the lock be recursively held?
+
friend class ConditionVariable;
DISALLOW_COPY_AND_ASSIGN(Mutex);
};
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 9a43790575..f8b977eea7 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -34,8 +34,8 @@
#include "dex/descriptors_names.h"
#include "dex/dex_file-inl.h"
#include "gc/space/space.h"
-#include "java_vm_ext.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/field.h"
#include "mirror/method.h"
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 57c0d9dab2..4141a37366 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -79,11 +79,11 @@
#include "imtable-inl.h"
#include "intern_table.h"
#include "interpreter/interpreter.h"
-#include "java_vm_ext.h"
#include "jit/debugger_interface.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "linear_alloc.h"
#include "mirror/call_site.h"
#include "mirror/class-inl.h"
@@ -7884,6 +7884,40 @@ ArtMethod* ClassLinker::FindResolvedMethod(ObjPtr<mirror::Class> klass,
return resolved;
}
+// Returns true if `method` is either null or hidden.
+// Does not print any warnings if it is hidden.
+static bool CheckNoSuchMethod(ArtMethod* method,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return method == nullptr ||
+ hiddenapi::GetMemberAction(method,
+ class_loader,
+ dex_cache,
+ hiddenapi::kNone) // do not print warnings
+ == hiddenapi::kDeny;
+}
+
+ArtMethod* ClassLinker::FindIncompatibleMethod(ObjPtr<mirror::Class> klass,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader,
+ uint32_t method_idx) {
+ if (klass->IsInterface()) {
+ ArtMethod* method = klass->FindClassMethod(dex_cache, method_idx, image_pointer_size_);
+ return CheckNoSuchMethod(method, dex_cache, class_loader) ? nullptr : method;
+ } else {
+ // If there was an interface method with the same signature, we would have
+ // found it in the "copied" methods. Only DCHECK that the interface method
+ // really does not exist.
+ if (kIsDebugBuild) {
+ ArtMethod* method =
+ klass->FindInterfaceMethod(dex_cache, method_idx, image_pointer_size_);
+ DCHECK(CheckNoSuchMethod(method, dex_cache, class_loader));
+ }
+ return nullptr;
+ }
+}
+
template <ClassLinker::ResolveMode kResolveMode>
ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
@@ -7959,13 +7993,7 @@ ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
// If we had a method, or if we can find one with another lookup type,
// it's an incompatible-class-change error.
if (resolved == nullptr) {
- if (klass->IsInterface()) {
- resolved = klass->FindClassMethod(dex_cache.Get(), method_idx, pointer_size);
- } else {
- // If there was an interface method with the same signature,
- // we would have found it also in the "copied" methods.
- DCHECK(klass->FindInterfaceMethod(dex_cache.Get(), method_idx, pointer_size) == nullptr);
- }
+ resolved = FindIncompatibleMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx);
}
if (resolved != nullptr) {
ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index fa70f65bca..e935d1dfb8 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -329,6 +329,15 @@ class ClassLinker {
uint32_t method_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Find a method using the wrong lookup mechanism. If `klass` is an interface,
+ // search for a class method. If it is a class, search for an interface method.
+ // This is useful when throwing IncompatibleClassChangeError.
+ ArtMethod* FindIncompatibleMethod(ObjPtr<mirror::Class> klass,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader,
+ uint32_t method_idx)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
// Resolve a method with a given ID from the DexFile associated with the given DexCache
// and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader are
// used as in ResolveType. What is unique is the method type argument which is used to
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 4afc44cb91..2bd541118b 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -25,7 +25,7 @@
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
#include "handle_scope-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "oat_file_assistant.h"
#include "obj_ptr-inl.h"
#include "runtime.h"
@@ -672,9 +672,10 @@ static bool IsAbsoluteLocation(const std::string& location) {
return !location.empty() && location[0] == '/';
}
-bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec,
- bool verify_names,
- bool verify_checksums) const {
+ClassLoaderContext::VerificationResult ClassLoaderContext::VerifyClassLoaderContextMatch(
+ const std::string& context_spec,
+ bool verify_names,
+ bool verify_checksums) const {
if (verify_names || verify_checksums) {
DCHECK(dex_files_open_attempted_);
DCHECK(dex_files_open_result_);
@@ -683,15 +684,21 @@ bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& contex
ClassLoaderContext expected_context;
if (!expected_context.Parse(context_spec, verify_checksums)) {
LOG(WARNING) << "Invalid class loader context: " << context_spec;
- return false;
+ return VerificationResult::kMismatch;
}
// Special shared library contexts always match. They essentially instruct the runtime
// to ignore the class path check because the oat file is known to be loaded in different
// contexts. OatFileManager will further verify if the oat file can be loaded based on the
// collision check.
- if (special_shared_library_ || expected_context.special_shared_library_) {
- return true;
+ if (expected_context.special_shared_library_) {
+ // Special case where we are the only entry in the class path.
+ if (class_loader_chain_.size() == 1 && class_loader_chain_[0].classpath.size() == 0) {
+ return VerificationResult::kVerifies;
+ }
+ return VerificationResult::kForcedToSkipChecks;
+ } else if (special_shared_library_) {
+ return VerificationResult::kForcedToSkipChecks;
}
if (expected_context.class_loader_chain_.size() != class_loader_chain_.size()) {
@@ -699,7 +706,7 @@ bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& contex
<< expected_context.class_loader_chain_.size()
<< ", actual=" << class_loader_chain_.size()
<< " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
- return false;
+ return VerificationResult::kMismatch;
}
for (size_t i = 0; i < class_loader_chain_.size(); i++) {
@@ -710,14 +717,14 @@ bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& contex
<< ". expected=" << GetClassLoaderTypeName(expected_info.type)
<< ", found=" << GetClassLoaderTypeName(info.type)
<< " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
- return false;
+ return VerificationResult::kMismatch;
}
if (info.classpath.size() != expected_info.classpath.size()) {
LOG(WARNING) << "ClassLoaderContext classpath size mismatch for position " << i
<< ". expected=" << expected_info.classpath.size()
<< ", found=" << info.classpath.size()
<< " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
- return false;
+ return VerificationResult::kMismatch;
}
if (verify_checksums) {
@@ -772,7 +779,7 @@ bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& contex
<< ". expected=" << expected_info.classpath[k]
<< ", found=" << info.classpath[k]
<< " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
- return false;
+ return VerificationResult::kMismatch;
}
// Compare the checksums.
@@ -781,11 +788,11 @@ bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& contex
<< ". expected=" << expected_info.checksums[k]
<< ", found=" << info.checksums[k]
<< " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
- return false;
+ return VerificationResult::kMismatch;
}
}
}
- return true;
+ return VerificationResult::kVerifies;
}
jclass ClassLoaderContext::GetClassLoaderClass(ClassLoaderType type) {
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index 1c83007f41..a4268aa09a 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -22,8 +22,10 @@
#include "arch/instruction_set.h"
#include "base/dchecked_vector.h"
+#include "dex/dex_file.h"
#include "handle_scope.h"
#include "mirror/class_loader.h"
+#include "oat_file.h"
#include "scoped_thread_state_change.h"
namespace art {
@@ -34,6 +36,18 @@ class OatFile;
// Utility class which holds the class loader context used during compilation/verification.
class ClassLoaderContext {
public:
+ enum class VerificationResult {
+ kVerifies,
+ kForcedToSkipChecks,
+ kMismatch,
+ };
+
+ enum ClassLoaderType {
+ kInvalidClassLoader = 0,
+ kPathClassLoader = 1,
+ kDelegateLastClassLoader = 2
+ };
+
~ClassLoaderContext();
// Opens requested class path files and appends them to ClassLoaderInfo::opened_dex_files.
@@ -109,7 +123,7 @@ class ClassLoaderContext {
// This should be called after OpenDexFiles().
// Names are only verified if verify_names is true.
// Checksums are only verified if verify_checksums is true.
- bool VerifyClassLoaderContextMatch(const std::string& context_spec,
+ VerificationResult VerifyClassLoaderContextMatch(const std::string& context_spec,
bool verify_names = true,
bool verify_checksums = true) const;
@@ -141,12 +155,6 @@ class ClassLoaderContext {
static std::unique_ptr<ClassLoaderContext> Default();
private:
- enum ClassLoaderType {
- kInvalidClassLoader = 0,
- kPathClassLoader = 1,
- kDelegateLastClassLoader = 2
- };
-
struct ClassLoaderInfo {
// The type of this class loader.
ClassLoaderType type;
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index 4689ae4c3f..5e3f48c100 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -608,6 +608,17 @@ TEST_F(ClassLoaderContextTest, CreateContextForClassLoader) {
VerifyClassLoaderPCLFromTestDex(context.get(), 3, "ForClassLoaderA");
}
+
+TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextFirstElement) {
+ std::string context_spec = "PCL[]";
+ std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec);
+ ASSERT_TRUE(context != nullptr);
+ PretendContextOpenedDexFiles(context.get());
+ // Ensure that the special shared library marks as verified for the first thing in the class path.
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(OatFile::kSpecialSharedLibrary),
+ ClassLoaderContext::VerificationResult::kVerifies);
+}
+
TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatch) {
std::string context_spec = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890]";
std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec);
@@ -619,28 +630,36 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatch) {
VerifyClassLoaderPCL(context.get(), 0, "a.dex:b.dex");
VerifyClassLoaderDLC(context.get(), 1, "c.dex");
- ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_spec));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_spec),
+ ClassLoaderContext::VerificationResult::kVerifies);
std::string wrong_class_loader_type = "PCL[a.dex*123:b.dex*456];PCL[c.dex*890]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_class_loader_type));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_class_loader_type),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_class_loader_order = "DLC[c.dex*890];PCL[a.dex*123:b.dex*456]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_class_loader_order));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_class_loader_order),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_classpath_order = "PCL[b.dex*456:a.dex*123];DLC[c.dex*890]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_classpath_order));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_classpath_order),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_checksum = "PCL[a.dex*999:b.dex*456];DLC[c.dex*890]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_checksum));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_checksum),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_extra_class_loader = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890];PCL[d.dex*321]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_extra_class_loader));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_extra_class_loader),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_extra_classpath = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890:d.dex*321]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_extra_classpath));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_extra_classpath),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_spec = "PCL[a.dex*999:b.dex*456];DLC[";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_spec));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_spec),
+ ClassLoaderContext::VerificationResult::kMismatch);
}
TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncoding) {
@@ -652,7 +671,8 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncoding) {
std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader_d);
std::string context_with_no_base_dir = context->EncodeContextForOatFile("");
- ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_with_no_base_dir));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_with_no_base_dir),
+ ClassLoaderContext::VerificationResult::kVerifies);
std::string dex_location = GetTestDexFileName("ForClassLoaderA");
size_t pos = dex_location.rfind('/');
@@ -661,7 +681,8 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncoding) {
std::string context_with_base_dir = context->EncodeContextForOatFile(parent);
ASSERT_NE(context_with_base_dir, context_with_no_base_dir);
- ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_with_base_dir));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_with_base_dir),
+ ClassLoaderContext::VerificationResult::kVerifies);
}
TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncodingMultidex) {
@@ -669,7 +690,8 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncodingMultide
std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader);
- ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")),
+ ClassLoaderContext::VerificationResult::kVerifies);
}
} // namespace art
diff --git a/runtime/class_loader_utils.h b/runtime/class_loader_utils.h
index 1439f11636..af42878e97 100644
--- a/runtime/class_loader_utils.h
+++ b/runtime/class_loader_utils.h
@@ -20,7 +20,7 @@
#include "art_field-inl.h"
#include "base/mutex.h"
#include "handle_scope.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class_loader.h"
#include "native/dalvik_system_DexFile.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index f5b15ec239..75b091d98f 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -48,8 +48,8 @@
#include "gtest/gtest.h"
#include "handle_scope-inl.h"
#include "interpreter/unstarted_runtime.h"
-#include "java_vm_ext.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "native/dalvik_system_DexFile.h"
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 28659cb11d..88628bbc50 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -51,7 +51,7 @@
#include "handle_scope-inl.h"
#include "jdwp/jdwp_priv.h"
#include "jdwp/object_registry.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "jvalue-inl.h"
#include "mirror/class-inl.h"
#include "mirror/class.h"
diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc
index 415e451098..392ce1e7f5 100644
--- a/runtime/dex/art_dex_file_loader.cc
+++ b/runtime/dex/art_dex_file_loader.cc
@@ -534,7 +534,10 @@ std::unique_ptr<DexFile> ArtDexFileLoader::OpenCommon(const uint8_t* base,
// Check if this dex file is located in the framework directory.
// If it is, set a flag on the dex file. This is used by hidden API
// policy decision logic.
- if (dex_file != nullptr && LocationIsOnSystemFramework(location.c_str())) {
+ // Location can contain multidex suffix, so fetch its canonical version. Note
+ // that this will call `realpath`.
+ std::string path = DexFileLoader::GetDexCanonicalLocation(location.c_str());
+ if (dex_file != nullptr && LocationIsOnSystemFramework(path.c_str())) {
dex_file->SetIsPlatformDexFile();
}
diff --git a/runtime/dex/art_dex_file_loader_test.cc b/runtime/dex/art_dex_file_loader_test.cc
index aee397b65b..274a6df702 100644
--- a/runtime/dex/art_dex_file_loader_test.cc
+++ b/runtime/dex/art_dex_file_loader_test.cc
@@ -49,20 +49,31 @@ class ArtDexFileLoaderTest : public CommonRuntimeTest {
CommonRuntimeTest::SetUp();
std::string dex_location = GetTestDexFileName("Main");
+ std::string multidex_location = GetTestDexFileName("MultiDex");
data_location_path_ = android_data_ + "/foo.jar";
system_location_path_ = GetAndroidRoot() + "/foo.jar";
system_framework_location_path_ = GetAndroidRoot() + "/framework/foo.jar";
+ data_multi_location_path_ = android_data_ + "/multifoo.jar";
+ system_multi_location_path_ = GetAndroidRoot() + "/multifoo.jar";
+ system_framework_multi_location_path_ = GetAndroidRoot() + "/framework/multifoo.jar";
Copy(dex_location, data_location_path_);
Copy(dex_location, system_location_path_);
Copy(dex_location, system_framework_location_path_);
+
+ Copy(multidex_location, data_multi_location_path_);
+ Copy(multidex_location, system_multi_location_path_);
+ Copy(multidex_location, system_framework_multi_location_path_);
}
virtual void TearDown() {
remove(data_location_path_.c_str());
remove(system_location_path_.c_str());
remove(system_framework_location_path_.c_str());
+ remove(data_multi_location_path_.c_str());
+ remove(system_multi_location_path_.c_str());
+ remove(system_framework_multi_location_path_.c_str());
CommonRuntimeTest::TearDown();
}
@@ -70,6 +81,9 @@ class ArtDexFileLoaderTest : public CommonRuntimeTest {
std::string data_location_path_;
std::string system_location_path_;
std::string system_framework_location_path_;
+ std::string data_multi_location_path_;
+ std::string system_multi_location_path_;
+ std::string system_framework_multi_location_path_;
};
// TODO: Port OpenTestDexFile(s) need to be ported to use non-ART utilities, and
@@ -390,6 +404,53 @@ TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile) {
for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
ASSERT_TRUE(dex_file->IsPlatformDexFile());
}
+
+ dex_files.clear();
+
+ // Load multidex file from a non-system directory and check that it is not flagged as framework.
+ success = loader.Open(data_multi_location_path_.c_str(),
+ data_multi_location_path_,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg,
+ &dex_files);
+ ASSERT_TRUE(success) << error_msg;
+ ASSERT_GT(dex_files.size(), 1u);
+ for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ ASSERT_FALSE(dex_file->IsPlatformDexFile());
+ }
+
+ dex_files.clear();
+
+ // Load multidex file from a system, non-framework directory and check that it is not flagged
+ // as framework.
+ success = loader.Open(system_multi_location_path_.c_str(),
+ system_multi_location_path_,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg,
+ &dex_files);
+ ASSERT_TRUE(success);
+ ASSERT_GT(dex_files.size(), 1u);
+ for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ ASSERT_FALSE(dex_file->IsPlatformDexFile());
+ }
+
+ dex_files.clear();
+
+ // Load multidex file from a system/framework directory and check that it is flagged as a
+ // framework dex.
+ success = loader.Open(system_framework_multi_location_path_.c_str(),
+ system_framework_multi_location_path_,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg,
+ &dex_files);
+ ASSERT_TRUE(success);
+ ASSERT_GT(dex_files.size(), 1u);
+ for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ ASSERT_TRUE(dex_file->IsPlatformDexFile());
+ }
}
} // namespace art
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index 6f3354b724..c399b1c7fe 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -24,7 +24,7 @@
#include "art_method-inl.h"
#include "class_linker-inl.h"
#include "dex/dex_file-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "jvalue-inl.h"
#include "mirror/field.h"
#include "mirror/method.h"
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 137eb4fe1e..d4e7492f00 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -31,7 +31,7 @@
#include "imt_conflict_table.h"
#include "imtable-inl.h"
#include "indirect_reference_table.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/array.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index ffa138d5b1..a58946ae66 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -26,7 +26,7 @@
#include "entrypoints/quick/callee_save_frame.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
-#include "java_vm_ext.h"
+#include "jni/java_vm_ext.h"
#include "mirror/class-inl.h"
#include "mirror/method.h"
#include "mirror/object-inl.h"
@@ -260,4 +260,26 @@ ArtMethod* GetCalleeSaveOuterMethod(Thread* self, CalleeSaveType type) {
return DoGetCalleeSaveMethodOuterCallerAndPc(sp, type).first;
}
+ObjPtr<mirror::MethodHandle> ResolveMethodHandleFromCode(ArtMethod* referrer,
+ uint32_t method_handle_idx) {
+ Thread::PoisonObjectPointersIfDebug();
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ return class_linker->ResolveMethodHandle(Thread::Current(), method_handle_idx, referrer);
+}
+
+ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer,
+ uint32_t proto_idx) {
+ Thread::PoisonObjectPointersIfDebug();
+ ObjPtr<mirror::MethodType> method_type =
+ referrer->GetDexCache()->GetResolvedMethodType(proto_idx);
+ if (UNLIKELY(method_type == nullptr)) {
+ StackHandleScope<2> hs(Thread::Current());
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ method_type = class_linker->ResolveMethodType(hs.Self(), proto_idx, dex_cache, class_loader);
+ }
+ return method_type;
+}
+
} // namespace art
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index eb32153b16..0a3b5dfc93 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -34,6 +34,8 @@ namespace art {
namespace mirror {
class Array;
class Class;
+class MethodHandle;
+class MethodType;
class Object;
class String;
} // namespace mirror
@@ -151,6 +153,15 @@ inline ObjPtr<mirror::Class> ResolveVerifyAndClinit(dex::TypeIndex type_idx,
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
+ObjPtr<mirror::MethodHandle> ResolveMethodHandleFromCode(ArtMethod* referrer,
+ uint32_t method_handle_idx)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_);
+
+ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer, uint32_t proto_idx)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_);
+
inline ObjPtr<mirror::String> ResolveStringFromCode(ArtMethod* referrer,
dex::StringIndex string_idx)
REQUIRES_SHARED(Locks::mutator_lock_)
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index 780e221129..a4083a4f81 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -18,7 +18,7 @@
#include "art_method-inl.h"
#include "entrypoints/entrypoint_utils.h"
-#include "java_vm_ext.h"
+#include "jni/java_vm_ext.h"
#include "mirror/object-inl.h"
#include "scoped_thread_state_change-inl.h"
#include "thread.h"
diff --git a/runtime/entrypoints/quick/quick_default_externs.h b/runtime/entrypoints/quick/quick_default_externs.h
index 2d0932a0c4..1804d9e64d 100644
--- a/runtime/entrypoints/quick/quick_default_externs.h
+++ b/runtime/entrypoints/quick/quick_default_externs.h
@@ -37,6 +37,8 @@ extern "C" void art_quick_check_instance_of(art::mirror::Object*, art::mirror::C
extern "C" void* art_quick_initialize_static_storage(uint32_t);
extern "C" void* art_quick_initialize_type(uint32_t);
extern "C" void* art_quick_initialize_type_and_verify_access(uint32_t);
+extern "C" void* art_quick_resolve_method_handle(uint32_t);
+extern "C" void* art_quick_resolve_method_type(uint32_t);
extern "C" void* art_quick_resolve_string(uint32_t);
// Field entrypoints.
diff --git a/runtime/entrypoints/quick/quick_default_init_entrypoints.h b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
index 8c90800463..3f66045576 100644
--- a/runtime/entrypoints/quick/quick_default_init_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
@@ -37,6 +37,8 @@ static void DefaultInitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qp
qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage;
qpoints->pInitializeTypeAndVerifyAccess = art_quick_initialize_type_and_verify_access;
qpoints->pInitializeType = art_quick_initialize_type;
+ qpoints->pResolveMethodHandle = art_quick_resolve_method_handle;
+ qpoints->pResolveMethodType = art_quick_resolve_method_type;
qpoints->pResolveString = art_quick_resolve_string;
// Field
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index cfb427f1ac..cf9ddd8aa8 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -183,6 +183,27 @@ extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type
return result.Ptr();
}
+extern "C" mirror::MethodHandle* artResolveMethodHandleFromCode(uint32_t method_handle_idx,
+ Thread* self)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ScopedQuickEntrypointChecks sqec(self);
+ auto caller_and_outer =
+ GetCalleeSaveMethodCallerAndOuterMethod(self, CalleeSaveType::kSaveEverything);
+ ArtMethod* caller = caller_and_outer.caller;
+ ObjPtr<mirror::MethodHandle> result = ResolveMethodHandleFromCode(caller, method_handle_idx);
+ return result.Ptr();
+}
+
+extern "C" mirror::MethodType* artResolveMethodTypeFromCode(uint32_t proto_idx, Thread* self)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ScopedQuickEntrypointChecks sqec(self);
+ auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(self,
+ CalleeSaveType::kSaveEverything);
+ ArtMethod* caller = caller_and_outer.caller;
+ ObjPtr<mirror::MethodType> result = ResolveMethodTypeFromCode(caller, proto_idx);
+ return result.Ptr();
+}
+
extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
ScopedQuickEntrypointChecks sqec(self);
diff --git a/runtime/entrypoints/quick/quick_entrypoints_list.h b/runtime/entrypoints/quick/quick_entrypoints_list.h
index 48a56f2fbf..3a8faca11d 100644
--- a/runtime/entrypoints/quick/quick_entrypoints_list.h
+++ b/runtime/entrypoints/quick/quick_entrypoints_list.h
@@ -38,6 +38,8 @@
V(InitializeStaticStorage, void*, uint32_t) \
V(InitializeTypeAndVerifyAccess, void*, uint32_t) \
V(InitializeType, void*, uint32_t) \
+ V(ResolveMethodHandle, void*, uint32_t) \
+ V(ResolveMethodType, void*, uint32_t) \
V(ResolveString, void*, uint32_t) \
\
V(Set8Instance, int, uint32_t, void*, int8_t) \
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 1fdf439d3f..1337cd5fb2 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -183,7 +183,9 @@ class EntrypointsOrderTest : public CommonRuntimeTest {
sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInitializeTypeAndVerifyAccess, pInitializeType,
sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInitializeType, pResolveString, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInitializeType, pResolveMethodHandle, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pResolveMethodHandle, pResolveMethodType, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pResolveMethodType, pResolveString, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pResolveString, pSet8Instance, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet8Instance, pSet8Static, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet8Static, pSet16Instance, sizeof(void*));
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index 1e136bca2e..681ac2ef28 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -39,7 +39,7 @@
#include "gc/space/space-inl.h"
#include "indirect_reference_table.h"
#include "intern_table.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mark_sweep-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object-refvisitor-inl.h"
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index e85824de70..b004566ed1 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -71,9 +71,9 @@
#include "heap-visit-objects-inl.h"
#include "image.h"
#include "intern_table.h"
-#include "java_vm_ext.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
+#include "jni/java_vm_ext.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object-refvisitor-inl.h"
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index 356f3ecaa8..5be7b325d0 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -19,7 +19,7 @@
#include "base/time_utils.h"
#include "base/utils.h"
#include "collector/garbage_collector.h"
-#include "java_vm_ext.h"
+#include "jni/java_vm_ext.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/reference-inl.h"
diff --git a/runtime/gc/space/region_space.h b/runtime/gc/space/region_space.h
index 811d6db876..a12917140b 100644
--- a/runtime/gc/space/region_space.h
+++ b/runtime/gc/space/region_space.h
@@ -299,10 +299,17 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace {
public:
Region()
: idx_(static_cast<size_t>(-1)),
- begin_(nullptr), top_(nullptr), end_(nullptr),
- state_(RegionState::kRegionStateAllocated), type_(RegionType::kRegionTypeToSpace),
- objects_allocated_(0), alloc_time_(0), live_bytes_(static_cast<size_t>(-1)),
- is_newly_allocated_(false), is_a_tlab_(false), thread_(nullptr) {}
+ live_bytes_(static_cast<size_t>(-1)),
+ begin_(nullptr),
+ thread_(nullptr),
+ top_(nullptr),
+ end_(nullptr),
+ objects_allocated_(0),
+ alloc_time_(0),
+ is_newly_allocated_(false),
+ is_a_tlab_(false),
+ state_(RegionState::kRegionStateAllocated),
+ type_(RegionType::kRegionTypeToSpace) {}
void Init(size_t idx, uint8_t* begin, uint8_t* end) {
idx_ = idx;
@@ -496,22 +503,22 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace {
private:
size_t idx_; // The region's index in the region space.
+ size_t live_bytes_; // The live bytes. Used to compute the live percent.
uint8_t* begin_; // The begin address of the region.
+ Thread* thread_; // The owning thread if it's a tlab.
// Note that `top_` can be higher than `end_` in the case of a
// large region, where an allocated object spans multiple regions
// (large region + one or more large tail regions).
Atomic<uint8_t*> top_; // The current position of the allocation.
uint8_t* end_; // The end address of the region.
- RegionState state_; // The region state (see RegionState).
- RegionType type_; // The region type (see RegionType).
Atomic<size_t> objects_allocated_; // The number of objects allocated.
uint32_t alloc_time_; // The allocation time of the region.
// Note that newly allocated and evacuated regions use -1 as
// special value for `live_bytes_`.
- size_t live_bytes_; // The live bytes. Used to compute the live percent.
bool is_newly_allocated_; // True if it's allocated after the last collection.
bool is_a_tlab_; // True if it's a tlab.
- Thread* thread_; // The owning thread if it's a tlab.
+ RegionState state_; // The region state (see RegionState).
+ RegionType type_; // The region type (see RegionType).
friend class RegionSpace;
};
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index 0e72f275d2..9445ae0c8e 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <metricslogger/metrics_logger.h>
+
#include "hidden_api.h"
#include <nativehelper/scoped_local_ref.h>
@@ -22,11 +24,28 @@
#include "thread-current-inl.h"
#include "well_known_classes.h"
+using android::metricslogger::ComplexEventLogger;
+using android::metricslogger::ACTION_HIDDEN_API_ACCESSED;
+using android::metricslogger::FIELD_HIDDEN_API_ACCESS_METHOD;
+using android::metricslogger::FIELD_HIDDEN_API_ACCESS_DENIED;
+using android::metricslogger::FIELD_HIDDEN_API_SIGNATURE;
+
namespace art {
namespace hiddenapi {
+// Set to true if we should always print a warning in logcat for all hidden API accesses, not just
+// dark grey and black. This can be set to true for developer preview / beta builds, but should be
+// false for public release builds.
+// Note that when flipping this flag, you must also update the expectations of test 674-hiddenapi
+// as it affects whether or not we warn for light grey APIs that have been added to the exemptions
+// list.
+static constexpr bool kLogAllAccesses = true;
+
static inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {
switch (value) {
+ case kNone:
+ LOG(FATAL) << "Internal access to hidden API should not be logged";
+ UNREACHABLE();
case kReflection:
os << "reflection";
break;
@@ -46,42 +65,47 @@ static constexpr bool EnumsEqual(EnforcementPolicy policy, HiddenApiAccessFlags:
// GetMemberAction-related static_asserts.
static_assert(
- EnumsEqual(EnforcementPolicy::kAllLists, HiddenApiAccessFlags::kLightGreylist) &&
EnumsEqual(EnforcementPolicy::kDarkGreyAndBlackList, HiddenApiAccessFlags::kDarkGreylist) &&
EnumsEqual(EnforcementPolicy::kBlacklistOnly, HiddenApiAccessFlags::kBlacklist),
"Mismatch between EnforcementPolicy and ApiList enums");
static_assert(
- EnforcementPolicy::kAllLists < EnforcementPolicy::kDarkGreyAndBlackList &&
+ EnforcementPolicy::kJustWarn < EnforcementPolicy::kDarkGreyAndBlackList &&
EnforcementPolicy::kDarkGreyAndBlackList < EnforcementPolicy::kBlacklistOnly,
"EnforcementPolicy values ordering not correct");
namespace detail {
MemberSignature::MemberSignature(ArtField* field) {
- member_type_ = "field";
- signature_parts_ = {
- field->GetDeclaringClass()->GetDescriptor(&tmp_),
- "->",
- field->GetName(),
- ":",
- field->GetTypeDescriptor()
- };
+ class_name_ = field->GetDeclaringClass()->GetDescriptor(&tmp_);
+ member_name_ = field->GetName();
+ type_signature_ = field->GetTypeDescriptor();
+ type_ = kField;
}
MemberSignature::MemberSignature(ArtMethod* method) {
- member_type_ = "method";
- signature_parts_ = {
- method->GetDeclaringClass()->GetDescriptor(&tmp_),
- "->",
- method->GetName(),
- method->GetSignature().ToString()
- };
+ // If this is a proxy method, print the signature of the interface method.
+ method = method->GetInterfaceMethodIfProxy(
+ Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+
+ class_name_ = method->GetDeclaringClass()->GetDescriptor(&tmp_);
+ member_name_ = method->GetName();
+ type_signature_ = method->GetSignature().ToString();
+ type_ = kMethod;
+}
+
+inline std::vector<const char*> MemberSignature::GetSignatureParts() const {
+ if (type_ == kField) {
+ return { class_name_.c_str(), "->", member_name_.c_str(), ":", type_signature_.c_str() };
+ } else {
+ DCHECK_EQ(type_, kMethod);
+ return { class_name_.c_str(), "->", member_name_.c_str(), type_signature_.c_str() };
+ }
}
bool MemberSignature::DoesPrefixMatch(const std::string& prefix) const {
size_t pos = 0;
- for (const std::string& part : signature_parts_) {
- size_t count = std::min(prefix.length() - pos, part.length());
+ for (const char* part : GetSignatureParts()) {
+ size_t count = std::min(prefix.length() - pos, strlen(part));
if (prefix.compare(pos, count, part, 0, count) == 0) {
pos += count;
} else {
@@ -103,42 +127,115 @@ bool MemberSignature::IsExempted(const std::vector<std::string>& exemptions) {
}
void MemberSignature::Dump(std::ostream& os) const {
- for (std::string part : signature_parts_) {
+ for (const char* part : GetSignatureParts()) {
os << part;
}
}
void MemberSignature::WarnAboutAccess(AccessMethod access_method,
HiddenApiAccessFlags::ApiList list) {
- LOG(WARNING) << "Accessing hidden " << member_type_ << " " << Dumpable<MemberSignature>(*this)
- << " (" << list << ", " << access_method << ")";
+ LOG(WARNING) << "Accessing hidden " << (type_ == kField ? "field " : "method ")
+ << Dumpable<MemberSignature>(*this) << " (" << list << ", " << access_method << ")";
+}
+// Convert an AccessMethod enum to a value for logging from the proto enum.
+// This method may look odd (the enum values are current the same), but it
+// prevents coupling the internal enum to the proto enum (which should never
+// be changed) so that we are free to change the internal one if necessary in
+// future.
+inline static int32_t GetEnumValueForLog(AccessMethod access_method) {
+ switch (access_method) {
+ case kNone:
+ return android::metricslogger::ACCESS_METHOD_NONE;
+ case kReflection:
+ return android::metricslogger::ACCESS_METHOD_REFLECTION;
+ case kJNI:
+ return android::metricslogger::ACCESS_METHOD_JNI;
+ case kLinking:
+ return android::metricslogger::ACCESS_METHOD_LINKING;
+ default:
+ DCHECK(false);
+ }
+}
+
+void MemberSignature::LogAccessToEventLog(AccessMethod access_method, Action action_taken) {
+ if (access_method == kLinking) {
+ // Linking warnings come from static analysis/compilation of the bytecode
+ // and can contain false positives (i.e. code that is never run). We choose
+ // not to log these in the event log.
+ return;
+ }
+ ComplexEventLogger log_maker(ACTION_HIDDEN_API_ACCESSED);
+ log_maker.AddTaggedData(FIELD_HIDDEN_API_ACCESS_METHOD, GetEnumValueForLog(access_method));
+ if (action_taken == kDeny) {
+ log_maker.AddTaggedData(FIELD_HIDDEN_API_ACCESS_DENIED, 1);
+ }
+ std::ostringstream signature_str;
+ Dump(signature_str);
+ log_maker.AddTaggedData(FIELD_HIDDEN_API_SIGNATURE, signature_str.str());
+ log_maker.Record();
+}
+
+static ALWAYS_INLINE bool CanUpdateMemberAccessFlags(ArtField*) {
+ return true;
+}
+
+static ALWAYS_INLINE bool CanUpdateMemberAccessFlags(ArtMethod* method) {
+ return !method->IsIntrinsic();
}
template<typename T>
-Action GetMemberActionImpl(T* member, Action action, AccessMethod access_method) {
+static ALWAYS_INLINE void MaybeWhitelistMember(Runtime* runtime, T* member)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (CanUpdateMemberAccessFlags(member) && runtime->ShouldDedupeHiddenApiWarnings()) {
+ member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
+ member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
+ }
+}
+
+template<typename T>
+Action GetMemberActionImpl(T* member,
+ HiddenApiAccessFlags::ApiList api_list,
+ Action action,
+ AccessMethod access_method) {
+ DCHECK_NE(action, kAllow);
+
// Get the signature, we need it later.
MemberSignature member_signature(member);
Runtime* runtime = Runtime::Current();
- if (action == kDeny) {
- // If we were about to deny, check for an exemption first.
- // Exempted APIs are treated as light grey list.
+ // Check for an exemption first. Exempted APIs are treated as white list.
+ // We only do this if we're about to deny, or if the app is debuggable. This is because:
+ // - we only print a warning for light greylist violations for debuggable apps
+ // - for non-debuggable apps, there is no distinction between light grey & whitelisted APIs.
+ // - we want to avoid the overhead of checking for exemptions for light greylisted APIs whenever
+ // possible.
+ if (kLogAllAccesses || action == kDeny || runtime->IsJavaDebuggable()) {
if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) {
- action = kAllowButWarn;
+ action = kAllow;
// Avoid re-examining the exemption list next time.
- // Note this results in the warning below showing "light greylist", which
- // seems like what one would expect. Exemptions effectively add new members to
- // the light greylist.
- member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
- member->GetAccessFlags(), HiddenApiAccessFlags::kLightGreylist));
+ // Note this results in no warning for the member, which seems like what one would expect.
+ // Exemptions effectively adds new members to the whitelist.
+ MaybeWhitelistMember(runtime, member);
+ return kAllow;
+ }
+
+ if (access_method != kNone) {
+ // Print a log message with information about this class member access.
+ // We do this if we're about to block access, or the app is debuggable.
+ member_signature.WarnAboutAccess(access_method, api_list);
}
}
- // Print a log message with information about this class member access.
- // We do this regardless of whether we block the access or not.
- member_signature.WarnAboutAccess(access_method,
- HiddenApiAccessFlags::DecodeFromRuntime(member->GetAccessFlags()));
+ if (kIsTargetBuild) {
+ uint32_t eventLogSampleRate = runtime->GetHiddenApiEventLogSampleRate();
+ // Assert that RAND_MAX is big enough, to ensure sampling below works as expected.
+ static_assert(RAND_MAX >= 0xffff, "RAND_MAX too small");
+ if (eventLogSampleRate != 0 &&
+ (static_cast<uint32_t>(std::rand()) & 0xffff) < eventLogSampleRate) {
+ member_signature.LogAccessToEventLog(access_method, action);
+ }
+ }
if (action == kDeny) {
// Block access
@@ -148,16 +245,15 @@ Action GetMemberActionImpl(T* member, Action action, AccessMethod access_method)
// Allow access to this member but print a warning.
DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
- // Depending on a runtime flag, we might move the member into whitelist and
- // skip the warning the next time the member is accessed.
- if (runtime->ShouldDedupeHiddenApiWarnings()) {
- member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(
- member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist));
- }
+ if (access_method != kNone) {
+ // Depending on a runtime flag, we might move the member into whitelist and
+ // skip the warning the next time the member is accessed.
+ MaybeWhitelistMember(runtime, member);
- // If this action requires a UI warning, set the appropriate flag.
- if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
- runtime->SetPendingHiddenApiWarning(true);
+ // If this action requires a UI warning, set the appropriate flag.
+ if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
+ runtime->SetPendingHiddenApiWarning(true);
+ }
}
return action;
@@ -165,9 +261,11 @@ Action GetMemberActionImpl(T* member, Action action, AccessMethod access_method)
// Need to instantiate this.
template Action GetMemberActionImpl<ArtField>(ArtField* member,
+ HiddenApiAccessFlags::ApiList api_list,
Action action,
AccessMethod access_method);
template Action GetMemberActionImpl<ArtMethod>(ArtMethod* member,
+ HiddenApiAccessFlags::ApiList api_list,
Action action,
AccessMethod access_method);
} // namespace detail
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index ffdeacbfff..8e21fd3b8f 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -33,7 +33,7 @@ namespace hiddenapi {
// frameworks/base/core/java/android/content/pm/ApplicationInfo.java
enum class EnforcementPolicy {
kNoChecks = 0,
- kAllLists = 1, // ban anything but whitelist
+ kJustWarn = 1, // keep checks enabled, but allow everything (enables logging)
kDarkGreyAndBlackList = 2, // ban dark grey & blacklist
kBlacklistOnly = 3, // ban blacklist violations only
kMax = kBlacklistOnly,
@@ -53,22 +53,37 @@ enum Action {
};
enum AccessMethod {
+ kNone, // internal test that does not correspond to an actual access by app
kReflection,
kJNI,
kLinking,
};
-inline Action GetActionFromAccessFlags(uint32_t access_flags) {
+// Do not change the values of items in this enum, as they are written to the
+// event log for offline analysis. Any changes will interfere with that analysis.
+enum AccessContextFlags {
+ // Accessed member is a field if this bit is set, else a method
+ kMemberIsField = 1 << 0,
+ // Indicates if access was denied to the member, instead of just printing a warning.
+ kAccessDenied = 1 << 1,
+};
+
+inline Action GetActionFromAccessFlags(HiddenApiAccessFlags::ApiList api_list) {
+ if (api_list == HiddenApiAccessFlags::kWhitelist) {
+ return kAllow;
+ }
+
EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
if (policy == EnforcementPolicy::kNoChecks) {
// Exit early. Nothing to enforce.
return kAllow;
}
- HiddenApiAccessFlags::ApiList api_list = HiddenApiAccessFlags::DecodeFromRuntime(access_flags);
- if (api_list == HiddenApiAccessFlags::kWhitelist) {
- return kAllow;
+ // if policy is "just warn", always warn. We returned above for whitelist APIs.
+ if (policy == EnforcementPolicy::kJustWarn) {
+ return kAllowButWarn;
}
+ DCHECK(policy >= EnforcementPolicy::kDarkGreyAndBlackList);
// The logic below relies on equality of values in the enums EnforcementPolicy and
// HiddenApiAccessFlags::ApiList, and their ordering. Assertions are in hidden_api.cc.
if (static_cast<int>(policy) > static_cast<int>(api_list)) {
@@ -87,9 +102,18 @@ namespace detail {
// is used as a helper when matching prefixes, and when logging the signature.
class MemberSignature {
private:
- std::string member_type_;
- std::vector<std::string> signature_parts_;
+ enum MemberType {
+ kField,
+ kMethod,
+ };
+
+ std::string class_name_;
+ std::string member_name_;
+ std::string type_signature_;
std::string tmp_;
+ MemberType type_;
+
+ inline std::vector<const char*> GetSignatureParts() const;
public:
explicit MemberSignature(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -105,45 +129,72 @@ class MemberSignature {
bool IsExempted(const std::vector<std::string>& exemptions);
void WarnAboutAccess(AccessMethod access_method, HiddenApiAccessFlags::ApiList list);
+
+ void LogAccessToEventLog(AccessMethod access_method, Action action_taken);
};
template<typename T>
-Action GetMemberActionImpl(T* member, Action action, AccessMethod access_method)
+Action GetMemberActionImpl(T* member,
+ HiddenApiAccessFlags::ApiList api_list,
+ Action action,
+ AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns true if the caller is either loaded by the boot strap class loader or comes from
// a dex file located in ${ANDROID_ROOT}/framework/.
ALWAYS_INLINE
-inline bool IsCallerInPlatformDex(ObjPtr<mirror::ClassLoader> caller_class_loader,
- ObjPtr<mirror::DexCache> caller_dex_cache)
+inline bool IsCallerTrusted(ObjPtr<mirror::Class> caller,
+ ObjPtr<mirror::ClassLoader> caller_class_loader,
+ ObjPtr<mirror::DexCache> caller_dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (caller_class_loader.IsNull()) {
+ // Boot class loader.
return true;
- } else if (caller_dex_cache.IsNull()) {
- return false;
- } else {
+ }
+
+ if (!caller_dex_cache.IsNull()) {
const DexFile* caller_dex_file = caller_dex_cache->GetDexFile();
- return caller_dex_file != nullptr && caller_dex_file->IsPlatformDexFile();
+ if (caller_dex_file != nullptr && caller_dex_file->IsPlatformDexFile()) {
+ // Caller is in a platform dex file.
+ return true;
+ }
}
+
+ if (!caller.IsNull() &&
+ caller->ShouldSkipHiddenApiChecks() &&
+ Runtime::Current()->IsJavaDebuggable()) {
+ // We are in debuggable mode and this caller has been marked trusted.
+ return true;
+ }
+
+ return false;
}
} // namespace detail
// Returns true if access to `member` should be denied to the caller of the
-// reflective query. The decision is based on whether the caller is in the
-// platform or not. Because different users of this function determine this
-// in a different way, `fn_caller_in_platform(self)` is called and should
-// return true if the caller is located in the platform.
+// reflective query. The decision is based on whether the caller is trusted or
+// not. Because different users of this function determine this in a different
+// way, `fn_caller_is_trusted(self)` is called and should return true if the
+// caller is allowed to access the platform.
// This function might print warnings into the log if the member is hidden.
template<typename T>
inline Action GetMemberAction(T* member,
Thread* self,
- std::function<bool(Thread*)> fn_caller_in_platform,
+ std::function<bool(Thread*)> fn_caller_is_trusted,
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(member != nullptr);
- Action action = GetActionFromAccessFlags(member->GetAccessFlags());
+ // Decode hidden API access flags.
+ // NB Multiple threads might try to access (and overwrite) these simultaneously,
+ // causing a race. We only do that if access has not been denied, so the race
+ // cannot change Java semantics. We should, however, decode the access flags
+ // once and use it throughout this function, otherwise we may get inconsistent
+ // results, e.g. print whitelist warnings (b/78327881).
+ HiddenApiAccessFlags::ApiList api_list = member->GetHiddenApiAccessFlags();
+
+ Action action = GetActionFromAccessFlags(member->GetHiddenApiAccessFlags());
if (action == kAllow) {
// Nothing to do.
return action;
@@ -151,19 +202,18 @@ inline Action GetMemberAction(T* member,
// Member is hidden. Invoke `fn_caller_in_platform` and find the origin of the access.
// This can be *very* expensive. Save it for last.
- if (fn_caller_in_platform(self)) {
- // Caller in the platform. Exit.
+ if (fn_caller_is_trusted(self)) {
+ // Caller is trusted. Exit.
return kAllow;
}
// Member is hidden and caller is not in the platform.
- return detail::GetMemberActionImpl(member, action, access_method);
+ return detail::GetMemberActionImpl(member, api_list, action, access_method);
}
-inline bool IsCallerInPlatformDex(ObjPtr<mirror::Class> caller)
- REQUIRES_SHARED(Locks::mutator_lock_) {
+inline bool IsCallerTrusted(ObjPtr<mirror::Class> caller) REQUIRES_SHARED(Locks::mutator_lock_) {
return !caller.IsNull() &&
- detail::IsCallerInPlatformDex(caller->GetClassLoader(), caller->GetDexCache());
+ detail::IsCallerTrusted(caller, caller->GetClassLoader(), caller->GetDexCache());
}
// Returns true if access to `member` should be denied to a caller loaded with
@@ -175,10 +225,11 @@ inline Action GetMemberAction(T* member,
ObjPtr<mirror::DexCache> caller_dex_cache,
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
- bool caller_in_platform = detail::IsCallerInPlatformDex(caller_class_loader, caller_dex_cache);
+ bool is_caller_trusted =
+ detail::IsCallerTrusted(/* caller */ nullptr, caller_class_loader, caller_dex_cache);
return GetMemberAction(member,
/* thread */ nullptr,
- [caller_in_platform] (Thread*) { return caller_in_platform; },
+ [is_caller_trusted] (Thread*) { return is_caller_trusted; },
access_method);
}
diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc
index 5a31dd4972..ab0c2901ff 100644
--- a/runtime/hidden_api_test.cc
+++ b/runtime/hidden_api_test.cc
@@ -17,11 +17,13 @@
#include "hidden_api.h"
#include "common_runtime_test.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
+#include "proxy_test.h"
namespace art {
using hiddenapi::detail::MemberSignature;
+using hiddenapi::GetActionFromAccessFlags;
class HiddenApiTest : public CommonRuntimeTest {
protected:
@@ -30,7 +32,7 @@ class HiddenApiTest : public CommonRuntimeTest {
CommonRuntimeTest::SetUp();
self_ = Thread::Current();
self_->TransitionFromSuspendedToRunnable();
- LoadDex("HiddenApiSignatures");
+ jclass_loader_ = LoadDex("HiddenApiSignatures");
bool started = runtime_->Start();
CHECK(started);
@@ -68,6 +70,7 @@ class HiddenApiTest : public CommonRuntimeTest {
protected:
Thread* self_;
+ jobject jclass_loader_;
ArtField* class1_field1_;
ArtField* class1_field12_;
ArtMethod* class1_init_;
@@ -84,6 +87,44 @@ class HiddenApiTest : public CommonRuntimeTest {
ArtMethod* class3_method1_i_;
};
+TEST_F(HiddenApiTest, CheckGetActionFromRuntimeFlags) {
+ runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kNoChecks);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kWhitelist), hiddenapi::kAllow);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kLightGreylist), hiddenapi::kAllow);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kDarkGreylist), hiddenapi::kAllow);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kBlacklist), hiddenapi::kAllow);
+
+ runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kJustWarn);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kWhitelist),
+ hiddenapi::kAllow);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kLightGreylist),
+ hiddenapi::kAllowButWarn);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kDarkGreylist),
+ hiddenapi::kAllowButWarn);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kBlacklist),
+ hiddenapi::kAllowButWarn);
+
+ runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kDarkGreyAndBlackList);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kWhitelist),
+ hiddenapi::kAllow);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kLightGreylist),
+ hiddenapi::kAllowButWarn);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kDarkGreylist),
+ hiddenapi::kDeny);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kBlacklist),
+ hiddenapi::kDeny);
+
+ runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kBlacklistOnly);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kWhitelist),
+ hiddenapi::kAllow);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kLightGreylist),
+ hiddenapi::kAllowButWarn);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kDarkGreylist),
+ hiddenapi::kAllowButWarnAndToast);
+ ASSERT_EQ(GetActionFromAccessFlags(HiddenApiAccessFlags::kBlacklist),
+ hiddenapi::kDeny);
+}
+
TEST_F(HiddenApiTest, CheckMembersRead) {
ASSERT_NE(nullptr, class1_field1_);
ASSERT_NE(nullptr, class1_field12_);
@@ -272,4 +313,56 @@ TEST_F(HiddenApiTest, CheckFieldTrailingCharsNoMatch) {
ASSERT_FALSE(MemberSignature(class1_field1_).DoesPrefixMatch(prefix));
}
+TEST_F(HiddenApiTest, CheckMemberSignatureForProxyClass) {
+ ScopedObjectAccess soa(self_);
+ StackHandleScope<4> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader(
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader_)));
+
+ // Find interface we will create a proxy for.
+ Handle<mirror::Class> h_iface(hs.NewHandle(
+ class_linker_->FindClass(soa.Self(), "Lmypackage/packagea/Interface;", class_loader)));
+ ASSERT_TRUE(h_iface != nullptr);
+
+ // Create the proxy class.
+ std::vector<mirror::Class*> interfaces;
+ interfaces.push_back(h_iface.Get());
+ Handle<mirror::Class> proxyClass = hs.NewHandle(proxy_test::GenerateProxyClass(
+ soa, jclass_loader_, runtime_->GetClassLinker(), "$Proxy1234", interfaces));
+ ASSERT_TRUE(proxyClass != nullptr);
+ ASSERT_TRUE(proxyClass->IsProxyClass());
+ ASSERT_TRUE(proxyClass->IsInitialized());
+
+ // Find the "method" virtual method.
+ ArtMethod* method = nullptr;
+ for (auto& m : proxyClass->GetDeclaredVirtualMethods(kRuntimePointerSize)) {
+ if (strcmp("method", m.GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetName()) == 0) {
+ method = &m;
+ break;
+ }
+ }
+ ASSERT_TRUE(method != nullptr);
+
+ // Find the "interfaces" static field. This is generated for all proxies.
+ ArtField* field = nullptr;
+ for (size_t i = 0; i < proxyClass->NumStaticFields(); ++i) {
+ ArtField* f = proxyClass->GetStaticField(i);
+ if (strcmp("interfaces", f->GetName()) == 0) {
+ field = f;
+ break;
+ }
+ }
+ ASSERT_TRUE(field != nullptr);
+
+ // Test the signature. We expect the signature from the interface class.
+ std::ostringstream ss_method;
+ MemberSignature(method).Dump(ss_method);
+ ASSERT_EQ("Lmypackage/packagea/Interface;->method()V", ss_method.str());
+
+ // Test the signature. We expect the signature of the proxy class.
+ std::ostringstream ss_field;
+ MemberSignature(field).Dump(ss_field);
+ ASSERT_EQ("L$Proxy1234;->interfaces:[Ljava/lang/Class;", ss_field.str());
+}
+
} // namespace art
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 6143ba6fd4..950a54d61e 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -19,8 +19,8 @@
#include "base/mutator_locked_dumpable.h"
#include "base/systrace.h"
#include "base/utils.h"
-#include "java_vm_ext.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "nth_caller_visitor.h"
#include "reference_table.h"
#include "runtime.h"
diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc
index 836bbe711f..3171eeb861 100644
--- a/runtime/instrumentation_test.cc
+++ b/runtime/instrumentation_test.cc
@@ -24,7 +24,7 @@
#include "dex/dex_file.h"
#include "gc/scoped_gc_critical_section.h"
#include "handle_scope-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "jvalue.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index 510f5f00a6..df1eb2b561 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -17,7 +17,7 @@
#include "object_registry.h"
#include "handle_scope-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class.h"
#include "mirror/throwable.h"
#include "obj_ptr-inl.h"
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 2c0fbadc1d..0684b461ae 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -27,8 +27,8 @@
#include "debugger.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "interpreter/interpreter.h"
-#include "java_vm_ext.h"
#include "jit_code_cache.h"
+#include "jni/java_vm_ext.h"
#include "mirror/method_handle_impl.h"
#include "mirror/var_handle.h"
#include "oat_file_manager.h"
@@ -185,10 +185,12 @@ Jit* Jit::Create(JitOptions* options, std::string* error_msg) {
if (jit_compiler_handle_ == nullptr && !LoadCompiler(error_msg)) {
return nullptr;
}
+ bool code_cache_only_for_profile_data = !options->UseJitCompilation();
jit->code_cache_.reset(JitCodeCache::Create(
options->GetCodeCacheInitialCapacity(),
options->GetCodeCacheMaxCapacity(),
jit->generate_debug_info_,
+ code_cache_only_for_profile_data,
error_msg));
if (jit->GetCodeCache() == nullptr) {
return nullptr;
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 6d27cfe5db..4b8b8919d1 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -252,6 +252,13 @@ class JitOptions {
void SetSaveProfilingInfo(bool save_profiling_info) {
profile_saver_options_.SetEnabled(save_profiling_info);
}
+ void SetWaitForJitNotificationsToSaveProfile(bool value) {
+ profile_saver_options_.SetWaitForJitNotificationsToSave(value);
+ }
+ void SetProfileAOTCode(bool value) {
+ profile_saver_options_.SetProfileAOTCode(value);
+ }
+
void SetJitAtFirstUse() {
use_jit_compilation_ = true;
compile_threshold_ = 0;
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 1c8c26cf5d..d8aa00c45e 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -50,7 +50,6 @@
namespace art {
namespace jit {
-static constexpr int kProtAll = PROT_READ | PROT_WRITE | PROT_EXEC;
static constexpr int kProtData = PROT_READ | PROT_WRITE;
static constexpr int kProtCode = PROT_READ | PROT_EXEC;
@@ -161,6 +160,7 @@ class JitCodeCache::JniStubData {
JitCodeCache* JitCodeCache::Create(size_t initial_capacity,
size_t max_capacity,
bool generate_debug_info,
+ bool used_only_for_profile_data,
std::string* error_msg) {
ScopedTrace trace(__PRETTY_FUNCTION__);
CHECK_GE(max_capacity, initial_capacity);
@@ -184,6 +184,15 @@ JitCodeCache* JitCodeCache::Create(size_t initial_capacity,
return nullptr;
}
+ // Decide how we should map the code and data sections.
+ // If we use the code cache just for profiling we do not need to map the code section as
+ // executable.
+ // NOTE 1: this is yet another workaround to bypass strict SElinux policies in order to be able
+ // to profile system server.
+ // NOTE 2: We could just not create the code section at all but we will need to
+ // special case too many cases.
+ int memmap_flags_prot_code = used_only_for_profile_data ? (kProtCode & ~PROT_EXEC) : kProtCode;
+
std::string error_str;
// Map name specific for android_os_Debug.cpp accounting.
// Map in low 4gb to simplify accessing root tables for x86_64.
@@ -216,8 +225,11 @@ JitCodeCache* JitCodeCache::Create(size_t initial_capacity,
DCHECK_EQ(code_size + data_size, max_capacity);
uint8_t* divider = data_map->Begin() + data_size;
- MemMap* code_map =
- data_map->RemapAtEnd(divider, "jit-code-cache", kProtAll, &error_str, use_ashmem);
+ MemMap* code_map = data_map->RemapAtEnd(
+ divider,
+ "jit-code-cache",
+ memmap_flags_prot_code | PROT_WRITE,
+ &error_str, use_ashmem);
if (code_map == nullptr) {
std::ostringstream oss;
oss << "Failed to create read write execute cache: " << error_str << " size=" << max_capacity;
@@ -229,7 +241,13 @@ JitCodeCache* JitCodeCache::Create(size_t initial_capacity,
code_size = initial_capacity - data_size;
DCHECK_EQ(code_size + data_size, initial_capacity);
return new JitCodeCache(
- code_map, data_map.release(), code_size, data_size, max_capacity, garbage_collect_code);
+ code_map,
+ data_map.release(),
+ code_size,
+ data_size,
+ max_capacity,
+ garbage_collect_code,
+ memmap_flags_prot_code);
}
JitCodeCache::JitCodeCache(MemMap* code_map,
@@ -237,7 +255,8 @@ JitCodeCache::JitCodeCache(MemMap* code_map,
size_t initial_code_capacity,
size_t initial_data_capacity,
size_t max_capacity,
- bool garbage_collect_code)
+ bool garbage_collect_code,
+ int memmap_flags_prot_code)
: lock_("Jit code cache", kJitCodeCacheLock),
lock_cond_("Jit code cache condition variable", lock_),
collection_in_progress_(false),
@@ -258,7 +277,8 @@ JitCodeCache::JitCodeCache(MemMap* code_map,
histogram_code_memory_use_("Memory used for compiled code", 16),
histogram_profiling_info_memory_use_("Memory used for profiling info", 16),
is_weak_access_enabled_(true),
- inline_cache_cond_("Jit inline cache condition variable", lock_) {
+ inline_cache_cond_("Jit inline cache condition variable", lock_),
+ memmap_flags_prot_code_(memmap_flags_prot_code) {
DCHECK_GE(max_capacity, initial_code_capacity + initial_data_capacity);
code_mspace_ = create_mspace_with_base(code_map_->Begin(), code_end_, false /*locked*/);
@@ -274,7 +294,7 @@ JitCodeCache::JitCodeCache(MemMap* code_map,
"mprotect jit code cache",
code_map_->Begin(),
code_map_->Size(),
- kProtCode);
+ memmap_flags_prot_code_);
CheckedCall(mprotect,
"mprotect jit data cache",
data_map_->Begin(),
@@ -327,19 +347,30 @@ const void* JitCodeCache::GetJniStubCode(ArtMethod* method) {
class ScopedCodeCacheWrite : ScopedTrace {
public:
- explicit ScopedCodeCacheWrite(MemMap* code_map)
+ explicit ScopedCodeCacheWrite(const JitCodeCache* const code_cache)
: ScopedTrace("ScopedCodeCacheWrite"),
- code_map_(code_map) {
+ code_cache_(code_cache) {
ScopedTrace trace("mprotect all");
- CheckedCall(mprotect, "make code writable", code_map_->Begin(), code_map_->Size(), kProtAll);
+ CheckedCall(
+ mprotect,
+ "make code writable",
+ code_cache_->code_map_->Begin(),
+ code_cache_->code_map_->Size(),
+ code_cache_->memmap_flags_prot_code_ | PROT_WRITE);
}
+
~ScopedCodeCacheWrite() {
ScopedTrace trace("mprotect code");
- CheckedCall(mprotect, "make code protected", code_map_->Begin(), code_map_->Size(), kProtCode);
+ CheckedCall(
+ mprotect,
+ "make code protected",
+ code_cache_->code_map_->Begin(),
+ code_cache_->code_map_->Size(),
+ code_cache_->memmap_flags_prot_code_);
}
private:
- MemMap* const code_map_;
+ const JitCodeCache* const code_cache_;
DISALLOW_COPY_AND_ASSIGN(ScopedCodeCacheWrite);
};
@@ -532,7 +563,7 @@ void JitCodeCache::SweepRootTables(IsMarkedVisitor* visitor) {
}
}
-void JitCodeCache::FreeCode(const void* code_ptr) {
+void JitCodeCache::FreeCodeAndData(const void* code_ptr) {
uintptr_t allocation = FromCodeToAllocation(code_ptr);
// Notify native debugger that we are about to remove the code.
// It does nothing if we are not using native debugger.
@@ -557,9 +588,9 @@ void JitCodeCache::FreeAllMethodHeaders(
// so it's possible for the same method_header to start representing
// different compile code.
MutexLock mu(Thread::Current(), lock_);
- ScopedCodeCacheWrite scc(code_map_.get());
+ ScopedCodeCacheWrite scc(this);
for (const OatQuickMethodHeader* method_header : method_headers) {
- FreeCode(method_header->GetCode());
+ FreeCodeAndData(method_header->GetCode());
}
}
@@ -576,7 +607,7 @@ void JitCodeCache::RemoveMethodsIn(Thread* self, const LinearAlloc& alloc) {
// with the classlinker_classes_lock_ held, and suspending ourselves could
// lead to a deadlock.
{
- ScopedCodeCacheWrite scc(code_map_.get());
+ ScopedCodeCacheWrite scc(this);
for (auto it = jni_stubs_map_.begin(); it != jni_stubs_map_.end();) {
it->second.RemoveMethodsIn(alloc);
if (it->second.GetMethods().empty()) {
@@ -715,7 +746,7 @@ uint8_t* JitCodeCache::CommitCodeInternal(Thread* self,
MutexLock mu(self, lock_);
WaitForPotentialCollectionToComplete(self);
{
- ScopedCodeCacheWrite scc(code_map_.get());
+ ScopedCodeCacheWrite scc(this);
memory = AllocateCode(total_size);
if (memory == nullptr) {
return nullptr;
@@ -878,14 +909,14 @@ bool JitCodeCache::RemoveMethodLocked(ArtMethod* method, bool release_memory) {
}
bool in_cache = false;
- ScopedCodeCacheWrite ccw(code_map_.get());
+ ScopedCodeCacheWrite ccw(this);
if (UNLIKELY(method->IsNative())) {
auto it = jni_stubs_map_.find(JniStubKey(method));
if (it != jni_stubs_map_.end() && it->second.RemoveMethod(method)) {
in_cache = true;
if (it->second.GetMethods().empty()) {
if (release_memory) {
- FreeCode(it->second.GetCode());
+ FreeCodeAndData(it->second.GetCode());
}
jni_stubs_map_.erase(it);
} else {
@@ -897,7 +928,7 @@ bool JitCodeCache::RemoveMethodLocked(ArtMethod* method, bool release_memory) {
if (it->second == method) {
in_cache = true;
if (release_memory) {
- FreeCode(it->first);
+ FreeCodeAndData(it->first);
}
it = method_code_map_.erase(it);
} else {
@@ -1105,7 +1136,7 @@ void JitCodeCache::SetFootprintLimit(size_t new_footprint) {
DCHECK_EQ(per_space_footprint * 2, new_footprint);
mspace_set_footprint_limit(data_mspace_, per_space_footprint);
{
- ScopedCodeCacheWrite scc(code_map_.get());
+ ScopedCodeCacheWrite scc(this);
mspace_set_footprint_limit(code_mspace_, per_space_footprint);
}
}
@@ -1273,7 +1304,7 @@ void JitCodeCache::RemoveUnmarkedCode(Thread* self) {
std::unordered_set<OatQuickMethodHeader*> method_headers;
{
MutexLock mu(self, lock_);
- ScopedCodeCacheWrite scc(code_map_.get());
+ ScopedCodeCacheWrite scc(this);
// Iterate over all compiled code and remove entries that are not marked.
for (auto it = jni_stubs_map_.begin(); it != jni_stubs_map_.end();) {
JniStubData* data = &it->second;
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index f1c99fb85a..958e8e8aa2 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -68,6 +68,7 @@ template<class T> class ObjectArray;
namespace jit {
class JitInstrumentationCache;
+class ScopedCodeCacheWrite;
// Alignment in bits that will suit all architectures.
static constexpr int kJitCodeAlignment = 16;
@@ -88,6 +89,7 @@ class JitCodeCache {
static JitCodeCache* Create(size_t initial_capacity,
size_t max_capacity,
bool generate_debug_info,
+ bool used_only_for_profile_data,
std::string* error_msg);
~JitCodeCache();
@@ -270,7 +272,8 @@ class JitCodeCache {
size_t initial_code_capacity,
size_t initial_data_capacity,
size_t max_capacity,
- bool garbage_collect_code);
+ bool garbage_collect_code,
+ int memmap_flags_prot_code);
// Internal version of 'CommitCode' that will not retry if the
// allocation fails. Return null if the allocation fails.
@@ -314,8 +317,8 @@ class JitCodeCache {
REQUIRES(lock_)
REQUIRES(Locks::mutator_lock_);
- // Free in the mspace allocations for `code_ptr`.
- void FreeCode(const void* code_ptr) REQUIRES(lock_);
+ // Free code and data allocations for `code_ptr`.
+ void FreeCodeAndData(const void* code_ptr) REQUIRES(lock_);
// Number of bytes allocated in the code cache.
size_t CodeCacheSizeLocked() REQUIRES(lock_);
@@ -354,10 +357,10 @@ class JitCodeCache {
REQUIRES(lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- void FreeCode(uint8_t* code) REQUIRES(lock_);
uint8_t* AllocateCode(size_t code_size) REQUIRES(lock_);
- void FreeData(uint8_t* data) REQUIRES(lock_);
+ void FreeCode(uint8_t* code) REQUIRES(lock_);
uint8_t* AllocateData(size_t data_size) REQUIRES(lock_);
+ void FreeData(uint8_t* data) REQUIRES(lock_);
bool IsWeakAccessEnabled(Thread* self) const;
void WaitUntilInlineCacheAccessible(Thread* self)
@@ -442,7 +445,12 @@ class JitCodeCache {
// Condition to wait on for accessing inline caches.
ConditionVariable inline_cache_cond_ GUARDED_BY(lock_);
+ // Mapping flags for the code section.
+ const int memmap_flags_prot_code_;
+
friend class art::JitJniStubTestHelper;
+ friend class ScopedCodeCacheWrite;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(JitCodeCache);
};
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 618fde8f00..6ccda8b0bb 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -131,6 +131,11 @@ void ProfileSaver::Run() {
}
FetchAndCacheResolvedClassesAndMethods(/*startup*/ true);
+
+ // When we save without waiting for JIT notifications we use a simple
+ // exponential back off policy bounded by max_wait_without_jit.
+ uint32_t max_wait_without_jit = options_.GetMinSavePeriodMs() * 16;
+ uint64_t cur_wait_without_jit = options_.GetMinSavePeriodMs();
// Loop for the profiled methods.
while (!ShuttingDown(self)) {
uint64_t sleep_start = NanoTime();
@@ -138,7 +143,14 @@ void ProfileSaver::Run() {
uint64_t sleep_time = 0;
{
MutexLock mu(self, wait_lock_);
- period_condition_.Wait(self);
+ if (options_.GetWaitForJitNotificationsToSave()) {
+ period_condition_.Wait(self);
+ } else {
+ period_condition_.TimedWait(self, cur_wait_without_jit, 0);
+ if (cur_wait_without_jit < max_wait_without_jit) {
+ cur_wait_without_jit *= 2;
+ }
+ }
sleep_time = NanoTime() - sleep_start;
}
// Check if the thread was woken up for shutdown.
@@ -516,10 +528,24 @@ bool ProfileSaver::ProcessProfilingInfo(bool force_save, /*out*/uint16_t* number
uint64_t last_save_number_of_methods = info.GetNumberOfMethods();
uint64_t last_save_number_of_classes = info.GetNumberOfResolvedClasses();
- info.AddMethods(profile_methods, ProfileCompilationInfo::MethodHotness::kFlagPostStartup);
+ // Try to add the method data. Note this may fail is the profile loaded from disk contains
+ // outdated data (e.g. the previous profiled dex files might have been updated).
+ // If this happens we clear the profile data and for the save to ensure the file is cleared.
+ if (!info.AddMethods(profile_methods,
+ ProfileCompilationInfo::MethodHotness::kFlagPostStartup)) {
+ LOG(WARNING) << "Could not add methods to the existing profiler. "
+ << "Clearing the profile data.";
+ info.ClearData();
+ force_save = true;
+ }
+
auto profile_cache_it = profile_cache_.find(filename);
if (profile_cache_it != profile_cache_.end()) {
- info.MergeWith(*(profile_cache_it->second));
+ if (!info.MergeWith(*(profile_cache_it->second))) {
+ LOG(WARNING) << "Could not merge the profile. Clearing the profile data.";
+ info.ClearData();
+ force_save = true;
+ }
}
int64_t delta_number_of_methods =
@@ -597,7 +623,13 @@ void* ProfileSaver::RunProfileSaverThread(void* arg) {
return nullptr;
}
-static bool ShouldProfileLocation(const std::string& location) {
+static bool ShouldProfileLocation(const std::string& location, bool profile_aot_code) {
+ if (profile_aot_code) {
+ // If we have to profile all the code, irrespective of its compilation state, return true
+ // right away.
+ return true;
+ }
+
OatFileManager& oat_manager = Runtime::Current()->GetOatFileManager();
const OatFile* oat_file = oat_manager.FindOpenedOatFileFromDexLocation(location);
if (oat_file == nullptr) {
@@ -629,7 +661,7 @@ void ProfileSaver::Start(const ProfileSaverOptions& options,
std::vector<std::string> code_paths_to_profile;
for (const std::string& location : code_paths) {
- if (ShouldProfileLocation(location)) {
+ if (ShouldProfileLocation(location, options.GetProfileAOTCode())) {
code_paths_to_profile.push_back(location);
}
}
diff --git a/runtime/jit/profile_saver_options.h b/runtime/jit/profile_saver_options.h
index d1e14e2766..18f7899af1 100644
--- a/runtime/jit/profile_saver_options.h
+++ b/runtime/jit/profile_saver_options.h
@@ -41,7 +41,9 @@ struct ProfileSaverOptions {
min_notification_before_wake_(kMinNotificationBeforeWake),
max_notification_before_wake_(kMaxNotificationBeforeWake),
profile_path_(""),
- profile_boot_class_path_(false) {}
+ profile_boot_class_path_(false),
+ profile_aot_code_(false),
+ wait_for_jit_notifications_to_save_(true) {}
ProfileSaverOptions(
bool enabled,
@@ -53,7 +55,9 @@ struct ProfileSaverOptions {
uint32_t min_notification_before_wake,
uint32_t max_notification_before_wake,
const std::string& profile_path,
- bool profile_boot_class_path)
+ bool profile_boot_class_path,
+ bool profile_aot_code = false,
+ bool wait_for_jit_notifications_to_save = true)
: enabled_(enabled),
min_save_period_ms_(min_save_period_ms),
save_resolved_classes_delay_ms_(save_resolved_classes_delay_ms),
@@ -63,7 +67,9 @@ struct ProfileSaverOptions {
min_notification_before_wake_(min_notification_before_wake),
max_notification_before_wake_(max_notification_before_wake),
profile_path_(profile_path),
- profile_boot_class_path_(profile_boot_class_path) {}
+ profile_boot_class_path_(profile_boot_class_path),
+ profile_aot_code_(profile_aot_code),
+ wait_for_jit_notifications_to_save_(wait_for_jit_notifications_to_save) {}
bool IsEnabled() const {
return enabled_;
@@ -103,6 +109,18 @@ struct ProfileSaverOptions {
bool GetProfileBootClassPath() const {
return profile_boot_class_path_;
}
+ bool GetProfileAOTCode() const {
+ return profile_aot_code_;
+ }
+ void SetProfileAOTCode(bool value) {
+ profile_aot_code_ = value;
+ }
+ bool GetWaitForJitNotificationsToSave() const {
+ return wait_for_jit_notifications_to_save_;
+ }
+ void SetWaitForJitNotificationsToSave(bool value) {
+ wait_for_jit_notifications_to_save_ = value;
+ }
friend std::ostream & operator<<(std::ostream &os, const ProfileSaverOptions& pso) {
os << "enabled_" << pso.enabled_
@@ -113,7 +131,9 @@ struct ProfileSaverOptions {
<< ", min_classes_to_save_" << pso.min_classes_to_save_
<< ", min_notification_before_wake_" << pso.min_notification_before_wake_
<< ", max_notification_before_wake_" << pso.max_notification_before_wake_
- << ", profile_boot_class_path_" << pso.profile_boot_class_path_;
+ << ", profile_boot_class_path_" << pso.profile_boot_class_path_
+ << ", profile_aot_code_" << pso.profile_aot_code_
+ << ", wait_for_jit_notifications_to_save_" << pso.wait_for_jit_notifications_to_save_;
return os;
}
@@ -129,6 +149,8 @@ struct ProfileSaverOptions {
uint32_t max_notification_before_wake_;
std::string profile_path_;
bool profile_boot_class_path_;
+ bool profile_aot_code_;
+ bool wait_for_jit_notifications_to_save_;
};
} // namespace art
diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc
index 9126bea7d0..2cb569c61a 100644
--- a/runtime/jit/profiling_info.cc
+++ b/runtime/jit/profiling_info.cc
@@ -26,12 +26,12 @@
namespace art {
ProfilingInfo::ProfilingInfo(ArtMethod* method, const std::vector<uint32_t>& entries)
- : number_of_inline_caches_(entries.size()),
- method_(method),
- is_method_being_compiled_(false),
- is_osr_method_being_compiled_(false),
+ : method_(method),
+ saved_entry_point_(nullptr),
+ number_of_inline_caches_(entries.size()),
current_inline_uses_(0),
- saved_entry_point_(nullptr) {
+ is_method_being_compiled_(false),
+ is_osr_method_being_compiled_(false) {
memset(&cache_, 0, number_of_inline_caches_ * sizeof(InlineCache));
for (size_t i = 0; i < number_of_inline_caches_; ++i) {
cache_[i].dex_pc_ = entries[i];
diff --git a/runtime/jit/profiling_info.h b/runtime/jit/profiling_info.h
index 788fa1f92b..a3dae8330a 100644
--- a/runtime/jit/profiling_info.h
+++ b/runtime/jit/profiling_info.h
@@ -132,27 +132,27 @@ class ProfilingInfo {
private:
ProfilingInfo(ArtMethod* method, const std::vector<uint32_t>& entries);
- // Number of instructions we are profiling in the ArtMethod.
- const uint32_t number_of_inline_caches_;
-
// Method this profiling info is for.
// Not 'const' as JVMTI introduces obsolete methods that we implement by creating new ArtMethods.
// See JitCodeCache::MoveObsoleteMethod.
ArtMethod* method_;
- // Whether the ArtMethod is currently being compiled. This flag
- // is implicitly guarded by the JIT code cache lock.
- // TODO: Make the JIT code cache lock global.
- bool is_method_being_compiled_;
- bool is_osr_method_being_compiled_;
+ // Entry point of the corresponding ArtMethod, while the JIT code cache
+ // is poking for the liveness of compiled code.
+ const void* saved_entry_point_;
+
+ // Number of instructions we are profiling in the ArtMethod.
+ const uint32_t number_of_inline_caches_;
// When the compiler inlines the method associated to this ProfilingInfo,
// it updates this counter so that the GC does not try to clear the inline caches.
uint16_t current_inline_uses_;
- // Entry point of the corresponding ArtMethod, while the JIT code cache
- // is poking for the liveness of compiled code.
- const void* saved_entry_point_;
+ // Whether the ArtMethod is currently being compiled. This flag
+ // is implicitly guarded by the JIT code cache lock.
+ // TODO: Make the JIT code cache lock global.
+ bool is_method_being_compiled_;
+ bool is_osr_method_being_compiled_;
// Dynamically allocated array of size `number_of_inline_caches_`.
InlineCache cache_[0];
diff --git a/runtime/java_vm_ext.cc b/runtime/jni/java_vm_ext.cc
index 8fe68bd318..8fe68bd318 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/jni/java_vm_ext.cc
diff --git a/runtime/java_vm_ext.h b/runtime/jni/java_vm_ext.h
index ac20afecd4..408d3542ed 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/jni/java_vm_ext.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_JAVA_VM_EXT_H_
-#define ART_RUNTIME_JAVA_VM_EXT_H_
+#ifndef ART_RUNTIME_JNI_JAVA_VM_EXT_H_
+#define ART_RUNTIME_JNI_JAVA_VM_EXT_H_
#include "jni.h"
@@ -262,4 +262,4 @@ class JavaVMExt : public JavaVM {
} // namespace art
-#endif // ART_RUNTIME_JAVA_VM_EXT_H_
+#endif // ART_RUNTIME_JNI_JAVA_VM_EXT_H_
diff --git a/runtime/java_vm_ext_test.cc b/runtime/jni/java_vm_ext_test.cc
index a15ec56274..74e4a30905 100644
--- a/runtime/java_vm_ext_test.cc
+++ b/runtime/jni/java_vm_ext_test.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include <pthread.h>
diff --git a/runtime/jni_env_ext-inl.h b/runtime/jni/jni_env_ext-inl.h
index 14f708b18d..7609a9e01a 100644
--- a/runtime/jni_env_ext-inl.h
+++ b/runtime/jni/jni_env_ext-inl.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_JNI_ENV_EXT_INL_H_
-#define ART_RUNTIME_JNI_ENV_EXT_INL_H_
+#ifndef ART_RUNTIME_JNI_JNI_ENV_EXT_INL_H_
+#define ART_RUNTIME_JNI_JNI_ENV_EXT_INL_H_
#include "jni_env_ext.h"
@@ -51,4 +51,4 @@ inline T JNIEnvExt::AddLocalReference(ObjPtr<mirror::Object> obj) {
} // namespace art
-#endif // ART_RUNTIME_JNI_ENV_EXT_INL_H_
+#endif // ART_RUNTIME_JNI_JNI_ENV_EXT_INL_H_
diff --git a/runtime/jni_env_ext.cc b/runtime/jni/jni_env_ext.cc
index efe43ee0e9..efe43ee0e9 100644
--- a/runtime/jni_env_ext.cc
+++ b/runtime/jni/jni_env_ext.cc
diff --git a/runtime/jni_env_ext.h b/runtime/jni/jni_env_ext.h
index 291ac48e86..3a007adcf0 100644
--- a/runtime/jni_env_ext.h
+++ b/runtime/jni/jni_env_ext.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_JNI_ENV_EXT_H_
-#define ART_RUNTIME_JNI_ENV_EXT_H_
+#ifndef ART_RUNTIME_JNI_JNI_ENV_EXT_H_
+#define ART_RUNTIME_JNI_JNI_ENV_EXT_H_
#include <jni.h>
@@ -229,4 +229,4 @@ class ScopedJniEnvLocalRefState {
} // namespace art
-#endif // ART_RUNTIME_JNI_ENV_EXT_H_
+#endif // ART_RUNTIME_JNI_JNI_ENV_EXT_H_
diff --git a/runtime/jni_internal.cc b/runtime/jni/jni_internal.cc
index 9dbcded867..cd66a60376 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni/jni_internal.cc
@@ -80,15 +80,15 @@ namespace art {
// things not rendering correctly. E.g. b/16858794
static constexpr bool kWarnJniAbort = false;
-static bool IsCallerInPlatformDex(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
- return hiddenapi::IsCallerInPlatformDex(GetCallingClass(self, /* num_frames */ 1));
+static bool IsCallerTrusted(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return hiddenapi::IsCallerTrusted(GetCallingClass(self, /* num_frames */ 1));
}
template<typename T>
ALWAYS_INLINE static bool ShouldBlockAccessToMember(T* member, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
hiddenapi::Action action = hiddenapi::GetMemberAction(
- member, self, IsCallerInPlatformDex, hiddenapi::kJNI);
+ member, self, IsCallerTrusted, hiddenapi::kJNI);
if (action != hiddenapi::kAllow) {
hiddenapi::NotifyHiddenApiListener(member);
}
diff --git a/runtime/jni_internal.h b/runtime/jni/jni_internal.h
index 2c90b3ba78..d0426617eb 100644
--- a/runtime/jni_internal.h
+++ b/runtime/jni/jni_internal.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_JNI_INTERNAL_H_
-#define ART_RUNTIME_JNI_INTERNAL_H_
+#ifndef ART_RUNTIME_JNI_JNI_INTERNAL_H_
+#define ART_RUNTIME_JNI_JNI_INTERNAL_H_
#include <jni.h>
#include <iosfwd>
@@ -59,4 +59,4 @@ static inline ArtMethod* DecodeArtMethod(jmethodID method_id) {
std::ostream& operator<<(std::ostream& os, const jobjectRefType& rhs);
-#endif // ART_RUNTIME_JNI_INTERNAL_H_
+#endif // ART_RUNTIME_JNI_JNI_INTERNAL_H_
diff --git a/runtime/jni_internal_test.cc b/runtime/jni/jni_internal_test.cc
index 5d74181cef..5d74181cef 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni/jni_internal_test.cc
diff --git a/runtime/jobject_comparator.cc b/runtime/jobject_comparator.cc
deleted file mode 100644
index 4c45e3839b..0000000000
--- a/runtime/jobject_comparator.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "jobject_comparator.h"
-
-#include "mirror/array-inl.h"
-#include "mirror/class-inl.h"
-#include "mirror/object-inl.h"
-#include "scoped_thread_state_change-inl.h"
-
-namespace art {
-
-bool JobjectComparator::operator()(jobject jobj1, jobject jobj2) const {
- // Ensure null references and cleared jweaks appear at the end.
- if (jobj1 == nullptr) {
- return true;
- } else if (jobj2 == nullptr) {
- return false;
- }
- ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<2> hs(soa.Self());
- Handle<mirror::Object> obj1(hs.NewHandle(soa.Decode<mirror::Object>(jobj1)));
- Handle<mirror::Object> obj2(hs.NewHandle(soa.Decode<mirror::Object>(jobj2)));
- if (obj1 == nullptr) {
- return true;
- } else if (obj2 == nullptr) {
- return false;
- }
- // Sort by class...
- if (obj1->GetClass() != obj2->GetClass()) {
- return obj1->GetClass()->IdentityHashCode() < obj2->GetClass()->IdentityHashCode();
- }
- // ...then by size...
- const size_t count1 = obj1->SizeOf();
- const size_t count2 = obj2->SizeOf();
- if (count1 != count2) {
- return count1 < count2;
- }
- // ...and finally by identity hash code.
- return obj1->IdentityHashCode() < obj2->IdentityHashCode();
-}
-
-} // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 51d1376a3c..98e25eb320 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -210,6 +210,15 @@ class MANAGED Class FINAL : public Object {
return (GetAccessFlags() & kAccClassIsFinalizable) != 0;
}
+ ALWAYS_INLINE bool ShouldSkipHiddenApiChecks() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return (GetAccessFlags() & kAccSkipHiddenApiChecks) != 0;
+ }
+
+ ALWAYS_INLINE void SetSkipHiddenApiChecks() REQUIRES_SHARED(Locks::mutator_lock_) {
+ uint32_t flags = GetAccessFlags();
+ SetAccessFlags(flags | kAccSkipHiddenApiChecks);
+ }
+
ALWAYS_INLINE void SetRecursivelyInitialized() REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_EQ(GetLockOwnerThreadId(), Thread::Current()->GetThreadId());
uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
diff --git a/runtime/mirror/method_handles_lookup.cc b/runtime/mirror/method_handles_lookup.cc
index 039bbf2932..aeecf75c1f 100644
--- a/runtime/mirror/method_handles_lookup.cc
+++ b/runtime/mirror/method_handles_lookup.cc
@@ -20,7 +20,7 @@
#include "dex/modifiers.h"
#include "gc_root-inl.h"
#include "handle_scope.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/method_handle_impl.h"
#include "object-inl.h"
#include "well_known_classes.h"
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index a79c0a26d0..b309f596fd 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -22,7 +22,7 @@
#include "class_linker.h"
#include "gc_root-inl.h"
#include "intrinsics_enum.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "jvalue-inl.h"
#include "method_handles.h"
#include "method_type.h"
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 8320d9c7ba..cdba6b204f 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -35,7 +35,7 @@
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
#include "jit/debugger_interface.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
#include "mirror/string.h"
@@ -816,6 +816,28 @@ static jlong DexFile_getStaticSizeOfDexFile(JNIEnv* env, jclass, jobject cookie)
return static_cast<jlong>(file_size);
}
+static void DexFile_setTrusted(JNIEnv* env, jclass, jobject j_cookie) {
+ Runtime* runtime = Runtime::Current();
+ ScopedObjectAccess soa(env);
+
+ // Currently only allow this for debuggable apps.
+ if (!runtime->IsJavaDebuggable()) {
+ ThrowSecurityException("Can't exempt class, process is not debuggable.");
+ return;
+ }
+
+ std::vector<const DexFile*> dex_files;
+ const OatFile* oat_file;
+ if (!ConvertJavaArrayToDexFiles(env, j_cookie, dex_files, oat_file)) {
+ Thread::Current()->AssertPendingException();
+ return;
+ }
+
+ for (const DexFile* dex_file : dex_files) {
+ const_cast<DexFile*>(dex_file)->SetIsPlatformDexFile();
+ }
+}
+
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(DexFile, closeDexFile, "(Ljava/lang/Object;)Z"),
NATIVE_METHOD(DexFile,
@@ -854,7 +876,8 @@ static JNINativeMethod gMethods[] = {
"(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"),
NATIVE_METHOD(DexFile, getStaticSizeOfDexFile, "(Ljava/lang/Object;)J"),
NATIVE_METHOD(DexFile, getDexFileOptimizationStatus,
- "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;")
+ "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"),
+ NATIVE_METHOD(DexFile, setTrusted, "(Ljava/lang/Object;)V")
};
void register_dalvik_system_DexFile(JNIEnv* env) {
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index 3692a308d8..f1e267becc 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -35,8 +35,8 @@
#include "gc/space/zygote_space.h"
#include "handle_scope-inl.h"
#include "hprof/hprof.h"
-#include "java_vm_ext.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "mirror/class.h"
#include "mirror/object_array-inl.h"
#include "native_util.h"
@@ -588,6 +588,25 @@ static void VMDebug_nativeAttachAgent(JNIEnv* env, jclass, jstring agent, jobjec
Runtime::Current()->AttachAgent(env, filename, classloader);
}
+static void VMDebug_allowHiddenApiReflectionFrom(JNIEnv* env, jclass, jclass j_caller) {
+ Runtime* runtime = Runtime::Current();
+ ScopedObjectAccess soa(env);
+
+ if (!runtime->IsJavaDebuggable()) {
+ ThrowSecurityException("Can't exempt class, process is not debuggable.");
+ return;
+ }
+
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::Class> h_caller(hs.NewHandle(soa.Decode<mirror::Class>(j_caller)));
+ if (h_caller.IsNull()) {
+ ThrowNullPointerException("argument is null");
+ return;
+ }
+
+ h_caller->SetSkipHiddenApiChecks();
+}
+
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"),
NATIVE_METHOD(VMDebug, countInstancesOfClasses, "([Ljava/lang/Class;Z)[J"),
@@ -623,6 +642,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMDebug, getRuntimeStatInternal, "(I)Ljava/lang/String;"),
NATIVE_METHOD(VMDebug, getRuntimeStatsInternal, "()[Ljava/lang/String;"),
NATIVE_METHOD(VMDebug, nativeAttachAgent, "(Ljava/lang/String;Ljava/lang/ClassLoader;)V"),
+ NATIVE_METHOD(VMDebug, allowHiddenApiReflectionFrom, "(Ljava/lang/Class;)V"),
};
void register_dalvik_system_VMDebug(JNIEnv* env) {
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index a5ade6f30f..7f7b524227 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -41,8 +41,8 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version);
#include "gc/space/image_space.h"
#include "gc/task_processor.h"
#include "intern_table.h"
-#include "java_vm_ext.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
#include "mirror/object-inl.h"
@@ -93,6 +93,10 @@ static void VMRuntime_setHiddenApiExemptions(JNIEnv* env,
Runtime::Current()->SetHiddenApiExemptions(exemptions_vec);
}
+static void VMRuntime_setHiddenApiAccessLogSamplingRate(JNIEnv*, jclass, jint rate) {
+ Runtime::Current()->SetHiddenApiEventLogSampleRate(rate);
+}
+
static jobject VMRuntime_newNonMovableArray(JNIEnv* env, jobject, jclass javaElementClass,
jint length) {
ScopedFastNativeObjectAccess soa(env);
@@ -678,6 +682,12 @@ static void VMRuntime_setSystemDaemonThreadPriority(JNIEnv* env ATTRIBUTE_UNUSED
#endif
}
+static void VMRuntime_setDedupeHiddenApiWarnings(JNIEnv* env ATTRIBUTE_UNUSED,
+ jclass klass ATTRIBUTE_UNUSED,
+ jboolean dedupe) {
+ Runtime::Current()->SetDedupeHiddenApiWarnings(dedupe);
+}
+
static JNINativeMethod gMethods[] = {
FAST_NATIVE_METHOD(VMRuntime, addressOf, "(Ljava/lang/Object;)J"),
NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
@@ -688,6 +698,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMRuntime, disableJitCompilation, "()V"),
NATIVE_METHOD(VMRuntime, hasUsedHiddenApi, "()Z"),
NATIVE_METHOD(VMRuntime, setHiddenApiExemptions, "([Ljava/lang/String;)V"),
+ NATIVE_METHOD(VMRuntime, setHiddenApiAccessLogSamplingRate, "(I)V"),
NATIVE_METHOD(VMRuntime, getTargetHeapUtilization, "()F"),
FAST_NATIVE_METHOD(VMRuntime, isDebuggerActive, "()Z"),
FAST_NATIVE_METHOD(VMRuntime, isNativeDebuggable, "()Z"),
@@ -718,6 +729,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMRuntime, getCurrentInstructionSet, "()Ljava/lang/String;"),
NATIVE_METHOD(VMRuntime, didPruneDalvikCache, "()Z"),
NATIVE_METHOD(VMRuntime, setSystemDaemonThreadPriority, "()V"),
+ NATIVE_METHOD(VMRuntime, setDedupeHiddenApiWarnings, "(Z)V"),
};
void register_dalvik_system_VMRuntime(JNIEnv* env) {
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index ed0eb97da1..39192274ad 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -22,7 +22,7 @@
#include "art_method-inl.h"
#include "gc/task_processor.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index cf0a72a477..38c65f5deb 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -28,9 +28,9 @@
#include "base/runtime_debug.h"
#include "debugger.h"
#include "hidden_api.h"
-#include "java_vm_ext.h"
#include "jit/jit.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "native_util.h"
#include "nativehelper/jni_macros.h"
#include "nativehelper/scoped_utf_chars.h"
@@ -177,6 +177,7 @@ enum {
DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11,
HIDDEN_API_ENFORCEMENT_POLICY_MASK = (1 << 12)
| (1 << 13),
+ PROFILE_SYSTEM_SERVER = 1 << 14,
// bits to shift (flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) by to get a value
// corresponding to hiddenapi::EnforcementPolicy
@@ -308,6 +309,9 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
(runtime_flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT);
runtime_flags &= ~HIDDEN_API_ENFORCEMENT_POLICY_MASK;
+ bool profile_system_server = (runtime_flags & PROFILE_SYSTEM_SERVER) == PROFILE_SYSTEM_SERVER;
+ runtime_flags &= ~PROFILE_SYSTEM_SERVER;
+
if (runtime_flags != 0) {
LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags);
}
@@ -363,6 +367,13 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
<< "Child zygote processes should be forked with EnforcementPolicy::kDisable";
Runtime::Current()->SetHiddenApiEnforcementPolicy(api_enforcement_policy);
Runtime::Current()->SetDedupeHiddenApiWarnings(dedupe_hidden_api_warnings);
+ if (api_enforcement_policy != hiddenapi::EnforcementPolicy::kNoChecks &&
+ Runtime::Current()->GetHiddenApiEventLogSampleRate() != 0) {
+ // Hidden API checks are enabled, and we are sampling access for the event log. Initialize the
+ // random seed, to ensure the sampling is actually random. We do this post-fork, as doing it
+ // pre-fork would result in the same sequence for every forked process.
+ std::srand(static_cast<uint32_t>(NanoTime()));
+ }
// Clear the hidden API warning flag, in case it was set.
Runtime::Current()->SetPendingHiddenApiWarning(false);
@@ -385,7 +396,11 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
env, is_system_server, action, isa_string.c_str());
} else {
Runtime::Current()->InitNonZygoteOrPostFork(
- env, is_system_server, Runtime::NativeBridgeAction::kUnload, nullptr);
+ env,
+ is_system_server,
+ Runtime::NativeBridgeAction::kUnload,
+ /*isa*/ nullptr,
+ profile_system_server);
}
}
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index bfd7f69cef..68024cd1c2 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -28,7 +28,7 @@
#include "dex/dex_file_annotations.h"
#include "dex/utf.h"
#include "hidden_api.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/field-inl.h"
@@ -52,7 +52,7 @@ namespace art {
// Returns true if the first caller outside of the Class class or java.lang.invoke package
// is in a platform DEX file.
-static bool IsCallerInPlatformDex(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
+static bool IsCallerTrusted(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
// Walk the stack and find the first frame not from java.lang.Class and not from java.lang.invoke.
// This is very expensive. Save this till the last.
struct FirstExternalCallerVisitor : public StackVisitor {
@@ -99,7 +99,7 @@ static bool IsCallerInPlatformDex(Thread* self) REQUIRES_SHARED(Locks::mutator_l
FirstExternalCallerVisitor visitor(self);
visitor.WalkStack();
return visitor.caller != nullptr &&
- hiddenapi::IsCallerInPlatformDex(visitor.caller->GetDeclaringClass());
+ hiddenapi::IsCallerTrusted(visitor.caller->GetDeclaringClass());
}
// Returns true if the first non-ClassClass caller up the stack is not allowed to
@@ -107,7 +107,7 @@ static bool IsCallerInPlatformDex(Thread* self) REQUIRES_SHARED(Locks::mutator_l
ALWAYS_INLINE static bool ShouldEnforceHiddenApi(Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
hiddenapi::EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
- return policy != hiddenapi::EnforcementPolicy::kNoChecks && !IsCallerInPlatformDex(self);
+ return policy != hiddenapi::EnforcementPolicy::kNoChecks && !IsCallerTrusted(self);
}
// Returns true if the first non-ClassClass caller up the stack should not be
@@ -116,7 +116,7 @@ template<typename T>
ALWAYS_INLINE static bool ShouldBlockAccessToMember(T* member, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
hiddenapi::Action action = hiddenapi::GetMemberAction(
- member, self, IsCallerInPlatformDex, hiddenapi::kReflection);
+ member, self, IsCallerTrusted, hiddenapi::kReflection);
if (action != hiddenapi::kAllow) {
hiddenapi::NotifyHiddenApiListener(member);
}
@@ -128,19 +128,20 @@ ALWAYS_INLINE static bool ShouldBlockAccessToMember(T* member, Thread* self)
// the criteria. Some reflection calls only return public members
// (public_only == true), some members should be hidden from non-boot class path
// callers (enforce_hidden_api == true).
+template<typename T>
ALWAYS_INLINE static bool IsDiscoverable(bool public_only,
bool enforce_hidden_api,
- uint32_t access_flags) {
- if (public_only && ((access_flags & kAccPublic) == 0)) {
- return false;
- }
-
- if (enforce_hidden_api &&
- hiddenapi::GetActionFromAccessFlags(access_flags) == hiddenapi::kDeny) {
+ T* member)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (public_only && ((member->GetAccessFlags() & kAccPublic) == 0)) {
return false;
}
- return true;
+ return hiddenapi::GetMemberAction(member,
+ nullptr,
+ [enforce_hidden_api] (Thread*) { return !enforce_hidden_api; },
+ hiddenapi::kNone)
+ != hiddenapi::kDeny;
}
ALWAYS_INLINE static inline ObjPtr<mirror::Class> DecodeClass(
@@ -269,12 +270,12 @@ static mirror::ObjectArray<mirror::Field>* GetDeclaredFields(
bool enforce_hidden_api = ShouldEnforceHiddenApi(self);
// Lets go subtract all the non discoverable fields.
for (ArtField& field : ifields) {
- if (!IsDiscoverable(public_only, enforce_hidden_api, field.GetAccessFlags())) {
+ if (!IsDiscoverable(public_only, enforce_hidden_api, &field)) {
--array_size;
}
}
for (ArtField& field : sfields) {
- if (!IsDiscoverable(public_only, enforce_hidden_api, field.GetAccessFlags())) {
+ if (!IsDiscoverable(public_only, enforce_hidden_api, &field)) {
--array_size;
}
}
@@ -285,7 +286,7 @@ static mirror::ObjectArray<mirror::Field>* GetDeclaredFields(
return nullptr;
}
for (ArtField& field : ifields) {
- if (IsDiscoverable(public_only, enforce_hidden_api, field.GetAccessFlags())) {
+ if (IsDiscoverable(public_only, enforce_hidden_api, &field)) {
auto* reflect_field = mirror::Field::CreateFromArtField<kRuntimePointerSize>(self,
&field,
force_resolve);
@@ -300,7 +301,7 @@ static mirror::ObjectArray<mirror::Field>* GetDeclaredFields(
}
}
for (ArtField& field : sfields) {
- if (IsDiscoverable(public_only, enforce_hidden_api, field.GetAccessFlags())) {
+ if (IsDiscoverable(public_only, enforce_hidden_api, &field)) {
auto* reflect_field = mirror::Field::CreateFromArtField<kRuntimePointerSize>(self,
&field,
force_resolve);
@@ -521,7 +522,7 @@ static ALWAYS_INLINE inline bool MethodMatchesConstructor(
DCHECK(m != nullptr);
return m->IsConstructor() &&
!m->IsStatic() &&
- IsDiscoverable(public_only, enforce_hidden_api, m->GetAccessFlags());
+ IsDiscoverable(public_only, enforce_hidden_api, m);
}
static jobjectArray Class_getDeclaredConstructorsInternal(
@@ -591,7 +592,7 @@ static jobjectArray Class_getDeclaredMethodsUnchecked(JNIEnv* env, jobject javaT
uint32_t modifiers = m.GetAccessFlags();
// Add non-constructor declared methods.
if ((modifiers & kAccConstructor) == 0 &&
- IsDiscoverable(public_only, enforce_hidden_api, modifiers)) {
+ IsDiscoverable(public_only, enforce_hidden_api, &m)) {
++num_methods;
}
}
@@ -605,7 +606,7 @@ static jobjectArray Class_getDeclaredMethodsUnchecked(JNIEnv* env, jobject javaT
for (ArtMethod& m : klass->GetDeclaredMethods(kRuntimePointerSize)) {
uint32_t modifiers = m.GetAccessFlags();
if ((modifiers & kAccConstructor) == 0 &&
- IsDiscoverable(public_only, enforce_hidden_api, modifiers)) {
+ IsDiscoverable(public_only, enforce_hidden_api, &m)) {
DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
DCHECK(!Runtime::Current()->IsActiveTransaction());
auto* method =
diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc
index d52bf0490b..208ccf6a82 100644
--- a/runtime/native/java_lang_Object.cc
+++ b/runtime/native/java_lang_Object.cc
@@ -18,7 +18,7 @@
#include "nativehelper/jni_macros.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/object-inl.h"
#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
index b5aea7ca7c..8976058b53 100644
--- a/runtime/native/java_lang_String.cc
+++ b/runtime/native/java_lang_String.cc
@@ -19,7 +19,7 @@
#include "nativehelper/jni_macros.h"
#include "common_throws.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/array.h"
#include "mirror/object-inl.h"
#include "mirror/string-inl.h"
diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc
index 136a02f8f6..07e875efcb 100644
--- a/runtime/native/java_lang_StringFactory.cc
+++ b/runtime/native/java_lang_StringFactory.cc
@@ -17,7 +17,7 @@
#include "java_lang_StringFactory.h"
#include "common_throws.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/object-inl.h"
#include "mirror/string.h"
#include "native_util.h"
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
index 390f026588..2c4184c285 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -20,7 +20,7 @@
#include "common_throws.h"
#include "gc/accounting/card_table-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/array.h"
#include "mirror/class-inl.h"
#include "mirror/class.h"
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index 9a52f7002b..9edb0c21dd 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -17,7 +17,7 @@
#include "java_lang_Thread.h"
#include "common_throws.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/object.h"
#include "monitor.h"
#include "native_util.h"
diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc
index 03b7f9dfba..b5ef7d807b 100644
--- a/runtime/native/java_lang_Throwable.cc
+++ b/runtime/native/java_lang_Throwable.cc
@@ -18,7 +18,7 @@
#include "nativehelper/jni_macros.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
#include "thread.h"
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 44585fc453..0630737d29 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -20,7 +20,7 @@
#include "class_linker.h"
#include "dex/descriptors_names.h"
#include "dex/dex_file_loader.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
#include "native_util.h"
diff --git a/runtime/native/java_lang_invoke_MethodHandleImpl.cc b/runtime/native/java_lang_invoke_MethodHandleImpl.cc
index 2e3b4d41ef..1f2bf09f0e 100644
--- a/runtime/native/java_lang_invoke_MethodHandleImpl.cc
+++ b/runtime/native/java_lang_invoke_MethodHandleImpl.cc
@@ -20,7 +20,7 @@
#include "art_method.h"
#include "handle_scope-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/field.h"
#include "mirror/method.h"
#include "mirror/method_handle_impl.h"
diff --git a/runtime/native/java_lang_ref_FinalizerReference.cc b/runtime/native/java_lang_ref_FinalizerReference.cc
index 72af5f7ea7..c89188c99c 100644
--- a/runtime/native/java_lang_ref_FinalizerReference.cc
+++ b/runtime/native/java_lang_ref_FinalizerReference.cc
@@ -20,7 +20,7 @@
#include "gc/heap.h"
#include "gc/reference_processor.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/object-inl.h"
#include "mirror/reference-inl.h"
#include "native_util.h"
diff --git a/runtime/native/java_lang_ref_Reference.cc b/runtime/native/java_lang_ref_Reference.cc
index 524a18ca20..fc018d15c4 100644
--- a/runtime/native/java_lang_ref_Reference.cc
+++ b/runtime/native/java_lang_ref_Reference.cc
@@ -20,7 +20,7 @@
#include "gc/heap.h"
#include "gc/reference_processor.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/object-inl.h"
#include "mirror/reference-inl.h"
#include "native_util.h"
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
index d28f74158e..8bcda10f2a 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -22,7 +22,7 @@
#include "common_throws.h"
#include "dex/dex_file-inl.h"
#include "handle_scope-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "native_util.h"
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index 86124388bc..a5d6c9704d 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -23,7 +23,7 @@
#include "class_linker-inl.h"
#include "class_linker.h"
#include "dex/dex_file_annotations.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/method.h"
#include "mirror/object-inl.h"
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index b129c66759..9a2d3020c0 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -22,7 +22,7 @@
#include "art_method-inl.h"
#include "dex/dex_file_annotations.h"
#include "handle.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/method.h"
#include "mirror/object-inl.h"
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 13275d92e4..e0afbee845 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -26,7 +26,7 @@
#include "common_throws.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_annotations.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/field-inl.h"
#include "native_util.h"
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index 4355c06acd..2503b3cb44 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -23,7 +23,7 @@
#include "class_linker-inl.h"
#include "class_linker.h"
#include "dex/dex_file_annotations.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc
index b80b20cd8d..263a56796f 100644
--- a/runtime/native/java_lang_reflect_Parameter.cc
+++ b/runtime/native/java_lang_reflect_Parameter.cc
@@ -24,7 +24,7 @@
#include "common_throws.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_annotations.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
index 691ed28b0b..f723ed223d 100644
--- a/runtime/native/java_lang_reflect_Proxy.cc
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -19,7 +19,7 @@
#include "nativehelper/jni_macros.h"
#include "class_linker.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object_array.h"
#include "mirror/string.h"
diff --git a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
index c0032975ce..fa288edcb8 100644
--- a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
+++ b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
@@ -21,7 +21,7 @@
#include "arch/instruction_set.h"
#include "base/atomic.h"
#include "base/quasi_atomic.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "native_util.h"
namespace art {
diff --git a/runtime/native/libcore_util_CharsetUtils.cc b/runtime/native/libcore_util_CharsetUtils.cc
index f3aba2575b..24298049ee 100644
--- a/runtime/native/libcore_util_CharsetUtils.cc
+++ b/runtime/native/libcore_util_CharsetUtils.cc
@@ -18,7 +18,7 @@
#include <string.h>
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/string-inl.h"
#include "mirror/string.h"
#include "native_util.h"
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
index 8f8fd71727..419aed8578 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
@@ -20,7 +20,7 @@
#include "base/array_ref.h"
#include "debugger.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "native_util.h"
#include "nativehelper/jni_macros.h"
#include "nativehelper/scoped_primitive_array.h"
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index fbee7b31a3..028675d448 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -22,7 +22,7 @@
#include "base/mutex.h"
#include "debugger.h"
#include "gc/heap.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "native_util.h"
#include "nativehelper/jni_macros.h"
#include "nativehelper/scoped_local_ref.h"
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index fb00ae3967..d41a19556e 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -27,7 +27,7 @@
#include "base/quasi_atomic.h"
#include "common_throws.h"
#include "gc/accounting/card_table-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/array.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
index 7d72805dc6..def48e8be9 100644
--- a/runtime/native_bridge_art_interface.cc
+++ b/runtime/native_bridge_art_interface.cc
@@ -25,7 +25,7 @@
#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "dex/dex_file-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "scoped_thread_state_change-inl.h"
#include "sigchain.h"
diff --git a/runtime/non_debuggable_classes.cc b/runtime/non_debuggable_classes.cc
index 8484e2cde7..f42a2d6755 100644
--- a/runtime/non_debuggable_classes.cc
+++ b/runtime/non_debuggable_classes.cc
@@ -16,7 +16,7 @@
#include "non_debuggable_classes.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "nativehelper/scoped_local_ref.h"
#include "obj_ptr-inl.h"
diff --git a/runtime/oat.h b/runtime/oat.h
index 0318606f87..6c683f1541 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@ class InstructionSetFeatures;
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- // Last oat version changed reason: Use rMR as temp in Baker RB introspection marking.
- static constexpr uint8_t kOatVersion[] = { '1', '4', '1', '\0' };
+ // Last oat version changed reason: compiler support const-method-handle
+ static constexpr uint8_t kOatVersion[] = { '1', '4', '3', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 9c8b6512a7..241102ea83 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -1217,7 +1217,9 @@ bool OatFileAssistant::OatFileInfo::ClassLoaderContextIsOkay(ClassLoaderContext*
return false;
}
- bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext());
+
+ bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext()) ==
+ ClassLoaderContext::VerificationResult::kVerifies;
if (!result) {
VLOG(oat) << "ClassLoaderContext check failed. Context was "
<< file->GetClassLoaderContext()
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index f6fb9ded87..59a1045ba2 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -38,7 +38,7 @@
#include "gc/scoped_gc_critical_section.h"
#include "gc/space/image_space.h"
#include "handle_scope-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
#include "oat_file.h"
@@ -276,9 +276,19 @@ static void AddNext(/*inout*/DexFileAndClassPair& original,
}
}
-static bool CollisionCheck(std::vector<const DexFile*>& dex_files_loaded,
- std::vector<const DexFile*>& dex_files_unloaded,
- std::string* error_msg /*out*/) {
+static bool CheckClassCollision(const OatFile* oat_file,
+ const ClassLoaderContext* context,
+ std::string* error_msg /*out*/) {
+ std::vector<const DexFile*> dex_files_loaded = context->FlattenOpenedDexFiles();
+
+ // Vector that holds the newly opened dex files live, this is done to prevent leaks.
+ std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
+
+ ScopedTrace st("Collision check");
+ // Add dex files from the oat file to check.
+ std::vector<const DexFile*> dex_files_unloaded;
+ AddDexFilesFromOat(oat_file, &dex_files_unloaded, &opened_dex_files);
+
// Generate type index information for each dex file.
std::vector<TypeIndexInfo> loaded_types;
for (const DexFile* dex_file : dex_files_loaded) {
@@ -355,9 +365,10 @@ static bool CollisionCheck(std::vector<const DexFile*>& dex_files_loaded,
// against the following top element. If the descriptor is the same, it is now checked whether
// the two elements agree on whether their dex file was from an already-loaded oat-file or the
// new oat file. Any disagreement indicates a collision.
-bool OatFileManager::HasCollisions(const OatFile* oat_file,
- const ClassLoaderContext* context,
- std::string* error_msg /*out*/) const {
+OatFileManager::CheckCollisionResult OatFileManager::CheckCollision(
+ const OatFile* oat_file,
+ const ClassLoaderContext* context,
+ /*out*/ std::string* error_msg) const {
DCHECK(oat_file != nullptr);
DCHECK(error_msg != nullptr);
@@ -367,28 +378,59 @@ bool OatFileManager::HasCollisions(const OatFile* oat_file,
// Note that this has correctness implications as we cannot guarantee that the class resolution
// used during compilation is OK (b/37777332).
if (context == nullptr) {
- LOG(WARNING) << "Skipping duplicate class check due to unsupported classloader";
- return false;
+ LOG(WARNING) << "Skipping duplicate class check due to unsupported classloader";
+ return CheckCollisionResult::kSkippedUnsupportedClassLoader;
}
- // If the pat file loading context matches the context used during compilation then we accept
+ // If the oat file loading context matches the context used during compilation then we accept
// the oat file without addition checks
- if (context->VerifyClassLoaderContextMatch(oat_file->GetClassLoaderContext())) {
- return false;
+ ClassLoaderContext::VerificationResult result = context->VerifyClassLoaderContextMatch(
+ oat_file->GetClassLoaderContext(),
+ /*verify_names*/ true,
+ /*verify_checksums*/ true);
+ switch (result) {
+ case ClassLoaderContext::VerificationResult::kForcedToSkipChecks:
+ return CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary;
+ case ClassLoaderContext::VerificationResult::kMismatch:
+ // Mismatched context, do the actual collision check.
+ break;
+ case ClassLoaderContext::VerificationResult::kVerifies:
+ return CheckCollisionResult::kNoCollisions;
}
// The class loader context does not match. Perform a full duplicate classes check.
+ return CheckClassCollision(oat_file, context, error_msg)
+ ? CheckCollisionResult::kPerformedHasCollisions : CheckCollisionResult::kNoCollisions;
+}
- std::vector<const DexFile*> dex_files_loaded = context->FlattenOpenedDexFiles();
-
- // Vector that holds the newly opened dex files live, this is done to prevent leaks.
- std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
+bool OatFileManager::AcceptOatFile(CheckCollisionResult result) const {
+ // Take the file only if it has no collisions, or we must take it because of preopting.
+ // Also accept oat files for shared libraries and unsupported class loaders.
+ return result != CheckCollisionResult::kPerformedHasCollisions;
+}
- ScopedTrace st("Collision check");
- // Add dex files from the oat file to check.
- std::vector<const DexFile*> dex_files_unloaded;
- AddDexFilesFromOat(oat_file, &dex_files_unloaded, &opened_dex_files);
- return CollisionCheck(dex_files_loaded, dex_files_unloaded, error_msg);
+bool OatFileManager::ShouldLoadAppImage(CheckCollisionResult check_collision_result,
+ const OatFile* source_oat_file,
+ ClassLoaderContext* context,
+ std::string* error_msg) {
+ Runtime* const runtime = Runtime::Current();
+ if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) {
+ // If we verified the class loader context (skipping due to the special marker doesn't
+ // count), then also avoid the collision check.
+ bool load_image = check_collision_result == CheckCollisionResult::kNoCollisions;
+ // If we skipped the collision check, we need to reverify to be sure its OK to load the
+ // image.
+ if (!load_image &&
+ check_collision_result ==
+ CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary) {
+ // We can load the app image only if there are no collisions. If we know the
+ // class loader but didn't do the full collision check in HasCollisions(),
+ // do it now. b/77342775
+ load_image = !CheckClassCollision(source_oat_file, context, error_msg);
+ }
+ return load_image;
+ }
+ return false;
}
std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
@@ -473,16 +515,17 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
<< reinterpret_cast<uintptr_t>(oat_file.get())
<< " (executable=" << (oat_file != nullptr ? oat_file->IsExecutable() : false) << ")";
+ CheckCollisionResult check_collision_result = CheckCollisionResult::kPerformedHasCollisions;
if ((class_loader != nullptr || dex_elements != nullptr) && oat_file != nullptr) {
// Prevent oat files from being loaded if no class_loader or dex_elements are provided.
// This can happen when the deprecated DexFile.<init>(String) is called directly, and it
// could load oat files without checking the classpath, which would be incorrect.
// Take the file only if it has no collisions, or we must take it because of preopting.
- bool accept_oat_file =
- !HasCollisions(oat_file.get(), context.get(), /*out*/ &error_msg);
+ check_collision_result = CheckCollision(oat_file.get(), context.get(), /*out*/ &error_msg);
+ bool accept_oat_file = AcceptOatFile(check_collision_result);
if (!accept_oat_file) {
// Failed the collision check. Print warning.
- if (Runtime::Current()->IsDexFileFallbackEnabled()) {
+ if (runtime->IsDexFileFallbackEnabled()) {
if (!oat_file_assistant.HasOriginalDexFiles()) {
// We need to fallback but don't have original dex files. We have to
// fallback to opening the existing oat file. This is potentially
@@ -529,10 +572,11 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
// We need to throw away the image space if we are debuggable but the oat-file source of the
// image is not otherwise we might get classes with inlined methods or other such things.
std::unique_ptr<gc::space::ImageSpace> image_space;
- if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) {
+ if (ShouldLoadAppImage(check_collision_result,
+ source_oat_file,
+ context.get(),
+ &error_msg)) {
image_space = oat_file_assistant.OpenImageSpace(source_oat_file);
- } else {
- image_space = nullptr;
}
if (image_space != nullptr) {
ScopedObjectAccess soa(self);
diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h
index 038474e31f..80456e9b75 100644
--- a/runtime/oat_file_manager.h
+++ b/runtime/oat_file_manager.h
@@ -108,23 +108,39 @@ class OatFileManager {
void SetOnlyUseSystemOatFiles();
private:
+ enum class CheckCollisionResult {
+ kSkippedUnsupportedClassLoader,
+ kSkippedClassLoaderContextSharedLibrary,
+ kNoCollisions,
+ kPerformedHasCollisions,
+ };
+
// Check that the class loader context of the given oat file matches the given context.
// This will perform a check that all class loaders in the chain have the same type and
// classpath.
// If the context is null (which means the initial class loader was null or unsupported)
- // this returns false.
+ // this returns kSkippedUnsupportedClassLoader.
// If the context does not validate the method will check for duplicate class definitions of
// the given oat file against the oat files (either from the class loaders if possible or all
// non-boot oat files otherwise).
- // Return true if there are any class definition collisions in the oat_file.
- bool HasCollisions(const OatFile* oat_file,
- const ClassLoaderContext* context,
- /*out*/ std::string* error_msg) const
+ // Return kPerformedHasCollisions if there are any class definition collisions in the oat_file.
+ CheckCollisionResult CheckCollision(const OatFile* oat_file,
+ const ClassLoaderContext* context,
+ /*out*/ std::string* error_msg) const
REQUIRES(!Locks::oat_file_manager_lock_);
const OatFile* FindOpenedOatFileFromOatLocationLocked(const std::string& oat_location) const
REQUIRES(Locks::oat_file_manager_lock_);
+ // Return true if we should accept the oat file.
+ bool AcceptOatFile(CheckCollisionResult result) const;
+
+ // Return true if we should attempt to load the app image.
+ bool ShouldLoadAppImage(CheckCollisionResult check_collision_result,
+ const OatFile* source_oat_file,
+ ClassLoaderContext* context,
+ std::string* error_msg);
+
std::set<std::unique_ptr<const OatFile>> oat_files_ GUARDED_BY(Locks::oat_file_manager_lock_);
bool have_non_pic_oat_file_;
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 5518eb2c49..3aa481af8c 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -252,12 +252,6 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize
.Define("-Xstackdumplockprofthreshold:_")
.WithType<unsigned int>()
.IntoKey(M::StackDumpLockProfThreshold)
- .Define("-Xusetombstonedtraces")
- .WithValue(true)
- .IntoKey(M::UseTombstonedTraces)
- .Define("-Xstacktracefile:_")
- .WithType<std::string>()
- .IntoKey(M::StackTraceFile)
.Define("-Xmethod-trace")
.IntoKey(M::MethodTrace)
.Define("-Xmethod-trace-file:_")
@@ -699,7 +693,6 @@ void ParsedOptions::Usage(const char* fmt, ...) {
UsageMessage(stream, "The following Dalvik options are supported:\n");
UsageMessage(stream, " -Xzygote\n");
UsageMessage(stream, " -Xjnitrace:substring (eg NativeClass or nativeMethod)\n");
- UsageMessage(stream, " -Xstacktracefile:<filename>\n");
UsageMessage(stream, " -Xgc:[no]preverify\n");
UsageMessage(stream, " -Xgc:[no]postverify\n");
UsageMessage(stream, " -XX:HeapGrowthLimit=N\n");
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index 3ad3a4b6a9..4e0bf890db 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -18,97 +18,16 @@
#include <vector>
#include "art_field-inl.h"
-#include "art_method-inl.h"
#include "base/enums.h"
-#include "class_linker-inl.h"
#include "common_compiler_test.h"
-#include "mirror/class-inl.h"
#include "mirror/field-inl.h"
-#include "mirror/method.h"
+#include "proxy_test.h"
#include "scoped_thread_state_change-inl.h"
namespace art {
+namespace proxy_test {
-class ProxyTest : public CommonCompilerTest {
- public:
- // Generate a proxy class with the given name and interfaces. This is a simplification from what
- // libcore does to fit to our test needs. We do not check for duplicated interfaces or methods and
- // we do not declare exceptions.
- mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa, jobject jclass_loader,
- const char* className,
- const std::vector<mirror::Class*>& interfaces)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Class* javaLangObject = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
- CHECK(javaLangObject != nullptr);
-
- jclass javaLangClass = soa.AddLocalReference<jclass>(mirror::Class::GetJavaLangClass());
-
- // Builds the interfaces array.
- jobjectArray proxyClassInterfaces = soa.Env()->NewObjectArray(interfaces.size(), javaLangClass,
- nullptr);
- soa.Self()->AssertNoPendingException();
- for (size_t i = 0; i < interfaces.size(); ++i) {
- soa.Env()->SetObjectArrayElement(proxyClassInterfaces, i,
- soa.AddLocalReference<jclass>(interfaces[i]));
- }
-
- // Builds the method array.
- jsize methods_count = 3; // Object.equals, Object.hashCode and Object.toString.
- for (mirror::Class* interface : interfaces) {
- methods_count += interface->NumVirtualMethods();
- }
- jobjectArray proxyClassMethods = soa.Env()->NewObjectArray(
- methods_count, soa.AddLocalReference<jclass>(mirror::Method::StaticClass()), nullptr);
- soa.Self()->AssertNoPendingException();
-
- jsize array_index = 0;
- // Fill the method array
- DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
- ArtMethod* method = javaLangObject->FindClassMethod(
- "equals", "(Ljava/lang/Object;)Z", kRuntimePointerSize);
- CHECK(method != nullptr);
- CHECK(!method->IsDirect());
- CHECK(method->GetDeclaringClass() == javaLangObject);
- DCHECK(!Runtime::Current()->IsActiveTransaction());
- soa.Env()->SetObjectArrayElement(
- proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
- mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
- method = javaLangObject->FindClassMethod("hashCode", "()I", kRuntimePointerSize);
- CHECK(method != nullptr);
- CHECK(!method->IsDirect());
- CHECK(method->GetDeclaringClass() == javaLangObject);
- soa.Env()->SetObjectArrayElement(
- proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
- mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
- method = javaLangObject->FindClassMethod(
- "toString", "()Ljava/lang/String;", kRuntimePointerSize);
- CHECK(method != nullptr);
- CHECK(!method->IsDirect());
- CHECK(method->GetDeclaringClass() == javaLangObject);
- soa.Env()->SetObjectArrayElement(
- proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
- mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
- // Now adds all interfaces virtual methods.
- for (mirror::Class* interface : interfaces) {
- for (auto& m : interface->GetDeclaredVirtualMethods(kRuntimePointerSize)) {
- soa.Env()->SetObjectArrayElement(
- proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
- mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), &m)));
- }
- }
- CHECK_EQ(array_index, methods_count);
-
- // Builds an empty exception array.
- jobjectArray proxyClassThrows = soa.Env()->NewObjectArray(0, javaLangClass, nullptr);
- soa.Self()->AssertNoPendingException();
-
- mirror::Class* proxyClass = class_linker_->CreateProxyClass(
- soa, soa.Env()->NewStringUTF(className), proxyClassInterfaces, jclass_loader,
- proxyClassMethods, proxyClassThrows);
- soa.Self()->AssertNoPendingException();
- return proxyClass;
- }
-};
+class ProxyTest : public CommonRuntimeTest {};
// Creates a proxy class and check ClassHelper works correctly.
TEST_F(ProxyTest, ProxyClassHelper) {
@@ -129,7 +48,7 @@ TEST_F(ProxyTest, ProxyClassHelper) {
interfaces.push_back(I.Get());
interfaces.push_back(J.Get());
Handle<mirror::Class> proxy_class(hs.NewHandle(
- GenerateProxyClass(soa, jclass_loader, "$Proxy1234", interfaces)));
+ GenerateProxyClass(soa, jclass_loader, class_linker_, "$Proxy1234", interfaces)));
interfaces.clear(); // Don't least possibly stale objects in the array as good practice.
ASSERT_TRUE(proxy_class != nullptr);
ASSERT_TRUE(proxy_class->IsProxyClass());
@@ -164,7 +83,8 @@ TEST_F(ProxyTest, ProxyFieldHelper) {
std::vector<mirror::Class*> interfaces;
interfaces.push_back(I.Get());
interfaces.push_back(J.Get());
- proxyClass = hs.NewHandle(GenerateProxyClass(soa, jclass_loader, "$Proxy1234", interfaces));
+ proxyClass = hs.NewHandle(
+ GenerateProxyClass(soa, jclass_loader, class_linker_, "$Proxy1234", interfaces));
}
ASSERT_TRUE(proxyClass != nullptr);
@@ -212,8 +132,10 @@ TEST_F(ProxyTest, CheckArtMirrorFieldsOfProxyStaticFields) {
Handle<mirror::Class> proxyClass1;
{
std::vector<mirror::Class*> interfaces;
- proxyClass0 = hs.NewHandle(GenerateProxyClass(soa, jclass_loader, "$Proxy0", interfaces));
- proxyClass1 = hs.NewHandle(GenerateProxyClass(soa, jclass_loader, "$Proxy1", interfaces));
+ proxyClass0 = hs.NewHandle(
+ GenerateProxyClass(soa, jclass_loader, class_linker_, "$Proxy0", interfaces));
+ proxyClass1 = hs.NewHandle(
+ GenerateProxyClass(soa, jclass_loader, class_linker_, "$Proxy1", interfaces));
}
ASSERT_TRUE(proxyClass0 != nullptr);
@@ -255,4 +177,5 @@ TEST_F(ProxyTest, CheckArtMirrorFieldsOfProxyStaticFields) {
EXPECT_EQ(field11->GetArtField(), &static_fields1->At(1));
}
+} // namespace proxy_test
} // namespace art
diff --git a/runtime/proxy_test.h b/runtime/proxy_test.h
new file mode 100644
index 0000000000..b559823257
--- /dev/null
+++ b/runtime/proxy_test.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_PROXY_TEST_H_
+#define ART_RUNTIME_PROXY_TEST_H_
+
+#include <jni.h>
+#include <vector>
+
+#include "art_method-inl.h"
+#include "class_linker-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/method.h"
+
+namespace art {
+namespace proxy_test {
+
+// Generate a proxy class with the given name and interfaces. This is a simplification from what
+// libcore does to fit to our test needs. We do not check for duplicated interfaces or methods and
+// we do not declare exceptions.
+mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa,
+ jobject jclass_loader,
+ ClassLinker* class_linker,
+ const char* className,
+ const std::vector<mirror::Class*>& interfaces)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ mirror::Class* javaLangObject = class_linker->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
+ CHECK(javaLangObject != nullptr);
+
+ jclass javaLangClass = soa.AddLocalReference<jclass>(mirror::Class::GetJavaLangClass());
+
+ // Builds the interfaces array.
+ jobjectArray proxyClassInterfaces = soa.Env()->NewObjectArray(interfaces.size(), javaLangClass,
+ nullptr);
+ soa.Self()->AssertNoPendingException();
+ for (size_t i = 0; i < interfaces.size(); ++i) {
+ soa.Env()->SetObjectArrayElement(proxyClassInterfaces, i,
+ soa.AddLocalReference<jclass>(interfaces[i]));
+ }
+
+ // Builds the method array.
+ jsize methods_count = 3; // Object.equals, Object.hashCode and Object.toString.
+ for (mirror::Class* interface : interfaces) {
+ methods_count += interface->NumVirtualMethods();
+ }
+ jobjectArray proxyClassMethods = soa.Env()->NewObjectArray(
+ methods_count, soa.AddLocalReference<jclass>(mirror::Method::StaticClass()), nullptr);
+ soa.Self()->AssertNoPendingException();
+
+ jsize array_index = 0;
+ // Fill the method array
+ DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
+ ArtMethod* method = javaLangObject->FindClassMethod(
+ "equals", "(Ljava/lang/Object;)Z", kRuntimePointerSize);
+ CHECK(method != nullptr);
+ CHECK(!method->IsDirect());
+ CHECK(method->GetDeclaringClass() == javaLangObject);
+ DCHECK(!Runtime::Current()->IsActiveTransaction());
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
+ method = javaLangObject->FindClassMethod("hashCode", "()I", kRuntimePointerSize);
+ CHECK(method != nullptr);
+ CHECK(!method->IsDirect());
+ CHECK(method->GetDeclaringClass() == javaLangObject);
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
+ method = javaLangObject->FindClassMethod(
+ "toString", "()Ljava/lang/String;", kRuntimePointerSize);
+ CHECK(method != nullptr);
+ CHECK(!method->IsDirect());
+ CHECK(method->GetDeclaringClass() == javaLangObject);
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
+ // Now adds all interfaces virtual methods.
+ for (mirror::Class* interface : interfaces) {
+ for (auto& m : interface->GetDeclaredVirtualMethods(kRuntimePointerSize)) {
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), &m)));
+ }
+ }
+ CHECK_EQ(array_index, methods_count);
+
+ // Builds an empty exception array.
+ jobjectArray proxyClassThrows = soa.Env()->NewObjectArray(0, javaLangClass, nullptr);
+ soa.Self()->AssertNoPendingException();
+
+ mirror::Class* proxyClass = class_linker->CreateProxyClass(
+ soa, soa.Env()->NewStringUTF(className), proxyClassInterfaces, jclass_loader,
+ proxyClassMethods, proxyClassThrows);
+ soa.Self()->AssertNoPendingException();
+ return proxyClass;
+}
+
+} // namespace proxy_test
+} // namespace art
+
+#endif // ART_RUNTIME_PROXY_TEST_H_
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 068bc285e5..dfa4b3daab 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -23,8 +23,8 @@
#include "common_throws.h"
#include "dex/dex_file-inl.h"
#include "indirect_reference_table-inl.h"
-#include "java_vm_ext.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/executable.h"
#include "mirror/object_array-inl.h"
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 7b36c7368e..d2d720f722 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -23,8 +23,8 @@
#include "base/enums.h"
#include "common_compiler_test.h"
#include "dex/descriptors_names.h"
-#include "java_vm_ext.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "nativehelper/scoped_local_ref.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index d12a976be8..b8775b874f 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -93,11 +93,11 @@
#include "instrumentation.h"
#include "intern_table.h"
#include "interpreter/interpreter.h"
-#include "java_vm_ext.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
#include "jit/profile_saver.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "linear_alloc.h"
#include "memory_representation.h"
#include "mirror/array.h"
@@ -232,7 +232,6 @@ Runtime::Runtime()
intern_table_(nullptr),
class_linker_(nullptr),
signal_catcher_(nullptr),
- use_tombstoned_traces_(false),
java_vm_(nullptr),
fault_message_lock_("Fault message lock"),
fault_message_(""),
@@ -274,6 +273,7 @@ Runtime::Runtime()
pending_hidden_api_warning_(false),
dedupe_hidden_api_warnings_(true),
always_set_hidden_api_warning_flag_(false),
+ hidden_api_access_event_log_rate_(0),
dump_native_stack_on_sig_quit_(true),
pruned_dalvik_cache_(false),
// Initially assume we perceive jank in case the process state is never updated.
@@ -861,7 +861,11 @@ void Runtime::EndThreadBirth() REQUIRES(Locks::runtime_shutdown_lock_) {
}
void Runtime::InitNonZygoteOrPostFork(
- JNIEnv* env, bool is_system_server, NativeBridgeAction action, const char* isa) {
+ JNIEnv* env,
+ bool is_system_server,
+ NativeBridgeAction action,
+ const char* isa,
+ bool profile_system_server) {
is_zygote_ = false;
if (is_native_bridge_loaded_) {
@@ -884,8 +888,15 @@ void Runtime::InitNonZygoteOrPostFork(
heap_->ResetGcPerformanceInfo();
// We may want to collect profiling samples for system server, but we never want to JIT there.
- if ((!is_system_server || !jit_options_->UseJitCompilation()) &&
- !safe_mode_ &&
+ if (is_system_server) {
+ jit_options_->SetUseJitCompilation(false);
+ jit_options_->SetSaveProfilingInfo(profile_system_server);
+ if (profile_system_server) {
+ jit_options_->SetWaitForJitNotificationsToSaveProfile(false);
+ VLOG(profiler) << "Enabling system server profiles";
+ }
+ }
+ if (!safe_mode_ &&
(jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) &&
jit_ == nullptr) {
// Note that when running ART standalone (not zygote, nor zygote fork),
@@ -904,7 +915,7 @@ void Runtime::InitNonZygoteOrPostFork(
void Runtime::StartSignalCatcher() {
if (!is_zygote_) {
- signal_catcher_ = new SignalCatcher(stack_trace_file_, use_tombstoned_traces_);
+ signal_catcher_ = new SignalCatcher();
}
}
@@ -1152,12 +1163,6 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
abort_ = runtime_options.GetOrDefault(Opt::HookAbort);
default_stack_size_ = runtime_options.GetOrDefault(Opt::StackSize);
- use_tombstoned_traces_ = runtime_options.GetOrDefault(Opt::UseTombstonedTraces);
-#if !defined(ART_TARGET_ANDROID)
- CHECK(!use_tombstoned_traces_)
- << "-Xusetombstonedtraces is only supported in an Android environment";
-#endif
- stack_trace_file_ = runtime_options.ReleaseOrDefault(Opt::StackTraceFile);
compiler_executable_ = runtime_options.ReleaseOrDefault(Opt::Compiler);
compiler_options_ = runtime_options.ReleaseOrDefault(Opt::CompilerOptions);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 1b7663cbdf..953acbb948 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -451,7 +451,11 @@ class Runtime {
void PreZygoteFork();
void InitNonZygoteOrPostFork(
- JNIEnv* env, bool is_system_server, NativeBridgeAction action, const char* isa);
+ JNIEnv* env,
+ bool is_system_server,
+ NativeBridgeAction action,
+ const char* isa,
+ bool profile_system_server = false);
const instrumentation::Instrumentation* GetInstrumentation() const {
return &instrumentation_;
@@ -569,6 +573,14 @@ class Runtime {
return always_set_hidden_api_warning_flag_;
}
+ void SetHiddenApiEventLogSampleRate(uint32_t rate) {
+ hidden_api_access_event_log_rate_ = rate;
+ }
+
+ uint32_t GetHiddenApiEventLogSampleRate() const {
+ return hidden_api_access_event_log_rate_;
+ }
+
bool IsDexFileFallbackEnabled() const {
return allow_dex_file_fallback_;
}
@@ -871,14 +883,6 @@ class Runtime {
SignalCatcher* signal_catcher_;
- // If true, the runtime will connect to tombstoned via a socket to
- // request an open file descriptor to write its traces to.
- bool use_tombstoned_traces_;
-
- // Location to which traces must be written on SIGQUIT. Only used if
- // tombstoned_traces_ == false.
- std::string stack_trace_file_;
-
std::unique_ptr<JavaVMExt> java_vm_;
std::unique_ptr<jit::Jit> jit_;
@@ -1014,7 +1018,8 @@ class Runtime {
// Whether access checks on hidden API should be performed.
hiddenapi::EnforcementPolicy hidden_api_policy_;
- // List of signature prefixes of methods that have been removed from the blacklist
+ // List of signature prefixes of methods that have been removed from the blacklist, and treated
+ // as if whitelisted.
std::vector<std::string> hidden_api_exemptions_;
// Whether the application has used an API which is not restricted but we
@@ -1030,6 +1035,10 @@ class Runtime {
// when there is a warning. This is only used for testing.
bool always_set_hidden_api_warning_flag_;
+ // How often to log hidden API access to the event log. An integer between 0 (never)
+ // and 0x10000 (always).
+ uint32_t hidden_api_access_event_log_rate_;
+
// Whether threads should dump their native stack on SIGQUIT.
bool dump_native_stack_on_sig_quit_;
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 4121ad69ed..427385d914 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -103,8 +103,6 @@ RUNTIME_OPTIONS_KEY (Unit, ForceNativeBridge)
RUNTIME_OPTIONS_KEY (LogVerbosity, Verbose)
RUNTIME_OPTIONS_KEY (unsigned int, LockProfThreshold)
RUNTIME_OPTIONS_KEY (unsigned int, StackDumpLockProfThreshold)
-RUNTIME_OPTIONS_KEY (bool, UseTombstonedTraces, false)
-RUNTIME_OPTIONS_KEY (std::string, StackTraceFile)
RUNTIME_OPTIONS_KEY (Unit, MethodTrace)
RUNTIME_OPTIONS_KEY (std::string, MethodTraceFile, "/data/misc/trace/method-trace-file.bin")
RUNTIME_OPTIONS_KEY (unsigned int, MethodTraceFileSize, 10 * MB)
diff --git a/runtime/scoped_thread_state_change-inl.h b/runtime/scoped_thread_state_change-inl.h
index f95593209b..3089c24c59 100644
--- a/runtime/scoped_thread_state_change-inl.h
+++ b/runtime/scoped_thread_state_change-inl.h
@@ -22,7 +22,7 @@
#include <android-base/logging.h>
#include "base/casts.h"
-#include "jni_env_ext-inl.h"
+#include "jni/jni_env_ext-inl.h"
#include "obj_ptr-inl.h"
#include "runtime.h"
#include "thread-inl.h"
diff --git a/runtime/scoped_thread_state_change.cc b/runtime/scoped_thread_state_change.cc
index 6a86cc6411..edbce05325 100644
--- a/runtime/scoped_thread_state_change.cc
+++ b/runtime/scoped_thread_state_change.cc
@@ -19,7 +19,7 @@
#include <type_traits>
#include "base/casts.h"
-#include "java_vm_ext.h"
+#include "jni/java_vm_ext.h"
#include "obj_ptr-inl.h"
#include "runtime-inl.h"
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index d590ad5cc6..f4a27b8397 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -73,19 +73,10 @@ static void DumpCmdLine(std::ostream& os) {
#endif
}
-SignalCatcher::SignalCatcher(const std::string& stack_trace_file,
- bool use_tombstoned_stack_trace_fd)
- : stack_trace_file_(stack_trace_file),
- use_tombstoned_stack_trace_fd_(use_tombstoned_stack_trace_fd),
- lock_("SignalCatcher lock"),
+SignalCatcher::SignalCatcher()
+ : lock_("SignalCatcher lock"),
cond_("SignalCatcher::cond_", lock_),
thread_(nullptr) {
-#if !defined(ART_TARGET_ANDROID)
- // We're not running on Android, so we can't communicate with tombstoned
- // to ask for an open file.
- CHECK(!use_tombstoned_stack_trace_fd_);
-#endif
-
SetHaltFlag(false);
// Create a raw pthread; its start routine will attach to the runtime.
@@ -116,37 +107,11 @@ bool SignalCatcher::ShouldHalt() {
return halt_;
}
-bool SignalCatcher::OpenStackTraceFile(android::base::unique_fd* tombstone_fd,
- android::base::unique_fd* output_fd) {
- if (use_tombstoned_stack_trace_fd_) {
-#if defined(ART_TARGET_ANDROID)
- return tombstoned_connect(getpid(), tombstone_fd, output_fd, kDebuggerdJavaBacktrace);
-#else
- UNUSED(tombstone_fd);
- UNUSED(output_fd);
-#endif
- }
-
- // The runtime is not configured to dump traces to a file, will LOG(INFO)
- // instead.
- if (stack_trace_file_.empty()) {
- return false;
- }
-
- int fd = open(stack_trace_file_.c_str(), O_APPEND | O_CREAT | O_WRONLY, 0666);
- if (fd == -1) {
- PLOG(ERROR) << "Unable to open stack trace file '" << stack_trace_file_ << "'";
- return false;
- }
-
- output_fd->reset(fd);
- return true;
-}
-
void SignalCatcher::Output(const std::string& s) {
+#if defined(ART_TARGET_ANDROID)
android::base::unique_fd tombstone_fd;
android::base::unique_fd output_fd;
- if (!OpenStackTraceFile(&tombstone_fd, &output_fd)) {
+ if (!tombstoned_connect(getpid(), &tombstone_fd, &output_fd, kDebuggerdJavaBacktrace)) {
LOG(INFO) << s;
return;
}
@@ -161,19 +126,16 @@ void SignalCatcher::Output(const std::string& s) {
file->Erase();
}
- const std::string output_path_msg = (use_tombstoned_stack_trace_fd_) ?
- "[tombstoned]" : stack_trace_file_;
-
if (success) {
- LOG(INFO) << "Wrote stack traces to '" << output_path_msg << "'";
+ LOG(INFO) << "Wrote stack traces to tombstoned";
} else {
- PLOG(ERROR) << "Failed to write stack traces to '" << output_path_msg << "'";
+ PLOG(ERROR) << "Failed to write stack traces to tombstoned";
}
-
-#if defined(ART_TARGET_ANDROID)
- if (use_tombstoned_stack_trace_fd_ && !tombstoned_notify_completion(tombstone_fd)) {
+ if (!tombstoned_notify_completion(tombstone_fd)) {
PLOG(WARNING) << "Unable to notify tombstoned of dump completion";
}
+#else
+ LOG(INFO) << s;
#endif
}
diff --git a/runtime/signal_catcher.h b/runtime/signal_catcher.h
index 8a2a7289de..46eae7e50e 100644
--- a/runtime/signal_catcher.h
+++ b/runtime/signal_catcher.h
@@ -33,17 +33,7 @@ class Thread;
*/
class SignalCatcher {
public:
- // If |use_tombstoned_stack_trace_fd| is |true|, traces will be
- // written to a file descriptor provided by tombstoned. The process
- // will communicate with tombstoned via a unix domain socket. This
- // mode of stack trace dumping is only supported in an Android
- // environment.
- //
- // If false, all traces will be dumped to |stack_trace_file| if it's
- // non-empty. If |stack_trace_file| is empty, all traces will be written
- // to the log buffer.
- SignalCatcher(const std::string& stack_trace_file,
- const bool use_tombstoned_stack_trace_fd);
+ SignalCatcher();
~SignalCatcher();
void HandleSigQuit() REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_,
@@ -54,19 +44,12 @@ class SignalCatcher {
// NO_THREAD_SAFETY_ANALYSIS for static function calling into member function with excludes lock.
static void* Run(void* arg) NO_THREAD_SAFETY_ANALYSIS;
- // NOTE: We're using android::base::unique_fd here for easier
- // interoperability with tombstoned client APIs.
- bool OpenStackTraceFile(android::base::unique_fd* tombstone_fd,
- android::base::unique_fd* output_fd);
void HandleSigUsr1();
void Output(const std::string& s);
void SetHaltFlag(bool new_value) REQUIRES(!lock_);
bool ShouldHalt() REQUIRES(!lock_);
int WaitForSignal(Thread* self, SignalSet& signals) REQUIRES(!lock_);
- std::string stack_trace_file_;
- const bool use_tombstoned_stack_trace_fd_;
-
mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
ConditionVariable cond_ GUARDED_BY(lock_);
bool halt_ GUARDED_BY(lock_);
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index e34f32e0bf..91c27af407 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -23,7 +23,7 @@
#include "base/casts.h"
#include "base/mutex-inl.h"
#include "base/time_utils.h"
-#include "jni_env_ext.h"
+#include "jni/jni_env_ext.h"
#include "managed_stack-inl.h"
#include "obj_ptr.h"
#include "thread-current-inl.h"
diff --git a/runtime/thread.cc b/runtime/thread.cc
index f6ac64f7bd..eada24d257 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -65,8 +65,8 @@
#include "interpreter/interpreter.h"
#include "interpreter/shadow_frame.h"
#include "java_frame_root_info.h"
-#include "java_vm_ext.h"
-#include "jni_internal.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/object_array-inl.h"
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 44af867d60..b2be549996 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -40,7 +40,7 @@
#include "gc/heap.h"
#include "gc/reference_processor.h"
#include "gc_root.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "lock_word.h"
#include "monitor.h"
#include "native_stack_dump.h"
diff --git a/runtime/ti/agent.cc b/runtime/ti/agent.cc
index 15c514e593..608f0ee13c 100644
--- a/runtime/ti/agent.cc
+++ b/runtime/ti/agent.cc
@@ -21,7 +21,7 @@
#include "nativeloader/native_loader.h"
#include "base/strlcpy.h"
-#include "java_vm_ext.h"
+#include "jni/java_vm_ext.h"
#include "runtime.h"
#include "thread-current-inl.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 72292c33f8..3518d2facd 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2287,14 +2287,10 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::CONST_METHOD_HANDLE:
work_line_->SetRegisterType<LockOp::kClear>(
this, inst->VRegA_21c(), reg_types_.JavaLangInvokeMethodHandle());
- // TODO: add compiler support for const-method-{handle,type} (b/66890674)
- Fail(VERIFY_ERROR_FORCE_INTERPRETER);
break;
case Instruction::CONST_METHOD_TYPE:
work_line_->SetRegisterType<LockOp::kClear>(
this, inst->VRegA_21c(), reg_types_.JavaLangInvokeMethodType());
- // TODO: add compiler support for const-method-{handle,type} (b/66890674)
- Fail(VERIFY_ERROR_FORCE_INTERPRETER);
break;
case Instruction::MONITOR_ENTER:
work_line_->PushMonitor(this, inst->VRegA_11x(), work_insn_idx_);
@@ -3801,16 +3797,8 @@ ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(
must_fail = true;
// Try to find the method also with the other type for better error reporting below
// but do not store such bogus lookup result in the DexCache or VerifierDeps.
- if (klass->IsInterface()) {
- // NB This is normally not really allowed but we want to get any static or private object
- // methods for error message purposes. This will never be returned.
- // TODO We might want to change the verifier to not require this.
- res_method = klass->FindClassMethod(dex_cache_.Get(), dex_method_idx, pointer_size);
- } else {
- // If there was an interface method with the same signature,
- // we would have found it also in the "copied" methods.
- DCHECK(klass->FindInterfaceMethod(dex_cache_.Get(), dex_method_idx, pointer_size) == nullptr);
- }
+ res_method = class_linker->FindIncompatibleMethod(
+ klass, dex_cache_.Get(), class_loader_.Get(), dex_method_idx);
}
if (res_method == nullptr) {
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index f5d112c30b..b79334ac7f 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -25,7 +25,7 @@
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "hidden_api.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class.h"
#include "mirror/throwable.h"
#include "nativehelper/scoped_local_ref.h"
diff --git a/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
index f01b82553d..d9ade931d2 100644
--- a/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
+++ b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
@@ -19,8 +19,8 @@
#include "base/casts.h"
#include "base/macros.h"
-#include "java_vm_ext.h"
-#include "jni_env_ext.h"
+#include "jni/java_vm_ext.h"
+#include "jni/jni_env_ext.h"
#include "thread-current-inl.h"
namespace art {
diff --git a/test/172-app-image-twice/check b/test/172-app-image-twice/check
new file mode 100755
index 0000000000..26a97a48ae
--- /dev/null
+++ b/test/172-app-image-twice/check
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Remove all lines not containing "passed".
+grep "^passed" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null
diff --git a/test/172-app-image-twice/debug_print_class.cc b/test/172-app-image-twice/debug_print_class.cc
new file mode 100644
index 0000000000..6c3de20f2d
--- /dev/null
+++ b/test/172-app-image-twice/debug_print_class.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "debug_print.h"
+#include "dex/dex_file.h"
+#include "mirror/class-inl.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread-current-inl.h"
+
+namespace art {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_debugPrintClass(JNIEnv*, jclass, jclass cls) {
+ ScopedObjectAccess soa(Thread::Current());
+ ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
+ LOG(ERROR) << "klass: " << klass.Ptr() << " dex_file: " << klass->GetDexFile().GetLocation()
+ << "/" << static_cast<const void*>(&klass->GetDexFile())
+ << " " << DescribeSpace(klass);
+}
+
+} // namespace art
diff --git a/test/172-app-image-twice/expected.txt b/test/172-app-image-twice/expected.txt
new file mode 100644
index 0000000000..b0aad4deb5
--- /dev/null
+++ b/test/172-app-image-twice/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/172-app-image-twice/info.txt b/test/172-app-image-twice/info.txt
new file mode 100644
index 0000000000..028046e872
--- /dev/null
+++ b/test/172-app-image-twice/info.txt
@@ -0,0 +1 @@
+Regression test for loading the same app image twice.
diff --git a/test/172-app-image-twice/profile b/test/172-app-image-twice/profile
new file mode 100644
index 0000000000..70cb2efbb5
--- /dev/null
+++ b/test/172-app-image-twice/profile
@@ -0,0 +1 @@
+LTestClass;
diff --git a/test/172-app-image-twice/run b/test/172-app-image-twice/run
new file mode 100644
index 0000000000..aa2819075f
--- /dev/null
+++ b/test/172-app-image-twice/run
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Build an app image with TestClass (specified by profile) and class loader
+# context that skips the duplicate class checks.
+
+# Target and host use a different shell, and we need to special case the
+# passing of the class loader context marker.
+if [[ "$@" = *" --host "* ]]; then
+ ${RUN} $@ --profile -Xcompiler-option --compiler-filter=speed-profile \
+ -Xcompiler-option --class-loader-context=\&
+else
+ ${RUN} $@ --profile -Xcompiler-option --compiler-filter=speed-profile \
+ -Xcompiler-option '--class-loader-context=\&'
+fi
diff --git a/test/172-app-image-twice/src/Main.java b/test/172-app-image-twice/src/Main.java
new file mode 100644
index 0000000000..a1c151a6bc
--- /dev/null
+++ b/test/172-app-image-twice/src/Main.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+ private static String TEST_NAME = "172-app-image-twice";
+
+ public static void main(String args[]) throws Exception {
+ System.loadLibrary(args[0]);
+
+ Class<?> tc1 = Class.forName("TestClass");
+
+ String dexPath = System.getenv("DEX_LOCATION") + "/" + TEST_NAME + ".jar";
+ Class<?> bdcl = Class.forName("dalvik.system.BaseDexClassLoader");
+ Method addDexPathMethod = bdcl.getDeclaredMethod("addDexPath", String.class);
+ addDexPathMethod.invoke(Main.class.getClassLoader(), dexPath);
+
+ Class<?> tc2 = Class.forName("TestClass");
+
+ // Add extra logging to simulate libcore logging, this logging should not be compared
+ // against.
+ System.out.println("Extra logging");
+
+ if (tc1 != tc2) {
+ System.out.println("Class mismatch!");
+ debugPrintClass(tc1);
+ debugPrintClass(tc2);
+ } else {
+ System.out.println("passed");
+ }
+ }
+
+ public static native void debugPrintClass(Class<?> cls);
+}
diff --git a/test/172-app-image-twice/src/TestClass.java b/test/172-app-image-twice/src/TestClass.java
new file mode 100644
index 0000000000..5381718f6e
--- /dev/null
+++ b/test/172-app-image-twice/src/TestClass.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class TestClass {
+}
diff --git a/test/1947-breakpoint-redefine-deopt/check_deopt.cc b/test/1947-breakpoint-redefine-deopt/check_deopt.cc
index b40b201c9c..667d8be684 100644
--- a/test/1947-breakpoint-redefine-deopt/check_deopt.cc
+++ b/test/1947-breakpoint-redefine-deopt/check_deopt.cc
@@ -16,7 +16,7 @@
#include "jni.h"
#include "art_method-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "instrumentation.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/test/674-hiddenapi/src-art/Main.java b/test/674-hiddenapi/src-art/Main.java
index a808e946a9..782748c345 100644
--- a/test/674-hiddenapi/src-art/Main.java
+++ b/test/674-hiddenapi/src-art/Main.java
@@ -16,6 +16,7 @@
import dalvik.system.InMemoryDexClassLoader;
import dalvik.system.PathClassLoader;
+import dalvik.system.VMRuntime;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Constructor;
@@ -34,26 +35,41 @@ public class Main {
// Enable hidden API checks in case they are disabled by default.
init();
+ // TODO there are sequential depencies between these test cases, and bugs
+ // in the production code may lead to subsequent tests to erroneously pass,
+ // or test the wrong thing. We rely on not deduping hidden API warnings
+ // here for the same reasons), meaning the code under test and production
+ // code are running in different configurations. Each test should be run in
+ // a fresh process to ensure that they are working correcting and not
+ // accidentally interfering with eachother.
+
// Run test with both parent and child dex files loaded with class loaders.
// The expectation is that hidden members in parent should be visible to
// the child.
- doTest(false, false);
+ doTest(false, false, false);
doUnloading();
// Now append parent dex file to boot class path and run again. This time
- // the child dex file should not be able to access private APIs of the parent.
+ // the child dex file should not be able to access private APIs of the
+ // parent.
appendToBootClassLoader(DEX_PARENT_BOOT);
- doTest(true, false);
+ doTest(true, false, false);
+ doUnloading();
+
+ // Now run the same test again, but with the blacklist exmemptions list set
+ // to "L" which matches everything.
+ doTest(true, false, true);
doUnloading();
// And finally append to child to boot class path as well. With both in the
// boot class path, access should be granted.
appendToBootClassLoader(DEX_CHILD);
- doTest(true, true);
+ doTest(true, true, false);
doUnloading();
}
- private static void doTest(boolean parentInBoot, boolean childInBoot) throws Exception {
+ private static void doTest(boolean parentInBoot, boolean childInBoot, boolean whitelistAllApis)
+ throws Exception {
// Load parent dex if it is not in boot class path.
ClassLoader parentLoader = null;
if (parentInBoot) {
@@ -78,12 +94,18 @@ public class Main {
// be loaded once, but for some reason even classes from a class loader
// cannot register their native methods against symbols in a shared library
// loaded by their parent class loader.
- String nativeLibCopy = createNativeLibCopy(parentInBoot, childInBoot);
+ String nativeLibCopy = createNativeLibCopy(parentInBoot, childInBoot, whitelistAllApis);
+
+ if (whitelistAllApis) {
+ VMRuntime.getRuntime().setHiddenApiExemptions(new String[]{"L"});
+ }
// Invoke ChildClass.runTest
Class.forName("ChildClass", true, childLoader)
- .getDeclaredMethod("runTest", String.class, Boolean.TYPE, Boolean.TYPE)
- .invoke(null, nativeLibCopy, parentInBoot, childInBoot);
+ .getDeclaredMethod("runTest", String.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE)
+ .invoke(null, nativeLibCopy, parentInBoot, childInBoot, whitelistAllApis);
+
+ VMRuntime.getRuntime().setHiddenApiExemptions(new String[0]);
}
// Routine which tries to figure out the absolute path of our native library.
@@ -122,20 +144,21 @@ public class Main {
return buffer;
}
- // Copy native library to a new file with a unique name so it does not conflict
- // with other loaded instance of the same binary file.
- private static String createNativeLibCopy(boolean parentInBoot, boolean childInBoot)
- throws Exception {
+ // Copy native library to a new file with a unique name so it does not
+ // conflict with other loaded instance of the same binary file.
+ private static String createNativeLibCopy(
+ boolean parentInBoot, boolean childInBoot, boolean whitelistAllApis) throws Exception {
String tempFileName = System.mapLibraryName(
- "hiddenapitest_" + (parentInBoot ? "1" : "0") + (childInBoot ? "1" : "0"));
+ "hiddenapitest_" + (parentInBoot ? "1" : "0") + (childInBoot ? "1" : "0") +
+ (whitelistAllApis ? "1" : "0"));
File tempFile = new File(System.getenv("DEX_LOCATION"), tempFileName);
Files.copy(new File(nativeLibFileName).toPath(), tempFile.toPath());
return tempFile.getAbsolutePath();
}
private static void doUnloading() {
- // Do multiple GCs to prevent rare flakiness if some other thread is keeping the
- // classloader live.
+ // Do multiple GCs to prevent rare flakiness if some other thread is
+ // keeping the classloader live.
for (int i = 0; i < 5; ++i) {
Runtime.getRuntime().gc();
}
diff --git a/test/674-hiddenapi/src-ex/ChildClass.java b/test/674-hiddenapi/src-ex/ChildClass.java
index ea66f1651e..0349e8fe46 100644
--- a/test/674-hiddenapi/src-ex/ChildClass.java
+++ b/test/674-hiddenapi/src-ex/ChildClass.java
@@ -70,7 +70,7 @@ public class ChildClass {
private static final boolean booleanValues[] = new boolean[] { false, true };
public static void runTest(String libFileName, boolean expectedParentInBoot,
- boolean expectedChildInBoot) throws Exception {
+ boolean expectedChildInBoot, boolean everythingWhitelisted) throws Exception {
System.load(libFileName);
// Check expectations about loading into boot class path.
@@ -84,13 +84,14 @@ public class ChildClass {
throw new RuntimeException("Expected ChildClass " + (expectedChildInBoot ? "" : "not ") +
"in boot class path");
}
+ ChildClass.everythingWhitelisted = everythingWhitelisted;
boolean isSameBoot = (isParentInBoot == isChildInBoot);
// Run meaningful combinations of access flags.
for (Hiddenness hiddenness : Hiddenness.values()) {
final Behaviour expected;
- if (isSameBoot || hiddenness == Hiddenness.Whitelist) {
+ if (isSameBoot || hiddenness == Hiddenness.Whitelist || everythingWhitelisted) {
expected = Behaviour.Granted;
} else if (hiddenness == Hiddenness.Blacklist) {
expected = Behaviour.Denied;
@@ -121,6 +122,7 @@ public class ChildClass {
checkLinking("LinkFieldGet" + suffix, /*takesParameter*/ false, expected);
checkLinking("LinkFieldSet" + suffix, /*takesParameter*/ true, expected);
checkLinking("LinkMethod" + suffix, /*takesParameter*/ false, expected);
+ checkLinking("LinkMethodInterface" + suffix, /*takesParameter*/ false, expected);
}
// Check whether Class.newInstance succeeds.
@@ -509,14 +511,16 @@ public class ChildClass {
String fn, boolean canAccess) {
throw new RuntimeException("Expected " + (isField ? "field " : "method ") + klass.getName() +
"." + name + " to " + (canAccess ? "" : "not ") + "be discoverable with " + fn + ". " +
- "isParentInBoot = " + isParentInBoot + ", " + "isChildInBoot = " + isChildInBoot);
+ "isParentInBoot = " + isParentInBoot + ", " + "isChildInBoot = " + isChildInBoot + ", " +
+ "everythingWhitelisted = " + everythingWhitelisted);
}
private static void throwAccessException(Class<?> klass, String name, boolean isField,
String fn) {
throw new RuntimeException("Expected to be able to access " + (isField ? "field " : "method ") +
klass.getName() + "." + name + " using " + fn + ". " +
- "isParentInBoot = " + isParentInBoot + ", " + "isChildInBoot = " + isChildInBoot);
+ "isParentInBoot = " + isParentInBoot + ", " + "isChildInBoot = " + isChildInBoot + ", " +
+ "everythingWhitelisted = " + everythingWhitelisted);
}
private static void throwWarningException(Class<?> klass, String name, boolean isField,
@@ -524,7 +528,8 @@ public class ChildClass {
throw new RuntimeException("Expected access to " + (isField ? "field " : "method ") +
klass.getName() + "." + name + " using " + fn + " to " + (setsWarning ? "" : "not ") +
"set the warning flag. " +
- "isParentInBoot = " + isParentInBoot + ", " + "isChildInBoot = " + isChildInBoot);
+ "isParentInBoot = " + isParentInBoot + ", " + "isChildInBoot = " + isChildInBoot + ", " +
+ "everythingWhitelisted = " + everythingWhitelisted);
}
private static void throwModifiersException(Class<?> klass, String name, boolean isField) {
@@ -534,6 +539,7 @@ public class ChildClass {
private static boolean isParentInBoot;
private static boolean isChildInBoot;
+ private static boolean everythingWhitelisted;
private static native boolean hasPendingWarning();
private static native void clearWarning();
diff --git a/test/674-hiddenapi/src-ex/Linking.java b/test/674-hiddenapi/src-ex/Linking.java
index a89b92b2b9..0fa0b1912f 100644
--- a/test/674-hiddenapi/src-ex/Linking.java
+++ b/test/674-hiddenapi/src-ex/Linking.java
@@ -174,6 +174,32 @@ class LinkMethodBlacklist {
}
}
+// INVOKE INSTANCE INTERFACE METHOD
+
+class LinkMethodInterfaceWhitelist {
+ public static int access() {
+ return DummyClass.getInterfaceInstance().methodPublicWhitelist();
+ }
+}
+
+class LinkMethodInterfaceLightGreylist {
+ public static int access() {
+ return DummyClass.getInterfaceInstance().methodPublicLightGreylist();
+ }
+}
+
+class LinkMethodInterfaceDarkGreylist {
+ public static int access() {
+ return DummyClass.getInterfaceInstance().methodPublicDarkGreylist();
+ }
+}
+
+class LinkMethodInterfaceBlacklist {
+ public static int access() {
+ return DummyClass.getInterfaceInstance().methodPublicBlacklist();
+ }
+}
+
// INVOKE STATIC METHOD
class LinkMethodStaticWhitelist {
@@ -199,3 +225,29 @@ class LinkMethodStaticBlacklist {
return ParentClass.methodPublicStaticBlacklist();
}
}
+
+// INVOKE INTERFACE STATIC METHOD
+
+class LinkMethodInterfaceStaticWhitelist {
+ public static int access() {
+ return ParentInterface.methodPublicStaticWhitelist();
+ }
+}
+
+class LinkMethodInterfaceStaticLightGreylist {
+ public static int access() {
+ return ParentInterface.methodPublicStaticLightGreylist();
+ }
+}
+
+class LinkMethodInterfaceStaticDarkGreylist {
+ public static int access() {
+ return ParentInterface.methodPublicStaticDarkGreylist();
+ }
+}
+
+class LinkMethodInterfaceStaticBlacklist {
+ public static int access() {
+ return ParentInterface.methodPublicStaticBlacklist();
+ }
+}
diff --git a/test/674-hiddenapi/src/DummyClass.java b/test/674-hiddenapi/src/DummyClass.java
new file mode 100644
index 0000000000..51281a2666
--- /dev/null
+++ b/test/674-hiddenapi/src/DummyClass.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class DummyClass implements ParentInterface {
+ public int methodPublicWhitelist() { return 1; }
+ public int methodPublicLightGreylist() { return 2; }
+ public int methodPublicDarkGreylist() { return 3; }
+ public int methodPublicBlacklist() { return 4; }
+
+ public static ParentInterface getInterfaceInstance() {
+ return new DummyClass();
+ }
+}
diff --git a/test/674-hiddenapi/src/ParentInterface.java b/test/674-hiddenapi/src/ParentInterface.java
index e36fe0e6b2..f79ac9d661 100644
--- a/test/674-hiddenapi/src/ParentInterface.java
+++ b/test/674-hiddenapi/src/ParentInterface.java
@@ -23,9 +23,9 @@ public interface ParentInterface {
// INSTANCE METHOD
int methodPublicWhitelist();
- int methodPublicBlacklist();
int methodPublicLightGreylist();
int methodPublicDarkGreylist();
+ int methodPublicBlacklist();
// STATIC METHOD
static int methodPublicStaticWhitelist() { return 21; }
diff --git a/test/708-jit-cache-churn/jit.cc b/test/708-jit-cache-churn/jit.cc
index 1284a8703d..1b80eb3c0c 100644
--- a/test/708-jit-cache-churn/jit.cc
+++ b/test/708-jit-cache-churn/jit.cc
@@ -19,7 +19,7 @@
#include "art_method.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/test/900-hello-plugin/load_unload.cc b/test/900-hello-plugin/load_unload.cc
index cab0abf58b..7121d108a4 100644
--- a/test/900-hello-plugin/load_unload.cc
+++ b/test/900-hello-plugin/load_unload.cc
@@ -21,7 +21,7 @@
#include <android-base/macros.h>
#include "art_method-inl.h"
-#include "java_vm_ext.h"
+#include "jni/java_vm_ext.h"
#include "runtime.h"
namespace art {
diff --git a/test/913-heaps/expected_d8.diff b/test/913-heaps/expected_d8.diff
index 3ea3c0d2b0..1ad0cbdd3b 100644
--- a/test/913-heaps/expected_d8.diff
+++ b/test/913-heaps/expected_d8.diff
@@ -10,8 +10,8 @@
51c50,51
< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
---
-> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=5,location= 21])--> 1@1000 [size=16, length=-1]
-> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1]
102,103c102
< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1]
< root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1]
@@ -24,8 +24,8 @@
117c116,117
< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
---
-> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=5,location= 21])--> 1@1000 [size=16, length=-1]
-> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1]
162c162
< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1]
---
@@ -37,8 +37,8 @@
179c179,180
< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
---
-> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=5,location= 21])--> 1@1000 [size=16, length=-1]
-> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1]
201,202c202
< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1]
< root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1]
@@ -51,8 +51,8 @@
248c248,249
< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
---
-> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=5,location= 21])--> 1@1000 [size=16, length=-1]
-> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1]
292d292
< root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1]
347c347
@@ -66,5 +66,5 @@
368c368,369
< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1]
---
-> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=5,location= 21])--> 1@1000 [size=16, length=-1]
-> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1]
diff --git a/test/979-const-method-handle/expected.txt b/test/979-const-method-handle/expected.txt
index bc943e368e..bbaaedb0af 100644
--- a/test/979-const-method-handle/expected.txt
+++ b/test/979-const-method-handle/expected.txt
@@ -1,6 +1,9 @@
(int,Integer,System)String
+repeatConstMethodType0((int,Integer,System)String)
+repeatConstMethodType1((LocalClass)void)
Hello World! And Hello Zog
Hello World! And Hello Zorba
name is HoverFly
2.718281828459045
+repeatConstMethodHandle()
Attempting to set Math.E raised IAE
diff --git a/test/979-const-method-handle/src/Main.java b/test/979-const-method-handle/src/Main.java
index 663814f232..427ca7a306 100644
--- a/test/979-const-method-handle/src/Main.java
+++ b/test/979-const-method-handle/src/Main.java
@@ -20,78 +20,146 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
class Main {
+ /**
+ * Number of iterations run to attempt to trigger JIT compilation. These tests run on ART and
+ * the RI so they iterate rather than using the ART only native method ensureJitCompiled().
+ */
+ private static final int ITERATIONS_FOR_JIT = 12000;
+
+ /** A static field updated by method handle getters and setters. */
private static String name = "default";
private static void unreachable() {
throw new Error("Unreachable");
}
+ private static void assertEquals(Object expected, Object actual) {
+ if (!expected.equals(actual)) {
+ throw new AssertionError("Assertion failure: " + expected + " != " + actual);
+ }
+ }
+
+ private static class LocalClass {
+ public LocalClass() {}
+
+ private int field;
+ }
+
@ConstantMethodType(
- returnType = String.class,
- parameterTypes = {int.class, Integer.class, System.class}
- )
+ returnType = String.class,
+ parameterTypes = {int.class, Integer.class, System.class})
private static MethodType methodType0() {
unreachable();
return null;
}
+ @ConstantMethodType(
+ returnType = void.class,
+ parameterTypes = {LocalClass.class})
+ private static MethodType methodType1() {
+ unreachable();
+ return null;
+ }
+
+ private static void repeatConstMethodType0(MethodType expected) {
+ System.out.print("repeatConstMethodType0(");
+ System.out.print(expected);
+ System.out.println(")");
+ for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) {
+ MethodType actual = methodType0();
+ assertEquals(expected, actual);
+ }
+ }
+
+ private static void repeatConstMethodType1(MethodType expected) {
+ System.out.print("repeatConstMethodType1(");
+ System.out.print(expected);
+ System.out.println(")");
+ for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) {
+ MethodType actual = methodType1();
+ assertEquals(expected, actual);
+ }
+ }
+
static void helloWorld(String who) {
System.out.print("Hello World! And Hello ");
System.out.println(who);
}
@ConstantMethodHandle(
- kind = ConstantMethodHandle.INVOKE_STATIC,
- owner = "Main",
- fieldOrMethodName = "helloWorld",
- descriptor = "(Ljava/lang/String;)V"
- )
+ kind = ConstantMethodHandle.INVOKE_STATIC,
+ owner = "Main",
+ fieldOrMethodName = "helloWorld",
+ descriptor = "(Ljava/lang/String;)V")
private static MethodHandle printHelloHandle() {
unreachable();
return null;
}
@ConstantMethodHandle(
- kind = ConstantMethodHandle.STATIC_PUT,
- owner = "Main",
- fieldOrMethodName = "name",
- descriptor = "Ljava/lang/String;"
- )
+ kind = ConstantMethodHandle.STATIC_PUT,
+ owner = "Main",
+ fieldOrMethodName = "name",
+ descriptor = "Ljava/lang/String;")
private static MethodHandle setNameHandle() {
unreachable();
return null;
}
@ConstantMethodHandle(
- kind = ConstantMethodHandle.STATIC_GET,
- owner = "java/lang/Math",
- fieldOrMethodName = "E",
- descriptor = "D"
- )
+ kind = ConstantMethodHandle.STATIC_GET,
+ owner = "Main",
+ fieldOrMethodName = "name",
+ descriptor = "Ljava/lang/String;")
+ private static MethodHandle getNameHandle() {
+ unreachable();
+ return null;
+ }
+
+ @ConstantMethodHandle(
+ kind = ConstantMethodHandle.STATIC_GET,
+ owner = "java/lang/Math",
+ fieldOrMethodName = "E",
+ descriptor = "D")
private static MethodHandle getMathE() {
unreachable();
return null;
}
@ConstantMethodHandle(
- kind = ConstantMethodHandle.STATIC_PUT,
- owner = "java/lang/Math",
- fieldOrMethodName = "E",
- descriptor = "D"
- )
+ kind = ConstantMethodHandle.STATIC_PUT,
+ owner = "java/lang/Math",
+ fieldOrMethodName = "E",
+ descriptor = "D")
private static MethodHandle putMathE() {
unreachable();
return null;
}
+ private static void repeatConstMethodHandle() throws Throwable {
+ System.out.println("repeatConstMethodHandle()");
+ String[] values = {"A", "B", "C"};
+ for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) {
+ String value = values[i % values.length];
+ setNameHandle().invoke(value);
+ String actual = (String) getNameHandle().invokeExact();
+ assertEquals(value, actual);
+ assertEquals(value, name);
+ }
+ }
+
public static void main(String[] args) throws Throwable {
System.out.println(methodType0());
+ repeatConstMethodType0(
+ MethodType.methodType(String.class, int.class, Integer.class, System.class));
+ repeatConstMethodType1(MethodType.methodType(void.class, LocalClass.class));
printHelloHandle().invokeExact("Zog");
printHelloHandle().invokeExact("Zorba");
setNameHandle().invokeExact("HoverFly");
System.out.print("name is ");
System.out.println(name);
System.out.println(getMathE().invoke());
+ repeatConstMethodHandle();
try {
putMathE().invokeExact(Math.PI);
unreachable();
diff --git a/test/Android.bp b/test/Android.bp
index 0c6b449877..76189f62a9 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -423,6 +423,7 @@ cc_defaults {
"154-gc-loop/heap_interface.cc",
"167-visit-locks/visit_locks.cc",
"169-threadgroup-jni/jni_daemon_thread.cc",
+ "172-app-image-twice/debug_print_class.cc",
"1945-proxy-method-arguments/get_args.cc",
"203-multi-checkpoint/multi_checkpoint.cc",
"305-other-fault-handler/fault_handler.cc",
diff --git a/runtime/jobject_comparator.h b/test/HiddenApiSignatures/Interface.java
index 698d6678d6..f141d09bf6 100644
--- a/runtime/jobject_comparator.h
+++ b/test/HiddenApiSignatures/Interface.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,17 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_JOBJECT_COMPARATOR_H_
-#define ART_RUNTIME_JOBJECT_COMPARATOR_H_
+package mypackage.packagea;
-#include <jni.h>
-
-namespace art {
-
-struct JobjectComparator {
- bool operator()(jobject jobj1, jobject jobj2) const;
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_JOBJECT_COMPARATOR_H_
+public interface Interface {
+ public void method();
+}
diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc
index fd6273769b..192274e5ae 100644
--- a/test/common/stack_inspect.cc
+++ b/test/common/stack_inspect.cc
@@ -20,7 +20,7 @@
#include "base/mutex.h"
#include "dex/dex_file-inl.h"
-#include "jni_internal.h"
+#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
#include "nth_caller_visitor.h"
#include "oat_file.h"
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index be1296b990..fad801192a 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -13,6 +13,7 @@ ARCHITECTURES_32="(arm|x86|mips|none)"
ARCHITECTURES_64="(arm64|x86_64|mips64|none)"
ARCHITECTURES_PATTERN="${ARCHITECTURES_32}"
BOOT_IMAGE=""
+CHROOT=
COMPILE_FLAGS=""
DALVIKVM="dalvikvm32"
DEBUGGER="n"
@@ -80,11 +81,6 @@ DEX2OAT_TIMEOUT="300" # 5 mins
# The *hard* timeout where we really start trying to kill the dex2oat.
DEX2OAT_RT_TIMEOUT="360" # 6 mins
-# if "y", set -Xstacktracedir and inform the test of its location. When
-# this is set, stack trace dumps (from signal 3) will be written to a file
-# under this directory instead of stdout.
-SET_STACK_TRACE_DUMP_DIR="n"
-
# if "y", run 'sync' before dalvikvm to make sure all files from
# build step (e.g. dex2oat) were finished writing.
SYNC_BEFORE_RUN="n"
@@ -304,6 +300,10 @@ while true; do
elif [ "x$1" = "x--no-optimize" ]; then
OPTIMIZE="n"
shift
+ elif [ "x$1" = "x--chroot" ]; then
+ shift
+ CHROOT="$1"
+ shift
elif [ "x$1" = "x--android-root" ]; then
shift
ANDROID_ROOT="$1"
@@ -364,9 +364,6 @@ while true; do
elif [ "x$1" = "x--random-profile" ]; then
RANDOM_PROFILE="y"
shift
- elif [ "x$1" = "x--set-stack-trace-dump-dir" ]; then
- SET_STACK_TRACE_DUMP_DIR="y"
- shift
elif expr "x$1" : "x--" >/dev/null 2>&1; then
echo "unknown $0 option: $1" 1>&2
exit 1
@@ -375,7 +372,8 @@ while true; do
fi
done
-mkdir_locations=""
+# The DEX_LOCATION with the chroot prefix, if any.
+CHROOT_DEX_LOCATION="$CHROOT$DEX_LOCATION"
if [ "$USE_JVM" = "n" ]; then
FLAGS="${FLAGS} ${ANDROID_FLAGS}"
@@ -383,14 +381,6 @@ if [ "$USE_JVM" = "n" ]; then
FLAGS="${FLAGS} -Xexperimental:${feature} -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:${feature}"
COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xexperimental:${feature}"
done
-
- if [ "$SET_STACK_TRACE_DUMP_DIR" = "y" ]; then
- # Note that DEX_LOCATION is used as a proxy for tmpdir throughout this
- # file (it will be under the test specific folder).
- mkdir_locations="${mkdir_locations} $DEX_LOCATION/stack_traces"
- FLAGS="${FLAGS} -Xstacktracedir:$DEX_LOCATION/stack_traces"
- ARGS="${ARGS} --stack-trace-dir $DEX_LOCATION/stack_traces"
- fi
fi
if [ "x$1" = "x" ] ; then
@@ -684,7 +674,7 @@ profman_cmdline="true"
dex2oat_cmdline="true"
vdex_cmdline="true"
dm_cmdline="true"
-mkdir_locations="${mkdir_locations} ${DEX_LOCATION}/dalvik-cache/$ISA"
+mkdir_locations="${DEX_LOCATION}/dalvik-cache/$ISA"
strip_cmdline="true"
sync_cmdline="true"
@@ -835,28 +825,28 @@ if [ "$HOST" = "n" ]; then
adb root > /dev/null
adb wait-for-device
if [ "$QUIET" = "n" ]; then
- adb shell rm -rf $DEX_LOCATION
- adb shell mkdir -p $DEX_LOCATION
- adb push $TEST_NAME.jar $DEX_LOCATION
- adb push $TEST_NAME-ex.jar $DEX_LOCATION
+ adb shell rm -rf $CHROOT_DEX_LOCATION
+ adb shell mkdir -p $CHROOT_DEX_LOCATION
+ adb push $TEST_NAME.jar $CHROOT_DEX_LOCATION
+ adb push $TEST_NAME-ex.jar $CHROOT_DEX_LOCATION
if [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then
- adb push profile $DEX_LOCATION
+ adb push profile $CHROOT_DEX_LOCATION
fi
# Copy resource folder
if [ -d res ]; then
- adb push res $DEX_LOCATION
+ adb push res $CHROOT_DEX_LOCATION
fi
else
- adb shell rm -r $DEX_LOCATION >/dev/null 2>&1
- adb shell mkdir -p $DEX_LOCATION >/dev/null 2>&1
- adb push $TEST_NAME.jar $DEX_LOCATION >/dev/null 2>&1
- adb push $TEST_NAME-ex.jar $DEX_LOCATION >/dev/null 2>&1
+ adb shell rm -rf $CHROOT_DEX_LOCATION >/dev/null 2>&1
+ adb shell mkdir -p $CHROOT_DEX_LOCATION >/dev/null 2>&1
+ adb push $TEST_NAME.jar $CHROOT_DEX_LOCATION >/dev/null 2>&1
+ adb push $TEST_NAME-ex.jar $CHROOT_DEX_LOCATION >/dev/null 2>&1
if [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then
- adb push profile $DEX_LOCATION >/dev/null 2>&1
+ adb push profile $CHROOT_DEX_LOCATION >/dev/null 2>&1
fi
# Copy resource folder
if [ -d res ]; then
- adb push res $DEX_LOCATION >/dev/null 2>&1
+ adb push res $CHROOT_DEX_LOCATION >/dev/null 2>&1
fi
fi
@@ -865,7 +855,7 @@ if [ "$HOST" = "n" ]; then
# Current default installation is dalvikvm 64bits and dex2oat 32bits,
# so we can only use LD_LIBRARY_PATH when testing on a local
# installation.
- LD_LIBRARY_PATH=$ANDROID_ROOT/$LIBRARY_DIRECTORY:$LD_LIBRARY_PATH
+ LD_LIBRARY_PATH="$ANDROID_ROOT/$LIBRARY_DIRECTORY:$LD_LIBRARY_PATH"
fi
# System libraries needed by libarttestd.so
@@ -907,14 +897,18 @@ if [ "$HOST" = "n" ]; then
fi
if [ "$QUIET" = "n" ]; then
- adb push $cmdfile $DEX_LOCATION/cmdline.sh
+ adb push $cmdfile $CHROOT_DEX_LOCATION/cmdline.sh
else
- adb push $cmdfile $DEX_LOCATION/cmdline.sh > /dev/null 2>&1
+ adb push $cmdfile $CHROOT_DEX_LOCATION/cmdline.sh >/dev/null 2>&1
fi
exit_status=0
if [ "$DRY_RUN" != "y" ]; then
- adb shell sh $DEX_LOCATION/cmdline.sh
+ if [ -n "$CHROOT" ]; then
+ adb shell chroot "$CHROOT" sh $DEX_LOCATION/cmdline.sh
+ else
+ adb shell sh $DEX_LOCATION/cmdline.sh
+ fi
exit_status=$?
fi
diff --git a/test/knownfailures.json b/test/knownfailures.json
index e109bf5a8f..f473a99a27 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -412,10 +412,11 @@
".*methodhandle.*",
".*method-handle.*",
".*varhandle.*",
- ".*var-handle.*"
+ ".*var-handle.*",
+ "716-jli-jit-samples"
],
"description": [
- "Tests that use invoke-polymorphic/invoke-custom which is not yet supported by",
+ "Tests for bytecodes introduced after DEX version 037 that are unsupported by",
"dexter/slicer."
],
"bug": "b/37272822",
@@ -733,6 +734,7 @@
"164-resolution-trampoline-dex-cache",
"167-visit-locks",
"168-vmstack-annotated",
+ "172-app-image-twice",
"201-built-in-except-detail-messages",
"203-multi-checkpoint",
"304-method-tracing",
diff --git a/test/run-test b/test/run-test
index 5f85b0875b..be0a88d1f9 100755
--- a/test/run-test
+++ b/test/run-test
@@ -121,6 +121,8 @@ if [ -z "$HIDDENAPI" ]; then
export HIDDENAPI="${ANDROID_HOST_OUT}/bin/hiddenapi"
fi
+chroot=
+
info="info.txt"
build="build"
run="run"
@@ -380,6 +382,16 @@ while true; do
break
fi
shift
+ elif [ "x$1" = "x--chroot" ]; then
+ shift
+ if [ "x$1" = "x" ]; then
+ echo "$0 missing argument to --chroot" 1>&2
+ usage="yes"
+ break
+ fi
+ chroot="$1"
+ run_args="${run_args} --chroot $1"
+ shift
elif [ "x$1" = "x--android-root" ]; then
shift
if [ "x$1" = "x" ]; then
@@ -449,6 +461,9 @@ while true; do
fi
done
+# The DEX_LOCATION with the chroot prefix, if any.
+chroot_dex_location="$chroot$DEX_LOCATION"
+
run_args="${run_args} ${image_args}"
# Allocate file descriptor real_stderr and redirect it to the shell's error
# output (fd 2).
@@ -476,7 +491,7 @@ function err_echo() {
# tmp_dir may be relative, resolve.
#
# Cannot use realpath, as it does not exist on Mac.
-# Cannot us a simple "cd", as the path might not be created yet.
+# Cannot use a simple "cd", as the path might not be created yet.
# Cannot use readlink -m, as it does not exist on Mac.
# Fallback to nuclear option:
noncanonical_tmp_dir=$tmp_dir
@@ -550,7 +565,13 @@ if [ "$target_mode" = "no" ]; then
if [ "$runtime" = "jvm" ]; then
if [ "$prebuild_mode" = "yes" ]; then
err_echo "--prebuild with --jvm is unsupported"
- exit 1;
+ exit 1
+ fi
+ else
+ # ART/Dalvik host mode.
+ if [ -n "$chroot" ]; then
+ err_echo "--chroot with --host is unsupported"
+ exit 1
fi
fi
fi
@@ -628,6 +649,12 @@ if [ "$bisection_search" = "yes" -a "$have_patchoat" = "no" ]; then
usage="yes"
fi
+# TODO: Chroot-based bisection search is not supported yet (see below); implement it.
+if [ "$bisection_search" = "yes" -a -n "$chroot" ]; then
+ err_echo "--chroot with --bisection-search is unsupported"
+ exit 1
+fi
+
if [ "$usage" = "no" ]; then
if [ "x$1" = "x" -o "x$1" = "x-" ]; then
test_dir=`basename "$oldwd"`
@@ -732,6 +759,7 @@ if [ "$usage" = "yes" ]; then
echo " Run with jvmti method redefinition stress testing"
echo " --always-clean Delete the test files even if the test fails."
echo " --never-clean Keep the test files even if the test succeeds."
+ echo " --chroot [newroot] Run with root directory set to newroot."
echo " --android-root [path] The path on target for the android root. (/system by default)."
echo " --dex2oat-swap Use a dex2oat swap file."
echo " --instruction-set-features [string]"
@@ -866,7 +894,7 @@ if [ "$dev_mode" = "yes" ]; then
if [ "$run_exit" = "0" ]; then
if [ "$run_checker" = "yes" ]; then
if [ "$target_mode" = "yes" ]; then
- adb pull $cfg_output_dir/$cfg_output &> /dev/null
+ adb pull "$chroot/$cfg_output_dir/$cfg_output" &> /dev/null
fi
"$checker" $checker_args "$cfg_output" "$tmp_dir" 2>&1
checker_exit="$?"
@@ -888,7 +916,7 @@ elif [ "$update_mode" = "yes" ]; then
"./${run}" $run_args "$@" >"$output" 2>&1
if [ "$run_checker" = "yes" ]; then
if [ "$target_mode" = "yes" ]; then
- adb pull $cfg_output_dir/$cfg_output &> /dev/null
+ adb pull "$chroot/$cfg_output_dir/$cfg_output" &> /dev/null
fi
"$checker" -q $checker_args "$cfg_output" "$tmp_dir" >> "$output" 2>&1
fi
@@ -926,7 +954,7 @@ else
good_run="no"
elif [ "$run_checker" = "yes" ]; then
if [ "$target_mode" = "yes" ]; then
- adb pull $cfg_output_dir/$cfg_output &> /dev/null
+ adb pull "$chroot/$cfg_output_dir/$cfg_output" &> /dev/null
fi
"$checker" -q $checker_args "$cfg_output" "$tmp_dir" >> "$output" 2>&1
checker_exit="$?"
@@ -986,6 +1014,7 @@ fi
) 2>&${real_stderr} 1>&2
# Attempt bisection only if the test failed.
+# TODO: Implement support for chroot-based bisection search.
if [ "$bisection_search" = "yes" -a "$good" != "yes" ]; then
# Bisecting works by skipping different optimization passes which breaks checker assertions.
if [ "$run_checker" == "yes" ]; then
@@ -997,17 +1026,18 @@ if [ "$bisection_search" = "yes" -a "$good" != "yes" ]; then
maybe_device_mode=""
raw_cmd=""
if [ "$target_mode" = "yes" ]; then
- # Produce cmdline.sh in $DEX_LOCATION. "$@" is passed as a runtime option
+ # Produce cmdline.sh in $chroot_dex_location. "$@" is passed as a runtime option
# so that cmdline.sh forwards its arguments to dalvikvm. invoke-with is set
# to exec in order to preserve pid when calling dalvikvm. This is required
# for bisection search to correctly retrieve logs from device.
"./${run}" $run_args --runtime-option '"$@"' --invoke-with exec --dry-run "$@" &> /dev/null
- adb shell chmod u+x "$DEX_LOCATION/cmdline.sh"
+ adb shell chmod u+x "$chroot_dex_location/cmdline.sh"
maybe_device_mode="--device"
raw_cmd="$DEX_LOCATION/cmdline.sh"
else
raw_cmd="$cwd/${run} --external-log-tags $run_args $@"
fi
+ # TODO: Pass a `--chroot` option to the bisection_search.py script and use it there.
$ANDROID_BUILD_TOP/art/tools/bisection_search/bisection_search.py \
$maybe_device_mode \
--raw-cmd="$raw_cmd" \
@@ -1023,7 +1053,7 @@ if [ "$always_clean" = "yes" -o "$good" = "yes" ] && [ "$never_clean" = "no" ];
cd "$oldwd"
rm -rf "$tmp_dir"
if [ "$target_mode" = "yes" -a "$build_exit" = "0" ]; then
- adb shell rm -rf $DEX_LOCATION
+ adb shell rm -rf $chroot_dex_location
fi
if [ "$good" = "yes" ]; then
exit 0
@@ -1040,7 +1070,7 @@ fi
else
echo "${TEST_NAME} files left in ${tmp_dir} on host"
if [ "$target_mode" == "yes" ]; then
- echo "and in ${DEX_LOCATION} on target"
+ echo "and in ${chroot_dex_location} on target"
fi
fi
diff --git a/test/testrunner/env.py b/test/testrunner/env.py
index 7564f5a6b4..0c1c308218 100644
--- a/test/testrunner/env.py
+++ b/test/testrunner/env.py
@@ -91,6 +91,8 @@ HOST_2ND_ARCH_PREFIX = _get_build_var('HOST_2ND_ARCH_PREFIX')
HOST_2ND_ARCH_PREFIX_DEX2OAT_HOST_INSTRUCTION_SET_FEATURES = _env.get(
HOST_2ND_ARCH_PREFIX + 'DEX2OAT_HOST_INSTRUCTION_SET_FEATURES')
+ART_TEST_CHROOT = _env.get('ART_TEST_CHROOT')
+
ART_TEST_ANDROID_ROOT = _env.get('ART_TEST_ANDROID_ROOT')
ART_TEST_WITH_STRACE = _getEnvBoolean('ART_TEST_DEBUG_GC', False)
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index 88b509d3b7..254ffc9db1 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -320,6 +320,9 @@ def run_tests(tests):
if env.ART_TEST_BISECTION:
options_all += ' --bisection-search'
+ if env.ART_TEST_CHROOT:
+ options_all += ' --chroot ' + env.ART_TEST_CHROOT
+
if env.ART_TEST_ANDROID_ROOT:
options_all += ' --android-root ' + env.ART_TEST_ANDROID_ROOT
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index 31bddd5213..10eb9360af 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -83,6 +83,10 @@ elif [[ $mode == "target" ]]; then
make_command+=" debuggerd su"
make_command+=" ${out_dir}/host/linux-x86/bin/adb libstdc++ "
make_command+=" ${out_dir}/target/product/${TARGET_PRODUCT}/system/etc/public.libraries.txt"
+ if [[ -n "$ART_TEST_CHROOT" ]]; then
+ # These targets are needed for the chroot environment.
+ make_command+=" crash_dump event-log-tags"
+ fi
mode_suffix="-target"
fi
diff --git a/tools/cleanup-buildbot-device.sh b/tools/cleanup-buildbot-device.sh
new file mode 100755
index 0000000000..53072ae7c5
--- /dev/null
+++ b/tools/cleanup-buildbot-device.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+green='\033[0;32m'
+nc='\033[0m'
+
+# Setup as root, as device cleanup requires it.
+adb root
+adb wait-for-device
+
+if [[ -n "$ART_TEST_CHROOT" ]]; then
+ # Check that ART_TEST_CHROOT is correctly defined.
+ if [[ "x$ART_TEST_CHROOT" != x/* ]]; then
+ echo "$ART_TEST_CHROOT is not an absolute path"
+ exit 1
+ fi
+
+ echo -e "${green}Clean up /system in chroot${nc}"
+ # Remove all files under /system except the potential property_contexts file.
+ #
+ # The current ART Buildbot set-up runs the "setup device" step
+ # (performed by script tools/setup-buildbot-device.sh) before the
+ # "device cleanup" step (implemented by this script). As
+ # property_contexts file aliases are created during the former step,
+ # we need this exception to prevent the property_contexts file under
+ # /system in the chroot from being removed by the latter step.
+ #
+ # TODO: Reorder ART Buildbot steps so that "device cleanup" happens
+ # before "setup device" and remove this special case.
+ #
+ # TODO: Also consider adding a "tear down device" step on the ART
+ # Buildbot (at the very end of a build) undoing (some of) the work
+ # done in the "device setup" step.
+ adb shell find "$ART_TEST_CHROOT/system" \
+ ! -path "$ART_TEST_CHROOT/system/etc/selinux/plat_property_contexts" \
+ ! -type d \
+ -exec rm -f \{\} +
+
+ echo -e "${green}Clean up some subdirs in /data in chroot${nc}"
+ adb shell rm -rf \
+ "$ART_TEST_CHROOT/data/local/tmp/*" \
+ "$ART_TEST_CHROOT/data/art-test" \
+ "$ART_TEST_CHROOT/data/nativetest" \
+ "$ART_TEST_CHROOT/data/nativetest64" \
+ "$ART_TEST_CHROOT/data/run-test" \
+ "$ART_TEST_CHROOT/data/dalvik-cache/*" \
+ "$ART_TEST_CHROOT/data/misc/trace/*"
+else
+ adb shell rm -rf \
+ /data/local/tmp /data/art-test /data/nativetest /data/nativetest64 '/data/misc/trace/*'
+fi
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index 56d412bfa0..d376cad9da 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -68,6 +68,8 @@ test="org.apache.harmony.jpda.tests.share.AllTests"
mode="target"
# Use JIT compiling by default.
use_jit=true
+# Don't use chroot by default.
+use_chroot=false
variant_cmdline_parameter="--variant=X32"
dump_command="/bin/true"
# Timeout of JDWP test in ms.
@@ -110,6 +112,15 @@ while true; do
# We don't care about jit with the RI
use_jit=false
shift
+ elif [[ "$1" == "--chroot" ]]; then
+ use_chroot=true
+ # Adjust settings for chroot environment.
+ art="/system/bin/art"
+ art_debugee="sh /system/bin/art"
+ vm_command="--vm-command=$art"
+ device_dir="--device-dir=/tmp"
+ # Shift the "--chroot" flag and its argument.
+ shift 2
elif [[ $1 == --test-timeout-ms ]]; then
# Remove the --test-timeout-ms from the arguments.
args=${args/$1}
@@ -191,6 +202,12 @@ while true; do
fi
done
+if $use_chroot && [[ $mode == "host" ]]; then
+ # Chroot-based testing is not supported on host.
+ echo "Cannot use --chroot with --mode=host"
+ exit 1
+fi
+
if [[ $has_gdb = "yes" ]]; then
if [[ $explicit_debug = "no" ]]; then
debug="yes"
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 26b5c0a09b..3537c1b861 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -104,10 +104,14 @@ vogar_args=$@
gcstress=false
debug=false
+# Don't use device mode by default.
+device_mode=false
+# Don't use chroot by default.
+use_chroot=false
+
while true; do
if [[ "$1" == "--mode=device" ]]; then
- vogar_args="$vogar_args --device-dir=/data/local/tmp"
- vogar_args="$vogar_args --vm-command=$android_root/bin/art"
+ device_mode=true
vogar_args="$vogar_args --vm-arg -Ximage:/data/art-test/core.art"
shift
elif [[ "$1" == "--mode=host" ]]; then
@@ -131,6 +135,10 @@ while true; do
elif [[ "$1" == "-Xgc:gcstress" ]]; then
gcstress=true
shift
+ elif [[ "$1" == "--chroot" ]]; then
+ use_chroot=true
+ # Shift the "--chroot" flag and its argument.
+ shift 2
elif [[ "$1" == "" ]]; then
break
else
@@ -138,6 +146,23 @@ while true; do
fi
done
+if $device_mode; then
+ if $use_chroot; then
+ vogar_args="$vogar_args --device-dir=/tmp"
+ vogar_args="$vogar_args --vm-command=/system/bin/art"
+ else
+ vogar_args="$vogar_args --device-dir=/data/local/tmp"
+ vogar_args="$vogar_args --vm-command=$android_root/bin/art"
+ fi
+else
+ # Host mode.
+ if $use_chroot; then
+ # Chroot-based testing is not supported on host.
+ echo "Cannot use --chroot with --mode=host"
+ exit 1
+ fi
+fi
+
# Increase the timeout, as vogar cannot set individual test
# timeout when being asked to run packages, and some tests go above
# the default timeout.
diff --git a/tools/setup-buildbot-device.sh b/tools/setup-buildbot-device.sh
index 5ce7f5244e..f71d973925 100755
--- a/tools/setup-buildbot-device.sh
+++ b/tools/setup-buildbot-device.sh
@@ -17,8 +17,7 @@
green='\033[0;32m'
nc='\033[0m'
-# Setup as root, as the next buildbot step (device cleanup) requires it.
-# This is also required to set the date, if needed.
+# Setup as root, as some actions performed here (e.g. setting the date) requires it.
adb root
adb wait-for-device
@@ -100,3 +99,58 @@ else
processes=$(adb shell "ps" | grep dalvikvm | awk '{print $2}')
for i in $processes; do adb shell kill -9 $i; done
fi
+
+if [[ -n "$ART_TEST_CHROOT" ]]; then
+ # Prepare the chroot dir.
+ echo -e "${green}Prepare the chroot dir in $ART_TEST_CHROOT${nc}"
+
+ # Check that ART_TEST_CHROOT is correctly defined.
+ [[ "x$ART_TEST_CHROOT" = x/* ]] || { echo "$ART_TEST_CHROOT is not an absolute path"; exit 1; }
+
+ # Create chroot.
+ adb shell mkdir -p "$ART_TEST_CHROOT"
+
+ # Provide property_contexts file(s) in chroot.
+ # This is required to have Android system properties work from the chroot.
+ # Notes:
+ # - In Android N, only '/property_contexts' is expected.
+ # - In Android O, property_context files are expected under /system and /vendor.
+ # (See bionic/libc/bionic/system_properties.cpp for more information.)
+ property_context_files="/property_contexts \
+ /system/etc/selinux/plat_property_contexts \
+ /vendor/etc/selinux/nonplat_property_context \
+ /plat_property_contexts \
+ /nonplat_property_contexts"
+ for f in $property_context_files; do
+ adb shell test -f "$f" \
+ "&&" mkdir -p "$ART_TEST_CHROOT$(dirname $f)" \
+ "&&" cp -f "$f" "$ART_TEST_CHROOT$f"
+ done
+
+ # Create directories required for ART testing in chroot.
+ adb shell mkdir -p "$ART_TEST_CHROOT/tmp"
+ adb shell mkdir -p "$ART_TEST_CHROOT/data/dalvik-cache"
+ adb shell mkdir -p "$ART_TEST_CHROOT/data/local/tmp"
+
+ # Populate /etc in chroot with required files.
+ adb shell mkdir -p "$ART_TEST_CHROOT/system/etc"
+ adb shell "cd $ART_TEST_CHROOT && ln -s system/etc etc"
+
+ # Provide /proc in chroot.
+ adb shell mkdir -p "$ART_TEST_CHROOT/proc"
+ adb shell mount | grep -q "^proc on $ART_TEST_CHROOT/proc type proc " \
+ || adb shell mount -t proc proc "$ART_TEST_CHROOT/proc"
+
+ # Provide /sys in chroot.
+ adb shell mkdir -p "$ART_TEST_CHROOT/sys"
+ adb shell mount | grep -q "^sysfs on $ART_TEST_CHROOT/sys type sysfs " \
+ || adb shell mount -t sysfs sysfs "$ART_TEST_CHROOT/sys"
+ # Provide /sys/kernel/debug in chroot.
+ adb shell mount | grep -q "^debugfs on $ART_TEST_CHROOT/sys/kernel/debug type debugfs " \
+ || adb shell mount -t debugfs debugfs "$ART_TEST_CHROOT/sys/kernel/debug"
+
+ # Provide /dev in chroot.
+ adb shell mkdir -p "$ART_TEST_CHROOT/dev"
+ adb shell mount | grep -q "^tmpfs on $ART_TEST_CHROOT/dev type tmpfs " \
+ || adb shell mount -o bind /dev "$ART_TEST_CHROOT/dev"
+fi
diff --git a/tools/veridex/flow_analysis.cc b/tools/veridex/flow_analysis.cc
index 736abb7f17..154c60f6ac 100644
--- a/tools/veridex/flow_analysis.cc
+++ b/tools/veridex/flow_analysis.cc
@@ -112,7 +112,12 @@ void VeriFlowAnalysis::UpdateRegister(uint32_t dex_register, const VeriClass* cl
RegisterValue(RegisterSource::kNone, DexFileReference(nullptr, 0), cls);
}
-const RegisterValue& VeriFlowAnalysis::GetRegister(uint32_t dex_register) {
+void VeriFlowAnalysis::UpdateRegister(uint32_t dex_register, int32_t value, const VeriClass* cls) {
+ current_registers_[dex_register] =
+ RegisterValue(RegisterSource::kConstant, value, DexFileReference(nullptr, 0), cls);
+}
+
+const RegisterValue& VeriFlowAnalysis::GetRegister(uint32_t dex_register) const {
return current_registers_[dex_register];
}
@@ -131,6 +136,49 @@ RegisterValue VeriFlowAnalysis::GetFieldType(uint32_t field_index) {
return RegisterValue(RegisterSource::kField, DexFileReference(&dex_file, field_index), cls);
}
+int VeriFlowAnalysis::GetBranchFlags(const Instruction& instruction) const {
+ switch (instruction.Opcode()) {
+ #define IF_XX(cond, op) \
+ case Instruction::IF_##cond: { \
+ RegisterValue lhs = GetRegister(instruction.VRegA()); \
+ RegisterValue rhs = GetRegister(instruction.VRegB()); \
+ if (lhs.IsConstant() && rhs.IsConstant()) { \
+ if (lhs.GetConstant() op rhs.GetConstant()) { \
+ return Instruction::kBranch; \
+ } else { \
+ return Instruction::kContinue; \
+ } \
+ } \
+ break; \
+ } \
+ case Instruction::IF_##cond##Z: { \
+ RegisterValue val = GetRegister(instruction.VRegA()); \
+ if (val.IsConstant()) { \
+ if (val.GetConstant() op 0) { \
+ return Instruction::kBranch; \
+ } else { \
+ return Instruction::kContinue; \
+ } \
+ } \
+ break; \
+ }
+
+ IF_XX(EQ, ==);
+ IF_XX(NE, !=);
+ IF_XX(LT, <);
+ IF_XX(LE, <=);
+ IF_XX(GT, >);
+ IF_XX(GE, >=);
+
+ #undef IF_XX
+
+ default:
+ break;
+ }
+
+ return Instruction::FlagsOf(instruction.Opcode());
+}
+
void VeriFlowAnalysis::AnalyzeCode() {
std::vector<uint32_t> work_list;
work_list.push_back(0);
@@ -149,16 +197,17 @@ void VeriFlowAnalysis::AnalyzeCode() {
ProcessDexInstruction(inst);
SetVisited(dex_pc);
- int opcode_flags = Instruction::FlagsOf(inst.Opcode());
- if ((opcode_flags & Instruction::kContinue) != 0) {
- if ((opcode_flags & Instruction::kBranch) != 0) {
+ int branch_flags = GetBranchFlags(inst);
+
+ if ((branch_flags & Instruction::kContinue) != 0) {
+ if ((branch_flags & Instruction::kBranch) != 0) {
uint32_t branch_dex_pc = dex_pc + inst.GetTargetOffset();
if (MergeRegisterValues(branch_dex_pc)) {
work_list.push_back(branch_dex_pc);
}
}
dex_pc += inst.SizeInCodeUnits();
- } else if ((opcode_flags & Instruction::kBranch) != 0) {
+ } else if ((branch_flags & Instruction::kBranch) != 0) {
dex_pc += inst.GetTargetOffset();
DCHECK(IsBranchTarget(dex_pc));
} else {
@@ -178,12 +227,30 @@ void VeriFlowAnalysis::AnalyzeCode() {
void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
switch (instruction.Opcode()) {
- case Instruction::CONST_4:
- case Instruction::CONST_16:
- case Instruction::CONST:
+ case Instruction::CONST_4: {
+ int32_t register_index = instruction.VRegA();
+ int32_t value = instruction.VRegB_11n();
+ UpdateRegister(register_index, value, VeriClass::integer_);
+ break;
+ }
+ case Instruction::CONST_16: {
+ int32_t register_index = instruction.VRegA();
+ int32_t value = instruction.VRegB_21s();
+ UpdateRegister(register_index, value, VeriClass::integer_);
+ break;
+ }
+
+ case Instruction::CONST: {
+ int32_t register_index = instruction.VRegA();
+ int32_t value = instruction.VRegB_31i();
+ UpdateRegister(register_index, value, VeriClass::integer_);
+ break;
+ }
+
case Instruction::CONST_HIGH16: {
int32_t register_index = instruction.VRegA();
- UpdateRegister(register_index, VeriClass::integer_);
+ int32_t value = instruction.VRegB_21h();
+ UpdateRegister(register_index, value, VeriClass::integer_);
break;
}
@@ -243,43 +310,7 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
case Instruction::INVOKE_STATIC:
case Instruction::INVOKE_SUPER:
case Instruction::INVOKE_VIRTUAL: {
- VeriMethod method = resolver_->GetMethod(instruction.VRegB_35c());
- uint32_t args[5];
- instruction.GetVarArgs(args);
- if (method == VeriClass::forName_) {
- RegisterValue value = GetRegister(args[0]);
- last_result_ = RegisterValue(
- value.GetSource(), value.GetDexFileReference(), VeriClass::class_);
- } else if (IsGetField(method)) {
- RegisterValue cls = GetRegister(args[0]);
- RegisterValue name = GetRegister(args[1]);
- field_uses_.push_back(std::make_pair(cls, name));
- last_result_ = GetReturnType(instruction.VRegB_35c());
- } else if (IsGetMethod(method)) {
- RegisterValue cls = GetRegister(args[0]);
- RegisterValue name = GetRegister(args[1]);
- method_uses_.push_back(std::make_pair(cls, name));
- last_result_ = GetReturnType(instruction.VRegB_35c());
- } else if (method == VeriClass::getClass_) {
- RegisterValue obj = GetRegister(args[0]);
- const VeriClass* cls = obj.GetType();
- if (cls != nullptr && cls->GetClassDef() != nullptr) {
- const DexFile::ClassDef* def = cls->GetClassDef();
- last_result_ = RegisterValue(
- RegisterSource::kClass,
- DexFileReference(&resolver_->GetDexFileOf(*cls), def->class_idx_.index_),
- VeriClass::class_);
- } else {
- last_result_ = RegisterValue(
- obj.GetSource(), obj.GetDexFileReference(), VeriClass::class_);
- }
- } else if (method == VeriClass::loadClass_) {
- RegisterValue value = GetRegister(args[1]);
- last_result_ = RegisterValue(
- value.GetSource(), value.GetDexFileReference(), VeriClass::class_);
- } else {
- last_result_ = GetReturnType(instruction.VRegB_35c());
- }
+ last_result_ = AnalyzeInvoke(instruction, /* is_range */ false);
break;
}
@@ -288,7 +319,7 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
case Instruction::INVOKE_STATIC_RANGE:
case Instruction::INVOKE_SUPER_RANGE:
case Instruction::INVOKE_VIRTUAL_RANGE: {
- last_result_ = GetReturnType(instruction.VRegB_3rc());
+ last_result_ = AnalyzeInvoke(instruction, /* is_range */ true);
break;
}
@@ -304,6 +335,8 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
case Instruction::RETURN: {
break;
}
+
+ // If operations will be handled when looking at the control flow.
#define IF_XX(cond) \
case Instruction::IF_##cond: break; \
case Instruction::IF_##cond##Z: break
@@ -315,6 +348,8 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
IF_XX(GT);
IF_XX(GE);
+ #undef IF_XX
+
case Instruction::GOTO:
case Instruction::GOTO_16:
case Instruction::GOTO_32: {
@@ -520,6 +555,7 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
case Instruction::IPUT_BYTE:
case Instruction::IPUT_CHAR:
case Instruction::IPUT_SHORT: {
+ AnalyzeFieldSet(instruction);
break;
}
@@ -530,7 +566,13 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
case Instruction::SGET_BYTE:
case Instruction::SGET_CHAR:
case Instruction::SGET_SHORT: {
- UpdateRegister(instruction.VRegA_22c(), GetFieldType(instruction.VRegC_22c()));
+ uint32_t dest_reg = instruction.VRegA_21c();
+ uint16_t field_index = instruction.VRegB_21c();
+ if (VeriClass::sdkInt_ != nullptr && resolver_->GetField(field_index) == VeriClass::sdkInt_) {
+ UpdateRegister(dest_reg, gTargetSdkVersion, VeriClass::integer_);
+ } else {
+ UpdateRegister(dest_reg, GetFieldType(instruction.VRegC_22c()));
+ }
break;
}
@@ -541,6 +583,7 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
case Instruction::SPUT_BYTE:
case Instruction::SPUT_CHAR:
case Instruction::SPUT_SHORT: {
+ AnalyzeFieldSet(instruction);
break;
}
@@ -613,7 +656,112 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
void VeriFlowAnalysis::Run() {
FindBranches();
+ uint32_t number_of_registers = code_item_accessor_.RegistersSize();
+ uint32_t number_of_parameters = code_item_accessor_.InsSize();
+ std::vector<RegisterValue>& initial_values = *dex_registers_[0].get();
+ for (uint32_t i = 0; i < number_of_parameters; ++i) {
+ initial_values[number_of_registers - number_of_parameters + i] = RegisterValue(
+ RegisterSource::kParameter,
+ i,
+ DexFileReference(&resolver_->GetDexFile(), method_id_),
+ nullptr);
+ }
AnalyzeCode();
}
+static uint32_t GetParameterAt(const Instruction& instruction,
+ bool is_range,
+ uint32_t* args,
+ uint32_t index) {
+ return is_range ? instruction.VRegC() + index : args[index];
+}
+
+RegisterValue FlowAnalysisCollector::AnalyzeInvoke(const Instruction& instruction, bool is_range) {
+ uint32_t id = is_range ? instruction.VRegB_3rc() : instruction.VRegB_35c();
+ VeriMethod method = resolver_->GetMethod(id);
+ uint32_t args[5];
+ if (!is_range) {
+ instruction.GetVarArgs(args);
+ }
+
+ if (method == VeriClass::forName_) {
+ // Class.forName. Fetch the first parameter.
+ RegisterValue value = GetRegister(GetParameterAt(instruction, is_range, args, 0));
+ return RegisterValue(
+ value.GetSource(), value.GetDexFileReference(), VeriClass::class_);
+ } else if (IsGetField(method)) {
+ // Class.getField or Class.getDeclaredField. Fetch the first parameter for the class, and the
+ // second parameter for the field name.
+ RegisterValue cls = GetRegister(GetParameterAt(instruction, is_range, args, 0));
+ RegisterValue name = GetRegister(GetParameterAt(instruction, is_range, args, 1));
+ uses_.push_back(ReflectAccessInfo(cls, name, /* is_method */ false));
+ return GetReturnType(id);
+ } else if (IsGetMethod(method)) {
+ // Class.getMethod or Class.getDeclaredMethod. Fetch the first parameter for the class, and the
+ // second parameter for the field name.
+ RegisterValue cls = GetRegister(GetParameterAt(instruction, is_range, args, 0));
+ RegisterValue name = GetRegister(GetParameterAt(instruction, is_range, args, 1));
+ uses_.push_back(ReflectAccessInfo(cls, name, /* is_method */ true));
+ return GetReturnType(id);
+ } else if (method == VeriClass::getClass_) {
+ // Get the type of the first parameter.
+ RegisterValue obj = GetRegister(GetParameterAt(instruction, is_range, args, 0));
+ const VeriClass* cls = obj.GetType();
+ if (cls != nullptr && cls->GetClassDef() != nullptr) {
+ const DexFile::ClassDef* def = cls->GetClassDef();
+ return RegisterValue(
+ RegisterSource::kClass,
+ DexFileReference(&resolver_->GetDexFileOf(*cls), def->class_idx_.index_),
+ VeriClass::class_);
+ } else {
+ return RegisterValue(
+ obj.GetSource(), obj.GetDexFileReference(), VeriClass::class_);
+ }
+ } else if (method == VeriClass::loadClass_) {
+ // ClassLoader.loadClass. Fetch the first parameter.
+ RegisterValue value = GetRegister(GetParameterAt(instruction, is_range, args, 1));
+ return RegisterValue(
+ value.GetSource(), value.GetDexFileReference(), VeriClass::class_);
+ } else {
+ // Return a RegisterValue referencing the method whose type is the return type
+ // of the method.
+ return GetReturnType(id);
+ }
+}
+
+void FlowAnalysisCollector::AnalyzeFieldSet(const Instruction& instruction ATTRIBUTE_UNUSED) {
+ // There are no fields that escape reflection uses.
+}
+
+RegisterValue FlowAnalysisSubstitutor::AnalyzeInvoke(const Instruction& instruction,
+ bool is_range) {
+ uint32_t id = is_range ? instruction.VRegB_3rc() : instruction.VRegB_35c();
+ MethodReference method(&resolver_->GetDexFile(), id);
+ // TODO: doesn't work for multidex
+ // TODO: doesn't work for overriding (but maybe should be done at a higher level);
+ if (accesses_.find(method) == accesses_.end()) {
+ return GetReturnType(id);
+ }
+ uint32_t args[5];
+ if (!is_range) {
+ instruction.GetVarArgs(args);
+ }
+ for (const ReflectAccessInfo& info : accesses_.at(method)) {
+ if (info.cls.IsParameter() || info.name.IsParameter()) {
+ RegisterValue cls = info.cls.IsParameter()
+ ? GetRegister(GetParameterAt(instruction, is_range, args, info.cls.GetParameterIndex()))
+ : info.cls;
+ RegisterValue name = info.name.IsParameter()
+ ? GetRegister(GetParameterAt(instruction, is_range, args, info.name.GetParameterIndex()))
+ : info.name;
+ uses_.push_back(ReflectAccessInfo(cls, name, info.is_method));
+ }
+ }
+ return GetReturnType(id);
+}
+
+void FlowAnalysisSubstitutor::AnalyzeFieldSet(const Instruction& instruction ATTRIBUTE_UNUSED) {
+ // TODO: analyze field sets.
+}
+
} // namespace art
diff --git a/tools/veridex/flow_analysis.h b/tools/veridex/flow_analysis.h
index 80ae5fc9df..fc093600c3 100644
--- a/tools/veridex/flow_analysis.h
+++ b/tools/veridex/flow_analysis.h
@@ -21,13 +21,11 @@
#include "dex/dex_file_reference.h"
#include "dex/method_reference.h"
#include "hidden_api.h"
+#include "resolver.h"
#include "veridex.h"
namespace art {
-class VeridexClass;
-class VeridexResolver;
-
/**
* The source where a dex register comes from.
*/
@@ -37,6 +35,7 @@ enum class RegisterSource {
kMethod,
kClass,
kString,
+ kConstant,
kNone
};
@@ -45,13 +44,34 @@ enum class RegisterSource {
*/
class RegisterValue {
public:
- RegisterValue() : source_(RegisterSource::kNone), reference_(nullptr, 0), type_(nullptr) {}
+ RegisterValue() : source_(RegisterSource::kNone),
+ value_(0),
+ reference_(nullptr, 0),
+ type_(nullptr) {}
RegisterValue(RegisterSource source, DexFileReference reference, const VeriClass* type)
- : source_(source), reference_(reference), type_(type) {}
+ : source_(source), value_(0), reference_(reference), type_(type) {}
+
+ RegisterValue(RegisterSource source,
+ uint32_t value,
+ DexFileReference reference,
+ const VeriClass* type)
+ : source_(source), value_(value), reference_(reference), type_(type) {}
RegisterSource GetSource() const { return source_; }
DexFileReference GetDexFileReference() const { return reference_; }
const VeriClass* GetType() const { return type_; }
+ uint32_t GetParameterIndex() const {
+ CHECK(IsParameter());
+ return value_;
+ }
+ uint32_t GetConstant() const {
+ CHECK(IsConstant());
+ return value_;
+ }
+ bool IsParameter() const { return source_ == RegisterSource::kParameter; }
+ bool IsClass() const { return source_ == RegisterSource::kClass; }
+ bool IsString() const { return source_ == RegisterSource::kString; }
+ bool IsConstant() const { return source_ == RegisterSource::kConstant; }
std::string ToString() const {
switch (source_) {
@@ -68,6 +88,8 @@ class RegisterValue {
}
case RegisterSource::kClass:
return reference_.dex_file->StringByTypeIdx(dex::TypeIndex(reference_.index));
+ case RegisterSource::kParameter:
+ return std::string("Parameter of ") + reference_.dex_file->PrettyMethod(reference_.index);
default:
return "<unknown>";
}
@@ -75,6 +97,7 @@ class RegisterValue {
private:
RegisterSource source_;
+ uint32_t value_;
DexFileReference reference_;
const VeriClass* type_;
};
@@ -85,22 +108,18 @@ struct InstructionInfo {
class VeriFlowAnalysis {
public:
- VeriFlowAnalysis(VeridexResolver* resolver,
- const CodeItemDataAccessor& code_item_accessor)
+ VeriFlowAnalysis(VeridexResolver* resolver, const ClassDataItemIterator& it)
: resolver_(resolver),
- code_item_accessor_(code_item_accessor),
- dex_registers_(code_item_accessor.InsnsSizeInCodeUnits()),
- instruction_infos_(code_item_accessor.InsnsSizeInCodeUnits()) {}
+ method_id_(it.GetMemberIndex()),
+ code_item_accessor_(resolver->GetDexFile(), it.GetMethodCodeItem()),
+ dex_registers_(code_item_accessor_.InsnsSizeInCodeUnits()),
+ instruction_infos_(code_item_accessor_.InsnsSizeInCodeUnits()) {}
void Run();
- const std::vector<std::pair<RegisterValue, RegisterValue>>& GetFieldUses() const {
- return field_uses_;
- }
-
- const std::vector<std::pair<RegisterValue, RegisterValue>>& GetMethodUses() const {
- return method_uses_;
- }
+ virtual RegisterValue AnalyzeInvoke(const Instruction& instruction, bool is_range) = 0;
+ virtual void AnalyzeFieldSet(const Instruction& instruction) = 0;
+ virtual ~VeriFlowAnalysis() {}
private:
// Find all branches in the code.
@@ -124,14 +143,22 @@ class VeriFlowAnalysis {
uint32_t dex_register, RegisterSource kind, VeriClass* cls, uint32_t source_id);
void UpdateRegister(uint32_t dex_register, const RegisterValue& value);
void UpdateRegister(uint32_t dex_register, const VeriClass* cls);
- const RegisterValue& GetRegister(uint32_t dex_register);
+ void UpdateRegister(uint32_t dex_register, int32_t value, const VeriClass* cls);
void ProcessDexInstruction(const Instruction& inst);
void SetVisited(uint32_t dex_pc);
- RegisterValue GetReturnType(uint32_t method_index);
RegisterValue GetFieldType(uint32_t field_index);
+ int GetBranchFlags(const Instruction& instruction) const;
+
+ protected:
+ const RegisterValue& GetRegister(uint32_t dex_register) const;
+ RegisterValue GetReturnType(uint32_t method_index);
+
VeridexResolver* resolver_;
- const CodeItemDataAccessor& code_item_accessor_;
+
+ private:
+ const uint32_t method_id_;
+ CodeItemDataAccessor code_item_accessor_;
// Vector of register values for all branch targets.
std::vector<std::unique_ptr<std::vector<RegisterValue>>> dex_registers_;
@@ -144,12 +171,59 @@ class VeriFlowAnalysis {
// The value of invoke instructions, to be fetched when visiting move-result.
RegisterValue last_result_;
+};
+
+struct ReflectAccessInfo {
+ RegisterValue cls;
+ RegisterValue name;
+ bool is_method;
+
+ ReflectAccessInfo(RegisterValue c, RegisterValue n, bool m) : cls(c), name(n), is_method(m) {}
- // List of reflection field uses found.
- std::vector<std::pair<RegisterValue, RegisterValue>> field_uses_;
+ bool IsConcrete() const {
+ // We capture RegisterSource::kString for the class, for example in Class.forName.
+ return (cls.IsClass() || cls.IsString()) && name.IsString();
+ }
+};
+
+// Collects all reflection uses.
+class FlowAnalysisCollector : public VeriFlowAnalysis {
+ public:
+ FlowAnalysisCollector(VeridexResolver* resolver, const ClassDataItemIterator& it)
+ : VeriFlowAnalysis(resolver, it) {}
+
+ const std::vector<ReflectAccessInfo>& GetUses() const {
+ return uses_;
+ }
+
+ RegisterValue AnalyzeInvoke(const Instruction& instruction, bool is_range) OVERRIDE;
+ void AnalyzeFieldSet(const Instruction& instruction) OVERRIDE;
+
+ private:
+ // List of reflection uses found, concrete and abstract.
+ std::vector<ReflectAccessInfo> uses_;
+};
+
+// Substitutes reflection uses by new ones.
+class FlowAnalysisSubstitutor : public VeriFlowAnalysis {
+ public:
+ FlowAnalysisSubstitutor(VeridexResolver* resolver,
+ const ClassDataItemIterator& it,
+ const std::map<MethodReference, std::vector<ReflectAccessInfo>>& accesses)
+ : VeriFlowAnalysis(resolver, it), accesses_(accesses) {}
- // List of reflection method uses found.
- std::vector<std::pair<RegisterValue, RegisterValue>> method_uses_;
+ const std::vector<ReflectAccessInfo>& GetUses() const {
+ return uses_;
+ }
+
+ RegisterValue AnalyzeInvoke(const Instruction& instruction, bool is_range) OVERRIDE;
+ void AnalyzeFieldSet(const Instruction& instruction) OVERRIDE;
+
+ private:
+ // List of reflection uses found, concrete and abstract.
+ std::vector<ReflectAccessInfo> uses_;
+ // The abstract uses we are trying to subsititute.
+ const std::map<MethodReference, std::vector<ReflectAccessInfo>>& accesses_;
};
} // namespace art
diff --git a/tools/veridex/precise_hidden_api_finder.cc b/tools/veridex/precise_hidden_api_finder.cc
index 4ae5769014..89754c2cdf 100644
--- a/tools/veridex/precise_hidden_api_finder.cc
+++ b/tools/veridex/precise_hidden_api_finder.cc
@@ -29,7 +29,9 @@
namespace art {
-void PreciseHiddenApiFinder::Run(const std::vector<std::unique_ptr<VeridexResolver>>& resolvers) {
+void PreciseHiddenApiFinder::RunInternal(
+ const std::vector<std::unique_ptr<VeridexResolver>>& resolvers,
+ const std::function<void(VeridexResolver*, const ClassDataItemIterator&)>& action) {
for (const std::unique_ptr<VeridexResolver>& resolver : resolvers) {
const DexFile& dex_file = resolver->GetDexFile();
size_t class_def_count = dex_file.NumClassDefs();
@@ -47,43 +49,67 @@ void PreciseHiddenApiFinder::Run(const std::vector<std::unique_ptr<VeridexResolv
if (code_item == nullptr) {
continue;
}
- CodeItemDataAccessor code_item_accessor(dex_file, code_item);
- VeriFlowAnalysis ana(resolver.get(), code_item_accessor);
- ana.Run();
- if (!ana.GetFieldUses().empty()) {
- field_uses_[MethodReference(&dex_file, it.GetMemberIndex())] = ana.GetFieldUses();
- }
- if (!ana.GetMethodUses().empty()) {
- method_uses_[MethodReference(&dex_file, it.GetMemberIndex())] = ana.GetMethodUses();
- }
+ action(resolver.get(), it);
}
}
}
}
+void PreciseHiddenApiFinder::AddUsesAt(const std::vector<ReflectAccessInfo>& accesses,
+ MethodReference ref) {
+ for (const ReflectAccessInfo& info : accesses) {
+ if (info.IsConcrete()) {
+ concrete_uses_[ref].push_back(info);
+ } else {
+ abstract_uses_[ref].push_back(info);
+ }
+ }
+}
+
+void PreciseHiddenApiFinder::Run(const std::vector<std::unique_ptr<VeridexResolver>>& resolvers) {
+ // Collect reflection uses.
+ RunInternal(resolvers, [this] (VeridexResolver* resolver, const ClassDataItemIterator& it) {
+ FlowAnalysisCollector collector(resolver, it);
+ collector.Run();
+ AddUsesAt(collector.GetUses(), MethodReference(&resolver->GetDexFile(), it.GetMemberIndex()));
+ });
+
+ // For non-final reflection uses, do a limited fixed point calculation over the code to try
+ // substituting them with final reflection uses.
+ // We limit the number of times we iterate over the code as one run can be long.
+ static const int kMaximumIterations = 10;
+ uint32_t i = 0;
+ while (!abstract_uses_.empty() && (i++ < kMaximumIterations)) {
+ // Fetch and clear the worklist.
+ std::map<MethodReference, std::vector<ReflectAccessInfo>> current_uses
+ = std::move(abstract_uses_);
+ RunInternal(resolvers,
+ [this, current_uses] (VeridexResolver* resolver, const ClassDataItemIterator& it) {
+ FlowAnalysisSubstitutor substitutor(resolver, it, current_uses);
+ substitutor.Run();
+ AddUsesAt(substitutor.GetUses(),
+ MethodReference(&resolver->GetDexFile(), it.GetMemberIndex()));
+ });
+ }
+}
+
void PreciseHiddenApiFinder::Dump(std::ostream& os, HiddenApiStats* stats) {
static const char* kPrefix = " ";
- std::map<std::string, std::vector<MethodReference>> uses;
- for (auto kinds : { field_uses_, method_uses_ }) {
- for (auto it : kinds) {
- MethodReference ref = it.first;
- for (const std::pair<RegisterValue, RegisterValue>& info : it.second) {
- if ((info.first.GetSource() == RegisterSource::kClass ||
- info.first.GetSource() == RegisterSource::kString) &&
- info.second.GetSource() == RegisterSource::kString) {
- std::string cls(info.first.ToString());
- std::string name(info.second.ToString());
- std::string full_name = cls + "->" + name;
- HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(full_name);
- if (api_list != HiddenApiAccessFlags::kWhitelist) {
- uses[full_name].push_back(ref);
- }
- }
+ std::map<std::string, std::vector<MethodReference>> named_uses;
+ for (auto it : concrete_uses_) {
+ MethodReference ref = it.first;
+ for (const ReflectAccessInfo& info : it.second) {
+ std::string cls(info.cls.ToString());
+ std::string name(info.name.ToString());
+ std::string full_name = cls + "->" + name;
+ HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(full_name);
+ if (api_list != HiddenApiAccessFlags::kWhitelist) {
+ named_uses[full_name].push_back(ref);
}
}
}
- for (auto it : uses) {
+ for (auto it : named_uses) {
++stats->reflection_count;
const std::string& full_name = it.first;
HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(full_name);
diff --git a/tools/veridex/precise_hidden_api_finder.h b/tools/veridex/precise_hidden_api_finder.h
index 22744a6f1f..1c4d0ae84e 100644
--- a/tools/veridex/precise_hidden_api_finder.h
+++ b/tools/veridex/precise_hidden_api_finder.h
@@ -45,9 +45,18 @@ class PreciseHiddenApiFinder {
void Dump(std::ostream& os, HiddenApiStats* stats);
private:
+ // Run over all methods of all dex files, and call `action` on each.
+ void RunInternal(
+ const std::vector<std::unique_ptr<VeridexResolver>>& resolvers,
+ const std::function<void(VeridexResolver*, const ClassDataItemIterator&)>& action);
+
+ // Add uses found in method `ref`.
+ void AddUsesAt(const std::vector<ReflectAccessInfo>& accesses, MethodReference ref);
+
const HiddenApi& hidden_api_;
- std::map<MethodReference, std::vector<std::pair<RegisterValue, RegisterValue>>> field_uses_;
- std::map<MethodReference, std::vector<std::pair<RegisterValue, RegisterValue>>> method_uses_;
+
+ std::map<MethodReference, std::vector<ReflectAccessInfo>> concrete_uses_;
+ std::map<MethodReference, std::vector<ReflectAccessInfo>> abstract_uses_;
};
} // namespace art
diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc
index dc7ea94032..bcd4815a38 100644
--- a/tools/veridex/veridex.cc
+++ b/tools/veridex/veridex.cc
@@ -25,6 +25,7 @@
#include "precise_hidden_api_finder.h"
#include "resolver.h"
+#include <cstdlib>
#include <sstream>
namespace art {
@@ -62,6 +63,7 @@ VeriMethod VeriClass::getMethod_ = nullptr;
VeriMethod VeriClass::getDeclaredMethod_ = nullptr;
VeriMethod VeriClass::getClass_ = nullptr;
VeriMethod VeriClass::loadClass_ = nullptr;
+VeriField VeriClass::sdkInt_ = nullptr;
struct VeridexOptions {
const char* dex_file = nullptr;
@@ -70,6 +72,7 @@ struct VeridexOptions {
const char* light_greylist = nullptr;
const char* dark_greylist = nullptr;
bool precise = true;
+ int target_sdk_version = 28; /* P */
};
static const char* Substr(const char* str, int index) {
@@ -91,6 +94,7 @@ static void ParseArgs(VeridexOptions* options, int argc, char** argv) {
static const char* kDarkGreylistOption = "--dark-greylist=";
static const char* kLightGreylistOption = "--light-greylist=";
static const char* kImprecise = "--imprecise";
+ static const char* kTargetSdkVersion = "--target-sdk-version=";
for (int i = 0; i < argc; ++i) {
if (StartsWith(argv[i], kDexFileOption)) {
@@ -105,6 +109,8 @@ static void ParseArgs(VeridexOptions* options, int argc, char** argv) {
options->light_greylist = Substr(argv[i], strlen(kLightGreylistOption));
} else if (strcmp(argv[i], kImprecise) == 0) {
options->precise = false;
+ } else if (StartsWith(argv[i], kTargetSdkVersion)) {
+ options->target_sdk_version = atoi(Substr(argv[i], strlen(kTargetSdkVersion)));
}
}
}
@@ -124,6 +130,7 @@ class Veridex {
static int Run(int argc, char** argv) {
VeridexOptions options;
ParseArgs(&options, argc, argv);
+ gTargetSdkVersion = options.target_sdk_version;
std::vector<std::string> boot_content;
std::vector<std::string> app_content;
@@ -200,6 +207,11 @@ class Veridex {
VeriClass::loadClass_ = boot_resolvers[0]->LookupDeclaredMethodIn(
*VeriClass::class_loader_, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+ VeriClass* version = type_map["Landroid/os/Build$VERSION;"];
+ if (version != nullptr) {
+ VeriClass::sdkInt_ = boot_resolvers[0]->LookupFieldIn(*version, "SDK_INT", "I");
+ }
+
std::vector<std::unique_ptr<VeridexResolver>> app_resolvers;
Resolve(app_dex_files, resolver_map, type_map, &app_resolvers);
diff --git a/tools/veridex/veridex.h b/tools/veridex/veridex.h
index 9c0a158174..31ddbf439e 100644
--- a/tools/veridex/veridex.h
+++ b/tools/veridex/veridex.h
@@ -24,6 +24,8 @@
namespace art {
+static int gTargetSdkVersion = 1000; // Will be initialized after parsing options.
+
/**
* Abstraction for fields defined in dex files. Currently, that's a pointer into their
* `encoded_field` description.
@@ -86,6 +88,8 @@ class VeriClass {
static VeriMethod getClass_;
static VeriMethod loadClass_;
+ static VeriField sdkInt_;
+
private:
Primitive::Type kind_;
uint8_t dimensions_;