summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/art.go13
-rw-r--r--cmdline/cmdline_parser_test.cc4
-rw-r--r--cmdline/cmdline_types.h4
-rw-r--r--compiler/common_compiler_test.cc2
-rw-r--r--compiler/dex/dex_to_dex_compiler.cc2
-rw-r--r--compiler/dex/inline_method_analyser.cc7
-rw-r--r--compiler/dex/verification_results.cc5
-rw-r--r--compiler/driver/compiled_method_storage.cc2
-rw-r--r--compiler/driver/compiler_driver.cc315
-rw-r--r--compiler/driver/compiler_driver_test.cc10
-rw-r--r--compiler/elf_writer_quick.cc2
-rw-r--r--compiler/image_writer.h2
-rw-r--r--compiler/jit/jit_compiler.cc10
-rw-r--r--compiler/optimizing/code_generator.cc53
-rw-r--r--compiler/optimizing/code_generator.h14
-rw-r--r--compiler/optimizing/code_generator_arm.cc59
-rw-r--r--compiler/optimizing/code_generator_arm.h7
-rw-r--r--compiler/optimizing/code_generator_arm64.cc72
-rw-r--r--compiler/optimizing/code_generator_arm64.h7
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc87
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.h7
-rw-r--r--compiler/optimizing/code_generator_mips.cc65
-rw-r--r--compiler/optimizing/code_generator_mips.h6
-rw-r--r--compiler/optimizing/code_generator_mips64.cc63
-rw-r--r--compiler/optimizing/code_generator_mips64.h9
-rw-r--r--compiler/optimizing/code_generator_vector_mips64.cc642
-rw-r--r--compiler/optimizing/code_generator_x86.cc62
-rw-r--r--compiler/optimizing/code_generator_x86.h7
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc53
-rw-r--r--compiler/optimizing/code_generator_x86_64.h7
-rw-r--r--compiler/optimizing/induction_var_range.cc24
-rw-r--r--compiler/optimizing/inliner.cc2
-rw-r--r--compiler/optimizing/instruction_builder.cc2
-rw-r--r--compiler/optimizing/intrinsics.cc2
-rw-r--r--compiler/optimizing/intrinsics_arm.cc55
-rw-r--r--compiler/optimizing/intrinsics_arm64.cc74
-rw-r--r--compiler/optimizing/intrinsics_arm_vixl.cc62
-rw-r--r--compiler/optimizing/intrinsics_mips.cc9
-rw-r--r--compiler/optimizing/intrinsics_mips64.cc9
-rw-r--r--compiler/optimizing/intrinsics_utils.h5
-rw-r--r--compiler/optimizing/intrinsics_x86.cc63
-rw-r--r--compiler/optimizing/intrinsics_x86_64.cc63
-rw-r--r--compiler/optimizing/loop_optimization.cc47
-rw-r--r--compiler/optimizing/loop_optimization.h1
-rw-r--r--compiler/optimizing/nodes.cc20
-rw-r--r--compiler/optimizing/nodes.h55
-rw-r--r--compiler/optimizing/register_allocator_graph_color.cc2
-rw-r--r--compiler/optimizing/scheduler_arm.cc5
-rw-r--r--compiler/optimizing/scheduler_arm.h5
-rw-r--r--compiler/optimizing/scheduler_arm64.cc151
-rw-r--r--compiler/optimizing/scheduler_arm64.h79
-rw-r--r--compiler/optimizing/sharpening.cc14
-rw-r--r--compiler/utils/dedupe_set_test.cc2
-rw-r--r--compiler/utils/mips64/assembler_mips64.cc111
-rw-r--r--compiler/utils/mips64/assembler_mips64.h23
-rw-r--r--compiler/utils/mips64/assembler_mips64_test.cc100
-rw-r--r--compiler/utils/swap_space.cc2
-rw-r--r--dex2oat/dex2oat.cc11
-rw-r--r--dex2oat/dex2oat_test.cc5
-rw-r--r--dexlayout/dex_visualize.cc2
-rw-r--r--dexlayout/dexlayout.cc4
-rw-r--r--dexlayout/dexlayout_test.cc20
-rw-r--r--disassembler/disassembler_mips.cc6
-rw-r--r--imgdiag/imgdiag_test.cc1
-rw-r--r--oatdump/oatdump.cc1
-rw-r--r--profman/profile_assistant_test.cc144
-rw-r--r--profman/profman.cc97
-rw-r--r--runtime/Android.bp2
-rw-r--r--runtime/arch/arm/context_arm.cc2
-rw-r--r--runtime/arch/arm/fault_handler_arm.cc2
-rw-r--r--runtime/arch/arm64/context_arm64.cc2
-rw-r--r--runtime/arch/arm64/fault_handler_arm64.cc2
-rw-r--r--runtime/arch/mips/fault_handler_mips.cc2
-rw-r--r--runtime/arch/mips/instruction_set_features_mips.cc63
-rw-r--r--runtime/arch/mips/instruction_set_features_mips.h12
-rw-r--r--runtime/arch/mips/instruction_set_features_mips_test.cc98
-rw-r--r--runtime/arch/mips64/fault_handler_mips64.cc2
-rw-r--r--runtime/arch/x86/fault_handler_x86.cc2
-rw-r--r--runtime/arch/x86/thread_x86.cc2
-rw-r--r--runtime/arch/x86_64/thread_x86_64.cc2
-rw-r--r--runtime/art_field-inl.h2
-rw-r--r--runtime/art_method-inl.h9
-rw-r--r--runtime/art_method.h23
-rw-r--r--runtime/asm_support.h1
-rw-r--r--runtime/atomic.cc2
-rw-r--r--runtime/atomic.h7
-rw-r--r--runtime/barrier_test.cc2
-rw-r--r--runtime/base/arena_allocator.cc2
-rw-r--r--runtime/base/dumpable-inl.h2
-rw-r--r--runtime/base/histogram-inl.h2
-rw-r--r--runtime/base/logging.cc2
-rw-r--r--runtime/base/mutex-inl.h33
-rw-r--r--runtime/base/mutex.h32
-rw-r--r--runtime/base/mutex_test.cc4
-rw-r--r--runtime/base/timing_logger.cc3
-rw-r--r--runtime/check_reference_map_visitor.h1
-rw-r--r--runtime/class_linker.cc126
-rw-r--r--runtime/class_linker.h11
-rw-r--r--runtime/class_linker_test.cc2
-rw-r--r--runtime/class_table-inl.h6
-rw-r--r--runtime/class_table.cc2
-rw-r--r--runtime/debugger.cc58
-rw-r--r--runtime/dex_cache_resolved_classes.h11
-rw-r--r--runtime/dex_file.h1
-rw-r--r--runtime/dex_file_test.cc2
-rw-r--r--runtime/dex_file_tracking_registrar.cc52
-rw-r--r--runtime/dex_file_tracking_registrar.h32
-rw-r--r--runtime/dex_file_verifier_test.cc2
-rw-r--r--runtime/dex_method_iterator_test.cc2
-rw-r--r--runtime/entrypoints/jni/jni_entrypoints.cc7
-rw-r--r--runtime/entrypoints/quick/callee_save_frame.h9
-rw-r--r--runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc2
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc3
-rw-r--r--runtime/fault_handler.cc2
-rw-r--r--runtime/gc/accounting/bitmap.h1
-rw-r--r--runtime/gc/accounting/heap_bitmap.h1
-rw-r--r--runtime/gc/accounting/mod_union_table.cc2
-rw-r--r--runtime/gc/accounting/mod_union_table_test.cc2
-rw-r--r--runtime/gc/accounting/remembered_set.h1
-rw-r--r--runtime/gc/accounting/space_bitmap.h4
-rw-r--r--runtime/gc/allocation_listener.h1
-rw-r--r--runtime/gc/allocation_record.cc1
-rw-r--r--runtime/gc/allocation_record.h2
-rw-r--r--runtime/gc/allocator/rosalloc.cc2
-rw-r--r--runtime/gc/collector/concurrent_copying.cc9
-rw-r--r--runtime/gc/collector/concurrent_copying.h6
-rw-r--r--runtime/gc/collector/garbage_collector.cc3
-rw-r--r--runtime/gc/collector/immune_spaces_test.cc2
-rw-r--r--runtime/gc/collector/mark_compact.cc2
-rw-r--r--runtime/gc/collector/mark_compact.h1
-rw-r--r--runtime/gc/collector/mark_sweep.cc4
-rw-r--r--runtime/gc/collector/mark_sweep.h1
-rw-r--r--runtime/gc/collector/partial_mark_sweep.cc2
-rw-r--r--runtime/gc/collector/semi_space.h1
-rw-r--r--runtime/gc/collector/sticky_mark_sweep.cc3
-rw-r--r--runtime/gc/heap.h5
-rw-r--r--runtime/gc/heap_verification_test.cc2
-rw-r--r--runtime/gc/reference_processor-inl.h2
-rw-r--r--runtime/gc/reference_processor.cc1
-rw-r--r--runtime/gc/reference_processor.h2
-rw-r--r--runtime/gc/reference_queue.cc1
-rw-r--r--runtime/gc/reference_queue.h4
-rw-r--r--runtime/gc/scoped_gc_critical_section.cc2
-rw-r--r--runtime/gc/space/bump_pointer_space.h9
-rw-r--r--runtime/gc/space/dlmalloc_space.cc1
-rw-r--r--runtime/gc/space/large_object_space.cc2
-rw-r--r--runtime/gc/space/region_space-inl.h2
-rw-r--r--runtime/gc/space/region_space.cc27
-rw-r--r--runtime/gc/space/region_space.h6
-rw-r--r--runtime/gc/space/rosalloc_space.cc1
-rw-r--r--runtime/gc/space/space.cc2
-rw-r--r--runtime/gc/space/zygote_space.cc4
-rw-r--r--runtime/gc/task_processor_test.cc2
-rw-r--r--runtime/handle_scope-inl.h2
-rw-r--r--runtime/imtable_test.cc2
-rw-r--r--runtime/indirect_reference_table.cc55
-rw-r--r--runtime/indirect_reference_table.h8
-rw-r--r--runtime/instrumentation.cc125
-rw-r--r--runtime/instrumentation.h106
-rw-r--r--runtime/instrumentation_test.cc182
-rw-r--r--runtime/intern_table.cc2
-rw-r--r--runtime/intern_table.h3
-rw-r--r--runtime/intern_table_test.cc1
-rw-r--r--runtime/interpreter/interpreter.cc7
-rw-r--r--runtime/interpreter/interpreter_common.cc1
-rw-r--r--runtime/interpreter/interpreter_switch_impl.cc2
-rw-r--r--runtime/interpreter/unstarted_runtime.cc2
-rw-r--r--runtime/invoke_type.h2
-rw-r--r--runtime/java_vm_ext.cc81
-rw-r--r--runtime/java_vm_ext.h1
-rw-r--r--runtime/jdwp/jdwp_adb.cc2
-rw-r--r--runtime/jdwp/jdwp_handler.cc2
-rw-r--r--runtime/jit/debugger_interface.cc2
-rw-r--r--runtime/jit/jit.cc2
-rw-r--r--runtime/jit/jit.h1
-rw-r--r--runtime/jit/jit_code_cache.cc3
-rw-r--r--runtime/jit/jit_code_cache.h3
-rw-r--r--runtime/jit/profile_compilation_info.cc200
-rw-r--r--runtime/jit/profile_compilation_info.h126
-rw-r--r--runtime/jit/profile_compilation_info_test.cc90
-rw-r--r--runtime/jit/profile_saver.cc67
-rw-r--r--runtime/jit/profile_saver_options.h18
-rw-r--r--runtime/jni_env_ext.cc6
-rw-r--r--runtime/jni_env_ext.h1
-rw-r--r--runtime/jni_internal.cc56
-rw-r--r--runtime/jni_internal.h8
-rw-r--r--runtime/jni_internal_test.cc25
-rw-r--r--runtime/linear_alloc.cc2
-rw-r--r--runtime/managed_stack-inl.h48
-rw-r--r--runtime/managed_stack.cc57
-rw-r--r--runtime/managed_stack.h107
-rw-r--r--runtime/mem_map.cc3
-rw-r--r--runtime/method_handles.h1
-rw-r--r--runtime/mirror/accessible_object.h1
-rw-r--r--runtime/mirror/array.h1
-rw-r--r--runtime/mirror/class-inl.h5
-rw-r--r--runtime/mirror/class.h1
-rw-r--r--runtime/mirror/class_ext.h1
-rw-r--r--runtime/mirror/class_loader-inl.h2
-rw-r--r--runtime/mirror/class_loader.h3
-rw-r--r--runtime/mirror/dex_cache.cc1
-rw-r--r--runtime/mirror/executable.h1
-rw-r--r--runtime/mirror/field.h1
-rw-r--r--runtime/mirror/object-inl.h33
-rw-r--r--runtime/mirror/object-readbarrier-inl.h30
-rw-r--r--runtime/mirror/object-refvisitor-inl.h2
-rw-r--r--runtime/mirror/object.h15
-rw-r--r--runtime/mirror/reference-inl.h8
-rw-r--r--runtime/mirror/reference.h7
-rw-r--r--runtime/mirror/stack_trace_element.cc1
-rw-r--r--runtime/mirror/stack_trace_element.h1
-rw-r--r--runtime/mirror/string.cc2
-rw-r--r--runtime/mirror/string.h1
-rw-r--r--runtime/mirror/throwable.cc14
-rw-r--r--runtime/mirror/throwable.h17
-rw-r--r--runtime/monitor.cc12
-rw-r--r--runtime/monitor.h9
-rw-r--r--runtime/monitor_android.cc130
-rw-r--r--runtime/monitor_linux.cc2
-rw-r--r--runtime/monitor_pool.cc2
-rw-r--r--runtime/monitor_pool_test.cc2
-rw-r--r--runtime/native/dalvik_system_DexFile.cc1
-rw-r--r--runtime/native/dalvik_system_VMDebug.cc1
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc1
-rw-r--r--runtime/native/dalvik_system_VMStack.cc1
-rw-r--r--runtime/native/dalvik_system_ZygoteHooks.cc4
-rw-r--r--runtime/native/java_lang_Class.cc1
-rw-r--r--runtime/native/java_lang_Object.cc1
-rw-r--r--runtime/native/java_lang_String.cc1
-rw-r--r--runtime/native/java_lang_StringFactory.cc1
-rw-r--r--runtime/native/java_lang_System.cc1
-rw-r--r--runtime/native/java_lang_Thread.cc1
-rw-r--r--runtime/native/java_lang_Throwable.cc1
-rw-r--r--runtime/native/java_lang_VMClassLoader.cc1
-rw-r--r--runtime/native/java_lang_Void.cc1
-rw-r--r--runtime/native/java_lang_invoke_MethodHandleImpl.cc1
-rw-r--r--runtime/native/java_lang_ref_FinalizerReference.cc1
-rw-r--r--runtime/native/java_lang_ref_Reference.cc1
-rw-r--r--runtime/native/java_lang_reflect_Array.cc3
-rw-r--r--runtime/native/java_lang_reflect_Constructor.cc1
-rw-r--r--runtime/native/java_lang_reflect_Executable.cc1
-rw-r--r--runtime/native/java_lang_reflect_Field.cc1
-rw-r--r--runtime/native/java_lang_reflect_Method.cc1
-rw-r--r--runtime/native/java_lang_reflect_Parameter.cc1
-rw-r--r--runtime/native/java_lang_reflect_Proxy.cc1
-rw-r--r--runtime/native/java_util_concurrent_atomic_AtomicLong.cc1
-rw-r--r--runtime/native/libcore_util_CharsetUtils.cc1
-rw-r--r--runtime/native/native_util.h45
-rw-r--r--runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc1
-rw-r--r--runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc1
-rw-r--r--runtime/native/sun_misc_Unsafe.cc2
-rw-r--r--runtime/native_stack_dump.cc2
-rw-r--r--runtime/non_debuggable_classes.cc2
-rw-r--r--runtime/oat_file.h5
-rw-r--r--runtime/oat_file_assistant_test.cc2
-rw-r--r--runtime/oat_file_manager.cc13
-rw-r--r--runtime/obj_ptr-inl.h2
-rw-r--r--runtime/openjdkjvmti/OpenjdkJvmTi.cc2
-rw-r--r--runtime/openjdkjvmti/events.cc2
-rw-r--r--runtime/openjdkjvmti/jvmti_weak_table.h2
-rw-r--r--runtime/openjdkjvmti/ti_class.cc2
-rw-r--r--runtime/openjdkjvmti/ti_dump.cc2
-rw-r--r--runtime/openjdkjvmti/ti_field.cc2
-rw-r--r--runtime/openjdkjvmti/ti_heap.cc1
-rw-r--r--runtime/openjdkjvmti/ti_jni.cc2
-rw-r--r--runtime/openjdkjvmti/ti_method.cc2
-rw-r--r--runtime/openjdkjvmti/ti_monitor.cc2
-rw-r--r--runtime/openjdkjvmti/ti_object.cc2
-rw-r--r--runtime/openjdkjvmti/ti_phase.cc2
-rw-r--r--runtime/openjdkjvmti/ti_properties.cc2
-rw-r--r--runtime/openjdkjvmti/ti_redefine.cc30
-rw-r--r--runtime/openjdkjvmti/ti_search.cc2
-rw-r--r--runtime/openjdkjvmti/ti_stack.cc2
-rw-r--r--runtime/openjdkjvmti/ti_thread.cc2
-rw-r--r--runtime/openjdkjvmti/ti_threadgroup.cc2
-rw-r--r--runtime/parsed_options.cc2
-rw-r--r--runtime/read_barrier-inl.h4
-rw-r--r--runtime/reference_table.h1
-rw-r--r--runtime/reference_table_test.cc2
-rw-r--r--runtime/runtime_android.cc6
-rw-r--r--runtime/runtime_common.cc65
-rw-r--r--runtime/runtime_common.h3
-rw-r--r--runtime/runtime_linux.cc8
-rw-r--r--runtime/safe_map.h6
-rw-r--r--runtime/scoped_thread_state_change-inl.h1
-rw-r--r--runtime/stack.cc38
-rw-r--r--runtime/stack.h80
-rw-r--r--runtime/thread-current-inl.h47
-rw-r--r--runtime/thread-inl.h38
-rw-r--r--runtime/thread.cc5
-rw-r--r--runtime/thread.h29
-rw-r--r--runtime/thread_list.cc10
-rw-r--r--runtime/thread_list.h4
-rw-r--r--runtime/thread_pool.cc2
-rw-r--r--runtime/trace.cc29
-rw-r--r--runtime/trace.h48
-rw-r--r--runtime/transaction.cc2
-rw-r--r--runtime/transaction.h1
-rw-r--r--runtime/verifier/method_verifier.cc17
-rw-r--r--runtime/verifier/method_verifier.h6
-rw-r--r--runtime/verifier/reg_type.h1
-rw-r--r--runtime/verifier/reg_type_test.cc2
-rw-r--r--runtime/verifier/verifier_deps.h1
-rw-r--r--runtime/verify_object.h1
-rw-r--r--runtime/well_known_classes.cc2
-rw-r--r--test/003-omnibus-opcodes/src/Main.java2
-rw-r--r--test/008-exceptions/src/Main.java12
-rw-r--r--test/023-many-interfaces/src/ManyInterfaces.java6
-rw-r--r--test/024-illegal-access/src/Main.java10
-rw-r--r--test/031-class-attributes/src/ClassAttrs.java10
-rw-r--r--test/032-concrete-sub/src/ConcreteSub.java2
-rw-r--r--test/032-concrete-sub/src/Main.java2
-rw-r--r--test/036-finalizer/src/Main.java2
-rw-r--r--test/042-new-instance/src/Main.java60
-rw-r--r--test/044-proxy/src/BasicTest.java12
-rw-r--r--test/044-proxy/src/Clash.java4
-rw-r--r--test/044-proxy/src/Clash2.java2
-rw-r--r--test/044-proxy/src/Clash3.java2
-rw-r--r--test/044-proxy/src/Clash4.java2
-rw-r--r--test/044-proxy/src/ConstructorProxy.java2
-rw-r--r--test/044-proxy/src/WrappedThrow.java32
-rw-r--r--test/045-reflect-array/src/Main.java4
-rw-r--r--test/046-reflect/src/Main.java28
-rw-r--r--test/048-reflect-v8/src/DefaultDeclared.java2
-rw-r--r--test/050-sync-test/src/Main.java8
-rw-r--r--test/050-sync-test/src/ThreadDeathHandler.java4
-rw-r--r--test/051-thread/src/Main.java2
-rw-r--r--test/053-wait-some/src/Main.java4
-rw-r--r--test/054-uncaught/src/Main.java4
-rw-r--r--test/054-uncaught/src/ThreadDeathHandler.java4
-rw-r--r--test/059-finalizer-throw/src/Main.java4
-rw-r--r--test/064-field-access/src/Main.java32
-rw-r--r--test/065-mismatched-implements/src/Main.java2
-rw-r--r--test/066-mismatched-super/src/Main.java2
-rw-r--r--test/068-classloader/src/Main.java76
-rw-r--r--test/069-field-type/src/Main.java2
-rw-r--r--test/070-nio-buffer/src/Main.java6
-rw-r--r--test/073-mismatched-field/src/Main.java2
-rw-r--r--test/074-gc-thrash/src/Main.java16
-rw-r--r--test/075-verification-error/src/Main.java18
-rw-r--r--test/077-method-override/src/Main.java8
-rw-r--r--test/079-phantom/src/Main.java2
-rw-r--r--test/084-class-init/src/Main.java14
-rw-r--r--test/086-null-super/src/Main.java8
-rw-r--r--test/088-monitor-verification/src/Main.java2
-rw-r--r--test/092-locale/src/Main.java16
-rw-r--r--test/095-switch-MAX_INT/src/Main.java2
-rw-r--r--test/100-reflect2/src/Main.java4
-rw-r--r--test/101-fibonacci/src/Main.java2
-rw-r--r--test/109-suspend-check/src/Main.java2
-rw-r--r--test/114-ParallelGC/src/Main.java2
-rwxr-xr-xtest/115-native-bridge/check20
-rw-r--r--test/120-hashcode/src/Main.java2
-rw-r--r--test/130-hprof/src/Main.java6
-rw-r--r--test/1337-gc-coverage/gc_coverage.cc2
-rw-r--r--test/135-MirandaDispatch/src/Main.java2
-rw-r--r--test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc2
-rw-r--r--test/138-duplicate-classes-check/src/Main.java2
-rw-r--r--test/138-duplicate-classes-check2/src/Main.java2
-rw-r--r--test/141-class-unload/jni_unload.cc2
-rw-r--r--test/141-class-unload/src/Main.java2
-rw-r--r--test/142-classloader2/src/Main.java2
-rw-r--r--test/146-bad-interface/src/Main.java2
-rw-r--r--test/148-multithread-gc-annotations/gc_coverage.cc2
-rw-r--r--test/155-java-set-resolved-type/src/Main.java2
-rw-r--r--test/156-register-dex-file-multi-loader/src/Main.java2
-rw-r--r--test/158-app-image-class-table/src/Main.java2
-rw-r--r--test/159-app-image-fields/src/Main.java2
-rw-r--r--test/301-abstract-protected/src/Main.java2
-rw-r--r--test/487-checker-inline-calls/src/Main.java2
-rw-r--r--test/488-checker-inline-recursive-calls/src/Main.java2
-rw-r--r--test/492-checker-inline-invoke-interface/src/Main.java2
-rw-r--r--test/493-checker-inline-invoke-interface/src/Main.java2
-rw-r--r--test/497-inlining-and-class-loader/src/Main.java2
-rw-r--r--test/522-checker-regression-monitor-exit/src/Main.java6
-rw-r--r--test/552-checker-sharpening/src/Main.java8
-rw-r--r--test/564-checker-irreducible-loop/smali/IrreducibleLoop.smali4
-rw-r--r--test/570-checker-osr/osr.cc1
-rw-r--r--test/570-checker-osr/src/DeoptimizationController.java4
-rw-r--r--test/588-checker-irreducib-lifetime-hole/smali/IrreducibleLoop.smali8
-rw-r--r--test/595-profile-saving/profile-saving.cc1
-rw-r--r--test/596-app-images/app_images.cc6
-rw-r--r--test/596-app-images/src/Main.java124
-rw-r--r--test/596-monitor-inflation/monitor_inflation.cc2
-rw-r--r--test/602-deoptimizeable/src/Main.java4
-rw-r--r--test/617-clinit-oome/src/Main.java2
-rw-r--r--test/623-checker-loop-regressions/src/Main.java23
-rw-r--r--test/626-const-class-linking/src/RacyMisbehavingHelper.java2
-rw-r--r--test/638-no-line-number/src/Main.java4
-rw-r--r--test/640-checker-boolean-simd/src/Main.java24
-rw-r--r--test/640-checker-byte-simd/src/Main.java42
-rw-r--r--test/640-checker-char-simd/src/Main.java42
-rw-r--r--test/640-checker-double-simd/src/Main.java40
-rw-r--r--test/640-checker-float-simd/src/Main.java42
-rw-r--r--test/640-checker-int-simd/src/Main.java69
-rw-r--r--test/640-checker-long-simd/src/Main.java67
-rw-r--r--test/640-checker-short-simd/src/Main.java42
-rw-r--r--test/645-checker-abs-simd/src/Main.java72
-rw-r--r--test/646-checker-hadd-alt-byte/src/Main.java44
-rw-r--r--test/646-checker-hadd-alt-char/src/Main.java44
-rw-r--r--test/646-checker-hadd-alt-short/src/Main.java44
-rw-r--r--test/646-checker-hadd-byte/src/Main.java44
-rw-r--r--test/646-checker-hadd-char/src/Main.java44
-rw-r--r--test/646-checker-hadd-short/src/Main.java72
-rw-r--r--test/654-checker-periodic/expected.txt1
-rw-r--r--test/654-checker-periodic/info.txt1
-rw-r--r--test/654-checker-periodic/src/Main.java173
-rw-r--r--test/655-jit-clinit/expected.txt1
-rw-r--r--test/655-jit-clinit/info.txt3
-rw-r--r--test/655-jit-clinit/src/Main.java51
-rw-r--r--test/802-deoptimization/src/DeoptimizationController.java4
-rw-r--r--test/906-iterate-heap/expected.txt5
-rw-r--r--test/906-iterate-heap/iterate_heap.cc10
-rw-r--r--test/906-iterate-heap/src/art/Test906.java29
-rw-r--r--test/909-attach-agent/src/Main.java6
-rw-r--r--test/913-heaps/expected.txt2
-rw-r--r--test/913-heaps/heaps.cc9
-rw-r--r--test/913-heaps/src/art/Test913.java25
-rw-r--r--test/916-obsolete-jit/src/Main.java2
-rw-r--r--test/934-load-transform/src/Main.java2
-rw-r--r--test/935-non-retransformable/src/Main.java2
-rw-r--r--test/938-load-transform-bcp/src-ex/TestMain.java2
-rw-r--r--test/938-load-transform-bcp/src/Main.java2
-rw-r--r--test/941-recurive-obsolete-jit/src/Main.java2
-rw-r--r--test/943-private-recursive-jit/src/Main.java2
-rw-r--r--test/947-reflect-method/src/art/Test947.java2
-rw-r--r--test/953-invoke-polymorphic-compiler/src/Main.java34
-rw-r--r--test/972-default-imt-collision/src/Main.java2
-rw-r--r--test/972-iface-super-multidex/src/Main.java10
-rw-r--r--test/973-default-multidex/src/Main.java2
-rw-r--r--test/983-source-transform-verify/source_transform.cc2
-rw-r--r--test/988-redefine-use-after-free/expected.txt0
-rw-r--r--test/988-redefine-use-after-free/info.txt13
-rwxr-xr-xtest/988-redefine-use-after-free/run17
-rw-r--r--test/988-redefine-use-after-free/src-ex/DexCacheSmash.java155
-rw-r--r--test/988-redefine-use-after-free/src-ex/art/Redefinition.java91
-rw-r--r--test/988-redefine-use-after-free/src/Main.java54
-rw-r--r--test/Instrumentation/Instrumentation.java13
-rw-r--r--test/common/runtime_state.cc24
-rw-r--r--test/common/stack_inspect.cc2
-rwxr-xr-xtest/etc/run-test-jar2
-rw-r--r--test/knownfailures.json26
-rw-r--r--tools/add_package_property.sh29
-rw-r--r--tools/asan.sh21
444 files changed, 5786 insertions, 2489 deletions
diff --git a/build/art.go b/build/art.go
index b33b565899..f52c63525a 100644
--- a/build/art.go
+++ b/build/art.go
@@ -87,7 +87,7 @@ func globalFlags(ctx android.BaseContext) ([]string, []string) {
"-DART_STACK_OVERFLOW_GAP_arm64=8192",
"-DART_STACK_OVERFLOW_GAP_mips=16384",
"-DART_STACK_OVERFLOW_GAP_mips64=16384",
- "-DART_STACK_OVERFLOW_GAP_x86=12288",
+ "-DART_STACK_OVERFLOW_GAP_x86=16384",
"-DART_STACK_OVERFLOW_GAP_x86_64=20480")
} else {
cflags = append(cflags,
@@ -170,12 +170,23 @@ func globalDefaults(ctx android.LoadHookContext) {
}
Cflags []string
Asflags []string
+ Sanitize struct {
+ Recover []string
+ }
}
p := &props{}
p.Cflags, p.Asflags = globalFlags(ctx)
p.Target.Android.Cflags = deviceFlags(ctx)
p.Target.Host.Cflags = hostFlags(ctx)
+
+ if envTrue(ctx, "ART_DEX_FILE_ACCESS_TRACKING") {
+ p.Cflags = append(p.Cflags, "-DART_DEX_FILE_ACCESS_TRACKING")
+ p.Sanitize.Recover = []string {
+ "address",
+ }
+ }
+
ctx.AppendProperties(p)
}
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 9f12f64a31..07639e8a7d 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -35,7 +35,7 @@ namespace art {
return lhs.enabled_ == rhs.enabled_ &&
lhs.min_save_period_ms_ == rhs.min_save_period_ms_ &&
lhs.save_resolved_classes_delay_ms_ == rhs.save_resolved_classes_delay_ms_ &&
- lhs.startup_method_samples_ == rhs.startup_method_samples_ &&
+ lhs.hot_startup_method_samples_ == rhs.hot_startup_method_samples_ &&
lhs.min_methods_to_save_ == rhs.min_methods_to_save_ &&
lhs.min_classes_to_save_ == rhs.min_classes_to_save_ &&
lhs.min_notification_before_wake_ == rhs.min_notification_before_wake_ &&
@@ -490,7 +490,7 @@ TEST_F(CmdlineParserTest, ProfileSaverOptions) {
"-Xjitsaveprofilinginfo "
"-Xps-min-save-period-ms:1 "
"-Xps-save-resolved-classes-delay-ms:2 "
- "-Xps-startup-method-samples:3 "
+ "-Xps-hot-startup-method-samples:3 "
"-Xps-min-methods-to-save:4 "
"-Xps-min-classes-to-save:5 "
"-Xps-min-notification-before-wake:6 "
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 0d2aed8ad1..185a0e403e 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -727,10 +727,10 @@ struct CmdlineType<ProfileSaverOptions> : CmdlineTypeParser<ProfileSaverOptions>
&ProfileSaverOptions::save_resolved_classes_delay_ms_,
type_parser.Parse(suffix));
}
- if (android::base::StartsWith(option, "startup-method-samples:")) {
+ if (android::base::StartsWith(option, "hot-startup-method-samples:")) {
CmdlineType<unsigned int> type_parser;
return ParseInto(existing,
- &ProfileSaverOptions::startup_method_samples_,
+ &ProfileSaverOptions::hot_startup_method_samples_,
type_parser.Parse(suffix));
}
if (android::base::StartsWith(option, "min-methods-to-save:")) {
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 39edd1eb02..a1ee68faeb 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -33,7 +33,7 @@
#include "mirror/object-inl.h"
#include "oat_quick_method_header.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils.h"
namespace art {
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 1573062033..2db99cda3e 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -28,7 +28,7 @@
#include "driver/compiler_driver.h"
#include "driver/dex_compilation_unit.h"
#include "mirror/dex_cache.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace optimizer {
diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc
index e691a67dc0..257229101c 100644
--- a/compiler/dex/inline_method_analyser.cc
+++ b/compiler/dex/inline_method_analyser.cc
@@ -433,8 +433,11 @@ bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* re
// Native or abstract.
return false;
}
- return AnalyseMethodCode(
- code_item, method->ToMethodReference(), method->IsStatic(), method, result);
+ return AnalyseMethodCode(code_item,
+ MethodReference(method->GetDexFile(), method->GetDexMethodIndex()),
+ method->IsStatic(),
+ method,
+ result);
}
bool InlineMethodAnalyser::AnalyseMethodCode(const DexFile::CodeItem* code_item,
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 0338cfde8c..b87cb61ed6 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -17,12 +17,13 @@
#include "verification_results.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "base/mutex-inl.h"
+#include "base/stl_util.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
+#include "runtime.h"
#include "thread.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils/atomic_method_ref_map-inl.h"
#include "verified_method.h"
#include "verifier/method_verifier-inl.h"
diff --git a/compiler/driver/compiled_method_storage.cc b/compiler/driver/compiled_method_storage.cc
index e6a47ba60f..528b0a215b 100644
--- a/compiler/driver/compiled_method_storage.cc
+++ b/compiler/driver/compiled_method_storage.cc
@@ -21,7 +21,7 @@
#include "base/logging.h"
#include "compiled_method.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils.h"
#include "utils/dedupe_set-inl.h"
#include "utils/swap_space.h"
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index fc5f847354..29413d9a0a 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1000,7 +1000,9 @@ bool CompilerDriver::ShouldCompileBasedOnProfile(const MethodReference& method_r
if (profile_compilation_info_ == nullptr) {
return false;
}
- bool result = profile_compilation_info_->ContainsMethod(method_ref);
+ // Compile only hot methods, it is the profile saver's job to decide what startup methods to mark
+ // as hot.
+ bool result = profile_compilation_info_->ContainsHotMethod(method_ref);
if (kDebugProfileGuidedCompilation) {
LOG(INFO) << "[ProfileGuidedCompilation] "
@@ -2239,7 +2241,7 @@ class InitializeClassVisitor : public CompilationVisitor {
public:
explicit InitializeClassVisitor(const ParallelCompilationManager* manager) : manager_(manager) {}
- void Visit(size_t class_def_index) OVERRIDE {
+ void Visit(size_t class_def_index) REQUIRES(!Locks::mutator_lock_) OVERRIDE {
ATRACE_CALL();
jobject jclass_loader = manager_->GetClassLoader();
const DexFile& dex_file = *manager_->GetDexFile();
@@ -2254,123 +2256,89 @@ class InitializeClassVisitor : public CompilationVisitor {
Handle<mirror::Class> klass(
hs.NewHandle(manager_->GetClassLinker()->FindClass(soa.Self(), descriptor, class_loader)));
- if (klass != nullptr && !SkipClass(manager_->GetClassLoader(), dex_file, klass.Get())) {
- TryInitializeClass(klass, class_loader);
- }
- // Clear any class not found or verification exceptions.
- soa.Self()->ClearException();
- }
-
- // A helper function for initializing klass.
- void TryInitializeClass(Handle<mirror::Class> klass, Handle<mirror::ClassLoader>& class_loader)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile& dex_file = klass->GetDexFile();
- const DexFile::ClassDef* class_def = klass->GetClassDef();
- const DexFile::TypeId& class_type_id = dex_file.GetTypeId(class_def->class_idx_);
- const char* descriptor = dex_file.StringDataByIdx(class_type_id.descriptor_idx_);
- ScopedObjectAccessUnchecked soa(Thread::Current());
- StackHandleScope<3> hs(soa.Self());
-
- mirror::Class::Status old_status = klass->GetStatus();;
- // Only try to initialize classes that were successfully verified.
- if (klass->IsVerified()) {
- // Attempt to initialize the class but bail if we either need to initialize the super-class
- // or static fields.
- manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, false);
- old_status = klass->GetStatus();
- if (!klass->IsInitialized()) {
- // We don't want non-trivial class initialization occurring on multiple threads due to
- // deadlock problems. For example, a parent class is initialized (holding its lock) that
- // refers to a sub-class in its static/class initializer causing it to try to acquire the
- // sub-class' lock. While on a second thread the sub-class is initialized (holding its lock)
- // after first initializing its parents, whose locks are acquired. This leads to a
- // parent-to-child and a child-to-parent lock ordering and consequent potential deadlock.
- // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
- // than use a special Object for the purpose we use the Class of java.lang.Class.
- Handle<mirror::Class> h_klass(hs.NewHandle(klass->GetClass()));
- ObjectLock<mirror::Class> lock(soa.Self(), h_klass);
- // Attempt to initialize allowing initialization of parent classes but still not static
- // fields.
- bool is_superclass_initialized = InitializeDependencies(klass, class_loader, soa.Self());
- if (is_superclass_initialized) {
+ if (klass != nullptr && !SkipClass(jclass_loader, dex_file, klass.Get())) {
+ // Only try to initialize classes that were successfully verified.
+ if (klass->IsVerified()) {
+ // Attempt to initialize the class but bail if we either need to initialize the super-class
+ // or static fields.
+ manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, false);
+ if (!klass->IsInitialized()) {
+ // We don't want non-trivial class initialization occurring on multiple threads due to
+ // deadlock problems. For example, a parent class is initialized (holding its lock) that
+ // refers to a sub-class in its static/class initializer causing it to try to acquire the
+ // sub-class' lock. While on a second thread the sub-class is initialized (holding its lock)
+ // after first initializing its parents, whose locks are acquired. This leads to a
+ // parent-to-child and a child-to-parent lock ordering and consequent potential deadlock.
+ // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
+ // than use a special Object for the purpose we use the Class of java.lang.Class.
+ Handle<mirror::Class> h_klass(hs.NewHandle(klass->GetClass()));
+ ObjectLock<mirror::Class> lock(soa.Self(), h_klass);
+ // Attempt to initialize allowing initialization of parent classes but still not static
+ // fields.
manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, true);
- }
- old_status = klass->GetStatus();
- // If superclass cannot be initialized, no need to proceed.
- if (!klass->IsInitialized() &&
- is_superclass_initialized &&
- manager_->GetCompiler()->IsImageClass(descriptor)) {
- bool can_init_static_fields = false;
- if (manager_->GetCompiler()->GetCompilerOptions().IsBootImage()) {
+ if (!klass->IsInitialized()) {
// We need to initialize static fields, we only do this for image classes that aren't
// marked with the $NoPreloadHolder (which implies this should not be initialized early).
- can_init_static_fields = !StringPiece(descriptor).ends_with("$NoPreloadHolder;");
- } else {
- can_init_static_fields = manager_->GetCompiler()->GetCompilerOptions().IsAppImage() &&
- !soa.Self()->IsExceptionPending() &&
- NoClinitInDependency(klass, soa.Self(), &class_loader);
- // TODO The checking for clinit can be removed since it's already
- // checked when init superclass. Currently keep it because it contains
- // processing of intern strings. Will be removed later when intern strings
- // and clinit are both initialized.
- }
-
- if (can_init_static_fields) {
- VLOG(compiler) << "Initializing: " << descriptor;
- // TODO multithreading support. We should ensure the current compilation thread has
- // exclusive access to the runtime and the transaction. To achieve this, we could use
- // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity
- // checks in Thread::AssertThreadSuspensionIsAllowable.
- Runtime* const runtime = Runtime::Current();
- Transaction transaction;
-
- // Run the class initializer in transaction mode.
- runtime->EnterTransactionMode(&transaction);
- bool success = manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, true,
- true);
- // TODO we detach transaction from runtime to indicate we quit the transactional
- // mode which prevents the GC from visiting objects modified during the transaction.
- // Ensure GC is not run so don't access freed objects when aborting transaction.
-
- {
- ScopedAssertNoThreadSuspension ants("Transaction end");
- runtime->ExitTransactionMode();
-
- if (!success) {
- CHECK(soa.Self()->IsExceptionPending());
- mirror::Throwable* exception = soa.Self()->GetException();
- VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
- << exception->Dump();
- std::ostream* file_log = manager_->GetCompiler()->
- GetCompilerOptions().GetInitFailureOutput();
- if (file_log != nullptr) {
- *file_log << descriptor << "\n";
- *file_log << exception->Dump() << "\n";
+ bool can_init_static_fields =
+ manager_->GetCompiler()->GetCompilerOptions().IsBootImage() &&
+ manager_->GetCompiler()->IsImageClass(descriptor) &&
+ !StringPiece(descriptor).ends_with("$NoPreloadHolder;");
+ if (can_init_static_fields) {
+ VLOG(compiler) << "Initializing: " << descriptor;
+ // TODO multithreading support. We should ensure the current compilation thread has
+ // exclusive access to the runtime and the transaction. To achieve this, we could use
+ // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity
+ // checks in Thread::AssertThreadSuspensionIsAllowable.
+ Runtime* const runtime = Runtime::Current();
+ Transaction transaction;
+
+ // Run the class initializer in transaction mode.
+ runtime->EnterTransactionMode(&transaction);
+ const mirror::Class::Status old_status = klass->GetStatus();
+ bool success = manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, true,
+ true);
+ // TODO we detach transaction from runtime to indicate we quit the transactional
+ // mode which prevents the GC from visiting objects modified during the transaction.
+ // Ensure GC is not run so don't access freed objects when aborting transaction.
+
+ {
+ ScopedAssertNoThreadSuspension ants("Transaction end");
+ runtime->ExitTransactionMode();
+
+ if (!success) {
+ CHECK(soa.Self()->IsExceptionPending());
+ mirror::Throwable* exception = soa.Self()->GetException();
+ VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
+ << exception->Dump();
+ std::ostream* file_log = manager_->GetCompiler()->
+ GetCompilerOptions().GetInitFailureOutput();
+ if (file_log != nullptr) {
+ *file_log << descriptor << "\n";
+ *file_log << exception->Dump() << "\n";
+ }
+ soa.Self()->ClearException();
+ transaction.Rollback();
+ CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
}
- soa.Self()->ClearException();
- transaction.Rollback();
- CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
}
- }
- if (!success) {
- // On failure, still intern strings of static fields and seen in <clinit>, as these
- // will be created in the zygote. This is separated from the transaction code just
- // above as we will allocate strings, so must be allowed to suspend.
- if (&klass->GetDexFile() == manager_->GetDexFile()) {
+ if (!success) {
+ // On failure, still intern strings of static fields and seen in <clinit>, as these
+ // will be created in the zygote. This is separated from the transaction code just
+ // above as we will allocate strings, so must be allowed to suspend.
InternStrings(klass, class_loader);
}
}
}
+ soa.Self()->AssertNoPendingException();
}
- soa.Self()->AssertNoPendingException();
}
+ // Record the final class status if necessary.
+ ClassReference ref(manager_->GetDexFile(), class_def_index);
+ manager_->GetCompiler()->RecordClassStatus(ref, klass->GetStatus());
}
- // Record the final class status if necessary.
- ClassReference ref(&dex_file, klass->GetDexClassDefIndex());
- // Back up the status before doing initialization for static encoded fields,
- // because the static encoded branch wants to keep the status to uninitialized.
- manager_->GetCompiler()->RecordClassStatus(ref, old_status);
+ // Clear any class not found or verification exceptions.
+ soa.Self()->ClearException();
}
private:
@@ -2425,136 +2393,6 @@ class InitializeClassVisitor : public CompilationVisitor {
}
}
- bool ResolveTypesOfMethods(Thread* self, ArtMethod* m)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- auto rtn_type = m->GetReturnType(true);
- if (rtn_type == nullptr) {
- self->ClearException();
- return false;
- }
- const DexFile::TypeList* types = m->GetParameterTypeList();
- if (types != nullptr) {
- for (uint32_t i = 0; i < types->Size(); ++i) {
- dex::TypeIndex param_type_idx = types->GetTypeItem(i).type_idx_;
- auto param_type = m->GetClassFromTypeIndex(param_type_idx, true);
- if (param_type == nullptr) {
- self->ClearException();
- return false;
- }
- }
- }
- return true;
- }
-
- // Pre resolve types mentioned in all method signatures before start a transaction
- // since ResolveType doesn't work in transaction mode.
- bool PreResolveTypes(Thread* self, const Handle<mirror::Class>& klass)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- PointerSize pointer_size = manager_->GetClassLinker()->GetImagePointerSize();
- for (ArtMethod& m : klass->GetMethods(pointer_size)) {
- if (!ResolveTypesOfMethods(self, &m)) {
- return false;
- }
- }
- if (klass->IsInterface()) {
- return true;
- } else if (klass->HasSuperClass()) {
- StackHandleScope<1> hs(self);
- MutableHandle<mirror::Class> super_klass(hs.NewHandle<mirror::Class>(klass->GetSuperClass()));
- for (int i = super_klass->GetVTableLength() - 1; i >= 0; --i) {
- ArtMethod* m = klass->GetVTableEntry(i, pointer_size);
- ArtMethod* super_m = super_klass->GetVTableEntry(i, pointer_size);
- if (!ResolveTypesOfMethods(self, m) || !ResolveTypesOfMethods(self, super_m)) {
- return false;
- }
- }
- for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) {
- super_klass.Assign(klass->GetIfTable()->GetInterface(i));
- if (klass->GetClassLoader() != super_klass->GetClassLoader()) {
- uint32_t num_methods = super_klass->NumVirtualMethods();
- for (uint32_t j = 0; j < num_methods; ++j) {
- ArtMethod* m = klass->GetIfTable()->GetMethodArray(i)->GetElementPtrSize<ArtMethod*>(
- j, pointer_size);
- ArtMethod* super_m = super_klass->GetVirtualMethod(j, pointer_size);
- if (!ResolveTypesOfMethods(self, m) || !ResolveTypesOfMethods(self, super_m)) {
- return false;
- }
- }
- }
- }
- }
- return true;
- }
-
- // Initialize the klass's dependencies recursively before initializing itself.
- // Checking for interfaces is also necessary since interfaces can contain
- // both default methods and static encoded fields.
- bool InitializeDependencies(const Handle<mirror::Class>& klass,
- Handle<mirror::ClassLoader> class_loader,
- Thread* self)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (klass->HasSuperClass()) {
- ObjPtr<mirror::Class> super_class = klass->GetSuperClass();
- StackHandleScope<1> hs(self);
- Handle<mirror::Class> handle_scope_super(hs.NewHandle(super_class));
- if (!handle_scope_super->IsInitialized()) {
- this->TryInitializeClass(handle_scope_super, class_loader);
- if (!handle_scope_super->IsInitialized()) {
- return false;
- }
- }
- }
-
- uint32_t num_if = klass->NumDirectInterfaces();
- for (size_t i = 0; i < num_if; i++) {
- ObjPtr<mirror::Class>
- interface = mirror::Class::GetDirectInterface(self, klass.Get(), i);
- StackHandleScope<1> hs(self);
- Handle<mirror::Class> handle_interface(hs.NewHandle(interface));
-
- TryInitializeClass(handle_interface, class_loader);
-
- if (!handle_interface->IsInitialized()) {
- return false;
- }
- }
-
- return PreResolveTypes(self, klass);
- }
-
- // In this phase the classes containing class initializers are ignored. Make sure no
- // clinit appears in kalss's super class chain and interfaces.
- bool NoClinitInDependency(const Handle<mirror::Class>& klass,
- Thread* self,
- Handle<mirror::ClassLoader>* class_loader)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* clinit =
- klass->FindClassInitializer(manager_->GetClassLinker()->GetImagePointerSize());
- if (clinit != nullptr) {
- VLOG(compiler) << klass->PrettyClass() << ' ' << clinit->PrettyMethod(true);
- return false;
- }
- if (klass->HasSuperClass()) {
- ObjPtr<mirror::Class> super_class = klass->GetSuperClass();
- StackHandleScope<1> hs(self);
- Handle<mirror::Class> handle_scope_super(hs.NewHandle(super_class));
- if (!NoClinitInDependency(handle_scope_super, self, class_loader))
- return false;
- }
-
- uint32_t num_if = klass->NumDirectInterfaces();
- for (size_t i = 0; i < num_if; i++) {
- ObjPtr<mirror::Class>
- interface = mirror::Class::GetDirectInterface(self, klass.Get(), i);
- StackHandleScope<1> hs(self);
- Handle<mirror::Class> handle_interface(hs.NewHandle(interface));
- if (!NoClinitInDependency(handle_interface, self, class_loader))
- return false;
- }
-
- return true;
- }
-
const ParallelCompilationManager* const manager_;
};
@@ -2574,10 +2412,7 @@ void CompilerDriver::InitializeClasses(jobject jni_class_loader,
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, dex_files,
init_thread_pool);
-
- if (GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsAppImage()) {
- // Set the concurrency thread to 1 to support initialization for App Images since transaction
- // doesn't support multithreading now.
+ if (GetCompilerOptions().IsBootImage()) {
// TODO: remove this when transactional mode supports multithreading.
init_thread_count = 1U;
}
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 26ea39f205..4b979d8125 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -239,8 +239,14 @@ class CompilerDriverProfileTest : public CompilerDriverTest {
ProfileCompilationInfo info;
for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
- profile_info_.AddMethodIndex(dex_file->GetLocation(), dex_file->GetLocationChecksum(), 1);
- profile_info_.AddMethodIndex(dex_file->GetLocation(), dex_file->GetLocationChecksum(), 2);
+ profile_info_.AddMethodIndex(dex_file->GetLocation(),
+ dex_file->GetLocationChecksum(),
+ 1,
+ dex_file->NumMethodIds());
+ profile_info_.AddMethodIndex(dex_file->GetLocation(),
+ dex_file->GetLocationChecksum(),
+ 2,
+ dex_file->NumMethodIds());
}
return &profile_info_;
}
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 28c35e96b4..738f5a2b29 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -34,7 +34,7 @@
#include "leb128.h"
#include "linker/buffered_output_stream.h"
#include "linker/file_output_stream.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_pool.h"
#include "utils.h"
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index a12d849f02..2283b39773 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -33,6 +33,7 @@
#include "base/enums.h"
#include "base/length_prefixed_array.h"
#include "base/macros.h"
+#include "class_table.h"
#include "driver/compiler_driver.h"
#include "image.h"
#include "lock_word.h"
@@ -60,7 +61,6 @@ class ClassLoader;
} // namespace mirror
class ClassLoaderVisitor;
-class ClassTable;
class ImtConflictTable;
static constexpr int kInvalidFd = -1;
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index fed1f48d65..66135414f7 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -189,18 +189,12 @@ JitCompiler::~JitCompiler() {
bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method, bool osr) {
DCHECK(!method->IsProxyMethod());
+ DCHECK(method->GetDeclaringClass()->IsResolved());
+
TimingLogger logger("JIT compiler timing logger", true, VLOG_IS_ON(jit));
- StackHandleScope<2> hs(self);
self->AssertNoPendingException();
Runtime* runtime = Runtime::Current();
- // Ensure the class is initialized.
- Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
- if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
- VLOG(jit) << "JIT failed to initialize " << method->PrettyMethod();
- return false;
- }
-
// Do the compilation.
bool success = false;
{
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 65f3c72e99..136401898c 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -58,7 +58,7 @@
#include "parallel_move_resolver.h"
#include "ssa_liveness_analysis.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils/assembler.h"
namespace art {
@@ -337,7 +337,7 @@ void CodeGenerator::CreateCommonInvokeLocationSummary(
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
locations->SetInAt(call->GetSpecialInputIndex(), visitor->GetMethodLocation());
break;
- case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod:
+ case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall:
locations->AddTemp(visitor->GetMethodLocation());
locations->SetInAt(call->GetSpecialInputIndex(), Location::RequiresRegister());
break;
@@ -350,6 +350,34 @@ void CodeGenerator::CreateCommonInvokeLocationSummary(
}
}
+void CodeGenerator::GenerateInvokeStaticOrDirectRuntimeCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
+ MoveConstant(temp, invoke->GetDexMethodIndex());
+
+ // The access check is unnecessary but we do not want to introduce
+ // extra entrypoints for the codegens that do not support some
+ // invoke type and fall back to the runtime call.
+
+ // Initialize to anything to silent compiler warnings.
+ QuickEntrypointEnum entrypoint = kQuickInvokeStaticTrampolineWithAccessCheck;
+ switch (invoke->GetInvokeType()) {
+ case kStatic:
+ entrypoint = kQuickInvokeStaticTrampolineWithAccessCheck;
+ break;
+ case kDirect:
+ entrypoint = kQuickInvokeDirectTrampolineWithAccessCheck;
+ break;
+ case kSuper:
+ entrypoint = kQuickInvokeSuperTrampolineWithAccessCheck;
+ break;
+ case kVirtual:
+ case kInterface:
+ LOG(FATAL) << "Unexpected invoke type: " << invoke->GetInvokeType();
+ UNREACHABLE();
+ }
+
+ InvokeRuntime(entrypoint, invoke, invoke->GetDexPc(), slow_path);
+}
void CodeGenerator::GenerateInvokeUnresolvedRuntimeCall(HInvokeUnresolved* invoke) {
MoveConstant(invoke->GetLocations()->GetTemp(0), invoke->GetDexMethodIndex());
@@ -508,7 +536,7 @@ void CodeGenerator::GenerateUnresolvedFieldAccess(
void CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(HLoadClass* cls,
Location runtime_type_index_location,
Location runtime_return_location) {
- DCHECK_EQ(cls->GetLoadKind(), HLoadClass::LoadKind::kDexCacheViaMethod);
+ DCHECK_EQ(cls->GetLoadKind(), HLoadClass::LoadKind::kRuntimeCall);
DCHECK_EQ(cls->InputCount(), 1u);
LocationSummary* locations = new (cls->GetBlock()->GetGraph()->GetArena()) LocationSummary(
cls, LocationSummary::kCallOnMainOnly);
@@ -518,7 +546,7 @@ void CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(HLoadClass* cls,
}
void CodeGenerator::GenerateLoadClassRuntimeCall(HLoadClass* cls) {
- DCHECK_EQ(cls->GetLoadKind(), HLoadClass::LoadKind::kDexCacheViaMethod);
+ DCHECK_EQ(cls->GetLoadKind(), HLoadClass::LoadKind::kRuntimeCall);
LocationSummary* locations = cls->GetLocations();
MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
if (cls->NeedsAccessCheck()) {
@@ -557,6 +585,9 @@ void CodeGenerator::BlockIfInRegister(Location location, bool is_out) const {
}
void CodeGenerator::AllocateLocations(HInstruction* instruction) {
+ for (HEnvironment* env = instruction->GetEnvironment(); env != nullptr; env = env->GetParent()) {
+ env->AllocateLocations();
+ }
instruction->Accept(GetLocationBuilder());
DCHECK(CheckTypeConsistency(instruction));
LocationSummary* locations = instruction->GetLocations();
@@ -1400,20 +1431,6 @@ void CodeGenerator::CreateSystemArrayCopyLocationSummary(HInvoke* invoke) {
locations->AddTemp(Location::RequiresRegister());
}
-uint32_t CodeGenerator::GetReferenceSlowFlagOffset() const {
- ScopedObjectAccess soa(Thread::Current());
- mirror::Class* klass = mirror::Reference::GetJavaLangRefReference();
- DCHECK(klass->IsInitialized());
- return klass->GetSlowPathFlagOffset().Uint32Value();
-}
-
-uint32_t CodeGenerator::GetReferenceDisableFlagOffset() const {
- ScopedObjectAccess soa(Thread::Current());
- mirror::Class* klass = mirror::Reference::GetJavaLangRefReference();
- DCHECK(klass->IsInitialized());
- return klass->GetDisableIntrinsicFlagOffset().Uint32Value();
-}
-
void CodeGenerator::EmitJitRoots(uint8_t* code,
Handle<mirror::ObjectArray<mirror::Object>> roots,
const uint8_t* roots_data) {
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index c2b2ebfade..7bf43f7971 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -31,6 +31,7 @@
#include "nodes.h"
#include "optimizing_compiler_stats.h"
#include "read_barrier_option.h"
+#include "stack.h"
#include "stack_map_stream.h"
#include "string_reference.h"
#include "type_reference.h"
@@ -495,6 +496,8 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> {
static void CreateCommonInvokeLocationSummary(
HInvoke* invoke, InvokeDexCallingConventionVisitor* visitor);
+ void GenerateInvokeStaticOrDirectRuntimeCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path);
void GenerateInvokeUnresolvedRuntimeCall(HInvokeUnresolved* invoke);
void GenerateInvokePolymorphicCall(HInvokePolymorphic* invoke);
@@ -541,7 +544,7 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> {
case HLoadString::LoadKind::kBssEntry:
DCHECK(load->NeedsEnvironment());
return LocationSummary::kCallOnSlowPath;
- case HLoadString::LoadKind::kDexCacheViaMethod:
+ case HLoadString::LoadKind::kRuntimeCall:
DCHECK(load->NeedsEnvironment());
return LocationSummary::kCallOnMainOnly;
case HLoadString::LoadKind::kJitTableAddress:
@@ -563,18 +566,17 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> {
HInvokeStaticOrDirect* invoke) = 0;
// Generate a call to a static or direct method.
- virtual void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) = 0;
+ virtual void GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) = 0;
// Generate a call to a virtual method.
- virtual void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) = 0;
+ virtual void GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) = 0;
// Copy the result of a call into the given target.
virtual void MoveFromReturnRegister(Location trg, Primitive::Type type) = 0;
virtual void GenerateNop() = 0;
- uint32_t GetReferenceSlowFlagOffset() const;
- uint32_t GetReferenceDisableFlagOffset() const;
-
static QuickEntrypointEnum GetArrayAllocationEntrypoint(Handle<mirror::Class> array_klass);
protected:
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index c66bd77d6b..8300f8186e 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -47,7 +47,6 @@ static bool ExpectedPairLayout(Location location) {
return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
}
-static constexpr int kCurrentMethodStackOffset = 0;
static constexpr Register kMethodRegisterArgument = R0;
static constexpr Register kCoreAlwaysSpillRegister = R5;
@@ -3589,7 +3588,6 @@ void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirec
LocationSummary* locations = invoke->GetLocations();
codegen_->GenerateStaticOrDirectCall(
invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
@@ -3613,7 +3611,6 @@ void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
@@ -7137,7 +7134,7 @@ HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadClass::LoadKind::kBootImageAddress:
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
break;
}
return desired_class_load_kind;
@@ -7145,7 +7142,7 @@ HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
InvokeRuntimeCallingConvention calling_convention;
CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
cls,
@@ -7198,7 +7195,7 @@ void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
// move.
void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
codegen_->GenerateLoadClassRuntimeCall(cls);
return;
}
@@ -7270,7 +7267,7 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFE
GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, read_barrier_option);
break;
}
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
case HLoadClass::LoadKind::kInvalid:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
@@ -7332,7 +7329,7 @@ HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadString::LoadKind::kBootImageAddress:
- case HLoadString::LoadKind::kDexCacheViaMethod:
+ case HLoadString::LoadKind::kRuntimeCall:
break;
}
return desired_string_load_kind;
@@ -7342,7 +7339,7 @@ void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
HLoadString::LoadKind load_kind = load->GetLoadKind();
- if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadString::LoadKind::kRuntimeCall) {
locations->SetOut(Location::RegisterLocation(R0));
} else {
locations->SetOut(Location::RequiresRegister());
@@ -7429,7 +7426,7 @@ void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) NO_THREAD_S
}
// TODO: Consider re-adding the compiler code to do string dex cache lookup again.
- DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
+ DCHECK(load_kind == HLoadString::LoadKind::kRuntimeCall);
InvokeRuntimeCallingConvention calling_convention;
DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
__ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
@@ -8946,7 +8943,8 @@ Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOr
// save one load. However, since this is just an intrinsic slow path we prefer this
// simple and more robust approach rather that trying to determine if that's the case.
SlowPathCode* slow_path = GetCurrentSlowPath();
- if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
+ DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
+ if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
__ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
return temp;
@@ -8954,8 +8952,8 @@ Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOr
return location.AsRegister<Register>();
}
-Location CodeGeneratorARM::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
- Location temp) {
+void CodeGeneratorARM::GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
@@ -8992,35 +8990,11 @@ Location CodeGeneratorARM::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticO
__ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
break;
}
- case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
- Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
- Register method_reg;
- Register reg = temp.AsRegister<Register>();
- if (current_method.IsRegister()) {
- method_reg = current_method.AsRegister<Register>();
- } else {
- DCHECK(invoke->GetLocations()->Intrinsified());
- DCHECK(!current_method.IsValid());
- method_reg = reg;
- __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
- }
- // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
- __ LoadFromOffset(kLoadWord,
- reg,
- method_reg,
- ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
- // temp = temp[index_in_cache];
- // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
- uint32_t index_in_cache = invoke->GetDexMethodIndex();
- __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
- break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
+ GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
+ return; // No code pointer retrieval; the runtime performs the call directly.
}
}
- return callee_method;
-}
-
-void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
- Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
switch (invoke->GetCodePtrLocation()) {
case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
@@ -9035,11 +9009,13 @@ void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
__ blx(LR);
break;
}
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
DCHECK(!IsLeafMethod());
}
-void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
+void CodeGeneratorARM::GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp_location, SlowPathCode* slow_path) {
Register temp = temp_location.AsRegister<Register>();
uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
@@ -9070,6 +9046,7 @@ void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp
__ LoadFromOffset(kLoadWord, LR, temp, entry_point);
// LR();
__ blx(LR);
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
}
CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeMethodPatch(
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 2409a4d38d..398b6ed7d8 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -455,9 +455,10 @@ class CodeGeneratorARM : public CodeGenerator {
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
HInvokeStaticOrDirect* invoke) OVERRIDE;
- Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
- void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
- void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
+ void GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
+ void GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 7d9c61b76c..a84f8f3308 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -78,7 +78,6 @@ using helpers::VIXLRegCodeFromART;
using helpers::WRegisterFrom;
using helpers::XRegisterFrom;
-static constexpr int kCurrentMethodStackOffset = 0;
// The compare/jump sequence will generate about (1.5 * num_entries + 3) instructions. While jump
// table version generates 7 instructions and num_entries literals. Compare/jump sequence will
// generates less code/data with a small num_entries.
@@ -4497,8 +4496,8 @@ HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM64::GetSupportedInvokeStatic
return desired_dispatch_info;
}
-Location CodeGeneratorARM64::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
- Location temp) {
+void CodeGeneratorARM64::GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
// Make sure that ArtMethod* is passed in kArtMethodRegister as per the calling convention.
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
@@ -4539,40 +4538,22 @@ Location CodeGeneratorARM64::GenerateCalleeMethodStaticOrDirectCall(HInvokeStati
EmitLdrOffsetPlaceholder(ldr_label, XRegisterFrom(temp), XRegisterFrom(temp));
break;
}
- case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
- Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
- Register reg = XRegisterFrom(temp);
- Register method_reg;
- if (current_method.IsRegister()) {
- method_reg = XRegisterFrom(current_method);
- } else {
- DCHECK(invoke->GetLocations()->Intrinsified());
- DCHECK(!current_method.IsValid());
- method_reg = reg;
- __ Ldr(reg.X(), MemOperand(sp, kCurrentMethodStackOffset));
- }
-
- // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
- __ Ldr(reg.X(),
- MemOperand(method_reg.X(),
- ArtMethod::DexCacheResolvedMethodsOffset(kArm64PointerSize).Int32Value()));
- // temp = temp[index_in_cache];
- // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
- uint32_t index_in_cache = invoke->GetDexMethodIndex();
- __ Ldr(reg.X(), MemOperand(reg.X(), GetCachePointerOffset(index_in_cache)));
- break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
+ GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
+ return; // No code pointer retrieval; the runtime performs the call directly.
}
}
- return callee_method;
-}
-
-void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
- // All registers are assumed to be correctly set up.
- Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
switch (invoke->GetCodePtrLocation()) {
case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
- __ Bl(&frame_entry_label_);
+ {
+ // Use a scope to help guarantee that `RecordPcInfo()` records the correct pc.
+ ExactAssemblyScope eas(GetVIXLAssembler(),
+ kInstructionSize,
+ CodeBufferCheckScope::kExactSize);
+ __ bl(&frame_entry_label_);
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
+ }
break;
case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
// LR = callee_method->entry_point_from_quick_compiled_code_;
@@ -4580,14 +4561,13 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invok
XRegisterFrom(callee_method),
ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64PointerSize).Int32Value()));
{
- // To ensure that the pc position is recorded immediately after the `blr` instruction
- // BLR must be the last instruction emitted in this function.
- // Recording the pc will occur right after returning from this function.
+ // Use a scope to help guarantee that `RecordPcInfo()` records the correct pc.
ExactAssemblyScope eas(GetVIXLAssembler(),
kInstructionSize,
CodeBufferCheckScope::kExactSize);
// lr()
__ blr(lr);
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
}
break;
}
@@ -4595,7 +4575,8 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invok
DCHECK(!IsLeafMethod());
}
-void CodeGeneratorARM64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
+void CodeGeneratorARM64::GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp_in, SlowPathCode* slow_path) {
// Use the calling convention instead of the location of the receiver, as
// intrinsics may have put the receiver in a different register. In the intrinsics
// slow path, the arguments have been moved to the right place, so here we are
@@ -4629,12 +4610,11 @@ void CodeGeneratorARM64::GenerateVirtualCall(HInvokeVirtual* invoke, Location te
// lr = temp->GetEntryPoint();
__ Ldr(lr, MemOperand(temp, entry_point.SizeValue()));
{
- // To ensure that the pc position is recorded immediately after the `blr` instruction
- // BLR should be the last instruction emitted in this function.
- // Recording the pc will occur right after returning from this function.
+ // Use a scope to help guarantee that `RecordPcInfo()` records the correct pc.
ExactAssemblyScope eas(GetVIXLAssembler(), kInstructionSize, CodeBufferCheckScope::kExactSize);
// lr();
__ blr(lr);
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
}
}
@@ -4831,7 +4811,6 @@ void InstructionCodeGeneratorARM64::VisitInvokeStaticOrDirect(HInvokeStaticOrDir
LocationSummary* locations = invoke->GetLocations();
codegen_->GenerateStaticOrDirectCall(
invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
@@ -4844,7 +4823,6 @@ void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
EmissionCheckScope guard(GetVIXLAssembler(), kInvokeCodeMarginSizeInBytes);
codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
HLoadClass::LoadKind CodeGeneratorARM64::GetSupportedLoadClassKind(
@@ -4863,7 +4841,7 @@ HLoadClass::LoadKind CodeGeneratorARM64::GetSupportedLoadClassKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadClass::LoadKind::kBootImageAddress:
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
break;
}
return desired_class_load_kind;
@@ -4871,7 +4849,7 @@ HLoadClass::LoadKind CodeGeneratorARM64::GetSupportedLoadClassKind(
void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
InvokeRuntimeCallingConvention calling_convention;
CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
cls,
@@ -4916,7 +4894,7 @@ void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
// move.
void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
codegen_->GenerateLoadClassRuntimeCall(cls);
return;
}
@@ -4998,7 +4976,7 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SA
read_barrier_option);
break;
}
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
case HLoadClass::LoadKind::kInvalid:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
@@ -5054,7 +5032,7 @@ HLoadString::LoadKind CodeGeneratorARM64::GetSupportedLoadStringKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadString::LoadKind::kBootImageAddress:
- case HLoadString::LoadKind::kDexCacheViaMethod:
+ case HLoadString::LoadKind::kRuntimeCall:
break;
}
return desired_string_load_kind;
@@ -5063,7 +5041,7 @@ HLoadString::LoadKind CodeGeneratorARM64::GetSupportedLoadStringKind(
void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
- if (load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod) {
+ if (load->GetLoadKind() == HLoadString::LoadKind::kRuntimeCall) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetOut(calling_convention.GetReturnLocation(load->GetType()));
} else {
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 7a4b3d4805..5bb2ab57df 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -540,9 +540,10 @@ class CodeGeneratorARM64 : public CodeGenerator {
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
HInvokeStaticOrDirect* invoke) OVERRIDE;
- Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
- void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
- void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
+ void GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
+ void GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 1f8e1efd5e..d5e3723e68 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -76,7 +76,6 @@ static bool ExpectedPairLayout(Location location) {
// Use a local definition to prevent copying mistakes.
static constexpr size_t kArmWordSize = static_cast<size_t>(kArmPointerSize);
static constexpr size_t kArmBitsPerWord = kArmWordSize * kBitsPerByte;
-static constexpr int kCurrentMethodStackOffset = 0;
static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
// Reference load (except object array loads) is using LDR Rt, [Rn, #offset] which can handle
@@ -3678,7 +3677,6 @@ void InstructionCodeGeneratorARMVIXL::VisitInvokeStaticOrDirect(HInvokeStaticOrD
LocationSummary* locations = invoke->GetLocations();
codegen_->GenerateStaticOrDirectCall(
invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void LocationsBuilderARMVIXL::HandleInvoke(HInvoke* invoke) {
@@ -3701,7 +3699,6 @@ void InstructionCodeGeneratorARMVIXL::VisitInvokeVirtual(HInvokeVirtual* invoke)
}
codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
DCHECK(!codegen_->IsLeafMethod());
}
@@ -7252,7 +7249,7 @@ HLoadClass::LoadKind CodeGeneratorARMVIXL::GetSupportedLoadClassKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadClass::LoadKind::kBootImageAddress:
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
break;
}
return desired_class_load_kind;
@@ -7260,7 +7257,7 @@ HLoadClass::LoadKind CodeGeneratorARMVIXL::GetSupportedLoadClassKind(
void LocationsBuilderARMVIXL::VisitLoadClass(HLoadClass* cls) {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
InvokeRuntimeCallingConventionARMVIXL calling_convention;
CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
cls,
@@ -7313,7 +7310,7 @@ void LocationsBuilderARMVIXL::VisitLoadClass(HLoadClass* cls) {
// move.
void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
codegen_->GenerateLoadClassRuntimeCall(cls);
return;
}
@@ -7375,7 +7372,7 @@ void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) NO_THREAD_
GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, read_barrier_option);
break;
}
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
case HLoadClass::LoadKind::kInvalid:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
@@ -7444,7 +7441,7 @@ HLoadString::LoadKind CodeGeneratorARMVIXL::GetSupportedLoadStringKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadString::LoadKind::kBootImageAddress:
- case HLoadString::LoadKind::kDexCacheViaMethod:
+ case HLoadString::LoadKind::kRuntimeCall:
break;
}
return desired_string_load_kind;
@@ -7454,7 +7451,7 @@ void LocationsBuilderARMVIXL::VisitLoadString(HLoadString* load) {
LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
HLoadString::LoadKind load_kind = load->GetLoadKind();
- if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadString::LoadKind::kRuntimeCall) {
locations->SetOut(LocationFrom(r0));
} else {
locations->SetOut(Location::RequiresRegister());
@@ -7532,7 +7529,7 @@ void InstructionCodeGeneratorARMVIXL::VisitLoadString(HLoadString* load) NO_THRE
}
// TODO: Re-add the compiler code to do string dex cache lookup again.
- DCHECK_EQ(load->GetLoadKind(), HLoadString::LoadKind::kDexCacheViaMethod);
+ DCHECK_EQ(load->GetLoadKind(), HLoadString::LoadKind::kRuntimeCall);
InvokeRuntimeCallingConventionARMVIXL calling_convention;
__ Mov(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
@@ -9119,8 +9116,8 @@ vixl32::Register CodeGeneratorARMVIXL::GetInvokeStaticOrDirectExtraParameter(
return RegisterFrom(location);
}
-Location CodeGeneratorARMVIXL::GenerateCalleeMethodStaticOrDirectCall(
- HInvokeStaticOrDirect* invoke, Location temp) {
+void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
@@ -9151,42 +9148,22 @@ Location CodeGeneratorARMVIXL::GenerateCalleeMethodStaticOrDirectCall(
GetAssembler()->LoadFromOffset(kLoadWord, RegisterFrom(temp), base_reg, offset);
break;
}
- case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
- Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
- vixl32::Register method_reg;
- vixl32::Register reg = RegisterFrom(temp);
- if (current_method.IsRegister()) {
- method_reg = RegisterFrom(current_method);
- } else {
- DCHECK(invoke->GetLocations()->Intrinsified());
- DCHECK(!current_method.IsValid());
- method_reg = reg;
- GetAssembler()->LoadFromOffset(kLoadWord, reg, sp, kCurrentMethodStackOffset);
- }
- // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
- GetAssembler()->LoadFromOffset(
- kLoadWord,
- reg,
- method_reg,
- ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
- // temp = temp[index_in_cache];
- // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
- uint32_t index_in_cache = invoke->GetDexMethodIndex();
- GetAssembler()->LoadFromOffset(
- kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
- break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
+ GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
+ return; // No code pointer retrieval; the runtime performs the call directly.
}
}
- return callee_method;
-}
-
-void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
- Location temp) {
- Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
switch (invoke->GetCodePtrLocation()) {
case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
- __ Bl(GetFrameEntryLabel());
+ {
+ // Use a scope to help guarantee that `RecordPcInfo()` records the correct pc.
+ ExactAssemblyScope aas(GetVIXLAssembler(),
+ vixl32::k32BitT32InstructionSizeInBytes,
+ CodeBufferCheckScope::kMaximumSize);
+ __ bl(GetFrameEntryLabel());
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
+ }
break;
case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
// LR = callee_method->entry_point_from_quick_compiled_code_
@@ -9196,12 +9173,14 @@ void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* inv
RegisterFrom(callee_method),
ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
{
+ // Use a scope to help guarantee that `RecordPcInfo()` records the correct pc.
// blx in T32 has only 16bit encoding that's why a stricter check for the scope is used.
ExactAssemblyScope aas(GetVIXLAssembler(),
vixl32::k16BitT32InstructionSizeInBytes,
CodeBufferCheckScope::kExactSize);
// LR()
__ blx(lr);
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
}
break;
}
@@ -9209,7 +9188,8 @@ void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* inv
DCHECK(!IsLeafMethod());
}
-void CodeGeneratorARMVIXL::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
+void CodeGeneratorARMVIXL::GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp_location, SlowPathCode* slow_path) {
vixl32::Register temp = RegisterFrom(temp_location);
uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
@@ -9245,15 +9225,16 @@ void CodeGeneratorARMVIXL::GenerateVirtualCall(HInvokeVirtual* invoke, Location
GetAssembler()->LoadFromOffset(kLoadWord, temp, temp, method_offset);
// LR = temp->GetEntryPoint();
GetAssembler()->LoadFromOffset(kLoadWord, lr, temp, entry_point);
- // LR();
- // This `blx` *must* be the *last* instruction generated by this stub, so that calls to
- // `RecordPcInfo()` immediately following record the correct pc. Use a scope to help guarantee
- // that.
- // blx in T32 has only 16bit encoding that's why a stricter check for the scope is used.
- ExactAssemblyScope aas(GetVIXLAssembler(),
- vixl32::k16BitT32InstructionSizeInBytes,
- CodeBufferCheckScope::kExactSize);
- __ blx(lr);
+ {
+ // Use a scope to help guarantee that `RecordPcInfo()` records the correct pc.
+ // blx in T32 has only 16bit encoding that's why a stricter check for the scope is used.
+ ExactAssemblyScope aas(GetVIXLAssembler(),
+ vixl32::k16BitT32InstructionSizeInBytes,
+ CodeBufferCheckScope::kExactSize);
+ // LR();
+ __ blx(lr);
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
+ }
}
CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativeMethodPatch(
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index ef809510ad..5320f71290 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -538,9 +538,10 @@ class CodeGeneratorARMVIXL : public CodeGenerator {
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
HInvokeStaticOrDirect* invoke) OVERRIDE;
- Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
- void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
- void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
+ void GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
+ void GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 1978534112..8560e3e5f6 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -7016,12 +7016,12 @@ HLoadString::LoadKind CodeGeneratorMIPS::GetSupportedLoadStringKind(
DCHECK(Runtime::Current()->UseJitCompilation());
fallback_load = false;
break;
- case HLoadString::LoadKind::kDexCacheViaMethod:
+ case HLoadString::LoadKind::kRuntimeCall:
fallback_load = false;
break;
}
if (fallback_load) {
- desired_string_load_kind = HLoadString::LoadKind::kDexCacheViaMethod;
+ desired_string_load_kind = HLoadString::LoadKind::kRuntimeCall;
}
return desired_string_load_kind;
}
@@ -7050,12 +7050,12 @@ HLoadClass::LoadKind CodeGeneratorMIPS::GetSupportedLoadClassKind(
DCHECK(Runtime::Current()->UseJitCompilation());
fallback_load = false;
break;
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
fallback_load = false;
break;
}
if (fallback_load) {
- desired_class_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod;
+ desired_class_load_kind = HLoadClass::LoadKind::kRuntimeCall;
}
return desired_class_load_kind;
}
@@ -7105,13 +7105,14 @@ HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticO
break;
}
if (fallback_load) {
- dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
+ dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall;
dispatch_info.method_load_data = 0;
}
return dispatch_info;
}
-void CodeGeneratorMIPS::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
+void CodeGeneratorMIPS::GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
// All registers are assumed to be correctly set up per the calling convention.
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
HInvokeStaticOrDirect::MethodLoadKind method_load_kind = invoke->GetMethodLoadKind();
@@ -7165,33 +7166,9 @@ void CodeGeneratorMIPS::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke
__ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
}
break;
- case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
- Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
- Register reg = temp.AsRegister<Register>();
- Register method_reg;
- if (current_method.IsRegister()) {
- method_reg = current_method.AsRegister<Register>();
- } else {
- // TODO: use the appropriate DCHECK() here if possible.
- // DCHECK(invoke->GetLocations()->Intrinsified());
- DCHECK(!current_method.IsValid());
- method_reg = reg;
- __ Lw(reg, SP, kCurrentMethodStackOffset);
- }
-
- // temp = temp->dex_cache_resolved_methods_;
- __ LoadFromOffset(kLoadWord,
- reg,
- method_reg,
- ArtMethod::DexCacheResolvedMethodsOffset(kMipsPointerSize).Int32Value());
- // temp = temp[index_in_cache];
- // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
- uint32_t index_in_cache = invoke->GetDexMethodIndex();
- __ LoadFromOffset(kLoadWord,
- reg,
- reg,
- CodeGenerator::GetCachePointerOffset(index_in_cache));
- break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
+ GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
+ return; // No code pointer retrieval; the runtime performs the call directly.
}
}
@@ -7211,6 +7188,8 @@ void CodeGeneratorMIPS::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke
__ NopIfNoReordering();
break;
}
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
+
DCHECK(!IsLeafMethod());
}
@@ -7228,10 +7207,10 @@ void InstructionCodeGeneratorMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDire
locations->HasTemps()
? locations->GetTemp(0)
: Location::NoLocation());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
-void CodeGeneratorMIPS::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
+void CodeGeneratorMIPS::GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp_location, SlowPathCode* slow_path) {
// Use the calling convention instead of the location of the receiver, as
// intrinsics may have put the receiver in a different register. In the intrinsics
// slow path, the arguments have been moved to the right place, so here we are
@@ -7263,6 +7242,7 @@ void CodeGeneratorMIPS::GenerateVirtualCall(HInvokeVirtual* invoke, Location tem
// T9();
__ Jalr(T9);
__ NopIfNoReordering();
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
}
void InstructionCodeGeneratorMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
@@ -7272,12 +7252,11 @@ void InstructionCodeGeneratorMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void LocationsBuilderMIPS::VisitLoadClass(HLoadClass* cls) {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
InvokeRuntimeCallingConvention calling_convention;
Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(cls, loc, loc);
@@ -7331,7 +7310,7 @@ void LocationsBuilderMIPS::VisitLoadClass(HLoadClass* cls) {
// move.
void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
codegen_->GenerateLoadClassRuntimeCall(cls);
return;
}
@@ -7350,7 +7329,7 @@ void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAF
base_or_current_method_reg = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
break;
case HLoadClass::LoadKind::kReferrersClass:
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
base_or_current_method_reg = locations->InAt(0).AsRegister<Register>();
break;
default:
@@ -7428,7 +7407,7 @@ void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAF
__ SetReorder(reordering);
break;
}
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
case HLoadClass::LoadKind::kInvalid:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
@@ -7488,13 +7467,13 @@ void LocationsBuilderMIPS::VisitLoadString(HLoadString* load) {
}
FALLTHROUGH_INTENDED;
// We need an extra register for PC-relative dex cache accesses.
- case HLoadString::LoadKind::kDexCacheViaMethod:
+ case HLoadString::LoadKind::kRuntimeCall:
locations->SetInAt(0, Location::RequiresRegister());
break;
default:
break;
}
- if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadString::LoadKind::kRuntimeCall) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetOut(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
} else {
@@ -7610,7 +7589,7 @@ void InstructionCodeGeneratorMIPS::VisitLoadString(HLoadString* load) NO_THREAD_
}
// TODO: Re-add the compiler code to do string dex cache lookup again.
- DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
+ DCHECK(load_kind == HLoadString::LoadKind::kRuntimeCall);
InvokeRuntimeCallingConvention calling_convention;
DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
__ LoadConst32(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 736b5070d9..d774219ba9 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -552,8 +552,10 @@ class CodeGeneratorMIPS : public CodeGenerator {
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
HInvokeStaticOrDirect* invoke) OVERRIDE;
- void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
- void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
+ void GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
+ void GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 096139191e..da43c4e757 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -951,7 +951,7 @@ CodeGeneratorMIPS64::CodeGeneratorMIPS64(HGraph* graph,
location_builder_(graph, this),
instruction_visitor_(graph, this),
move_resolver_(graph->GetArena(), this),
- assembler_(graph->GetArena()),
+ assembler_(graph->GetArena(), &isa_features),
isa_features_(isa_features),
uint32_literals_(std::less<uint32_t>(),
graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
@@ -4873,11 +4873,11 @@ HLoadString::LoadKind CodeGeneratorMIPS64::GetSupportedLoadStringKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadString::LoadKind::kBootImageAddress:
- case HLoadString::LoadKind::kDexCacheViaMethod:
+ case HLoadString::LoadKind::kRuntimeCall:
break;
}
if (fallback_load) {
- desired_string_load_kind = HLoadString::LoadKind::kDexCacheViaMethod;
+ desired_string_load_kind = HLoadString::LoadKind::kRuntimeCall;
}
return desired_string_load_kind;
}
@@ -4899,11 +4899,11 @@ HLoadClass::LoadKind CodeGeneratorMIPS64::GetSupportedLoadClassKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadClass::LoadKind::kBootImageAddress:
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
break;
}
if (fallback_load) {
- desired_class_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod;
+ desired_class_load_kind = HLoadClass::LoadKind::kRuntimeCall;
}
return desired_class_load_kind;
}
@@ -4915,7 +4915,8 @@ HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS64::GetSupportedInvokeStati
return desired_dispatch_info;
}
-void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
+void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
// All registers are assumed to be correctly set up per the calling convention.
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
HInvokeStaticOrDirect::MethodLoadKind method_load_kind = invoke->GetMethodLoadKind();
@@ -4956,33 +4957,9 @@ void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo
__ Ld(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
break;
}
- case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
- Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
- GpuRegister reg = temp.AsRegister<GpuRegister>();
- GpuRegister method_reg;
- if (current_method.IsRegister()) {
- method_reg = current_method.AsRegister<GpuRegister>();
- } else {
- // TODO: use the appropriate DCHECK() here if possible.
- // DCHECK(invoke->GetLocations()->Intrinsified());
- DCHECK(!current_method.IsValid());
- method_reg = reg;
- __ Ld(reg, SP, kCurrentMethodStackOffset);
- }
-
- // temp = temp->dex_cache_resolved_methods_;
- __ LoadFromOffset(kLoadDoubleword,
- reg,
- method_reg,
- ArtMethod::DexCacheResolvedMethodsOffset(kMips64PointerSize).Int32Value());
- // temp = temp[index_in_cache];
- // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
- uint32_t index_in_cache = invoke->GetDexMethodIndex();
- __ LoadFromOffset(kLoadDoubleword,
- reg,
- reg,
- CodeGenerator::GetCachePointerOffset(index_in_cache));
- break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
+ GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
+ return; // No code pointer retrieval; the runtime performs the call directly.
}
}
@@ -5002,6 +4979,8 @@ void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo
__ Nop();
break;
}
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
+
DCHECK(!IsLeafMethod());
}
@@ -5019,10 +4998,10 @@ void InstructionCodeGeneratorMIPS64::VisitInvokeStaticOrDirect(HInvokeStaticOrDi
locations->HasTemps()
? locations->GetTemp(0)
: Location::NoLocation());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
-void CodeGeneratorMIPS64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
+void CodeGeneratorMIPS64::GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp_location, SlowPathCode* slow_path) {
// Use the calling convention instead of the location of the receiver, as
// intrinsics may have put the receiver in a different register. In the intrinsics
// slow path, the arguments have been moved to the right place, so here we are
@@ -5054,6 +5033,7 @@ void CodeGeneratorMIPS64::GenerateVirtualCall(HInvokeVirtual* invoke, Location t
// T9();
__ Jalr(T9);
__ Nop();
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
}
void InstructionCodeGeneratorMIPS64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
@@ -5063,12 +5043,11 @@ void InstructionCodeGeneratorMIPS64::VisitInvokeVirtual(HInvokeVirtual* invoke)
codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void LocationsBuilderMIPS64::VisitLoadClass(HLoadClass* cls) {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
InvokeRuntimeCallingConvention calling_convention;
Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(cls, loc, loc);
@@ -5105,7 +5084,7 @@ void LocationsBuilderMIPS64::VisitLoadClass(HLoadClass* cls) {
// move.
void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
codegen_->GenerateLoadClassRuntimeCall(cls);
return;
}
@@ -5116,7 +5095,7 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) NO_THREAD_S
GpuRegister out = out_loc.AsRegister<GpuRegister>();
GpuRegister current_method_reg = ZERO;
if (load_kind == HLoadClass::LoadKind::kReferrersClass ||
- load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ load_kind == HLoadClass::LoadKind::kRuntimeCall) {
current_method_reg = locations->InAt(0).AsRegister<GpuRegister>();
}
@@ -5170,7 +5149,7 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) NO_THREAD_S
cls->GetClass()));
GenerateGcRootFieldLoad(cls, out_loc, out, 0, read_barrier_option);
break;
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
case HLoadClass::LoadKind::kInvalid:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
@@ -5219,7 +5198,7 @@ void LocationsBuilderMIPS64::VisitLoadString(HLoadString* load) {
HLoadString::LoadKind load_kind = load->GetLoadKind();
LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
- if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadString::LoadKind::kRuntimeCall) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetOut(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
} else {
@@ -5293,7 +5272,7 @@ void InstructionCodeGeneratorMIPS64::VisitLoadString(HLoadString* load) NO_THREA
}
// TODO: Re-add the compiler code to do string dex cache lookup again.
- DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
+ DCHECK(load_kind == HLoadString::LoadKind::kRuntimeCall);
InvokeRuntimeCallingConvention calling_convention;
DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
__ LoadConst32(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 8405040386..2e8af2185a 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -314,6 +314,9 @@ class InstructionCodeGeneratorMIPS64 : public InstructionCodeGenerator {
uint32_t num_entries,
HBasicBlock* switch_block,
HBasicBlock* default_block);
+ int32_t VecAddress(LocationSummary* locations,
+ size_t size,
+ /* out */ GpuRegister* adjusted_base);
Mips64Assembler* const assembler_;
CodeGeneratorMIPS64* const codegen_;
@@ -518,8 +521,10 @@ class CodeGeneratorMIPS64 : public CodeGenerator {
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
HInvokeStaticOrDirect* invoke) OVERRIDE;
- void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
- void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
+ void GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
+ void GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
diff --git a/compiler/optimizing/code_generator_vector_mips64.cc b/compiler/optimizing/code_generator_vector_mips64.cc
index 50b95c17cb..af9e89e791 100644
--- a/compiler/optimizing/code_generator_vector_mips64.cc
+++ b/compiler/optimizing/code_generator_vector_mips64.cc
@@ -15,6 +15,7 @@
*/
#include "code_generator_mips64.h"
+#include "mirror/array-inl.h"
namespace art {
namespace mips64 {
@@ -22,12 +23,72 @@ namespace mips64 {
// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
#define __ down_cast<Mips64Assembler*>(GetAssembler())-> // NOLINT
+VectorRegister VectorRegisterFrom(Location location) {
+ DCHECK(location.IsFpuRegister());
+ return static_cast<VectorRegister>(location.AsFpuRegister<FpuRegister>());
+}
+
void LocationsBuilderMIPS64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresFpuRegister());
+ break;
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void InstructionCodeGeneratorMIPS64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ FillB(dst, locations->InAt(0).AsRegister<GpuRegister>());
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ FillH(dst, locations->InAt(0).AsRegister<GpuRegister>());
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FillW(dst, locations->InAt(0).AsRegister<GpuRegister>());
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FillD(dst, locations->InAt(0).AsRegister<GpuRegister>());
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ ReplicateFPToVectorRegister(dst,
+ locations->InAt(0).AsFpuRegister<FpuRegister>(),
+ /* is_double */ false);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ ReplicateFPToVectorRegister(dst,
+ locations->InAt(0).AsFpuRegister<FpuRegister>(),
+ /* is_double */ true);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecSetScalars(HVecSetScalars* instruction) {
@@ -51,13 +112,23 @@ static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* in
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case Primitive::kPrimBoolean:
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(),
+ instruction->IsVecNot() ? Location::kOutputOverlap
+ : Location::kNoOutputOverlap);
+ break;
case Primitive::kPrimByte:
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
- DCHECK(locations);
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(),
+ (instruction->IsVecNeg() || instruction->IsVecAbs())
+ ? Location::kOutputOverlap
+ : Location::kNoOutputOverlap);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -70,7 +141,18 @@ void LocationsBuilderMIPS64::VisitVecCnv(HVecCnv* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecCnv(HVecCnv* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister src = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ Primitive::Type from = instruction->GetInputType();
+ Primitive::Type to = instruction->GetResultType();
+ if (from == Primitive::kPrimInt && to == Primitive::kPrimFloat) {
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Ffint_sW(dst, src);
+ } else {
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecNeg(HVecNeg* instruction) {
@@ -78,7 +160,45 @@ void LocationsBuilderMIPS64::VisitVecNeg(HVecNeg* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecNeg(HVecNeg* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister src = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ FillB(dst, ZERO);
+ __ SubvB(dst, dst, src);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ FillH(dst, ZERO);
+ __ SubvH(dst, dst, src);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FillW(dst, ZERO);
+ __ SubvW(dst, dst, src);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FillD(dst, ZERO);
+ __ SubvD(dst, dst, src);
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FillW(dst, ZERO);
+ __ FsubW(dst, dst, src);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FillD(dst, ZERO);
+ __ FsubD(dst, dst, src);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecAbs(HVecAbs* instruction) {
@@ -86,7 +206,47 @@ void LocationsBuilderMIPS64::VisitVecAbs(HVecAbs* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecAbs(HVecAbs* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister src = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ FillB(dst, ZERO); // all zeroes
+ __ Add_aB(dst, dst, src); // dst = abs(0) + abs(src)
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ FillH(dst, ZERO); // all zeroes
+ __ Add_aH(dst, dst, src); // dst = abs(0) + abs(src)
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FillW(dst, ZERO); // all zeroes
+ __ Add_aW(dst, dst, src); // dst = abs(0) + abs(src)
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FillD(dst, ZERO); // all zeroes
+ __ Add_aD(dst, dst, src); // dst = abs(0) + abs(src)
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ LdiW(dst, -1); // all ones
+ __ SrliW(dst, dst, 1);
+ __ AndV(dst, dst, src);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ LdiD(dst, -1); // all ones
+ __ SrliD(dst, dst, 1);
+ __ AndV(dst, dst, src);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecNot(HVecNot* instruction) {
@@ -94,7 +254,30 @@ void LocationsBuilderMIPS64::VisitVecNot(HVecNot* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecNot(HVecNot* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister src = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean: // special case boolean-not
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ LdiB(dst, 1);
+ __ XorV(dst, dst, src);
+ break;
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ DCHECK_LE(2u, instruction->GetVectorLength());
+ DCHECK_LE(instruction->GetVectorLength(), 16u);
+ __ NorV(dst, src, src); // lanes do not matter
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
// Helper to set up locations for vector binary operations.
@@ -106,9 +289,12 @@ static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation*
case Primitive::kPrimChar:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
- DCHECK(locations);
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -121,7 +307,40 @@ void LocationsBuilderMIPS64::VisitVecAdd(HVecAdd* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecAdd(HVecAdd* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ AddvB(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ AddvH(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ AddvW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ AddvD(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FaddW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FaddD(dst, lhs, rhs);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
@@ -129,7 +348,40 @@ void LocationsBuilderMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ instruction->IsRounded()
+ ? __ Aver_uB(dst, lhs, rhs)
+ : __ Ave_uB(dst, lhs, rhs);
+ } else {
+ instruction->IsRounded()
+ ? __ Aver_sB(dst, lhs, rhs)
+ : __ Ave_sB(dst, lhs, rhs);
+ }
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ if (instruction->IsUnsigned()) {
+ instruction->IsRounded()
+ ? __ Aver_uH(dst, lhs, rhs)
+ : __ Ave_uH(dst, lhs, rhs);
+ } else {
+ instruction->IsRounded()
+ ? __ Aver_sH(dst, lhs, rhs)
+ : __ Ave_sH(dst, lhs, rhs);
+ }
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecSub(HVecSub* instruction) {
@@ -137,7 +389,40 @@ void LocationsBuilderMIPS64::VisitVecSub(HVecSub* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecSub(HVecSub* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ SubvB(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ SubvH(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ SubvW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ SubvD(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FsubW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FsubD(dst, lhs, rhs);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecMul(HVecMul* instruction) {
@@ -145,7 +430,40 @@ void LocationsBuilderMIPS64::VisitVecMul(HVecMul* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecMul(HVecMul* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ MulvB(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ MulvH(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ MulvW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ MulvD(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FmulW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FmulD(dst, lhs, rhs);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecDiv(HVecDiv* instruction) {
@@ -153,7 +471,23 @@ void LocationsBuilderMIPS64::VisitVecDiv(HVecDiv* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecDiv(HVecDiv* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FdivW(dst, lhs, rhs);
+ break;
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FdivD(dst, lhs, rhs);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecMin(HVecMin* instruction) {
@@ -177,7 +511,27 @@ void LocationsBuilderMIPS64::VisitVecAnd(HVecAnd* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecAnd(HVecAnd* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ DCHECK_LE(2u, instruction->GetVectorLength());
+ DCHECK_LE(instruction->GetVectorLength(), 16u);
+ __ AndV(dst, lhs, rhs); // lanes do not matter
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecAndNot(HVecAndNot* instruction) {
@@ -193,7 +547,27 @@ void LocationsBuilderMIPS64::VisitVecOr(HVecOr* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecOr(HVecOr* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ DCHECK_LE(2u, instruction->GetVectorLength());
+ DCHECK_LE(instruction->GetVectorLength(), 16u);
+ __ OrV(dst, lhs, rhs); // lanes do not matter
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecXor(HVecXor* instruction) {
@@ -201,7 +575,27 @@ void LocationsBuilderMIPS64::VisitVecXor(HVecXor* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecXor(HVecXor* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ DCHECK_LE(2u, instruction->GetVectorLength());
+ DCHECK_LE(instruction->GetVectorLength(), 16u);
+ __ XorV(dst, lhs, rhs); // lanes do not matter
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
// Helper to set up locations for vector shift operations.
@@ -213,7 +607,9 @@ static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation*
case Primitive::kPrimShort:
case Primitive::kPrimInt:
case Primitive::kPrimLong:
- DCHECK(locations);
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -226,7 +622,32 @@ void LocationsBuilderMIPS64::VisitVecShl(HVecShl* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecShl(HVecShl* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ SlliB(dst, lhs, value);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ SlliH(dst, lhs, value);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ SlliW(dst, lhs, value);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ SlliD(dst, lhs, value);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecShr(HVecShr* instruction) {
@@ -234,7 +655,32 @@ void LocationsBuilderMIPS64::VisitVecShr(HVecShr* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecShr(HVecShr* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ SraiB(dst, lhs, value);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ SraiH(dst, lhs, value);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ SraiW(dst, lhs, value);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ SraiD(dst, lhs, value);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecUShr(HVecUShr* instruction) {
@@ -242,7 +688,32 @@ void LocationsBuilderMIPS64::VisitVecUShr(HVecUShr* instruction) {
}
void InstructionCodeGeneratorMIPS64::VisitVecUShr(HVecUShr* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister lhs = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister dst = VectorRegisterFrom(locations->Out());
+ int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ SrliB(dst, lhs, value);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ SrliH(dst, lhs, value);
+ break;
+ case Primitive::kPrimInt:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ SrliW(dst, lhs, value);
+ break;
+ case Primitive::kPrimLong:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ SrliD(dst, lhs, value);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
@@ -253,20 +724,143 @@ void InstructionCodeGeneratorMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccu
LOG(FATAL) << "No SIMD for " << instr->GetId();
}
+// Helper to set up locations for vector memory operations.
+static void CreateVecMemLocations(ArenaAllocator* arena,
+ HVecMemoryOperation* instruction,
+ bool is_load) {
+ LocationSummary* locations = new (arena) LocationSummary(instruction);
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ if (is_load) {
+ locations->SetOut(Location::RequiresFpuRegister());
+ } else {
+ locations->SetInAt(2, Location::RequiresFpuRegister());
+ }
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
+}
+
+// Helper to prepare register and offset for vector memory operations. Returns the offset and sets
+// the output parameter adjusted_base to the original base or to a reserved temporary register (AT).
+int32_t InstructionCodeGeneratorMIPS64::VecAddress(LocationSummary* locations,
+ size_t size,
+ /* out */ GpuRegister* adjusted_base) {
+ GpuRegister base = locations->InAt(0).AsRegister<GpuRegister>();
+ Location index = locations->InAt(1);
+ int scale = TIMES_1;
+ switch (size) {
+ case 2: scale = TIMES_2; break;
+ case 4: scale = TIMES_4; break;
+ case 8: scale = TIMES_8; break;
+ default: break;
+ }
+ int32_t offset = mirror::Array::DataOffset(size).Int32Value();
+
+ if (index.IsConstant()) {
+ offset += index.GetConstant()->AsIntConstant()->GetValue() << scale;
+ __ AdjustBaseOffsetAndElementSizeShift(base, offset, scale);
+ *adjusted_base = base;
+ } else {
+ GpuRegister index_reg = index.AsRegister<GpuRegister>();
+ if (scale != TIMES_1) {
+ __ Dlsa(AT, index_reg, base, scale);
+ } else {
+ __ Daddu(AT, base, index_reg);
+ }
+ *adjusted_base = AT;
+ }
+ return offset;
+}
+
void LocationsBuilderMIPS64::VisitVecLoad(HVecLoad* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ CreateVecMemLocations(GetGraph()->GetArena(), instruction, /* is_load */ true);
}
void InstructionCodeGeneratorMIPS64::VisitVecLoad(HVecLoad* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+ VectorRegister reg = VectorRegisterFrom(locations->Out());
+ GpuRegister base;
+ int32_t offset = VecAddress(locations, size, &base);
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ LdB(reg, base, offset);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ // Loading 8-bytes (needed if dealing with compressed strings in StringCharAt) from unaligned
+ // memory address may cause a trap to the kernel if the CPU doesn't directly support unaligned
+ // loads and stores.
+ // TODO: Implement support for StringCharAt.
+ DCHECK(!instruction->IsStringCharAt());
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ LdH(reg, base, offset);
+ break;
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ LdW(reg, base, offset);
+ break;
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ LdD(reg, base, offset);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
void LocationsBuilderMIPS64::VisitVecStore(HVecStore* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ CreateVecMemLocations(GetGraph()->GetArena(), instruction, /* is_load */ false);
}
void InstructionCodeGeneratorMIPS64::VisitVecStore(HVecStore* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
+ LocationSummary* locations = instruction->GetLocations();
+ size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+ VectorRegister reg = VectorRegisterFrom(locations->InAt(2));
+ GpuRegister base;
+ int32_t offset = VecAddress(locations, size, &base);
+ switch (instruction->GetPackedType()) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ StB(reg, base, offset);
+ break;
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ StH(reg, base, offset);
+ break;
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ StW(reg, base, offset);
+ break;
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ StD(reg, base, offset);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
#undef __
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 317ca71136..ca921b843e 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -2204,7 +2204,6 @@ void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirec
LocationSummary* locations = invoke->GetLocations();
codegen_->GenerateStaticOrDirectCall(
invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
@@ -2228,7 +2227,6 @@ void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
@@ -4521,18 +4519,17 @@ Register CodeGeneratorX86::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOr
// save one load. However, since this is just an intrinsic slow path we prefer this
// simple and more robust approach rather that trying to determine if that's the case.
SlowPathCode* slow_path = GetCurrentSlowPath();
- if (slow_path != nullptr) {
- if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
- int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
- __ movl(temp, Address(ESP, stack_offset));
- return temp;
- }
+ DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
+ if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
+ int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
+ __ movl(temp, Address(ESP, stack_offset));
+ return temp;
}
return location.AsRegister<Register>();
}
-Location CodeGeneratorX86::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
- Location temp) {
+void CodeGeneratorX86::GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
@@ -4568,33 +4565,11 @@ Location CodeGeneratorX86::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticO
offset));
break;
}
- case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
- Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
- Register method_reg;
- Register reg = temp.AsRegister<Register>();
- if (current_method.IsRegister()) {
- method_reg = current_method.AsRegister<Register>();
- } else {
- DCHECK(invoke->GetLocations()->Intrinsified());
- DCHECK(!current_method.IsValid());
- method_reg = reg;
- __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
- }
- // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
- __ movl(reg, Address(method_reg,
- ArtMethod::DexCacheResolvedMethodsOffset(kX86PointerSize).Int32Value()));
- // temp = temp[index_in_cache];
- // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
- uint32_t index_in_cache = invoke->GetDexMethodIndex();
- __ movl(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
- break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
+ GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
+ return; // No code pointer retrieval; the runtime performs the call directly.
}
}
- return callee_method;
-}
-
-void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
- Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
switch (invoke->GetCodePtrLocation()) {
case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
@@ -4607,11 +4582,13 @@ void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
kX86PointerSize).Int32Value()));
break;
}
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
DCHECK(!IsLeafMethod());
}
-void CodeGeneratorX86::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
+void CodeGeneratorX86::GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp_in, SlowPathCode* slow_path) {
Register temp = temp_in.AsRegister<Register>();
uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
@@ -4639,6 +4616,7 @@ void CodeGeneratorX86::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp
// call temp->GetEntryPoint();
__ call(Address(
temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86PointerSize).Int32Value()));
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
}
void CodeGeneratorX86::RecordBootMethodPatch(HInvokeStaticOrDirect* invoke) {
@@ -6066,7 +6044,7 @@ HLoadClass::LoadKind CodeGeneratorX86::GetSupportedLoadClassKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadClass::LoadKind::kBootImageAddress:
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
break;
}
return desired_class_load_kind;
@@ -6074,7 +6052,7 @@ HLoadClass::LoadKind CodeGeneratorX86::GetSupportedLoadClassKind(
void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
InvokeRuntimeCallingConvention calling_convention;
CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
cls,
@@ -6128,7 +6106,7 @@ Label* CodeGeneratorX86::NewJitRootClassPatch(const DexFile& dex_file,
// move.
void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
codegen_->GenerateLoadClassRuntimeCall(cls);
return;
}
@@ -6188,7 +6166,7 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFE
GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, read_barrier_option);
break;
}
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
case HLoadClass::LoadKind::kInvalid:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
@@ -6251,7 +6229,7 @@ HLoadString::LoadKind CodeGeneratorX86::GetSupportedLoadStringKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadString::LoadKind::kBootImageAddress:
- case HLoadString::LoadKind::kDexCacheViaMethod:
+ case HLoadString::LoadKind::kRuntimeCall:
break;
}
return desired_string_load_kind;
@@ -6265,7 +6243,7 @@ void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
load_kind == HLoadString::LoadKind::kBssEntry) {
locations->SetInAt(0, Location::RequiresRegister());
}
- if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadString::LoadKind::kRuntimeCall) {
locations->SetOut(Location::RegisterLocation(EAX));
} else {
locations->SetOut(Location::RequiresRegister());
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 21c527e8b0..689f93e31a 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -408,10 +408,11 @@ class CodeGeneratorX86 : public CodeGenerator {
HInvokeStaticOrDirect* invoke) OVERRIDE;
// Generate a call to a static or direct method.
- Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
- void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
+ void GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
// Generate a call to a virtual method.
- void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
+ void GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
void RecordBootMethodPatch(HInvokeStaticOrDirect* invoke);
void RecordBootTypePatch(HLoadClass* load_class);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 6b5e4d602d..148f55139e 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -977,9 +977,10 @@ HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86_64::GetSupportedInvokeStati
return desired_dispatch_info;
}
-Location CodeGeneratorX86_64::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
- Location temp) {
+void CodeGeneratorX86_64::GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
// All registers are assumed to be correctly set up.
+
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
@@ -1009,36 +1010,11 @@ Location CodeGeneratorX86_64::GenerateCalleeMethodStaticOrDirectCall(HInvokeStat
__ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset));
break;
}
- case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
- Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
- Register method_reg;
- CpuRegister reg = temp.AsRegister<CpuRegister>();
- if (current_method.IsRegister()) {
- method_reg = current_method.AsRegister<Register>();
- } else {
- DCHECK(invoke->GetLocations()->Intrinsified());
- DCHECK(!current_method.IsValid());
- method_reg = reg.AsRegister();
- __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
- }
- // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
- __ movq(reg,
- Address(CpuRegister(method_reg),
- ArtMethod::DexCacheResolvedMethodsOffset(kX86_64PointerSize).SizeValue()));
- // temp = temp[index_in_cache];
- // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
- uint32_t index_in_cache = invoke->GetDexMethodIndex();
- __ movq(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
- break;
+ case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
+ GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
+ return; // No code pointer retrieval; the runtime performs the call directly.
}
}
- return callee_method;
-}
-
-void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
- Location temp) {
- // All registers are assumed to be correctly set up.
- Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
switch (invoke->GetCodePtrLocation()) {
case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
@@ -1051,11 +1027,13 @@ void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo
kX86_64PointerSize).SizeValue()));
break;
}
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
DCHECK(!IsLeafMethod());
}
-void CodeGeneratorX86_64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
+void CodeGeneratorX86_64::GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp_in, SlowPathCode* slow_path) {
CpuRegister temp = temp_in.AsRegister<CpuRegister>();
size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
@@ -1084,6 +1062,7 @@ void CodeGeneratorX86_64::GenerateVirtualCall(HInvokeVirtual* invoke, Location t
// call temp->GetEntryPoint();
__ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
kX86_64PointerSize).SizeValue()));
+ RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
}
void CodeGeneratorX86_64::RecordBootMethodPatch(HInvokeStaticOrDirect* invoke) {
@@ -2393,7 +2372,6 @@ void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDi
LocationSummary* locations = invoke->GetLocations();
codegen_->GenerateStaticOrDirectCall(
invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
@@ -2417,7 +2395,6 @@ void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke)
codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) {
@@ -5483,7 +5460,7 @@ HLoadClass::LoadKind CodeGeneratorX86_64::GetSupportedLoadClassKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadClass::LoadKind::kBootImageAddress:
- case HLoadClass::LoadKind::kDexCacheViaMethod:
+ case HLoadClass::LoadKind::kRuntimeCall:
break;
}
return desired_class_load_kind;
@@ -5491,7 +5468,7 @@ HLoadClass::LoadKind CodeGeneratorX86_64::GetSupportedLoadClassKind(
void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
// Custom calling convention: RAX serves as both input and output.
CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
cls,
@@ -5542,7 +5519,7 @@ Label* CodeGeneratorX86_64::NewJitRootClassPatch(const DexFile& dex_file,
// move.
void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
HLoadClass::LoadKind load_kind = cls->GetLoadKind();
- if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
codegen_->GenerateLoadClassRuntimeCall(cls);
return;
}
@@ -5653,7 +5630,7 @@ HLoadString::LoadKind CodeGeneratorX86_64::GetSupportedLoadStringKind(
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadString::LoadKind::kBootImageAddress:
- case HLoadString::LoadKind::kDexCacheViaMethod:
+ case HLoadString::LoadKind::kRuntimeCall:
break;
}
return desired_string_load_kind;
@@ -5662,7 +5639,7 @@ HLoadString::LoadKind CodeGeneratorX86_64::GetSupportedLoadStringKind(
void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
- if (load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod) {
+ if (load->GetLoadKind() == HLoadString::LoadKind::kRuntimeCall) {
locations->SetOut(Location::RegisterLocation(RAX));
} else {
locations->SetOut(Location::RequiresRegister());
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 3039e0519c..31debde0ce 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -404,9 +404,10 @@ class CodeGeneratorX86_64 : public CodeGenerator {
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
HInvokeStaticOrDirect* invoke) OVERRIDE;
- Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
- void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
- void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
+ void GenerateStaticOrDirectCall(
+ HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
+ void GenerateVirtualCall(
+ HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
void RecordBootMethodPatch(HInvokeStaticOrDirect* invoke);
void RecordBootTypePatch(HLoadClass* load_class);
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index 7c833cf70c..c0ec58f824 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -1132,11 +1132,27 @@ bool InductionVarRange::GenerateLastValuePeriodic(HInductionVarAnalysis::Inducti
/*out*/bool* needs_taken_test) const {
DCHECK(info != nullptr);
DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kPeriodic);
- // Count period.
+ // Count period and detect all-invariants.
int64_t period = 1;
- for (HInductionVarAnalysis::InductionInfo* p = info;
- p->induction_class == HInductionVarAnalysis::kPeriodic;
- p = p->op_b, ++period) {}
+ bool all_invariants = true;
+ HInductionVarAnalysis::InductionInfo* p = info;
+ for (; p->induction_class == HInductionVarAnalysis::kPeriodic; p = p->op_b, ++period) {
+ DCHECK_EQ(p->op_a->induction_class, HInductionVarAnalysis::kInvariant);
+ if (p->op_a->operation != HInductionVarAnalysis::kFetch) {
+ all_invariants = false;
+ }
+ }
+ DCHECK_EQ(p->induction_class, HInductionVarAnalysis::kInvariant);
+ if (p->operation != HInductionVarAnalysis::kFetch) {
+ all_invariants = false;
+ }
+ // Don't rely on FP arithmetic to be precise, unless the full period
+ // consist of pre-computed expressions only.
+ if (info->type == Primitive::kPrimFloat || info->type == Primitive::kPrimDouble) {
+ if (!all_invariants) {
+ return false;
+ }
+ }
// Handle any periodic(x, periodic(.., y)) for known maximum index value m.
int64_t m = 0;
if (IsConstant(trip->op_a, kExact, &m) && m >= 1) {
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 9be6a512f5..142c95780e 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -56,7 +56,7 @@ static constexpr size_t kMaximumNumberOfInstructionsForSmallMethod = 3;
// Limit the number of dex registers that we accumulate while inlining
// to avoid creating large amount of nested environments.
-static constexpr size_t kMaximumNumberOfCumulatedDexRegisters = 64;
+static constexpr size_t kMaximumNumberOfCumulatedDexRegisters = 32;
// Limit recursive call inlining, which do not benefit from too
// much inlining compared to code locality.
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index df9e7164ed..a73b1246d8 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -888,7 +888,7 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction,
}
HInvokeStaticOrDirect::DispatchInfo dispatch_info = {
- HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod,
+ HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall,
HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
0u
};
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index b1d2727e39..b664d41013 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -25,7 +25,7 @@
#include "mirror/dex_cache-inl.h"
#include "nodes.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils.h"
namespace art {
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 9803c9a0e9..ae5f8d1760 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -28,7 +28,7 @@
#include "mirror/reference.h"
#include "mirror/string.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils/arm/assembler_arm.h"
namespace art {
@@ -2624,58 +2624,6 @@ void IntrinsicCodeGeneratorARM::VisitDoubleIsInfinite(HInvoke* invoke) {
codegen_->GenerateConditionWithZero(kCondEQ, out, out);
}
-void IntrinsicLocationsBuilderARM::VisitReferenceGetReferent(HInvoke* invoke) {
- if (kEmitCompilerReadBarrier) {
- // Do not intrinsify this call with the read barrier configuration.
- return;
- }
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnSlowPath,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetOut(Location::SameAsFirstInput());
- locations->AddTemp(Location::RequiresRegister());
-}
-
-void IntrinsicCodeGeneratorARM::VisitReferenceGetReferent(HInvoke* invoke) {
- DCHECK(!kEmitCompilerReadBarrier);
- ArmAssembler* const assembler = GetAssembler();
- LocationSummary* locations = invoke->GetLocations();
-
- Register obj = locations->InAt(0).AsRegister<Register>();
- Register out = locations->Out().AsRegister<Register>();
-
- SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
- codegen_->AddSlowPath(slow_path);
-
- // Load ArtMethod first.
- HInvokeStaticOrDirect* invoke_direct = invoke->AsInvokeStaticOrDirect();
- DCHECK(invoke_direct != nullptr);
- Register temp = codegen_->GenerateCalleeMethodStaticOrDirectCall(
- invoke_direct, locations->GetTemp(0)).AsRegister<Register>();
-
- // Now get declaring class.
- __ ldr(temp, Address(temp, ArtMethod::DeclaringClassOffset().Int32Value()));
-
- uint32_t slow_path_flag_offset = codegen_->GetReferenceSlowFlagOffset();
- uint32_t disable_flag_offset = codegen_->GetReferenceDisableFlagOffset();
- DCHECK_NE(slow_path_flag_offset, 0u);
- DCHECK_NE(disable_flag_offset, 0u);
- DCHECK_NE(slow_path_flag_offset, disable_flag_offset);
-
- // Check static flags that prevent using intrinsic.
- __ ldr(IP, Address(temp, disable_flag_offset));
- __ ldr(temp, Address(temp, slow_path_flag_offset));
- __ orr(IP, IP, ShifterOperand(temp));
- __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
-
- // Fast path.
- __ ldr(out, Address(obj, mirror::Reference::ReferentOffset().Int32Value()));
- codegen_->MaybeRecordImplicitNullCheck(invoke);
- __ MaybeUnpoisonHeapReference(out);
- __ Bind(slow_path->GetExitLabel());
-}
-
void IntrinsicLocationsBuilderARM::VisitIntegerValueOf(HInvoke* invoke) {
InvokeRuntimeCallingConvention calling_convention;
IntrinsicVisitor::ComputeIntegerValueOfLocations(
@@ -2782,6 +2730,7 @@ UNIMPLEMENTED_INTRINSIC(ARM, MathRoundDouble) // Could be done by changing rou
UNIMPLEMENTED_INTRINSIC(ARM, MathRoundFloat) // Could be done by changing rounding mode, maybe?
UNIMPLEMENTED_INTRINSIC(ARM, UnsafeCASLong) // High register pressure.
UNIMPLEMENTED_INTRINSIC(ARM, SystemArrayCopyChar)
+UNIMPLEMENTED_INTRINSIC(ARM, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(ARM, IntegerHighestOneBit)
UNIMPLEMENTED_INTRINSIC(ARM, LongHighestOneBit)
UNIMPLEMENTED_INTRINSIC(ARM, IntegerLowestOneBit)
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index b511c5a18d..37d79814be 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -28,7 +28,7 @@
#include "mirror/reference.h"
#include "mirror/string-inl.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils/arm64/assembler_arm64.h"
using namespace vixl::aarch64; // NOLINT(build/namespaces)
@@ -124,12 +124,12 @@ class IntrinsicSlowPathARM64 : public SlowPathCodeARM64 {
// are no pools emitted.
vixl::EmissionCheckScope guard(codegen->GetVIXLAssembler(), kInvokeCodeMarginSizeInBytes);
if (invoke_->IsInvokeStaticOrDirect()) {
- codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
- LocationFrom(kArtMethodRegister));
+ codegen->GenerateStaticOrDirectCall(
+ invoke_->AsInvokeStaticOrDirect(), LocationFrom(kArtMethodRegister), this);
} else {
- codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), LocationFrom(kArtMethodRegister));
+ codegen->GenerateVirtualCall(
+ invoke_->AsInvokeVirtual(), LocationFrom(kArtMethodRegister), this);
}
- codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
}
// Copy the result back to the expected output.
@@ -2897,69 +2897,6 @@ void IntrinsicCodeGeneratorARM64::VisitDoubleIsInfinite(HInvoke* invoke) {
GenIsInfinite(invoke->GetLocations(), /* is64bit */ true, GetVIXLAssembler());
}
-void IntrinsicLocationsBuilderARM64::VisitReferenceGetReferent(HInvoke* invoke) {
- if (kEmitCompilerReadBarrier) {
- // Do not intrinsify this call with the read barrier configuration.
- return;
- }
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnSlowPath,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetOut(Location::SameAsFirstInput());
- locations->AddTemp(Location::RequiresRegister());
-}
-
-void IntrinsicCodeGeneratorARM64::VisitReferenceGetReferent(HInvoke* invoke) {
- DCHECK(!kEmitCompilerReadBarrier);
- MacroAssembler* masm = GetVIXLAssembler();
- LocationSummary* locations = invoke->GetLocations();
-
- Register obj = InputRegisterAt(invoke, 0);
- Register out = OutputRegister(invoke);
-
- SlowPathCodeARM64* slow_path = new (GetAllocator()) IntrinsicSlowPathARM64(invoke);
- codegen_->AddSlowPath(slow_path);
-
- // Load ArtMethod first.
- HInvokeStaticOrDirect* invoke_direct = invoke->AsInvokeStaticOrDirect();
- DCHECK(invoke_direct != nullptr);
- Register temp0 = XRegisterFrom(codegen_->GenerateCalleeMethodStaticOrDirectCall(
- invoke_direct, locations->GetTemp(0)));
-
- // Now get declaring class.
- __ Ldr(temp0.W(), MemOperand(temp0, ArtMethod::DeclaringClassOffset().Int32Value()));
-
- uint32_t slow_path_flag_offset = codegen_->GetReferenceSlowFlagOffset();
- uint32_t disable_flag_offset = codegen_->GetReferenceDisableFlagOffset();
- DCHECK_NE(slow_path_flag_offset, 0u);
- DCHECK_NE(disable_flag_offset, 0u);
- DCHECK_NE(slow_path_flag_offset, disable_flag_offset);
-
- // Check static flags that prevent using intrinsic.
- if (slow_path_flag_offset == disable_flag_offset + 1) {
- // Load two adjacent flags in one 64-bit load.
- __ Ldr(temp0, MemOperand(temp0, disable_flag_offset));
- } else {
- UseScratchRegisterScope temps(masm);
- Register temp1 = temps.AcquireW();
- __ Ldr(temp1.W(), MemOperand(temp0, disable_flag_offset));
- __ Ldr(temp0.W(), MemOperand(temp0, slow_path_flag_offset));
- __ Orr(temp0, temp1, temp0);
- }
- __ Cbnz(temp0, slow_path->GetEntryLabel());
-
- {
- // Ensure that between load and MaybeRecordImplicitNullCheck there are no pools emitted.
- vixl::EmissionCheckScope guard(codegen_->GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes);
- // Fast path.
- __ Ldr(out, HeapOperand(obj, mirror::Reference::ReferentOffset().Int32Value()));
- codegen_->MaybeRecordImplicitNullCheck(invoke);
- }
- codegen_->GetAssembler()->MaybeUnpoisonHeapReference(out);
- __ Bind(slow_path->GetExitLabel());
-}
-
void IntrinsicLocationsBuilderARM64::VisitIntegerValueOf(HInvoke* invoke) {
InvokeRuntimeCallingConvention calling_convention;
IntrinsicVisitor::ComputeIntegerValueOfLocations(
@@ -3055,6 +2992,7 @@ void IntrinsicCodeGeneratorARM64::VisitThreadInterrupted(HInvoke* invoke) {
__ Bind(&done);
}
+UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(ARM64, IntegerHighestOneBit)
UNIMPLEMENTED_INTRINSIC(ARM64, LongHighestOneBit)
UNIMPLEMENTED_INTRINSIC(ARM64, IntegerLowestOneBit)
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index 1a33b0ee01..3c9b613803 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -26,7 +26,7 @@
#include "mirror/reference.h"
#include "mirror/string.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "aarch32/constants-aarch32.h"
@@ -97,11 +97,10 @@ class IntrinsicSlowPathARMVIXL : public SlowPathCodeARMVIXL {
Location method_loc = MoveArguments(codegen);
if (invoke_->IsInvokeStaticOrDirect()) {
- codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), method_loc);
+ codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), method_loc, this);
} else {
- codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), method_loc);
+ codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), method_loc, this);
}
- codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
// Copy the result back to the expected output.
Location out = invoke_->GetLocations()->Out();
@@ -3000,60 +2999,6 @@ void IntrinsicCodeGeneratorARMVIXL::VisitDoubleIsInfinite(HInvoke* invoke) {
codegen_->GenerateConditionWithZero(kCondEQ, out, out);
}
-void IntrinsicLocationsBuilderARMVIXL::VisitReferenceGetReferent(HInvoke* invoke) {
- if (kEmitCompilerReadBarrier) {
- // Do not intrinsify this call with the read barrier configuration.
- return;
- }
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnSlowPath,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetOut(Location::SameAsFirstInput());
- locations->AddTemp(Location::RequiresRegister());
-}
-
-void IntrinsicCodeGeneratorARMVIXL::VisitReferenceGetReferent(HInvoke* invoke) {
- DCHECK(!kEmitCompilerReadBarrier);
- ArmVIXLAssembler* assembler = GetAssembler();
- LocationSummary* locations = invoke->GetLocations();
-
- vixl32::Register obj = InputRegisterAt(invoke, 0);
- vixl32::Register out = OutputRegister(invoke);
-
- SlowPathCodeARMVIXL* slow_path = new (GetAllocator()) IntrinsicSlowPathARMVIXL(invoke);
- codegen_->AddSlowPath(slow_path);
-
- // Load ArtMethod first.
- HInvokeStaticOrDirect* invoke_direct = invoke->AsInvokeStaticOrDirect();
- DCHECK(invoke_direct != nullptr);
- vixl32::Register temp0 = RegisterFrom(codegen_->GenerateCalleeMethodStaticOrDirectCall(
- invoke_direct, locations->GetTemp(0)));
-
- // Now get declaring class.
- __ Ldr(temp0, MemOperand(temp0, ArtMethod::DeclaringClassOffset().Int32Value()));
-
- uint32_t slow_path_flag_offset = codegen_->GetReferenceSlowFlagOffset();
- uint32_t disable_flag_offset = codegen_->GetReferenceDisableFlagOffset();
- DCHECK_NE(slow_path_flag_offset, 0u);
- DCHECK_NE(disable_flag_offset, 0u);
- DCHECK_NE(slow_path_flag_offset, disable_flag_offset);
-
- // Check static flags that prevent using intrinsic.
- UseScratchRegisterScope temps(assembler->GetVIXLAssembler());
- vixl32::Register temp1 = temps.Acquire();
- __ Ldr(temp1, MemOperand(temp0, disable_flag_offset));
- __ Ldr(temp0, MemOperand(temp0, slow_path_flag_offset));
- __ Orr(temp0, temp1, temp0);
- __ CompareAndBranchIfNonZero(temp0, slow_path->GetEntryLabel());
-
- // Fast path.
- __ Ldr(out, MemOperand(obj, mirror::Reference::ReferentOffset().Int32Value()));
- codegen_->MaybeRecordImplicitNullCheck(invoke);
- assembler->MaybeUnpoisonHeapReference(out);
- __ Bind(slow_path->GetExitLabel());
-}
-
void IntrinsicLocationsBuilderARMVIXL::VisitMathCeil(HInvoke* invoke) {
if (features_.HasARMv8AInstructions()) {
CreateFPToFPLocations(arena_, invoke);
@@ -3178,6 +3123,7 @@ void IntrinsicCodeGeneratorARMVIXL::VisitThreadInterrupted(HInvoke* invoke) {
UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundDouble) // Could be done by changing rounding mode, maybe?
UNIMPLEMENTED_INTRINSIC(ARMVIXL, UnsafeCASLong) // High register pressure.
UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar)
+UNIMPLEMENTED_INTRINSIC(ARMVIXL, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, IntegerHighestOneBit)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, LongHighestOneBit)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, IntegerLowestOneBit)
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 4731da1ea9..4cea6dfdfb 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -23,6 +23,7 @@
#include "intrinsics.h"
#include "mirror/array-inl.h"
#include "mirror/string.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "utils/mips/assembler_mips.h"
#include "utils/mips/constants_mips.h"
@@ -111,12 +112,12 @@ class IntrinsicSlowPathMIPS : public SlowPathCodeMIPS {
MoveArguments(invoke_, codegen);
if (invoke_->IsInvokeStaticOrDirect()) {
- codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
- Location::RegisterLocation(A0));
+ codegen->GenerateStaticOrDirectCall(
+ invoke_->AsInvokeStaticOrDirect(), Location::RegisterLocation(A0), this);
} else {
- codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), Location::RegisterLocation(A0));
+ codegen->GenerateVirtualCall(
+ invoke_->AsInvokeVirtual(), Location::RegisterLocation(A0), this);
}
- codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
// Copy the result back to the expected output.
Location out = invoke_->GetLocations()->Out();
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 00afbcd8f2..d785567e0f 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -23,6 +23,7 @@
#include "intrinsics.h"
#include "mirror/array-inl.h"
#include "mirror/string.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "utils/mips64/assembler_mips64.h"
#include "utils/mips64/constants_mips64.h"
@@ -100,12 +101,12 @@ class IntrinsicSlowPathMIPS64 : public SlowPathCodeMIPS64 {
MoveArguments(invoke_, codegen);
if (invoke_->IsInvokeStaticOrDirect()) {
- codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
- Location::RegisterLocation(A0));
+ codegen->GenerateStaticOrDirectCall(
+ invoke_->AsInvokeStaticOrDirect(), Location::RegisterLocation(A0), this);
} else {
- codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), Location::RegisterLocation(A0));
+ codegen->GenerateVirtualCall(
+ invoke_->AsInvokeVirtual(), Location::RegisterLocation(A0), this);
}
- codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
// Copy the result back to the expected output.
Location out = invoke_->GetLocations()->Out();
diff --git a/compiler/optimizing/intrinsics_utils.h b/compiler/optimizing/intrinsics_utils.h
index c1f9ae6425..8c69d9b643 100644
--- a/compiler/optimizing/intrinsics_utils.h
+++ b/compiler/optimizing/intrinsics_utils.h
@@ -56,11 +56,10 @@ class IntrinsicSlowPath : public SlowPathCode {
Location method_loc = MoveArguments(codegen);
if (invoke_->IsInvokeStaticOrDirect()) {
- codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), method_loc);
+ codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), method_loc, this);
} else {
- codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), method_loc);
+ codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), method_loc, this);
}
- codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
// Copy the result back to the expected output.
Location out = invoke_->GetLocations()->Out();
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 57adcc3c2f..6b4851d541 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -31,7 +31,7 @@
#include "mirror/reference.h"
#include "mirror/string.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils/x86/assembler_x86.h"
#include "utils/x86/constants_x86.h"
@@ -796,7 +796,6 @@ static void InvokeOutOfLineIntrinsic(CodeGeneratorX86* codegen, HInvoke* invoke)
DCHECK(invoke->IsInvokeStaticOrDirect());
codegen->GenerateStaticOrDirectCall(invoke->AsInvokeStaticOrDirect(),
Location::RegisterLocation(EAX));
- codegen->RecordPcInfo(invoke, invoke->GetDexPc());
// Copy the result back to the expected output.
Location out = invoke->GetLocations()->Out();
@@ -2819,65 +2818,6 @@ void IntrinsicCodeGeneratorX86::VisitLongNumberOfTrailingZeros(HInvoke* invoke)
GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true);
}
-void IntrinsicLocationsBuilderX86::VisitReferenceGetReferent(HInvoke* invoke) {
- if (kEmitCompilerReadBarrier) {
- // Do not intrinsify this call with the read barrier configuration.
- return;
- }
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnSlowPath,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetOut(Location::SameAsFirstInput());
- locations->AddTemp(Location::RequiresRegister());
-}
-
-void IntrinsicCodeGeneratorX86::VisitReferenceGetReferent(HInvoke* invoke) {
- DCHECK(!kEmitCompilerReadBarrier);
- LocationSummary* locations = invoke->GetLocations();
- X86Assembler* assembler = GetAssembler();
-
- Register obj = locations->InAt(0).AsRegister<Register>();
- Register out = locations->Out().AsRegister<Register>();
-
- SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
- codegen_->AddSlowPath(slow_path);
-
- // Load ArtMethod first.
- HInvokeStaticOrDirect* invoke_direct = invoke->AsInvokeStaticOrDirect();
- DCHECK(invoke_direct != nullptr);
- Location temp_loc = codegen_->GenerateCalleeMethodStaticOrDirectCall(
- invoke_direct, locations->GetTemp(0));
- DCHECK(temp_loc.Equals(locations->GetTemp(0)));
- Register temp = temp_loc.AsRegister<Register>();
-
- // Now get declaring class.
- __ movl(temp, Address(temp, ArtMethod::DeclaringClassOffset().Int32Value()));
-
- uint32_t slow_path_flag_offset = codegen_->GetReferenceSlowFlagOffset();
- uint32_t disable_flag_offset = codegen_->GetReferenceDisableFlagOffset();
- DCHECK_NE(slow_path_flag_offset, 0u);
- DCHECK_NE(disable_flag_offset, 0u);
- DCHECK_NE(slow_path_flag_offset, disable_flag_offset);
-
- // Check static flags preventing us for using intrinsic.
- if (slow_path_flag_offset == disable_flag_offset + 1) {
- __ cmpw(Address(temp, disable_flag_offset), Immediate(0));
- __ j(kNotEqual, slow_path->GetEntryLabel());
- } else {
- __ cmpb(Address(temp, disable_flag_offset), Immediate(0));
- __ j(kNotEqual, slow_path->GetEntryLabel());
- __ cmpb(Address(temp, slow_path_flag_offset), Immediate(0));
- __ j(kNotEqual, slow_path->GetEntryLabel());
- }
-
- // Fast path.
- __ movl(out, Address(obj, mirror::Reference::ReferentOffset().Int32Value()));
- codegen_->MaybeRecordImplicitNullCheck(invoke);
- __ MaybeUnpoisonHeapReference(out);
- __ Bind(slow_path->GetExitLabel());
-}
-
static bool IsSameInput(HInstruction* instruction, size_t input0, size_t input1) {
return instruction->InputAt(input0) == instruction->InputAt(input1);
}
@@ -3429,6 +3369,7 @@ void IntrinsicCodeGeneratorX86::VisitThreadInterrupted(HInvoke* invoke) {
UNIMPLEMENTED_INTRINSIC(X86, MathRoundDouble)
+UNIMPLEMENTED_INTRINSIC(X86, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(X86, FloatIsInfinite)
UNIMPLEMENTED_INTRINSIC(X86, DoubleIsInfinite)
UNIMPLEMENTED_INTRINSIC(X86, IntegerHighestOneBit)
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 773383ef1b..ef98b7be30 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -31,7 +31,7 @@
#include "mirror/reference.h"
#include "mirror/string.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils/x86_64/assembler_x86_64.h"
#include "utils/x86_64/constants_x86_64.h"
@@ -567,7 +567,6 @@ static void InvokeOutOfLineIntrinsic(CodeGeneratorX86_64* codegen, HInvoke* invo
DCHECK(invoke->IsInvokeStaticOrDirect());
codegen->GenerateStaticOrDirectCall(
invoke->AsInvokeStaticOrDirect(), Location::RegisterLocation(RDI));
- codegen->RecordPcInfo(invoke, invoke->GetDexPc());
// Copy the result back to the expected output.
Location out = invoke->GetLocations()->Out();
@@ -2959,65 +2958,6 @@ void IntrinsicCodeGeneratorX86_64::VisitLongNumberOfTrailingZeros(HInvoke* invok
GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true);
}
-void IntrinsicLocationsBuilderX86_64::VisitReferenceGetReferent(HInvoke* invoke) {
- if (kEmitCompilerReadBarrier) {
- // Do not intrinsify this call with the read barrier configuration.
- return;
- }
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnSlowPath,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetOut(Location::SameAsFirstInput());
- locations->AddTemp(Location::RequiresRegister());
-}
-
-void IntrinsicCodeGeneratorX86_64::VisitReferenceGetReferent(HInvoke* invoke) {
- DCHECK(!kEmitCompilerReadBarrier);
- LocationSummary* locations = invoke->GetLocations();
- X86_64Assembler* assembler = GetAssembler();
-
- CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
- CpuRegister out = locations->Out().AsRegister<CpuRegister>();
-
- SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86_64(invoke);
- codegen_->AddSlowPath(slow_path);
-
- // Load ArtMethod first.
- HInvokeStaticOrDirect* invoke_direct = invoke->AsInvokeStaticOrDirect();
- DCHECK(invoke_direct != nullptr);
- Location temp_loc = codegen_->GenerateCalleeMethodStaticOrDirectCall(
- invoke_direct, locations->GetTemp(0));
- DCHECK(temp_loc.Equals(locations->GetTemp(0)));
- CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
-
- // Now get declaring class.
- __ movl(temp, Address(temp, ArtMethod::DeclaringClassOffset().Int32Value()));
-
- uint32_t slow_path_flag_offset = codegen_->GetReferenceSlowFlagOffset();
- uint32_t disable_flag_offset = codegen_->GetReferenceDisableFlagOffset();
- DCHECK_NE(slow_path_flag_offset, 0u);
- DCHECK_NE(disable_flag_offset, 0u);
- DCHECK_NE(slow_path_flag_offset, disable_flag_offset);
-
- // Check static flags preventing us for using intrinsic.
- if (slow_path_flag_offset == disable_flag_offset + 1) {
- __ cmpw(Address(temp, disable_flag_offset), Immediate(0));
- __ j(kNotEqual, slow_path->GetEntryLabel());
- } else {
- __ cmpb(Address(temp, disable_flag_offset), Immediate(0));
- __ j(kNotEqual, slow_path->GetEntryLabel());
- __ cmpb(Address(temp, slow_path_flag_offset), Immediate(0));
- __ j(kNotEqual, slow_path->GetEntryLabel());
- }
-
- // Fast path.
- __ movl(out, Address(obj, mirror::Reference::ReferentOffset().Int32Value()));
- codegen_->MaybeRecordImplicitNullCheck(invoke);
- __ MaybeUnpoisonHeapReference(out);
- __ Bind(slow_path->GetExitLabel());
-}
-
void IntrinsicLocationsBuilderX86_64::VisitIntegerValueOf(HInvoke* invoke) {
InvokeRuntimeCallingConvention calling_convention;
IntrinsicVisitor::ComputeIntegerValueOfLocations(
@@ -3106,6 +3046,7 @@ void IntrinsicCodeGeneratorX86_64::VisitThreadInterrupted(HInvoke* invoke) {
__ Bind(&done);
}
+UNIMPLEMENTED_INTRINSIC(X86_64, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(X86_64, FloatIsInfinite)
UNIMPLEMENTED_INTRINSIC(X86_64, DoubleIsInfinite)
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 94787c99b2..c3aa976d49 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -811,6 +811,11 @@ bool HLoopOptimization::VectorizeUse(LoopNode* node,
}
return true;
} else if (instruction->IsArrayGet()) {
+ // Deal with vector restrictions.
+ if (instruction->AsArrayGet()->IsStringCharAt() &&
+ HasVectorRestrictions(restrictions, kNoStringCharAt)) {
+ return false;
+ }
// Accept a right-hand-side array base[index] for
// (1) exact matching vector type,
// (2) loop-invariant base,
@@ -1072,9 +1077,36 @@ bool HLoopOptimization::TrySetVectorType(Primitive::Type type, uint64_t* restric
}
return false;
case kMips:
- case kMips64:
// TODO: implement MIPS SIMD.
return false;
+ case kMips64:
+ if (features->AsMips64InstructionSetFeatures()->HasMsa()) {
+ switch (type) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ *restrictions |= kNoDiv | kNoMinMax;
+ return TrySetVectorLength(16);
+ case Primitive::kPrimChar:
+ case Primitive::kPrimShort:
+ *restrictions |= kNoDiv | kNoMinMax | kNoStringCharAt;
+ return TrySetVectorLength(8);
+ case Primitive::kPrimInt:
+ *restrictions |= kNoDiv | kNoMinMax;
+ return TrySetVectorLength(4);
+ case Primitive::kPrimLong:
+ *restrictions |= kNoDiv | kNoMinMax;
+ return TrySetVectorLength(2);
+ case Primitive::kPrimFloat:
+ *restrictions |= kNoMinMax;
+ return TrySetVectorLength(4);
+ case Primitive::kPrimDouble:
+ *restrictions |= kNoMinMax;
+ return TrySetVectorLength(2);
+ default:
+ break;
+ } // switch type
+ }
+ return false;
default:
return false;
} // switch instruction set
@@ -1270,9 +1302,10 @@ void HLoopOptimization::GenerateVecOp(HInstruction* org,
// corresponding new scalar instructions in the loop. The instruction will get an
// environment while being inserted from the instruction map in original program order.
DCHECK(vector_mode_ == kSequential);
+ size_t num_args = invoke->GetNumberOfArguments();
HInvokeStaticOrDirect* new_invoke = new (global_allocator_) HInvokeStaticOrDirect(
global_allocator_,
- invoke->GetNumberOfArguments(),
+ num_args,
invoke->GetType(),
invoke->GetDexPc(),
invoke->GetDexMethodIndex(),
@@ -1282,8 +1315,14 @@ void HLoopOptimization::GenerateVecOp(HInstruction* org,
invoke->GetTargetMethod(),
invoke->GetClinitCheckRequirement());
HInputsRef inputs = invoke->GetInputs();
- for (size_t index = 0; index < inputs.size(); ++index) {
- new_invoke->SetArgumentAt(index, vector_map_->Get(inputs[index]));
+ size_t num_inputs = inputs.size();
+ DCHECK_LE(num_args, num_inputs);
+ DCHECK_EQ(num_inputs, new_invoke->GetInputs().size()); // both invokes agree
+ for (size_t index = 0; index < num_inputs; ++index) {
+ HInstruction* new_input = index < num_args
+ ? vector_map_->Get(inputs[index])
+ : inputs[index]; // beyond arguments: just pass through
+ new_invoke->SetArgumentAt(index, new_input);
}
new_invoke->SetIntrinsic(invoke->GetIntrinsic(),
kNeedsEnvironmentOrCache,
diff --git a/compiler/optimizing/loop_optimization.h b/compiler/optimizing/loop_optimization.h
index 35298d4076..75a42f3297 100644
--- a/compiler/optimizing/loop_optimization.h
+++ b/compiler/optimizing/loop_optimization.h
@@ -72,6 +72,7 @@ class HLoopOptimization : public HOptimization {
kNoUnroundedHAdd = 64, // no unrounded halving add
kNoAbs = 128, // no absolute value
kNoMinMax = 256, // no min/max
+ kNoStringCharAt = 512, // no StringCharAt
};
/*
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 689991010e..e53209f941 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2623,7 +2623,7 @@ const DexFile& HInvokeStaticOrDirect::GetDexFileForPcRelativeDexCache() const {
}
bool HInvokeStaticOrDirect::NeedsDexCacheOfDeclaringClass() const {
- if (GetMethodLoadKind() != MethodLoadKind::kDexCacheViaMethod) {
+ if (GetMethodLoadKind() != MethodLoadKind::kRuntimeCall) {
return false;
}
if (!IsIntrinsic()) {
@@ -2645,8 +2645,8 @@ std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::MethodLoadKind
return os << "DirectAddress";
case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
return os << "DexCachePcRelative";
- case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod:
- return os << "DexCacheViaMethod";
+ case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall:
+ return os << "RuntimeCall";
default:
LOG(FATAL) << "Unknown MethodLoadKind: " << static_cast<int>(rhs);
UNREACHABLE();
@@ -2690,7 +2690,7 @@ bool HLoadClass::InstructionDataEquals(const HInstruction* other) const {
void HLoadClass::SetLoadKind(LoadKind load_kind) {
SetPackedField<LoadKindField>(load_kind);
- if (load_kind != LoadKind::kDexCacheViaMethod &&
+ if (load_kind != LoadKind::kRuntimeCall &&
load_kind != LoadKind::kReferrersClass) {
RemoveAsUserOfInput(0u);
SetRawInputAt(0u, nullptr);
@@ -2714,8 +2714,8 @@ std::ostream& operator<<(std::ostream& os, HLoadClass::LoadKind rhs) {
return os << "BssEntry";
case HLoadClass::LoadKind::kJitTableAddress:
return os << "JitTableAddress";
- case HLoadClass::LoadKind::kDexCacheViaMethod:
- return os << "DexCacheViaMethod";
+ case HLoadClass::LoadKind::kRuntimeCall:
+ return os << "RuntimeCall";
default:
LOG(FATAL) << "Unknown HLoadClass::LoadKind: " << static_cast<int>(rhs);
UNREACHABLE();
@@ -2743,10 +2743,10 @@ bool HLoadString::InstructionDataEquals(const HInstruction* other) const {
void HLoadString::SetLoadKind(LoadKind load_kind) {
// Once sharpened, the load kind should not be changed again.
- DCHECK_EQ(GetLoadKind(), LoadKind::kDexCacheViaMethod);
+ DCHECK_EQ(GetLoadKind(), LoadKind::kRuntimeCall);
SetPackedField<LoadKindField>(load_kind);
- if (load_kind != LoadKind::kDexCacheViaMethod) {
+ if (load_kind != LoadKind::kRuntimeCall) {
RemoveAsUserOfInput(0u);
SetRawInputAt(0u, nullptr);
}
@@ -2766,8 +2766,8 @@ std::ostream& operator<<(std::ostream& os, HLoadString::LoadKind rhs) {
return os << "BssEntry";
case HLoadString::LoadKind::kJitTableAddress:
return os << "JitTableAddress";
- case HLoadString::LoadKind::kDexCacheViaMethod:
- return os << "DexCacheViaMethod";
+ case HLoadString::LoadKind::kRuntimeCall:
+ return os << "RuntimeCall";
default:
LOG(FATAL) << "Unknown HLoadString::LoadKind: " << static_cast<int>(rhs);
UNREACHABLE();
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 4d96fbe24c..74bb2ab3c4 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1790,7 +1790,7 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> {
uint32_t dex_pc,
HInstruction* holder)
: vregs_(number_of_vregs, arena->Adapter(kArenaAllocEnvironmentVRegs)),
- locations_(number_of_vregs, arena->Adapter(kArenaAllocEnvironmentLocations)),
+ locations_(arena->Adapter(kArenaAllocEnvironmentLocations)),
parent_(nullptr),
method_(method),
dex_pc_(dex_pc),
@@ -1804,6 +1804,11 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> {
to_copy.GetDexPc(),
holder) {}
+ void AllocateLocations() {
+ DCHECK(locations_.empty());
+ locations_.resize(vregs_.size());
+ }
+
void SetAndCopyParentChain(ArenaAllocator* allocator, HEnvironment* parent) {
if (parent_ != nullptr) {
parent_->SetAndCopyParentChain(allocator, parent);
@@ -4167,11 +4172,9 @@ class HInvokeStaticOrDirect FINAL : public HInvoke {
// and we know that we can access the dex cache arrays using a PC-relative load.
kDexCachePcRelative,
- // Use ArtMethod* from the resolved methods of the compiled method's own ArtMethod*.
- // Used for JIT when we need to use the dex cache. This is also the last-resort-kind
- // used when other kinds are unavailable (say, dex cache arrays are not PC-relative)
- // or unimplemented or impractical (i.e. slow) on a particular architecture.
- kDexCacheViaMethod,
+ // Make a runtime call to resolve and call the method. This is the last-resort-kind
+ // used when other kinds are unimplemented on a particular architecture.
+ kRuntimeCall,
};
// Determines the location of the code pointer.
@@ -4371,7 +4374,7 @@ class HInvokeStaticOrDirect FINAL : public HInvoke {
// Does this method load kind need the current method as an input?
static bool NeedsCurrentMethodInput(MethodLoadKind kind) {
- return kind == MethodLoadKind::kRecursive || kind == MethodLoadKind::kDexCacheViaMethod;
+ return kind == MethodLoadKind::kRecursive || kind == MethodLoadKind::kRuntimeCall;
}
DECLARE_INSTRUCTION(InvokeStaticOrDirect);
@@ -5687,12 +5690,11 @@ class HLoadClass FINAL : public HInstruction {
// Load from the root table associated with the JIT compiled method.
kJitTableAddress,
- // Load from resolved types array accessed through the class loaded from
- // the compiled method's own ArtMethod*. This is the default access type when
- // all other types are unavailable.
- kDexCacheViaMethod,
+ // Load using a simple runtime call. This is the fall-back load kind when
+ // the codegen is unable to use another appropriate kind.
+ kRuntimeCall,
- kLast = kDexCacheViaMethod
+ kLast = kRuntimeCall
};
HLoadClass(HCurrentMethod* current_method,
@@ -5713,7 +5715,7 @@ class HLoadClass FINAL : public HInstruction {
DCHECK(!is_referrers_class || !needs_access_check);
SetPackedField<LoadKindField>(
- is_referrers_class ? LoadKind::kReferrersClass : LoadKind::kDexCacheViaMethod);
+ is_referrers_class ? LoadKind::kReferrersClass : LoadKind::kRuntimeCall);
SetPackedFlag<kFlagNeedsAccessCheck>(needs_access_check);
SetPackedFlag<kFlagIsInBootImage>(false);
SetPackedFlag<kFlagGenerateClInitCheck>(false);
@@ -5747,7 +5749,7 @@ class HLoadClass FINAL : public HInstruction {
bool CanCallRuntime() const {
return NeedsAccessCheck() ||
MustGenerateClinitCheck() ||
- GetLoadKind() == LoadKind::kDexCacheViaMethod ||
+ GetLoadKind() == LoadKind::kRuntimeCall ||
GetLoadKind() == LoadKind::kBssEntry;
}
@@ -5757,7 +5759,7 @@ class HLoadClass FINAL : public HInstruction {
// If the class is in the boot image, the lookup in the runtime call cannot throw.
// This keeps CanThrow() consistent between non-PIC (using kBootImageAddress) and
// PIC and subsequently avoids a DCE behavior dependency on the PIC option.
- ((GetLoadKind() == LoadKind::kDexCacheViaMethod ||
+ ((GetLoadKind() == LoadKind::kRuntimeCall ||
GetLoadKind() == LoadKind::kBssEntry) &&
!IsInBootImage());
}
@@ -5776,7 +5778,7 @@ class HLoadClass FINAL : public HInstruction {
const DexFile& GetDexFile() const { return dex_file_; }
bool NeedsDexCacheOfDeclaringClass() const OVERRIDE {
- return GetLoadKind() == LoadKind::kDexCacheViaMethod;
+ return GetLoadKind() == LoadKind::kRuntimeCall;
}
static SideEffects SideEffectsForArchRuntimeCalls() {
@@ -5827,12 +5829,12 @@ class HLoadClass FINAL : public HInstruction {
return load_kind == LoadKind::kReferrersClass ||
load_kind == LoadKind::kBootImageLinkTimePcRelative ||
load_kind == LoadKind::kBssEntry ||
- load_kind == LoadKind::kDexCacheViaMethod;
+ load_kind == LoadKind::kRuntimeCall;
}
void SetLoadKindInternal(LoadKind load_kind);
- // The special input is the HCurrentMethod for kDexCacheViaMethod or kReferrersClass.
+ // The special input is the HCurrentMethod for kRuntimeCall or kReferrersClass.
// For other load kinds it's empty or possibly some architecture-specific instruction
// for PC-relative loads, i.e. kBssEntry or kBootImageLinkTimePcRelative.
HUserRecord<HInstruction*> special_input_;
@@ -5841,7 +5843,7 @@ class HLoadClass FINAL : public HInstruction {
// - The compiling method's dex file if the class is defined there too.
// - The compiling method's dex file if the class is referenced there.
// - The dex file where the class is defined. When the load kind can only be
- // kBssEntry or kDexCacheViaMethod, we cannot emit code for this `HLoadClass`.
+ // kBssEntry or kRuntimeCall, we cannot emit code for this `HLoadClass`.
const dex::TypeIndex type_index_;
const DexFile& dex_file_;
@@ -5884,12 +5886,11 @@ class HLoadString FINAL : public HInstruction {
// Load from the root table associated with the JIT compiled method.
kJitTableAddress,
- // Load from resolved strings array accessed through the class loaded from
- // the compiled method's own ArtMethod*. This is the default access type when
- // all other types are unavailable.
- kDexCacheViaMethod,
+ // Load using a simple runtime call. This is the fall-back load kind when
+ // the codegen is unable to use another appropriate kind.
+ kRuntimeCall,
- kLast = kDexCacheViaMethod,
+ kLast = kRuntimeCall,
};
HLoadString(HCurrentMethod* current_method,
@@ -5900,7 +5901,7 @@ class HLoadString FINAL : public HInstruction {
special_input_(HUserRecord<HInstruction*>(current_method)),
string_index_(string_index),
dex_file_(dex_file) {
- SetPackedField<LoadKindField>(LoadKind::kDexCacheViaMethod);
+ SetPackedField<LoadKindField>(LoadKind::kRuntimeCall);
}
void SetLoadKind(LoadKind load_kind);
@@ -5944,7 +5945,7 @@ class HLoadString FINAL : public HInstruction {
}
bool NeedsDexCacheOfDeclaringClass() const OVERRIDE {
- return GetLoadKind() == LoadKind::kDexCacheViaMethod;
+ return GetLoadKind() == LoadKind::kRuntimeCall;
}
bool CanBeNull() const OVERRIDE { return false; }
@@ -5978,7 +5979,7 @@ class HLoadString FINAL : public HInstruction {
void SetLoadKindInternal(LoadKind load_kind);
- // The special input is the HCurrentMethod for kDexCacheViaMethod.
+ // The special input is the HCurrentMethod for kRuntimeCall.
// For other load kinds it's empty or possibly some architecture-specific instruction
// for PC-relative loads, i.e. kBssEntry or kBootImageLinkTimePcRelative.
HUserRecord<HInstruction*> special_input_;
diff --git a/compiler/optimizing/register_allocator_graph_color.cc b/compiler/optimizing/register_allocator_graph_color.cc
index 300f4c6239..2fd7b03151 100644
--- a/compiler/optimizing/register_allocator_graph_color.cc
+++ b/compiler/optimizing/register_allocator_graph_color.cc
@@ -20,7 +20,7 @@
#include "linear_order.h"
#include "register_allocation_resolver.h"
#include "ssa_liveness_analysis.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/compiler/optimizing/scheduler_arm.cc b/compiler/optimizing/scheduler_arm.cc
index 1a89567991..832a7e1571 100644
--- a/compiler/optimizing/scheduler_arm.cc
+++ b/compiler/optimizing/scheduler_arm.cc
@@ -288,6 +288,11 @@ void SchedulingLatencyVisitorARM::VisitIntermediateAddress(HIntermediateAddress*
last_visited_latency_ = kArmIntegerOpLatency;
}
+void SchedulingLatencyVisitorARM::VisitIntermediateAddressIndex(
+ HIntermediateAddressIndex* ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL) << "IntermediateAddressIndex is not implemented for ARM";
+}
+
void SchedulingLatencyVisitorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* ATTRIBUTE_UNUSED) {
last_visited_latency_ = kArmMulIntegerLatency;
}
diff --git a/compiler/optimizing/scheduler_arm.h b/compiler/optimizing/scheduler_arm.h
index 8d5e4f375b..897e97da49 100644
--- a/compiler/optimizing/scheduler_arm.h
+++ b/compiler/optimizing/scheduler_arm.h
@@ -17,7 +17,11 @@
#ifndef ART_COMPILER_OPTIMIZING_SCHEDULER_ARM_H_
#define ART_COMPILER_OPTIMIZING_SCHEDULER_ARM_H_
+#ifdef ART_USE_OLD_ARM_BACKEND
+#include "code_generator_arm.h"
+#else
#include "code_generator_arm_vixl.h"
+#endif
#include "scheduler.h"
namespace art {
@@ -99,6 +103,7 @@ class SchedulingLatencyVisitorARM : public SchedulingLatencyVisitor {
M(BitwiseNegatedRight, unused) \
M(MultiplyAccumulate, unused) \
M(IntermediateAddress, unused) \
+ M(IntermediateAddressIndex, unused) \
M(DataProcWithShifterOp, unused)
#define DECLARE_VISIT_INSTRUCTION(type, unused) \
diff --git a/compiler/optimizing/scheduler_arm64.cc b/compiler/optimizing/scheduler_arm64.cc
index 558dcc4cbc..83b487fb5b 100644
--- a/compiler/optimizing/scheduler_arm64.cc
+++ b/compiler/optimizing/scheduler_arm64.cc
@@ -16,6 +16,7 @@
#include "scheduler_arm64.h"
#include "code_generator_utils.h"
+#include "mirror/array-inl.h"
namespace art {
namespace arm64 {
@@ -43,6 +44,13 @@ void SchedulingLatencyVisitorARM64::VisitIntermediateAddress(
last_visited_latency_ = kArm64IntegerOpLatency + 2;
}
+void SchedulingLatencyVisitorARM64::VisitIntermediateAddressIndex(
+ HIntermediateAddressIndex* instr ATTRIBUTE_UNUSED) {
+ // Although the code generated is a simple `add` instruction, we found through empirical results
+ // that spacing it from its use in memory accesses was beneficial.
+ last_visited_latency_ = kArm64DataProcWithShifterOpLatency + 2;
+}
+
void SchedulingLatencyVisitorARM64::VisitMultiplyAccumulate(HMultiplyAccumulate* ATTRIBUTE_UNUSED) {
last_visited_latency_ = kArm64MulIntegerLatency;
}
@@ -192,5 +200,148 @@ void SchedulingLatencyVisitorARM64::VisitTypeConversion(HTypeConversion* instr)
}
}
+void SchedulingLatencyVisitorARM64::HandleSimpleArithmeticSIMD(HVecOperation *instr) {
+ if (Primitive::IsFloatingPointType(instr->GetPackedType())) {
+ last_visited_latency_ = kArm64SIMDFloatingPointOpLatency;
+ } else {
+ last_visited_latency_ = kArm64SIMDIntegerOpLatency;
+ }
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecReplicateScalar(
+ HVecReplicateScalar* instr ATTRIBUTE_UNUSED) {
+ last_visited_latency_ = kArm64SIMDReplicateOpLatency;
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecSetScalars(HVecSetScalars* instr) {
+ LOG(FATAL) << "Unsupported SIMD instruction " << instr->GetId();
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecSumReduce(HVecSumReduce* instr) {
+ LOG(FATAL) << "Unsupported SIMD instruction " << instr->GetId();
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecCnv(HVecCnv* instr ATTRIBUTE_UNUSED) {
+ last_visited_latency_ = kArm64SIMDTypeConversionInt2FPLatency;
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecNeg(HVecNeg* instr) {
+ HandleSimpleArithmeticSIMD(instr);
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecAbs(HVecAbs* instr) {
+ HandleSimpleArithmeticSIMD(instr);
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecNot(HVecNot* instr) {
+ if (instr->GetPackedType() == Primitive::kPrimBoolean) {
+ last_visited_internal_latency_ = kArm64SIMDIntegerOpLatency;
+ }
+ last_visited_latency_ = kArm64SIMDIntegerOpLatency;
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecAdd(HVecAdd* instr) {
+ HandleSimpleArithmeticSIMD(instr);
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecHalvingAdd(HVecHalvingAdd* instr) {
+ HandleSimpleArithmeticSIMD(instr);
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecSub(HVecSub* instr) {
+ HandleSimpleArithmeticSIMD(instr);
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecMul(HVecMul* instr) {
+ if (Primitive::IsFloatingPointType(instr->GetPackedType())) {
+ last_visited_latency_ = kArm64SIMDMulFloatingPointLatency;
+ } else {
+ last_visited_latency_ = kArm64SIMDMulIntegerLatency;
+ }
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecDiv(HVecDiv* instr) {
+ if (instr->GetPackedType() == Primitive::kPrimFloat) {
+ last_visited_latency_ = kArm64SIMDDivFloatLatency;
+ } else {
+ DCHECK(instr->GetPackedType() == Primitive::kPrimDouble);
+ last_visited_latency_ = kArm64SIMDDivDoubleLatency;
+ }
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecMin(HVecMin* instr) {
+ HandleSimpleArithmeticSIMD(instr);
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecMax(HVecMax* instr) {
+ HandleSimpleArithmeticSIMD(instr);
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecAnd(HVecAnd* instr ATTRIBUTE_UNUSED) {
+ last_visited_latency_ = kArm64SIMDIntegerOpLatency;
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecAndNot(HVecAndNot* instr) {
+ LOG(FATAL) << "Unsupported SIMD instruction " << instr->GetId();
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecOr(HVecOr* instr ATTRIBUTE_UNUSED) {
+ last_visited_latency_ = kArm64SIMDIntegerOpLatency;
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecXor(HVecXor* instr ATTRIBUTE_UNUSED) {
+ last_visited_latency_ = kArm64SIMDIntegerOpLatency;
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecShl(HVecShl* instr) {
+ HandleSimpleArithmeticSIMD(instr);
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecShr(HVecShr* instr) {
+ HandleSimpleArithmeticSIMD(instr);
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecUShr(HVecUShr* instr) {
+ HandleSimpleArithmeticSIMD(instr);
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecMultiplyAccumulate(
+ HVecMultiplyAccumulate* instr ATTRIBUTE_UNUSED) {
+ last_visited_latency_ = kArm64SIMDMulIntegerLatency;
+}
+
+void SchedulingLatencyVisitorARM64::HandleVecAddress(
+ HVecMemoryOperation* instruction,
+ size_t size ATTRIBUTE_UNUSED) {
+ HInstruction* index = instruction->InputAt(1);
+ if (!index->IsConstant()) {
+ last_visited_internal_latency_ += kArm64DataProcWithShifterOpLatency;
+ }
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecLoad(HVecLoad* instr) {
+ last_visited_internal_latency_ = 0;
+ size_t size = Primitive::ComponentSize(instr->GetPackedType());
+
+ if (instr->GetPackedType() == Primitive::kPrimChar
+ && mirror::kUseStringCompression
+ && instr->IsStringCharAt()) {
+ // Set latencies for the uncompressed case.
+ last_visited_internal_latency_ += kArm64MemoryLoadLatency + kArm64BranchLatency;
+ HandleVecAddress(instr, size);
+ last_visited_latency_ = kArm64SIMDMemoryLoadLatency;
+ } else {
+ HandleVecAddress(instr, size);
+ last_visited_latency_ = kArm64SIMDMemoryLoadLatency;
+ }
+}
+
+void SchedulingLatencyVisitorARM64::VisitVecStore(HVecStore* instr) {
+ last_visited_internal_latency_ = 0;
+ size_t size = Primitive::ComponentSize(instr->GetPackedType());
+ HandleVecAddress(instr, size);
+ last_visited_latency_ = kArm64SIMDMemoryStoreLatency;
+}
+
} // namespace arm64
} // namespace art
diff --git a/compiler/optimizing/scheduler_arm64.h b/compiler/optimizing/scheduler_arm64.h
index 7a33720655..63d5b7d6b6 100644
--- a/compiler/optimizing/scheduler_arm64.h
+++ b/compiler/optimizing/scheduler_arm64.h
@@ -42,6 +42,18 @@ static constexpr uint32_t kArm64LoadStringInternalLatency = 7;
static constexpr uint32_t kArm64MulFloatingPointLatency = 6;
static constexpr uint32_t kArm64MulIntegerLatency = 6;
static constexpr uint32_t kArm64TypeConversionFloatingPointIntegerLatency = 5;
+static constexpr uint32_t kArm64BranchLatency = kArm64IntegerOpLatency;
+
+static constexpr uint32_t kArm64SIMDFloatingPointOpLatency = 10;
+static constexpr uint32_t kArm64SIMDIntegerOpLatency = 6;
+static constexpr uint32_t kArm64SIMDMemoryLoadLatency = 10;
+static constexpr uint32_t kArm64SIMDMemoryStoreLatency = 6;
+static constexpr uint32_t kArm64SIMDMulFloatingPointLatency = 12;
+static constexpr uint32_t kArm64SIMDMulIntegerLatency = 12;
+static constexpr uint32_t kArm64SIMDReplicateOpLatency = 16;
+static constexpr uint32_t kArm64SIMDDivDoubleLatency = 60;
+static constexpr uint32_t kArm64SIMDDivFloatLatency = 30;
+static constexpr uint32_t kArm64SIMDTypeConversionInt2FPLatency = 10;
class SchedulingLatencyVisitorARM64 : public SchedulingLatencyVisitor {
public:
@@ -52,29 +64,54 @@ class SchedulingLatencyVisitorARM64 : public SchedulingLatencyVisitor {
// We add a second unused parameter to be able to use this macro like the others
// defined in `nodes.h`.
-#define FOR_EACH_SCHEDULED_COMMON_INSTRUCTION(M) \
- 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) \
- M(NewInstance , unused) \
- M(Rem , unused) \
- M(StaticFieldGet , unused) \
- M(SuspendCheck , unused) \
- M(TypeConversion , unused)
+#define FOR_EACH_SCHEDULED_COMMON_INSTRUCTION(M) \
+ 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) \
+ M(NewInstance , unused) \
+ M(Rem , unused) \
+ M(StaticFieldGet , unused) \
+ M(SuspendCheck , unused) \
+ M(TypeConversion , unused) \
+ M(VecReplicateScalar , unused) \
+ M(VecSetScalars , unused) \
+ M(VecSumReduce , unused) \
+ M(VecCnv , unused) \
+ M(VecNeg , unused) \
+ M(VecAbs , unused) \
+ M(VecNot , unused) \
+ M(VecAdd , unused) \
+ M(VecHalvingAdd , unused) \
+ M(VecSub , unused) \
+ M(VecMul , unused) \
+ M(VecDiv , unused) \
+ M(VecMin , unused) \
+ M(VecMax , unused) \
+ M(VecAnd , unused) \
+ M(VecAndNot , unused) \
+ M(VecOr , unused) \
+ M(VecXor , unused) \
+ M(VecShl , unused) \
+ M(VecShr , unused) \
+ M(VecUShr , unused) \
+ M(VecMultiplyAccumulate, unused) \
+ M(VecLoad , unused) \
+ M(VecStore , unused)
#define FOR_EACH_SCHEDULED_SHARED_INSTRUCTION(M) \
M(BitwiseNegatedRight, unused) \
M(MultiplyAccumulate, unused) \
M(IntermediateAddress, unused) \
+ M(IntermediateAddressIndex, unused) \
M(DataProcWithShifterOp, unused)
#define DECLARE_VISIT_INSTRUCTION(type, unused) \
@@ -85,6 +122,10 @@ class SchedulingLatencyVisitorARM64 : public SchedulingLatencyVisitor {
FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION)
#undef DECLARE_VISIT_INSTRUCTION
+
+ private:
+ void HandleSimpleArithmeticSIMD(HVecOperation *instr);
+ void HandleVecAddress(HVecMemoryOperation* instruction, size_t size);
};
class HSchedulerARM64 : public HScheduler {
@@ -101,6 +142,8 @@ class HSchedulerARM64 : public HScheduler {
return true;
FOR_EACH_CONCRETE_INSTRUCTION_ARM64(CASE_INSTRUCTION_KIND)
return true;
+ FOR_EACH_SCHEDULED_COMMON_INSTRUCTION(CASE_INSTRUCTION_KIND)
+ return true;
default:
return HScheduler::IsSchedulable(instruction);
}
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 7b8104b8ca..106b709eda 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -159,7 +159,7 @@ HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(HLoadClass* load_class,
CompilerDriver* compiler_driver,
const DexCompilationUnit& dex_compilation_unit) {
Handle<mirror::Class> klass = load_class->GetClass();
- DCHECK(load_class->GetLoadKind() == HLoadClass::LoadKind::kDexCacheViaMethod ||
+ DCHECK(load_class->GetLoadKind() == HLoadClass::LoadKind::kRuntimeCall ||
load_class->GetLoadKind() == HLoadClass::LoadKind::kReferrersClass)
<< load_class->GetLoadKind();
DCHECK(!load_class->IsInBootImage()) << "HLoadClass should not be optimized before sharpening.";
@@ -185,7 +185,7 @@ HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(HLoadClass* load_class,
DCHECK(!runtime->UseJitCompilation());
if (!compiler_driver->GetSupportBootImageFixup()) {
// compiler_driver_test. Do not sharpen.
- desired_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod;
+ desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
} else if ((klass != nullptr) &&
compiler_driver->IsImageClass(dex_file.StringByTypeIdx(type_index))) {
is_in_boot_image = true;
@@ -210,7 +210,7 @@ HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(HLoadClass* load_class,
// this `HLoadClass` hasn't been executed in the interpreter.
// Fallback to the dex cache.
// TODO(ngeoffray): Generate HDeoptimize instead.
- desired_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod;
+ desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
}
} else if (is_in_boot_image && !codegen->GetCompilerOptions().GetCompilePic()) {
// AOT app compilation. Check if the class is in the boot image.
@@ -229,7 +229,7 @@ HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(HLoadClass* load_class,
}
if (!IsSameDexFile(load_class->GetDexFile(), *dex_compilation_unit.GetDexFile())) {
- if ((load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) ||
+ if ((load_kind == HLoadClass::LoadKind::kRuntimeCall) ||
(load_kind == HLoadClass::LoadKind::kBssEntry)) {
// We actually cannot reference this class, we're forced to bail.
// We cannot reference this class with Bss, as the entrypoint will lookup the class
@@ -241,7 +241,7 @@ HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(HLoadClass* load_class,
}
void HSharpening::ProcessLoadString(HLoadString* load_string) {
- DCHECK_EQ(load_string->GetLoadKind(), HLoadString::LoadKind::kDexCacheViaMethod);
+ DCHECK_EQ(load_string->GetLoadKind(), HLoadString::LoadKind::kRuntimeCall);
const DexFile& dex_file = load_string->GetDexFile();
dex::StringIndex string_index = load_string->GetStringIndex();
@@ -268,7 +268,7 @@ void HSharpening::ProcessLoadString(HLoadString* load_string) {
desired_load_kind = HLoadString::LoadKind::kBootImageLinkTimePcRelative;
} else {
// compiler_driver_test. Do not sharpen.
- desired_load_kind = HLoadString::LoadKind::kDexCacheViaMethod;
+ desired_load_kind = HLoadString::LoadKind::kRuntimeCall;
}
} else if (runtime->UseJitCompilation()) {
DCHECK(!codegen_->GetCompilerOptions().GetCompilePic());
@@ -280,7 +280,7 @@ void HSharpening::ProcessLoadString(HLoadString* load_string) {
desired_load_kind = HLoadString::LoadKind::kJitTableAddress;
}
} else {
- desired_load_kind = HLoadString::LoadKind::kDexCacheViaMethod;
+ desired_load_kind = HLoadString::LoadKind::kRuntimeCall;
}
} else {
// AOT app compilation. Try to lookup the string without allocating if not found.
diff --git a/compiler/utils/dedupe_set_test.cc b/compiler/utils/dedupe_set_test.cc
index 4c0979e0b7..b390508ed4 100644
--- a/compiler/utils/dedupe_set_test.cc
+++ b/compiler/utils/dedupe_set_test.cc
@@ -23,7 +23,7 @@
#include "base/array_ref.h"
#include "dedupe_set-inl.h"
#include "gtest/gtest.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index c03b98c5c2..24900a7f10 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -1456,6 +1456,86 @@ void Mips64Assembler::Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegist
EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10);
}
+void Mips64Assembler::Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe);
+}
+
+void Mips64Assembler::Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe);
+}
+
void Mips64Assembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b);
@@ -1496,6 +1576,26 @@ void Mips64Assembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister
EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b);
}
+void Mips64Assembler::FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b);
+}
+
+void Mips64Assembler::FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b);
+}
+
+void Mips64Assembler::FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b);
+}
+
+void Mips64Assembler::FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
+ CHECK(HasMsa());
+ EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b);
+}
+
void Mips64Assembler::Ffint_sW(VectorRegister wd, VectorRegister ws) {
CHECK(HasMsa());
EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e);
@@ -1795,6 +1895,17 @@ void Mips64Assembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister
EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14);
}
+void Mips64Assembler::ReplicateFPToVectorRegister(VectorRegister dst,
+ FpuRegister src,
+ bool is_double) {
+ // Float or double in FPU register Fx can be considered as 0th element in vector register Wx.
+ if (is_double) {
+ SplatiD(dst, static_cast<VectorRegister>(src), 0);
+ } else {
+ SplatiW(dst, static_cast<VectorRegister>(src), 0);
+ }
+}
+
void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
TemplateLoadConst32(this, rd, value);
}
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index c92cf4c048..b212958ddb 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -704,6 +704,22 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
void Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
@@ -713,6 +729,10 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
void FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ void FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void Ffint_sW(VectorRegister wd, VectorRegister ws);
void Ffint_sD(VectorRegister wd, VectorRegister ws);
@@ -774,6 +794,9 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
void IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt);
void IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt);
+ // Helper for replicating floating point value in all destination elements.
+ void ReplicateFPToVectorRegister(VectorRegister dst, FpuRegister src, bool is_double);
+
// Higher level composite instructions.
int InstrCountForLoadReplicatedConst32(int64_t);
void LoadConst32(GpuRegister rd, int32_t value);
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index fbebe0ce15..bdf9598ee7 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -2998,6 +2998,86 @@ TEST_F(AssemblerMIPS64Test, Aver_uD) {
"aver_u.d");
}
+TEST_F(AssemblerMIPS64Test, Max_sB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_sB, "max_s.b ${reg1}, ${reg2}, ${reg3}"),
+ "max_s.b");
+}
+
+TEST_F(AssemblerMIPS64Test, Max_sH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_sH, "max_s.h ${reg1}, ${reg2}, ${reg3}"),
+ "max_s.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Max_sW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_sW, "max_s.w ${reg1}, ${reg2}, ${reg3}"),
+ "max_s.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Max_sD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_sD, "max_s.d ${reg1}, ${reg2}, ${reg3}"),
+ "max_s.d");
+}
+
+TEST_F(AssemblerMIPS64Test, Max_uB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_uB, "max_u.b ${reg1}, ${reg2}, ${reg3}"),
+ "max_u.b");
+}
+
+TEST_F(AssemblerMIPS64Test, Max_uH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_uH, "max_u.h ${reg1}, ${reg2}, ${reg3}"),
+ "max_u.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Max_uW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_uW, "max_u.w ${reg1}, ${reg2}, ${reg3}"),
+ "max_u.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Max_uD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Max_uD, "max_u.d ${reg1}, ${reg2}, ${reg3}"),
+ "max_u.d");
+}
+
+TEST_F(AssemblerMIPS64Test, Min_sB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_sB, "min_s.b ${reg1}, ${reg2}, ${reg3}"),
+ "min_s.b");
+}
+
+TEST_F(AssemblerMIPS64Test, Min_sH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_sH, "min_s.h ${reg1}, ${reg2}, ${reg3}"),
+ "min_s.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Min_sW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_sW, "min_s.w ${reg1}, ${reg2}, ${reg3}"),
+ "min_s.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Min_sD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_sD, "min_s.d ${reg1}, ${reg2}, ${reg3}"),
+ "min_s.d");
+}
+
+TEST_F(AssemblerMIPS64Test, Min_uB) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_uB, "min_u.b ${reg1}, ${reg2}, ${reg3}"),
+ "min_u.b");
+}
+
+TEST_F(AssemblerMIPS64Test, Min_uH) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_uH, "min_u.h ${reg1}, ${reg2}, ${reg3}"),
+ "min_u.h");
+}
+
+TEST_F(AssemblerMIPS64Test, Min_uW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_uW, "min_u.w ${reg1}, ${reg2}, ${reg3}"),
+ "min_u.w");
+}
+
+TEST_F(AssemblerMIPS64Test, Min_uD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::Min_uD, "min_u.d ${reg1}, ${reg2}, ${reg3}"),
+ "min_u.d");
+}
+
TEST_F(AssemblerMIPS64Test, FaddW) {
DriverStr(RepeatVVV(&mips64::Mips64Assembler::FaddW, "fadd.w ${reg1}, ${reg2}, ${reg3}"),
"fadd.w");
@@ -3038,6 +3118,26 @@ TEST_F(AssemblerMIPS64Test, FdivD) {
"fdiv.d");
}
+TEST_F(AssemblerMIPS64Test, FmaxW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmaxW, "fmax.w ${reg1}, ${reg2}, ${reg3}"),
+ "fmax.w");
+}
+
+TEST_F(AssemblerMIPS64Test, FmaxD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FmaxD, "fmax.d ${reg1}, ${reg2}, ${reg3}"),
+ "fmax.d");
+}
+
+TEST_F(AssemblerMIPS64Test, FminW) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FminW, "fmin.w ${reg1}, ${reg2}, ${reg3}"),
+ "fmin.w");
+}
+
+TEST_F(AssemblerMIPS64Test, FminD) {
+ DriverStr(RepeatVVV(&mips64::Mips64Assembler::FminD, "fmin.d ${reg1}, ${reg2}, ${reg3}"),
+ "fmin.d");
+}
+
TEST_F(AssemblerMIPS64Test, Ffint_sW) {
DriverStr(RepeatVV(&mips64::Mips64Assembler::Ffint_sW, "ffint_s.w ${reg1}, ${reg2}"),
"ffint_s.w");
diff --git a/compiler/utils/swap_space.cc b/compiler/utils/swap_space.cc
index a1eb08e041..4f6c915142 100644
--- a/compiler/utils/swap_space.cc
+++ b/compiler/utils/swap_space.cc
@@ -23,7 +23,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/mutex.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 53e73c344e..dcdf3bca02 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -74,6 +74,7 @@
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "oat_file.h"
#include "oat_file_assistant.h"
#include "oat_writer.h"
#include "os.h"
@@ -477,6 +478,16 @@ class WatchDog {
android::base::LogId::DEFAULT,
LogSeverity::FATAL,
message.c_str());
+ // If we're on the host, try to dump all threads to get a sense of what's going on. This is
+ // restricted to the host as the dump may itself go bad.
+ // TODO: Use a double watchdog timeout, so we can enable this on-device.
+ if (!kIsTargetBuild && Runtime::Current() != nullptr) {
+ Runtime::Current()->AttachCurrentThread("Watchdog thread attached for dumping",
+ true,
+ nullptr,
+ false);
+ Runtime::Current()->DumpForSigQuit(std::cerr);
+ }
exit(1);
}
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 6420aa8759..b604e8b5f1 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -28,6 +28,7 @@
#include "base/logging.h"
#include "base/macros.h"
+#include "base/mutex-inl.h"
#include "dex_file-inl.h"
#include "dex2oat_environment_test.h"
#include "dex2oat_return_codes.h"
@@ -38,6 +39,8 @@
namespace art {
+static constexpr size_t kMaxMethodIds = 65535;
+
using android::base::StringPrintf;
class Dex2oatTest : public Dex2oatEnvironmentTest {
@@ -612,7 +615,7 @@ class Dex2oatLayoutTest : public Dex2oatTest {
ProfileCompilationInfo info;
std::string profile_key = ProfileCompilationInfo::GetProfileDexFileKey(dex_location);
for (size_t i = 0; i < num_classes; ++i) {
- info.AddClassIndex(profile_key, checksum, dex::TypeIndex(1 + i));
+ info.AddClassIndex(profile_key, checksum, dex::TypeIndex(1 + i), kMaxMethodIds);
}
bool result = info.Save(profile_test_fd);
close(profile_test_fd);
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
index 829e9feda8..d279bcb65c 100644
--- a/dexlayout/dex_visualize.cc
+++ b/dexlayout/dex_visualize.cc
@@ -174,7 +174,7 @@ class Dumper {
ProfileCompilationInfo* profile_info) {
if (profile_info != nullptr) {
uint32_t method_idx = method->GetMethodId()->GetIndex();
- if (!profile_info->ContainsMethod(MethodReference(dex_file, method_idx))) {
+ if (!profile_info->ContainsHotMethod(MethodReference(dex_file, method_idx))) {
return;
}
}
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 205c0d1384..db227676c2 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1557,7 +1557,7 @@ void DexLayout::LayoutStringData(const DexFile* dex_file) {
(method->GetAccessFlags() & kAccConstructor) != 0 &&
(method->GetAccessFlags() & kAccStatic) != 0;
const bool method_executed = is_clinit ||
- info_->ContainsMethod(MethodReference(dex_file, method_id->GetIndex()));
+ info_->IsStartupOrHotMethod(MethodReference(dex_file, method_id->GetIndex()));
if (!method_executed) {
continue;
}
@@ -1699,7 +1699,7 @@ int32_t DexLayout::LayoutCodeItems(const DexFile* dex_file,
(method->GetAccessFlags() & kAccConstructor) != 0 &&
(method->GetAccessFlags() & kAccStatic) != 0;
const bool is_method_executed = is_clinit ||
- info_->ContainsMethod(MethodReference(dex_file, method_id->GetIndex()));
+ info_->IsStartupOrHotMethod(MethodReference(dex_file, method_id->GetIndex()));
code_items[is_method_executed
? CodeItemKind::kMethodExecuted
: CodeItemKind::kMethodNotExecuted]
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 1d09a7f72a..6fe8eeb66e 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -341,18 +341,30 @@ class DexLayoutTest : public CommonRuntimeTest {
if ((i & 3) != 0) {
pfi.AddMethodIndex(dex_location,
dex_file->GetLocationChecksum(),
- i);
+ i,
+ dex_file->NumMethodIds());
+ ++profile_methods;
+ } else if ((i & 2) != 0) {
+ pfi.AddSampledMethod(/*startup*/true,
+ dex_location,
+ dex_file->GetLocationChecksum(),
+ i,
+ dex_file->NumMethodIds());
++profile_methods;
}
}
DexCacheResolvedClasses cur_classes(dex_location,
dex_location,
- dex_file->GetLocationChecksum());
+ dex_file->GetLocationChecksum(),
+ dex_file->NumMethodIds());
// Add every even class too.
for (uint32_t i = 0; i < dex_file->NumClassDefs(); i += 1) {
- cur_classes.AddClass(dex_file->GetClassDef(i).class_idx_);
- ++profile_classes;
+ if ((i & 2) == 0) {
+ cur_classes.AddClass(dex_file->GetClassDef(i).class_idx_);
+ ++profile_classes;
+ }
}
+ classes.insert(cur_classes);
}
pfi.AddMethodsAndClasses(pmis, classes);
// Write to provided file.
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index 8894cc9899..91203cb9f9 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -438,10 +438,16 @@ static const MipsInstruction gMipsInstructions[] = {
{ kMsaMask | (0x7 << 23), kMsa | (0x5 << 23) | 0x10, "ave_u", "Vkmn" },
{ kMsaMask | (0x7 << 23), kMsa | (0x6 << 23) | 0x10, "aver_s", "Vkmn" },
{ kMsaMask | (0x7 << 23), kMsa | (0x7 << 23) | 0x10, "aver_u", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x2 << 23) | 0xe, "max_s", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x3 << 23) | 0xe, "max_u", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x4 << 23) | 0xe, "min_s", "Vkmn" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x5 << 23) | 0xe, "min_u", "Vkmn" },
{ kMsaMask | (0xf << 22), kMsa | (0x0 << 22) | 0x1b, "fadd", "Ukmn" },
{ kMsaMask | (0xf << 22), kMsa | (0x1 << 22) | 0x1b, "fsub", "Ukmn" },
{ kMsaMask | (0xf << 22), kMsa | (0x2 << 22) | 0x1b, "fmul", "Ukmn" },
{ kMsaMask | (0xf << 22), kMsa | (0x3 << 22) | 0x1b, "fdiv", "Ukmn" },
+ { kMsaMask | (0xf << 22), kMsa | (0xe << 22) | 0x1b, "fmax", "Ukmn" },
+ { kMsaMask | (0xf << 22), kMsa | (0xc << 22) | 0x1b, "fmin", "Ukmn" },
{ kMsaMask | (0x1ff << 17), kMsa | (0x19e << 17) | 0x1e, "ffint_s", "ukm" },
{ kMsaMask | (0x1ff << 17), kMsa | (0x19c << 17) | 0x1e, "ftint_s", "ukm" },
{ kMsaMask | (0x7 << 23), kMsa | (0x0 << 23) | 0xd, "sll", "Vkmn" },
diff --git a/imgdiag/imgdiag_test.cc b/imgdiag/imgdiag_test.cc
index 0d46b2ea7a..c948d3cbe2 100644
--- a/imgdiag/imgdiag_test.cc
+++ b/imgdiag/imgdiag_test.cc
@@ -28,6 +28,7 @@
#include "runtime/utils.h"
#include "runtime/gc/space/image_space.h"
#include "runtime/gc/heap.h"
+#include "runtime/runtime.h"
#include <sys/types.h>
#include <unistd.h>
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index f07e0f9941..a79b408a40 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -63,6 +63,7 @@
#include "safe_map.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
+#include "stack.h"
#include "stack_map.h"
#include "string_reference.h"
#include "thread_list.h"
diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc
index 1c328987cb..ccf9ac6ad5 100644
--- a/profman/profile_assistant_test.cc
+++ b/profman/profile_assistant_test.cc
@@ -30,6 +30,8 @@
namespace art {
+static constexpr size_t kMaxMethodIds = 65535;
+
class ProfileAssistantTest : public CommonRuntimeTest {
public:
void PostRuntimeCreate() OVERRIDE {
@@ -56,15 +58,18 @@ class ProfileAssistantTest : public CommonRuntimeTest {
GetOfflineProfileMethodInfo(dex_location1, dex_location_checksum1,
dex_location2, dex_location_checksum2);
if (reverse_dex_write_order) {
- ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, pmi));
- ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, pmi));
+ ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi));
+ ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi));
} else {
- ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, pmi));
- ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, pmi));
+ ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi));
+ ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi));
}
}
for (uint16_t i = 0; i < number_of_classes; i++) {
- ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, dex::TypeIndex(i)));
+ ASSERT_TRUE(info->AddClassIndex(dex_location1,
+ dex_location_checksum1,
+ dex::TypeIndex(i),
+ kMaxMethodIds));
}
ASSERT_TRUE(info->Save(GetFd(profile)));
@@ -72,6 +77,29 @@ class ProfileAssistantTest : public CommonRuntimeTest {
ASSERT_TRUE(profile.GetFile()->ResetOffset());
}
+ void SetupBasicProfile(const std::string& id,
+ uint32_t checksum,
+ uint16_t number_of_methods,
+ const std::vector<uint32_t> hot_methods,
+ const std::vector<uint32_t> startup_methods,
+ const std::vector<uint32_t> post_startup_methods,
+ const ScratchFile& profile,
+ ProfileCompilationInfo* info) {
+ std::string dex_location = "location1" + id;
+ for (uint32_t idx : hot_methods) {
+ info->AddMethodIndex(dex_location, checksum, idx, number_of_methods);
+ }
+ for (uint32_t idx : startup_methods) {
+ info->AddSampledMethod(/*startup*/true, dex_location, checksum, idx, number_of_methods);
+ }
+ for (uint32_t idx : post_startup_methods) {
+ info->AddSampledMethod(/*startup*/false, dex_location, checksum, idx, number_of_methods);
+ }
+ ASSERT_TRUE(info->Save(GetFd(profile)));
+ ASSERT_EQ(0, profile.GetFile()->Flush());
+ ASSERT_TRUE(profile.GetFile()->ResetOffset());
+ }
+
// Creates an inline cache which will be destructed at the end of the test.
ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() {
used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap(
@@ -84,8 +112,8 @@ class ProfileAssistantTest : public CommonRuntimeTest {
const std::string& dex_location2, uint32_t dex_checksum2) {
ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
- pmi.dex_references.emplace_back(dex_location1, dex_checksum1);
- pmi.dex_references.emplace_back(dex_location2, dex_checksum2);
+ pmi.dex_references.emplace_back(dex_location1, dex_checksum1, kMaxMethodIds);
+ pmi.dex_references.emplace_back(dex_location2, dex_checksum2, kMaxMethodIds);
// Monomorphic
for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
@@ -193,28 +221,42 @@ class ProfileAssistantTest : public CommonRuntimeTest {
return true;
}
- bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
- ScratchFile class_names_file;
+ bool RunProfman(const std::string& filename,
+ std::vector<std::string>& extra_args,
+ std::string* output) {
+ ScratchFile output_file;
std::string profman_cmd = GetProfmanCmd();
std::vector<std::string> argv_str;
argv_str.push_back(profman_cmd);
- argv_str.push_back("--dump-classes-and-methods");
+ argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end());
argv_str.push_back("--profile-file=" + filename);
argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]);
argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]);
- argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(class_names_file)));
+ argv_str.push_back("--dump-output-to-fd=" + std::to_string(GetFd(output_file)));
std::string error;
EXPECT_EQ(ExecAndReturnCode(argv_str, &error), 0);
- File* file = class_names_file.GetFile();
+ File* file = output_file.GetFile();
EXPECT_EQ(0, file->Flush());
EXPECT_TRUE(file->ResetOffset());
int64_t length = file->GetLength();
std::unique_ptr<char[]> buf(new char[length]);
EXPECT_EQ(file->Read(buf.get(), length, 0), length);
- *file_contents = std::string(buf.get(), length);
+ *output = std::string(buf.get(), length);
return true;
}
+ bool DumpClassesAndMethods(const std::string& filename, std::string* file_contents) {
+ std::vector<std::string> extra_args;
+ extra_args.push_back("--dump-classes-and-methods");
+ return RunProfman(filename, extra_args, file_contents);
+ }
+
+ bool DumpOnly(const std::string& filename, std::string* file_contents) {
+ std::vector<std::string> extra_args;
+ extra_args.push_back("--dump-only");
+ return RunProfman(filename, extra_args, file_contents);
+ }
+
bool CreateAndDump(const std::string& input_file_contents,
std::string* output_file_contents) {
ScratchFile profile_file;
@@ -520,10 +562,11 @@ TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) {
TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) {
// Class names put here need to be in sorted order.
std::vector<std::string> class_names = {
+ "HLjava/lang/Object;-><init>()V",
"Ljava/lang/Comparable;",
"Ljava/lang/Math;",
"Ljava/lang/Object;",
- "Ljava/lang/Object;-><init>()V"
+ "SPLjava/lang/Comparable;->compareTo(Ljava/lang/Object;)I",
};
std::string file_contents;
for (std::string& class_name : class_names) {
@@ -807,15 +850,80 @@ TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) {
// Verify that the start-up classes contain the invalid class.
std::set<dex::TypeIndex> classes;
- std::set<uint16_t> methods;
- ASSERT_TRUE(info.GetClassesAndMethods(*dex_file, &classes, &methods));
+ std::set<uint16_t> hot_methods;
+ std::set<uint16_t> startup_methods;
+ std::set<uint16_t> post_start_methods;
+ ASSERT_TRUE(info.GetClassesAndMethods(*dex_file,
+ &classes,
+ &hot_methods,
+ &startup_methods,
+ &post_start_methods));
ASSERT_EQ(1u, classes.size());
ASSERT_TRUE(classes.find(invalid_class_index) != classes.end());
// Verify that the invalid method is in the profile.
- ASSERT_EQ(2u, methods.size());
+ ASSERT_EQ(2u, hot_methods.size());
uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1;
- ASSERT_TRUE(methods.find(invalid_method_index) != methods.end());
+ ASSERT_TRUE(hot_methods.find(invalid_method_index) != hot_methods.end());
+}
+
+TEST_F(ProfileAssistantTest, DumpOnly) {
+ ScratchFile profile;
+
+ const uint32_t kNumberOfMethods = 64;
+ std::vector<uint32_t> hot_methods;
+ std::vector<uint32_t> startup_methods;
+ std::vector<uint32_t> post_startup_methods;
+ for (size_t i = 0; i < kNumberOfMethods; ++i) {
+ if (i % 2 == 0) {
+ hot_methods.push_back(i);
+ }
+ if (i % 3 == 1) {
+ startup_methods.push_back(i);
+ }
+ if (i % 4 == 2) {
+ post_startup_methods.push_back(i);
+ }
+ }
+ EXPECT_GT(hot_methods.size(), 0u);
+ EXPECT_GT(startup_methods.size(), 0u);
+ EXPECT_GT(post_startup_methods.size(), 0u);
+ ProfileCompilationInfo info1;
+ SetupBasicProfile("p1",
+ 1,
+ kNumberOfMethods,
+ hot_methods,
+ startup_methods,
+ post_startup_methods,
+ profile,
+ &info1);
+ std::string output;
+ DumpOnly(profile.GetFilename(), &output);
+ const size_t hot_offset = output.find("hot methods:");
+ const size_t startup_offset = output.find("startup methods:");
+ const size_t post_startup_offset = output.find("post startup methods:");
+ const size_t classes_offset = output.find("classes:");
+ ASSERT_NE(hot_offset, std::string::npos);
+ ASSERT_NE(startup_offset, std::string::npos);
+ ASSERT_NE(post_startup_offset, std::string::npos);
+ ASSERT_LT(hot_offset, startup_offset);
+ ASSERT_LT(startup_offset, post_startup_offset);
+ // Check the actual contents of the dump by looking at the offsets of the methods.
+ for (uint32_t m : hot_methods) {
+ const size_t pos = output.find(std::to_string(m) + "[],", hot_offset);
+ ASSERT_NE(pos, std::string::npos);
+ EXPECT_LT(pos, startup_offset);
+ }
+ for (uint32_t m : startup_methods) {
+ const size_t pos = output.find(std::to_string(m) + ",", startup_offset);
+ ASSERT_NE(pos, std::string::npos);
+ EXPECT_LT(pos, post_startup_offset);
+ }
+ for (uint32_t m : post_startup_methods) {
+ const size_t pos = output.find(std::to_string(m) + ",", post_startup_offset);
+ ASSERT_NE(pos, std::string::npos);
+ EXPECT_LT(pos, classes_offset);
+ }
}
} // namespace art
diff --git a/profman/profman.cc b/profman/profman.cc
index afc21057b1..adef0d0332 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -43,6 +43,7 @@
#include "runtime.h"
#include "type_reference.h"
#include "utils.h"
+#include "type_reference.h"
#include "zip_archive.h"
namespace art {
@@ -150,6 +151,9 @@ static const std::string kClassAllMethods = "*";
static constexpr char kProfileParsingInlineChacheSep = '+';
static constexpr char kProfileParsingTypeSep = ',';
static constexpr char kProfileParsingFirstCharInSignature = '(';
+static constexpr char kMethodFlagStringHot = 'H';
+static constexpr char kMethodFlagStringStartup = 'S';
+static constexpr char kMethodFlagStringPostStartup = 'P';
// TODO(calin): This class has grown too much from its initial design. Split the functionality
// into smaller, more contained pieces.
@@ -426,18 +430,42 @@ class ProfMan FINAL {
}
for (const std::unique_ptr<const DexFile>& dex_file : *dex_files) {
std::set<dex::TypeIndex> class_types;
- std::set<uint16_t> methods;
- if (profile_info.GetClassesAndMethods(*dex_file.get(), &class_types, &methods)) {
+ std::set<uint16_t> hot_methods;
+ std::set<uint16_t> startup_methods;
+ std::set<uint16_t> post_startup_methods;
+ std::set<uint16_t> combined_methods;
+ if (profile_info.GetClassesAndMethods(*dex_file.get(),
+ &class_types,
+ &hot_methods,
+ &startup_methods,
+ &post_startup_methods)) {
for (const dex::TypeIndex& type_index : class_types) {
const DexFile::TypeId& type_id = dex_file->GetTypeId(type_index);
out_lines->insert(std::string(dex_file->GetTypeDescriptor(type_id)));
}
- for (uint16_t dex_method_idx : methods) {
+ combined_methods = hot_methods;
+ combined_methods.insert(startup_methods.begin(), startup_methods.end());
+ combined_methods.insert(post_startup_methods.begin(), post_startup_methods.end());
+ for (uint16_t dex_method_idx : combined_methods) {
const DexFile::MethodId& id = dex_file->GetMethodId(dex_method_idx);
std::string signature_string(dex_file->GetMethodSignature(id).ToString());
std::string type_string(dex_file->GetTypeDescriptor(dex_file->GetTypeId(id.class_idx_)));
std::string method_name(dex_file->GetMethodName(id));
- out_lines->insert(type_string + kMethodSep + method_name + signature_string);
+ std::string flags_string;
+ if (hot_methods.find(dex_method_idx) != hot_methods.end()) {
+ flags_string += kMethodFlagStringHot;
+ }
+ if (startup_methods.find(dex_method_idx) != startup_methods.end()) {
+ flags_string += kMethodFlagStringStartup;
+ }
+ if (post_startup_methods.find(dex_method_idx) != post_startup_methods.end()) {
+ flags_string += kMethodFlagStringPostStartup;
+ }
+ out_lines->insert(flags_string +
+ type_string +
+ kMethodSep +
+ method_name +
+ signature_string);
}
}
}
@@ -461,7 +489,7 @@ class ProfMan FINAL {
return true;
}
- int DumpClasses() {
+ int DumpClassesAndMethods() {
// Validate that at least one profile file or reference was specified.
if (profile_files_.empty() && profile_files_fd_.empty() &&
reference_profile_file_.empty() && !FdIsValid(reference_profile_file_fd_)) {
@@ -694,11 +722,30 @@ class ProfMan FINAL {
/*out*/ProfileCompilationInfo* profile) {
std::string klass;
std::string method_str;
- size_t method_sep_index = line.find(kMethodSep);
+ bool is_hot = false;
+ bool is_startup = false;
+ bool is_post_startup = false;
+ const size_t method_sep_index = line.find(kMethodSep, 0);
if (method_sep_index == std::string::npos) {
- klass = line;
+ klass = line.substr(0);
} else {
- klass = line.substr(0, method_sep_index);
+ // The method prefix flags are only valid for method strings.
+ size_t start_index = 0;
+ while (start_index < line.size() && line[start_index] != 'L') {
+ const char c = line[start_index];
+ if (c == kMethodFlagStringHot) {
+ is_hot = true;
+ } else if (c == kMethodFlagStringStartup) {
+ is_startup = true;
+ } else if (c == kMethodFlagStringPostStartup) {
+ is_post_startup = true;
+ } else {
+ LOG(WARNING) << "Invalid flag " << c;
+ return false;
+ }
+ ++start_index;
+ }
+ klass = line.substr(start_index, method_sep_index - start_index);
method_str = line.substr(method_sep_index + kMethodSep.size());
}
@@ -715,7 +762,8 @@ class ProfMan FINAL {
const auto& dex_resolved_classes = resolved_class_set.emplace(
dex_file->GetLocation(),
dex_file->GetBaseLocation(),
- dex_file->GetLocationChecksum());
+ dex_file->GetLocationChecksum(),
+ dex_file->NumMethodIds());
dex_resolved_classes.first->AddClass(class_ref.type_index);
std::vector<ProfileMethodInfo> methods;
if (method_str == kClassAllMethods) {
@@ -745,6 +793,9 @@ class ProfMan FINAL {
std::string method_spec;
std::vector<std::string> inline_cache_elems;
+ // If none of the flags are set, default to hot.
+ is_hot = is_hot || (!is_hot && !is_startup && !is_post_startup);
+
std::vector<std::string> method_elems;
bool is_missing_types = false;
Split(method_str, kProfileParsingInlineChacheSep, &method_elems);
@@ -766,7 +817,6 @@ class ProfMan FINAL {
return false;
}
- std::vector<ProfileMethodInfo> pmi;
std::vector<ProfileMethodInfo::ProfileInlineCache> inline_caches;
if (is_missing_types || !inline_cache_elems.empty()) {
uint32_t dex_pc;
@@ -783,8 +833,29 @@ class ProfMan FINAL {
}
inline_caches.emplace_back(dex_pc, is_missing_types, classes);
}
- pmi.emplace_back(class_ref.dex_file, method_index, inline_caches);
- profile->AddMethodsAndClasses(pmi, std::set<DexCacheResolvedClasses>());
+ ProfileMethodInfo pmi(class_ref.dex_file, method_index, inline_caches);
+ if (is_hot) {
+ profile->AddMethod(pmi);
+ }
+ if (is_startup) {
+ if (!profile->AddSampledMethod(/*is_startup*/ true,
+ pmi.dex_file->GetLocation(),
+ pmi.dex_file->GetLocationChecksum(),
+ method_index,
+ pmi.dex_file->NumMethodIds())) {
+ return false;
+ }
+ DCHECK(profile->IsStartupOrHotMethod(MethodReference(pmi.dex_file, method_index)));
+ }
+ if (is_post_startup) {
+ if (!profile->AddSampledMethod(/*is_startup*/ false,
+ pmi.dex_file->GetLocation(),
+ pmi.dex_file->GetLocationChecksum(),
+ method_index,
+ pmi.dex_file->NumMethodIds())) {
+ return false;
+ }
+ }
return true;
}
@@ -959,7 +1030,7 @@ static int profman(int argc, char** argv) {
return profman.DumpProfileInfo();
}
if (profman.ShouldOnlyDumpClassesAndMethods()) {
- return profman.DumpClasses();
+ return profman.DumpClassesAndMethods();
}
if (profman.ShouldCreateProfile()) {
return profman.CreateProfile();
diff --git a/runtime/Android.bp b/runtime/Android.bp
index aa7dc65871..c5508e32d4 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -54,6 +54,7 @@ cc_defaults {
"compiler_filter.cc",
"debugger.cc",
"dex_file.cc",
+ "dex_file_tracking_registrar.cc",
"dex_file_annotations.cc",
"dex_file_verifier.cc",
"dex_instruction.cc",
@@ -123,6 +124,7 @@ cc_defaults {
"jni_internal.cc",
"jobject_comparator.cc",
"linear_alloc.cc",
+ "managed_stack.cc",
"mem_map.cc",
"memory_region.cc",
"method_handles.cc",
diff --git a/runtime/arch/arm/context_arm.cc b/runtime/arch/arm/context_arm.cc
index 9cbec1e5bc..817dcf5783 100644
--- a/runtime/arch/arm/context_arm.cc
+++ b/runtime/arch/arm/context_arm.cc
@@ -18,7 +18,7 @@
#include "base/bit_utils.h"
#include "quick/quick_method_frame_info.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace arm {
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index 4c15450ff7..b4bca014f4 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -25,7 +25,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "globals.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
//
// ARM specific fault handler functions.
diff --git a/runtime/arch/arm64/context_arm64.cc b/runtime/arch/arm64/context_arm64.cc
index d5d1ec7f07..a8f034eaf4 100644
--- a/runtime/arch/arm64/context_arm64.cc
+++ b/runtime/arch/arm64/context_arm64.cc
@@ -20,7 +20,7 @@
#include "base/bit_utils.h"
#include "quick/quick_method_frame_info.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace arm64 {
diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc
index dc4e8f389e..0ead732cdd 100644
--- a/runtime/arch/arm64/fault_handler_arm64.cc
+++ b/runtime/arch/arm64/fault_handler_arm64.cc
@@ -26,7 +26,7 @@
#include "base/macros.h"
#include "globals.h"
#include "registers_arm64.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
extern "C" void art_quick_throw_stack_overflow();
extern "C" void art_quick_throw_null_pointer_exception_from_signal();
diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc
index 7072a8a613..25e442c3e6 100644
--- a/runtime/arch/mips/fault_handler_mips.cc
+++ b/runtime/arch/mips/fault_handler_mips.cc
@@ -24,7 +24,7 @@
#include "globals.h"
#include "quick_method_frame_info_mips.h"
#include "registers_mips.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
extern "C" void art_quick_throw_stack_overflow();
extern "C" void art_quick_throw_null_pointer_exception_from_signal();
diff --git a/runtime/arch/mips/instruction_set_features_mips.cc b/runtime/arch/mips/instruction_set_features_mips.cc
index 3c5afc28a3..6540b44518 100644
--- a/runtime/arch/mips/instruction_set_features_mips.cc
+++ b/runtime/arch/mips/instruction_set_features_mips.cc
@@ -47,7 +47,7 @@ static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kR2;
static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kBase;
#endif
-static void GetFlagsFromCppDefined(bool* mips_isa_gte2, bool* r6, bool* fpu_32bit) {
+static void GetFlagsFromCppDefined(bool* mips_isa_gte2, bool* r6, bool* fpu_32bit, bool* msa) {
// Override defaults based on compiler flags.
if (kRuntimeMipsLevel >= MipsLevel::kR2) {
*mips_isa_gte2 = true;
@@ -57,8 +57,10 @@ static void GetFlagsFromCppDefined(bool* mips_isa_gte2, bool* r6, bool* fpu_32bi
if (kRuntimeMipsLevel >= MipsLevel::kR5) {
*fpu_32bit = false;
+ *msa = true;
} else {
*fpu_32bit = true;
+ *msa = false;
}
if (kRuntimeMipsLevel >= MipsLevel::kR6) {
@@ -76,7 +78,8 @@ MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromVariant(
bool fpu_32bit;
bool mips_isa_gte2;
bool r6;
- GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit);
+ bool msa;
+ GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit, &msa);
// Override defaults based on variant string.
// Only care if it is R1, R2, R5 or R6 and we assume all CPUs will have a FP unit.
@@ -87,6 +90,7 @@ MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromVariant(
r6 = (variant[kPrefixLength] >= '6');
fpu_32bit = (variant[kPrefixLength] < '5');
mips_isa_gte2 = (variant[kPrefixLength] >= '2');
+ msa = (variant[kPrefixLength] >= '5');
} else if (variant == "default") {
// Default variant has FPU, is gte2. This is the traditional setting.
//
@@ -100,32 +104,57 @@ MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromVariant(
LOG(WARNING) << "Unexpected CPU variant for Mips32 using defaults: " << variant;
}
- return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6));
+ return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6, msa));
}
MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
bool fpu_32bit = (bitmap & kFpu32Bitfield) != 0;
bool mips_isa_gte2 = (bitmap & kIsaRevGte2Bitfield) != 0;
bool r6 = (bitmap & kR6) != 0;
- return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6));
+ bool msa = (bitmap & kMsaBitfield) != 0;
+ return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6, msa));
}
MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromCppDefines() {
bool fpu_32bit;
bool mips_isa_gte2;
bool r6;
- GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit);
+ bool msa;
+ GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit, &msa);
- return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6));
+ return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6, msa));
}
MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromCpuInfo() {
bool fpu_32bit;
bool mips_isa_gte2;
bool r6;
- GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit);
+ bool msa;
+ GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit, &msa);
+
+ msa = false;
+
+ std::ifstream in("/proc/cpuinfo");
+ if (!in.fail()) {
+ while (!in.eof()) {
+ std::string line;
+ std::getline(in, line);
+ if (!in.eof()) {
+ LOG(INFO) << "cpuinfo line: " << line;
+ if (line.find("ASEs") != std::string::npos) {
+ LOG(INFO) << "found Application Specific Extensions";
+ if (line.find("msa") != std::string::npos) {
+ msa = true;
+ }
+ }
+ }
+ }
+ in.close();
+ } else {
+ LOG(ERROR) << "Failed to open /proc/cpuinfo";
+ }
- return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6));
+ return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6, msa));
}
MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromHwcap() {
@@ -145,13 +174,15 @@ bool MipsInstructionSetFeatures::Equals(const InstructionSetFeatures* other) con
const MipsInstructionSetFeatures* other_as_mips = other->AsMipsInstructionSetFeatures();
return (fpu_32bit_ == other_as_mips->fpu_32bit_) &&
(mips_isa_gte2_ == other_as_mips->mips_isa_gte2_) &&
- (r6_ == other_as_mips->r6_);
+ (r6_ == other_as_mips->r6_) &&
+ (msa_ == other_as_mips->msa_);
}
uint32_t MipsInstructionSetFeatures::AsBitmap() const {
return (fpu_32bit_ ? kFpu32Bitfield : 0) |
(mips_isa_gte2_ ? kIsaRevGte2Bitfield : 0) |
- (r6_ ? kR6 : 0);
+ (r6_ ? kR6 : 0) |
+ (msa_ ? kMsaBitfield : 0);
}
std::string MipsInstructionSetFeatures::GetFeatureString() const {
@@ -169,6 +200,11 @@ std::string MipsInstructionSetFeatures::GetFeatureString() const {
if (r6_) {
result += ",r6";
} // Suppress non-r6.
+ if (msa_) {
+ result += ",msa";
+ } else {
+ result += ",-msa";
+ }
return result;
}
@@ -178,6 +214,7 @@ MipsInstructionSetFeatures::AddFeaturesFromSplitString(
bool fpu_32bit = fpu_32bit_;
bool mips_isa_gte2 = mips_isa_gte2_;
bool r6 = r6_;
+ bool msa = msa_;
for (auto i = features.begin(); i != features.end(); i++) {
std::string feature = android::base::Trim(*i);
if (feature == "fpu32") {
@@ -192,13 +229,17 @@ MipsInstructionSetFeatures::AddFeaturesFromSplitString(
r6 = true;
} else if (feature == "-r6") {
r6 = false;
+ } else if (feature == "msa") {
+ msa = true;
+ } else if (feature == "-msa") {
+ msa = false;
} else {
*error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
return nullptr;
}
}
return std::unique_ptr<const InstructionSetFeatures>(
- new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6));
+ new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6, msa));
}
} // namespace art
diff --git a/runtime/arch/mips/instruction_set_features_mips.h b/runtime/arch/mips/instruction_set_features_mips.h
index 1aec99fa73..1cb852e262 100644
--- a/runtime/arch/mips/instruction_set_features_mips.h
+++ b/runtime/arch/mips/instruction_set_features_mips.h
@@ -75,6 +75,11 @@ class MipsInstructionSetFeatures FINAL : public InstructionSetFeatures {
return r6_;
}
+ // Does it have MSA (MIPS SIMD Architecture) support.
+ bool HasMsa() const {
+ return msa_;
+ }
+
virtual ~MipsInstructionSetFeatures() {}
protected:
@@ -84,11 +89,12 @@ class MipsInstructionSetFeatures FINAL : public InstructionSetFeatures {
std::string* error_msg) const OVERRIDE;
private:
- MipsInstructionSetFeatures(bool fpu_32bit, bool mips_isa_gte2, bool r6)
+ MipsInstructionSetFeatures(bool fpu_32bit, bool mips_isa_gte2, bool r6, bool msa)
: InstructionSetFeatures(),
fpu_32bit_(fpu_32bit),
mips_isa_gte2_(mips_isa_gte2),
- r6_(r6) {
+ r6_(r6),
+ msa_(msa) {
// Sanity checks.
if (r6) {
CHECK(mips_isa_gte2);
@@ -104,11 +110,13 @@ class MipsInstructionSetFeatures FINAL : public InstructionSetFeatures {
kFpu32Bitfield = 1 << 0,
kIsaRevGte2Bitfield = 1 << 1,
kR6 = 1 << 2,
+ kMsaBitfield = 1 << 3,
};
const bool fpu_32bit_;
const bool mips_isa_gte2_;
const bool r6_;
+ const bool msa_;
DISALLOW_COPY_AND_ASSIGN(MipsInstructionSetFeatures);
};
diff --git a/runtime/arch/mips/instruction_set_features_mips_test.cc b/runtime/arch/mips/instruction_set_features_mips_test.cc
index 6613b84365..54fd2c94c4 100644
--- a/runtime/arch/mips/instruction_set_features_mips_test.cc
+++ b/runtime/arch/mips/instruction_set_features_mips_test.cc
@@ -20,15 +20,109 @@
namespace art {
-TEST(MipsInstructionSetFeaturesTest, MipsFeatures) {
+TEST(MipsInstructionSetFeaturesTest, MipsFeaturesFromDefaultVariant) {
std::string error_msg;
std::unique_ptr<const InstructionSetFeatures> mips_features(
InstructionSetFeatures::FromVariant(kMips, "default", &error_msg));
ASSERT_TRUE(mips_features.get() != nullptr) << error_msg;
EXPECT_EQ(mips_features->GetInstructionSet(), kMips);
EXPECT_TRUE(mips_features->Equals(mips_features.get()));
- EXPECT_STREQ("fpu32,mips2", mips_features->GetFeatureString().c_str());
+ EXPECT_STREQ("fpu32,mips2,-msa", mips_features->GetFeatureString().c_str());
EXPECT_EQ(mips_features->AsBitmap(), 3U);
}
+TEST(MipsInstructionSetFeaturesTest, MipsFeaturesFromR1Variant) {
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> mips32r1_features(
+ InstructionSetFeatures::FromVariant(kMips, "mips32r1", &error_msg));
+ ASSERT_TRUE(mips32r1_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(mips32r1_features->GetInstructionSet(), kMips);
+ EXPECT_TRUE(mips32r1_features->Equals(mips32r1_features.get()));
+ EXPECT_STREQ("fpu32,-mips2,-msa", mips32r1_features->GetFeatureString().c_str());
+ EXPECT_EQ(mips32r1_features->AsBitmap(), 1U);
+
+ std::unique_ptr<const InstructionSetFeatures> mips_default_features(
+ InstructionSetFeatures::FromVariant(kMips, "default", &error_msg));
+ ASSERT_TRUE(mips_default_features.get() != nullptr) << error_msg;
+ EXPECT_FALSE(mips32r1_features->Equals(mips_default_features.get()));
+}
+
+TEST(MipsInstructionSetFeaturesTest, MipsFeaturesFromR2Variant) {
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> mips32r2_features(
+ InstructionSetFeatures::FromVariant(kMips, "mips32r2", &error_msg));
+ ASSERT_TRUE(mips32r2_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(mips32r2_features->GetInstructionSet(), kMips);
+ EXPECT_TRUE(mips32r2_features->Equals(mips32r2_features.get()));
+ EXPECT_STREQ("fpu32,mips2,-msa", mips32r2_features->GetFeatureString().c_str());
+ EXPECT_EQ(mips32r2_features->AsBitmap(), 3U);
+
+ std::unique_ptr<const InstructionSetFeatures> mips_default_features(
+ InstructionSetFeatures::FromVariant(kMips, "default", &error_msg));
+ ASSERT_TRUE(mips_default_features.get() != nullptr) << error_msg;
+ EXPECT_TRUE(mips32r2_features->Equals(mips_default_features.get()));
+
+ std::unique_ptr<const InstructionSetFeatures> mips32r1_features(
+ InstructionSetFeatures::FromVariant(kMips, "mips32r1", &error_msg));
+ ASSERT_TRUE(mips32r1_features.get() != nullptr) << error_msg;
+ EXPECT_FALSE(mips32r2_features->Equals(mips32r1_features.get()));
+}
+
+TEST(MipsInstructionSetFeaturesTest, MipsFeaturesFromR5Variant) {
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> mips32r5_features(
+ InstructionSetFeatures::FromVariant(kMips, "mips32r5", &error_msg));
+ ASSERT_TRUE(mips32r5_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(mips32r5_features->GetInstructionSet(), kMips);
+ EXPECT_TRUE(mips32r5_features->Equals(mips32r5_features.get()));
+ EXPECT_STREQ("-fpu32,mips2,msa", mips32r5_features->GetFeatureString().c_str());
+ EXPECT_EQ(mips32r5_features->AsBitmap(), 10U);
+
+ std::unique_ptr<const InstructionSetFeatures> mips_default_features(
+ InstructionSetFeatures::FromVariant(kMips, "default", &error_msg));
+ ASSERT_TRUE(mips_default_features.get() != nullptr) << error_msg;
+ EXPECT_FALSE(mips32r5_features->Equals(mips_default_features.get()));
+
+ std::unique_ptr<const InstructionSetFeatures> mips32r1_features(
+ InstructionSetFeatures::FromVariant(kMips, "mips32r1", &error_msg));
+ ASSERT_TRUE(mips32r1_features.get() != nullptr) << error_msg;
+ EXPECT_FALSE(mips32r5_features->Equals(mips32r1_features.get()));
+
+ std::unique_ptr<const InstructionSetFeatures> mips32r2_features(
+ InstructionSetFeatures::FromVariant(kMips, "mips32r2", &error_msg));
+ ASSERT_TRUE(mips32r2_features.get() != nullptr) << error_msg;
+ EXPECT_FALSE(mips32r5_features->Equals(mips32r2_features.get()));
+}
+
+TEST(MipsInstructionSetFeaturesTest, MipsFeaturesFromR6Variant) {
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> mips32r6_features(
+ InstructionSetFeatures::FromVariant(kMips, "mips32r6", &error_msg));
+ ASSERT_TRUE(mips32r6_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(mips32r6_features->GetInstructionSet(), kMips);
+ EXPECT_TRUE(mips32r6_features->Equals(mips32r6_features.get()));
+ EXPECT_STREQ("-fpu32,mips2,r6,msa", mips32r6_features->GetFeatureString().c_str());
+ EXPECT_EQ(mips32r6_features->AsBitmap(), 14U);
+
+ std::unique_ptr<const InstructionSetFeatures> mips_default_features(
+ InstructionSetFeatures::FromVariant(kMips, "default", &error_msg));
+ ASSERT_TRUE(mips_default_features.get() != nullptr) << error_msg;
+ EXPECT_FALSE(mips32r6_features->Equals(mips_default_features.get()));
+
+ std::unique_ptr<const InstructionSetFeatures> mips32r1_features(
+ InstructionSetFeatures::FromVariant(kMips, "mips32r1", &error_msg));
+ ASSERT_TRUE(mips32r1_features.get() != nullptr) << error_msg;
+ EXPECT_FALSE(mips32r6_features->Equals(mips32r1_features.get()));
+
+ std::unique_ptr<const InstructionSetFeatures> mips32r2_features(
+ InstructionSetFeatures::FromVariant(kMips, "mips32r2", &error_msg));
+ ASSERT_TRUE(mips32r2_features.get() != nullptr) << error_msg;
+ EXPECT_FALSE(mips32r6_features->Equals(mips32r2_features.get()));
+
+ std::unique_ptr<const InstructionSetFeatures> mips32r5_features(
+ InstructionSetFeatures::FromVariant(kMips, "mips32r5", &error_msg));
+ ASSERT_TRUE(mips32r5_features.get() != nullptr) << error_msg;
+ EXPECT_FALSE(mips32r6_features->Equals(mips32r5_features.get()));
+}
+
} // namespace art
diff --git a/runtime/arch/mips64/fault_handler_mips64.cc b/runtime/arch/mips64/fault_handler_mips64.cc
index f9a92c834e..69d73b09c2 100644
--- a/runtime/arch/mips64/fault_handler_mips64.cc
+++ b/runtime/arch/mips64/fault_handler_mips64.cc
@@ -25,7 +25,7 @@
#include "globals.h"
#include "quick_method_frame_info_mips64.h"
#include "registers_mips64.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
extern "C" void art_quick_throw_stack_overflow();
extern "C" void art_quick_throw_null_pointer_exception_from_signal();
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index 7d8abb8cc5..798c500f18 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -26,7 +26,7 @@
#include "base/macros.h"
#include "base/safe_copy.h"
#include "globals.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#if defined(__APPLE__)
#define ucontext __darwin_ucontext
diff --git a/runtime/arch/x86/thread_x86.cc b/runtime/arch/x86/thread_x86.cc
index 241650eaf4..cc8f1fa00e 100644
--- a/runtime/arch/x86/thread_x86.cc
+++ b/runtime/arch/x86/thread_x86.cc
@@ -22,7 +22,7 @@
#include "asm_support_x86.h"
#include "base/enums.h"
#include "base/macros.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#if defined(__APPLE__)
diff --git a/runtime/arch/x86_64/thread_x86_64.cc b/runtime/arch/x86_64/thread_x86_64.cc
index 553b6569c8..19d25f6990 100644
--- a/runtime/arch/x86_64/thread_x86_64.cc
+++ b/runtime/arch/x86_64/thread_x86_64.cc
@@ -18,7 +18,7 @@
#include "asm_support_x86_64.h"
#include "base/macros.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#if defined(__linux__)
diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h
index 98002aed31..a8a58e135e 100644
--- a/runtime/art_field-inl.h
+++ b/runtime/art_field-inl.h
@@ -28,7 +28,7 @@
#include "mirror/dex_cache-inl.h"
#include "mirror/object-inl.h"
#include "primitive.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "scoped_thread_state_change-inl.h"
#include "well_known_classes.h"
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 9d0bfdee5d..07ca35fb00 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -27,6 +27,7 @@
#include "dex_file_annotations.h"
#include "dex_file-inl.h"
#include "gc_root-inl.h"
+#include "invoke_type.h"
#include "jit/profiling_info.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
@@ -35,10 +36,12 @@
#include "mirror/string.h"
#include "oat.h"
#include "obj_ptr-inl.h"
+#include "primitive.h"
#include "quick/quick_method_frame_info.h"
+#include "read_barrier-inl.h"
#include "runtime-inl.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils.h"
namespace art {
@@ -339,6 +342,10 @@ inline const char* ArtMethod::GetReturnTypeDescriptor() {
return dex_file->GetTypeDescriptor(dex_file->GetTypeId(proto_id.return_type_idx_));
}
+inline Primitive::Type ArtMethod::GetReturnTypePrimitive() {
+ return Primitive::GetType(GetReturnTypeDescriptor()[0]);
+}
+
inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx) {
DCHECK(!IsProxyMethod());
const DexFile* dex_file = GetDexFile();
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 856bfd23e5..3a8d279606 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -24,19 +24,17 @@
#include "base/enums.h"
#include "dex_file.h"
#include "gc_root.h"
-#include "invoke_type.h"
-#include "method_reference.h"
#include "modifiers.h"
-#include "mirror/dex_cache.h"
-#include "mirror/object.h"
#include "obj_ptr.h"
+#include "offsets.h"
+#include "primitive.h"
#include "read_barrier_option.h"
-#include "utils.h"
namespace art {
template<class T> class Handle;
class ImtConflictTable;
+enum InvokeType : uint32_t;
union JValue;
class OatQuickMethodHeader;
class ProfilingInfo;
@@ -47,8 +45,13 @@ class ShadowFrame;
namespace mirror {
class Array;
class Class;
+class ClassLoader;
+class DexCache;
class IfTable;
+class Object;
+template <typename MirrorType> class ObjectArray;
class PointerArray;
+class String;
} // namespace mirror
class ArtMethod FINAL {
@@ -318,11 +321,11 @@ class ArtMethod FINAL {
}
static MemberOffset DexMethodIndexOffset() {
- return OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_);
+ return MemberOffset(OFFSETOF_MEMBER(ArtMethod, dex_method_index_));
}
static MemberOffset MethodIndexOffset() {
- return OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_);
+ return MemberOffset(OFFSETOF_MEMBER(ArtMethod, method_index_));
}
uint32_t GetCodeItemOffset() {
@@ -524,10 +527,6 @@ class ArtMethod FINAL {
bool IsImtUnimplementedMethod() REQUIRES_SHARED(Locks::mutator_lock_);
- MethodReference ToMethodReference() REQUIRES_SHARED(Locks::mutator_lock_) {
- return MethodReference(GetDexFile(), GetDexMethodIndex());
- }
-
// Find the catch block for the given exception type and dex_pc. When a catch block is found,
// indicates whether the found catch block is responsible for clearing the exception or whether
// a move-exception instruction is present.
@@ -571,6 +570,8 @@ class ArtMethod FINAL {
const char* GetReturnTypeDescriptor() REQUIRES_SHARED(Locks::mutator_lock_);
+ ALWAYS_INLINE Primitive::Type GetReturnTypePrimitive() REQUIRES_SHARED(Locks::mutator_lock_);
+
const char* GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index fce6da4718..1ce7fd33bb 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -30,6 +30,7 @@
#include "mirror/string.h"
#include "utils/dex_cache_arrays_layout.h"
#include "runtime.h"
+#include "stack.h"
#include "thread.h"
#endif
diff --git a/runtime/atomic.cc b/runtime/atomic.cc
index d5ae570c30..07aceb7cfc 100644
--- a/runtime/atomic.cc
+++ b/runtime/atomic.cc
@@ -17,7 +17,7 @@
#include "atomic.h"
#include "base/mutex.h"
#include "base/stl_util.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/atomic.h b/runtime/atomic.h
index 45c3165b18..25dd1a3a5e 100644
--- a/runtime/atomic.h
+++ b/runtime/atomic.h
@@ -257,6 +257,13 @@ class PACKED(sizeof(T)) Atomic : public std::atomic<T> {
return this->compare_exchange_strong(expected_value, desired_value, std::memory_order_relaxed);
}
+ // Atomically replace the value with desired value if it matches the expected value. Prior writes
+ // to other memory locations become visible to the threads that do a consume or an acquire on the
+ // same location.
+ bool CompareExchangeStrongRelease(T expected_value, T desired_value) {
+ return this->compare_exchange_strong(expected_value, desired_value, std::memory_order_release);
+ }
+
// The same, except it may fail spuriously.
bool CompareExchangeWeakRelaxed(T expected_value, T desired_value) {
return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_relaxed);
diff --git a/runtime/barrier_test.cc b/runtime/barrier_test.cc
index f68a5d42e4..25b6925fd8 100644
--- a/runtime/barrier_test.cc
+++ b/runtime/barrier_test.cc
@@ -22,7 +22,7 @@
#include "common_runtime_test.h"
#include "mirror/object_array-inl.h"
#include "thread_pool.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
class CheckWaitTask : public Task {
diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc
index 99c310af8c..54b40f28cf 100644
--- a/runtime/base/arena_allocator.cc
+++ b/runtime/base/arena_allocator.cc
@@ -26,7 +26,7 @@
#include "logging.h"
#include "mem_map.h"
#include "mutex.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "systrace.h"
namespace art {
diff --git a/runtime/base/dumpable-inl.h b/runtime/base/dumpable-inl.h
index 2cdf083f01..9d7fc39093 100644
--- a/runtime/base/dumpable-inl.h
+++ b/runtime/base/dumpable-inl.h
@@ -19,7 +19,7 @@
#include "base/dumpable.h"
#include "base/mutex.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/base/histogram-inl.h b/runtime/base/histogram-inl.h
index b28eb729d8..be2092040d 100644
--- a/runtime/base/histogram-inl.h
+++ b/runtime/base/histogram-inl.h
@@ -198,7 +198,7 @@ inline void Histogram<Value>::PrintConfidenceIntervals(std::ostream &os, double
kFractionalDigits)
<< "-" << FormatDuration(Percentile(per_1, data) * kAdjust, unit, kFractionalDigits) << " "
<< "Avg: " << FormatDuration(Mean() * kAdjust, unit, kFractionalDigits) << " Max: "
- << FormatDuration(Max() * kAdjust, unit, kFractionalDigits) << "\n";
+ << FormatDuration(Max() * kAdjust, unit, kFractionalDigits) << std::endl;
}
template <class Value>
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index 553928d20a..adfd7d323c 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -21,7 +21,7 @@
#include <sstream>
#include "base/mutex.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils.h"
// Headers for LogMessage::LogLine.
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index 08b370ec4e..0ac2399a5d 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -194,6 +194,16 @@ inline uint64_t Mutex::GetExclusiveOwnerTid() const {
return exclusive_owner_;
}
+inline void Mutex::AssertExclusiveHeld(const Thread* self) const {
+ if (kDebugLocking && (gAborting == 0)) {
+ CHECK(IsExclusiveHeld(self)) << *this;
+ }
+}
+
+inline void Mutex::AssertHeld(const Thread* self) const {
+ AssertExclusiveHeld(self);
+}
+
inline bool ReaderWriterMutex::IsExclusiveHeld(const Thread* self) const {
DCHECK(self == nullptr || self == Thread::Current());
bool result = (GetExclusiveOwnerTid() == SafeGetTid(self));
@@ -221,6 +231,16 @@ inline uint64_t ReaderWriterMutex::GetExclusiveOwnerTid() const {
#endif
}
+inline void ReaderWriterMutex::AssertExclusiveHeld(const Thread* self) const {
+ if (kDebugLocking && (gAborting == 0)) {
+ CHECK(IsExclusiveHeld(self)) << *this;
+ }
+}
+
+inline void ReaderWriterMutex::AssertWriterHeld(const Thread* self) const {
+ AssertExclusiveHeld(self);
+}
+
inline void MutatorMutex::TransitionFromRunnableToSuspended(Thread* self) {
AssertSharedHeld(self);
RegisterAsUnlocked(self);
@@ -231,6 +251,19 @@ inline void MutatorMutex::TransitionFromSuspendedToRunnable(Thread* self) {
AssertSharedHeld(self);
}
+inline ReaderMutexLock::ReaderMutexLock(Thread* self, ReaderWriterMutex& mu)
+ : self_(self), mu_(mu) {
+ mu_.SharedLock(self_);
+}
+
+inline ReaderMutexLock::~ReaderMutexLock() {
+ mu_.SharedUnlock(self_);
+}
+
+// Catch bug where variable name is omitted. "ReaderMutexLock (lock);" instead of
+// "ReaderMutexLock mu(lock)".
+#define ReaderMutexLock(x) static_assert(0, "ReaderMutexLock declaration missing variable name")
+
} // namespace art
#endif // ART_RUNTIME_BASE_MUTEX_INL_H_
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 03ae63a068..e77d8d749d 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -244,15 +244,11 @@ class LOCKABLE Mutex : public BaseMutex {
void Unlock(Thread* self) RELEASE() { ExclusiveUnlock(self); }
// Is the current thread the exclusive holder of the Mutex.
- bool IsExclusiveHeld(const Thread* self) const;
+ ALWAYS_INLINE bool IsExclusiveHeld(const Thread* self) const;
// Assert that the Mutex is exclusively held by the current thread.
- void AssertExclusiveHeld(const Thread* self) ASSERT_CAPABILITY(this) {
- if (kDebugLocking && (gAborting == 0)) {
- CHECK(IsExclusiveHeld(self)) << *this;
- }
- }
- void AssertHeld(const Thread* self) ASSERT_CAPABILITY(this) { AssertExclusiveHeld(self); }
+ ALWAYS_INLINE void AssertExclusiveHeld(const Thread* self) const ASSERT_CAPABILITY(this);
+ ALWAYS_INLINE void AssertHeld(const Thread* self) const ASSERT_CAPABILITY(this);
// Assert that the Mutex is not held by the current thread.
void AssertNotHeldExclusive(const Thread* self) ASSERT_CAPABILITY(!*this) {
@@ -349,15 +345,11 @@ class SHARED_LOCKABLE ReaderWriterMutex : public BaseMutex {
void ReaderUnlock(Thread* self) RELEASE_SHARED() { SharedUnlock(self); }
// Is the current thread the exclusive holder of the ReaderWriterMutex.
- bool IsExclusiveHeld(const Thread* self) const;
+ ALWAYS_INLINE bool IsExclusiveHeld(const Thread* self) const;
// Assert the current thread has exclusive access to the ReaderWriterMutex.
- void AssertExclusiveHeld(const Thread* self) ASSERT_CAPABILITY(this) {
- if (kDebugLocking && (gAborting == 0)) {
- CHECK(IsExclusiveHeld(self)) << *this;
- }
- }
- void AssertWriterHeld(const Thread* self) ASSERT_CAPABILITY(this) { AssertExclusiveHeld(self); }
+ ALWAYS_INLINE void AssertExclusiveHeld(const Thread* self) const ASSERT_CAPABILITY(this);
+ ALWAYS_INLINE void AssertWriterHeld(const Thread* self) const ASSERT_CAPABILITY(this);
// Assert the current thread doesn't have exclusive access to the ReaderWriterMutex.
void AssertNotExclusiveHeld(const Thread* self) ASSERT_CAPABILITY(!this) {
@@ -517,23 +509,15 @@ class SCOPED_CAPABILITY MutexLock {
// construction and releases it upon destruction.
class SCOPED_CAPABILITY ReaderMutexLock {
public:
- ReaderMutexLock(Thread* self, ReaderWriterMutex& mu) ACQUIRE(mu) ALWAYS_INLINE :
- self_(self), mu_(mu) {
- mu_.SharedLock(self_);
- }
+ ALWAYS_INLINE ReaderMutexLock(Thread* self, ReaderWriterMutex& mu) ACQUIRE(mu);
- ~ReaderMutexLock() RELEASE() ALWAYS_INLINE {
- mu_.SharedUnlock(self_);
- }
+ ALWAYS_INLINE ~ReaderMutexLock() RELEASE();
private:
Thread* const self_;
ReaderWriterMutex& mu_;
DISALLOW_COPY_AND_ASSIGN(ReaderMutexLock);
};
-// Catch bug where variable name is omitted. "ReaderMutexLock (lock);" instead of
-// "ReaderMutexLock mu(lock)".
-#define ReaderMutexLock(x) static_assert(0, "ReaderMutexLock declaration missing variable name")
// Scoped locker/unlocker for a ReaderWriterMutex that acquires write access to mu upon
// construction and releases it upon destruction.
diff --git a/runtime/base/mutex_test.cc b/runtime/base/mutex_test.cc
index 340550f02e..752e77a7c0 100644
--- a/runtime/base/mutex_test.cc
+++ b/runtime/base/mutex_test.cc
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include "mutex.h"
+#include "mutex-inl.h"
#include "common_runtime_test.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/base/timing_logger.cc b/runtime/base/timing_logger.cc
index 06e2526294..aaa24317bb 100644
--- a/runtime/base/timing_logger.cc
+++ b/runtime/base/timing_logger.cc
@@ -25,7 +25,8 @@
#include "base/systrace.h"
#include "base/time_utils.h"
#include "gc/heap.h"
-#include "thread-inl.h"
+#include "runtime.h"
+#include "thread-current-inl.h"
#include <cmath>
#include <iomanip>
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index a955cb5acb..f6c8fa9659 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -20,6 +20,7 @@
#include "art_method-inl.h"
#include "oat_quick_method_header.h"
#include "scoped_thread_state_change-inl.h"
+#include "stack.h"
#include "stack_map.h"
namespace art {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c169ac0733..0921bd6783 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -55,7 +55,6 @@
#include "gc_root-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/accounting/heap_bitmap-inl.h"
-#include "gc/accounting/space_bitmap-inl.h"
#include "gc/heap.h"
#include "gc/scoped_gc_critical_section.h"
#include "gc/space/image_space.h"
@@ -89,7 +88,6 @@
#include "mirror/method_handles_lookup.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
-#include "mirror/object-refvisitor-inl.h"
#include "mirror/proxy.h"
#include "mirror/reference-inl.h"
#include "mirror/stack_trace_element.h"
@@ -109,6 +107,7 @@
#include "thread-inl.h"
#include "thread_list.h"
#include "trace.h"
+#include "utf.h"
#include "utils.h"
#include "utils/dex_cache_arrays_layout-inl.h"
#include "verifier/method_verifier.h"
@@ -1194,63 +1193,6 @@ class VerifyDeclaringClassVisitor : public ArtMethodVisitor {
gc::accounting::HeapBitmap* const live_bitmap_;
};
-class FixupInternVisitor {
- public:
- ALWAYS_INLINE ObjPtr<mirror::Object> TryInsertIntern(mirror::Object* obj) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (obj != nullptr && obj->IsString()) {
- const auto intern = Runtime::Current()->GetInternTable()->InternStrong(obj->AsString());
- return intern;
- }
- return obj;
- }
-
- ALWAYS_INLINE void VisitRootIfNonNull(
- mirror::CompressedReference<mirror::Object>* root) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (!root->IsNull()) {
- VisitRoot(root);
- }
- }
-
- ALWAYS_INLINE void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- root->Assign(TryInsertIntern(root->AsMirrorPtr()));
- }
-
- // Visit Class Fields
- ALWAYS_INLINE void operator()(ObjPtr<mirror::Object> obj,
- MemberOffset offset,
- bool is_static ATTRIBUTE_UNUSED) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- // There could be overlap between ranges, we must avoid visiting the same reference twice.
- // Avoid the class field since we already fixed it up in FixupClassVisitor.
- if (offset.Uint32Value() != mirror::Object::ClassOffset().Uint32Value()) {
- // Updating images, don't do a read barrier.
- // Only string fields are fixed, don't do a verify.
- mirror::Object* ref = obj->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(
- offset);
- obj->SetFieldObject<false, false>(offset, TryInsertIntern(ref));
- }
- }
-
- void operator()(ObjPtr<mirror::Class> klass ATTRIBUTE_UNUSED,
- ObjPtr<mirror::Reference> ref) const
- REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_) {
- this->operator()(ref, mirror::Reference::ReferentOffset(), false);
- }
-
- void operator()(mirror::Object* obj) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (obj->IsDexCache()) {
- obj->VisitReferences<true, kVerifyNone, kWithoutReadBarrier>(*this, *this);
- } else {
- // Don't visit native roots for non-dex-cache
- obj->VisitReferences<false, kVerifyNone, kWithoutReadBarrier>(*this, *this);
- }
- }
-};
-
// Copies data from one array to another array at the same position
// if pred returns false. If there is a page of continuous data in
// the src array for which pred consistently returns true then
@@ -1343,7 +1285,6 @@ bool AppImageClassLoadersAndDexCachesHelper::Update(
return false;
}
}
-
// Only add the classes to the class loader after the points where we can return false.
for (size_t i = 0; i < num_dex_caches; i++) {
ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i);
@@ -1507,21 +1448,6 @@ bool AppImageClassLoadersAndDexCachesHelper::Update(
}
}
}
- {
- // Fixup all the literal strings happens at app images which are supposed to be interned.
- ScopedTrace timing("Fixup String Intern in image and dex_cache");
- const auto& image_header = space->GetImageHeader();
- const auto bitmap = space->GetMarkBitmap(); // bitmap of objects
- const uint8_t* target_base = space->GetMemMap()->Begin();
- const ImageSection& objects_section =
- image_header.GetImageSection(ImageHeader::kSectionObjects);
-
- uintptr_t objects_begin = reinterpret_cast<uintptr_t>(target_base + objects_section.Offset());
- uintptr_t objects_end = reinterpret_cast<uintptr_t>(target_base + objects_section.End());
-
- FixupInternVisitor fixup_intern_visitor;
- bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_intern_visitor);
- }
if (*out_forward_dex_cache_array) {
ScopedTrace timing("Fixup ArtMethod dex cache arrays");
FixupArtMethodArrayVisitor visitor(header);
@@ -3535,6 +3461,39 @@ ObjPtr<mirror::DexCache> ClassLinker::EnsureSameClassLoader(
return dex_cache;
}
+void ClassLinker::RegisterExistingDexCache(ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader) {
+ Thread* self = Thread::Current();
+ StackHandleScope<2> hs(self);
+ Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(dex_cache));
+ Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader));
+ const DexFile* dex_file = dex_cache->GetDexFile();
+ DCHECK(dex_file != nullptr) << "Attempt to register uninitialized dex_cache object!";
+ if (kIsDebugBuild) {
+ DexCacheData old_data;
+ {
+ ReaderMutexLock mu(self, *Locks::dex_lock_);
+ old_data = FindDexCacheDataLocked(*dex_file);
+ }
+ ObjPtr<mirror::DexCache> old_dex_cache = DecodeDexCache(self, old_data);
+ DCHECK(old_dex_cache.IsNull()) << "Attempt to manually register a dex cache thats already "
+ << "been registered on dex file " << dex_file->GetLocation();
+ }
+ ClassTable* table;
+ {
+ WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
+ table = InsertClassTableForClassLoader(h_class_loader.Get());
+ }
+ WriterMutexLock mu(self, *Locks::dex_lock_);
+ RegisterDexFileLocked(*dex_file, h_dex_cache.Get(), h_class_loader.Get());
+ table->InsertStrongRoot(h_dex_cache.Get());
+ if (h_class_loader.Get() != nullptr) {
+ // Since we added a strong root to the class table, do the write barrier as required for
+ // remembered sets and generational GCs.
+ Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(h_class_loader.Get());
+ }
+}
+
ObjPtr<mirror::DexCache> ClassLinker::RegisterDexFile(const DexFile& dex_file,
ObjPtr<mirror::ClassLoader> class_loader) {
Thread* self = Thread::Current();
@@ -3949,6 +3908,12 @@ void ClassLinker::UpdateClassMethods(ObjPtr<mirror::Class> klass,
}
mirror::Class* ClassLinker::LookupClass(Thread* self,
+ const char* descriptor,
+ ObjPtr<mirror::ClassLoader> class_loader) {
+ return LookupClass(self, descriptor, ComputeModifiedUtf8Hash(descriptor), class_loader);
+}
+
+mirror::Class* ClassLinker::LookupClass(Thread* self,
const char* descriptor,
size_t hash,
ObjPtr<mirror::ClassLoader> class_loader) {
@@ -4571,7 +4536,10 @@ void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod*
DCHECK(out != nullptr);
out->CopyFrom(proxy_constructor, image_pointer_size_);
// Make this constructor public and fix the class to be our Proxy version
- out->SetAccessFlags((out->GetAccessFlags() & ~kAccProtected) | kAccPublic);
+ // Mark kAccCompileDontBother so that we don't take JIT samples for the method. b/62349349
+ out->SetAccessFlags((out->GetAccessFlags() & ~kAccProtected) |
+ kAccPublic |
+ kAccCompileDontBother);
out->SetDeclaringClass(klass.Get());
}
@@ -4605,7 +4573,8 @@ void ClassLinker::CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prot
// preference to the invocation handler.
const uint32_t kRemoveFlags = kAccAbstract | kAccDefault | kAccDefaultConflict;
// Make the method final.
- const uint32_t kAddFlags = kAccFinal;
+ // Mark kAccCompileDontBother so that we don't take JIT samples for the method. b/62349349
+ const uint32_t kAddFlags = kAccFinal | kAccCompileDontBother;
out->SetAccessFlags((out->GetAccessFlags() & ~kRemoveFlags) | kAddFlags);
// Clear the dex_code_item_offset_. It needs to be 0 since proxy methods have no CodeItems but the
@@ -8949,7 +8918,8 @@ class GetResolvedClassesVisitor : public ClassVisitor {
last_dex_file_ = &dex_file;
DexCacheResolvedClasses resolved_classes(dex_file.GetLocation(),
dex_file.GetBaseLocation(),
- dex_file.GetLocationChecksum());
+ dex_file.GetLocationChecksum(),
+ dex_file.NumMethodIds());
last_resolved_classes_ = result_->find(resolved_classes);
if (last_resolved_classes_ == result_->end()) {
last_resolved_classes_ = result_->insert(resolved_classes).first;
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 205ea1e496..1e8125eb05 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -212,9 +212,7 @@ class ClassLinker {
const char* descriptor,
ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES(!Locks::classlinker_classes_lock_)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- return LookupClass(self, descriptor, ComputeModifiedUtf8Hash(descriptor), class_loader);
- }
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Finds all the classes with the given descriptor, regardless of ClassLoader.
void LookupClasses(const char* descriptor, std::vector<ObjPtr<mirror::Class>>& classes)
@@ -385,6 +383,13 @@ class ClassLinker {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+ // Directly register an already existing dex cache. RegisterDexFile should be preferred since that
+ // reduplicates DexCaches when possible. The DexCache given to this function must already be fully
+ // initialized and not already registered.
+ void RegisterExistingDexCache(ObjPtr<mirror::DexCache> cache,
+ ObjPtr<mirror::ClassLoader> class_loader)
+ REQUIRES(!Locks::dex_lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
ObjPtr<mirror::DexCache> RegisterDexFile(const DexFile& dex_file,
ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES(!Locks::dex_lock_)
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index b421810113..684a261cca 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -50,7 +50,7 @@
#include "mirror/string-inl.h"
#include "handle_scope-inl.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h
index dfe8949134..b15d82f5e4 100644
--- a/runtime/class_table-inl.h
+++ b/runtime/class_table-inl.h
@@ -18,6 +18,8 @@
#define ART_RUNTIME_CLASS_TABLE_INL_H_
#include "class_table.h"
+
+#include "gc_root-inl.h"
#include "oat_file.h"
namespace art {
@@ -93,7 +95,7 @@ inline mirror::Class* ClassTable::TableSlot::Read() const {
if (kReadBarrierOption != kWithoutReadBarrier && before_ptr != after_ptr) {
// If another thread raced and updated the reference, do not store the read barrier updated
// one.
- data_.CompareExchangeStrongRelaxed(before, Encode(after_ptr, MaskHash(before)));
+ data_.CompareExchangeStrongRelease(before, Encode(after_ptr, MaskHash(before)));
}
return after_ptr.Ptr();
}
@@ -108,7 +110,7 @@ inline void ClassTable::TableSlot::VisitRoot(const Visitor& visitor) const {
if (before_ptr != after_ptr) {
// If another thread raced and updated the reference, do not store the read barrier updated
// one.
- data_.CompareExchangeStrongRelaxed(before, Encode(after_ptr, MaskHash(before)));
+ data_.CompareExchangeStrongRelease(before, Encode(after_ptr, MaskHash(before)));
}
}
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index 0891d3f9f5..b71610ac7f 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "class_table.h"
+#include "class_table-inl.h"
#include "mirror/class-inl.h"
#include "oat_file.h"
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index d0b50fe820..7e70b7564c 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -38,7 +38,7 @@
#include "gc/scoped_gc_critical_section.h"
#include "gc/space/large_object_space.h"
#include "gc/space/space-inl.h"
-#include "handle_scope.h"
+#include "handle_scope-inl.h"
#include "jdwp/jdwp_priv.h"
#include "jdwp/object_registry.h"
#include "jni_internal.h"
@@ -56,7 +56,7 @@
#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
-#include "handle_scope-inl.h"
+#include "stack.h"
#include "thread_list.h"
#include "utf.h"
#include "well_known_classes.h"
@@ -149,7 +149,9 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati
DebugInstrumentationListener() {}
virtual ~DebugInstrumentationListener() {}
- void MethodEntered(Thread* thread, mirror::Object* this_object, ArtMethod* method,
+ void MethodEntered(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
uint32_t dex_pc)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
if (method->IsNative()) {
@@ -171,12 +173,15 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati
// also group it with other events for this location like BREAKPOINT or SINGLE_STEP.
thread->SetDebugMethodEntry();
} else {
- Dbg::UpdateDebugger(thread, this_object, method, 0, Dbg::kMethodEntry, nullptr);
+ Dbg::UpdateDebugger(thread, this_object.Get(), method, 0, Dbg::kMethodEntry, nullptr);
}
}
- void MethodExited(Thread* thread, mirror::Object* this_object, ArtMethod* method,
- uint32_t dex_pc, const JValue& return_value)
+ void MethodExited(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ const JValue& return_value)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
if (method->IsNative()) {
// TODO: post location events is a suspension point and native method entry stubs aren't.
@@ -189,18 +194,22 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati
events |= Dbg::kMethodEntry;
thread->ClearDebugMethodEntry();
}
- Dbg::UpdateDebugger(thread, this_object, method, dex_pc, events, &return_value);
+ Dbg::UpdateDebugger(thread, this_object.Get(), method, dex_pc, events, &return_value);
}
- void MethodUnwind(Thread* thread ATTRIBUTE_UNUSED, mirror::Object* this_object ATTRIBUTE_UNUSED,
- ArtMethod* method, uint32_t dex_pc)
+ void MethodUnwind(Thread* thread ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
+ ArtMethod* method,
+ uint32_t dex_pc)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
// We're not recorded to listen to this kind of event, so complain.
LOG(ERROR) << "Unexpected method unwind event in debugger " << ArtMethod::PrettyMethod(method)
<< " " << dex_pc;
}
- void DexPcMoved(Thread* thread, mirror::Object* this_object, ArtMethod* method,
+ void DexPcMoved(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
uint32_t new_dex_pc)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
if (IsListeningToMethodExit() && IsReturn(method, new_dex_pc)) {
@@ -217,26 +226,33 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati
events = Dbg::kMethodEntry;
thread->ClearDebugMethodEntry();
}
- Dbg::UpdateDebugger(thread, this_object, method, new_dex_pc, events, nullptr);
+ Dbg::UpdateDebugger(thread, this_object.Get(), method, new_dex_pc, events, nullptr);
}
}
- void FieldRead(Thread* thread ATTRIBUTE_UNUSED, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc, ArtField* field)
+ void FieldRead(Thread* thread ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ ArtField* field)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
- Dbg::PostFieldAccessEvent(method, dex_pc, this_object, field);
+ Dbg::PostFieldAccessEvent(method, dex_pc, this_object.Get(), field);
}
- void FieldWritten(Thread* thread ATTRIBUTE_UNUSED, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc, ArtField* field,
+ void FieldWritten(Thread* thread ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ ArtField* field,
const JValue& field_value)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
- Dbg::PostFieldModificationEvent(method, dex_pc, this_object, field, &field_value);
+ Dbg::PostFieldModificationEvent(method, dex_pc, this_object.Get(), field, &field_value);
}
- void ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED, mirror::Throwable* exception_object)
+ void ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED,
+ Handle<mirror::Throwable> exception_object)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
- Dbg::PostException(exception_object);
+ Dbg::PostException(exception_object.Get());
}
// We only care about branches in the Jit.
@@ -248,10 +264,10 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati
// We only care about invokes in the Jit.
void InvokeVirtualOrInterface(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Object*,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
ArtMethod* method,
uint32_t dex_pc,
- ArtMethod*)
+ ArtMethod* target ATTRIBUTE_UNUSED)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
LOG(ERROR) << "Unexpected invoke event in debugger " << ArtMethod::PrettyMethod(method)
<< " " << dex_pc;
diff --git a/runtime/dex_cache_resolved_classes.h b/runtime/dex_cache_resolved_classes.h
index bebdf0dbfe..2278b052ed 100644
--- a/runtime/dex_cache_resolved_classes.h
+++ b/runtime/dex_cache_resolved_classes.h
@@ -30,10 +30,12 @@ class DexCacheResolvedClasses {
public:
DexCacheResolvedClasses(const std::string& dex_location,
const std::string& base_location,
- uint32_t location_checksum)
+ uint32_t location_checksum,
+ uint32_t num_method_ids)
: dex_location_(dex_location),
base_location_(base_location),
- location_checksum_(location_checksum) {}
+ location_checksum_(location_checksum),
+ num_method_ids_(num_method_ids) {}
// Only compare the key elements, ignore the resolved classes.
int Compare(const DexCacheResolvedClasses& other) const {
@@ -69,10 +71,15 @@ class DexCacheResolvedClasses {
return classes_;
}
+ size_t NumMethodIds() const {
+ return num_method_ids_;
+ }
+
private:
const std::string dex_location_;
const std::string base_location_;
const uint32_t location_checksum_;
+ const uint32_t num_method_ids_;
// Array of resolved class def indexes.
mutable std::unordered_set<dex::TypeIndex> classes_;
};
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 591ba42003..3de78ed5a3 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -28,7 +28,6 @@
#include "invoke_type.h"
#include "jni.h"
#include "modifiers.h"
-#include "utf.h"
namespace art {
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 1d4507a9d6..78d5c5f4ba 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -27,7 +27,7 @@
#include "mem_map.h"
#include "os.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils.h"
namespace art {
diff --git a/runtime/dex_file_tracking_registrar.cc b/runtime/dex_file_tracking_registrar.cc
new file mode 100644
index 0000000000..cfbca3d00f
--- /dev/null
+++ b/runtime/dex_file_tracking_registrar.cc
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#include "dex_file_tracking_registrar.h"
+
+// For dex tracking through poisoning. Note: Requires forcing sanitization. This is the reason for
+// the ifdefs and early include.
+#ifdef ART_DEX_FILE_ACCESS_TRACKING
+#ifndef ART_ENABLE_ADDRESS_SANITIZER
+#define ART_ENABLE_ADDRESS_SANITIZER
+#endif
+#endif
+#include "base/memory_tool.h"
+
+#include "base/logging.h"
+
+namespace art {
+namespace dex {
+namespace tracking {
+
+// If true, poison dex files to track accesses.
+static constexpr bool kDexFileAccessTracking =
+#ifdef ART_DEX_FILE_ACCESS_TRACKING
+ true;
+#else
+ false;
+#endif
+
+void RegisterDexFile(const DexFile* const dex_file) {
+ if (kDexFileAccessTracking && dex_file != nullptr) {
+ LOG(ERROR) << dex_file->GetLocation() + " @ " << std::hex
+ << reinterpret_cast<uintptr_t>(dex_file->Begin());
+ MEMORY_TOOL_MAKE_NOACCESS(dex_file->Begin(), dex_file->Size());
+ }
+}
+
+} // namespace tracking
+} // namespace dex
+} // namespace art
diff --git a/runtime/dex_file_tracking_registrar.h b/runtime/dex_file_tracking_registrar.h
new file mode 100644
index 0000000000..7d5d78d6df
--- /dev/null
+++ b/runtime/dex_file_tracking_registrar.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_DEX_FILE_TRACKING_REGISTRAR_H_
+#define ART_RUNTIME_DEX_FILE_TRACKING_REGISTRAR_H_
+
+#include "dex_file.h"
+
+namespace art {
+namespace dex {
+namespace tracking {
+
+void RegisterDexFile(const DexFile* const dex_file);
+
+} // namespace tracking
+} // namespace dex
+} // namespace art
+
+#endif // ART_RUNTIME_DEX_FILE_TRACKING_REGISTRAR_H_
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index 068e1223e5..0e58e6d564 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -29,7 +29,7 @@
#include "dex_file_types.h"
#include "leb128.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils.h"
namespace art {
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
index cd8c39096d..e83829bb46 100644
--- a/runtime/dex_method_iterator_test.cc
+++ b/runtime/dex_method_iterator_test.cc
@@ -20,7 +20,7 @@
#include "common_runtime_test.h"
#include "oat_file.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index eeb138b295..dd0819ed8f 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -42,12 +42,11 @@ extern "C" const void* artFindNativeMethod(Thread* self) {
// otherwise we return the address of the method we found.
void* native_code = soa.Vm()->FindCodeForNativeMethod(method);
if (native_code == nullptr) {
- DCHECK(self->IsExceptionPending());
+ self->AssertPendingException();
return nullptr;
- } else {
- // Register so that future calls don't come here
- return method->RegisterNative(native_code, false);
}
+ // Register so that future calls don't come here
+ return method->RegisterNative(native_code, false);
}
} // namespace art
diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h
index df37f9586f..c94bf4a318 100644
--- a/runtime/entrypoints/quick/callee_save_frame.h
+++ b/runtime/entrypoints/quick/callee_save_frame.h
@@ -21,7 +21,7 @@
#include "base/enums.h"
#include "base/mutex.h"
#include "runtime.h"
-#include "thread-inl.h"
+#include "thread.h"
// Specific frame size code is in architecture-specific files. We include this to compile-time
// specialize the code.
@@ -46,13 +46,6 @@ class ScopedQuickEntrypointChecks {
}
}
- ScopedQuickEntrypointChecks() REQUIRES_SHARED(Locks::mutator_lock_)
- : self_(kIsDebugBuild ? Thread::Current() : nullptr), exit_check_(kIsDebugBuild) {
- if (kIsDebugBuild) {
- TestsOnEntry();
- }
- }
-
~ScopedQuickEntrypointChecks() REQUIRES_SHARED(Locks::mutator_lock_) {
if (exit_check_) {
TestsOnExit();
diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
index 81560ccbaf..aa1ebb7ee7 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -21,7 +21,7 @@
#include "instrumentation.h"
#include "mirror/object-inl.h"
#include "runtime.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 2b349e39a0..90231e289e 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -18,6 +18,7 @@
#include "base/enums.h"
#include "callee_save_frame.h"
#include "common_throws.h"
+#include "debugger.h"
#include "dex_file-inl.h"
#include "dex_instruction-inl.h"
#include "entrypoints/entrypoint_utils-inl.h"
@@ -40,7 +41,7 @@
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "stack.h"
-#include "debugger.h"
+#include "thread-inl.h"
#include "well_known_classes.h"
namespace art {
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 5594f4dfc7..fd0cd5f0b2 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -27,7 +27,7 @@
#include "mirror/object_reference.h"
#include "oat_quick_method_header.h"
#include "sigchain.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "verify_object-inl.h"
namespace art {
diff --git a/runtime/gc/accounting/bitmap.h b/runtime/gc/accounting/bitmap.h
index eb004726df..d039d88770 100644
--- a/runtime/gc/accounting/bitmap.h
+++ b/runtime/gc/accounting/bitmap.h
@@ -25,7 +25,6 @@
#include "base/mutex.h"
#include "globals.h"
-#include "object_callbacks.h"
namespace art {
diff --git a/runtime/gc/accounting/heap_bitmap.h b/runtime/gc/accounting/heap_bitmap.h
index 76247bce84..7097f87e91 100644
--- a/runtime/gc/accounting/heap_bitmap.h
+++ b/runtime/gc/accounting/heap_bitmap.h
@@ -19,7 +19,6 @@
#include "base/allocator.h"
#include "base/logging.h"
-#include "object_callbacks.h"
#include "space_bitmap.h"
namespace art {
diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc
index c416b9cc3d..57c290ea94 100644
--- a/runtime/gc/accounting/mod_union_table.cc
+++ b/runtime/gc/accounting/mod_union_table.cc
@@ -28,7 +28,7 @@
#include "mirror/object-inl.h"
#include "mirror/object-refvisitor-inl.h"
#include "space_bitmap-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/gc/accounting/mod_union_table_test.cc b/runtime/gc/accounting/mod_union_table_test.cc
index 48a8742cc8..e5b8ea5609 100644
--- a/runtime/gc/accounting/mod_union_table_test.cc
+++ b/runtime/gc/accounting/mod_union_table_test.cc
@@ -21,7 +21,7 @@
#include "gc/space/space-inl.h"
#include "mirror/array-inl.h"
#include "space_bitmap-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
namespace art {
diff --git a/runtime/gc/accounting/remembered_set.h b/runtime/gc/accounting/remembered_set.h
index 5594781672..c332f969ad 100644
--- a/runtime/gc/accounting/remembered_set.h
+++ b/runtime/gc/accounting/remembered_set.h
@@ -19,7 +19,6 @@
#include "base/allocator.h"
#include "globals.h"
-#include "object_callbacks.h"
#include "safe_map.h"
#include <set>
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index b13648894d..889f57b333 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -25,7 +25,6 @@
#include "base/mutex.h"
#include "globals.h"
-#include "object_callbacks.h"
namespace art {
@@ -35,6 +34,9 @@ namespace mirror {
} // namespace mirror
class MemMap;
+// Same as in object_callbacks.h. Just avoid the include.
+typedef void (ObjectCallback)(mirror::Object* obj, void* arg);
+
namespace gc {
namespace accounting {
diff --git a/runtime/gc/allocation_listener.h b/runtime/gc/allocation_listener.h
index d694a68b9c..21fa2142df 100644
--- a/runtime/gc/allocation_listener.h
+++ b/runtime/gc/allocation_listener.h
@@ -23,7 +23,6 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "obj_ptr.h"
-#include "object_callbacks.h"
#include "gc_root.h"
namespace art {
diff --git a/runtime/gc/allocation_record.cc b/runtime/gc/allocation_record.cc
index 122f7799df..2257b81e09 100644
--- a/runtime/gc/allocation_record.cc
+++ b/runtime/gc/allocation_record.cc
@@ -20,6 +20,7 @@
#include "base/enums.h"
#include "base/stl_util.h"
#include "obj_ptr-inl.h"
+#include "object_callbacks.h"
#include "stack.h"
#ifdef ART_TARGET_ANDROID
diff --git a/runtime/gc/allocation_record.h b/runtime/gc/allocation_record.h
index 227c7ad28c..d31e442cc9 100644
--- a/runtime/gc/allocation_record.h
+++ b/runtime/gc/allocation_record.h
@@ -22,12 +22,12 @@
#include "base/mutex.h"
#include "obj_ptr.h"
-#include "object_callbacks.h"
#include "gc_root.h"
namespace art {
class ArtMethod;
+class IsMarkedVisitor;
class Thread;
namespace mirror {
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index 35a251fda8..d5d3540b1f 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -30,7 +30,7 @@
#include "mirror/class-inl.h"
#include "mirror/object.h"
#include "mirror/object-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
namespace art {
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index ef843c6650..c0d648117c 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -359,7 +359,7 @@ class ConcurrentCopying::ThreadFlipVisitor : public Closure, public RootVisitor
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
// We can use the non-CAS VisitRoots functions below because we update thread-local GC roots
// only.
- thread->VisitRoots(this);
+ thread->VisitRoots(this, kVisitRootFlagAllRoots);
concurrent_copying_->GetBarrier().Pass(self);
}
@@ -2086,8 +2086,11 @@ inline void ConcurrentCopying::Process(mirror::Object* obj, MemberOffset offset)
// It was updated by the mutator.
break;
}
- } while (!obj->CasFieldWeakRelaxedObjectWithoutWriteBarrier<
- false, false, kVerifyNone>(offset, expected_ref, new_ref));
+ // Use release cas to make sure threads reading the reference see contents of copied objects.
+ } while (!obj->CasFieldWeakReleaseObjectWithoutWriteBarrier<false, false, kVerifyNone>(
+ offset,
+ expected_ref,
+ new_ref));
}
// Process some roots.
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index f8ca8dba42..7b4340ee09 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -21,9 +21,7 @@
#include "garbage_collector.h"
#include "immune_spaces.h"
#include "jni.h"
-#include "object_callbacks.h"
#include "offsets.h"
-#include "mirror/object.h"
#include "mirror/object_reference.h"
#include "safe_map.h"
@@ -34,6 +32,10 @@ namespace art {
class Closure;
class RootInfo;
+namespace mirror {
+class Object;
+} // namespace mirror
+
namespace gc {
namespace accounting {
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index 1e4196b1ac..c5a341fc80 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -31,7 +31,8 @@
#include "gc/heap.h"
#include "gc/space/large_object_space.h"
#include "gc/space/space-inl.h"
-#include "thread-inl.h"
+#include "runtime.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#include "utils.h"
diff --git a/runtime/gc/collector/immune_spaces_test.cc b/runtime/gc/collector/immune_spaces_test.cc
index acb4f575c8..9823708606 100644
--- a/runtime/gc/collector/immune_spaces_test.cc
+++ b/runtime/gc/collector/immune_spaces_test.cc
@@ -21,7 +21,7 @@
#include "gc/space/image_space.h"
#include "gc/space/space-inl.h"
#include "oat_file.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace mirror {
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index 9d3d950a0f..aef98dee58 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -32,7 +32,7 @@
#include "mirror/object-refvisitor-inl.h"
#include "runtime.h"
#include "stack.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
namespace art {
diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h
index 85727c25c2..0bf4095ac3 100644
--- a/runtime/gc/collector/mark_compact.h
+++ b/runtime/gc/collector/mark_compact.h
@@ -28,7 +28,6 @@
#include "gc/accounting/heap_bitmap.h"
#include "immune_spaces.h"
#include "lock_word.h"
-#include "object_callbacks.h"
#include "offsets.h"
namespace art {
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index f591cf09ca..fb82b4d270 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -42,7 +42,7 @@
#include "mirror/object-inl.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
namespace art {
@@ -1141,7 +1141,7 @@ class MarkSweep::CheckpointMarkThreadRoots : public Closure, public RootVisitor
Thread* const self = Thread::Current();
CHECK(thread == self || thread->IsSuspended() || thread->GetState() == kWaitingPerformingGc)
<< thread->GetState() << " thread " << thread << " self " << self;
- thread->VisitRoots(this);
+ thread->VisitRoots(this, kVisitRootFlagAllRoots);
if (revoke_ros_alloc_thread_local_buffers_at_checkpoint_) {
ScopedTrace trace2("RevokeRosAllocThreadLocalBuffers");
mark_sweep_->GetHeap()->RevokeRosAllocThreadLocalBuffers(thread);
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 5a9b9f8765..b9e06f9688 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -27,7 +27,6 @@
#include "gc_root.h"
#include "gc/accounting/heap_bitmap.h"
#include "immune_spaces.h"
-#include "object_callbacks.h"
#include "offsets.h"
namespace art {
diff --git a/runtime/gc/collector/partial_mark_sweep.cc b/runtime/gc/collector/partial_mark_sweep.cc
index 984779484e..f6ca867e69 100644
--- a/runtime/gc/collector/partial_mark_sweep.cc
+++ b/runtime/gc/collector/partial_mark_sweep.cc
@@ -19,7 +19,7 @@
#include "gc/heap.h"
#include "gc/space/space.h"
#include "partial_mark_sweep.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index 9d6e74dde4..d3858baaf5 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -27,7 +27,6 @@
#include "gc/accounting/heap_bitmap.h"
#include "immune_spaces.h"
#include "mirror/object_reference.h"
-#include "object_callbacks.h"
#include "offsets.h"
namespace art {
diff --git a/runtime/gc/collector/sticky_mark_sweep.cc b/runtime/gc/collector/sticky_mark_sweep.cc
index 428e387c21..98fdfac17b 100644
--- a/runtime/gc/collector/sticky_mark_sweep.cc
+++ b/runtime/gc/collector/sticky_mark_sweep.cc
@@ -21,7 +21,8 @@
#include "gc/heap.h"
#include "gc/space/large_object_space.h"
#include "gc/space/space-inl.h"
-#include "thread-inl.h"
+#include "runtime.h"
+#include "thread-current-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 24f4ce29e2..0289250966 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -34,7 +34,6 @@
#include "globals.h"
#include "handle.h"
#include "obj_ptr.h"
-#include "object_callbacks.h"
#include "offsets.h"
#include "process_state.h"
#include "safe_map.h"
@@ -43,6 +42,7 @@
namespace art {
class ConditionVariable;
+class IsMarkedVisitor;
class Mutex;
class RootVisitor;
class StackVisitor;
@@ -51,6 +51,9 @@ class ThreadPool;
class TimingLogger;
class VariableSizedHandleScope;
+// Same as in object_callbacks.h. Just avoid the include.
+typedef void (ObjectCallback)(mirror::Object* obj, void* arg);
+
namespace mirror {
class Class;
class Object;
diff --git a/runtime/gc/heap_verification_test.cc b/runtime/gc/heap_verification_test.cc
index 2cdfc16f62..a307c519cb 100644
--- a/runtime/gc/heap_verification_test.cc
+++ b/runtime/gc/heap_verification_test.cc
@@ -17,7 +17,7 @@
#include "common_runtime_test.h"
#include "base/memory_tool.h"
-#include "class_linker.h"
+#include "class_linker-inl.h"
#include "handle_scope-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
diff --git a/runtime/gc/reference_processor-inl.h b/runtime/gc/reference_processor-inl.h
index f619a15f74..0f47d3dc9f 100644
--- a/runtime/gc/reference_processor-inl.h
+++ b/runtime/gc/reference_processor-inl.h
@@ -19,6 +19,8 @@
#include "reference_processor.h"
+#include "mirror/reference-inl.h"
+
namespace art {
namespace gc {
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index 886c950710..52da7632f0 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -22,6 +22,7 @@
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/reference-inl.h"
+#include "object_callbacks.h"
#include "reference_processor-inl.h"
#include "reflection.h"
#include "ScopedLocalRef.h"
diff --git a/runtime/gc/reference_processor.h b/runtime/gc/reference_processor.h
index 38b68cbbe8..a8135d9a3b 100644
--- a/runtime/gc/reference_processor.h
+++ b/runtime/gc/reference_processor.h
@@ -20,11 +20,11 @@
#include "base/mutex.h"
#include "globals.h"
#include "jni.h"
-#include "object_callbacks.h"
#include "reference_queue.h"
namespace art {
+class IsMarkedVisitor;
class TimingLogger;
namespace mirror {
diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc
index fd5dcf9de6..321d22a592 100644
--- a/runtime/gc/reference_queue.cc
+++ b/runtime/gc/reference_queue.cc
@@ -22,6 +22,7 @@
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/reference-inl.h"
+#include "object_callbacks.h"
namespace art {
namespace gc {
diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h
index b73a880a8a..c48d48c530 100644
--- a/runtime/gc/reference_queue.h
+++ b/runtime/gc/reference_queue.h
@@ -27,7 +27,6 @@
#include "globals.h"
#include "jni.h"
#include "obj_ptr.h"
-#include "object_callbacks.h"
#include "offsets.h"
#include "thread_pool.h"
@@ -36,6 +35,9 @@ namespace mirror {
class Reference;
} // namespace mirror
+class IsMarkedVisitor;
+class MarkObjectVisitor;
+
namespace gc {
namespace collector {
diff --git a/runtime/gc/scoped_gc_critical_section.cc b/runtime/gc/scoped_gc_critical_section.cc
index f937d2c778..2976dd0252 100644
--- a/runtime/gc/scoped_gc_critical_section.cc
+++ b/runtime/gc/scoped_gc_critical_section.cc
@@ -19,7 +19,7 @@
#include "gc/collector_type.h"
#include "gc/heap.h"
#include "runtime.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/gc/space/bump_pointer_space.h b/runtime/gc/space/bump_pointer_space.h
index e9982e9d3c..566dc5dc40 100644
--- a/runtime/gc/space/bump_pointer_space.h
+++ b/runtime/gc/space/bump_pointer_space.h
@@ -17,10 +17,17 @@
#ifndef ART_RUNTIME_GC_SPACE_BUMP_POINTER_SPACE_H_
#define ART_RUNTIME_GC_SPACE_BUMP_POINTER_SPACE_H_
-#include "object_callbacks.h"
#include "space.h"
namespace art {
+
+namespace mirror {
+class Object;
+}
+
+// Same as in object_callbacks.h. Just avoid the include.
+typedef void (ObjectCallback)(mirror::Object* obj, void* arg);
+
namespace gc {
namespace collector {
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index 9282ec7944..7ec54f59fe 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -26,6 +26,7 @@
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "thread_list.h"
#include "utils.h"
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index 0f856b8ecc..4597a96ce2 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -31,7 +31,7 @@
#include "os.h"
#include "scoped_thread_state_change-inl.h"
#include "space-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/gc/space/region_space-inl.h b/runtime/gc/space/region_space-inl.h
index 61161602ce..fc24fc2974 100644
--- a/runtime/gc/space/region_space-inl.h
+++ b/runtime/gc/space/region_space-inl.h
@@ -18,7 +18,7 @@
#define ART_RUNTIME_GC_SPACE_REGION_SPACE_INL_H_
#include "region_space.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc
index 27f30e0719..8d8c4885ef 100644
--- a/runtime/gc/space/region_space.cc
+++ b/runtime/gc/space/region_space.cc
@@ -255,13 +255,28 @@ void RegionSpace::ClearFromSpace(uint64_t* cleared_bytes, uint64_t* cleared_obje
MutexLock mu(Thread::Current(), region_lock_);
VerifyNonFreeRegionLimit();
size_t new_non_free_region_index_limit = 0;
+
+ // Combine zeroing and releasing pages to reduce how often madvise is called. This helps
+ // reduce contention on the mmap semaphore. b/62194020
+ // clear_region adds a region to the current block. If the region is not adjacent, the
+ // clear block is zeroed, released, and a new block begins.
+ uint8_t* clear_block_begin = nullptr;
+ uint8_t* clear_block_end = nullptr;
+ auto clear_region = [&clear_block_begin, &clear_block_end](Region* r) {
+ r->Clear(/*zero_and_release_pages*/false);
+ if (clear_block_end != r->Begin()) {
+ ZeroAndReleasePages(clear_block_begin, clear_block_end - clear_block_begin);
+ clear_block_begin = r->Begin();
+ }
+ clear_block_end = r->End();
+ };
for (size_t i = 0; i < std::min(num_regions_, non_free_region_index_limit_); ++i) {
Region* r = &regions_[i];
if (r->IsInFromSpace()) {
*cleared_bytes += r->BytesAllocated();
*cleared_objects += r->ObjectsAllocated();
--num_non_free_regions_;
- r->Clear();
+ clear_region(r);
} else if (r->IsInUnevacFromSpace()) {
if (r->LiveBytes() == 0) {
// Special case for 0 live bytes, this means all of the objects in the region are dead and
@@ -274,13 +289,13 @@ void RegionSpace::ClearFromSpace(uint64_t* cleared_bytes, uint64_t* cleared_obje
// Also release RAM for large tails.
while (i + free_regions < num_regions_ && regions_[i + free_regions].IsLargeTail()) {
DCHECK(r->IsLarge());
- regions_[i + free_regions].Clear();
+ clear_region(&regions_[i + free_regions]);
++free_regions;
}
*cleared_bytes += r->BytesAllocated();
*cleared_objects += r->ObjectsAllocated();
num_non_free_regions_ -= free_regions;
- r->Clear();
+ clear_region(r);
GetLiveBitmap()->ClearRange(
reinterpret_cast<mirror::Object*>(r->Begin()),
reinterpret_cast<mirror::Object*>(r->Begin() + free_regions * kRegionSize));
@@ -317,6 +332,8 @@ void RegionSpace::ClearFromSpace(uint64_t* cleared_bytes, uint64_t* cleared_obje
last_checked_region->Idx() + 1);
}
}
+ // Clear pages for the last block since clearing happens when a new block opens.
+ ZeroAndReleasePages(clear_block_begin, clear_block_end - clear_block_begin);
// Update non_free_region_index_limit_.
SetNonFreeRegionLimit(new_non_free_region_index_limit);
evac_region_ = nullptr;
@@ -369,7 +386,7 @@ void RegionSpace::Clear() {
if (!r->IsFree()) {
--num_non_free_regions_;
}
- r->Clear();
+ r->Clear(/*zero_and_release_pages*/true);
}
SetNonFreeRegionLimit(0);
current_region_ = &full_region_;
@@ -395,7 +412,7 @@ void RegionSpace::FreeLarge(mirror::Object* large_obj, size_t bytes_allocated) {
} else {
DCHECK(reg->IsLargeTail());
}
- reg->Clear();
+ reg->Clear(/*zero_and_release_pages*/true);
--num_non_free_regions_;
}
if (end_addr < Limit()) {
diff --git a/runtime/gc/space/region_space.h b/runtime/gc/space/region_space.h
index 1d1d27e0f4..323ccdbd74 100644
--- a/runtime/gc/space/region_space.h
+++ b/runtime/gc/space/region_space.h
@@ -284,14 +284,16 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace {
return type_;
}
- void Clear() {
+ void Clear(bool zero_and_release_pages) {
top_.StoreRelaxed(begin_);
state_ = RegionState::kRegionStateFree;
type_ = RegionType::kRegionTypeNone;
objects_allocated_.StoreRelaxed(0);
alloc_time_ = 0;
live_bytes_ = static_cast<size_t>(-1);
- ZeroAndReleasePages(begin_, end_ - begin_);
+ if (zero_and_release_pages) {
+ ZeroAndReleasePages(begin_, end_ - begin_);
+ }
is_newly_allocated_ = false;
is_a_tlab_ = false;
thread_ = nullptr;
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index 8d8b745b71..9e900e4558 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -24,6 +24,7 @@
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "thread_list.h"
#include "utils.h"
diff --git a/runtime/gc/space/space.cc b/runtime/gc/space/space.cc
index 4a078b8f49..74ce273abf 100644
--- a/runtime/gc/space/space.cc
+++ b/runtime/gc/space/space.cc
@@ -21,7 +21,7 @@
#include "gc/accounting/space_bitmap-inl.h"
#include "gc/heap.h"
#include "runtime.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/gc/space/zygote_space.cc b/runtime/gc/space/zygote_space.cc
index bbfcb31ab1..fddb3f2dd2 100644
--- a/runtime/gc/space/zygote_space.cc
+++ b/runtime/gc/space/zygote_space.cc
@@ -16,10 +16,12 @@
#include "zygote_space.h"
+#include "base/mutex-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/accounting/space_bitmap-inl.h"
#include "gc/heap.h"
-#include "thread-inl.h"
+#include "runtime.h"
+#include "thread-current-inl.h"
#include "utils.h"
namespace art {
diff --git a/runtime/gc/task_processor_test.cc b/runtime/gc/task_processor_test.cc
index f1d26d9a41..5a75b37b67 100644
--- a/runtime/gc/task_processor_test.cc
+++ b/runtime/gc/task_processor_test.cc
@@ -18,7 +18,7 @@
#include "common_runtime_test.h"
#include "task_processor.h"
#include "thread_pool.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/handle_scope-inl.h b/runtime/handle_scope-inl.h
index 492d4b4bd9..d091e7f371 100644
--- a/runtime/handle_scope-inl.h
+++ b/runtime/handle_scope-inl.h
@@ -22,7 +22,7 @@
#include "base/mutex.h"
#include "handle.h"
#include "obj_ptr-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "verify_object.h"
namespace art {
diff --git a/runtime/imtable_test.cc b/runtime/imtable_test.cc
index 17149dfe44..d482183d86 100644
--- a/runtime/imtable_test.cc
+++ b/runtime/imtable_test.cc
@@ -29,7 +29,7 @@
#include "mirror/class_loader.h"
#include "handle_scope-inl.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index c852d5af3a..cff3ea7ecd 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -34,6 +34,9 @@ namespace art {
static constexpr bool kDumpStackOnNonLocalReference = false;
static constexpr bool kDebugIRT = false;
+// Maximum table size we allow.
+static constexpr size_t kMaxTableSizeInBytes = 128 * MB;
+
const char* GetIndirectRefKindString(const IndirectRefKind& kind) {
switch (kind) {
case kHandleScopeOrInvalid:
@@ -71,6 +74,9 @@ IndirectReferenceTable::IndirectReferenceTable(size_t max_count,
CHECK(error_msg != nullptr);
CHECK_NE(desired_kind, kHandleScopeOrInvalid);
+ // Overflow and maximum check.
+ CHECK_LE(max_count, kMaxTableSizeInBytes / sizeof(IrtEntry));
+
const size_t table_bytes = max_count * sizeof(IrtEntry);
table_mem_map_.reset(MemMap::MapAnonymous("indirect ref table", nullptr, table_bytes,
PROT_READ | PROT_WRITE, false, false, error_msg));
@@ -203,6 +209,13 @@ static inline void CheckHoleCount(IrtEntry* table,
bool IndirectReferenceTable::Resize(size_t new_size, std::string* error_msg) {
CHECK_GT(new_size, max_entries_);
+ constexpr size_t kMaxEntries = kMaxTableSizeInBytes / sizeof(IrtEntry);
+ if (new_size > kMaxEntries) {
+ *error_msg = android::base::StringPrintf("Requested size exceeds maximum: %zu", new_size);
+ return false;
+ }
+ // Note: the above check also ensures that there is no overflow below.
+
const size_t table_bytes = new_size * sizeof(IrtEntry);
std::unique_ptr<MemMap> new_map(MemMap::MapAnonymous("indirect ref table",
nullptr,
@@ -247,6 +260,14 @@ IndirectRef IndirectReferenceTable::Add(IRTSegmentState previous_state,
}
// Try to double space.
+ if (std::numeric_limits<size_t>::max() / 2 < max_entries_) {
+ LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow "
+ << "(max=" << max_entries_ << ")" << std::endl
+ << MutatorLockedDumpable<IndirectReferenceTable>(*this)
+ << " Resizing failed: exceeds size_t";
+ UNREACHABLE();
+ }
+
std::string error_msg;
if (!Resize(max_entries_ * 2, &error_msg)) {
LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow "
@@ -453,4 +474,38 @@ void IndirectReferenceTable::SetSegmentState(IRTSegmentState new_state) {
segment_state_ = new_state;
}
+bool IndirectReferenceTable::EnsureFreeCapacity(size_t free_capacity, std::string* error_msg) {
+ size_t top_index = segment_state_.top_index;
+ if (top_index < max_entries_ && top_index + free_capacity <= max_entries_) {
+ return true;
+ }
+
+ // We're only gonna do a simple best-effort here, ensuring the asked-for capacity at the end.
+ if (resizable_ == ResizableCapacity::kNo) {
+ *error_msg = "Table is not resizable";
+ return false;
+ }
+
+ // Try to increase the table size.
+
+ // Would this overflow?
+ if (std::numeric_limits<size_t>::max() - free_capacity < top_index) {
+ *error_msg = "Cannot resize table, overflow.";
+ return false;
+ }
+
+ if (!Resize(top_index + free_capacity, error_msg)) {
+ LOG(WARNING) << "JNI ERROR: Unable to reserve space in EnsureFreeCapacity (" << free_capacity
+ << "): " << std::endl
+ << MutatorLockedDumpable<IndirectReferenceTable>(*this)
+ << " Resizing failed: " << *error_msg;
+ return false;
+ }
+ return true;
+}
+
+size_t IndirectReferenceTable::FreeCapacity() {
+ return max_entries_ - segment_state_.top_index;
+}
+
} // namespace art
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index 7e452a270a..6d52d959cb 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -28,7 +28,6 @@
#include "base/mutex.h"
#include "gc_root.h"
#include "obj_ptr.h"
-#include "object_callbacks.h"
#include "offsets.h"
#include "read_barrier_option.h"
@@ -285,6 +284,13 @@ class IndirectReferenceTable {
return segment_state_.top_index;
}
+ // Ensure that at least free_capacity elements are available, or return false.
+ bool EnsureFreeCapacity(size_t free_capacity, std::string* error_msg)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ // See implementation of EnsureFreeCapacity. We'll only state here how much is trivially free,
+ // without recovering holes. Thus this is a conservative estimate.
+ size_t FreeCapacity() REQUIRES_SHARED(Locks::mutator_lock_);
+
// Note IrtIterator does not have a read barrier as it's used to visit roots.
IrtIterator begin() {
return IrtIterator(table_, 0, Capacity());
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index d862ff2708..540b2e7e9b 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -20,6 +20,7 @@
#include "arch/context.h"
#include "art_method-inl.h"
+#include "art_field-inl.h"
#include "atomic.h"
#include "class_linker.h"
#include "debugger.h"
@@ -31,6 +32,7 @@
#include "interpreter/interpreter.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
+#include "jvalue-inl.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache.h"
#include "mirror/object_array-inl.h"
@@ -45,6 +47,30 @@ namespace instrumentation {
constexpr bool kVerboseInstrumentation = false;
+void InstrumentationListener::MethodExited(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ Handle<mirror::Object> return_value) {
+ DCHECK_EQ(method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetReturnTypePrimitive(),
+ Primitive::kPrimNot);
+ JValue v;
+ v.SetL(return_value.Get());
+ MethodExited(thread, this_object, method, dex_pc, v);
+}
+
+void InstrumentationListener::FieldWritten(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ ArtField* field,
+ Handle<mirror::Object> field_value) {
+ DCHECK(!field->IsPrimitiveType());
+ JValue v;
+ v.SetL(field_value.Get());
+ FieldWritten(thread, this_object, method, dex_pc, field, v);
+}
+
// Instrumentation works on non-inlined frames by updating returned PCs
// of compiled frames.
static constexpr StackVisitor::StackWalkKind kInstrumentationStackWalk =
@@ -916,48 +942,75 @@ const void* Instrumentation::GetQuickCodeFor(ArtMethod* method, PointerSize poin
return class_linker->GetQuickOatCodeFor(method);
}
-void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
+void Instrumentation::MethodEnterEventImpl(Thread* thread,
+ ObjPtr<mirror::Object> this_object,
ArtMethod* method,
uint32_t dex_pc) const {
if (HasMethodEntryListeners()) {
+ Thread* self = Thread::Current();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Object> thiz(hs.NewHandle(this_object));
for (InstrumentationListener* listener : method_entry_listeners_) {
if (listener != nullptr) {
- listener->MethodEntered(thread, this_object, method, dex_pc);
+ listener->MethodEntered(thread, thiz, method, dex_pc);
}
}
}
}
-void Instrumentation::MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
+void Instrumentation::MethodExitEventImpl(Thread* thread,
+ ObjPtr<mirror::Object> this_object,
ArtMethod* method,
- uint32_t dex_pc, const JValue& return_value) const {
+ uint32_t dex_pc,
+ const JValue& return_value) const {
if (HasMethodExitListeners()) {
- for (InstrumentationListener* listener : method_exit_listeners_) {
- if (listener != nullptr) {
- listener->MethodExited(thread, this_object, method, dex_pc, return_value);
+ Thread* self = Thread::Current();
+ StackHandleScope<2> hs(self);
+ Handle<mirror::Object> thiz(hs.NewHandle(this_object));
+ if (method->GetInterfaceMethodIfProxy(kRuntimePointerSize)
+ ->GetReturnTypePrimitive() != Primitive::kPrimNot) {
+ for (InstrumentationListener* listener : method_exit_listeners_) {
+ if (listener != nullptr) {
+ listener->MethodExited(thread, thiz, method, dex_pc, return_value);
+ }
+ }
+ } else {
+ Handle<mirror::Object> ret(hs.NewHandle(return_value.GetL()));
+ for (InstrumentationListener* listener : method_exit_listeners_) {
+ if (listener != nullptr) {
+ listener->MethodExited(thread, thiz, method, dex_pc, ret);
+ }
}
}
}
}
-void Instrumentation::MethodUnwindEvent(Thread* thread, mirror::Object* this_object,
+void Instrumentation::MethodUnwindEvent(Thread* thread,
+ mirror::Object* this_object,
ArtMethod* method,
uint32_t dex_pc) const {
if (HasMethodUnwindListeners()) {
+ Thread* self = Thread::Current();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Object> thiz(hs.NewHandle(this_object));
for (InstrumentationListener* listener : method_unwind_listeners_) {
if (listener != nullptr) {
- listener->MethodUnwind(thread, this_object, method, dex_pc);
+ listener->MethodUnwind(thread, thiz, method, dex_pc);
}
}
}
}
-void Instrumentation::DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
+void Instrumentation::DexPcMovedEventImpl(Thread* thread,
+ ObjPtr<mirror::Object> this_object,
ArtMethod* method,
uint32_t dex_pc) const {
+ Thread* self = Thread::Current();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Object> thiz(hs.NewHandle(this_object));
for (InstrumentationListener* listener : dex_pc_listeners_) {
if (listener != nullptr) {
- listener->DexPcMoved(thread, this_object, method, dex_pc);
+ listener->DexPcMoved(thread, thiz, method, dex_pc);
}
}
}
@@ -974,36 +1027,56 @@ void Instrumentation::BranchImpl(Thread* thread,
}
void Instrumentation::InvokeVirtualOrInterfaceImpl(Thread* thread,
- mirror::Object* this_object,
+ ObjPtr<mirror::Object> this_object,
ArtMethod* caller,
uint32_t dex_pc,
ArtMethod* callee) const {
- // We cannot have thread suspension since that would cause the this_object parameter to
- // potentially become a dangling pointer. An alternative could be to put it in a handle instead.
- ScopedAssertNoThreadSuspension ants(__FUNCTION__);
+ Thread* self = Thread::Current();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Object> thiz(hs.NewHandle(this_object));
for (InstrumentationListener* listener : invoke_virtual_or_interface_listeners_) {
if (listener != nullptr) {
- listener->InvokeVirtualOrInterface(thread, this_object, caller, dex_pc, callee);
+ listener->InvokeVirtualOrInterface(thread, thiz, caller, dex_pc, callee);
}
}
}
-void Instrumentation::FieldReadEventImpl(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc,
+void Instrumentation::FieldReadEventImpl(Thread* thread,
+ ObjPtr<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
ArtField* field) const {
+ Thread* self = Thread::Current();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Object> thiz(hs.NewHandle(this_object));
for (InstrumentationListener* listener : field_read_listeners_) {
if (listener != nullptr) {
- listener->FieldRead(thread, this_object, method, dex_pc, field);
+ listener->FieldRead(thread, thiz, method, dex_pc, field);
}
}
}
-void Instrumentation::FieldWriteEventImpl(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc,
- ArtField* field, const JValue& field_value) const {
- for (InstrumentationListener* listener : field_write_listeners_) {
- if (listener != nullptr) {
- listener->FieldWritten(thread, this_object, method, dex_pc, field, field_value);
+void Instrumentation::FieldWriteEventImpl(Thread* thread,
+ ObjPtr<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ ArtField* field,
+ const JValue& field_value) const {
+ Thread* self = Thread::Current();
+ StackHandleScope<2> hs(self);
+ Handle<mirror::Object> thiz(hs.NewHandle(this_object));
+ if (field->IsPrimitiveType()) {
+ for (InstrumentationListener* listener : field_write_listeners_) {
+ if (listener != nullptr) {
+ listener->FieldWritten(thread, thiz, method, dex_pc, field, field_value);
+ }
+ }
+ } else {
+ Handle<mirror::Object> val(hs.NewHandle(field_value.GetL()));
+ for (InstrumentationListener* listener : field_write_listeners_) {
+ if (listener != nullptr) {
+ listener->FieldWritten(thread, thiz, method, dex_pc, field, val);
+ }
}
}
}
@@ -1018,7 +1091,7 @@ void Instrumentation::ExceptionCaughtEvent(Thread* thread,
thread->ClearException();
for (InstrumentationListener* listener : exception_caught_listeners_) {
if (listener != nullptr) {
- listener->ExceptionCaught(thread, h_exception.Get());
+ listener->ExceptionCaught(thread, h_exception);
}
}
thread->SetException(h_exception.Get());
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index 01071a541f..363985fd62 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -36,6 +36,7 @@ namespace mirror {
} // namespace mirror
class ArtField;
class ArtMethod;
+template <typename T> class Handle;
union JValue;
class Thread;
@@ -62,37 +63,70 @@ struct InstrumentationListener {
virtual ~InstrumentationListener() {}
// Call-back for when a method is entered.
- virtual void MethodEntered(Thread* thread, mirror::Object* this_object,
+ virtual void MethodEntered(Thread* thread,
+ Handle<mirror::Object> this_object,
ArtMethod* method,
uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) = 0;
- // Call-back for when a method is exited.
- virtual void MethodExited(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc,
+ virtual void MethodExited(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ Handle<mirror::Object> return_value)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Call-back for when a method is exited. The implementor should either handler-ize the return
+ // value (if appropriate) or use the alternate MethodExited callback instead if they need to
+ // go through a suspend point.
+ virtual void MethodExited(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
const JValue& return_value)
REQUIRES_SHARED(Locks::mutator_lock_) = 0;
// Call-back for when a method is popped due to an exception throw. A method will either cause a
// MethodExited call-back or a MethodUnwind call-back when its activation is removed.
- virtual void MethodUnwind(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc)
+ virtual void MethodUnwind(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc)
REQUIRES_SHARED(Locks::mutator_lock_) = 0;
// Call-back for when the dex pc moves in a method.
- virtual void DexPcMoved(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t new_dex_pc)
+ virtual void DexPcMoved(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t new_dex_pc)
REQUIRES_SHARED(Locks::mutator_lock_) = 0;
// Call-back for when we read from a field.
- virtual void FieldRead(Thread* thread, mirror::Object* this_object, ArtMethod* method,
- uint32_t dex_pc, ArtField* field) = 0;
+ virtual void FieldRead(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ ArtField* field) = 0;
+
+ virtual void FieldWritten(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ ArtField* field,
+ Handle<mirror::Object> field_value)
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Call-back for when we write into a field.
- virtual void FieldWritten(Thread* thread, mirror::Object* this_object, ArtMethod* method,
- uint32_t dex_pc, ArtField* field, const JValue& field_value) = 0;
+ virtual void FieldWritten(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ ArtField* field,
+ const JValue& field_value)
+ REQUIRES_SHARED(Locks::mutator_lock_) = 0;
// Call-back when an exception is caught.
- virtual void ExceptionCaught(Thread* thread, mirror::Throwable* exception_object)
+ virtual void ExceptionCaught(Thread* thread,
+ Handle<mirror::Throwable> exception_object)
REQUIRES_SHARED(Locks::mutator_lock_) = 0;
// Call-back for when we execute a branch.
@@ -104,11 +138,10 @@ struct InstrumentationListener {
// Call-back for when we get an invokevirtual or an invokeinterface.
virtual void InvokeVirtualOrInterface(Thread* thread,
- mirror::Object* this_object,
+ Handle<mirror::Object> this_object,
ArtMethod* caller,
uint32_t dex_pc,
ArtMethod* callee)
- REQUIRES(Roles::uninterruptible_)
REQUIRES_SHARED(Locks::mutator_lock_) = 0;
};
@@ -323,8 +356,10 @@ class Instrumentation {
}
// Inform listeners that a method has been exited.
- void MethodExitEvent(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc,
+ void MethodExitEvent(Thread* thread,
+ mirror::Object* this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
const JValue& return_value) const
REQUIRES_SHARED(Locks::mutator_lock_) {
if (UNLIKELY(HasMethodExitListeners())) {
@@ -465,31 +500,42 @@ class Instrumentation {
// exclusive access to mutator lock which you can't get if the runtime isn't started.
void SetEntrypointsInstrumented(bool instrumented) NO_THREAD_SAFETY_ANALYSIS;
- void MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc) const
+ void MethodEnterEventImpl(Thread* thread,
+ ObjPtr<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc) const
REQUIRES_SHARED(Locks::mutator_lock_);
- void MethodExitEventImpl(Thread* thread, mirror::Object* this_object,
+ void MethodExitEventImpl(Thread* thread,
+ ObjPtr<mirror::Object> this_object,
ArtMethod* method,
- uint32_t dex_pc, const JValue& return_value) const
+ uint32_t dex_pc,
+ const JValue& return_value) const
REQUIRES_SHARED(Locks::mutator_lock_);
- void DexPcMovedEventImpl(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc) const
+ void DexPcMovedEventImpl(Thread* thread,
+ ObjPtr<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc) const
REQUIRES_SHARED(Locks::mutator_lock_);
void BranchImpl(Thread* thread, ArtMethod* method, uint32_t dex_pc, int32_t offset) const
REQUIRES_SHARED(Locks::mutator_lock_);
void InvokeVirtualOrInterfaceImpl(Thread* thread,
- mirror::Object* this_object,
+ ObjPtr<mirror::Object> this_object,
ArtMethod* caller,
uint32_t dex_pc,
ArtMethod* callee) const
REQUIRES_SHARED(Locks::mutator_lock_);
- void FieldReadEventImpl(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc,
- ArtField* field) const
+ void FieldReadEventImpl(Thread* thread,
+ ObjPtr<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ ArtField* field) const
REQUIRES_SHARED(Locks::mutator_lock_);
- void FieldWriteEventImpl(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc,
- ArtField* field, const JValue& field_value) const
+ void FieldWriteEventImpl(Thread* thread,
+ ObjPtr<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ ArtField* field,
+ const JValue& field_value) const
REQUIRES_SHARED(Locks::mutator_lock_);
// Read barrier-aware utility functions for accessing deoptimized_methods_
diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc
index 7f9f04f435..2a601c9cf2 100644
--- a/runtime/instrumentation_test.cc
+++ b/runtime/instrumentation_test.cc
@@ -23,11 +23,13 @@
#include "dex_file.h"
#include "gc/scoped_gc_critical_section.h"
#include "handle_scope-inl.h"
+#include "jni_internal.h"
#include "jvalue.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "thread_list.h"
#include "thread-inl.h"
+#include "well_known_classes.h"
namespace art {
namespace instrumentation {
@@ -35,16 +37,22 @@ namespace instrumentation {
class TestInstrumentationListener FINAL : public instrumentation::InstrumentationListener {
public:
TestInstrumentationListener()
- : received_method_enter_event(false), received_method_exit_event(false),
- received_method_unwind_event(false), received_dex_pc_moved_event(false),
- received_field_read_event(false), received_field_written_event(false),
- received_exception_caught_event(false), received_branch_event(false),
+ : received_method_enter_event(false),
+ received_method_exit_event(false),
+ received_method_exit_object_event(false),
+ received_method_unwind_event(false),
+ received_dex_pc_moved_event(false),
+ received_field_read_event(false),
+ received_field_written_event(false),
+ received_field_written_object_event(false),
+ received_exception_caught_event(false),
+ received_branch_event(false),
received_invoke_virtual_or_interface_event(false) {}
virtual ~TestInstrumentationListener() {}
void MethodEntered(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Object* this_object ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
ArtMethod* method ATTRIBUTE_UNUSED,
uint32_t dex_pc ATTRIBUTE_UNUSED)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -52,7 +60,16 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio
}
void MethodExited(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Object* this_object ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
+ ArtMethod* method ATTRIBUTE_UNUSED,
+ uint32_t dex_pc ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> return_value ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
+ received_method_exit_object_event = true;
+ }
+
+ void MethodExited(Thread* thread ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
ArtMethod* method ATTRIBUTE_UNUSED,
uint32_t dex_pc ATTRIBUTE_UNUSED,
const JValue& return_value ATTRIBUTE_UNUSED)
@@ -61,7 +78,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio
}
void MethodUnwind(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Object* this_object ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
ArtMethod* method ATTRIBUTE_UNUSED,
uint32_t dex_pc ATTRIBUTE_UNUSED)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -69,7 +86,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio
}
void DexPcMoved(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Object* this_object ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
ArtMethod* method ATTRIBUTE_UNUSED,
uint32_t new_dex_pc ATTRIBUTE_UNUSED)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -77,7 +94,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio
}
void FieldRead(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Object* this_object ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
ArtMethod* method ATTRIBUTE_UNUSED,
uint32_t dex_pc ATTRIBUTE_UNUSED,
ArtField* field ATTRIBUTE_UNUSED)
@@ -86,7 +103,17 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio
}
void FieldWritten(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Object* this_object ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
+ ArtMethod* method ATTRIBUTE_UNUSED,
+ uint32_t dex_pc ATTRIBUTE_UNUSED,
+ ArtField* field ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> field_value ATTRIBUTE_UNUSED)
+ OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
+ received_field_written_object_event = true;
+ }
+
+ void FieldWritten(Thread* thread ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
ArtMethod* method ATTRIBUTE_UNUSED,
uint32_t dex_pc ATTRIBUTE_UNUSED,
ArtField* field ATTRIBUTE_UNUSED,
@@ -96,7 +123,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio
}
void ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Throwable* exception_object ATTRIBUTE_UNUSED)
+ Handle<mirror::Throwable> exception_object ATTRIBUTE_UNUSED)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
received_exception_caught_event = true;
}
@@ -110,7 +137,7 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio
}
void InvokeVirtualOrInterface(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Object* this_object ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
ArtMethod* caller ATTRIBUTE_UNUSED,
uint32_t dex_pc ATTRIBUTE_UNUSED,
ArtMethod* callee ATTRIBUTE_UNUSED)
@@ -121,10 +148,12 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio
void Reset() {
received_method_enter_event = false;
received_method_exit_event = false;
+ received_method_exit_object_event = false;
received_method_unwind_event = false;
received_dex_pc_moved_event = false;
received_field_read_event = false;
received_field_written_event = false;
+ received_field_written_object_event = false;
received_exception_caught_event = false;
received_branch_event = false;
received_invoke_virtual_or_interface_event = false;
@@ -132,10 +161,12 @@ class TestInstrumentationListener FINAL : public instrumentation::Instrumentatio
bool received_method_enter_event;
bool received_method_exit_event;
+ bool received_method_exit_object_event;
bool received_method_unwind_event;
bool received_dex_pc_moved_event;
bool received_field_read_event;
bool received_field_written_event;
+ bool received_field_written_object_event;
bool received_exception_caught_event;
bool received_branch_event;
bool received_invoke_virtual_or_interface_event;
@@ -171,6 +202,13 @@ class InstrumentationTest : public CommonRuntimeTest {
}
void TestEvent(uint32_t instrumentation_event) {
+ TestEvent(instrumentation_event, nullptr, nullptr, false);
+ }
+
+ void TestEvent(uint32_t instrumentation_event,
+ ArtMethod* event_method,
+ ArtField* event_field,
+ bool with_object) {
ScopedObjectAccess soa(Thread::Current());
instrumentation::Instrumentation* instr = Runtime::Current()->GetInstrumentation();
TestInstrumentationListener listener;
@@ -180,15 +218,20 @@ class InstrumentationTest : public CommonRuntimeTest {
instr->AddListener(&listener, instrumentation_event);
}
- ArtMethod* const event_method = nullptr;
mirror::Object* const event_obj = nullptr;
const uint32_t event_dex_pc = 0;
// Check the listener is registered and is notified of the event.
EXPECT_TRUE(HasEventListener(instr, instrumentation_event));
- EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event));
- ReportEvent(instr, instrumentation_event, soa.Self(), event_method, event_obj, event_dex_pc);
- EXPECT_TRUE(DidListenerReceiveEvent(listener, instrumentation_event));
+ EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event, with_object));
+ ReportEvent(instr,
+ instrumentation_event,
+ soa.Self(),
+ event_method,
+ event_obj,
+ event_field,
+ event_dex_pc);
+ EXPECT_TRUE(DidListenerReceiveEvent(listener, instrumentation_event, with_object));
listener.Reset();
{
@@ -199,9 +242,15 @@ class InstrumentationTest : public CommonRuntimeTest {
// Check the listener is not registered and is not notified of the event.
EXPECT_FALSE(HasEventListener(instr, instrumentation_event));
- EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event));
- ReportEvent(instr, instrumentation_event, soa.Self(), event_method, event_obj, event_dex_pc);
- EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event));
+ EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event, with_object));
+ ReportEvent(instr,
+ instrumentation_event,
+ soa.Self(),
+ event_method,
+ event_obj,
+ event_field,
+ event_dex_pc);
+ EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event, with_object));
}
void DeoptimizeMethod(Thread* self, ArtMethod* method, bool enable_deoptimization)
@@ -317,8 +366,12 @@ class InstrumentationTest : public CommonRuntimeTest {
}
}
- static void ReportEvent(const instrumentation::Instrumentation* instr, uint32_t event_type,
- Thread* self, ArtMethod* method, mirror::Object* obj,
+ static void ReportEvent(const instrumentation::Instrumentation* instr,
+ uint32_t event_type,
+ Thread* self,
+ ArtMethod* method,
+ mirror::Object* obj,
+ ArtField* field,
uint32_t dex_pc)
REQUIRES_SHARED(Locks::mutator_lock_) {
switch (event_type) {
@@ -337,11 +390,11 @@ class InstrumentationTest : public CommonRuntimeTest {
instr->DexPcMovedEvent(self, obj, method, dex_pc);
break;
case instrumentation::Instrumentation::kFieldRead:
- instr->FieldReadEvent(self, obj, method, dex_pc, nullptr);
+ instr->FieldReadEvent(self, obj, method, dex_pc, field);
break;
case instrumentation::Instrumentation::kFieldWritten: {
JValue value;
- instr->FieldWriteEvent(self, obj, method, dex_pc, nullptr, value);
+ instr->FieldWriteEvent(self, obj, method, dex_pc, field, value);
break;
}
case instrumentation::Instrumentation::kExceptionCaught: {
@@ -364,12 +417,14 @@ class InstrumentationTest : public CommonRuntimeTest {
}
static bool DidListenerReceiveEvent(const TestInstrumentationListener& listener,
- uint32_t event_type) {
+ uint32_t event_type,
+ bool with_object) {
switch (event_type) {
case instrumentation::Instrumentation::kMethodEntered:
return listener.received_method_enter_event;
case instrumentation::Instrumentation::kMethodExited:
- return listener.received_method_exit_event;
+ return (!with_object && listener.received_method_exit_event) ||
+ (with_object && listener.received_method_exit_object_event);
case instrumentation::Instrumentation::kMethodUnwind:
return listener.received_method_unwind_event;
case instrumentation::Instrumentation::kDexPcMoved:
@@ -377,7 +432,8 @@ class InstrumentationTest : public CommonRuntimeTest {
case instrumentation::Instrumentation::kFieldRead:
return listener.received_field_read_event;
case instrumentation::Instrumentation::kFieldWritten:
- return listener.received_field_written_event;
+ return (!with_object && listener.received_field_written_event) ||
+ (with_object && listener.received_field_written_object_event);
case instrumentation::Instrumentation::kExceptionCaught:
return listener.received_exception_caught_event;
case instrumentation::Instrumentation::kBranch:
@@ -419,8 +475,42 @@ TEST_F(InstrumentationTest, MethodEntryEvent) {
TestEvent(instrumentation::Instrumentation::kMethodEntered);
}
-TEST_F(InstrumentationTest, MethodExitEvent) {
- TestEvent(instrumentation::Instrumentation::kMethodExited);
+TEST_F(InstrumentationTest, MethodExitObjectEvent) {
+ ScopedObjectAccess soa(Thread::Current());
+ jobject class_loader = LoadDex("Instrumentation");
+ Runtime* const runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
+ mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
+ ASSERT_TRUE(klass != nullptr);
+ ArtMethod* method = klass->FindDeclaredDirectMethod("returnReference",
+ "()Ljava/lang/Object;",
+ kRuntimePointerSize);
+ ASSERT_TRUE(method != nullptr);
+ TestEvent(instrumentation::Instrumentation::kMethodExited,
+ /*event_method*/ method,
+ /*event_field*/ nullptr,
+ /*with_object*/ true);
+}
+
+TEST_F(InstrumentationTest, MethodExitPrimEvent) {
+ ScopedObjectAccess soa(Thread::Current());
+ jobject class_loader = LoadDex("Instrumentation");
+ Runtime* const runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
+ mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
+ ASSERT_TRUE(klass != nullptr);
+ ArtMethod* method = klass->FindDeclaredDirectMethod("returnPrimitive",
+ "()I",
+ kRuntimePointerSize);
+ ASSERT_TRUE(method != nullptr);
+ TestEvent(instrumentation::Instrumentation::kMethodExited,
+ /*event_method*/ method,
+ /*event_field*/ nullptr,
+ /*with_object*/ false);
}
TEST_F(InstrumentationTest, MethodUnwindEvent) {
@@ -435,8 +525,40 @@ TEST_F(InstrumentationTest, FieldReadEvent) {
TestEvent(instrumentation::Instrumentation::kFieldRead);
}
-TEST_F(InstrumentationTest, FieldWriteEvent) {
- TestEvent(instrumentation::Instrumentation::kFieldWritten);
+TEST_F(InstrumentationTest, FieldWriteObjectEvent) {
+ ScopedObjectAccess soa(Thread::Current());
+ jobject class_loader = LoadDex("Instrumentation");
+ Runtime* const runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
+ mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
+ ASSERT_TRUE(klass != nullptr);
+ ArtField* field = klass->FindDeclaredStaticField("referenceField", "Ljava/lang/Object;");
+ ASSERT_TRUE(field != nullptr);
+
+ TestEvent(instrumentation::Instrumentation::kFieldWritten,
+ /*event_method*/ nullptr,
+ /*event_field*/ field,
+ /*with_object*/ true);
+}
+
+TEST_F(InstrumentationTest, FieldWritePrimEvent) {
+ ScopedObjectAccess soa(Thread::Current());
+ jobject class_loader = LoadDex("Instrumentation");
+ Runtime* const runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
+ mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
+ ASSERT_TRUE(klass != nullptr);
+ ArtField* field = klass->FindDeclaredStaticField("primitiveField", "I");
+ ASSERT_TRUE(field != nullptr);
+
+ TestEvent(instrumentation::Instrumentation::kFieldWritten,
+ /*event_method*/ nullptr,
+ /*event_field*/ field,
+ /*with_object*/ false);
}
TEST_F(InstrumentationTest, ExceptionCaughtEvent) {
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 3e1914604d..2bac2312bf 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -27,6 +27,8 @@
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
#include "mirror/string-inl.h"
+#include "object_callbacks.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "utf.h"
diff --git a/runtime/intern_table.h b/runtime/intern_table.h
index 68454fbfd4..2ec03be670 100644
--- a/runtime/intern_table.h
+++ b/runtime/intern_table.h
@@ -25,10 +25,11 @@
#include "base/mutex.h"
#include "gc_root.h"
#include "gc/weak_root_state.h"
-#include "object_callbacks.h"
namespace art {
+class IsMarkedVisitor;
+
namespace gc {
namespace space {
class ImageSpace;
diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc
index 311515c7ed..bb27b34cf5 100644
--- a/runtime/intern_table_test.cc
+++ b/runtime/intern_table_test.cc
@@ -23,6 +23,7 @@
#include "handle_scope-inl.h"
#include "mirror/string.h"
#include "scoped_thread_state_change-inl.h"
+#include "utf.h"
namespace art {
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index d2f5232de1..4bc0f2fa12 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -22,15 +22,16 @@
#include "interpreter_common.h"
#include "interpreter_mterp_impl.h"
#include "interpreter_switch_impl.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
#include "jvalue-inl.h"
#include "mirror/string-inl.h"
+#include "mterp/mterp.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "stack.h"
+#include "thread-inl.h"
#include "unstarted_runtime.h"
-#include "mterp/mterp.h"
-#include "jit/jit.h"
-#include "jit/jit_code_cache.h"
namespace art {
namespace interpreter {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 084cb4218f..d06ac23d3c 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -32,6 +32,7 @@
#include "reflection.h"
#include "reflection-inl.h"
#include "stack.h"
+#include "thread-inl.h"
#include "well_known_classes.h"
namespace art {
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index b191dd79a1..32a23783b7 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -307,6 +307,8 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), inst->GetDexPc(insns),
result);
+ // Re-load since it might have moved during the MethodExitEvent.
+ result.SetL(shadow_frame.GetVRegReference(ref_idx));
}
if (interpret_one_instruction) {
/* Signal mterp to return to caller */
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 96934bc0ca..152cce4c60 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -50,7 +50,7 @@
#include "mirror/string-inl.h"
#include "nth_caller_visitor.h"
#include "reflection.h"
-#include "thread.h"
+#include "thread-inl.h"
#include "transaction.h"
#include "well_known_classes.h"
#include "zip_archive.h"
diff --git a/runtime/invoke_type.h b/runtime/invoke_type.h
index de07c72ef0..a003f7fe9e 100644
--- a/runtime/invoke_type.h
+++ b/runtime/invoke_type.h
@@ -21,7 +21,7 @@
namespace art {
-enum InvokeType {
+enum InvokeType : uint32_t {
kStatic, // <<static>>
kDirect, // <<direct>>
kVirtual, // <<virtual>>
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index bd0f8420aa..2ad3b29f17 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "jni_internal.h"
+#include "java_vm_ext.h"
#include <dlfcn.h>
@@ -22,7 +22,7 @@
#include "art_method-inl.h"
#include "base/dumpable.h"
-#include "base/mutex.h"
+#include "base/mutex-inl.h"
#include "base/stl_util.h"
#include "base/systrace.h"
#include "check_jni.h"
@@ -30,11 +30,12 @@
#include "fault_handler.h"
#include "gc_root-inl.h"
#include "indirect_reference_table-inl.h"
+#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "nativebridge/native_bridge.h"
#include "nativeloader/native_loader.h"
-#include "java_vm_ext.h"
+#include "object_callbacks.h"
#include "parsed_options.h"
#include "runtime-inl.h"
#include "runtime_options.h"
@@ -145,19 +146,24 @@ class SharedLibrary {
return needs_native_bridge_;
}
- void* FindSymbol(const std::string& symbol_name, const char* shorty = nullptr) {
+ // No mutator lock since dlsym may block for a while if another thread is doing dlopen.
+ void* FindSymbol(const std::string& symbol_name, const char* shorty = nullptr)
+ REQUIRES(!Locks::mutator_lock_) {
return NeedsNativeBridge()
? FindSymbolWithNativeBridge(symbol_name.c_str(), shorty)
: FindSymbolWithoutNativeBridge(symbol_name.c_str());
}
- void* FindSymbolWithoutNativeBridge(const std::string& symbol_name) {
+ // No mutator lock since dlsym may block for a while if another thread is doing dlopen.
+ void* FindSymbolWithoutNativeBridge(const std::string& symbol_name)
+ REQUIRES(!Locks::mutator_lock_) {
CHECK(!NeedsNativeBridge());
return dlsym(handle_, symbol_name.c_str());
}
- void* FindSymbolWithNativeBridge(const std::string& symbol_name, const char* shorty) {
+ void* FindSymbolWithNativeBridge(const std::string& symbol_name, const char* shorty)
+ REQUIRES(!Locks::mutator_lock_) {
CHECK(NeedsNativeBridge());
uint32_t len = 0;
@@ -236,8 +242,8 @@ class Libraries {
}
// See section 11.3 "Linking Native Methods" of the JNI spec.
- void* FindNativeMethod(ArtMethod* m, std::string& detail)
- REQUIRES(Locks::jni_libraries_lock_)
+ void* FindNativeMethod(Thread* self, ArtMethod* m, std::string& detail)
+ REQUIRES(!Locks::jni_libraries_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
std::string jni_short_name(m->JniShortName());
std::string jni_long_name(m->JniLongName());
@@ -246,6 +252,34 @@ class Libraries {
void* const declaring_class_loader_allocator =
Runtime::Current()->GetClassLinker()->GetAllocatorForClassLoader(declaring_class_loader);
CHECK(declaring_class_loader_allocator != nullptr);
+ // TODO: Avoid calling GetShorty here to prevent dirtying dex pages?
+ const char* shorty = m->GetShorty();
+ {
+ // Go to suspended since dlsym may block for a long time if other threads are using dlopen.
+ ScopedThreadSuspension sts(self, kNative);
+ void* native_code = FindNativeMethodInternal(self,
+ declaring_class_loader_allocator,
+ shorty,
+ jni_short_name,
+ jni_long_name);
+ if (native_code != nullptr) {
+ return native_code;
+ }
+ }
+ detail += "No implementation found for ";
+ detail += m->PrettyMethod();
+ detail += " (tried " + jni_short_name + " and " + jni_long_name + ")";
+ return nullptr;
+ }
+
+ void* FindNativeMethodInternal(Thread* self,
+ void* declaring_class_loader_allocator,
+ const char* shorty,
+ const std::string& jni_short_name,
+ const std::string& jni_long_name)
+ REQUIRES(!Locks::jni_libraries_lock_)
+ REQUIRES(!Locks::mutator_lock_) {
+ MutexLock mu(self, *Locks::jni_libraries_lock_);
for (const auto& lib : libraries_) {
SharedLibrary* const library = lib.second;
// Use the allocator address for class loader equality to avoid unnecessary weak root decode.
@@ -254,22 +288,17 @@ class Libraries {
continue;
}
// Try the short name then the long name...
- const char* shorty = library->NeedsNativeBridge()
- ? m->GetShorty()
- : nullptr;
- void* fn = library->FindSymbol(jni_short_name, shorty);
+ const char* arg_shorty = library->NeedsNativeBridge() ? shorty : nullptr;
+ void* fn = library->FindSymbol(jni_short_name, arg_shorty);
if (fn == nullptr) {
- fn = library->FindSymbol(jni_long_name, shorty);
+ fn = library->FindSymbol(jni_long_name, arg_shorty);
}
if (fn != nullptr) {
- VLOG(jni) << "[Found native code for " << m->PrettyMethod()
+ VLOG(jni) << "[Found native code for " << jni_long_name
<< " in \"" << library->GetPath() << "\"]";
return fn;
}
}
- detail += "No implementation found for ";
- detail += m->PrettyMethod();
- detail += " (tried " + jni_short_name + " and " + jni_long_name + ")";
return nullptr;
}
@@ -277,18 +306,17 @@ class Libraries {
void UnloadNativeLibraries()
REQUIRES(!Locks::jni_libraries_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
- ScopedObjectAccessUnchecked soa(Thread::Current());
+ Thread* const self = Thread::Current();
std::vector<SharedLibrary*> unload_libraries;
{
- MutexLock mu(soa.Self(), *Locks::jni_libraries_lock_);
+ MutexLock mu(self, *Locks::jni_libraries_lock_);
for (auto it = libraries_.begin(); it != libraries_.end(); ) {
SharedLibrary* const library = it->second;
// If class loader is null then it was unloaded, call JNI_OnUnload.
const jweak class_loader = library->GetClassLoader();
// If class_loader is a null jobject then it is the boot class loader. We should not unload
// the native libraries of the boot class loader.
- if (class_loader != nullptr &&
- soa.Self()->IsJWeakCleared(class_loader)) {
+ if (class_loader != nullptr && self->IsJWeakCleared(class_loader)) {
unload_libraries.push_back(library);
it = libraries_.erase(it);
} else {
@@ -296,6 +324,7 @@ class Libraries {
}
}
}
+ ScopedThreadSuspension sts(self, kNative);
// Do this without holding the jni libraries lock to prevent possible deadlocks.
typedef void (*JNI_OnUnloadFn)(JavaVM*, void*);
for (auto library : unload_libraries) {
@@ -305,7 +334,7 @@ class Libraries {
} else {
VLOG(jni) << "[JNI_OnUnload found for \"" << library->GetPath() << "\"]: Calling...";
JNI_OnUnloadFn jni_on_unload = reinterpret_cast<JNI_OnUnloadFn>(sym);
- jni_on_unload(soa.Vm(), nullptr);
+ jni_on_unload(self->GetJniEnv()->vm, nullptr);
}
delete library;
}
@@ -956,12 +985,8 @@ void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m) {
// If this is a static method, it could be called before the class has been initialized.
CHECK(c->IsInitializing()) << c->GetStatus() << " " << m->PrettyMethod();
std::string detail;
- void* native_method;
- Thread* self = Thread::Current();
- {
- MutexLock mu(self, *Locks::jni_libraries_lock_);
- native_method = libraries_->FindNativeMethod(m, detail);
- }
+ Thread* const self = Thread::Current();
+ void* native_method = libraries_->FindNativeMethod(self, m, detail);
if (native_method == nullptr) {
// Lookup JNI native methods from native TI Agent libraries. See runtime/ti/agent.h for more
// information. Agent libraries are searched for native methods after all jni libraries.
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index 7374920f2b..50aabdcdf5 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -32,6 +32,7 @@ namespace mirror {
} // namespace mirror
class ArtMethod;
+class IsMarkedVisitor;
class Libraries;
class ParsedOptions;
class Runtime;
diff --git a/runtime/jdwp/jdwp_adb.cc b/runtime/jdwp/jdwp_adb.cc
index 0aa04c10ca..ede4f9edb7 100644
--- a/runtime/jdwp/jdwp_adb.cc
+++ b/runtime/jdwp/jdwp_adb.cc
@@ -24,7 +24,7 @@
#include "base/logging.h"
#include "jdwp/jdwp_priv.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#ifdef ART_TARGET_ANDROID
#include "cutils/sockets.h"
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index e8a9904dc6..618332b7ef 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -33,7 +33,7 @@
#include "jdwp/jdwp_priv.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils.h"
namespace art {
diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc
index ae0004426d..135d9b1f51 100644
--- a/runtime/jit/debugger_interface.cc
+++ b/runtime/jit/debugger_interface.cc
@@ -18,7 +18,7 @@
#include "base/logging.h"
#include "base/mutex.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread.h"
#include <unordered_map>
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index ae474da7c0..969a5708c4 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -32,7 +32,9 @@
#include "profile_saver.h"
#include "runtime.h"
#include "runtime_options.h"
+#include "stack.h"
#include "stack_map.h"
+#include "thread-inl.h"
#include "thread_list.h"
#include "utils.h"
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 75f9b0ac76..f898d416c1 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -23,7 +23,6 @@
#include "base/timing_logger.h"
#include "jit/profile_saver_options.h"
#include "obj_ptr.h"
-#include "object_callbacks.h"
#include "profile_compilation_info.h"
#include "thread_pool.h"
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index fdac24e5a0..0cafac7380 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -34,7 +34,10 @@
#include "linear_alloc.h"
#include "mem_map.h"
#include "oat_file-inl.h"
+#include "oat_quick_method_header.h"
+#include "object_callbacks.h"
#include "scoped_thread_state_change-inl.h"
+#include "stack.h"
#include "thread_list.h"
namespace art {
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 612d06ba1c..9ecc876716 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -29,7 +29,6 @@
#include "jni.h"
#include "method_reference.h"
#include "oat_file.h"
-#include "object_callbacks.h"
#include "profile_compilation_info.h"
#include "safe_map.h"
#include "thread_pool.h"
@@ -39,6 +38,8 @@ namespace art {
class ArtMethod;
class LinearAlloc;
class InlineCache;
+class IsMarkedVisitor;
+class OatQuickMethodHeader;
class ProfilingInfo;
namespace jit {
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index 86c15e6227..3852a5bc53 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -47,9 +47,9 @@
namespace art {
const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
-// Last profile version: Instead of method index, put the difference with the last
-// method's index.
-const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '0', '7', '\0' };
+// Last profile version: Move startup methods to use a bitmap. Also add support for post-startup
+// methods.
+const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '0', '8', '\0' };
static constexpr uint16_t kMaxDexFileKeyLength = PATH_MAX;
@@ -132,6 +132,33 @@ std::string ProfileCompilationInfo::GetProfileDexFileKey(const std::string& dex_
}
}
+bool ProfileCompilationInfo::AddSampledMethod(bool startup,
+ const std::string& dex_location,
+ uint32_t checksum,
+ uint16_t method_idx,
+ uint32_t num_method_ids) {
+ DexFileData* data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
+ checksum,
+ num_method_ids);
+ if (data == nullptr) {
+ return false;
+ }
+ data->AddSampledMethod(startup, method_idx);
+ return true;
+}
+
+bool ProfileCompilationInfo::AddSampledMethods(bool startup,
+ std::vector<MethodReference>& methods) {
+ for (const MethodReference& ref : methods) {
+ DexFileData* data = GetOrAddDexFileData(ref.dex_file);
+ if (data == nullptr) {
+ return false;
+ }
+ data->AddSampledMethod(startup, ref.dex_method_index);
+ }
+ return true;
+}
+
bool ProfileCompilationInfo::AddMethodsAndClasses(
const std::vector<ProfileMethodInfo>& methods,
const std::set<DexCacheResolvedClasses>& resolved_classes) {
@@ -252,15 +279,18 @@ static void AddUintToBuffer(std::vector<uint8_t>* buffer, T value) {
static constexpr size_t kLineHeaderSize =
2 * sizeof(uint16_t) + // class_set.size + dex_location.size
- 2 * sizeof(uint32_t); // method_map.size + checksum
+ 3 * sizeof(uint32_t); // method_map.size + checksum + num_method_ids
/**
* Serialization format:
* magic,version,number_of_dex_files,uncompressed_size_of_zipped_data,compressed_data_size,
- * zipped[dex_location1,number_of_classes1,methods_region_size,dex_location_checksum1, \
+ * zipped[dex_location1,number_of_classes1,methods_region_size,dex_location_checksum1
+ * num_method_ids,
* method_encoding_11,method_encoding_12...,class_id1,class_id2...
- * dex_location2,number_of_classes2,methods_region_size,dex_location_checksum2, \
+ * startup/post startup bitmap,
+ * dex_location2,number_of_classes2,methods_region_size,dex_location_checksum2, num_method_ids,
* method_encoding_21,method_encoding_22...,,class_id1,class_id2...
+ * startup/post startup bitmap,
* .....]
* The method_encoding is:
* method_id,number_of_inline_caches,inline_cache1,inline_cache2...
@@ -297,7 +327,8 @@ bool ProfileCompilationInfo::Save(int fd) {
required_capacity += kLineHeaderSize +
dex_data.profile_key.size() +
sizeof(uint16_t) * dex_data.class_set.size() +
- methods_region_size;
+ methods_region_size +
+ dex_data.bitmap_storage.size();
}
if (required_capacity > kProfileSizeErrorThresholdInBytes) {
LOG(ERROR) << "Profile data size exceeds "
@@ -335,10 +366,12 @@ bool ProfileCompilationInfo::Save(int fd) {
DCHECK_LE(dex_data.profile_key.size(), std::numeric_limits<uint16_t>::max());
DCHECK_LE(dex_data.class_set.size(), std::numeric_limits<uint16_t>::max());
+ // Write profile line header.
AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.profile_key.size()));
AddUintToBuffer(&buffer, static_cast<uint16_t>(dex_data.class_set.size()));
AddUintToBuffer(&buffer, methods_region_size); // uint32_t
AddUintToBuffer(&buffer, dex_data.checksum); // uint32_t
+ AddUintToBuffer(&buffer, dex_data.num_method_ids); // uint32_t
AddStringToBuffer(&buffer, dex_data.profile_key);
@@ -362,6 +395,10 @@ bool ProfileCompilationInfo::Save(int fd) {
last_class_index = class_id.index_;
AddUintToBuffer(&buffer, diff_with_last_class_index);
}
+
+ buffer.insert(buffer.end(),
+ dex_data.bitmap_storage.begin(),
+ dex_data.bitmap_storage.end());
}
uint32_t output_size = 0;
@@ -476,7 +513,8 @@ void ProfileCompilationInfo::GroupClassesByDex(
ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
const std::string& profile_key,
- uint32_t checksum) {
+ uint32_t checksum,
+ uint32_t num_method_ids) {
const auto profile_index_it = profile_key_map_.FindOrAdd(profile_key, profile_key_map_.size());
if (profile_key_map_.size() > std::numeric_limits<uint8_t>::max()) {
// Allow only 255 dex files to be profiled. This allows us to save bytes
@@ -492,7 +530,11 @@ ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData
if (info_.size() <= profile_index) {
// This is a new addition. Add it to the info_ array.
DexFileData* dex_file_data = new (&arena_) DexFileData(
- &arena_, profile_key, checksum, profile_index);
+ &arena_,
+ profile_key,
+ checksum,
+ profile_index,
+ num_method_ids);
info_.push_back(dex_file_data);
}
DexFileData* result = info_[profile_index];
@@ -500,6 +542,7 @@ ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData
// This should always be the case since since the cache map is managed by ProfileCompilationInfo.
DCHECK_EQ(profile_key, result->profile_key);
DCHECK_EQ(profile_index, result->profile_index);
+ DCHECK_EQ(num_method_ids, result->num_method_ids);
// Check that the checksum matches.
// This may different if for example the dex file was updated and
@@ -528,7 +571,7 @@ const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
bool ProfileCompilationInfo::AddResolvedClasses(const DexCacheResolvedClasses& classes) {
const std::string dex_location = GetProfileDexFileKey(classes.GetDexLocation());
const uint32_t checksum = classes.GetLocationChecksum();
- DexFileData* const data = GetOrAddDexFileData(dex_location, checksum);
+ DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, classes.NumMethodIds());
if (data == nullptr) {
return false;
}
@@ -538,15 +581,23 @@ bool ProfileCompilationInfo::AddResolvedClasses(const DexCacheResolvedClasses& c
bool ProfileCompilationInfo::AddMethodIndex(const std::string& dex_location,
uint32_t dex_checksum,
- uint16_t method_index) {
- return AddMethod(dex_location, dex_checksum, method_index, OfflineProfileMethodInfo(nullptr));
+ uint16_t method_index,
+ uint32_t num_method_ids) {
+ return AddMethod(dex_location,
+ dex_checksum,
+ method_index,
+ num_method_ids,
+ OfflineProfileMethodInfo(nullptr));
}
bool ProfileCompilationInfo::AddMethod(const std::string& dex_location,
uint32_t dex_checksum,
uint16_t method_index,
+ uint32_t num_method_ids,
const OfflineProfileMethodInfo& pmi) {
- DexFileData* const data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location), dex_checksum);
+ DexFileData* const data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location),
+ dex_checksum,
+ num_method_ids);
if (data == nullptr) { // checksum mismatch
return false;
}
@@ -579,7 +630,8 @@ bool ProfileCompilationInfo::AddMethod(const std::string& dex_location,
const DexReference& dex_ref = pmi.dex_references[class_ref.dex_profile_index];
DexFileData* class_dex_data = GetOrAddDexFileData(
GetProfileDexFileKey(dex_ref.dex_location),
- dex_ref.dex_checksum);
+ dex_ref.dex_checksum,
+ dex_ref.num_method_ids);
if (class_dex_data == nullptr) { // checksum mismatch
return false;
}
@@ -590,9 +642,7 @@ bool ProfileCompilationInfo::AddMethod(const std::string& dex_location,
}
bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi) {
- DexFileData* const data = GetOrAddDexFileData(
- GetProfileDexFileKey(pmi.dex_file->GetLocation()),
- pmi.dex_file->GetLocationChecksum());
+ DexFileData* const data = GetOrAddDexFileData(pmi.dex_file);
if (data == nullptr) { // checksum mismatch
return false;
}
@@ -604,9 +654,7 @@ bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi) {
continue;
}
for (const TypeReference& class_ref : cache.classes) {
- DexFileData* class_dex_data = GetOrAddDexFileData(
- GetProfileDexFileKey(class_ref.dex_file->GetLocation()),
- class_ref.dex_file->GetLocationChecksum());
+ DexFileData* class_dex_data = GetOrAddDexFileData(class_ref.dex_file);
if (class_dex_data == nullptr) { // checksum mismatch
return false;
}
@@ -623,8 +671,9 @@ bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi) {
bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
uint32_t checksum,
- dex::TypeIndex type_idx) {
- DexFileData* const data = GetOrAddDexFileData(dex_location, checksum);
+ dex::TypeIndex type_idx,
+ uint32_t num_method_ids) {
+ DexFileData* const data = GetOrAddDexFileData(dex_location, checksum, num_method_ids);
if (data == nullptr) {
return false;
}
@@ -694,7 +743,9 @@ bool ProfileCompilationInfo::ReadMethods(SafeBuffer& buffer,
- line_header.method_region_size_bytes;
uint16_t last_method_index = 0;
while (buffer.CountUnreadBytes() > expected_unread_bytes_after_operation) {
- DexFileData* const data = GetOrAddDexFileData(line_header.dex_location, line_header.checksum);
+ DexFileData* const data = GetOrAddDexFileData(line_header.dex_location,
+ line_header.checksum,
+ line_header.num_method_ids);
uint16_t diff_with_last_method_index;
READ_UINT(uint16_t, buffer, diff_with_last_method_index, error);
uint16_t method_index = last_method_index + diff_with_last_method_index;
@@ -729,7 +780,8 @@ bool ProfileCompilationInfo::ReadClasses(SafeBuffer& buffer,
last_class_index = type_index;
if (!AddClassIndex(line_header.dex_location,
line_header.checksum,
- dex::TypeIndex(type_index))) {
+ dex::TypeIndex(type_index),
+ line_header.num_method_ids)) {
return false;
}
}
@@ -863,6 +915,7 @@ bool ProfileCompilationInfo::ReadProfileLineHeaderElements(SafeBuffer& buffer,
READ_UINT(uint16_t, buffer, line_header->class_set_size, error);
READ_UINT(uint32_t, buffer, line_header->method_region_size_bytes, error);
READ_UINT(uint32_t, buffer, line_header->checksum, error);
+ READ_UINT(uint32_t, buffer, line_header->num_method_ids, error);
return true;
}
@@ -902,7 +955,10 @@ ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::ReadProfileLine
uint8_t number_of_dex_files,
const ProfileLineHeader& line_header,
/*out*/std::string* error) {
- if (GetOrAddDexFileData(line_header.dex_location, line_header.checksum) == nullptr) {
+ DexFileData* data = GetOrAddDexFileData(line_header.dex_location,
+ line_header.checksum,
+ line_header.num_method_ids);
+ if (data == nullptr) {
*error = "Error when reading profile file line header: checksum mismatch for "
+ line_header.dex_location;
return kProfileLoadBadData;
@@ -915,6 +971,16 @@ ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::ReadProfileLine
if (!ReadClasses(buffer, line_header, error)) {
return kProfileLoadBadData;
}
+
+ const size_t bytes = data->bitmap_storage.size();
+ if (buffer.CountUnreadBytes() < bytes) {
+ *error += "Profile EOF reached prematurely for ReadProfileHeaderDexLocation";
+ return kProfileLoadBadData;
+ }
+ const uint8_t* base_ptr = buffer.GetCurrentPtr();
+ std::copy_n(base_ptr, bytes, &data->bitmap_storage[0]);
+ buffer.Advance(bytes);
+ // Read method bitmap.
return kProfileLoadSuccess;
}
@@ -1110,7 +1176,8 @@ bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other) {
SafeMap<uint8_t, uint8_t> dex_profile_index_remap;
for (const DexFileData* other_dex_data : other.info_) {
const DexFileData* dex_data = GetOrAddDexFileData(other_dex_data->profile_key,
- other_dex_data->checksum);
+ other_dex_data->checksum,
+ other_dex_data->num_method_ids);
if (dex_data == nullptr) {
return false; // Could happen if we exceed the number of allowed dex files.
}
@@ -1147,6 +1214,9 @@ bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other) {
}
}
}
+
+ // Merge the bitmaps.
+ dex_data->MergeBitmap(*other_dex_data);
}
return true;
}
@@ -1159,7 +1229,28 @@ static bool ChecksumMatch(const DexFile& dex_file, uint32_t checksum) {
return ChecksumMatch(dex_file.GetLocationChecksum(), checksum);
}
-bool ProfileCompilationInfo::ContainsMethod(const MethodReference& method_ref) const {
+bool ProfileCompilationInfo::IsStartupOrHotMethod(const MethodReference& method_ref) const {
+ return IsStartupOrHotMethod(method_ref.dex_file->GetLocation(),
+ method_ref.dex_file->GetLocationChecksum(),
+ method_ref.dex_method_index);
+}
+
+bool ProfileCompilationInfo::IsStartupOrHotMethod(const std::string& dex_location,
+ uint32_t dex_checksum,
+ uint16_t dex_method_index) const {
+ const DexFileData* dex_data = FindDexData(GetProfileDexFileKey(dex_location));
+ if (dex_data == nullptr || !ChecksumMatch(dex_checksum, dex_data->checksum)) {
+ return false;
+ }
+ if (dex_data->HasSampledMethod(/*startup*/ true, dex_method_index)) {
+ return true;
+ }
+ const MethodMap& methods = dex_data->method_map;
+ const auto method_it = methods.find(dex_method_index);
+ return method_it != methods.end();
+}
+
+bool ProfileCompilationInfo::ContainsHotMethod(const MethodReference& method_ref) const {
return FindMethod(method_ref.dex_file->GetLocation(),
method_ref.dex_file->GetLocationChecksum(),
method_ref.dex_method_index) != nullptr;
@@ -1196,6 +1287,7 @@ std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> ProfileCompila
for (const DexFileData* dex_data : info_) {
pmi->dex_references[dex_data->profile_index].dex_location = dex_data->profile_key;
pmi->dex_references[dex_data->profile_index].dex_checksum = dex_data->checksum;
+ pmi->dex_references[dex_data->profile_index].num_method_ids = dex_data->num_method_ids;
}
return pmi;
@@ -1277,7 +1369,7 @@ std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>*
}
}
}
- os << "\n\tmethods: ";
+ os << "\n\thot methods: ";
for (const auto& method_it : dex_data->method_map) {
if (dex_file != nullptr) {
os << "\n\t\t" << dex_file->PrettyMethod(method_it.first, true);
@@ -1302,6 +1394,19 @@ std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>*
}
os << "], ";
}
+ bool startup = true;
+ while (true) {
+ os << "\n\t" << (startup ? "startup methods: " : "post startup methods: ");
+ for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
+ if (dex_data->HasSampledMethod(startup, method_idx)) {
+ os << method_idx << ", ";
+ }
+ }
+ if (startup == false) {
+ break;
+ }
+ startup = false;
+ }
os << "\n\tclasses: ";
for (const auto class_it : dex_data->class_set) {
if (dex_file != nullptr) {
@@ -1314,9 +1419,12 @@ std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>*
return os.str();
}
-bool ProfileCompilationInfo::GetClassesAndMethods(const DexFile& dex_file,
- std::set<dex::TypeIndex>* class_set,
- std::set<uint16_t>* method_set) const {
+bool ProfileCompilationInfo::GetClassesAndMethods(
+ const DexFile& dex_file,
+ /*out*/std::set<dex::TypeIndex>* class_set,
+ /*out*/std::set<uint16_t>* hot_method_set,
+ /*out*/std::set<uint16_t>* startup_method_set,
+ /*out*/std::set<uint16_t>* post_startup_method_method_set) const {
std::set<std::string> ret;
std::string profile_key = GetProfileDexFileKey(dex_file.GetLocation());
const DexFileData* dex_data = FindDexData(profile_key);
@@ -1324,7 +1432,15 @@ bool ProfileCompilationInfo::GetClassesAndMethods(const DexFile& dex_file,
return false;
}
for (const auto& it : dex_data->method_map) {
- method_set->insert(it.first);
+ hot_method_set->insert(it.first);
+ }
+ for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
+ if (dex_data->HasSampledMethod(/*startup*/ true, method_idx)) {
+ startup_method_set->insert(method_idx);
+ }
+ if (dex_data->HasSampledMethod(/*startup*/ false, method_idx)) {
+ post_startup_method_method_set->insert(method_idx);
+ }
}
for (const dex::TypeIndex& type_index : dex_data->class_set) {
class_set->insert(type_index);
@@ -1366,7 +1482,10 @@ std::set<DexCacheResolvedClasses> ProfileCompilationInfo::GetResolvedClasses(
<< ", profile checksum=" << dex_data->checksum;
return std::set<DexCacheResolvedClasses>();
}
- DexCacheResolvedClasses classes(dex_location, dex_location, dex_data->checksum);
+ DexCacheResolvedClasses classes(dex_location,
+ dex_location,
+ dex_data->checksum,
+ dex_data->num_method_ids);
classes.AddClasses(dex_data->class_set.begin(), dex_data->class_set.end());
ret.insert(classes);
}
@@ -1383,8 +1502,8 @@ bool ProfileCompilationInfo::GenerateTestProfile(int fd,
const std::string base_dex_location = "base.apk";
ProfileCompilationInfo info;
// The limits are defined by the dex specification.
- uint16_t max_method = std::numeric_limits<uint16_t>::max();
- uint16_t max_classes = std::numeric_limits<uint16_t>::max();
+ const uint16_t max_method = std::numeric_limits<uint16_t>::max();
+ const uint16_t max_classes = std::numeric_limits<uint16_t>::max();
uint16_t number_of_methods = max_method * method_ratio / 100;
uint16_t number_of_classes = max_classes * class_ratio / 100;
@@ -1404,7 +1523,7 @@ bool ProfileCompilationInfo::GenerateTestProfile(int fd,
if (m < (number_of_methods / kFavorSplit)) {
method_idx %= kFavorFirstN;
}
- info.AddMethodIndex(profile_key, 0, method_idx);
+ info.AddMethodIndex(profile_key, 0, method_idx, max_method);
}
for (uint16_t c = 0; c < number_of_classes; c++) {
@@ -1412,7 +1531,7 @@ bool ProfileCompilationInfo::GenerateTestProfile(int fd,
if (c < (number_of_classes / kFavorSplit)) {
type_idx %= kFavorFirstN;
}
- info.AddClassIndex(profile_key, 0, dex::TypeIndex(type_idx));
+ info.AddClassIndex(profile_key, 0, dex::TypeIndex(type_idx), max_method);
}
}
return info.Save(fd);
@@ -1431,13 +1550,16 @@ bool ProfileCompilationInfo::GenerateTestProfile(
for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
// Randomly add a class from the dex file (with 50% chance).
if (std::rand() % 2 != 0) {
- info.AddClassIndex(location, checksum, dex::TypeIndex(dex_file->GetClassDef(i).class_idx_));
+ info.AddClassIndex(location,
+ checksum,
+ dex::TypeIndex(dex_file->GetClassDef(i).class_idx_),
+ dex_file->NumMethodIds());
}
}
for (uint32_t i = 0; i < dex_file->NumMethodIds(); ++i) {
// Randomly add a method from the dex file (with 50% chance).
if (std::rand() % 2 != 0) {
- info.AddMethodIndex(location, checksum, i);
+ info.AddMethodIndex(location, checksum, i, dex_file->NumMethodIds());
}
}
}
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
index ca5b28a809..a9f2fb6dd8 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -23,6 +23,7 @@
#include "atomic.h"
#include "base/arena_object.h"
#include "base/arena_containers.h"
+#include "bit_memory_region.h"
#include "dex_cache_resolved_classes.h"
#include "dex_file.h"
#include "dex_file_types.h"
@@ -54,7 +55,9 @@ struct ProfileMethodInfo {
ProfileMethodInfo(const DexFile* dex,
uint32_t method_index,
const std::vector<ProfileInlineCache>& caches)
- : dex_file(dex), dex_method_index(method_index), inline_caches(caches) {}
+ : dex_file(dex),
+ dex_method_index(method_index),
+ inline_caches(caches) {}
const DexFile* dex_file;
const uint32_t dex_method_index;
@@ -79,13 +82,15 @@ class ProfileCompilationInfo {
// A dex location together with its checksum.
struct DexReference {
- DexReference() : dex_checksum(0) {}
+ DexReference() : dex_checksum(0), num_method_ids(0) {}
- DexReference(const std::string& location, uint32_t checksum)
- : dex_location(location), dex_checksum(checksum) {}
+ DexReference(const std::string& location, uint32_t checksum, uint32_t num_methods)
+ : dex_location(location), dex_checksum(checksum), num_method_ids(num_methods) {}
bool operator==(const DexReference& other) const {
- return dex_checksum == other.dex_checksum && dex_location == other.dex_location;
+ return dex_checksum == other.dex_checksum &&
+ dex_location == other.dex_location &&
+ num_method_ids == other.num_method_ids;
}
bool MatchesDex(const DexFile* dex_file) const {
@@ -95,6 +100,7 @@ class ProfileCompilationInfo {
std::string dex_location;
uint32_t dex_checksum;
+ uint32_t num_method_ids;
};
// Encodes a class reference in the profile.
@@ -191,6 +197,24 @@ class ProfileCompilationInfo {
bool AddMethodsAndClasses(const std::vector<ProfileMethodInfo>& methods,
const std::set<DexCacheResolvedClasses>& resolved_classes);
+ // Add a method index to the profile (without inline caches).
+ bool AddMethodIndex(const std::string& dex_location,
+ uint32_t checksum,
+ uint16_t method_idx,
+ uint32_t num_method_ids);
+
+ // Add a method to the profile using its online representation (containing runtime structures).
+ bool AddMethod(const ProfileMethodInfo& pmi);
+
+ // Add methods that have samples but are are not necessarily hot. These are partitioned into two
+ // possibly interesecting sets startup and post startup.
+ bool AddSampledMethods(bool startup, std::vector<MethodReference>& methods);
+ bool AddSampledMethod(bool startup,
+ const std::string& dex_location,
+ uint32_t checksum,
+ uint16_t method_idx,
+ uint32_t num_method_ids);
+
// Load profile information from the given file descriptor.
// If the current profile is non-empty the load will fail.
bool Load(int fd);
@@ -216,8 +240,14 @@ class ProfileCompilationInfo {
// Return the number of resolved classes that were profiled.
uint32_t GetNumberOfResolvedClasses() const;
- // Return true if the method reference is present in the profiling info.
- bool ContainsMethod(const MethodReference& method_ref) const;
+ // Return true if the method reference is a hot or startup method in the profiling info.
+ bool IsStartupOrHotMethod(const MethodReference& method_ref) const;
+ bool IsStartupOrHotMethod(const std::string& dex_location,
+ uint32_t dex_checksum,
+ uint16_t dex_method_index) const;
+
+ // Return true if the method reference iS present and hot in the profiling info.
+ bool ContainsHotMethod(const MethodReference& method_ref) const;
// Return true if the class's type is present in the profiling info.
bool ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const;
@@ -244,7 +274,9 @@ class ProfileCompilationInfo {
// file is register and has a matching checksum, false otherwise.
bool GetClassesAndMethods(const DexFile& dex_file,
/*out*/std::set<dex::TypeIndex>* class_set,
- /*out*/std::set<uint16_t>* method_set) const;
+ /*out*/std::set<uint16_t>* hot_method_set,
+ /*out*/std::set<uint16_t>* startup_method_set,
+ /*out*/std::set<uint16_t>* post_startup_method_method_set) const;
// Perform an equality test with the `other` profile information.
bool Equals(const ProfileCompilationInfo& other);
@@ -301,13 +333,43 @@ class ProfileCompilationInfo {
DexFileData(ArenaAllocator* arena,
const std::string& key,
uint32_t location_checksum,
- uint16_t index)
+ uint16_t index,
+ uint32_t num_methods)
: arena_(arena),
profile_key(key),
profile_index(index),
checksum(location_checksum),
method_map(std::less<uint16_t>(), arena->Adapter(kArenaAllocProfile)),
- class_set(std::less<dex::TypeIndex>(), arena->Adapter(kArenaAllocProfile)) {}
+ class_set(std::less<dex::TypeIndex>(), arena->Adapter(kArenaAllocProfile)),
+ num_method_ids(num_methods),
+ bitmap_storage(arena->Adapter(kArenaAllocProfile)) {
+ const size_t num_bits = num_method_ids * kBitmapCount;
+ bitmap_storage.resize(RoundUp(num_bits, kBitsPerByte) / kBitsPerByte);
+ if (!bitmap_storage.empty()) {
+ method_bitmap =
+ BitMemoryRegion(MemoryRegion(&bitmap_storage[0], bitmap_storage.size()), 0, num_bits);
+ }
+ }
+
+ bool operator==(const DexFileData& other) const {
+ return checksum == other.checksum && method_map == other.method_map;
+ }
+
+ // Mark a method as executed at least once.
+ void AddSampledMethod(bool startup, size_t index) {
+ method_bitmap.StoreBit(MethodBitIndex(startup, index), true);
+ }
+
+ bool HasSampledMethod(bool startup, size_t index) const {
+ return method_bitmap.LoadBit(MethodBitIndex(startup, index));
+ }
+
+ void MergeBitmap(const DexFileData& other) {
+ DCHECK_EQ(bitmap_storage.size(), other.bitmap_storage.size());
+ for (size_t i = 0; i < bitmap_storage.size(); ++i) {
+ bitmap_storage[i] |= other.bitmap_storage[i];
+ }
+ }
// The arena used to allocate new inline cache maps.
ArenaAllocator* arena_;
@@ -322,32 +384,57 @@ class ProfileCompilationInfo {
// The classes which have been profiled. Note that these don't necessarily include
// all the classes that can be found in the inline caches reference.
ArenaSet<dex::TypeIndex> class_set;
-
- bool operator==(const DexFileData& other) const {
- return checksum == other.checksum && method_map == other.method_map;
- }
-
// Find the inline caches of the the given method index. Add an empty entry if
// no previous data is found.
InlineCacheMap* FindOrAddMethod(uint16_t method_index);
+ // Num method ids.
+ uint32_t num_method_ids;
+ ArenaVector<uint8_t> bitmap_storage;
+ BitMemoryRegion method_bitmap;
+
+ private:
+ enum BitmapIndex {
+ kBitmapStartup,
+ kBitmapPostStartup,
+ kBitmapCount,
+ };
+
+ size_t MethodBitIndex(bool startup, size_t index) const {
+ DCHECK_LT(index, num_method_ids);
+ // The format is [startup bitmap][post startup bitmap]
+ // This compresses better than ([startup bit][post statup bit])*
+
+ return index + (startup
+ ? kBitmapStartup * num_method_ids
+ : kBitmapPostStartup * num_method_ids);
+ }
};
// Return the profile data for the given profile key or null if the dex location
// already exists but has a different checksum
- DexFileData* GetOrAddDexFileData(const std::string& profile_key, uint32_t checksum);
+ DexFileData* GetOrAddDexFileData(const std::string& profile_key,
+ uint32_t checksum,
+ uint32_t num_method_ids);
- // Add a method to the profile using its online representation (containing runtime structures).
- bool AddMethod(const ProfileMethodInfo& pmi);
+ DexFileData* GetOrAddDexFileData(const DexFile* dex_file) {
+ return GetOrAddDexFileData(GetProfileDexFileKey(dex_file->GetLocation()),
+ dex_file->GetLocationChecksum(),
+ dex_file->NumMethodIds());
+ }
// Add a method to the profile using its offline representation.
// This is mostly used to facilitate testing.
bool AddMethod(const std::string& dex_location,
uint32_t dex_checksum,
uint16_t method_index,
+ uint32_t num_method_ids,
const OfflineProfileMethodInfo& pmi);
// Add a class index to the profile.
- bool AddClassIndex(const std::string& dex_location, uint32_t checksum, dex::TypeIndex type_idx);
+ bool AddClassIndex(const std::string& dex_location,
+ uint32_t checksum,
+ dex::TypeIndex type_idx,
+ uint32_t num_method_ids);
// Add all classes from the given dex cache to the the profile.
bool AddResolvedClasses(const DexCacheResolvedClasses& classes);
@@ -392,6 +479,7 @@ class ProfileCompilationInfo {
uint16_t class_set_size;
uint32_t method_region_size_bytes;
uint32_t checksum;
+ uint32_t num_method_ids;
};
// A helper structure to make sure we don't read past our buffers in the loops.
diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc
index 1cfa3552b9..39670afb0c 100644
--- a/runtime/jit/profile_compilation_info_test.cc
+++ b/runtime/jit/profile_compilation_info_test.cc
@@ -32,6 +32,8 @@
namespace art {
+static constexpr size_t kMaxMethodIds = 65535;
+
class ProfileCompilationInfoTest : public CommonRuntimeTest {
public:
void PostRuntimeCreate() OVERRIDE {
@@ -61,7 +63,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest {
uint32_t checksum,
uint16_t method_index,
ProfileCompilationInfo* info) {
- return info->AddMethodIndex(dex_location, checksum, method_index);
+ return info->AddMethodIndex(dex_location, checksum, method_index, kMaxMethodIds);
}
bool AddMethod(const std::string& dex_location,
@@ -69,14 +71,14 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest {
uint16_t method_index,
const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi,
ProfileCompilationInfo* info) {
- return info->AddMethod(dex_location, checksum, method_index, pmi);
+ return info->AddMethod(dex_location, checksum, method_index, kMaxMethodIds, pmi);
}
bool AddClass(const std::string& dex_location,
uint32_t checksum,
uint16_t class_index,
ProfileCompilationInfo* info) {
- return info->AddMethodIndex(dex_location, checksum, class_index);
+ return info->AddMethodIndex(dex_location, checksum, class_index, kMaxMethodIds);
}
uint32_t GetFd(const ScratchFile& file) {
@@ -149,7 +151,9 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest {
std::vector<TypeReference> classes;
caches.emplace_back(dex_pc, /*is_missing_types*/true, classes);
}
- ProfileMethodInfo pmi(method->GetDexFile(), method->GetDexMethodIndex(), caches);
+ ProfileMethodInfo pmi(method->GetDexFile(),
+ method->GetDexMethodIndex(),
+ caches);
profile_methods.push_back(pmi);
profile_methods_map->Put(method, pmi);
}
@@ -191,7 +195,8 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest {
const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey(
class_ref.dex_file->GetLocation());
offline_pmi.dex_references.emplace_back(dex_key,
- class_ref.dex_file->GetLocationChecksum());
+ class_ref.dex_file->GetLocationChecksum(),
+ class_ref.dex_file->NumMethodIds());
}
}
}
@@ -201,6 +206,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest {
// Creates an offline profile used for testing inline caches.
ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo() {
ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
+
// Monomorphic
for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
@@ -231,9 +237,9 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest {
ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
- pmi.dex_references.emplace_back("dex_location1", /* checksum */1);
- pmi.dex_references.emplace_back("dex_location2", /* checksum */2);
- pmi.dex_references.emplace_back("dex_location3", /* checksum */3);
+ pmi.dex_references.emplace_back("dex_location1", /* checksum */1, kMaxMethodIds);
+ pmi.dex_references.emplace_back("dex_location2", /* checksum */2, kMaxMethodIds);
+ pmi.dex_references.emplace_back("dex_location3", /* checksum */3, kMaxMethodIds);
return pmi;
}
@@ -292,7 +298,8 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethods) {
{
ScopedObjectAccess soa(self);
for (ArtMethod* m : main_methods) {
- ASSERT_TRUE(info1.ContainsMethod(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())));
+ ASSERT_TRUE(info1.ContainsHotMethod(
+ MethodReference(m->GetDexFile(), m->GetDexMethodIndex())));
}
}
@@ -308,10 +315,12 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethods) {
{
ScopedObjectAccess soa(self);
for (ArtMethod* m : main_methods) {
- ASSERT_TRUE(info2.ContainsMethod(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())));
+ ASSERT_TRUE(
+ info2.ContainsHotMethod(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())));
}
for (ArtMethod* m : second_methods) {
- ASSERT_TRUE(info2.ContainsMethod(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())));
+ ASSERT_TRUE(
+ info2.ContainsHotMethod(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())));
}
}
}
@@ -657,7 +666,8 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) {
{
ScopedObjectAccess soa(self);
for (ArtMethod* m : main_methods) {
- ASSERT_TRUE(info.ContainsMethod(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())));
+ ASSERT_TRUE(
+ info.ContainsHotMethod(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())));
const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second;
std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi =
info.GetMethod(m->GetDexFile()->GetLocation(),
@@ -694,8 +704,8 @@ TEST_F(ProfileCompilationInfoTest, MergeInlineCacheTriggerReindex) {
ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
- pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1);
- pmi.dex_references.emplace_back("dex_location2", /* checksum */ 2);
+ pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
+ pmi.dex_references.emplace_back("dex_location2", /* checksum */ 2, kMaxMethodIds);
for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
dex_pc_data.AddClass(0, dex::TypeIndex(0));
@@ -705,8 +715,8 @@ TEST_F(ProfileCompilationInfoTest, MergeInlineCacheTriggerReindex) {
ProfileCompilationInfo::InlineCacheMap* ic_map_reindexed = CreateInlineCacheMap();
ProfileCompilationInfo::OfflineProfileMethodInfo pmi_reindexed(ic_map_reindexed);
- pmi_reindexed.dex_references.emplace_back("dex_location2", /* checksum */ 2);
- pmi_reindexed.dex_references.emplace_back("dex_location1", /* checksum */ 1);
+ pmi_reindexed.dex_references.emplace_back("dex_location2", /* checksum */ 2, kMaxMethodIds);
+ pmi_reindexed.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
for (uint16_t dex_pc = 1; dex_pc < 5; dex_pc++) {
ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
dex_pc_data.AddClass(1, dex::TypeIndex(0));
@@ -761,7 +771,7 @@ TEST_F(ProfileCompilationInfoTest, MegamorphicInlineCachesMerge) {
// Create a megamorphic inline cache.
ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
- pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1);
+ pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
dex_pc_data.SetIsMegamorphic();
ic_map->Put(/*dex_pc*/ 0, dex_pc_data);
@@ -791,7 +801,7 @@ TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCachesMerge) {
// Create an inline cache with missing types
ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap();
ProfileCompilationInfo::OfflineProfileMethodInfo pmi(ic_map);
- pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1);
+ pmi.dex_references.emplace_back("dex_location1", /* checksum */ 1, kMaxMethodIds);
ProfileCompilationInfo::DexPcData dex_pc_data(arena_.get());
dex_pc_data.SetIsMissingTypes();
ic_map->Put(/*dex_pc*/ 0, dex_pc_data);
@@ -839,4 +849,48 @@ TEST_F(ProfileCompilationInfoTest, LoadShouldClearExistingDataFromProfiles) {
// This should fail since the test_info already contains data and the load would overwrite it.
ASSERT_FALSE(test_info.Load(GetFd(profile)));
}
+
+TEST_F(ProfileCompilationInfoTest, SampledMethodsTest) {
+ ProfileCompilationInfo test_info;
+ static constexpr size_t kNumMethods = 1000;
+ static constexpr size_t kChecksum1 = 1234;
+ static constexpr size_t kChecksum2 = 4321;
+ static const std::string kDex1 = "dex1";
+ static const std::string kDex2 = "dex2";
+ test_info.AddSampledMethod(true, kDex1, kChecksum1, 1, kNumMethods);
+ test_info.AddSampledMethod(true, kDex1, kChecksum1, 5, kNumMethods);
+ test_info.AddSampledMethod(false, kDex2, kChecksum2, 1, kNumMethods);
+ test_info.AddSampledMethod(false, kDex2, kChecksum2, 5, kNumMethods);
+ auto run_test = [](const ProfileCompilationInfo& info) {
+ EXPECT_FALSE(info.IsStartupOrHotMethod(kDex1, kChecksum1, 0));
+ EXPECT_TRUE(info.IsStartupOrHotMethod(kDex1, kChecksum1, 1));
+ EXPECT_FALSE(info.IsStartupOrHotMethod(kDex1, kChecksum1, 3));
+ EXPECT_TRUE(info.IsStartupOrHotMethod(kDex1, kChecksum1, 5));
+ EXPECT_FALSE(info.IsStartupOrHotMethod(kDex1, kChecksum1, 6));
+ EXPECT_FALSE(info.IsStartupOrHotMethod(kDex2, kChecksum2, 5));
+ EXPECT_FALSE(info.IsStartupOrHotMethod(kDex2, kChecksum2, 5));
+ };
+ run_test(test_info);
+
+ // Save the profile.
+ ScratchFile profile;
+ ASSERT_TRUE(test_info.Save(GetFd(profile)));
+ ASSERT_EQ(0, profile.GetFile()->Flush());
+ ASSERT_TRUE(profile.GetFile()->ResetOffset());
+
+ // Load the profile and make sure we can read the data and it matches what we expect.
+ ProfileCompilationInfo loaded_info;
+ ASSERT_TRUE(loaded_info.Load(GetFd(profile)));
+ run_test(loaded_info);
+
+ // Test that the bitmap gets merged properly.
+ EXPECT_FALSE(test_info.IsStartupOrHotMethod(kDex1, kChecksum1, 11));
+ {
+ ProfileCompilationInfo merge_info;
+ merge_info.AddSampledMethod(true, kDex1, kChecksum1, 11, kNumMethods);
+ test_info.MergeWith(merge_info);
+ }
+ EXPECT_TRUE(test_info.IsStartupOrHotMethod(kDex1, kChecksum1, 11));
+}
+
} // namespace art
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index bc829cf9a7..6128d82e24 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -183,32 +183,41 @@ void ProfileSaver::NotifyJitActivityInternal() {
// Excludes native methods and classes in the boot image.
class GetMethodsVisitor : public ClassVisitor {
public:
- GetMethodsVisitor(std::vector<MethodReference>* methods, uint32_t startup_method_samples)
- : methods_(methods),
- startup_method_samples_(startup_method_samples) {}
+ GetMethodsVisitor(std::vector<MethodReference>* hot_methods,
+ std::vector<MethodReference>* sampled_methods,
+ uint32_t hot_method_sample_threshold)
+ : hot_methods_(hot_methods),
+ sampled_methods_(sampled_methods),
+ hot_method_sample_threshold_(hot_method_sample_threshold) {}
virtual bool operator()(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) {
return true;
}
for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
- if (!method.IsNative()) {
- if (method.GetCounter() >= startup_method_samples_ ||
- method.GetProfilingInfo(kRuntimePointerSize) != nullptr ||
- (method.GetAccessFlags() & kAccPreviouslyWarm) != 0) {
- // Have samples, add to profile.
- const DexFile* dex_file =
- method.GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetDexFile();
- methods_->push_back(MethodReference(dex_file, method.GetDexMethodIndex()));
+ if (!method.IsNative() && !method.IsProxyMethod()) {
+ const uint16_t counter = method.GetCounter();
+ MethodReference ref(method.GetDexFile(), method.GetDexMethodIndex());
+ // Mark startup methods as hot if they have more than hot_method_sample_threshold_ samples.
+ // This means they will get compiled by the compiler driver.
+ if (method.GetProfilingInfo(kRuntimePointerSize) != nullptr ||
+ (method.GetAccessFlags() & kAccPreviouslyWarm) != 0 ||
+ counter >= hot_method_sample_threshold_) {
+ hot_methods_->push_back(ref);
+ } else if (counter != 0) {
+ sampled_methods_->push_back(ref);
}
+ } else {
+ CHECK_EQ(method.GetCounter(), 0u);
}
}
return true;
}
private:
- std::vector<MethodReference>* const methods_;
- uint32_t startup_method_samples_;
+ std::vector<MethodReference>* const hot_methods_;
+ std::vector<MethodReference>* const sampled_methods_;
+ uint32_t hot_method_sample_threshold_;
};
void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
@@ -218,7 +227,8 @@ void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
ResolveTrackedLocations();
Thread* const self = Thread::Current();
- std::vector<MethodReference> methods;
+ std::vector<MethodReference> hot_methods;
+ std::vector<MethodReference> startup_methods;
std::set<DexCacheResolvedClasses> resolved_classes;
{
ScopedObjectAccess soa(self);
@@ -231,10 +241,13 @@ void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
{
ScopedTrace trace2("Get hot methods");
- GetMethodsVisitor visitor(&methods, options_.GetStartupMethodSamples());
+ GetMethodsVisitor visitor(&hot_methods,
+ &startup_methods,
+ options_.GetHotStartupMethodSamples());
class_linker->VisitClasses(&visitor);
- VLOG(profiler) << "Methods with samples greater than "
- << options_.GetStartupMethodSamples() << " = " << methods.size();
+ VLOG(profiler) << "Profile saver recorded " << hot_methods.size() << " hot methods and "
+ << startup_methods.size() << " startup methods with threshold "
+ << options_.GetHotStartupMethodSamples();
}
}
MutexLock mu(self, *Locks::profiler_lock_);
@@ -245,11 +258,20 @@ void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
const std::string& filename = it.first;
const std::set<std::string>& locations = it.second;
std::vector<ProfileMethodInfo> profile_methods_for_location;
- for (const MethodReference& ref : methods) {
+ std::vector<MethodReference> startup_methods_for_locations;
+ for (const MethodReference& ref : hot_methods) {
if (locations.find(ref.dex_file->GetBaseLocation()) != locations.end()) {
profile_methods_for_location.emplace_back(ref.dex_file, ref.dex_method_index);
+ // Hot methods are also startup methods since this function is only invoked during startup.
+ startup_methods_for_locations.push_back(ref);
}
}
+ for (const MethodReference& ref : startup_methods) {
+ if (locations.find(ref.dex_file->GetBaseLocation()) != locations.end()) {
+ startup_methods_for_locations.push_back(ref);
+ }
+ }
+
for (const DexCacheResolvedClasses& classes : resolved_classes) {
if (locations.find(classes.GetBaseLocation()) != locations.end()) {
VLOG(profiler) << "Added " << classes.GetClasses().size() << " classes for location "
@@ -265,8 +287,8 @@ void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
new ProfileCompilationInfo(Runtime::Current()->GetArenaPool()));
ProfileCompilationInfo* cached_info = info_it->second;
- cached_info->AddMethodsAndClasses(profile_methods_for_location,
- resolved_classes_for_location);
+ cached_info->AddMethodsAndClasses(profile_methods_for_location, resolved_classes_for_location);
+ cached_info->AddSampledMethods(/*startup*/ true, startup_methods_for_locations);
total_number_of_profile_entries_cached += resolved_classes_for_location.size();
}
max_number_of_profile_entries_cached_ = std::max(
@@ -317,8 +339,7 @@ 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.AddMethodsAndClasses(profile_methods,
- std::set<DexCacheResolvedClasses>());
+ info.AddMethodsAndClasses(profile_methods, std::set<DexCacheResolvedClasses>());
auto profile_cache_it = profile_cache_.find(filename);
if (profile_cache_it != profile_cache_.end()) {
info.MergeWith(*(profile_cache_it->second));
@@ -601,7 +622,7 @@ bool ProfileSaver::HasSeenMethod(const std::string& profile,
if (!info.Load(profile, /*clear_if_invalid*/false)) {
return false;
}
- return info.ContainsMethod(MethodReference(dex_file, method_idx));
+ return info.ContainsHotMethod(MethodReference(dex_file, method_idx));
}
return false;
}
diff --git a/runtime/jit/profile_saver_options.h b/runtime/jit/profile_saver_options.h
index 07aeb66eb6..455bc1aae4 100644
--- a/runtime/jit/profile_saver_options.h
+++ b/runtime/jit/profile_saver_options.h
@@ -22,8 +22,8 @@ struct ProfileSaverOptions {
public:
static constexpr uint32_t kMinSavePeriodMs = 40 * 1000; // 40 seconds
static constexpr uint32_t kSaveResolvedClassesDelayMs = 5 * 1000; // 5 seconds
- // Minimum number of JIT samples during launch to include a method into the profile.
- static constexpr uint32_t kStartupMethodSamples = 1;
+ // Minimum number of JIT samples during launch to mark a method as hot in the profile.
+ static constexpr uint32_t kHotStartupMethodSamples = 1;
static constexpr uint32_t kMinMethodsToSave = 10;
static constexpr uint32_t kMinClassesToSave = 10;
static constexpr uint32_t kMinNotificationBeforeWake = 10;
@@ -33,7 +33,7 @@ struct ProfileSaverOptions {
enabled_(false),
min_save_period_ms_(kMinSavePeriodMs),
save_resolved_classes_delay_ms_(kSaveResolvedClassesDelayMs),
- startup_method_samples_(kStartupMethodSamples),
+ hot_startup_method_samples_(kHotStartupMethodSamples),
min_methods_to_save_(kMinMethodsToSave),
min_classes_to_save_(kMinClassesToSave),
min_notification_before_wake_(kMinNotificationBeforeWake),
@@ -44,7 +44,7 @@ struct ProfileSaverOptions {
bool enabled,
uint32_t min_save_period_ms,
uint32_t save_resolved_classes_delay_ms,
- uint32_t startup_method_samples,
+ uint32_t hot_startup_method_samples,
uint32_t min_methods_to_save,
uint32_t min_classes_to_save,
uint32_t min_notification_before_wake,
@@ -53,7 +53,7 @@ struct ProfileSaverOptions {
enabled_(enabled),
min_save_period_ms_(min_save_period_ms),
save_resolved_classes_delay_ms_(save_resolved_classes_delay_ms),
- startup_method_samples_(startup_method_samples),
+ hot_startup_method_samples_(hot_startup_method_samples),
min_methods_to_save_(min_methods_to_save),
min_classes_to_save_(min_classes_to_save),
min_notification_before_wake_(min_notification_before_wake),
@@ -73,8 +73,8 @@ struct ProfileSaverOptions {
uint32_t GetSaveResolvedClassesDelayMs() const {
return save_resolved_classes_delay_ms_;
}
- uint32_t GetStartupMethodSamples() const {
- return startup_method_samples_;
+ uint32_t GetHotStartupMethodSamples() const {
+ return hot_startup_method_samples_;
}
uint32_t GetMinMethodsToSave() const {
return min_methods_to_save_;
@@ -96,7 +96,7 @@ struct ProfileSaverOptions {
os << "enabled_" << pso.enabled_
<< ", min_save_period_ms_" << pso.min_save_period_ms_
<< ", save_resolved_classes_delay_ms_" << pso.save_resolved_classes_delay_ms_
- << ", startup_method_samples_" << pso.startup_method_samples_
+ << ", hot_startup_method_samples_" << pso.hot_startup_method_samples_
<< ", min_methods_to_save_" << pso.min_methods_to_save_
<< ", min_classes_to_save_" << pso.min_classes_to_save_
<< ", min_notification_before_wake_" << pso.min_notification_before_wake_
@@ -107,7 +107,7 @@ struct ProfileSaverOptions {
bool enabled_;
uint32_t min_save_period_ms_;
uint32_t save_resolved_classes_delay_ms_;
- uint32_t startup_method_samples_;
+ uint32_t hot_startup_method_samples_;
uint32_t min_methods_to_save_;
uint32_t min_classes_to_save_;
uint32_t min_notification_before_wake_;
diff --git a/runtime/jni_env_ext.cc b/runtime/jni_env_ext.cc
index 0148a1c3b0..3ff94f995d 100644
--- a/runtime/jni_env_ext.cc
+++ b/runtime/jni_env_ext.cc
@@ -28,7 +28,7 @@
#include "lock_word.h"
#include "mirror/object-inl.h"
#include "nth_caller_visitor.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
namespace art {
@@ -123,8 +123,8 @@ void JNIEnvExt::DumpReferenceTables(std::ostream& os) {
monitors.Dump(os);
}
-void JNIEnvExt::PushFrame(int capacity ATTRIBUTE_UNUSED) {
- // TODO: take 'capacity' into account.
+void JNIEnvExt::PushFrame(int capacity) {
+ DCHECK_GE(locals.FreeCapacity(), static_cast<size_t>(capacity));
stacked_local_ref_cookies.push_back(local_ref_cookie);
local_ref_cookie = locals.GetSegmentState();
}
diff --git a/runtime/jni_env_ext.h b/runtime/jni_env_ext.h
index 60e4295e40..af933ae835 100644
--- a/runtime/jni_env_ext.h
+++ b/runtime/jni_env_ext.h
@@ -22,7 +22,6 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "indirect_reference_table.h"
-#include "object_callbacks.h"
#include "obj_ptr.h"
#include "reference_table.h"
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 0fde41bd4f..6be0953727 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -106,10 +106,9 @@ static void ThrowNoSuchMethodError(ScopedObjectAccess& soa,
static void ReportInvalidJNINativeMethod(const ScopedObjectAccess& soa,
ObjPtr<mirror::Class> c,
const char* kind,
- jint idx,
- bool return_errors)
+ jint idx)
REQUIRES_SHARED(Locks::mutator_lock_) {
- LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL)
+ LOG(ERROR)
<< "Failed to register native method in " << c->PrettyDescriptor()
<< " in " << c->GetDexCache()->GetLocation()->ToModifiedUtf8()
<< ": " << kind << " is null at index " << idx;
@@ -2145,13 +2144,10 @@ class JNI {
buf);
}
- static jint RegisterNatives(JNIEnv* env, jclass java_class, const JNINativeMethod* methods,
+ static jint RegisterNatives(JNIEnv* env,
+ jclass java_class,
+ const JNINativeMethod* methods,
jint method_count) {
- return RegisterNativeMethods(env, java_class, methods, method_count, true);
- }
-
- static jint RegisterNativeMethods(JNIEnv* env, jclass java_class, const JNINativeMethod* methods,
- jint method_count, bool return_errors) {
if (UNLIKELY(method_count < 0)) {
JavaVmExtFromEnv(env)->JniAbortF("RegisterNatives", "negative method count: %d",
method_count);
@@ -2172,13 +2168,13 @@ class JNI {
const char* sig = methods[i].signature;
const void* fnPtr = methods[i].fnPtr;
if (UNLIKELY(name == nullptr)) {
- ReportInvalidJNINativeMethod(soa, c.Get(), "method name", i, return_errors);
+ ReportInvalidJNINativeMethod(soa, c.Get(), "method name", i);
return JNI_ERR;
} else if (UNLIKELY(sig == nullptr)) {
- ReportInvalidJNINativeMethod(soa, c.Get(), "method signature", i, return_errors);
+ ReportInvalidJNINativeMethod(soa, c.Get(), "method signature", i);
return JNI_ERR;
} else if (UNLIKELY(fnPtr == nullptr)) {
- ReportInvalidJNINativeMethod(soa, c.Get(), "native function", i, return_errors);
+ ReportInvalidJNINativeMethod(soa, c.Get(), "native function", i);
return JNI_ERR;
}
bool is_fast = false;
@@ -2244,19 +2240,15 @@ class JNI {
}
if (m == nullptr) {
- c->DumpClass(
- LOG_STREAM(return_errors
- ? ::android::base::ERROR
- : ::android::base::FATAL_WITHOUT_ABORT),
- mirror::Class::kDumpClassFullDetail);
- LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL)
+ c->DumpClass(LOG_STREAM(ERROR), mirror::Class::kDumpClassFullDetail);
+ LOG(ERROR)
<< "Failed to register native method "
<< c->PrettyDescriptor() << "." << name << sig << " in "
<< c->GetDexCache()->GetLocation()->ToModifiedUtf8();
ThrowNoSuchMethodError(soa, c.Get(), name, sig, "static or non-static");
return JNI_ERR;
} else if (!m->IsNative()) {
- LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL)
+ LOG(ERROR)
<< "Failed to register non-native method "
<< c->PrettyDescriptor() << "." << name << sig
<< " as native";
@@ -2407,18 +2399,18 @@ class JNI {
static jint EnsureLocalCapacityInternal(ScopedObjectAccess& soa, jint desired_capacity,
const char* caller)
REQUIRES_SHARED(Locks::mutator_lock_) {
- // TODO: we should try to expand the table if necessary.
- if (desired_capacity < 0 || desired_capacity > static_cast<jint>(kLocalsInitial)) {
+ if (desired_capacity < 0) {
LOG(ERROR) << "Invalid capacity given to " << caller << ": " << desired_capacity;
return JNI_ERR;
}
- // TODO: this isn't quite right, since "capacity" includes holes.
- const size_t capacity = soa.Env()->locals.Capacity();
- bool okay = (static_cast<jint>(kLocalsInitial - capacity) >= desired_capacity);
- if (!okay) {
- soa.Self()->ThrowOutOfMemoryError(caller);
+
+ std::string error_msg;
+ if (!soa.Env()->locals.EnsureFreeCapacity(static_cast<size_t>(desired_capacity), &error_msg)) {
+ std::string caller_error = android::base::StringPrintf("%s: %s", caller, error_msg.c_str());
+ soa.Self()->ThrowOutOfMemoryError(caller_error.c_str());
+ return JNI_ERR;
}
- return okay ? JNI_OK : JNI_ERR;
+ return JNI_OK;
}
template<typename JniT, typename ArtT>
@@ -3051,16 +3043,6 @@ const JNINativeInterface* GetRuntimeShutdownNativeInterface() {
return reinterpret_cast<JNINativeInterface*>(&gJniSleepForeverStub);
}
-void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods,
- jint method_count) {
- ScopedLocalRef<jclass> c(env, env->FindClass(jni_class_name));
- if (c.get() == nullptr) {
- LOG(FATAL) << "Couldn't find class: " << jni_class_name;
- }
- jint jni_result = env->RegisterNatives(c.get(), methods, method_count);
- CHECK_EQ(JNI_OK, jni_result);
-}
-
} // namespace art
std::ostream& operator<<(std::ostream& os, const jobjectRefType& rhs) {
diff --git a/runtime/jni_internal.h b/runtime/jni_internal.h
index 24bee6fb1d..2c90b3ba78 100644
--- a/runtime/jni_internal.h
+++ b/runtime/jni_internal.h
@@ -22,9 +22,6 @@
#include "base/macros.h"
-#define REGISTER_NATIVE_METHODS(jni_class_name) \
- RegisterNativeMethods(env, jni_class_name, gMethods, arraysize(gMethods))
-
namespace art {
class ArtField;
@@ -33,11 +30,6 @@ class ArtMethod;
const JNINativeInterface* GetJniNativeInterface();
const JNINativeInterface* GetRuntimeShutdownNativeInterface();
-// Similar to RegisterNatives except its passed a descriptor for a class name and failures are
-// fatal.
-void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods,
- jint method_count);
-
int ThrowNewException(JNIEnv* env, jclass exception_class, const char* msg, jobject cause);
namespace jni {
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 08d1eeb95d..e1e4f9c7d6 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -1908,9 +1908,6 @@ TEST_F(JniInternalTest, PushLocalFrame_10395422) {
// Negative capacities are not allowed.
ASSERT_EQ(JNI_ERR, env_->PushLocalFrame(-1));
-
- // And it's okay to have an upper limit. Ours is currently 512.
- ASSERT_EQ(JNI_ERR, env_->PushLocalFrame(8192));
}
TEST_F(JniInternalTest, PushLocalFrame_PopLocalFrame) {
@@ -1962,6 +1959,28 @@ TEST_F(JniInternalTest, PushLocalFrame_PopLocalFrame) {
check_jni_abort_catcher.Check("use of deleted local reference");
}
+TEST_F(JniInternalTest, PushLocalFrame_LimitAndOverflow) {
+ // Try a very large value that should fail.
+ ASSERT_NE(JNI_OK, env_->PushLocalFrame(std::numeric_limits<jint>::max()));
+ ASSERT_TRUE(env_->ExceptionCheck());
+ env_->ExceptionClear();
+
+ // On 32-bit, also check for some overflow conditions.
+#ifndef __LP64__
+ ASSERT_EQ(JNI_OK, env_->PushLocalFrame(10));
+ ASSERT_NE(JNI_OK, env_->PushLocalFrame(std::numeric_limits<jint>::max() - 10));
+ ASSERT_TRUE(env_->ExceptionCheck());
+ env_->ExceptionClear();
+ EXPECT_EQ(env_->PopLocalFrame(nullptr), nullptr);
+#endif
+}
+
+TEST_F(JniInternalTest, PushLocalFrame_b62223672) {
+ // The 512 entry limit has been lifted, try a larger value.
+ ASSERT_EQ(JNI_OK, env_->PushLocalFrame(1024));
+ EXPECT_EQ(env_->PopLocalFrame(nullptr), nullptr);
+}
+
TEST_F(JniInternalTest, NewGlobalRef_nullptr) {
EXPECT_EQ(env_->NewGlobalRef(nullptr), nullptr);
}
diff --git a/runtime/linear_alloc.cc b/runtime/linear_alloc.cc
index e9db9b8b4c..3f01fc329a 100644
--- a/runtime/linear_alloc.cc
+++ b/runtime/linear_alloc.cc
@@ -16,7 +16,7 @@
#include "linear_alloc.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/managed_stack-inl.h b/runtime/managed_stack-inl.h
new file mode 100644
index 0000000000..f3f31cf8e8
--- /dev/null
+++ b/runtime/managed_stack-inl.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_MANAGED_STACK_INL_H_
+#define ART_RUNTIME_MANAGED_STACK_INL_H_
+
+#include "managed_stack.h"
+
+#include <cstring>
+#include <stdint.h>
+#include <string>
+
+#include "stack.h"
+
+namespace art {
+
+inline ShadowFrame* ManagedStack::PushShadowFrame(ShadowFrame* new_top_frame) {
+ DCHECK(top_quick_frame_ == nullptr);
+ ShadowFrame* old_frame = top_shadow_frame_;
+ top_shadow_frame_ = new_top_frame;
+ new_top_frame->SetLink(old_frame);
+ return old_frame;
+}
+
+inline ShadowFrame* ManagedStack::PopShadowFrame() {
+ DCHECK(top_quick_frame_ == nullptr);
+ CHECK(top_shadow_frame_ != nullptr);
+ ShadowFrame* frame = top_shadow_frame_;
+ top_shadow_frame_ = frame->GetLink();
+ return frame;
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_MANAGED_STACK_INL_H_
diff --git a/runtime/managed_stack.cc b/runtime/managed_stack.cc
new file mode 100644
index 0000000000..be609c325d
--- /dev/null
+++ b/runtime/managed_stack.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "managed_stack-inl.h"
+
+#include "android-base/stringprintf.h"
+
+#include "art_method.h"
+#include "mirror/object.h"
+#include "stack_reference.h"
+
+namespace art {
+
+size_t ManagedStack::NumJniShadowFrameReferences() const {
+ size_t count = 0;
+ for (const ManagedStack* current_fragment = this; current_fragment != nullptr;
+ current_fragment = current_fragment->GetLink()) {
+ for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_;
+ current_frame != nullptr;
+ current_frame = current_frame->GetLink()) {
+ if (current_frame->GetMethod()->IsNative()) {
+ // The JNI ShadowFrame only contains references. (For indirect reference.)
+ count += current_frame->NumberOfVRegs();
+ }
+ }
+ }
+ return count;
+}
+
+bool ManagedStack::ShadowFramesContain(StackReference<mirror::Object>* shadow_frame_entry) const {
+ for (const ManagedStack* current_fragment = this; current_fragment != nullptr;
+ current_fragment = current_fragment->GetLink()) {
+ for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_;
+ current_frame != nullptr;
+ current_frame = current_frame->GetLink()) {
+ if (current_frame->Contains(shadow_frame_entry)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+} // namespace art
diff --git a/runtime/managed_stack.h b/runtime/managed_stack.h
new file mode 100644
index 0000000000..8337f968ac
--- /dev/null
+++ b/runtime/managed_stack.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_MANAGED_STACK_H_
+#define ART_RUNTIME_MANAGED_STACK_H_
+
+#include <cstring>
+#include <stdint.h>
+#include <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+
+namespace art {
+
+namespace mirror {
+class Object;
+} // namespace mirror
+
+class ArtMethod;
+class ShadowFrame;
+template <typename T> class StackReference;
+
+// The managed stack is used to record fragments of managed code stacks. Managed code stacks
+// may either be shadow frames or lists of frames using fixed frame sizes. Transition records are
+// necessary for transitions between code using different frame layouts and transitions into native
+// code.
+class PACKED(4) ManagedStack {
+ public:
+ ManagedStack()
+ : top_quick_frame_(nullptr), link_(nullptr), top_shadow_frame_(nullptr) {}
+
+ void PushManagedStackFragment(ManagedStack* fragment) {
+ // Copy this top fragment into given fragment.
+ memcpy(fragment, this, sizeof(ManagedStack));
+ // Clear this fragment, which has become the top.
+ memset(this, 0, sizeof(ManagedStack));
+ // Link our top fragment onto the given fragment.
+ link_ = fragment;
+ }
+
+ void PopManagedStackFragment(const ManagedStack& fragment) {
+ DCHECK(&fragment == link_);
+ // Copy this given fragment back to the top.
+ memcpy(this, &fragment, sizeof(ManagedStack));
+ }
+
+ ManagedStack* GetLink() const {
+ return link_;
+ }
+
+ ArtMethod** GetTopQuickFrame() const {
+ return top_quick_frame_;
+ }
+
+ void SetTopQuickFrame(ArtMethod** top) {
+ DCHECK(top_shadow_frame_ == nullptr);
+ top_quick_frame_ = top;
+ }
+
+ static size_t TopQuickFrameOffset() {
+ return OFFSETOF_MEMBER(ManagedStack, top_quick_frame_);
+ }
+
+ ALWAYS_INLINE ShadowFrame* PushShadowFrame(ShadowFrame* new_top_frame);
+ ALWAYS_INLINE ShadowFrame* PopShadowFrame();
+
+ ShadowFrame* GetTopShadowFrame() const {
+ return top_shadow_frame_;
+ }
+
+ void SetTopShadowFrame(ShadowFrame* top) {
+ DCHECK(top_quick_frame_ == nullptr);
+ top_shadow_frame_ = top;
+ }
+
+ static size_t TopShadowFrameOffset() {
+ return OFFSETOF_MEMBER(ManagedStack, top_shadow_frame_);
+ }
+
+ size_t NumJniShadowFrameReferences() const REQUIRES_SHARED(Locks::mutator_lock_);
+
+ bool ShadowFramesContain(StackReference<mirror::Object>* shadow_frame_entry) const;
+
+ private:
+ ArtMethod** top_quick_frame_;
+ ManagedStack* link_;
+ ShadowFrame* top_shadow_frame_;
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_MANAGED_STACK_H_
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 6c39361e24..12793e433e 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -952,6 +952,9 @@ void MemMap::TryReadable() {
}
void ZeroAndReleasePages(void* address, size_t length) {
+ if (length == 0) {
+ return;
+ }
uint8_t* const mem_begin = reinterpret_cast<uint8_t*>(address);
uint8_t* const mem_end = mem_begin + length;
uint8_t* const page_begin = AlignUp(mem_begin, kPageSize);
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index e8a2dce42e..e02e62052c 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -23,6 +23,7 @@
#include "handle.h"
#include "jvalue.h"
#include "mirror/class.h"
+#include "stack.h"
namespace art {
diff --git a/runtime/mirror/accessible_object.h b/runtime/mirror/accessible_object.h
index 2581ac214f..a217193522 100644
--- a/runtime/mirror/accessible_object.h
+++ b/runtime/mirror/accessible_object.h
@@ -20,7 +20,6 @@
#include "class.h"
#include "gc_root.h"
#include "object.h"
-#include "object_callbacks.h"
#include "read_barrier_option.h"
#include "thread.h"
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 51d9d24619..7287a92fa5 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -22,7 +22,6 @@
#include "gc/allocator_type.h"
#include "obj_ptr.h"
#include "object.h"
-#include "object_callbacks.h"
namespace art {
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 5122b37aa6..c8d455711d 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -23,13 +23,14 @@
#include "art_method.h"
#include "base/array_slice.h"
#include "base/length_prefixed_array.h"
-#include "class_linker-inl.h"
+#include "class_linker.h"
#include "class_loader.h"
#include "common_throws.h"
+#include "dex_cache.h"
#include "dex_file-inl.h"
#include "gc/heap-inl.h"
#include "iftable.h"
-#include "object_array-inl.h"
+#include "object_array.h"
#include "object-inl.h"
#include "read_barrier-inl.h"
#include "reference-inl.h"
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index dfb2788c51..dfdd16240b 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -29,7 +29,6 @@
#include "modifiers.h"
#include "object.h"
#include "object_array.h"
-#include "object_callbacks.h"
#include "primitive.h"
#include "read_barrier_option.h"
#include "stride_iterator.h"
diff --git a/runtime/mirror/class_ext.h b/runtime/mirror/class_ext.h
index 708665d46b..75a3800989 100644
--- a/runtime/mirror/class_ext.h
+++ b/runtime/mirror/class_ext.h
@@ -23,7 +23,6 @@
#include "gc_root.h"
#include "object.h"
#include "object_array.h"
-#include "object_callbacks.h"
#include "string.h"
namespace art {
diff --git a/runtime/mirror/class_loader-inl.h b/runtime/mirror/class_loader-inl.h
index f5ecdaea26..39c8ee0d60 100644
--- a/runtime/mirror/class_loader-inl.h
+++ b/runtime/mirror/class_loader-inl.h
@@ -19,9 +19,7 @@
#include "class_loader.h"
-#include "base/mutex-inl.h"
#include "class_table-inl.h"
-#include "obj_ptr-inl.h"
namespace art {
namespace mirror {
diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h
index 6e1f44bb46..381d96b541 100644
--- a/runtime/mirror/class_loader.h
+++ b/runtime/mirror/class_loader.h
@@ -17,7 +17,10 @@
#ifndef ART_RUNTIME_MIRROR_CLASS_LOADER_H_
#define ART_RUNTIME_MIRROR_CLASS_LOADER_H_
+#include "base/mutex.h"
#include "object.h"
+#include "object_reference.h"
+#include "obj_ptr.h"
namespace art {
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index c95d92e34b..96e347576a 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -23,6 +23,7 @@
#include "gc/heap.h"
#include "globals.h"
#include "linear_alloc.h"
+#include "oat_file.h"
#include "object.h"
#include "object-inl.h"
#include "object_array-inl.h"
diff --git a/runtime/mirror/executable.h b/runtime/mirror/executable.h
index 6c465f6bbb..8a28f66868 100644
--- a/runtime/mirror/executable.h
+++ b/runtime/mirror/executable.h
@@ -20,7 +20,6 @@
#include "accessible_object.h"
#include "gc_root.h"
#include "object.h"
-#include "object_callbacks.h"
#include "read_barrier_option.h"
namespace art {
diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h
index 222d709cef..40186a689b 100644
--- a/runtime/mirror/field.h
+++ b/runtime/mirror/field.h
@@ -22,7 +22,6 @@
#include "gc_root.h"
#include "obj_ptr.h"
#include "object.h"
-#include "object_callbacks.h"
#include "read_barrier_option.h"
namespace art {
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index baed5f167c..95f829dc23 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -26,8 +26,7 @@
#include "class-inl.h"
#include "class_flags.h"
#include "class_linker.h"
-#include "class_loader-inl.h"
-#include "dex_cache-inl.h"
+#include "dex_cache.h"
#include "lock_word-inl.h"
#include "monitor.h"
#include "object_array-inl.h"
@@ -899,6 +898,36 @@ inline bool Object::CasFieldWeakRelaxedObjectWithoutWriteBarrier(
return success;
}
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline bool Object::CasFieldWeakReleaseObjectWithoutWriteBarrier(
+ MemberOffset field_offset,
+ ObjPtr<Object> old_value,
+ ObjPtr<Object> new_value) {
+ if (kCheckTransaction) {
+ DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+ }
+ if (kVerifyFlags & kVerifyThis) {
+ VerifyObject(this);
+ }
+ if (kVerifyFlags & kVerifyWrites) {
+ VerifyObject(new_value);
+ }
+ if (kVerifyFlags & kVerifyReads) {
+ VerifyObject(old_value);
+ }
+ if (kTransactionActive) {
+ Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true);
+ }
+ HeapReference<Object> old_ref(HeapReference<Object>::FromObjPtr(old_value));
+ HeapReference<Object> new_ref(HeapReference<Object>::FromObjPtr(new_value));
+ uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+ Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr);
+
+ bool success = atomic_addr->CompareExchangeWeakRelease(old_ref.reference_,
+ new_ref.reference_);
+ return success;
+}
+
template<bool kIsStatic,
VerifyObjectFlags kVerifyFlags,
ReadBarrierOption kReadBarrierOption,
diff --git a/runtime/mirror/object-readbarrier-inl.h b/runtime/mirror/object-readbarrier-inl.h
index 58e7c20667..69365af7fd 100644
--- a/runtime/mirror/object-readbarrier-inl.h
+++ b/runtime/mirror/object-readbarrier-inl.h
@@ -221,6 +221,36 @@ inline bool Object::CasFieldStrongRelaxedObjectWithoutWriteBarrier(
return success;
}
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline bool Object::CasFieldStrongReleaseObjectWithoutWriteBarrier(
+ MemberOffset field_offset,
+ ObjPtr<Object> old_value,
+ ObjPtr<Object> new_value) {
+ if (kCheckTransaction) {
+ DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+ }
+ if (kVerifyFlags & kVerifyThis) {
+ VerifyObject(this);
+ }
+ if (kVerifyFlags & kVerifyWrites) {
+ VerifyObject(new_value);
+ }
+ if (kVerifyFlags & kVerifyReads) {
+ VerifyObject(old_value);
+ }
+ if (kTransactionActive) {
+ Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true);
+ }
+ HeapReference<Object> old_ref(HeapReference<Object>::FromObjPtr(old_value));
+ HeapReference<Object> new_ref(HeapReference<Object>::FromObjPtr(new_value));
+ uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+ Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr);
+
+ bool success = atomic_addr->CompareExchangeStrongRelease(old_ref.reference_,
+ new_ref.reference_);
+ return success;
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/object-refvisitor-inl.h b/runtime/mirror/object-refvisitor-inl.h
index 49ab7c2a53..f5ab4dd8db 100644
--- a/runtime/mirror/object-refvisitor-inl.h
+++ b/runtime/mirror/object-refvisitor-inl.h
@@ -19,7 +19,9 @@
#include "object-inl.h"
+#include "class_loader-inl.h"
#include "class-refvisitor-inl.h"
+#include "dex_cache-inl.h"
namespace art {
namespace mirror {
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 35a1b733e1..9cf42522d1 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -350,10 +350,25 @@ class MANAGED LOCKABLE Object {
template<bool kTransactionActive,
bool kCheckTransaction = true,
VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ bool CasFieldWeakReleaseObjectWithoutWriteBarrier(MemberOffset field_offset,
+ ObjPtr<Object> old_value,
+ ObjPtr<Object> new_value)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ template<bool kTransactionActive,
+ bool kCheckTransaction = true,
+ VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool CasFieldStrongRelaxedObjectWithoutWriteBarrier(MemberOffset field_offset,
ObjPtr<Object> old_value,
ObjPtr<Object> new_value)
REQUIRES_SHARED(Locks::mutator_lock_);
+ template<bool kTransactionActive,
+ bool kCheckTransaction = true,
+ VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ bool CasFieldStrongReleaseObjectWithoutWriteBarrier(MemberOffset field_offset,
+ ObjPtr<Object> old_value,
+ ObjPtr<Object> new_value)
+ REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
HeapReference<Object>* GetFieldObjectReferenceAddr(MemberOffset field_offset);
diff --git a/runtime/mirror/reference-inl.h b/runtime/mirror/reference-inl.h
index a449b41087..84e54948dd 100644
--- a/runtime/mirror/reference-inl.h
+++ b/runtime/mirror/reference-inl.h
@@ -19,7 +19,9 @@
#include "reference.h"
+#include "gc_root-inl.h"
#include "obj_ptr-inl.h"
+#include "runtime.h"
namespace art {
namespace mirror {
@@ -47,6 +49,12 @@ inline void FinalizerReference::SetZombie(ObjPtr<Object> zombie) {
return SetFieldObjectVolatile<kTransactionActive>(ZombieOffset(), zombie);
}
+template<ReadBarrierOption kReadBarrierOption>
+inline Class* Reference::GetJavaLangRefReference() {
+ DCHECK(!java_lang_ref_Reference_.IsNull());
+ return java_lang_ref_Reference_.Read<kReadBarrierOption>();
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/reference.h b/runtime/mirror/reference.h
index cfcbd5ae1f..b10c29444e 100644
--- a/runtime/mirror/reference.h
+++ b/runtime/mirror/reference.h
@@ -18,6 +18,8 @@
#define ART_RUNTIME_MIRROR_REFERENCE_H_
#include "base/enums.h"
+#include "base/macros.h"
+#include "base/mutex.h"
#include "class.h"
#include "gc_root.h"
#include "obj_ptr.h"
@@ -97,10 +99,7 @@ class MANAGED Reference : public Object {
}
template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
- static Class* GetJavaLangRefReference() REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK(!java_lang_ref_Reference_.IsNull());
- return java_lang_ref_Reference_.Read<kReadBarrierOption>();
- }
+ static ALWAYS_INLINE Class* GetJavaLangRefReference() REQUIRES_SHARED(Locks::mutator_lock_);
static void SetClass(ObjPtr<Class> klass);
static void ResetClass();
static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc
index c00cf916a8..53de821498 100644
--- a/runtime/mirror/stack_trace_element.cc
+++ b/runtime/mirror/stack_trace_element.cc
@@ -19,6 +19,7 @@
#include "class.h"
#include "class-inl.h"
#include "gc/accounting/card_table-inl.h"
+#include "gc_root-inl.h"
#include "object-inl.h"
#include "handle_scope-inl.h"
#include "string.h"
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index d32d8dca26..87e8a1f659 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -19,7 +19,6 @@
#include "gc_root.h"
#include "object.h"
-#include "object_callbacks.h"
namespace art {
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index de0e75b083..80745d271d 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -18,8 +18,10 @@
#include "arch/memcmp16.h"
#include "array.h"
+#include "base/array_ref.h"
#include "class-inl.h"
#include "gc/accounting/card_table-inl.h"
+#include "gc_root-inl.h"
#include "handle_scope-inl.h"
#include "intern_table.h"
#include "object-inl.h"
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index b59bbfbd68..7fbe8bd3a6 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -20,7 +20,6 @@
#include "gc_root.h"
#include "gc/allocator_type.h"
#include "object.h"
-#include "object_callbacks.h"
namespace art {
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index e50409f2c5..7027410ca6 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -26,7 +26,9 @@
#include "object-inl.h"
#include "object_array.h"
#include "object_array-inl.h"
+#include "object_callbacks.h"
#include "stack_trace_element.h"
+#include "string.h"
#include "utils.h"
#include "well_known_classes.h"
@@ -169,5 +171,17 @@ void Throwable::VisitRoots(RootVisitor* visitor) {
java_lang_Throwable_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
}
+Object* Throwable::GetStackState() {
+ return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_));
+}
+
+Object* Throwable::GetStackTrace() {
+ return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_));
+}
+
+String* Throwable::GetDetailMessage() {
+ return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_));
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h
index 0a4ab6fe5c..fb45228f49 100644
--- a/runtime/mirror/throwable.h
+++ b/runtime/mirror/throwable.h
@@ -19,23 +19,22 @@
#include "gc_root.h"
#include "object.h"
-#include "object_callbacks.h"
-#include "string.h"
namespace art {
+class RootVisitor;
struct ThrowableOffsets;
namespace mirror {
+class String;
+
// C++ mirror of java.lang.Throwable
class MANAGED Throwable : public Object {
public:
void SetDetailMessage(ObjPtr<String> new_detail_message) REQUIRES_SHARED(Locks::mutator_lock_);
- String* GetDetailMessage() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_));
- }
+ String* GetDetailMessage() REQUIRES_SHARED(Locks::mutator_lock_);
std::string Dump() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -59,12 +58,8 @@ class MANAGED Throwable : public Object {
REQUIRES_SHARED(Locks::mutator_lock_);
private:
- Object* GetStackState() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_));
- }
- Object* GetStackTrace() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_));
- }
+ Object* GetStackState() REQUIRES_SHARED(Locks::mutator_lock_);
+ Object* GetStackTrace() REQUIRES_SHARED(Locks::mutator_lock_);
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
HeapReference<Object> backtrace_; // Note this is Java volatile:
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index bb33047895..a617818c3f 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -31,7 +31,9 @@
#include "lock_word-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
+#include "object_callbacks.h"
#include "scoped_thread_state_change-inl.h"
+#include "stack.h"
#include "thread.h"
#include "thread_list.h"
#include "verifier/method_verifier.h"
@@ -437,17 +439,11 @@ void Monitor::Lock(Thread* self) {
<< " in " << ArtMethod::PrettyMethod(m) << " for "
<< PrettyDuration(MsToNs(wait_ms));
}
- const char* owners_filename;
- int32_t owners_line_number;
- TranslateLocation(owners_method,
- owners_dex_pc,
- &owners_filename,
- &owners_line_number);
LogContentionEvent(self,
wait_ms,
sample_percent,
- owners_filename,
- owners_line_number);
+ owners_method,
+ owners_dex_pc);
}
}
}
diff --git a/runtime/monitor.h b/runtime/monitor.h
index e80d31cdd5..96c5a5b7cc 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -30,13 +30,13 @@
#include "base/mutex.h"
#include "gc_root.h"
#include "lock_word.h"
-#include "object_callbacks.h"
#include "read_barrier_option.h"
#include "thread_state.h"
namespace art {
class ArtMethod;
+class IsMarkedVisitor;
class LockWord;
template<class T> class Handle;
class StackVisitor;
@@ -181,8 +181,11 @@ class Monitor {
REQUIRES_SHARED(Locks::mutator_lock_)
NO_THREAD_SAFETY_ANALYSIS; // For m->Install(self)
- void LogContentionEvent(Thread* self, uint32_t wait_ms, uint32_t sample_percent,
- const char* owner_filename, int32_t owner_line_number)
+ void LogContentionEvent(Thread* self,
+ uint32_t wait_ms,
+ uint32_t sample_percent,
+ ArtMethod* owner_method,
+ uint32_t owner_dex_pc)
REQUIRES_SHARED(Locks::mutator_lock_);
static void FailedUnlock(mirror::Object* obj,
diff --git a/runtime/monitor_android.cc b/runtime/monitor_android.cc
index 1dd60f8d78..74623dab31 100644
--- a/runtime/monitor_android.cc
+++ b/runtime/monitor_android.cc
@@ -15,96 +15,94 @@
*/
#include "monitor.h"
-#include "thread.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <log/log.h>
+#include <log/log_event_list.h>
+
+#include "art_method.h"
+#include "thread.h"
#define EVENT_LOG_TAG_dvm_lock_sample 20003
namespace art {
-static void Set4LE(uint8_t* buf, uint32_t val) {
- *buf++ = (uint8_t)(val);
- *buf++ = (uint8_t)(val >> 8);
- *buf++ = (uint8_t)(val >> 16);
- *buf = (uint8_t)(val >> 24);
-}
+void Monitor::LogContentionEvent(Thread* self,
+ uint32_t wait_ms,
+ uint32_t sample_percent,
+ ArtMethod* owner_method,
+ uint32_t owner_dex_pc) {
+ android_log_event_list ctx(EVENT_LOG_TAG_dvm_lock_sample);
-static char* EventLogWriteInt(char* dst, int value) {
- *dst++ = EVENT_TYPE_INT;
- Set4LE(reinterpret_cast<uint8_t*>(dst), value);
- return dst + 4;
-}
+ const char* owner_filename;
+ int32_t owner_line_number;
+ TranslateLocation(owner_method, owner_dex_pc, &owner_filename, &owner_line_number);
-static char* EventLogWriteString(char* dst, const char* value, size_t len) {
- *dst++ = EVENT_TYPE_STRING;
- len = len < 32 ? len : 32;
- Set4LE(reinterpret_cast<uint8_t*>(dst), len);
- dst += 4;
- memcpy(dst, value, len);
- return dst + len;
-}
+ // Emit the process name, <= 37 bytes.
+ {
+ int fd = open("/proc/self/cmdline", O_RDONLY);
+ char procName[33];
+ memset(procName, 0, sizeof(procName));
+ read(fd, procName, sizeof(procName) - 1);
+ close(fd);
+ ctx << procName;
+ }
-void Monitor::LogContentionEvent(Thread* self, uint32_t wait_ms, uint32_t sample_percent,
- const char* owner_filename, int32_t owner_line_number) {
- // Emit the event list length, 1 byte.
- char eventBuffer[174];
- char* cp = eventBuffer;
- *cp++ = 9;
+ // Emit the sensitive thread ("main thread") status. We follow tradition that this corresponds
+ // to a C++ bool's value, but be explicit.
+ constexpr uint32_t kIsSensitive = 1u;
+ constexpr uint32_t kIsNotSensitive = 0u;
+ ctx << (Thread::IsSensitiveThread() ? kIsSensitive : kIsNotSensitive);
+
+ // Emit self thread name string.
+ {
+ std::string thread_name;
+ self->GetThreadName(thread_name);
+ ctx << thread_name;
+ }
- // Emit the process name, <= 37 bytes.
- int fd = open("/proc/self/cmdline", O_RDONLY);
- char procName[33];
- memset(procName, 0, sizeof(procName));
- read(fd, procName, sizeof(procName) - 1);
- close(fd);
- size_t len = strlen(procName);
- cp = EventLogWriteString(cp, procName, len);
-
- // Emit the sensitive thread ("main thread") status, 5 bytes.
- cp = EventLogWriteInt(cp, Thread::IsSensitiveThread());
-
- // Emit self thread name string, <= 37 bytes.
- std::string thread_name;
- self->GetThreadName(thread_name);
- cp = EventLogWriteString(cp, thread_name.c_str(), thread_name.size());
-
- // Emit the wait time, 5 bytes.
- cp = EventLogWriteInt(cp, wait_ms);
-
- // Emit the source code file name, <= 37 bytes.
- uint32_t pc;
- ArtMethod* m = self->GetCurrentMethod(&pc);
- const char* filename;
- int32_t line_number;
- TranslateLocation(m, pc, &filename, &line_number);
- cp = EventLogWriteString(cp, filename, strlen(filename));
-
- // Emit the source code line number, 5 bytes.
- cp = EventLogWriteInt(cp, line_number);
-
- // Emit the lock owner source code file name, <= 37 bytes.
+ // Emit the wait time.
+ ctx << wait_ms;
+
+ const char* filename = nullptr;
+ {
+ uint32_t pc;
+ ArtMethod* m = self->GetCurrentMethod(&pc);
+ int32_t line_number;
+ TranslateLocation(m, pc, &filename, &line_number);
+
+ // Emit the source code file name.
+ ctx << filename;
+
+ // Emit the source code line number.
+ ctx << line_number;
+
+ // Emit the method name.
+ ctx << ArtMethod::PrettyMethod(m);
+ }
+
+ // Emit the lock owner source code file name.
if (owner_filename == nullptr) {
owner_filename = "";
} else if (strcmp(filename, owner_filename) == 0) {
// Common case, so save on log space.
owner_filename = "-";
}
- cp = EventLogWriteString(cp, owner_filename, strlen(owner_filename));
+ ctx << owner_filename;
+
+ // Emit the source code line number.
+ ctx << owner_line_number;
- // Emit the source code line number, 5 bytes.
- cp = EventLogWriteInt(cp, owner_line_number);
+ // Emit the owner method name.
+ ctx << ArtMethod::PrettyMethod(owner_method);
- // Emit the sample percentage, 5 bytes.
- cp = EventLogWriteInt(cp, sample_percent);
+ // Emit the sample percentage.
+ ctx << sample_percent;
- CHECK_LE((size_t)(cp - eventBuffer), sizeof(eventBuffer));
- android_btWriteLog(EVENT_LOG_TAG_dvm_lock_sample, EVENT_TYPE_LIST, eventBuffer,
- (size_t)(cp - eventBuffer));
+ ctx << LOG_ID_EVENTS;
}
} // namespace art
diff --git a/runtime/monitor_linux.cc b/runtime/monitor_linux.cc
index 1c77ac0eb3..667866149b 100644
--- a/runtime/monitor_linux.cc
+++ b/runtime/monitor_linux.cc
@@ -18,7 +18,7 @@
namespace art {
-void Monitor::LogContentionEvent(Thread*, uint32_t, uint32_t, const char*, int32_t) {
+void Monitor::LogContentionEvent(Thread*, uint32_t, uint32_t, ArtMethod*, uint32_t) {
}
} // namespace art
diff --git a/runtime/monitor_pool.cc b/runtime/monitor_pool.cc
index 0f4e2387cc..48e9a6b47d 100644
--- a/runtime/monitor_pool.cc
+++ b/runtime/monitor_pool.cc
@@ -18,7 +18,7 @@
#include "base/logging.h"
#include "base/mutex-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "monitor.h"
namespace art {
diff --git a/runtime/monitor_pool_test.cc b/runtime/monitor_pool_test.cc
index a111c6c16a..5463877b83 100644
--- a/runtime/monitor_pool_test.cc
+++ b/runtime/monitor_pool_test.cc
@@ -18,7 +18,7 @@
#include "common_runtime_test.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 870402d301..ad009668bf 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -31,6 +31,7 @@
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
#include "mirror/string.h"
+#include "native_util.h"
#include "oat_file.h"
#include "oat_file_assistant.h"
#include "oat_file_manager.h"
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index bb8233b9e8..e1eae21df9 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -39,6 +39,7 @@
#include "jni_internal.h"
#include "mirror/class.h"
#include "mirror/object_array-inl.h"
+#include "native_util.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
#include "scoped_fast_native_object_access-inl.h"
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 18b871cca3..fed9c1cf5b 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -52,6 +52,7 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version);
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
#include "mirror/object-inl.h"
+#include "native_util.h"
#include "runtime.h"
#include "scoped_fast_native_object_access-inl.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index 6c41d515de..e86e64ed6a 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -25,6 +25,7 @@
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
#include "scoped_thread_state_change-inl.h"
#include "thread_list.h"
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 4c6f53081a..31aeba06f9 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -28,10 +28,12 @@
#include "jit/jit.h"
#include "jni_internal.h"
#include "JNIHelp.h"
+#include "native_util.h"
#include "non_debuggable_classes.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
-#include "thread-inl.h"
+#include "stack.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#include "trace.h"
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 9e07a5c1a4..d3377be393 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -36,6 +36,7 @@
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/string-inl.h"
+#include "native_util.h"
#include "obj_ptr-inl.h"
#include "reflection.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc
index c9841d1b23..d52bf0490b 100644
--- a/runtime/native/java_lang_Object.cc
+++ b/runtime/native/java_lang_Object.cc
@@ -20,6 +20,7 @@
#include "jni_internal.h"
#include "mirror/object-inl.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
namespace art {
diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
index 4928c01c96..ac0d6337b2 100644
--- a/runtime/native/java_lang_String.cc
+++ b/runtime/native/java_lang_String.cc
@@ -24,6 +24,7 @@
#include "mirror/object-inl.h"
#include "mirror/string.h"
#include "mirror/string-inl.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc
index c1292ef6c4..9c2e91843e 100644
--- a/runtime/native/java_lang_StringFactory.cc
+++ b/runtime/native/java_lang_StringFactory.cc
@@ -22,6 +22,7 @@
#include "jni_internal.h"
#include "mirror/object-inl.h"
#include "mirror/string.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
index 264b427460..0e5d740cab 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -26,6 +26,7 @@
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
namespace art {
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index f3254c4b18..e4d1705d28 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -22,6 +22,7 @@
#include "jni_internal.h"
#include "monitor.h"
#include "mirror/object.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc
index b69fbef8d8..03b7f9dfba 100644
--- a/runtime/native/java_lang_Throwable.cc
+++ b/runtime/native/java_lang_Throwable.cc
@@ -19,6 +19,7 @@
#include "nativehelper/jni_macros.h"
#include "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 55955e7c57..fc50d5584d 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -22,6 +22,7 @@
#include "jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
+#include "native_util.h"
#include "obj_ptr.h"
#include "scoped_fast_native_object_access-inl.h"
#include "ScopedLocalRef.h"
diff --git a/runtime/native/java_lang_Void.cc b/runtime/native/java_lang_Void.cc
index b0d63ef222..af83dd1a79 100644
--- a/runtime/native/java_lang_Void.cc
+++ b/runtime/native/java_lang_Void.cc
@@ -20,6 +20,7 @@
#include "class_linker-inl.h"
#include "jni_internal.h"
+#include "native_util.h"
#include "runtime.h"
#include "scoped_fast_native_object_access-inl.h"
diff --git a/runtime/native/java_lang_invoke_MethodHandleImpl.cc b/runtime/native/java_lang_invoke_MethodHandleImpl.cc
index 63168cec24..2e3b4d41ef 100644
--- a/runtime/native/java_lang_invoke_MethodHandleImpl.cc
+++ b/runtime/native/java_lang_invoke_MethodHandleImpl.cc
@@ -24,6 +24,7 @@
#include "mirror/field.h"
#include "mirror/method.h"
#include "mirror/method_handle_impl.h"
+#include "native_util.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/runtime/native/java_lang_ref_FinalizerReference.cc b/runtime/native/java_lang_ref_FinalizerReference.cc
index c75837aa96..72af5f7ea7 100644
--- a/runtime/native/java_lang_ref_FinalizerReference.cc
+++ b/runtime/native/java_lang_ref_FinalizerReference.cc
@@ -23,6 +23,7 @@
#include "jni_internal.h"
#include "mirror/object-inl.h"
#include "mirror/reference-inl.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
namespace art {
diff --git a/runtime/native/java_lang_ref_Reference.cc b/runtime/native/java_lang_ref_Reference.cc
index 606e656f3c..524a18ca20 100644
--- a/runtime/native/java_lang_ref_Reference.cc
+++ b/runtime/native/java_lang_ref_Reference.cc
@@ -23,6 +23,7 @@
#include "jni_internal.h"
#include "mirror/object-inl.h"
#include "mirror/reference-inl.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
namespace art {
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
index 96623950aa..5be317147b 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -21,11 +21,12 @@
#include "class_linker-inl.h"
#include "common_throws.h"
#include "dex_file-inl.h"
+#include "handle_scope-inl.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
-#include "handle_scope-inl.h"
namespace art {
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index d1953adacf..242e87afa9 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -27,6 +27,7 @@
#include "mirror/class-inl.h"
#include "mirror/method.h"
#include "mirror/object-inl.h"
+#include "native_util.h"
#include "reflection.h"
#include "scoped_fast_native_object_access-inl.h"
#include "well_known_classes.h"
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index 256a3d04de..2aad12d3b8 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -27,6 +27,7 @@
#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "native_util.h"
#include "reflection.h"
#include "scoped_fast_native_object_access-inl.h"
#include "well_known_classes.h"
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index e38bcd691a..f19004dab5 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -28,6 +28,7 @@
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/field.h"
+#include "native_util.h"
#include "reflection-inl.h"
#include "scoped_fast_native_object_access-inl.h"
#include "utils.h"
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index c9e8dba551..cbbb6a8ea3 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -27,6 +27,7 @@
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "native_util.h"
#include "reflection.h"
#include "scoped_fast_native_object_access-inl.h"
#include "well_known_classes.h"
diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc
index 92a7ac9836..c4ab5d69fc 100644
--- a/runtime/native/java_lang_reflect_Parameter.cc
+++ b/runtime/native/java_lang_reflect_Parameter.cc
@@ -24,6 +24,7 @@
#include "dex_file-inl.h"
#include "dex_file_annotations.h"
#include "jni_internal.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
#include "utils.h"
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
index 518aaa7317..691ed28b0b 100644
--- a/runtime/native/java_lang_reflect_Proxy.cc
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -23,6 +23,7 @@
#include "mirror/class_loader.h"
#include "mirror/object_array.h"
#include "mirror/string.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
#include "verify_object.h"
diff --git a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
index 101f386ff8..bd4b0fec70 100644
--- a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
+++ b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
@@ -21,6 +21,7 @@
#include "arch/instruction_set.h"
#include "atomic.h"
#include "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 c388ea1438..38634e6d0c 100644
--- a/runtime/native/libcore_util_CharsetUtils.cc
+++ b/runtime/native/libcore_util_CharsetUtils.cc
@@ -23,6 +23,7 @@
#include "jni_internal.h"
#include "mirror/string.h"
#include "mirror/string-inl.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
#include "ScopedPrimitiveArray.h"
#include "unicode/utf16.h"
diff --git a/runtime/native/native_util.h b/runtime/native/native_util.h
new file mode 100644
index 0000000000..98384e0178
--- /dev/null
+++ b/runtime/native/native_util.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_NATIVE_NATIVE_UTIL_H_
+#define ART_RUNTIME_NATIVE_NATIVE_UTIL_H_
+
+#include <jni.h>
+
+#include "android-base/logging.h"
+#include "base/macros.h"
+#include "ScopedLocalRef.h"
+
+namespace art {
+
+ALWAYS_INLINE inline void RegisterNativeMethodsInternal(JNIEnv* env,
+ const char* jni_class_name,
+ const JNINativeMethod* methods,
+ jint method_count) {
+ ScopedLocalRef<jclass> c(env, env->FindClass(jni_class_name));
+ if (c.get() == nullptr) {
+ LOG(FATAL) << "Couldn't find class: " << jni_class_name;
+ }
+ jint jni_result = env->RegisterNatives(c.get(), methods, method_count);
+ CHECK_EQ(JNI_OK, jni_result);
+}
+
+#define REGISTER_NATIVE_METHODS(jni_class_name) \
+ RegisterNativeMethodsInternal(env, (jni_class_name), gMethods, arraysize(gMethods))
+
+} // namespace art
+
+#endif // ART_RUNTIME_NATIVE_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 a860977c4c..925b90931c 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
@@ -21,6 +21,7 @@
#include "base/logging.h"
#include "debugger.h"
#include "jni_internal.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
#include "ScopedPrimitiveArray.h"
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index 71c5b50216..0a254aca54 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -23,6 +23,7 @@
#include "debugger.h"
#include "gc/heap.h"
#include "jni_internal.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index b42cedfaf0..e78c9da5e5 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -29,9 +29,9 @@
#include "mirror/array.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
+#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
-
namespace art {
static jboolean Unsafe_compareAndSwapInt(JNIEnv* env, jobject, jobject javaObj, jlong offset,
diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc
index cbc502487f..cbff0bb2f2 100644
--- a/runtime/native_stack_dump.cc
+++ b/runtime/native_stack_dump.cc
@@ -45,7 +45,7 @@
#include "base/unix_file/fd_file.h"
#include "oat_quick_method_header.h"
#include "os.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils.h"
#endif
diff --git a/runtime/non_debuggable_classes.cc b/runtime/non_debuggable_classes.cc
index 829ea65876..9cc7e60fa8 100644
--- a/runtime/non_debuggable_classes.cc
+++ b/runtime/non_debuggable_classes.cc
@@ -21,7 +21,7 @@
#include "mirror/class-inl.h"
#include "obj_ptr-inl.h"
#include "ScopedLocalRef.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 06c76b5464..a6d2eba354 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -39,9 +39,10 @@ class BitVector;
class ElfFile;
template <class MirrorType> class GcRoot;
class MemMap;
-class OatMethodOffsets;
-class OatHeader;
class OatDexFile;
+class OatHeader;
+class OatMethodOffsets;
+class OatQuickMethodHeader;
class VdexFile;
namespace gc {
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index b2b86ee289..c2029165ad 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -28,7 +28,7 @@
#include "oat_file_manager.h"
#include "os.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "utils.h"
namespace art {
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index c1cf800e5d..630945a829 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -29,6 +29,7 @@
#include "base/systrace.h"
#include "class_linker.h"
#include "dex_file-inl.h"
+#include "dex_file_tracking_registrar.h"
#include "gc/scoped_gc_critical_section.h"
#include "gc/space/image_space.h"
#include "handle_scope-inl.h"
@@ -38,7 +39,7 @@
#include "oat_file_assistant.h"
#include "obj_ptr-inl.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#include "well_known_classes.h"
@@ -737,6 +738,11 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
// Successfully added image space to heap, release the map so that it does not get
// freed.
image_space.release();
+
+ // Register for tracking.
+ for (const auto& dex_file : dex_files) {
+ dex::tracking::RegisterDexFile(dex_file.get());
+ }
} else {
LOG(INFO) << "Failed to add image file " << temp_error_msg;
dex_files.clear();
@@ -756,6 +762,11 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
if (!added_image_space) {
DCHECK(dex_files.empty());
dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location);
+
+ // Register for tracking.
+ for (const auto& dex_file : dex_files) {
+ dex::tracking::RegisterDexFile(dex_file.get());
+ }
}
if (dex_files.empty()) {
error_msgs->push_back("Failed to open dex files from " + source_oat_file->GetLocation());
diff --git a/runtime/obj_ptr-inl.h b/runtime/obj_ptr-inl.h
index f2921daeaa..3d9b3c6cf7 100644
--- a/runtime/obj_ptr-inl.h
+++ b/runtime/obj_ptr-inl.h
@@ -18,7 +18,7 @@
#define ART_RUNTIME_OBJ_PTR_INL_H_
#include "obj_ptr.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 9be486e269..45773fdfbf 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -46,7 +46,7 @@
#include "object_tagging.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#include "ti_class.h"
#include "ti_dump.h"
diff --git a/runtime/openjdkjvmti/events.cc b/runtime/openjdkjvmti/events.cc
index 0ec92b7c60..320c59c810 100644
--- a/runtime/openjdkjvmti/events.cc
+++ b/runtime/openjdkjvmti/events.cc
@@ -44,7 +44,7 @@
#include "runtime.h"
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace openjdkjvmti {
diff --git a/runtime/openjdkjvmti/jvmti_weak_table.h b/runtime/openjdkjvmti/jvmti_weak_table.h
index be6edefae2..01c24b1917 100644
--- a/runtime/openjdkjvmti/jvmti_weak_table.h
+++ b/runtime/openjdkjvmti/jvmti_weak_table.h
@@ -41,7 +41,7 @@
#include "globals.h"
#include "jvmti.h"
#include "mirror/object.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace openjdkjvmti {
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index dd90a71240..0aa93dfb57 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -63,7 +63,7 @@
#include "runtime_callbacks.h"
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#include "ti_class_loader.h"
#include "ti_phase.h"
diff --git a/runtime/openjdkjvmti/ti_dump.cc b/runtime/openjdkjvmti/ti_dump.cc
index d9e3ef1bcf..7a1e53f6e5 100644
--- a/runtime/openjdkjvmti/ti_dump.cc
+++ b/runtime/openjdkjvmti/ti_dump.cc
@@ -39,7 +39,7 @@
#include "events-inl.h"
#include "runtime_callbacks.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
namespace openjdkjvmti {
diff --git a/runtime/openjdkjvmti/ti_field.cc b/runtime/openjdkjvmti/ti_field.cc
index 1e5fbda35b..342d8be2b0 100644
--- a/runtime/openjdkjvmti/ti_field.cc
+++ b/runtime/openjdkjvmti/ti_field.cc
@@ -39,7 +39,7 @@
#include "mirror/object_array-inl.h"
#include "modifiers.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace openjdkjvmti {
diff --git a/runtime/openjdkjvmti/ti_heap.cc b/runtime/openjdkjvmti/ti_heap.cc
index 99774c67b5..319b1c2a9c 100644
--- a/runtime/openjdkjvmti/ti_heap.cc
+++ b/runtime/openjdkjvmti/ti_heap.cc
@@ -35,6 +35,7 @@
#include "primitive.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
+#include "stack.h"
#include "thread-inl.h"
#include "thread_list.h"
diff --git a/runtime/openjdkjvmti/ti_jni.cc b/runtime/openjdkjvmti/ti_jni.cc
index 88f0395ba5..dd2dda118a 100644
--- a/runtime/openjdkjvmti/ti_jni.cc
+++ b/runtime/openjdkjvmti/ti_jni.cc
@@ -38,7 +38,7 @@
#include "java_vm_ext.h"
#include "jni_env_ext.h"
#include "runtime.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace openjdkjvmti {
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index f7e53474aa..beb639e208 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -42,7 +42,7 @@
#include "runtime_callbacks.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#include "ti_phase.h"
diff --git a/runtime/openjdkjvmti/ti_monitor.cc b/runtime/openjdkjvmti/ti_monitor.cc
index 645faea41b..61bf533eb7 100644
--- a/runtime/openjdkjvmti/ti_monitor.cc
+++ b/runtime/openjdkjvmti/ti_monitor.cc
@@ -39,7 +39,7 @@
#include "art_jvmti.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace openjdkjvmti {
diff --git a/runtime/openjdkjvmti/ti_object.cc b/runtime/openjdkjvmti/ti_object.cc
index bf84499035..2506acac3a 100644
--- a/runtime/openjdkjvmti/ti_object.cc
+++ b/runtime/openjdkjvmti/ti_object.cc
@@ -34,7 +34,7 @@
#include "art_jvmti.h"
#include "mirror/object-inl.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace openjdkjvmti {
diff --git a/runtime/openjdkjvmti/ti_phase.cc b/runtime/openjdkjvmti/ti_phase.cc
index 941cf7b73b..3c8bdc61d0 100644
--- a/runtime/openjdkjvmti/ti_phase.cc
+++ b/runtime/openjdkjvmti/ti_phase.cc
@@ -38,7 +38,7 @@
#include "runtime_callbacks.h"
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#include "ti_thread.h"
diff --git a/runtime/openjdkjvmti/ti_properties.cc b/runtime/openjdkjvmti/ti_properties.cc
index 8ee5366140..e399b484ec 100644
--- a/runtime/openjdkjvmti/ti_properties.cc
+++ b/runtime/openjdkjvmti/ti_properties.cc
@@ -40,7 +40,7 @@
#include "art_jvmti.h"
#include "runtime.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "ti_phase.h"
#include "well_known_classes.h"
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index ca3a0e631a..b382a3e7c3 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -48,6 +48,7 @@
#include "gc/allocation_listener.h"
#include "gc/heap.h"
#include "instrumentation.h"
+#include "intern_table.h"
#include "jdwp/jdwp.h"
#include "jdwp/jdwp_constants.h"
#include "jdwp/jdwp_event.h"
@@ -452,7 +453,30 @@ art::mirror::ClassLoader* Redefiner::ClassRedefinition::GetClassLoader() {
art::mirror::DexCache* Redefiner::ClassRedefinition::CreateNewDexCache(
art::Handle<art::mirror::ClassLoader> loader) {
- return driver_->runtime_->GetClassLinker()->RegisterDexFile(*dex_file_, loader.Get()).Ptr();
+ art::StackHandleScope<2> hs(driver_->self_);
+ art::ClassLinker* cl = driver_->runtime_->GetClassLinker();
+ art::Handle<art::mirror::DexCache> cache(hs.NewHandle(
+ art::ObjPtr<art::mirror::DexCache>::DownCast(
+ cl->GetClassRoot(art::ClassLinker::kJavaLangDexCache)->AllocObject(driver_->self_))));
+ if (cache.IsNull()) {
+ driver_->self_->AssertPendingOOMException();
+ return nullptr;
+ }
+ art::Handle<art::mirror::String> location(hs.NewHandle(
+ cl->GetInternTable()->InternStrong(dex_file_->GetLocation().c_str())));
+ if (location.IsNull()) {
+ driver_->self_->AssertPendingOOMException();
+ return nullptr;
+ }
+ art::WriterMutexLock mu(driver_->self_, *art::Locks::dex_lock_);
+ art::mirror::DexCache::InitializeDexCache(driver_->self_,
+ cache.Get(),
+ location.Get(),
+ dex_file_.get(),
+ loader.IsNull() ? driver_->runtime_->GetLinearAlloc()
+ : loader->GetAllocator(),
+ art::kRuntimePointerSize);
+ return cache.Get();
}
void Redefiner::RecordFailure(jvmtiError result,
@@ -1293,8 +1317,10 @@ jvmtiError Redefiner::Run() {
// At this point we can no longer fail without corrupting the runtime state.
for (RedefinitionDataIter data = holder.begin(); data != holder.end(); ++data) {
+ art::ClassLinker* cl = runtime_->GetClassLinker();
+ cl->RegisterExistingDexCache(data.GetNewDexCache(), data.GetSourceClassLoader());
if (data.GetSourceClassLoader() == nullptr) {
- runtime_->GetClassLinker()->AppendToBootClassPath(self_, data.GetRedefinition().GetDexFile());
+ cl->AppendToBootClassPath(self_, data.GetRedefinition().GetDexFile());
}
}
UnregisterAllBreakpoints();
diff --git a/runtime/openjdkjvmti/ti_search.cc b/runtime/openjdkjvmti/ti_search.cc
index ec139f2004..6e0196edc3 100644
--- a/runtime/openjdkjvmti/ti_search.cc
+++ b/runtime/openjdkjvmti/ti_search.cc
@@ -49,7 +49,7 @@
#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "ti_phase.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#include "well_known_classes.h"
diff --git a/runtime/openjdkjvmti/ti_stack.cc b/runtime/openjdkjvmti/ti_stack.cc
index 1ddf04feb4..22da2d2f65 100644
--- a/runtime/openjdkjvmti/ti_stack.cc
+++ b/runtime/openjdkjvmti/ti_stack.cc
@@ -52,7 +52,7 @@
#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "stack.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#include "thread_pool.h"
#include "well_known_classes.h"
diff --git a/runtime/openjdkjvmti/ti_thread.cc b/runtime/openjdkjvmti/ti_thread.cc
index 3dfa63313d..2cc2a26c3b 100644
--- a/runtime/openjdkjvmti/ti_thread.cc
+++ b/runtime/openjdkjvmti/ti_thread.cc
@@ -49,7 +49,7 @@
#include "runtime_callbacks.h"
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#include "well_known_classes.h"
diff --git a/runtime/openjdkjvmti/ti_threadgroup.cc b/runtime/openjdkjvmti/ti_threadgroup.cc
index dd7be113d6..c0597ad0cc 100644
--- a/runtime/openjdkjvmti/ti_threadgroup.cc
+++ b/runtime/openjdkjvmti/ti_threadgroup.cc
@@ -45,7 +45,7 @@
#include "object_lock.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
#include "well_known_classes.h"
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index ef4957c0ba..abb6f8c018 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -709,7 +709,7 @@ void ParsedOptions::Usage(const char* fmt, ...) {
UsageMessage(stream, " -Xmethod-trace-file-size:integervalue\n");
UsageMessage(stream, " -Xps-min-save-period-ms:integervalue\n");
UsageMessage(stream, " -Xps-save-resolved-classes-delay-ms:integervalue\n");
- UsageMessage(stream, " -Xps-startup-method-samples:integervalue\n");
+ UsageMessage(stream, " -Xps-hot-startup-method-samples:integervalue\n");
UsageMessage(stream, " -Xps-min-methods-to-save:integervalue\n");
UsageMessage(stream, " -Xps-min-classes-to-save:integervalue\n");
UsageMessage(stream, " -Xps-min-notification-before-wake:integervalue\n");
diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h
index db774909dd..2d06e54f78 100644
--- a/runtime/read_barrier-inl.h
+++ b/runtime/read_barrier-inl.h
@@ -63,7 +63,7 @@ inline MirrorType* ReadBarrier::Barrier(
// If kAlwaysUpdateField is true, update the field atomically. This may fail if mutator
// updates before us, but it's OK.
if (kAlwaysUpdateField && ref != old_ref) {
- obj->CasFieldStrongRelaxedObjectWithoutWriteBarrier<false, false>(
+ obj->CasFieldStrongReleaseObjectWithoutWriteBarrier<false, false>(
offset, old_ref, ref);
}
}
@@ -81,7 +81,7 @@ inline MirrorType* ReadBarrier::Barrier(
ref = reinterpret_cast<MirrorType*>(Mark(old_ref));
// Update the field atomically. This may fail if mutator updates before us, but it's ok.
if (ref != old_ref) {
- obj->CasFieldStrongRelaxedObjectWithoutWriteBarrier<false, false>(
+ obj->CasFieldStrongReleaseObjectWithoutWriteBarrier<false, false>(
offset, old_ref, ref);
}
}
diff --git a/runtime/reference_table.h b/runtime/reference_table.h
index 8423e04e88..010c6f8fde 100644
--- a/runtime/reference_table.h
+++ b/runtime/reference_table.h
@@ -26,7 +26,6 @@
#include "base/mutex.h"
#include "gc_root.h"
#include "obj_ptr.h"
-#include "object_callbacks.h"
namespace art {
namespace mirror {
diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc
index e809ecf1f6..260be8f41f 100644
--- a/runtime/reference_table_test.cc
+++ b/runtime/reference_table_test.cc
@@ -29,7 +29,7 @@
#include "primitive.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/runtime_android.cc b/runtime/runtime_android.cc
index 495296cf7d..4bd3b3ae3a 100644
--- a/runtime/runtime_android.cc
+++ b/runtime/runtime_android.cc
@@ -27,7 +27,11 @@ namespace art {
struct sigaction old_action;
void HandleUnexpectedSignalAndroid(int signal_number, siginfo_t* info, void* raw_context) {
- HandleUnexpectedSignalCommon(signal_number, info, raw_context, /* running_on_linux */ false);
+ HandleUnexpectedSignalCommon(signal_number,
+ info,
+ raw_context,
+ /* handle_timeout_signal */ false,
+ /* dump_on_stderr */ false);
// Run the old signal handler.
old_action.sa_sigaction(signal_number, info, raw_context);
diff --git a/runtime/runtime_common.cc b/runtime/runtime_common.cc
index 36901293bb..940e4611f6 100644
--- a/runtime/runtime_common.cc
+++ b/runtime/runtime_common.cc
@@ -29,7 +29,8 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "native_stack_dump.h"
-#include "thread-inl.h"
+#include "runtime.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
namespace art {
@@ -370,10 +371,8 @@ static bool IsTimeoutSignal(int signal_number) {
void HandleUnexpectedSignalCommon(int signal_number,
siginfo_t* info,
void* raw_context,
- bool running_on_linux) {
- bool handle_timeout_signal = running_on_linux;
- bool dump_on_stderr = running_on_linux;
-
+ bool handle_timeout_signal,
+ bool dump_on_stderr) {
static bool handling_unexpected_signal = false;
if (handling_unexpected_signal) {
LogHelper::LogLineLowStack(__FILE__,
@@ -393,39 +392,41 @@ void HandleUnexpectedSignalCommon(int signal_number,
gAborting++; // set before taking any locks
MutexLock mu(Thread::Current(), *Locks::unexpected_signal_lock_);
- bool has_address = (signal_number == SIGILL || signal_number == SIGBUS ||
- signal_number == SIGFPE || signal_number == SIGSEGV);
+ auto logger = [&](auto& stream) {
+ bool has_address = (signal_number == SIGILL || signal_number == SIGBUS ||
+ signal_number == SIGFPE || signal_number == SIGSEGV);
+ OsInfo os_info;
+ const char* cmd_line = GetCmdLine();
+ if (cmd_line == nullptr) {
+ cmd_line = "<unset>"; // Because no-one called InitLogging.
+ }
+ pid_t tid = GetTid();
+ std::string thread_name(GetThreadName(tid));
+ UContext thread_context(raw_context);
+ Backtrace thread_backtrace(raw_context);
+
+ stream << "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***" << std::endl
+ << StringPrintf("Fatal signal %d (%s), code %d (%s)",
+ signal_number,
+ GetSignalName(signal_number),
+ info->si_code,
+ GetSignalCodeName(signal_number, info->si_code))
+ << (has_address ? StringPrintf(" fault addr %p", info->si_addr) : "") << std::endl
+ << "OS: " << Dumpable<OsInfo>(os_info) << std::endl
+ << "Cmdline: " << cmd_line << std::endl
+ << "Thread: " << tid << " \"" << thread_name << "\"" << std::endl
+ << "Registers:\n" << Dumpable<UContext>(thread_context) << std::endl
+ << "Backtrace:\n" << Dumpable<Backtrace>(thread_backtrace) << std::endl;
+ stream << std::flush;
+ };
- OsInfo os_info;
- const char* cmd_line = GetCmdLine();
- if (cmd_line == nullptr) {
- cmd_line = "<unset>"; // Because no-one called InitLogging.
- }
- pid_t tid = GetTid();
- std::string thread_name(GetThreadName(tid));
- UContext thread_context(raw_context);
- Backtrace thread_backtrace(raw_context);
-
- std::ostringstream stream;
- stream << "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"
- << StringPrintf("Fatal signal %d (%s), code %d (%s)",
- signal_number,
- GetSignalName(signal_number),
- info->si_code,
- GetSignalCodeName(signal_number, info->si_code))
- << (has_address ? StringPrintf(" fault addr %p", info->si_addr) : "") << '\n'
- << "OS: " << Dumpable<OsInfo>(os_info) << '\n'
- << "Cmdline: " << cmd_line << '\n'
- << "Thread: " << tid << " \"" << thread_name << "\"" << '\n'
- << "Registers:\n" << Dumpable<UContext>(thread_context) << '\n'
- << "Backtrace:\n" << Dumpable<Backtrace>(thread_backtrace) << '\n';
if (dump_on_stderr) {
// Note: We are using cerr directly instead of LOG macros to ensure even just partial output
// makes it out. That means we lose the "dalvikvm..." prefix, but that is acceptable
// considering this is an abort situation.
- std::cerr << stream.str() << std::flush;
+ logger(std::cerr);
} else {
- LOG(FATAL_WITHOUT_ABORT) << stream.str() << std::flush;
+ logger(LOG_STREAM(FATAL_WITHOUT_ABORT));
}
if (kIsDebugBuild && signal_number == SIGSEGV) {
PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT);
diff --git a/runtime/runtime_common.h b/runtime/runtime_common.h
index 832b6bbf3e..06d66270af 100644
--- a/runtime/runtime_common.h
+++ b/runtime/runtime_common.h
@@ -68,7 +68,8 @@ int GetTimeoutSignal();
void HandleUnexpectedSignalCommon(int signal_number,
siginfo_t* info,
void* raw_context,
- bool running_on_linux);
+ bool handle_timeout_signal,
+ bool dump_on_stderr);
void InitPlatformSignalHandlersCommon(void (*newact)(int, siginfo_t*, void*),
struct sigaction* oldact,
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index ad61cf373b..424dcf85cf 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -25,7 +25,13 @@
namespace art {
void HandleUnexpectedSignalLinux(int signal_number, siginfo_t* info, void* raw_context) {
- HandleUnexpectedSignalCommon(signal_number, info, raw_context, /* running_on_linux */ true);
+ // Linux is mainly used for host testing. Under those conditions, react to the timeout signal,
+ // and dump to stderr to avoid missing output on double-faults.
+ HandleUnexpectedSignalCommon(signal_number,
+ info,
+ raw_context,
+ /* handle_timeout_signal */ true,
+ /* dump_on_stderr */ true);
if (getenv("debug_db_uid") != nullptr || getenv("art_wait_for_gdb_on_crash") != nullptr) {
pid_t tid = GetTid();
diff --git a/runtime/safe_map.h b/runtime/safe_map.h
index e638fdb504..b54f587715 100644
--- a/runtime/safe_map.h
+++ b/runtime/safe_map.h
@@ -46,6 +46,7 @@ class SafeMap {
SafeMap() = default;
SafeMap(const SafeMap&) = default;
+ SafeMap(SafeMap&&) = default;
explicit SafeMap(const key_compare& cmp, const allocator_type& allocator = allocator_type())
: map_(cmp, allocator) {
}
@@ -151,6 +152,11 @@ class SafeMap {
return map_ == rhs.map_;
}
+ template <class... Args>
+ std::pair<iterator, bool> emplace(Args&&... args) {
+ return map_.emplace(std::forward<Args>(args)...);
+ }
+
private:
::std::map<K, V, Comparator, Allocator> map_;
};
diff --git a/runtime/scoped_thread_state_change-inl.h b/runtime/scoped_thread_state_change-inl.h
index ed6e349de4..aa96871145 100644
--- a/runtime/scoped_thread_state_change-inl.h
+++ b/runtime/scoped_thread_state_change-inl.h
@@ -22,6 +22,7 @@
#include "base/casts.h"
#include "jni_env_ext-inl.h"
#include "obj_ptr-inl.h"
+#include "runtime.h"
#include "thread-inl.h"
namespace art {
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 5c6eead34b..aedcc1eb03 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -29,6 +29,7 @@
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
#include "linear_alloc.h"
+#include "managed_stack.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
@@ -68,34 +69,6 @@ mirror::Object* ShadowFrame::GetThisObject(uint16_t num_ins) const {
}
}
-size_t ManagedStack::NumJniShadowFrameReferences() const {
- size_t count = 0;
- for (const ManagedStack* current_fragment = this; current_fragment != nullptr;
- current_fragment = current_fragment->GetLink()) {
- for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_; current_frame != nullptr;
- current_frame = current_frame->GetLink()) {
- if (current_frame->GetMethod()->IsNative()) {
- // The JNI ShadowFrame only contains references. (For indirect reference.)
- count += current_frame->NumberOfVRegs();
- }
- }
- }
- return count;
-}
-
-bool ManagedStack::ShadowFramesContain(StackReference<mirror::Object>* shadow_frame_entry) const {
- for (const ManagedStack* current_fragment = this; current_fragment != nullptr;
- current_fragment = current_fragment->GetLink()) {
- for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_; current_frame != nullptr;
- current_frame = current_frame->GetLink()) {
- if (current_frame->Contains(shadow_frame_entry)) {
- return true;
- }
- }
- }
- return false;
-}
-
StackVisitor::StackVisitor(Thread* thread,
Context* context,
StackWalkKind walk_kind,
@@ -648,6 +621,12 @@ static void AssertPcIsWithinQuickCode(ArtMethod* method, uintptr_t pc)
return;
}
+ Runtime* runtime = Runtime::Current();
+ if (runtime->UseJitCompilation() &&
+ runtime->GetJit()->GetCodeCache()->ContainsPc(reinterpret_cast<const void*>(pc))) {
+ return;
+ }
+
const void* code = method->GetEntryPointFromQuickCompiledCode();
if (code == GetQuickInstrumentationEntryPoint() || code == GetInvokeObsoleteMethodStub()) {
return;
@@ -659,9 +638,6 @@ static void AssertPcIsWithinQuickCode(ArtMethod* method, uintptr_t pc)
return;
}
- // If we are the JIT then we may have just compiled the method after the
- // IsQuickToInterpreterBridge check.
- Runtime* runtime = Runtime::Current();
if (runtime->UseJitCompilation() && runtime->GetJit()->GetCodeCache()->ContainsPc(code)) {
return;
}
diff --git a/runtime/stack.h b/runtime/stack.h
index bdaa4c3ca2..8c74a8c405 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -512,86 +512,6 @@ class JavaFrameRootInfo FINAL : public RootInfo {
const size_t vreg_;
};
-// The managed stack is used to record fragments of managed code stacks. Managed code stacks
-// may either be shadow frames or lists of frames using fixed frame sizes. Transition records are
-// necessary for transitions between code using different frame layouts and transitions into native
-// code.
-class PACKED(4) ManagedStack {
- public:
- ManagedStack()
- : top_quick_frame_(nullptr), link_(nullptr), top_shadow_frame_(nullptr) {}
-
- void PushManagedStackFragment(ManagedStack* fragment) {
- // Copy this top fragment into given fragment.
- memcpy(fragment, this, sizeof(ManagedStack));
- // Clear this fragment, which has become the top.
- memset(this, 0, sizeof(ManagedStack));
- // Link our top fragment onto the given fragment.
- link_ = fragment;
- }
-
- void PopManagedStackFragment(const ManagedStack& fragment) {
- DCHECK(&fragment == link_);
- // Copy this given fragment back to the top.
- memcpy(this, &fragment, sizeof(ManagedStack));
- }
-
- ManagedStack* GetLink() const {
- return link_;
- }
-
- ArtMethod** GetTopQuickFrame() const {
- return top_quick_frame_;
- }
-
- void SetTopQuickFrame(ArtMethod** top) {
- DCHECK(top_shadow_frame_ == nullptr);
- top_quick_frame_ = top;
- }
-
- static size_t TopQuickFrameOffset() {
- return OFFSETOF_MEMBER(ManagedStack, top_quick_frame_);
- }
-
- ShadowFrame* PushShadowFrame(ShadowFrame* new_top_frame) {
- DCHECK(top_quick_frame_ == nullptr);
- ShadowFrame* old_frame = top_shadow_frame_;
- top_shadow_frame_ = new_top_frame;
- new_top_frame->SetLink(old_frame);
- return old_frame;
- }
-
- ShadowFrame* PopShadowFrame() {
- DCHECK(top_quick_frame_ == nullptr);
- CHECK(top_shadow_frame_ != nullptr);
- ShadowFrame* frame = top_shadow_frame_;
- top_shadow_frame_ = frame->GetLink();
- return frame;
- }
-
- ShadowFrame* GetTopShadowFrame() const {
- return top_shadow_frame_;
- }
-
- void SetTopShadowFrame(ShadowFrame* top) {
- DCHECK(top_quick_frame_ == nullptr);
- top_shadow_frame_ = top;
- }
-
- static size_t TopShadowFrameOffset() {
- return OFFSETOF_MEMBER(ManagedStack, top_shadow_frame_);
- }
-
- size_t NumJniShadowFrameReferences() const REQUIRES_SHARED(Locks::mutator_lock_);
-
- bool ShadowFramesContain(StackReference<mirror::Object>* shadow_frame_entry) const;
-
- private:
- ArtMethod** top_quick_frame_;
- ManagedStack* link_;
- ShadowFrame* top_shadow_frame_;
-};
-
class StackVisitor {
public:
// This enum defines a flag to control whether inlined frames are included
diff --git a/runtime/thread-current-inl.h b/runtime/thread-current-inl.h
new file mode 100644
index 0000000000..9241b1f875
--- /dev/null
+++ b/runtime/thread-current-inl.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_THREAD_CURRENT_INL_H_
+#define ART_RUNTIME_THREAD_CURRENT_INL_H_
+
+#include "thread.h"
+
+#ifdef ART_TARGET_ANDROID
+#include <bionic_tls.h> // Access to our own TLS slot.
+#endif
+
+#include <pthread.h>
+
+namespace art {
+
+inline Thread* Thread::Current() {
+ // We rely on Thread::Current returning null for a detached thread, so it's not obvious
+ // that we can replace this with a direct %fs access on x86.
+ if (!is_started_) {
+ return nullptr;
+ } else {
+#ifdef ART_TARGET_ANDROID
+ void* thread = __get_tls()[TLS_SLOT_ART_THREAD_SELF];
+#else
+ void* thread = pthread_getspecific(Thread::pthread_key_self_);
+#endif
+ return reinterpret_cast<Thread*>(thread);
+ }
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_THREAD_CURRENT_INL_H_
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 5c65da6d41..7da15d9f4c 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -19,18 +19,13 @@
#include "thread.h"
-#ifdef ART_TARGET_ANDROID
-#include <bionic_tls.h> // Access to our own TLS slot.
-#endif
-
-#include <pthread.h>
-
#include "base/casts.h"
#include "base/mutex-inl.h"
#include "base/time_utils.h"
#include "jni_env_ext.h"
+#include "managed_stack-inl.h"
#include "obj_ptr.h"
-#include "runtime.h"
+#include "thread-current-inl.h"
#include "thread_pool.h"
namespace art {
@@ -41,21 +36,6 @@ static inline Thread* ThreadForEnv(JNIEnv* env) {
return full_env->self;
}
-inline Thread* Thread::Current() {
- // We rely on Thread::Current returning null for a detached thread, so it's not obvious
- // that we can replace this with a direct %fs access on x86.
- if (!is_started_) {
- return nullptr;
- } else {
-#ifdef ART_TARGET_ANDROID
- void* thread = __get_tls()[TLS_SLOT_ART_THREAD_SELF];
-#else
- void* thread = pthread_getspecific(Thread::pthread_key_self_);
-#endif
- return reinterpret_cast<Thread*>(thread);
- }
-}
-
inline void Thread::AllowThreadSuspension() {
DCHECK_EQ(Thread::Current(), this);
if (UNLIKELY(TestAllFlags())) {
@@ -295,12 +275,6 @@ inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
return static_cast<ThreadState>(old_state);
}
-inline void Thread::VerifyStack() {
- if (kVerifyStack) {
- VerifyStackImpl();
- }
-}
-
inline mirror::Object* Thread::AllocTlab(size_t bytes) {
DCHECK_GE(TlabSize(), bytes);
++tlsPtr_.thread_local_objects;
@@ -384,6 +358,14 @@ inline bool Thread::ModifySuspendCount(Thread* self,
}
}
+inline ShadowFrame* Thread::PushShadowFrame(ShadowFrame* new_top_frame) {
+ return tlsPtr_.managed_stack.PushShadowFrame(new_top_frame);
+}
+
+inline ShadowFrame* Thread::PopShadowFrame() {
+ return tlsPtr_.managed_stack.PopShadowFrame();
+}
+
} // namespace art
#endif // ART_RUNTIME_THREAD_INL_H_
diff --git a/runtime/thread.cc b/runtime/thread.cc
index c849a126ae..789f571253 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -55,6 +55,7 @@
#include "gc/allocator/rosalloc.h"
#include "gc/heap.h"
#include "gc/space/space-inl.h"
+#include "gc_root.h"
#include "handle_scope-inl.h"
#include "indirect_reference_table-inl.h"
#include "java_vm_ext.h"
@@ -2160,7 +2161,7 @@ Thread::~Thread() {
TearDownAlternateSignalStack();
}
-void Thread::HandleUncaughtExceptions(ScopedObjectAccess& soa) {
+void Thread::HandleUncaughtExceptions(ScopedObjectAccessAlreadyRunnable& soa) {
if (!IsExceptionPending()) {
return;
}
@@ -2180,7 +2181,7 @@ void Thread::HandleUncaughtExceptions(ScopedObjectAccess& soa) {
tlsPtr_.jni_env->ExceptionClear();
}
-void Thread::RemoveFromThreadGroup(ScopedObjectAccess& soa) {
+void Thread::RemoveFromThreadGroup(ScopedObjectAccessAlreadyRunnable& soa) {
// this.group.removeThread(this);
// group can be null if we're in the compiler or a test.
ObjPtr<mirror::Object> ogroup = jni::DecodeArtField(WellKnownClasses::java_lang_Thread_group)
diff --git a/runtime/thread.h b/runtime/thread.h
index a60fd58ca0..e85ee0d2f3 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -33,15 +33,13 @@
#include "base/mutex.h"
#include "entrypoints/jni/jni_entrypoints.h"
#include "entrypoints/quick/quick_entrypoints.h"
-#include "gc_root.h"
#include "globals.h"
#include "handle_scope.h"
#include "instrumentation.h"
#include "jvalue.h"
-#include "object_callbacks.h"
+#include "managed_stack.h"
#include "offsets.h"
#include "runtime_stats.h"
-#include "stack.h"
#include "thread_state.h"
class BacktraceMap;
@@ -87,12 +85,14 @@ class FrameIdToShadowFrame;
class JavaVMExt;
struct JNIEnvExt;
class Monitor;
+class RootVisitor;
class ScopedObjectAccessAlreadyRunnable;
class ShadowFrame;
class SingleStepControl;
class StackedShadowFrameRecord;
class Thread;
class ThreadList;
+enum VisitRootFlags : uint8_t;
// Thread priorities. These must match the Thread.MIN_PRIORITY,
// Thread.NORM_PRIORITY, and Thread.MAX_PRIORITY constants.
@@ -149,6 +149,7 @@ static constexpr size_t kNumRosAllocThreadLocalSizeBracketsInThread = 16;
class Thread {
public:
static const size_t kStackOverflowImplicitCheckSize;
+ static constexpr bool kVerifyStack = kIsDebugBuild;
// Creates a new native thread corresponding to the given managed peer.
// Used to implement Thread.start.
@@ -560,10 +561,14 @@ class Thread {
return tlsPtr_.frame_id_to_shadow_frame != nullptr;
}
- void VisitRoots(RootVisitor* visitor, VisitRootFlags flags = kVisitRootFlagAllRoots)
+ void VisitRoots(RootVisitor* visitor, VisitRootFlags flags)
REQUIRES_SHARED(Locks::mutator_lock_);
- ALWAYS_INLINE void VerifyStack() REQUIRES_SHARED(Locks::mutator_lock_);
+ void VerifyStack() REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (kVerifyStack) {
+ VerifyStackImpl();
+ }
+ }
//
// Offsets of various members of native Thread class, used by compiled code.
@@ -793,13 +798,8 @@ class Thread {
tlsPtr_.managed_stack.PopManagedStackFragment(fragment);
}
- ShadowFrame* PushShadowFrame(ShadowFrame* new_top_frame) {
- return tlsPtr_.managed_stack.PushShadowFrame(new_top_frame);
- }
-
- ShadowFrame* PopShadowFrame() {
- return tlsPtr_.managed_stack.PopShadowFrame();
- }
+ ALWAYS_INLINE ShadowFrame* PushShadowFrame(ShadowFrame* new_top_frame);
+ ALWAYS_INLINE ShadowFrame* PopShadowFrame();
template<PointerSize pointer_size>
static ThreadOffset<pointer_size> TopShadowFrameOffset() {
@@ -1250,9 +1250,10 @@ class Thread {
static void* CreateCallback(void* arg);
- void HandleUncaughtExceptions(ScopedObjectAccess& soa)
+ void HandleUncaughtExceptions(ScopedObjectAccessAlreadyRunnable& soa)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ void RemoveFromThreadGroup(ScopedObjectAccessAlreadyRunnable& soa)
REQUIRES_SHARED(Locks::mutator_lock_);
- void RemoveFromThreadGroup(ScopedObjectAccess& soa) REQUIRES_SHARED(Locks::mutator_lock_);
// Initialize a thread.
//
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index ca8f7b648c..95aba79ed7 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -37,6 +37,7 @@
#include "gc/gc_pause_listener.h"
#include "gc/heap.h"
#include "gc/reference_processor.h"
+#include "gc_root.h"
#include "jni_internal.h"
#include "lock_word.h"
#include "monitor.h"
@@ -164,7 +165,7 @@ static void DumpUnattachedThread(std::ostream& os, pid_t tid, bool dump_native_s
if (dump_native_stack) {
DumpNativeStack(os, tid, nullptr, " native: ");
}
- os << "\n";
+ os << std::endl;
}
void ThreadList::DumpUnattachedThreads(std::ostream& os, bool dump_native_stack) {
@@ -215,11 +216,10 @@ class DumpCheckpoint FINAL : public Closure {
ScopedObjectAccess soa(self);
thread->Dump(local_os, dump_native_stack_, backtrace_map_.get());
}
- local_os << "\n";
{
// Use the logging lock to ensure serialization when writing to the common ostream.
MutexLock mu(self, *Locks::logging_lock_);
- *os_ << local_os.str();
+ *os_ << local_os.str() << std::endl;
}
barrier_.Pass(self);
}
@@ -757,7 +757,7 @@ void ThreadList::SuspendAllInternal(Thread* self,
// EAGAIN and EINTR both indicate a spurious failure, try again from the beginning.
if ((errno != EAGAIN) && (errno != EINTR)) {
if (errno == ETIMEDOUT) {
- LOG(::android::base::FATAL)
+ LOG(kIsDebugBuild ? ::android::base::FATAL : ::android::base::ERROR)
<< "Timed out waiting for threads to suspend, waited for "
<< PrettyDuration(NanoTime() - start_time);
} else {
@@ -1509,7 +1509,7 @@ void ThreadList::VisitRootsForSuspendedThreads(RootVisitor* visitor) {
// Visit roots without holding thread_list_lock_ and thread_suspend_count_lock_ to prevent lock
// order violations.
for (Thread* thread : threads_to_visit) {
- thread->VisitRoots(visitor);
+ thread->VisitRoots(visitor, kVisitRootFlagAllRoots);
}
// Restore suspend counts.
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index 0ce1d78382..92702c6498 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -22,9 +22,7 @@
#include "base/mutex.h"
#include "base/time_utils.h"
#include "base/value_object.h"
-#include "gc_root.h"
#include "jni.h"
-#include "object_callbacks.h"
#include <bitset>
#include <list>
@@ -38,8 +36,10 @@ namespace gc {
class GcPauseListener;
} // namespace gc
class Closure;
+class RootVisitor;
class Thread;
class TimingLogger;
+enum VisitRootFlags : uint8_t;
class ThreadList {
public:
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index e051e7647f..8349f33028 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -30,7 +30,7 @@
#include "base/stl_util.h"
#include "base/time_utils.h"
#include "runtime.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 3a9975a4e2..cabd1620a7 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -41,6 +41,7 @@
#include "os.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
+#include "stack.h"
#include "thread.h"
#include "thread_list.h"
#include "utils.h"
@@ -739,7 +740,7 @@ void Trace::FinishTracing() {
}
void Trace::DexPcMoved(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Object* this_object ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
ArtMethod* method,
uint32_t new_dex_pc) {
// We're not recorded to listen to this kind of event, so complain.
@@ -748,7 +749,7 @@ void Trace::DexPcMoved(Thread* thread ATTRIBUTE_UNUSED,
}
void Trace::FieldRead(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Object* this_object ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
ArtMethod* method,
uint32_t dex_pc,
ArtField* field ATTRIBUTE_UNUSED)
@@ -759,7 +760,7 @@ void Trace::FieldRead(Thread* thread ATTRIBUTE_UNUSED,
}
void Trace::FieldWritten(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Object* this_object ATTRIBUTE_UNUSED,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
ArtMethod* method,
uint32_t dex_pc,
ArtField* field ATTRIBUTE_UNUSED,
@@ -770,8 +771,10 @@ void Trace::FieldWritten(Thread* thread ATTRIBUTE_UNUSED,
<< " " << dex_pc;
}
-void Trace::MethodEntered(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED,
- ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED) {
+void Trace::MethodEntered(Thread* thread,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
+ ArtMethod* method,
+ uint32_t dex_pc ATTRIBUTE_UNUSED) {
uint32_t thread_clock_diff = 0;
uint32_t wall_clock_diff = 0;
ReadClocks(thread, &thread_clock_diff, &wall_clock_diff);
@@ -779,8 +782,10 @@ void Trace::MethodEntered(Thread* thread, mirror::Object* this_object ATTRIBUTE_
thread_clock_diff, wall_clock_diff);
}
-void Trace::MethodExited(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED,
- ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED,
+void Trace::MethodExited(Thread* thread,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
+ ArtMethod* method,
+ uint32_t dex_pc ATTRIBUTE_UNUSED,
const JValue& return_value ATTRIBUTE_UNUSED) {
uint32_t thread_clock_diff = 0;
uint32_t wall_clock_diff = 0;
@@ -789,8 +794,10 @@ void Trace::MethodExited(Thread* thread, mirror::Object* this_object ATTRIBUTE_U
thread_clock_diff, wall_clock_diff);
}
-void Trace::MethodUnwind(Thread* thread, mirror::Object* this_object ATTRIBUTE_UNUSED,
- ArtMethod* method, uint32_t dex_pc ATTRIBUTE_UNUSED) {
+void Trace::MethodUnwind(Thread* thread,
+ Handle<mirror::Object> this_object ATTRIBUTE_UNUSED,
+ ArtMethod* method,
+ uint32_t dex_pc ATTRIBUTE_UNUSED) {
uint32_t thread_clock_diff = 0;
uint32_t wall_clock_diff = 0;
ReadClocks(thread, &thread_clock_diff, &wall_clock_diff);
@@ -799,7 +806,7 @@ void Trace::MethodUnwind(Thread* thread, mirror::Object* this_object ATTRIBUTE_U
}
void Trace::ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED,
- mirror::Throwable* exception_object ATTRIBUTE_UNUSED)
+ Handle<mirror::Throwable> exception_object ATTRIBUTE_UNUSED)
REQUIRES_SHARED(Locks::mutator_lock_) {
LOG(ERROR) << "Unexpected exception caught event in tracing";
}
@@ -811,7 +818,7 @@ void Trace::Branch(Thread* /*thread*/, ArtMethod* method,
}
void Trace::InvokeVirtualOrInterface(Thread*,
- mirror::Object*,
+ Handle<mirror::Object>,
ArtMethod* method,
uint32_t dex_pc,
ArtMethod*) {
diff --git a/runtime/trace.h b/runtime/trace.h
index 485e9a133a..ad1025045c 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -140,36 +140,54 @@ class Trace FINAL : public instrumentation::InstrumentationListener {
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_, !*streaming_lock_);
// InstrumentationListener implementation.
- void MethodEntered(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc)
+ void MethodEntered(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_, !*streaming_lock_)
OVERRIDE;
- void MethodExited(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc,
+ void MethodExited(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
const JValue& return_value)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_, !*streaming_lock_)
OVERRIDE;
- void MethodUnwind(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc)
+ void MethodUnwind(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_, !*streaming_lock_)
OVERRIDE;
- void DexPcMoved(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t new_dex_pc)
+ void DexPcMoved(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t new_dex_pc)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_, !*streaming_lock_)
OVERRIDE;
- void FieldRead(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc, ArtField* field)
+ void FieldRead(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ ArtField* field)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_) OVERRIDE;
- void FieldWritten(Thread* thread, mirror::Object* this_object,
- ArtMethod* method, uint32_t dex_pc, ArtField* field,
+ void FieldWritten(Thread* thread,
+ Handle<mirror::Object> this_object,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ ArtField* field,
const JValue& field_value)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_) OVERRIDE;
- void ExceptionCaught(Thread* thread, mirror::Throwable* exception_object)
+ void ExceptionCaught(Thread* thread,
+ Handle<mirror::Throwable> exception_object)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_) OVERRIDE;
- void Branch(Thread* thread, ArtMethod* method, uint32_t dex_pc, int32_t dex_pc_offset)
+ void Branch(Thread* thread,
+ ArtMethod* method,
+ uint32_t dex_pc,
+ int32_t dex_pc_offset)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_) OVERRIDE;
void InvokeVirtualOrInterface(Thread* thread,
- mirror::Object* this_object,
+ Handle<mirror::Object> this_object,
ArtMethod* caller,
uint32_t dex_pc,
ArtMethod* callee)
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
index 56ff0a13ac..907d37ef31 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -19,8 +19,10 @@
#include "base/stl_util.h"
#include "base/logging.h"
#include "gc/accounting/card_table-inl.h"
+#include "gc_root-inl.h"
#include "intern_table.h"
#include "mirror/class-inl.h"
+#include "mirror/dex_cache-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
diff --git a/runtime/transaction.h b/runtime/transaction.h
index 921de03754..747c2d0f38 100644
--- a/runtime/transaction.h
+++ b/runtime/transaction.h
@@ -22,7 +22,6 @@
#include "base/value_object.h"
#include "dex_file_types.h"
#include "gc_root.h"
-#include "object_callbacks.h"
#include "offsets.h"
#include "primitive.h"
#include "safe_map.h"
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 7490611cb6..12f791c1f1 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -50,6 +50,7 @@
#include "register_line-inl.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
+#include "stack.h"
#include "utils.h"
#include "verifier_deps.h"
#include "verifier_compiler_binding.h"
@@ -883,10 +884,13 @@ bool MethodVerifier::Verify() {
InstructionFlags());
// Run through the instructions and see if the width checks out.
bool result = ComputeWidthsAndCountOps();
+ bool allow_runtime_only_instructions = !Runtime::Current()->IsAotCompiler() || verify_to_dump_;
// Flag instructions guarded by a "try" block and check exception handlers.
result = result && ScanTryCatchBlocks();
// Perform static instruction verification.
- result = result && VerifyInstructions();
+ result = result && (allow_runtime_only_instructions
+ ? VerifyInstructions<true>()
+ : VerifyInstructions<false>());
// Perform code-flow analysis and return.
result = result && VerifyCodeFlow();
@@ -1102,6 +1106,7 @@ bool MethodVerifier::ScanTryCatchBlocks() {
return true;
}
+template <bool kAllowRuntimeOnlyInstructions>
bool MethodVerifier::VerifyInstructions() {
const Instruction* inst = Instruction::At(code_item_->insns_);
@@ -1110,9 +1115,8 @@ bool MethodVerifier::VerifyInstructions() {
GetInstructionFlags(0).SetCompileTimeInfoPoint();
uint32_t insns_size = code_item_->insns_size_in_code_units_;
- bool allow_runtime_only_instructions = !Runtime::Current()->IsAotCompiler() || verify_to_dump_;
for (uint32_t dex_pc = 0; dex_pc < insns_size;) {
- if (!VerifyInstruction(inst, dex_pc, allow_runtime_only_instructions)) {
+ if (!VerifyInstruction<kAllowRuntimeOnlyInstructions>(inst, dex_pc)) {
DCHECK_NE(failures_.size(), 0U);
return false;
}
@@ -1139,9 +1143,8 @@ bool MethodVerifier::VerifyInstructions() {
return true;
}
-bool MethodVerifier::VerifyInstruction(const Instruction* inst,
- uint32_t code_offset,
- bool allow_runtime_only_instructions) {
+template <bool kAllowRuntimeOnlyInstructions>
+bool MethodVerifier::VerifyInstruction(const Instruction* inst, uint32_t code_offset) {
if (Instruction::kHaveExperimentalInstructions && UNLIKELY(inst->IsExperimental())) {
// Experimental instructions don't yet have verifier support implementation.
// While it is possible to use them by themselves, when we try to use stable instructions
@@ -1250,7 +1253,7 @@ bool MethodVerifier::VerifyInstruction(const Instruction* inst,
result = false;
break;
}
- if (!allow_runtime_only_instructions && inst->GetVerifyIsRuntimeOnly()) {
+ if (!kAllowRuntimeOnlyInstructions && inst->GetVerifyIsRuntimeOnly()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "opcode only expected at runtime " << inst->Name();
result = false;
}
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 9ef98f70e4..cb208f44a5 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -360,6 +360,7 @@ class MethodVerifier {
*
* Walks through instructions in a method calling VerifyInstruction on each.
*/
+ template <bool kAllowRuntimeOnlyInstructions>
bool VerifyInstructions();
/*
@@ -395,9 +396,8 @@ class MethodVerifier {
* - (earlier) for each exception handler, the handler must start at a valid
* instruction
*/
- bool VerifyInstruction(const Instruction* inst,
- uint32_t code_offset,
- bool allow_runtime_only_instructions);
+ template <bool kAllowRuntimeOnlyInstructions>
+ bool VerifyInstruction(const Instruction* inst, uint32_t code_offset);
/* Ensure that the register index is valid for this code item. */
bool CheckRegisterIndex(uint32_t idx);
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index 25baac5094..6c01a7982a 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -30,7 +30,6 @@
#include "gc_root.h"
#include "handle_scope.h"
#include "obj_ptr.h"
-#include "object_callbacks.h"
#include "primitive.h"
namespace art {
diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc
index 49dac26bb4..b0ea6c857c 100644
--- a/runtime/verifier/reg_type_test.cc
+++ b/runtime/verifier/reg_type_test.cc
@@ -25,7 +25,7 @@
#include "reg_type_cache-inl.h"
#include "reg_type-inl.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace verifier {
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index 70ce0c4a29..43eb948c64 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -23,6 +23,7 @@
#include "base/array_ref.h"
#include "base/mutex.h"
+#include "dex_file_types.h"
#include "handle.h"
#include "method_resolution_kind.h"
#include "obj_ptr.h"
diff --git a/runtime/verify_object.h b/runtime/verify_object.h
index 519f7f5f5a..e4c01d0f78 100644
--- a/runtime/verify_object.h
+++ b/runtime/verify_object.h
@@ -48,7 +48,6 @@ enum VerifyObjectFlags {
kVerifyAll = kVerifyThis | kVerifyReads | kVerifyWrites,
};
-static constexpr bool kVerifyStack = kIsDebugBuild;
static constexpr VerifyObjectFlags kDefaultVerifyFlags = kVerifyNone;
static constexpr VerifyObjectMode kVerifyObjectSupport =
kDefaultVerifyFlags != 0 ? kVerifyObjectModeFast : kVerifyObjectModeDisabled;
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 5aef062728..24f194b5ee 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -30,7 +30,7 @@
#include "obj_ptr-inl.h"
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/test/003-omnibus-opcodes/src/Main.java b/test/003-omnibus-opcodes/src/Main.java
index a30ec15c66..4e1ffe2fde 100644
--- a/test/003-omnibus-opcodes/src/Main.java
+++ b/test/003-omnibus-opcodes/src/Main.java
@@ -67,7 +67,7 @@ public class Main {
} catch (Throwable th) {
// We and the RI throw ClassNotFoundException, but that isn't declared so javac
// won't let us try to catch it.
- th.printStackTrace();
+ th.printStackTrace(System.out);
}
InternedString.run();
GenSelect.run();
diff --git a/test/008-exceptions/src/Main.java b/test/008-exceptions/src/Main.java
index 74af00ccf7..89fe016856 100644
--- a/test/008-exceptions/src/Main.java
+++ b/test/008-exceptions/src/Main.java
@@ -155,7 +155,7 @@ public class Main {
} catch (BadError e) {
System.out.println(e);
} catch (Throwable t) {
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
try {
// Before splitting mirror::Class::kStatusError into
@@ -171,11 +171,11 @@ public class Main {
throw new IllegalStateException("Should not reach here.");
} catch (NoClassDefFoundError ncdfe) {
if (!(ncdfe.getCause() instanceof BadError)) {
- ncdfe.getCause().printStackTrace();
+ ncdfe.getCause().printStackTrace(System.out);
}
} catch (VerifyError e) {
} catch (Throwable t) {
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
}
@@ -186,7 +186,7 @@ public class Main {
} catch (Error e) {
System.out.println(e);
} catch (Throwable t) {
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
// Before splitting mirror::Class::kStatusError into
// kStatusErrorUnresolved and kStatusErrorResolved,
@@ -200,7 +200,7 @@ public class Main {
System.out.println(ncdfe);
System.out.println(" cause: " + ncdfe.getCause());
} catch (Throwable t) {
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
try {
MultiDexBadInitWrapper2.setDummy(1);
@@ -209,7 +209,7 @@ public class Main {
System.out.println(ncdfe);
System.out.println(" cause: " + ncdfe.getCause());
} catch (Throwable t) {
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
}
}
diff --git a/test/023-many-interfaces/src/ManyInterfaces.java b/test/023-many-interfaces/src/ManyInterfaces.java
index d69a490f67..8ec4566802 100644
--- a/test/023-many-interfaces/src/ManyInterfaces.java
+++ b/test/023-many-interfaces/src/ManyInterfaces.java
@@ -355,7 +355,7 @@ public class ManyInterfaces
static void testInstance001(Object obj, int count) {
if (!(obj instanceof Interface001))
- System.err.println("BAD");
+ System.out.println("BAD");
while (count-- != 0) {
boolean is;
is = obj instanceof Interface001;
@@ -379,7 +379,7 @@ public class ManyInterfaces
static void testInstance049(Object obj, int count) {
if (!(obj instanceof Interface049))
- System.err.println("BAD");
+ System.out.println("BAD");
while (count-- != 0) {
boolean is;
is = obj instanceof Interface049;
@@ -403,7 +403,7 @@ public class ManyInterfaces
static void testInstance099(Object obj, int count) {
if (!(obj instanceof Interface099))
- System.err.println("BAD");
+ System.out.println("BAD");
while (count-- != 0) {
boolean is;
is = obj instanceof Interface099;
diff --git a/test/024-illegal-access/src/Main.java b/test/024-illegal-access/src/Main.java
index 84c7114cb4..de9ad5b694 100644
--- a/test/024-illegal-access/src/Main.java
+++ b/test/024-illegal-access/src/Main.java
@@ -18,7 +18,7 @@ public class Main {
static public void main(String[] args) {
try {
PublicAccess.accessStaticField();
- System.err.println("ERROR: call 1 not expected to succeed");
+ System.out.println("ERROR: call 1 not expected to succeed");
} catch (VerifyError ve) {
// dalvik
System.out.println("Got expected failure 1");
@@ -29,7 +29,7 @@ public class Main {
try {
PublicAccess.accessStaticMethod();
- System.err.println("ERROR: call 2 not expected to succeed");
+ System.out.println("ERROR: call 2 not expected to succeed");
} catch (IllegalAccessError iae) {
// reference
System.out.println("Got expected failure 2");
@@ -37,7 +37,7 @@ public class Main {
try {
PublicAccess.accessInstanceField();
- System.err.println("ERROR: call 3 not expected to succeed");
+ System.out.println("ERROR: call 3 not expected to succeed");
} catch (VerifyError ve) {
// dalvik
System.out.println("Got expected failure 3");
@@ -48,7 +48,7 @@ public class Main {
try {
PublicAccess.accessInstanceMethod();
- System.err.println("ERROR: call 4 not expected to succeed");
+ System.out.println("ERROR: call 4 not expected to succeed");
} catch (IllegalAccessError iae) {
// reference
System.out.println("Got expected failure 4");
@@ -56,7 +56,7 @@ public class Main {
try {
CheckInstanceof.main(new Object());
- System.err.println("ERROR: call 5 not expected to succeed");
+ System.out.println("ERROR: call 5 not expected to succeed");
} catch (VerifyError ve) {
// dalvik
System.out.println("Got expected failure 5");
diff --git a/test/031-class-attributes/src/ClassAttrs.java b/test/031-class-attributes/src/ClassAttrs.java
index 39e69a3066..8489a2c222 100644
--- a/test/031-class-attributes/src/ClassAttrs.java
+++ b/test/031-class-attributes/src/ClassAttrs.java
@@ -133,12 +133,12 @@ public class ClassAttrs {
System.out.println("field signature: "
+ getSignatureAttribute(field));
} catch (NoSuchMethodException nsme) {
- System.err.println("FAILED: " + nsme);
+ System.out.println("FAILED: " + nsme);
} catch (NoSuchFieldException nsfe) {
- System.err.println("FAILED: " + nsfe);
+ System.out.println("FAILED: " + nsfe);
} catch (RuntimeException re) {
- System.err.println("FAILED: " + re);
- re.printStackTrace();
+ System.out.println("FAILED: " + re);
+ re.printStackTrace(System.out);
}
test_isAssignableFrom();
@@ -228,7 +228,7 @@ public class ClassAttrs {
method = c.getDeclaredMethod("getSignatureAttribute");
method.setAccessible(true);
} catch (Exception ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
return "<unknown>";
}
diff --git a/test/032-concrete-sub/src/ConcreteSub.java b/test/032-concrete-sub/src/ConcreteSub.java
index 95adf63c37..61d1602492 100644
--- a/test/032-concrete-sub/src/ConcreteSub.java
+++ b/test/032-concrete-sub/src/ConcreteSub.java
@@ -45,7 +45,7 @@ public class ConcreteSub extends AbstractBase {
try {
meth = absClass.getMethod("redefineMe");
} catch (NoSuchMethodException nsme) {
- nsme.printStackTrace();
+ nsme.printStackTrace(System.out);
return;
}
System.out.println("meth modifiers=" + meth.getModifiers());
diff --git a/test/032-concrete-sub/src/Main.java b/test/032-concrete-sub/src/Main.java
index 4a5193d635..7d3be1525d 100644
--- a/test/032-concrete-sub/src/Main.java
+++ b/test/032-concrete-sub/src/Main.java
@@ -26,7 +26,7 @@ public class Main {
ConcreteSub2 blah = new ConcreteSub2();
// other VMs fail here (AbstractMethodError)
blah.doStuff();
- System.err.println("Succeeded unexpectedly");
+ System.out.println("Succeeded unexpectedly");
} catch (VerifyError ve) {
System.out.println("Got expected failure");
} catch (AbstractMethodError ame) {
diff --git a/test/036-finalizer/src/Main.java b/test/036-finalizer/src/Main.java
index 0de56f9a7c..734830f7de 100644
--- a/test/036-finalizer/src/Main.java
+++ b/test/036-finalizer/src/Main.java
@@ -120,7 +120,7 @@ public class Main {
static void printNonFinalized() {
for (int i = 0; i < maxCount; ++i) {
if (!FinalizeCounter.finalized[i]) {
- System.err.println("Element " + i + " was not finalized");
+ System.out.println("Element " + i + " was not finalized");
}
}
}
diff --git a/test/042-new-instance/src/Main.java b/test/042-new-instance/src/Main.java
index 755d62ebb5..34d1f5a68d 100644
--- a/test/042-new-instance/src/Main.java
+++ b/test/042-new-instance/src/Main.java
@@ -37,31 +37,31 @@ public class Main {
Object obj = c.newInstance();
System.out.println("LocalClass succeeded");
} catch (Exception ex) {
- System.err.println("LocalClass failed");
- ex.printStackTrace();
+ System.out.println("LocalClass failed");
+ ex.printStackTrace(System.out);
}
// should fail
try {
Class<?> c = Class.forName("otherpackage.PackageAccess");
Object obj = c.newInstance();
- System.err.println("ERROR: PackageAccess succeeded unexpectedly");
+ System.out.println("ERROR: PackageAccess succeeded unexpectedly");
} catch (IllegalAccessException iae) {
System.out.println("Got expected PackageAccess complaint");
} catch (Exception ex) {
- System.err.println("Got unexpected PackageAccess failure");
- ex.printStackTrace();
+ System.out.println("Got unexpected PackageAccess failure");
+ ex.printStackTrace(System.out);
}
LocalClass3.main();
try {
MaybeAbstract ma = new MaybeAbstract();
- System.err.println("ERROR: MaybeAbstract succeeded unexpectedly");
+ System.out.println("ERROR: MaybeAbstract succeeded unexpectedly");
} catch (InstantiationError ie) {
System.out.println("Got expected InstantationError");
} catch (Exception ex) {
- System.err.println("Got unexpected MaybeAbstract failure");
+ System.out.println("Got unexpected MaybeAbstract failure");
}
}
@@ -73,12 +73,12 @@ public class Main {
try {
Class<?> c = Class.forName("LocalClass");
Constructor<?> cons = c.getConstructor();
- System.err.println("Cons LocalClass succeeded unexpectedly");
+ System.out.println("Cons LocalClass succeeded unexpectedly");
} catch (NoSuchMethodException nsme) {
System.out.println("Cons LocalClass failed as expected");
} catch (Exception ex) {
- System.err.println("Cons LocalClass failed strangely");
- ex.printStackTrace();
+ System.out.println("Cons LocalClass failed strangely");
+ ex.printStackTrace(System.out);
}
// should succeed
@@ -88,8 +88,8 @@ public class Main {
Object obj = cons.newInstance();
System.out.println("Cons LocalClass2 succeeded");
} catch (Exception ex) {
- System.err.println("Cons LocalClass2 failed");
- ex.printStackTrace();
+ System.out.println("Cons LocalClass2 failed");
+ ex.printStackTrace(System.out);
}
// should succeed
@@ -99,8 +99,8 @@ public class Main {
Object obj = cons.newInstance(new Main());
System.out.println("Cons InnerClass succeeded");
} catch (Exception ex) {
- System.err.println("Cons InnerClass failed");
- ex.printStackTrace();
+ System.out.println("Cons InnerClass failed");
+ ex.printStackTrace(System.out);
}
// should succeed
@@ -110,21 +110,21 @@ public class Main {
Object obj = cons.newInstance();
System.out.println("Cons StaticInnerClass succeeded");
} catch (Exception ex) {
- System.err.println("Cons StaticInnerClass failed");
- ex.printStackTrace();
+ System.out.println("Cons StaticInnerClass failed");
+ ex.printStackTrace(System.out);
}
// should fail
try {
Class<?> c = Class.forName("otherpackage.PackageAccess");
Constructor<?> cons = c.getConstructor();
- System.err.println("ERROR: Cons PackageAccess succeeded unexpectedly");
+ System.out.println("ERROR: Cons PackageAccess succeeded unexpectedly");
} catch (NoSuchMethodException nsme) {
// constructor isn't public
System.out.println("Cons got expected PackageAccess complaint");
} catch (Exception ex) {
- System.err.println("Cons got unexpected PackageAccess failure");
- ex.printStackTrace();
+ System.out.println("Cons got unexpected PackageAccess failure");
+ ex.printStackTrace(System.out);
}
// should fail
@@ -132,13 +132,13 @@ public class Main {
Class<?> c = Class.forName("MaybeAbstract");
Constructor<?> cons = c.getConstructor();
Object obj = cons.newInstance();
- System.err.println("ERROR: Cons MaybeAbstract succeeded unexpectedly");
+ System.out.println("ERROR: Cons MaybeAbstract succeeded unexpectedly");
} catch (InstantiationException ie) {
// note InstantiationException vs. InstantiationError
System.out.println("Cons got expected InstantationException");
} catch (Exception ex) {
- System.err.println("Cons got unexpected MaybeAbstract failure");
- ex.printStackTrace();
+ System.out.println("Cons got unexpected MaybeAbstract failure");
+ ex.printStackTrace(System.out);
}
// should fail
@@ -147,13 +147,13 @@ public class Main {
Constructor<?> cons = c.getConstructor();
if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
Object obj = cons.newInstance();
- System.err.println("ERROR: Cons PackageAccess2 succeeded unexpectedly");
+ System.out.println("ERROR: Cons PackageAccess2 succeeded unexpectedly");
} catch (IllegalAccessException iae) {
// constructor is public, but class has package scope
System.out.println("Cons got expected PackageAccess2 complaint");
} catch (Exception ex) {
- System.err.println("Cons got unexpected PackageAccess2 failure");
- ex.printStackTrace();
+ System.out.println("Cons got unexpected PackageAccess2 failure");
+ ex.printStackTrace(System.out);
}
// should succeed
@@ -161,8 +161,8 @@ public class Main {
otherpackage.ConstructorAccess.newConstructorInstance();
System.out.println("Cons ConstructorAccess succeeded");
} catch (Exception ex) {
- System.err.println("Cons ConstructorAccess failed");
- ex.printStackTrace();
+ System.out.println("Cons ConstructorAccess failed");
+ ex.printStackTrace(System.out);
}
}
@@ -187,8 +187,8 @@ class LocalClass3 {
CC.newInstance();
System.out.println("LocalClass3 succeeded");
} catch (Exception ex) {
- System.err.println("Got unexpected LocalClass3 failure");
- ex.printStackTrace();
+ System.out.println("Got unexpected LocalClass3 failure");
+ ex.printStackTrace(System.out);
}
}
@@ -200,7 +200,7 @@ class LocalClass3 {
Class<?> c = CC.class;
return c.newInstance();
} catch (Exception ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
return null;
}
}
diff --git a/test/044-proxy/src/BasicTest.java b/test/044-proxy/src/BasicTest.java
index 5f04b9344c..7f301f667b 100644
--- a/test/044-proxy/src/BasicTest.java
+++ b/test/044-proxy/src/BasicTest.java
@@ -34,9 +34,9 @@ public class BasicTest {
Object proxy = createProxy(proxyMe);
if (!Proxy.isProxyClass(proxy.getClass()))
- System.err.println("not a proxy class?");
+ System.out.println("not a proxy class?");
if (Proxy.getInvocationHandler(proxy) == null)
- System.err.println("ERROR: Proxy.getInvocationHandler is null");
+ System.out.println("ERROR: Proxy.getInvocationHandler is null");
/* take it for a spin; verifies instanceof constraint */
Shapes shapes = (Shapes) proxy;
@@ -110,13 +110,13 @@ public class BasicTest {
//System.out.println("Constructor is " + cons);
proxy = cons.newInstance(handler);
} catch (NoSuchMethodException nsme) {
- System.err.println("failed: " + nsme);
+ System.out.println("failed: " + nsme);
} catch (InstantiationException ie) {
- System.err.println("failed: " + ie);
+ System.out.println("failed: " + ie);
} catch (IllegalAccessException ie) {
- System.err.println("failed: " + ie);
+ System.out.println("failed: " + ie);
} catch (InvocationTargetException ite) {
- System.err.println("failed: " + ite);
+ System.out.println("failed: " + ite);
}
return proxy;
diff --git a/test/044-proxy/src/Clash.java b/test/044-proxy/src/Clash.java
index d000112fb6..7dabe927b0 100644
--- a/test/044-proxy/src/Clash.java
+++ b/test/044-proxy/src/Clash.java
@@ -32,7 +32,7 @@ public class Clash {
Proxy.newProxyInstance(Clash.class.getClassLoader(),
new Class<?>[] { Interface1A.class, Interface1A.class },
handler);
- System.err.println("Dupe did not throw expected exception");
+ System.out.println("Dupe did not throw expected exception");
} catch (IllegalArgumentException iae) {
System.out.println("Dupe threw expected exception");
}
@@ -41,7 +41,7 @@ public class Clash {
Proxy.newProxyInstance(Clash.class.getClassLoader(),
new Class<?>[] { Interface1A.class, Interface1B.class },
handler);
- System.err.println("Clash did not throw expected exception");
+ System.out.println("Clash did not throw expected exception");
} catch (IllegalArgumentException iae) {
System.out.println("Clash threw expected exception");
}
diff --git a/test/044-proxy/src/Clash2.java b/test/044-proxy/src/Clash2.java
index e405cfea03..51221f2656 100644
--- a/test/044-proxy/src/Clash2.java
+++ b/test/044-proxy/src/Clash2.java
@@ -31,7 +31,7 @@ public class Clash2 {
Proxy.newProxyInstance(Clash.class.getClassLoader(),
new Class<?>[] { Interface2A.class, Interface2B.class },
handler);
- System.err.println("Clash2 did not throw expected exception");
+ System.out.println("Clash2 did not throw expected exception");
} catch (IllegalArgumentException iae) {
System.out.println("Clash2 threw expected exception");
}
diff --git a/test/044-proxy/src/Clash3.java b/test/044-proxy/src/Clash3.java
index 44806cee7d..9d23059b9c 100644
--- a/test/044-proxy/src/Clash3.java
+++ b/test/044-proxy/src/Clash3.java
@@ -35,7 +35,7 @@ public class Clash3 {
Interface3aa.class,
Interface3b.class },
handler);
- System.err.println("Clash3 did not throw expected exception");
+ System.out.println("Clash3 did not throw expected exception");
} catch (IllegalArgumentException iae) {
System.out.println("Clash3 threw expected exception");
}
diff --git a/test/044-proxy/src/Clash4.java b/test/044-proxy/src/Clash4.java
index ca5c3ab6e6..45d48208e1 100644
--- a/test/044-proxy/src/Clash4.java
+++ b/test/044-proxy/src/Clash4.java
@@ -36,7 +36,7 @@ public class Clash4 {
Interface4b.class,
Interface4bb.class },
handler);
- System.err.println("Clash4 did not throw expected exception");
+ System.out.println("Clash4 did not throw expected exception");
} catch (IllegalArgumentException iae) {
System.out.println("Clash4 threw expected exception");
//System.out.println(iae);
diff --git a/test/044-proxy/src/ConstructorProxy.java b/test/044-proxy/src/ConstructorProxy.java
index 95d150cbbd..dfafbd804a 100644
--- a/test/044-proxy/src/ConstructorProxy.java
+++ b/test/044-proxy/src/ConstructorProxy.java
@@ -28,7 +28,7 @@ class ConstructorProxy implements InvocationHandler {
new ConstructorProxy().runTest();
} catch (Exception e) {
System.out.println("Unexpected failure occured");
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
diff --git a/test/044-proxy/src/WrappedThrow.java b/test/044-proxy/src/WrappedThrow.java
index 643ba053b9..afea26d5d5 100644
--- a/test/044-proxy/src/WrappedThrow.java
+++ b/test/044-proxy/src/WrappedThrow.java
@@ -43,29 +43,29 @@ public class WrappedThrow {
InterfaceW2 if2 = (InterfaceW2) proxy;
try {
if1.throwFunky();
- System.err.println("No exception thrown");
+ System.out.println("No exception thrown");
} catch (UndeclaredThrowableException ute) {
System.out.println("Got expected UTE");
} catch (Throwable t) {
- System.err.println("Got unexpected exception: " + t);
+ System.out.println("Got unexpected exception: " + t);
}
try {
if1.throwFunky2();
- System.err.println("No exception thrown");
+ System.out.println("No exception thrown");
} catch (IOException ioe) {
System.out.println("Got expected IOE");
} catch (Throwable t) {
- System.err.println("Got unexpected exception: " + t);
+ System.out.println("Got unexpected exception: " + t);
}
try {
if2.throwFunky2();
- System.err.println("No exception thrown");
+ System.out.println("No exception thrown");
} catch (IOException ioe) {
System.out.println("Got expected IOE");
} catch (Throwable t) {
- System.err.println("Got unexpected exception: " + t);
+ System.out.println("Got unexpected exception: " + t);
}
/*
@@ -73,38 +73,38 @@ public class WrappedThrow {
*/
try {
if1.throwException();
- System.err.println("No exception thrown");
+ System.out.println("No exception thrown");
} catch (UndeclaredThrowableException ute) {
System.out.println("Got expected UTE");
} catch (Throwable t) {
- System.err.println("Got unexpected exception: " + t);
+ System.out.println("Got unexpected exception: " + t);
}
try {
if1.throwBase();
- System.err.println("No exception thrown");
+ System.out.println("No exception thrown");
} catch (UndeclaredThrowableException ute) {
System.out.println("Got expected UTE");
} catch (Throwable t) {
- System.err.println("Got unexpected exception: " + t);
+ System.out.println("Got unexpected exception: " + t);
}
try {
if2.throwSub();
- System.err.println("No exception thrown");
+ System.out.println("No exception thrown");
} catch (SubException se) {
System.out.println("Got expected exception");
} catch (Throwable t) {
- System.err.println("Got unexpected exception: " + t);
+ System.out.println("Got unexpected exception: " + t);
}
try {
if2.throwSubSub();
- System.err.println("No exception thrown");
+ System.out.println("No exception thrown");
} catch (SubException se) {
System.out.println("Got expected exception");
} catch (Throwable t) {
- System.err.println("Got unexpected exception: " + t);
+ System.out.println("Got unexpected exception: " + t);
}
/*
@@ -113,11 +113,11 @@ public class WrappedThrow {
*/
try {
if1.bothThrowBase();
- System.err.println("No exception thrown");
+ System.out.println("No exception thrown");
} catch (BaseException se) {
System.out.println("Got expected exception");
} catch (Throwable t) {
- System.err.println("Got unexpected exception: " + t);
+ System.out.println("Got unexpected exception: " + t);
}
}
}
diff --git a/test/045-reflect-array/src/Main.java b/test/045-reflect-array/src/Main.java
index 7418eed824..4c321b3303 100644
--- a/test/045-reflect-array/src/Main.java
+++ b/test/045-reflect-array/src/Main.java
@@ -102,7 +102,7 @@ public class Main {
throw new RuntimeException("load should have worked");
}
} catch (IllegalArgumentException iae) {
- iae.printStackTrace();
+ iae.printStackTrace(System.out);
}
try {
Array.getByte(charArray, 2);
@@ -116,7 +116,7 @@ public class Main {
+ Array.getInt(charArray, 3));
}
} catch (IllegalArgumentException iae) {
- iae.printStackTrace();
+ iae.printStackTrace(System.out);
}
System.out.println("ReflectArrayTest.testSingleChar passed");
diff --git a/test/046-reflect/src/Main.java b/test/046-reflect/src/Main.java
index 10dad8ddac..b8a48ea247 100644
--- a/test/046-reflect/src/Main.java
+++ b/test/046-reflect/src/Main.java
@@ -89,7 +89,7 @@ public class Main {
try {
meth = target.getMethod("packageMethod");
- System.err.println("succeeded on package-scope method");
+ System.out.println("succeeded on package-scope method");
} catch (NoSuchMethodException nsme) {
// good
}
@@ -101,7 +101,7 @@ public class Main {
try {
if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
meth.invoke(instance);
- System.err.println("inner-method invoke unexpectedly worked");
+ System.out.println("inner-method invoke unexpectedly worked");
} catch (IllegalAccessException iae) {
// good
}
@@ -110,13 +110,13 @@ public class Main {
try {
int x = field.getInt(instance);
if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
- System.err.println("field get unexpectedly worked: " + x);
+ System.out.println("field get unexpectedly worked: " + x);
} catch (IllegalAccessException iae) {
// good
}
} catch (Exception ex) {
System.out.println("----- unexpected exception -----");
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
}
@@ -171,7 +171,7 @@ public class Main {
}
catch (Exception ex) {
System.out.println("GLITCH: invoke got wrong exception:");
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
System.out.println("");
@@ -400,7 +400,7 @@ public class Main {
} catch (Exception ex) {
System.out.println("----- unexpected exception -----");
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
System.out.println("ReflectTest done!");
@@ -414,7 +414,7 @@ public class Main {
m = Collections.class.getDeclaredMethod("swap",
Object[].class, int.class, int.class);
} catch (NoSuchMethodException nsme) {
- nsme.printStackTrace();
+ nsme.printStackTrace(System.out);
return;
}
System.out.println(m + " accessible=" + m.isAccessible());
@@ -423,10 +423,10 @@ public class Main {
try {
m.invoke(null, objects, 0, 1);
} catch (IllegalAccessException iae) {
- iae.printStackTrace();
+ iae.printStackTrace(System.out);
return;
} catch (InvocationTargetException ite) {
- ite.printStackTrace();
+ ite.printStackTrace(System.out);
return;
}
@@ -434,10 +434,10 @@ public class Main {
String s = "Should be ignored";
m.invoke(s, objects, 0, 1);
} catch (IllegalAccessException iae) {
- iae.printStackTrace();
+ iae.printStackTrace(System.out);
return;
} catch (InvocationTargetException ite) {
- ite.printStackTrace();
+ ite.printStackTrace(System.out);
return;
}
@@ -449,7 +449,7 @@ public class Main {
} catch (InvocationTargetException ite) {
System.out.println("checkType got expected exception");
} catch (IllegalAccessException iae) {
- iae.printStackTrace();
+ iae.printStackTrace(System.out);
return;
}
}
@@ -826,7 +826,7 @@ class FieldNoisyInit {
static {
System.out.println("FieldNoisyInit is initializing");
//Throwable th = new Throwable();
- //th.printStackTrace();
+ //th.printStackTrace(System.out);
}
}
@@ -842,7 +842,7 @@ class MethodNoisyInit {
static {
System.out.println("MethodNoisyInit is initializing");
//Throwable th = new Throwable();
- //th.printStackTrace();
+ //th.printStackTrace(System.out);
}
}
diff --git a/test/048-reflect-v8/src/DefaultDeclared.java b/test/048-reflect-v8/src/DefaultDeclared.java
index 16e8a24c00..d49bdc91a5 100644
--- a/test/048-reflect-v8/src/DefaultDeclared.java
+++ b/test/048-reflect-v8/src/DefaultDeclared.java
@@ -52,7 +52,7 @@ public class DefaultDeclared {
System.out.println("NoSuchMethodException thrown for class " + klass.toString());
} catch (Throwable t) {
System.out.println("Unknown error thrown for class " + klass.toString());
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
}
diff --git a/test/050-sync-test/src/Main.java b/test/050-sync-test/src/Main.java
index 5364e2aaaa..734b51e811 100644
--- a/test/050-sync-test/src/Main.java
+++ b/test/050-sync-test/src/Main.java
@@ -39,7 +39,7 @@ public class Main {
Thread.sleep(1000);
} catch (InterruptedException ie) {
System.out.println("INTERRUPT!");
- ie.printStackTrace();
+ ie.printStackTrace(System.out);
}
System.out.println("GONE");
}
@@ -56,7 +56,7 @@ public class Main {
one.wait();
} catch (InterruptedException ie) {
System.out.println("INTERRUPT!");
- ie.printStackTrace();
+ ie.printStackTrace(System.out);
}
}
@@ -69,7 +69,7 @@ public class Main {
two.join();
} catch (InterruptedException ie) {
System.out.println("INTERRUPT!");
- ie.printStackTrace();
+ ie.printStackTrace(System.out);
}
System.out.println("main: all done");
}
@@ -167,7 +167,7 @@ class SleepyThread extends Thread {
" interrupted, flag=" + Thread.interrupted());
intr = true;
} catch (Exception ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
if (!intr)
diff --git a/test/050-sync-test/src/ThreadDeathHandler.java b/test/050-sync-test/src/ThreadDeathHandler.java
index 0a7437d307..58061f8d00 100644
--- a/test/050-sync-test/src/ThreadDeathHandler.java
+++ b/test/050-sync-test/src/ThreadDeathHandler.java
@@ -27,7 +27,7 @@ public class ThreadDeathHandler implements Thread.UncaughtExceptionHandler {
}
public void uncaughtException(Thread t, Throwable e) {
- System.err.println("Uncaught exception " + mMyMessage + "!");
- e.printStackTrace();
+ System.out.println("Uncaught exception " + mMyMessage + "!");
+ e.printStackTrace(System.out);
}
}
diff --git a/test/051-thread/src/Main.java b/test/051-thread/src/Main.java
index 08cb5deeac..fe1cafef56 100644
--- a/test/051-thread/src/Main.java
+++ b/test/051-thread/src/Main.java
@@ -79,7 +79,7 @@ public class Main {
try {
t.join();
} catch (InterruptedException ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
System.out.print("testThreadDaemons finished\n");
diff --git a/test/053-wait-some/src/Main.java b/test/053-wait-some/src/Main.java
index 377a5781ea..b8e6dfeeae 100644
--- a/test/053-wait-some/src/Main.java
+++ b/test/053-wait-some/src/Main.java
@@ -39,7 +39,7 @@ public class Main {
} catch (IllegalArgumentException iae) {
System.out.println("Caught expected exception on neg arg");
} catch (InterruptedException ie) {
- ie.printStackTrace();
+ ie.printStackTrace(System.out);
}
for (long delay : DELAYS) {
@@ -49,7 +49,7 @@ public class Main {
try {
sleepy.wait(delay);
} catch (InterruptedException ie) {
- ie.printStackTrace();
+ ie.printStackTrace(System.out);
}
end = System.currentTimeMillis();
diff --git a/test/054-uncaught/src/Main.java b/test/054-uncaught/src/Main.java
index 688a2a4d79..43de7ae258 100644
--- a/test/054-uncaught/src/Main.java
+++ b/test/054-uncaught/src/Main.java
@@ -33,7 +33,7 @@ public class Main {
try {
t.join();
} catch (InterruptedException ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
}
@@ -41,7 +41,7 @@ public class Main {
ThreadDeathHandler defHandler = new ThreadDeathHandler("DEFAULT");
ThreadDeathHandler threadHandler = new ThreadDeathHandler("THREAD");
- System.err.println("Test " + which);
+ System.out.println("Test " + which);
switch (which) {
case 1: {
Thread.setDefaultUncaughtExceptionHandler(defHandler);
diff --git a/test/054-uncaught/src/ThreadDeathHandler.java b/test/054-uncaught/src/ThreadDeathHandler.java
index 0a7437d307..58061f8d00 100644
--- a/test/054-uncaught/src/ThreadDeathHandler.java
+++ b/test/054-uncaught/src/ThreadDeathHandler.java
@@ -27,7 +27,7 @@ public class ThreadDeathHandler implements Thread.UncaughtExceptionHandler {
}
public void uncaughtException(Thread t, Throwable e) {
- System.err.println("Uncaught exception " + mMyMessage + "!");
- e.printStackTrace();
+ System.out.println("Uncaught exception " + mMyMessage + "!");
+ e.printStackTrace(System.out);
}
}
diff --git a/test/059-finalizer-throw/src/Main.java b/test/059-finalizer-throw/src/Main.java
index fa80fe3f7a..3bfbc2d5b6 100644
--- a/test/059-finalizer-throw/src/Main.java
+++ b/test/059-finalizer-throw/src/Main.java
@@ -46,7 +46,7 @@ public class Main {
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
- System.err.println(ie);
+ System.out.println(ie);
}
}
@@ -54,7 +54,7 @@ public class Main {
try {
Thread.sleep(750);
} catch (InterruptedException ie) {
- System.err.println(ie);
+ System.out.println(ie);
}
System.out.println("done");
diff --git a/test/064-field-access/src/Main.java b/test/064-field-access/src/Main.java
index 50ad5b9a20..b08f3ae305 100644
--- a/test/064-field-access/src/Main.java
+++ b/test/064-field-access/src/Main.java
@@ -28,7 +28,7 @@ public class Main {
try {
GetNonexistent.main(null);
- System.err.println("Not expected to succeed");
+ System.out.println("Not expected to succeed");
} catch (VerifyError fe) {
// dalvik
System.out.println("Got expected failure");
@@ -101,22 +101,22 @@ public class Main {
/* success; expected? */
if (expectedException != null) {
- System.err.println("ERROR: call succeeded for field " + field +
+ System.out.println("ERROR: call succeeded for field " + field +
" with a read of type '" + type +
"', was expecting " + expectedException);
Thread.dumpStack();
}
} catch (Exception ex) {
if (expectedException == null) {
- System.err.println("ERROR: call failed unexpectedly: "
+ System.out.println("ERROR: call failed unexpectedly: "
+ ex.getClass());
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
} else {
if (!expectedException.equals(ex.getClass())) {
- System.err.println("ERROR: incorrect exception: wanted "
+ System.out.println("ERROR: incorrect exception: wanted "
+ expectedException.getName() + ", got "
+ ex.getClass());
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
}
}
@@ -675,22 +675,22 @@ class SubClass extends PublicClass {
/* success; expected? */
if (expectedException != null) {
- System.err.println("ERROR: call succeeded for field " + field +
+ System.out.println("ERROR: call succeeded for field " + field +
" with a read of type '" + type +
"', was expecting " + expectedException);
Thread.dumpStack();
}
} catch (Exception ex) {
if (expectedException == null) {
- System.err.println("ERROR: call failed unexpectedly: "
+ System.out.println("ERROR: call failed unexpectedly: "
+ ex.getClass());
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
} else {
if (!expectedException.equals(ex.getClass())) {
- System.err.println("ERROR: incorrect exception: wanted "
+ System.out.println("ERROR: incorrect exception: wanted "
+ expectedException.getName() + ", got "
+ ex.getClass());
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
}
}
@@ -704,19 +704,19 @@ class SubClass extends PublicClass {
result = method.invoke(obj);
/* success; expected? */
if (expectedException != null) {
- System.err.println("ERROR: call succeeded for method " + method + "', was expecting " +
+ System.out.println("ERROR: call succeeded for method " + method + "', was expecting " +
expectedException);
Thread.dumpStack();
}
} catch (Exception ex) {
if (expectedException == null) {
- System.err.println("ERROR: call failed unexpectedly: " + ex.getClass());
- ex.printStackTrace();
+ System.out.println("ERROR: call failed unexpectedly: " + ex.getClass());
+ ex.printStackTrace(System.out);
} else {
if (!expectedException.equals(ex.getClass())) {
- System.err.println("ERROR: incorrect exception: wanted " + expectedException.getName() +
+ System.out.println("ERROR: incorrect exception: wanted " + expectedException.getName() +
", got " + ex.getClass());
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
}
}
diff --git a/test/065-mismatched-implements/src/Main.java b/test/065-mismatched-implements/src/Main.java
index 5975b99e92..55d0babbef 100644
--- a/test/065-mismatched-implements/src/Main.java
+++ b/test/065-mismatched-implements/src/Main.java
@@ -21,7 +21,7 @@ public class Main {
public static void main(String[] args) {
try {
Indirect.main();
- System.err.println("Succeeded unexpectedly");
+ System.out.println("Succeeded unexpectedly");
} catch (IncompatibleClassChangeError icce) {
System.out.println("Got expected ICCE");
}
diff --git a/test/066-mismatched-super/src/Main.java b/test/066-mismatched-super/src/Main.java
index 5975b99e92..55d0babbef 100644
--- a/test/066-mismatched-super/src/Main.java
+++ b/test/066-mismatched-super/src/Main.java
@@ -21,7 +21,7 @@ public class Main {
public static void main(String[] args) {
try {
Indirect.main();
- System.err.println("Succeeded unexpectedly");
+ System.out.println("Succeeded unexpectedly");
} catch (IncompatibleClassChangeError icce) {
System.out.println("Got expected ICCE");
}
diff --git a/test/068-classloader/src/Main.java b/test/068-classloader/src/Main.java
index 01539b7172..0aaa1528c0 100644
--- a/test/068-classloader/src/Main.java
+++ b/test/068-classloader/src/Main.java
@@ -129,7 +129,7 @@ public class Main {
throw new RuntimeException("target 2 has unexpected value " + value);
}
} catch (Exception ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
}
@@ -153,8 +153,8 @@ public class Main {
try {
altClass = loader.loadClass("Inaccessible1");
} catch (ClassNotFoundException cnfe) {
- System.err.println("loadClass failed");
- cnfe.printStackTrace();
+ System.out.println("loadClass failed");
+ cnfe.printStackTrace(System.out);
return;
}
@@ -162,9 +162,9 @@ public class Main {
Object obj;
try {
obj = altClass.newInstance();
- System.err.println("ERROR: Inaccessible1 was accessible");
+ System.out.println("ERROR: Inaccessible1 was accessible");
} catch (InstantiationException ie) {
- System.err.println("newInstance failed: " + ie);
+ System.out.println("newInstance failed: " + ie);
return;
} catch (IllegalAccessException iae) {
System.out.println("Got expected access exception #1");
@@ -182,14 +182,14 @@ public class Main {
try {
altClass = loader.loadClass("Inaccessible2");
- System.err.println("ERROR: Inaccessible2 was accessible: " + altClass);
+ System.out.println("ERROR: Inaccessible2 was accessible: " + altClass);
} catch (ClassNotFoundException cnfe) {
Throwable cause = cnfe.getCause();
if (cause instanceof IllegalAccessError) {
System.out.println("Got expected CNFE/IAE #2");
} else {
- System.err.println("Got unexpected CNFE/IAE #2");
- cnfe.printStackTrace();
+ System.out.println("Got unexpected CNFE/IAE #2");
+ cnfe.printStackTrace(System.out);
}
}
}
@@ -202,14 +202,14 @@ public class Main {
try {
altClass = loader.loadClass("Inaccessible3");
- System.err.println("ERROR: Inaccessible3 was accessible: " + altClass);
+ System.out.println("ERROR: Inaccessible3 was accessible: " + altClass);
} catch (ClassNotFoundException cnfe) {
Throwable cause = cnfe.getCause();
if (cause instanceof IllegalAccessError) {
System.out.println("Got expected CNFE/IAE #3");
} else {
- System.err.println("Got unexpected CNFE/IAE #3");
- cnfe.printStackTrace();
+ System.out.println("Got unexpected CNFE/IAE #3");
+ cnfe.printStackTrace(System.out);
}
}
}
@@ -227,7 +227,7 @@ public class Main {
//System.out.println("+++ DoubledExtend is " + doubledExtendClass
// + " in " + doubledExtendClass.getClassLoader());
} catch (ClassNotFoundException cnfe) {
- System.err.println("loadClass failed: " + cnfe);
+ System.out.println("loadClass failed: " + cnfe);
return;
}
@@ -235,10 +235,10 @@ public class Main {
try {
obj = doubledExtendClass.newInstance();
} catch (InstantiationException ie) {
- System.err.println("newInstance failed: " + ie);
+ System.out.println("newInstance failed: " + ie);
return;
} catch (IllegalAccessException iae) {
- System.err.println("newInstance failed: " + iae);
+ System.out.println("newInstance failed: " + iae);
return;
} catch (LinkageError le) {
System.out.println("Got expected LinkageError on DE");
@@ -254,8 +254,8 @@ public class Main {
String result;
result = Base.doStuff(de);
- System.err.println("ERROR: did not get LinkageError on DE");
- System.err.println("(result=" + result + ")");
+ System.out.println("ERROR: did not get LinkageError on DE");
+ System.out.println("(result=" + result + ")");
} catch (LinkageError le) {
System.out.println("Got expected LinkageError on DE");
return;
@@ -274,7 +274,7 @@ public class Main {
try {
doubledExtendOkayClass = loader.loadClass("DoubledExtendOkay");
} catch (ClassNotFoundException cnfe) {
- System.err.println("loadClass failed: " + cnfe);
+ System.out.println("loadClass failed: " + cnfe);
return;
}
@@ -282,14 +282,14 @@ public class Main {
try {
obj = doubledExtendOkayClass.newInstance();
} catch (InstantiationException ie) {
- System.err.println("newInstance failed: " + ie);
+ System.out.println("newInstance failed: " + ie);
return;
} catch (IllegalAccessException iae) {
- System.err.println("newInstance failed: " + iae);
+ System.out.println("newInstance failed: " + iae);
return;
} catch (LinkageError le) {
- System.err.println("Got unexpected LinkageError on DEO");
- le.printStackTrace();
+ System.out.println("Got unexpected LinkageError on DEO");
+ le.printStackTrace(System.out);
return;
}
@@ -304,8 +304,8 @@ public class Main {
result = BaseOkay.doStuff(de);
System.out.println("Got DEO result " + result);
} catch (LinkageError le) {
- System.err.println("Got unexpected LinkageError on DEO");
- le.printStackTrace();
+ System.out.println("Got unexpected LinkageError on DEO");
+ le.printStackTrace(System.out);
return;
}
}
@@ -322,7 +322,7 @@ public class Main {
try {
getDoubledClass = loader.loadClass("GetDoubled");
} catch (ClassNotFoundException cnfe) {
- System.err.println("loadClass failed: " + cnfe);
+ System.out.println("loadClass failed: " + cnfe);
return;
}
@@ -330,10 +330,10 @@ public class Main {
try {
obj = getDoubledClass.newInstance();
} catch (InstantiationException ie) {
- System.err.println("newInstance failed: " + ie);
+ System.out.println("newInstance failed: " + ie);
return;
} catch (IllegalAccessException iae) {
- System.err.println("newInstance failed: " + iae);
+ System.out.println("newInstance failed: " + iae);
return;
} catch (LinkageError le) {
// Dalvik bails here
@@ -354,7 +354,7 @@ public class Main {
System.out.println("Got LinkageError on GD");
return;
}
- System.err.println("Should have failed by now on GetDoubled");
+ System.out.println("Should have failed by now on GetDoubled");
}
/**
@@ -368,7 +368,7 @@ public class Main {
try {
abstractGetClass = loader.loadClass("AbstractGet");
} catch (ClassNotFoundException cnfe) {
- System.err.println("loadClass ta failed: " + cnfe);
+ System.out.println("loadClass ta failed: " + cnfe);
return;
}
@@ -376,10 +376,10 @@ public class Main {
try {
obj = abstractGetClass.newInstance();
} catch (InstantiationException ie) {
- System.err.println("newInstance failed: " + ie);
+ System.out.println("newInstance failed: " + ie);
return;
} catch (IllegalAccessException iae) {
- System.err.println("newInstance failed: " + iae);
+ System.out.println("newInstance failed: " + iae);
return;
} catch (LinkageError le) {
System.out.println("Got LinkageError on TA");
@@ -399,7 +399,7 @@ public class Main {
System.out.println("Got LinkageError on TA");
return;
}
- System.err.println("Should have failed by now in testAbstract");
+ System.out.println("Should have failed by now in testAbstract");
}
/**
@@ -415,7 +415,7 @@ public class Main {
try {
doubledImplementClass = loader.loadClass("DoubledImplement");
} catch (ClassNotFoundException cnfe) {
- System.err.println("loadClass failed: " + cnfe);
+ System.out.println("loadClass failed: " + cnfe);
return;
}
@@ -423,10 +423,10 @@ public class Main {
try {
obj = doubledImplementClass.newInstance();
} catch (InstantiationException ie) {
- System.err.println("newInstance failed: " + ie);
+ System.out.println("newInstance failed: " + ie);
return;
} catch (IllegalAccessException iae) {
- System.err.println("newInstance failed: " + iae);
+ System.out.println("newInstance failed: " + iae);
return;
} catch (LinkageError le) {
System.out.println("Got LinkageError on DI (early)");
@@ -447,7 +447,7 @@ public class Main {
try {
di.one();
if (!isOne) {
- System.err.println("ERROR: did not get LinkageError on DI");
+ System.out.println("ERROR: did not get LinkageError on DI");
}
} catch (LinkageError le) {
if (!isOne) {
@@ -476,7 +476,7 @@ public class Main {
ifaceImplClass = loader.loadClass("IfaceImpl");
ifaceImplClass = loader.loadClass("DoubledImplement2");
} catch (ClassNotFoundException cnfe) {
- System.err.println("loadClass failed: " + cnfe);
+ System.out.println("loadClass failed: " + cnfe);
return;
}
@@ -484,10 +484,10 @@ public class Main {
try {
obj = ifaceImplClass.newInstance();
} catch (InstantiationException ie) {
- System.err.println("newInstance failed: " + ie);
+ System.out.println("newInstance failed: " + ie);
return;
} catch (IllegalAccessException iae) {
- System.err.println("newInstance failed: " + iae);
+ System.out.println("newInstance failed: " + iae);
return;
} catch (LinkageError le) {
System.out.println("Got LinkageError on IDI (early)");
diff --git a/test/069-field-type/src/Main.java b/test/069-field-type/src/Main.java
index f9885e64b2..d9aa9e11bf 100644
--- a/test/069-field-type/src/Main.java
+++ b/test/069-field-type/src/Main.java
@@ -19,7 +19,7 @@ public class Main {
/* try to use the reference; should fail */
try {
holder.mValue.run();
- System.err.println("ERROR: did not get expected ICCE");
+ System.out.println("ERROR: did not get expected ICCE");
} catch (IncompatibleClassChangeError icce) {
System.out.println("Got expected IncompatibleClassChangeError");
}
diff --git a/test/070-nio-buffer/src/Main.java b/test/070-nio-buffer/src/Main.java
index a7433b8516..a3eeb3fda6 100644
--- a/test/070-nio-buffer/src/Main.java
+++ b/test/070-nio-buffer/src/Main.java
@@ -58,7 +58,7 @@ public class Main {
try {
shortBuf.put(myShorts, 0, 1); // should fail
- System.err.println("ERROR: out-of-bounds put succeeded\n");
+ System.out.println("ERROR: out-of-bounds put succeeded\n");
} catch (BufferOverflowException boe) {
System.out.println("Got expected buffer overflow exception");
}
@@ -66,7 +66,7 @@ public class Main {
try {
shortBuf.position(0);
shortBuf.put(myShorts, 0, 33); // should fail
- System.err.println("ERROR: out-of-bounds put succeeded\n");
+ System.out.println("ERROR: out-of-bounds put succeeded\n");
} catch (IndexOutOfBoundsException ioobe) {
System.out.println("Got expected out-of-bounds exception");
}
@@ -74,7 +74,7 @@ public class Main {
try {
shortBuf.position(16);
shortBuf.put(myShorts, 0, 17); // should fail
- System.err.println("ERROR: out-of-bounds put succeeded\n");
+ System.out.println("ERROR: out-of-bounds put succeeded\n");
} catch (BufferOverflowException boe) {
System.out.println("Got expected buffer overflow exception");
}
diff --git a/test/073-mismatched-field/src/Main.java b/test/073-mismatched-field/src/Main.java
index 70709c0c86..2d6b9eb51e 100644
--- a/test/073-mismatched-field/src/Main.java
+++ b/test/073-mismatched-field/src/Main.java
@@ -23,7 +23,7 @@ public class Main extends SuperMain implements IMain {
void doit() {
try {
System.out.println("value=" + this.f);
- System.err.println("Succeeded unexpectedly");
+ System.out.println("Succeeded unexpectedly");
} catch (IncompatibleClassChangeError icce) {
System.out.println("Got expected failure");
}
diff --git a/test/074-gc-thrash/src/Main.java b/test/074-gc-thrash/src/Main.java
index df0479365f..5165df7bd3 100644
--- a/test/074-gc-thrash/src/Main.java
+++ b/test/074-gc-thrash/src/Main.java
@@ -52,9 +52,9 @@ public class Main {
try {
dumpHprofDataMethod.invoke(null, dumpFile);
} catch (IllegalAccessException iae) {
- System.err.println(iae);
+ System.out.println(iae);
} catch (InvocationTargetException ite) {
- System.err.println(ite);
+ System.out.println(ite);
}
}
@@ -80,7 +80,7 @@ public class Main {
try {
meth = vmdClass.getMethod("dumpHprofData", String.class);
} catch (NoSuchMethodException nsme) {
- System.err.println("Found VMDebug but not dumpHprofData method");
+ System.out.println("Found VMDebug but not dumpHprofData method");
return null;
}
@@ -126,7 +126,7 @@ public class Main {
deep.join();
large.join();
} catch (InterruptedException ie) {
- System.err.println("join was interrupted");
+ System.out.println("join was interrupted");
}
}
@@ -137,7 +137,7 @@ public class Main {
try {
Thread.sleep(ms);
} catch (InterruptedException ie) {
- System.err.println("sleep was interrupted");
+ System.out.println("sleep was interrupted");
}
}
@@ -213,7 +213,7 @@ class Deep extends Thread {
}
if (!once) {
- System.err.println("not even once?");
+ System.out.println("not even once?");
return;
}
@@ -229,7 +229,7 @@ class Deep extends Thread {
for (int i = 0; i < MAX_DEPTH; i++) {
if (weak[i].get() != null) {
- System.err.println("Deep: weak still has " + i);
+ System.out.println("Deep: weak still has " + i);
}
}
@@ -251,7 +251,7 @@ class Deep extends Thread {
private static void checkStringReferences() {
for (int i = 0; i < MAX_DEPTH; i++) {
if (strong[i] != weak[i].get()) {
- System.err.println("Deep: " + i + " strong=" + strong[i] +
+ System.out.println("Deep: " + i + " strong=" + strong[i] +
", weak=" + weak[i].get());
}
}
diff --git a/test/075-verification-error/src/Main.java b/test/075-verification-error/src/Main.java
index 9b66a8d5e1..3f2881eb10 100644
--- a/test/075-verification-error/src/Main.java
+++ b/test/075-verification-error/src/Main.java
@@ -36,12 +36,12 @@ public class Main {
static void testClassNewInstance() {
try {
MaybeAbstract ma = new MaybeAbstract();
- System.err.println("ERROR: MaybeAbstract succeeded unexpectedly");
+ System.out.println("ERROR: MaybeAbstract succeeded unexpectedly");
} catch (InstantiationError ie) {
System.out.println("Got expected InstantationError");
if (VERBOSE) System.out.println("--- " + ie);
} catch (Exception ex) {
- System.err.println("Got unexpected MaybeAbstract failure");
+ System.out.println("Got unexpected MaybeAbstract failure");
}
}
@@ -88,7 +88,7 @@ public class Main {
try {
int x = mutant.inaccessibleField;
- System.err.println("ERROR: bad access succeeded (ifield)");
+ System.out.println("ERROR: bad access succeeded (ifield)");
} catch (IllegalAccessError iae) {
System.out.println("Got expected IllegalAccessError (ifield)");
if (VERBOSE) System.out.println("--- " + iae);
@@ -96,7 +96,7 @@ public class Main {
try {
int y = Mutant.inaccessibleStaticField;
- System.err.println("ERROR: bad access succeeded (sfield)");
+ System.out.println("ERROR: bad access succeeded (sfield)");
} catch (IllegalAccessError iae) {
System.out.println("Got expected IllegalAccessError (sfield)");
if (VERBOSE) System.out.println("--- " + iae);
@@ -104,7 +104,7 @@ public class Main {
try {
mutant.inaccessibleMethod();
- System.err.println("ERROR: bad access succeeded (method)");
+ System.out.println("ERROR: bad access succeeded (method)");
} catch (IllegalAccessError iae) {
System.out.println("Got expected IllegalAccessError (method)");
if (VERBOSE) System.out.println("--- " + iae);
@@ -112,7 +112,7 @@ public class Main {
try {
Mutant.inaccessibleStaticMethod();
- System.err.println("ERROR: bad access succeeded (smethod)");
+ System.out.println("ERROR: bad access succeeded (smethod)");
} catch (IllegalAccessError iae) {
System.out.println("Got expected IllegalAccessError (smethod)");
if (VERBOSE) System.out.println("--- " + iae);
@@ -121,7 +121,7 @@ public class Main {
try {
/* accessible static method in an inaccessible class */
InaccessibleClass.test();
- System.err.println("ERROR: bad meth-class access succeeded (meth-class)");
+ System.out.println("ERROR: bad meth-class access succeeded (meth-class)");
} catch (IllegalAccessError iae) {
System.out.println("Got expected IllegalAccessError (meth-class)");
if (VERBOSE) System.out.println("--- " + iae);
@@ -130,7 +130,7 @@ public class Main {
try {
/* accessible static field in an inaccessible class */
int blah = InaccessibleClass.blah;
- System.err.println("ERROR: bad field-class access succeeded (field-class)");
+ System.out.println("ERROR: bad field-class access succeeded (field-class)");
} catch (IllegalAccessError iae) {
System.out.println("Got expected IllegalAccessError (field-class)");
if (VERBOSE) System.out.println("--- " + iae);
@@ -139,7 +139,7 @@ public class Main {
try {
/* inaccessible static method in an accessible class */
InaccessibleMethod.test();
- System.err.println("ERROR: bad access succeeded (meth-meth)");
+ System.out.println("ERROR: bad access succeeded (meth-meth)");
} catch (IllegalAccessError iae) {
System.out.println("Got expected IllegalAccessError (meth-meth)");
if (VERBOSE) System.out.println("--- " + iae);
diff --git a/test/077-method-override/src/Main.java b/test/077-method-override/src/Main.java
index 84bdf35c29..3a3c528d61 100644
--- a/test/077-method-override/src/Main.java
+++ b/test/077-method-override/src/Main.java
@@ -37,8 +37,8 @@ public class Main {
((Base)derived).overrideVirtualWithStatic();
} catch (NoSuchMethodError nsme) {
/* NSME is subclass of ICCE, so check it explicitly */
- System.err.println("Got NSME - ovws");
- nsme.printStackTrace(System.err);
+ System.out.println("Got NSME - ovws");
+ nsme.printStackTrace(System.out);
} catch (IncompatibleClassChangeError icce) {
System.out.println("Got expected exception - ovws");
}
@@ -46,8 +46,8 @@ public class Main {
try {
((Base)derived).overrideStaticWithVirtual();
} catch (NoSuchMethodError nsme) {
- System.err.println("Got NSME - oswv");
- nsme.printStackTrace(System.err);
+ System.out.println("Got NSME - oswv");
+ nsme.printStackTrace(System.out);
} catch (IncompatibleClassChangeError icce) {
System.out.println("Got expected exception - oswv");
}
diff --git a/test/079-phantom/src/Main.java b/test/079-phantom/src/Main.java
index c54bc0be68..daead2e1dd 100644
--- a/test/079-phantom/src/Main.java
+++ b/test/079-phantom/src/Main.java
@@ -21,7 +21,7 @@ public class Main {
try {
Thread.sleep(ms);
} catch (InterruptedException ie) {
- System.err.println("sleep interrupted");
+ System.out.println("sleep interrupted");
}
}
diff --git a/test/084-class-init/src/Main.java b/test/084-class-init/src/Main.java
index 28eb3e923f..a60fbac84f 100644
--- a/test/084-class-init/src/Main.java
+++ b/test/084-class-init/src/Main.java
@@ -24,7 +24,7 @@ public class Main {
// that is currently a resolution stub because it's running on behalf of <clinit>.
try {
throwDuringClinit();
- System.err.println("didn't throw!");
+ System.out.println("didn't throw!");
} catch (NullPointerException ex) {
System.out.println("caught exception thrown during clinit");
}
@@ -44,34 +44,34 @@ public class Main {
try {
Thread.sleep(msec);
} catch (InterruptedException ie) {
- System.err.println("sleep interrupted");
+ System.out.println("sleep interrupted");
}
}
static void checkExceptions() {
try {
System.out.println(PartialInit.FIELD0);
- System.err.println("Construction of PartialInit succeeded unexpectedly");
+ System.out.println("Construction of PartialInit succeeded unexpectedly");
} catch (ExceptionInInitializerError eiie) {
System.out.println("Got expected EIIE for FIELD0");
}
try {
System.out.println(PartialInit.FIELD0);
- System.err.println("Load of FIELD0 succeeded unexpectedly");
+ System.out.println("Load of FIELD0 succeeded unexpectedly");
} catch (NoClassDefFoundError ncdfe) {
System.out.println("Got expected NCDFE for FIELD0");
}
try {
System.out.println(PartialInit.FIELD1);
- System.err.println("Load of FIELD1 succeeded unexpectedly");
+ System.out.println("Load of FIELD1 succeeded unexpectedly");
} catch (NoClassDefFoundError ncdfe) {
System.out.println("Got expected NCDFE for FIELD1");
}
try {
System.out.println(Exploder.FIELD);
- System.err.println("Load of FIELD succeeded unexpectedly");
+ System.out.println("Load of FIELD succeeded unexpectedly");
} catch (AssertionError expected) {
System.out.println("Got expected '" + expected.getMessage() + "' from Exploder");
}
@@ -92,7 +92,7 @@ public class Main {
fieldThread.join();
methodThread.join();
} catch (InterruptedException ie) {
- System.err.println(ie);
+ System.out.println(ie);
}
/* print all values */
diff --git a/test/086-null-super/src/Main.java b/test/086-null-super/src/Main.java
index 8bd17860ea..039a9599e1 100644
--- a/test/086-null-super/src/Main.java
+++ b/test/086-null-super/src/Main.java
@@ -149,14 +149,14 @@ public class Main {
loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader());
loader.findBrokenClass();
- System.err.println("ERROR: Inaccessible was accessible");
+ System.out.println("ERROR: Inaccessible was accessible");
} catch (InvocationTargetException ite) {
Throwable cause = ite.getCause();
if (cause instanceof NullPointerException) {
- System.err.println("Got expected ITE/NPE");
+ System.out.println("Got expected ITE/NPE");
} else {
- System.err.println("Got unexpected ITE");
- ite.printStackTrace();
+ System.out.println("Got unexpected ITE");
+ ite.printStackTrace(System.out);
}
}
}
diff --git a/test/088-monitor-verification/src/Main.java b/test/088-monitor-verification/src/Main.java
index a6f0e642d4..bca3df6828 100644
--- a/test/088-monitor-verification/src/Main.java
+++ b/test/088-monitor-verification/src/Main.java
@@ -41,7 +41,7 @@ public class Main {
m.nestedMayThrow(false);
try {
m.nestedMayThrow(true);
- System.err.println("nestedThrow(true) did not throw");
+ System.out.println("nestedThrow(true) did not throw");
} catch (MyException me) {}
System.out.println("nestedMayThrow ok");
diff --git a/test/092-locale/src/Main.java b/test/092-locale/src/Main.java
index 8916a29c47..60c0551b84 100644
--- a/test/092-locale/src/Main.java
+++ b/test/092-locale/src/Main.java
@@ -34,31 +34,31 @@ public class Main {
try {
testCalendar();
} catch (Exception ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
try {
testDateFormatSymbols();
} catch (Exception ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
try {
testCurrency();
} catch (Exception ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
try {
testNormalizer();
} catch (Exception ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
try {
testIso3();
} catch (Exception ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
}
@@ -125,13 +125,13 @@ public class Main {
res = Normalizer.normalize(composed, Normalizer.Form.NFD);
if (!decomposed.equals(res)) {
- System.err.println("Bad decompose: '" + composed + "' --> '"
+ System.out.println("Bad decompose: '" + composed + "' --> '"
+ res + "'");
}
res = Normalizer.normalize(decomposed, Normalizer.Form.NFC);
if (!composed.equals(res)) {
- System.err.println("Bad compose: '" + decomposed + "' --> '"
+ System.out.println("Bad compose: '" + decomposed + "' --> '"
+ res + "'");
}
@@ -153,7 +153,7 @@ public class Main {
try {
System.out.println(" iso3=" + loc.getISO3Language());
} catch (MissingResourceException mre) {
- System.err.println("couldn't get iso3 language");
+ System.out.println("couldn't get iso3 language");
}
}
}
diff --git a/test/095-switch-MAX_INT/src/Main.java b/test/095-switch-MAX_INT/src/Main.java
index d1171ea6bc..a004a1aede 100644
--- a/test/095-switch-MAX_INT/src/Main.java
+++ b/test/095-switch-MAX_INT/src/Main.java
@@ -2,7 +2,7 @@ public class Main {
static public void main(String[] args) throws Exception {
switch (0x7fffffff) {
case 0x7fffffff:
- System.err.println("good");
+ System.out.println("good");
break;
default:
throw new AssertionError();
diff --git a/test/100-reflect2/src/Main.java b/test/100-reflect2/src/Main.java
index 91ba3075f4..5f6ffa8ae9 100644
--- a/test/100-reflect2/src/Main.java
+++ b/test/100-reflect2/src/Main.java
@@ -292,7 +292,7 @@ class Main {
// Expected.
} catch (Exception e) {
// Error.
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
@@ -304,7 +304,7 @@ class Main {
cons.newInstance();
} catch (Exception e) {
// Error.
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
diff --git a/test/101-fibonacci/src/Main.java b/test/101-fibonacci/src/Main.java
index c594edbded..9c57ba76eb 100644
--- a/test/101-fibonacci/src/Main.java
+++ b/test/101-fibonacci/src/Main.java
@@ -51,7 +51,7 @@ class Main {
y = fibonacci(x + 1);
System.out.printf("fibonacci(%d)=%d\n", x + 1, y);
} catch (NumberFormatException ex) {
- System.err.println(ex);
+ System.out.println(ex);
System.exit(1);
}
}
diff --git a/test/109-suspend-check/src/Main.java b/test/109-suspend-check/src/Main.java
index 3c3353b4db..e140a59173 100644
--- a/test/109-suspend-check/src/Main.java
+++ b/test/109-suspend-check/src/Main.java
@@ -55,7 +55,7 @@ public class Main {
try {
Thread.sleep(ms);
} catch (InterruptedException ie) {
- System.err.println("sleep was interrupted");
+ System.out.println("sleep was interrupted");
}
}
}
diff --git a/test/114-ParallelGC/src/Main.java b/test/114-ParallelGC/src/Main.java
index 159dd5c926..2199872ba6 100644
--- a/test/114-ParallelGC/src/Main.java
+++ b/test/114-ParallelGC/src/Main.java
@@ -82,7 +82,7 @@ public class Main implements Runnable {
// Any exception or error getting here is bad.
try {
// May need allocations...
- t.printStackTrace(System.err);
+ t.printStackTrace(System.out);
} catch (Throwable tInner) {
}
System.exit(1);
diff --git a/test/115-native-bridge/check b/test/115-native-bridge/check
new file mode 100755
index 0000000000..1ecf3348ca
--- /dev/null
+++ b/test/115-native-bridge/check
@@ -0,0 +1,20 @@
+#!/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.
+
+# ASAN prints a warning here.
+
+sed -e '/WARNING: ASan is ignoring requested __asan_handle_no_return/,+2d' "$2" | \
+ diff --strip-trailing-cr -q "$1" - >/dev/null
diff --git a/test/120-hashcode/src/Main.java b/test/120-hashcode/src/Main.java
index d2435cee62..0955f50c1a 100644
--- a/test/120-hashcode/src/Main.java
+++ b/test/120-hashcode/src/Main.java
@@ -30,7 +30,7 @@ public class Main {
// Make sure that all the hashes agree.
if (hashOrig != hashInflated || hashOrig != hashSystemOrig ||
hashSystemOrig != hashSystemInflated) {
- System.err.println("hash codes dont match: " + hashOrig + " " + hashInflated + " " +
+ System.out.println("hash codes dont match: " + hashOrig + " " + hashInflated + " " +
hashSystemOrig + " " + hashSystemInflated);
}
System.out.println("Done.");
diff --git a/test/130-hprof/src/Main.java b/test/130-hprof/src/Main.java
index 5899dd1183..a8597f1391 100644
--- a/test/130-hprof/src/Main.java
+++ b/test/130-hprof/src/Main.java
@@ -140,7 +140,7 @@ public class Main {
allocator.join();
dumper.join();
} catch (InterruptedException e) {
- System.err.println("join interrupted");
+ System.out.println("join interrupted");
}
}
@@ -178,7 +178,7 @@ public class Main {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
- System.err.println("sleep interrupted");
+ System.out.println("sleep interrupted");
}
}
@@ -223,7 +223,7 @@ public class Main {
try {
meth = vmdClass.getMethod("dumpHprofData", String.class);
} catch (NoSuchMethodException nsme) {
- System.err.println("Found VMDebug but not dumpHprofData method");
+ System.out.println("Found VMDebug but not dumpHprofData method");
return null;
}
diff --git a/test/1337-gc-coverage/gc_coverage.cc b/test/1337-gc-coverage/gc_coverage.cc
index 1cb2fb0976..ac959f68e8 100644
--- a/test/1337-gc-coverage/gc_coverage.cc
+++ b/test/1337-gc-coverage/gc_coverage.cc
@@ -18,7 +18,7 @@
#include "jni.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace {
diff --git a/test/135-MirandaDispatch/src/Main.java b/test/135-MirandaDispatch/src/Main.java
index ada8cefead..ab2a90b3b7 100644
--- a/test/135-MirandaDispatch/src/Main.java
+++ b/test/135-MirandaDispatch/src/Main.java
@@ -53,7 +53,7 @@ public class Main {
} catch (VerifyError expected) {
System.out.println("b/21646347");
} catch (Throwable t) {
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
System.out.println("Finishing");
}
diff --git a/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
index b7293015cf..7d40f5773d 100644
--- a/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
+++ b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
@@ -21,7 +21,7 @@
#include "base/macros.h"
#include "java_vm_ext.h"
#include "jni_env_ext.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace {
diff --git a/test/138-duplicate-classes-check/src/Main.java b/test/138-duplicate-classes-check/src/Main.java
index 5ffceb94fe..b32f0bcc46 100644
--- a/test/138-duplicate-classes-check/src/Main.java
+++ b/test/138-duplicate-classes-check/src/Main.java
@@ -42,7 +42,7 @@ public class Main {
Method test = testEx.getDeclaredMethod("test");
test.invoke(null);
} catch (Exception exc) {
- exc.printStackTrace();
+ exc.printStackTrace(System.out);
}
}
}
diff --git a/test/138-duplicate-classes-check2/src/Main.java b/test/138-duplicate-classes-check2/src/Main.java
index a0d6977405..faf8b5d337 100644
--- a/test/138-duplicate-classes-check2/src/Main.java
+++ b/test/138-duplicate-classes-check2/src/Main.java
@@ -37,7 +37,7 @@ public class Main {
Method test = testEx.getDeclaredMethod("test");
test.invoke(null);
} catch (Exception exc) {
- exc.printStackTrace();
+ exc.printStackTrace(System.out);
}
}
}
diff --git a/test/141-class-unload/jni_unload.cc b/test/141-class-unload/jni_unload.cc
index 9b7e171a95..355457d68d 100644
--- a/test/141-class-unload/jni_unload.cc
+++ b/test/141-class-unload/jni_unload.cc
@@ -20,7 +20,7 @@
#include "jit/jit.h"
#include "runtime.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace {
diff --git a/test/141-class-unload/src/Main.java b/test/141-class-unload/src/Main.java
index 7e8431fb52..9072c8b538 100644
--- a/test/141-class-unload/src/Main.java
+++ b/test/141-class-unload/src/Main.java
@@ -50,7 +50,7 @@ public class Main {
// Test that objects keep class loader live for sticky GC.
testStickyUnload(constructor);
} catch (Exception e) {
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
diff --git a/test/142-classloader2/src/Main.java b/test/142-classloader2/src/Main.java
index a0c77645a3..193fd5dea0 100644
--- a/test/142-classloader2/src/Main.java
+++ b/test/142-classloader2/src/Main.java
@@ -91,7 +91,7 @@ public class Main {
if (e.getCause() instanceof VerifyError) {
System.out.println("Caught wrapped VerifyError.");
} else {
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
diff --git a/test/146-bad-interface/src/Main.java b/test/146-bad-interface/src/Main.java
index 5534bb4bba..958ec7c3c4 100644
--- a/test/146-bad-interface/src/Main.java
+++ b/test/146-bad-interface/src/Main.java
@@ -37,7 +37,7 @@ public class Main {
} catch (Throwable t) {
System.out.println("Error occurred");
System.out.println(t);
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
}
}
diff --git a/test/148-multithread-gc-annotations/gc_coverage.cc b/test/148-multithread-gc-annotations/gc_coverage.cc
index 4862b87057..f48493c684 100644
--- a/test/148-multithread-gc-annotations/gc_coverage.cc
+++ b/test/148-multithread-gc-annotations/gc_coverage.cc
@@ -18,7 +18,7 @@
#include "jni.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace {
diff --git a/test/155-java-set-resolved-type/src/Main.java b/test/155-java-set-resolved-type/src/Main.java
index 8f79bd7ecd..44278a1c9a 100644
--- a/test/155-java-set-resolved-type/src/Main.java
+++ b/test/155-java-set-resolved-type/src/Main.java
@@ -61,7 +61,7 @@ public class Main {
// to be resolved and found through simple lookup.
timpl.newInstance();
} catch (Throwable t) {
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
}
diff --git a/test/156-register-dex-file-multi-loader/src/Main.java b/test/156-register-dex-file-multi-loader/src/Main.java
index ff5a2bd570..6aa1d780d3 100644
--- a/test/156-register-dex-file-multi-loader/src/Main.java
+++ b/test/156-register-dex-file-multi-loader/src/Main.java
@@ -81,7 +81,7 @@ public class Main {
!message.endsWith(" with multiple class loaders");
}
if (unexpected) {
- cnfe.getCause().printStackTrace();
+ cnfe.getCause().printStackTrace(System.out);
}
}
}
diff --git a/test/158-app-image-class-table/src/Main.java b/test/158-app-image-class-table/src/Main.java
index 804468fe91..97aa14d4b1 100644
--- a/test/158-app-image-class-table/src/Main.java
+++ b/test/158-app-image-class-table/src/Main.java
@@ -39,7 +39,7 @@ public class Main {
// to be resolved and found through simple lookup.
timpl.newInstance();
} catch (Throwable t) {
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
}
diff --git a/test/159-app-image-fields/src/Main.java b/test/159-app-image-fields/src/Main.java
index d06a50204a..47d0116a19 100644
--- a/test/159-app-image-fields/src/Main.java
+++ b/test/159-app-image-fields/src/Main.java
@@ -57,7 +57,7 @@ public class Main {
System.out.println("another_value: " + another_value);
}
} catch (Throwable t) {
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
}
diff --git a/test/301-abstract-protected/src/Main.java b/test/301-abstract-protected/src/Main.java
index 9b19a9d56b..f12026791e 100644
--- a/test/301-abstract-protected/src/Main.java
+++ b/test/301-abstract-protected/src/Main.java
@@ -16,7 +16,7 @@
public class Main {
public static void main(String args[]) throws Exception {
- System.err.println(new C().m());
+ System.out.println(new C().m());
}
}
diff --git a/test/487-checker-inline-calls/src/Main.java b/test/487-checker-inline-calls/src/Main.java
index 70384d5a7f..00694f359f 100644
--- a/test/487-checker-inline-calls/src/Main.java
+++ b/test/487-checker-inline-calls/src/Main.java
@@ -20,7 +20,7 @@ public class Main {
try {
doTopCall();
} catch (Error e) {
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
diff --git a/test/488-checker-inline-recursive-calls/src/Main.java b/test/488-checker-inline-recursive-calls/src/Main.java
index 441dbbfcb6..1137837048 100644
--- a/test/488-checker-inline-recursive-calls/src/Main.java
+++ b/test/488-checker-inline-recursive-calls/src/Main.java
@@ -20,7 +20,7 @@ public class Main {
try {
doTopCall(true);
} catch (Error e) {
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
diff --git a/test/492-checker-inline-invoke-interface/src/Main.java b/test/492-checker-inline-invoke-interface/src/Main.java
index a919690000..785c0db0eb 100644
--- a/test/492-checker-inline-invoke-interface/src/Main.java
+++ b/test/492-checker-inline-invoke-interface/src/Main.java
@@ -21,7 +21,7 @@ interface Itf {
class ForceStatic {
static {
System.out.println("Hello from clinit");
- new Exception().printStackTrace();
+ new Exception().printStackTrace(System.out);
}
static int field;
}
diff --git a/test/493-checker-inline-invoke-interface/src/Main.java b/test/493-checker-inline-invoke-interface/src/Main.java
index 171405ca44..0570b20a40 100644
--- a/test/493-checker-inline-invoke-interface/src/Main.java
+++ b/test/493-checker-inline-invoke-interface/src/Main.java
@@ -21,7 +21,7 @@ interface Itf {
class ForceStatic {
static {
System.out.println("Hello from clinit");
- new Exception().printStackTrace();
+ new Exception().printStackTrace(System.out);
}
static int field;
}
diff --git a/test/497-inlining-and-class-loader/src/Main.java b/test/497-inlining-and-class-loader/src/Main.java
index 1e27e77786..01b4bcd391 100644
--- a/test/497-inlining-and-class-loader/src/Main.java
+++ b/test/497-inlining-and-class-loader/src/Main.java
@@ -121,7 +121,7 @@ class Main {
// Because we cleared dex cache entries, we will have to find
// classes again, which require to use the correct class loader
// in the presence of inlining.
- new Exception().printStackTrace();
+ new Exception().printStackTrace(System.out);
}
static Object savedResolvedMethods;
diff --git a/test/522-checker-regression-monitor-exit/src/Main.java b/test/522-checker-regression-monitor-exit/src/Main.java
index c4f80fc9c6..5c26f36fe8 100644
--- a/test/522-checker-regression-monitor-exit/src/Main.java
+++ b/test/522-checker-regression-monitor-exit/src/Main.java
@@ -43,8 +43,8 @@ public class Main {
Method m = c.getMethod("synchronizedHashCode", Object.class);
result = (Integer) m.invoke(null, m_obj);
} catch (Exception e) {
- System.err.println("Hash code query exception");
- e.printStackTrace();
+ System.out.println("Hash code query exception");
+ e.printStackTrace(System.out);
result = -1;
}
return result;
@@ -77,7 +77,7 @@ public class Main {
}
pool.shutdown();
} catch (CancellationException ex) {
- System.err.println("Job timeout");
+ System.out.println("Job timeout");
System.exit(1);
}
}
diff --git a/test/552-checker-sharpening/src/Main.java b/test/552-checker-sharpening/src/Main.java
index 3f81fd644a..4bb179ecc4 100644
--- a/test/552-checker-sharpening/src/Main.java
+++ b/test/552-checker-sharpening/src/Main.java
@@ -42,7 +42,7 @@ public class Main {
}
/// CHECK-START: int Main.testSimple(int) sharpening (before)
- /// CHECK: InvokeStaticOrDirect method_load_kind:DexCacheViaMethod
+ /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall
/// CHECK-START-ARM: int Main.testSimple(int) sharpening (after)
/// CHECK-NOT: ArmDexCacheArraysBase
@@ -78,7 +78,7 @@ public class Main {
}
/// CHECK-START: int Main.testDiamond(boolean, int) sharpening (before)
- /// CHECK: InvokeStaticOrDirect method_load_kind:DexCacheViaMethod
+ /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall
/// CHECK-START-ARM: int Main.testDiamond(boolean, int) sharpening (after)
/// CHECK-NOT: ArmDexCacheArraysBase
@@ -212,7 +212,7 @@ public class Main {
}
/// CHECK-START: java.lang.String Main.$noinline$getBootImageString() sharpening (before)
- /// CHECK: LoadString load_kind:DexCacheViaMethod
+ /// CHECK: LoadString load_kind:RuntimeCall
/// CHECK-START-X86: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
// Note: load kind depends on PIC/non-PIC
@@ -246,7 +246,7 @@ public class Main {
}
/// CHECK-START: java.lang.String Main.$noinline$getNonBootImageString() sharpening (before)
- /// CHECK: LoadString load_kind:DexCacheViaMethod
+ /// CHECK: LoadString load_kind:RuntimeCall
/// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
/// CHECK: LoadString load_kind:BssEntry
diff --git a/test/564-checker-irreducible-loop/smali/IrreducibleLoop.smali b/test/564-checker-irreducible-loop/smali/IrreducibleLoop.smali
index e4bf236266..5f73bbe759 100644
--- a/test/564-checker-irreducible-loop/smali/IrreducibleLoop.smali
+++ b/test/564-checker-irreducible-loop/smali/IrreducibleLoop.smali
@@ -18,8 +18,8 @@
## CHECK-START-X86: int IrreducibleLoop.simpleLoop(int) dead_code_elimination$initial (before)
## CHECK-DAG: <<Constant:i\d+>> IntConstant 42
-## CHECK-DAG: InvokeStaticOrDirect [<<Constant>>] loop:{{B\d+}} irreducible:true
-## CHECK-DAG: InvokeStaticOrDirect [<<Constant>>] loop:none
+## CHECK-DAG: InvokeStaticOrDirect [<<Constant>>{{(,[ij]\d+)?}}] loop:{{B\d+}} irreducible:true
+## CHECK-DAG: InvokeStaticOrDirect [<<Constant>>{{(,[ij]\d+)?}}] loop:none
.method public static simpleLoop(I)I
.registers 3
const/16 v0, 42
diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc
index 8eca6b2ccb..45ead6b204 100644
--- a/test/570-checker-osr/osr.cc
+++ b/test/570-checker-osr/osr.cc
@@ -21,6 +21,7 @@
#include "oat_quick_method_header.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
+#include "stack.h"
#include "stack_map.h"
namespace art {
diff --git a/test/570-checker-osr/src/DeoptimizationController.java b/test/570-checker-osr/src/DeoptimizationController.java
index 907d133d3b..e272607ec4 100644
--- a/test/570-checker-osr/src/DeoptimizationController.java
+++ b/test/570-checker-osr/src/DeoptimizationController.java
@@ -53,7 +53,7 @@ public class DeoptimizationController {
throw new IllegalStateException("Not tracing.");
}
} catch (Exception exc) {
- exc.printStackTrace(System.err);
+ exc.printStackTrace(System.out);
} finally {
if (tempFile != null) {
tempFile.delete();
@@ -68,7 +68,7 @@ public class DeoptimizationController {
throw new IllegalStateException("Still tracing.");
}
} catch (Exception exc) {
- exc.printStackTrace(System.err);
+ exc.printStackTrace(System.out);
}
}
diff --git a/test/588-checker-irreducib-lifetime-hole/smali/IrreducibleLoop.smali b/test/588-checker-irreducib-lifetime-hole/smali/IrreducibleLoop.smali
index 9b8aa510a4..3058358033 100644
--- a/test/588-checker-irreducib-lifetime-hole/smali/IrreducibleLoop.smali
+++ b/test/588-checker-irreducib-lifetime-hole/smali/IrreducibleLoop.smali
@@ -19,8 +19,8 @@
## CHECK-START-X86: int IrreducibleLoop.simpleLoop1(int) dead_code_elimination$initial (before)
## CHECK-DAG: <<Constant:i\d+>> IntConstant 42
## CHECK-DAG: Goto irreducible:true
-## CHECK-DAG: InvokeStaticOrDirect [<<Constant>>] loop:none
-## CHECK-DAG: InvokeStaticOrDirect [{{i\d+}}] loop:none
+## CHECK-DAG: InvokeStaticOrDirect [<<Constant>>{{(,[ij]\d+)?}}] loop:none
+## CHECK-DAG: InvokeStaticOrDirect [{{i\d+}}{{(,[ij]\d+)?}}] loop:none
.method public static simpleLoop1(I)I
.registers 3
const/16 v0, 42
@@ -59,8 +59,8 @@
## CHECK-START-X86: int IrreducibleLoop.simpleLoop2(int) dead_code_elimination$initial (before)
## CHECK-DAG: <<Constant:i\d+>> IntConstant 42
## CHECK-DAG: Goto irreducible:true
-## CHECK-DAG: InvokeStaticOrDirect [<<Constant>>] loop:none
-## CHECK-DAG: InvokeStaticOrDirect [{{i\d+}}] loop:none
+## CHECK-DAG: InvokeStaticOrDirect [<<Constant>>{{(,[ij]\d+)?}}] loop:none
+## CHECK-DAG: InvokeStaticOrDirect [{{i\d+}}{{(,[ij]\d+)?}}] loop:none
.method public static simpleLoop2(I)I
.registers 3
const/16 v0, 42
diff --git a/test/595-profile-saving/profile-saving.cc b/test/595-profile-saving/profile-saving.cc
index 0f8dd57385..019ddad595 100644
--- a/test/595-profile-saving/profile-saving.cc
+++ b/test/595-profile-saving/profile-saving.cc
@@ -26,6 +26,7 @@
#include "oat_file_manager.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
+#include "stack.h"
#include "thread.h"
namespace art {
diff --git a/test/596-app-images/app_images.cc b/test/596-app-images/app_images.cc
index fa9c902070..42211f7548 100644
--- a/test/596-app-images/app_images.cc
+++ b/test/596-app-images/app_images.cc
@@ -63,12 +63,6 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkAppImageContains(JNIEnv*, j
return JNI_FALSE;
}
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkInitialized(JNIEnv*, jclass, jclass c) {
- ScopedObjectAccess soa(Thread::Current());
- ObjPtr<mirror::Class> klass_ptr = soa.Decode<mirror::Class>(c);
- return klass_ptr->IsInitialized();
-}
-
} // namespace
} // namespace art
diff --git a/test/596-app-images/src/Main.java b/test/596-app-images/src/Main.java
index 674ba4d037..75b31b8061 100644
--- a/test/596-app-images/src/Main.java
+++ b/test/596-app-images/src/Main.java
@@ -14,17 +14,9 @@
* limitations under the License.
*/
-import java.lang.reflect.Field;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-
class Main {
static class Inner {
- final public static int abc = 10;
- }
-
- static class Nested {
-
+ public static int abc = 0;
}
public static void main(String[] args) {
@@ -34,122 +26,8 @@ class Main {
} else if (!checkAppImageContains(Inner.class)) {
System.out.println("App image does not contain Inner!");
}
-
- if (!checkInitialized(Inner.class))
- System.out.println("Inner class is not initialized!");
-
- if (!checkInitialized(Nested.class))
- System.out.println("Nested class is not initialized!");
-
- if (!checkInitialized(StaticFields.class))
- System.out.println("StaticFields class is not initialized!");
-
- if (!checkInitialized(StaticFieldsInitSub.class))
- System.out.println("StaticFieldsInitSub class is not initialized!");
-
- if (!checkInitialized(StaticFieldsInit.class))
- System.out.println("StaticFieldsInit class is not initialized!");
-
- if (!checkInitialized(StaticInternString.class))
- System.out.println("StaticInternString class is not initialized!");
-
- StringBuffer sb = new StringBuffer();
- sb.append("java.");
- sb.append("abc.");
- sb.append("Action");
-
- String tmp = sb.toString();
- String intern = tmp.intern();
-
- assertNotEqual(tmp, intern, "Dynamically constructed String, not interned.");
- assertEqual(intern, StaticInternString.intent, "Static encoded literal String not interned.");
- assertEqual(BootInternedString.boot, BootInternedString.boot.intern(),
- "Static encoded literal String not moved back to runtime intern table.");
-
- try {
- Field f = StaticInternString.class.getDeclaredField("intent");
- assertEqual(intern, f.get(null), "String Literals are not interned properly.");
-
- } catch (Exception e) {
- System.out.println("Exception");
- }
-
- assertEqual(StaticInternString.getIntent(), StaticInternString2.getIntent(),
- "String Literals are not intenred properly, App image static strings duplicated.");
-
- // reload the class StaticInternString, check whether static strings interned properly
- final String DEX_FILE = System.getenv("DEX_LOCATION") + "/596-app-images.jar";
- final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path");
-
- try {
- Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
- if (pathClassLoader == null) {
- throw new AssertionError("Counldn't find path class loader class");
- }
- Constructor<?> ctor =
- pathClassLoader.getDeclaredConstructor(String.class, String.class, ClassLoader.class);
- ClassLoader loader = (ClassLoader) ctor.newInstance(
- DEX_FILE, LIBRARY_SEARCH_PATH, null);
-
- Class<?> staticInternString = loader.loadClass("StaticInternString");
-
- if (!checkAppImageContains(staticInternString)) {
- System.out.println("Not loaded again.");
- }
- Method getIntent = staticInternString.getDeclaredMethod("getIntent");
-
- assertEqual(StaticInternString.getIntent(), getIntent.invoke(staticInternString),
- "Dynamically loaded app image's literal strings not interned properly.");
- } catch (Exception e) {
- e.printStackTrace();
- }
-
}
public static native boolean checkAppImageLoaded();
public static native boolean checkAppImageContains(Class<?> klass);
- public static native boolean checkInitialized(Class<?> klass);
-
- public static void assertEqual(Object a, Object b, String msg) {
- if (a != b)
- System.out.println(msg);
- }
-
- public static void assertNotEqual(Object a, Object b, String msg) {
- if (a == b)
- System.out.println(msg);
- }
-
-}
-
-class StaticFields{
- public static int abc;
-}
-
-class StaticFieldsInitSub extends StaticFieldsInit {
- final public static int def = 10;
-}
-
-class StaticFieldsInit{
- final public static int abc = 10;
-}
-
-class StaticInternString {
- final public static String intent = "java.abc.Action";
- static public String getIntent() {
- return intent;
- }
-}
-
-class BootInternedString {
- final public static String boot = "double";
}
-
-class StaticInternString2 {
- final public static String intent = "java.abc.Action";
-
- static String getIntent() {
- return intent;
- }
-}
-
diff --git a/test/596-monitor-inflation/monitor_inflation.cc b/test/596-monitor-inflation/monitor_inflation.cc
index fb4275b711..07d1ddbe69 100644
--- a/test/596-monitor-inflation/monitor_inflation.cc
+++ b/test/596-monitor-inflation/monitor_inflation.cc
@@ -18,7 +18,7 @@
#include "jni.h"
#include "monitor.h"
#include "runtime.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
namespace {
diff --git a/test/602-deoptimizeable/src/Main.java b/test/602-deoptimizeable/src/Main.java
index 743a5796c9..d995923f88 100644
--- a/test/602-deoptimizeable/src/Main.java
+++ b/test/602-deoptimizeable/src/Main.java
@@ -99,7 +99,7 @@ public class Main {
System.exit(0);
}
} catch (Exception e) {
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
});
@@ -127,7 +127,7 @@ public class Main {
map.put(new DummyObject(10), Long.valueOf(100));
assertIsInterpreted(); // Every deoptimizeable method is deoptimized.
} catch (Exception e) {
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
});
diff --git a/test/617-clinit-oome/src/Main.java b/test/617-clinit-oome/src/Main.java
index 749a2325ef..94cb7ce7db 100644
--- a/test/617-clinit-oome/src/Main.java
+++ b/test/617-clinit-oome/src/Main.java
@@ -37,7 +37,7 @@ public class Main {
Other.print();
} catch (OutOfMemoryError e) {
} catch (Exception e) {
- System.err.println(e);
+ System.out.println(e);
}
}
}
diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java
index 3a2145bf2b..af205b074f 100644
--- a/test/623-checker-loop-regressions/src/Main.java
+++ b/test/623-checker-loop-regressions/src/Main.java
@@ -291,6 +291,9 @@ public class Main {
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
//
// NOTE: should correctly deal with compressed and uncompressed cases.
+ //
+ /// CHECK-START-MIPS64: void Main.string2Bytes(char[], java.lang.String) loop_optimization (after)
+ /// CHECK-NOT: VecLoad
private static void string2Bytes(char[] a, String b) {
int min = Math.min(a.length, b.length());
for (int i = 0; i < min; i++) {
@@ -333,6 +336,13 @@ public class Main {
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Repl>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Repl>>] loop:<<Loop>> outer_loop:none
//
+ /// CHECK-START-MIPS64: void Main.oneBoth(short[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Repl>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Repl>>] loop:<<Loop>> outer_loop:none
+ //
// Bug b/37764324: integral same-length packed types can be mixed freely.
private static void oneBoth(short[] a, char[] b) {
for (int i = 0; i < Math.min(a.length, b.length); i++) {
@@ -372,6 +382,19 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Add>>] loop:<<Loop2>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi2>>,<<Cnv>>] loop:<<Loop2>> outer_loop:none
//
+ /// CHECK-START-MIPS64: void Main.typeConv(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: <<Vadd:d\d+>> VecAdd [<<Load>>,<<Repl>>] loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi1>>,<<Vadd>>] loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi loop:<<Loop2:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:b\d+>> ArrayGet [{{l\d+}},<<Phi2>>] loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<One>>] loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Add>>] loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi2>>,<<Cnv>>] loop:<<Loop2>> outer_loop:none
+ //
// Scalar code in cleanup loop uses correct byte type on array get and type conversion.
private static void typeConv(byte[] a, byte[] b) {
int len = Math.min(a.length, b.length);
diff --git a/test/626-const-class-linking/src/RacyMisbehavingHelper.java b/test/626-const-class-linking/src/RacyMisbehavingHelper.java
index 45252789e4..9acd3c3ff6 100644
--- a/test/626-const-class-linking/src/RacyMisbehavingHelper.java
+++ b/test/626-const-class-linking/src/RacyMisbehavingHelper.java
@@ -26,7 +26,7 @@ public class RacyMisbehavingHelper {
Method reportAfterLoading = loader.getClass().getDeclaredMethod("reportAfterLoading");
reportAfterLoading.invoke(loader);
} catch (Throwable t) {
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
return new ClassPair(helper1_class, test_class);
}
diff --git a/test/638-no-line-number/src/Main.java b/test/638-no-line-number/src/Main.java
index 7fe0404204..851f049ba6 100644
--- a/test/638-no-line-number/src/Main.java
+++ b/test/638-no-line-number/src/Main.java
@@ -19,12 +19,12 @@ public class Main {
try {
doThrow(new Error());
} catch (Error e) {
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
try {
doThrow(null);
} catch (Throwable t) {
- t.printStackTrace();
+ t.printStackTrace(System.out);
}
}
diff --git a/test/640-checker-boolean-simd/src/Main.java b/test/640-checker-boolean-simd/src/Main.java
index f8239faaf3..64b76f8516 100644
--- a/test/640-checker-boolean-simd/src/Main.java
+++ b/test/640-checker-boolean-simd/src/Main.java
@@ -35,6 +35,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAnd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.and(boolean) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAnd loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void and(boolean x) {
for (int i = 0; i < 128; i++)
a[i] &= x; // NOTE: bitwise and, not the common &&
@@ -50,6 +56,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecOr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.or(boolean) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecOr loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void or(boolean x) {
for (int i = 0; i < 128; i++)
a[i] |= x; // NOTE: bitwise or, not the common ||
@@ -65,6 +77,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecXor loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.xor(boolean) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecXor loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void xor(boolean x) {
for (int i = 0; i < 128; i++)
a[i] ^= x; // NOTE: bitwise xor
@@ -80,6 +98,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.not() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void not() {
for (int i = 0; i < 128; i++)
a[i] = !a[i];
diff --git a/test/640-checker-byte-simd/src/Main.java b/test/640-checker-byte-simd/src/Main.java
index 21d71e8a13..283c2c907d 100644
--- a/test/640-checker-byte-simd/src/Main.java
+++ b/test/640-checker-byte-simd/src/Main.java
@@ -35,6 +35,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.add(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void add(int x) {
for (int i = 0; i < 128; i++)
a[i] += x;
@@ -50,6 +56,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.sub(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sub(int x) {
for (int i = 0; i < 128; i++)
a[i] -= x;
@@ -65,6 +77,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.mul(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void mul(int x) {
for (int i = 0; i < 128; i++)
a[i] *= x;
@@ -94,6 +112,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.neg() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void neg() {
for (int i = 0; i < 128; i++)
a[i] = (byte) -a[i];
@@ -109,6 +133,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.not() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void not() {
for (int i = 0; i < 128; i++)
a[i] = (byte) ~a[i];
@@ -124,6 +154,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shl4() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void shl4() {
for (int i = 0; i < 128; i++)
a[i] <<= 4;
@@ -139,6 +175,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.sar2() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sar2() {
for (int i = 0; i < 128; i++)
a[i] >>= 2;
diff --git a/test/640-checker-char-simd/src/Main.java b/test/640-checker-char-simd/src/Main.java
index 89d4b6b84e..dd879b40cd 100644
--- a/test/640-checker-char-simd/src/Main.java
+++ b/test/640-checker-char-simd/src/Main.java
@@ -35,6 +35,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.add(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void add(int x) {
for (int i = 0; i < 128; i++)
a[i] += x;
@@ -50,6 +56,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.sub(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sub(int x) {
for (int i = 0; i < 128; i++)
a[i] -= x;
@@ -65,6 +77,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.mul(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void mul(int x) {
for (int i = 0; i < 128; i++)
a[i] *= x;
@@ -94,6 +112,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.neg() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void neg() {
for (int i = 0; i < 128; i++)
a[i] = (char) -a[i];
@@ -109,6 +133,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.not() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void not() {
for (int i = 0; i < 128; i++)
a[i] = (char) ~a[i];
@@ -124,6 +154,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shl4() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void shl4() {
for (int i = 0; i < 128; i++)
a[i] <<= 4;
@@ -152,6 +188,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecUShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shr2() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecUShr loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void shr2() {
for (int i = 0; i < 128; i++)
a[i] >>>= 2;
diff --git a/test/640-checker-double-simd/src/Main.java b/test/640-checker-double-simd/src/Main.java
index 5709b5dab8..f7492d5578 100644
--- a/test/640-checker-double-simd/src/Main.java
+++ b/test/640-checker-double-simd/src/Main.java
@@ -36,6 +36,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.add(double) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void add(double x) {
for (int i = 0; i < 128; i++)
a[i] += x;
@@ -51,6 +57,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.sub(double) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sub(double x) {
for (int i = 0; i < 128; i++)
a[i] -= x;
@@ -66,6 +78,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.mul(double) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void mul(double x) {
for (int i = 0; i < 128; i++)
a[i] *= x;
@@ -81,6 +99,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecDiv loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.div(double) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecDiv loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void div(double x) {
for (int i = 0; i < 128; i++)
a[i] /= x;
@@ -96,6 +120,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.neg() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void neg() {
for (int i = 0; i < 128; i++)
a[i] = -a[i];
@@ -111,6 +141,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.abs() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAbs loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void abs() {
for (int i = 0; i < 128; i++)
a[i] = Math.abs(a[i]);
@@ -125,6 +161,10 @@ public class Main {
/// CHECK-NOT: VecLoad
/// CHECK-NOT: VecStore
//
+ /// CHECK-START-MIPS64: void Main.conv(long[]) loop_optimization (after)
+ /// CHECK-NOT: VecLoad
+ /// CHECK-NOT: VecStore
+ //
// TODO: fill in when long2double is supported
static void conv(long[] b) {
for (int i = 0; i < 128; i++)
diff --git a/test/640-checker-float-simd/src/Main.java b/test/640-checker-float-simd/src/Main.java
index 4bcb7e2c1b..4fe9675afe 100644
--- a/test/640-checker-float-simd/src/Main.java
+++ b/test/640-checker-float-simd/src/Main.java
@@ -36,6 +36,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.add(float) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void add(float x) {
for (int i = 0; i < 128; i++)
a[i] += x;
@@ -51,6 +57,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.sub(float) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sub(float x) {
for (int i = 0; i < 128; i++)
a[i] -= x;
@@ -66,6 +78,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.mul(float) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void mul(float x) {
for (int i = 0; i < 128; i++)
a[i] *= x;
@@ -81,6 +99,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecDiv loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.div(float) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecDiv loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void div(float x) {
for (int i = 0; i < 128; i++)
a[i] /= x;
@@ -96,6 +120,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.neg() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void neg() {
for (int i = 0; i < 128; i++)
a[i] = -a[i];
@@ -106,6 +136,12 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
+ /// CHECK-START-MIPS64: void Main.abs() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAbs loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
/// CHECK-START-ARM64: void Main.abs() loop_optimization (after)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
@@ -126,6 +162,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecCnv loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.conv(int[]) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecCnv loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void conv(int[] b) {
for (int i = 0; i < 128; i++)
a[i] = b[i];
diff --git a/test/640-checker-int-simd/src/Main.java b/test/640-checker-int-simd/src/Main.java
index 9ee553c469..9abf60d6fa 100644
--- a/test/640-checker-int-simd/src/Main.java
+++ b/test/640-checker-int-simd/src/Main.java
@@ -35,6 +35,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.add(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void add(int x) {
for (int i = 0; i < 128; i++)
a[i] += x;
@@ -50,6 +56,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.sub(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sub(int x) {
for (int i = 0; i < 128; i++)
a[i] -= x;
@@ -65,6 +77,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.mul(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void mul(int x) {
for (int i = 0; i < 128; i++)
a[i] *= x;
@@ -95,6 +113,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.neg() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void neg() {
for (int i = 0; i < 128; i++)
a[i] = -a[i];
@@ -110,6 +134,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.not() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void not() {
for (int i = 0; i < 128; i++)
a[i] = ~a[i];
@@ -125,6 +155,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shl4() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void shl4() {
for (int i = 0; i < 128; i++)
a[i] <<= 4;
@@ -134,12 +170,18 @@ public class Main {
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
- //
+ //
/// CHECK-START-ARM64: void Main.sar2() loop_optimization (after)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.sar2() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sar2() {
for (int i = 0; i < 128; i++)
a[i] >>= 2;
@@ -155,6 +197,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecUShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shr2() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecUShr loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void shr2() {
for (int i = 0; i < 128; i++)
a[i] >>>= 2;
@@ -185,6 +233,11 @@ public class Main {
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Get>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shr32() loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Get>>] loop:<<Loop>> outer_loop:none
static void shr32() {
// TODO: remove a[i] = a[i] altogether?
for (int i = 0; i < 128; i++)
@@ -211,6 +264,13 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<UShr>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shr33() loop_optimization (after)
+ /// CHECK-DAG: <<Dist:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<UShr>>] loop:<<Loop>> outer_loop:none
static void shr33() {
for (int i = 0; i < 128; i++)
a[i] >>>= $opt$inline$IntConstant33(); // 1, since & 31
@@ -236,6 +296,13 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<UShr>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shrMinus254() loop_optimization (after)
+ /// CHECK-DAG: <<Dist:i\d+>> IntConstant 2 loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<UShr>>] loop:<<Loop>> outer_loop:none
static void shrMinus254() {
for (int i = 0; i < 128; i++)
a[i] >>>= $opt$inline$IntConstantMinus254(); // 2, since & 31
diff --git a/test/640-checker-long-simd/src/Main.java b/test/640-checker-long-simd/src/Main.java
index 8f6af9d012..05dcae6f83 100644
--- a/test/640-checker-long-simd/src/Main.java
+++ b/test/640-checker-long-simd/src/Main.java
@@ -35,6 +35,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.add(long) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void add(long x) {
for (int i = 0; i < 128; i++)
a[i] += x;
@@ -50,6 +56,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.sub(long) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sub(long x) {
for (int i = 0; i < 128; i++)
a[i] -= x;
@@ -60,6 +72,12 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
+ /// CHECK-START-MIPS64: void Main.mul(long) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
// Not supported for longs.
/// CHECK-START-ARM64: void Main.mul(long) loop_optimization (after)
/// CHECK-NOT: VecMul
@@ -93,6 +111,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.neg() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void neg() {
for (int i = 0; i < 128; i++)
a[i] = -a[i];
@@ -108,6 +132,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.not() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void not() {
for (int i = 0; i < 128; i++)
a[i] = ~a[i];
@@ -123,6 +153,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shl4() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void shl4() {
for (int i = 0; i < 128; i++)
a[i] <<= 4;
@@ -138,6 +174,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.sar2() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sar2() {
for (int i = 0; i < 128; i++)
a[i] >>= 2;
@@ -153,6 +195,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecUShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shr2() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecUShr loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void shr2() {
for (int i = 0; i < 128; i++)
a[i] >>>= 2;
@@ -183,6 +231,11 @@ public class Main {
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Get>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shr64() loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Get>>] loop:<<Loop>> outer_loop:none
static void shr64() {
// TODO: remove a[i] = a[i] altogether?
for (int i = 0; i < 128; i++)
@@ -209,6 +262,13 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<UShr>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shr65() loop_optimization (after)
+ /// CHECK-DAG: <<Dist:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<UShr>>] loop:<<Loop>> outer_loop:none
static void shr65() {
for (int i = 0; i < 128; i++)
a[i] >>>= $opt$inline$IntConstant65(); // 1, since & 63
@@ -234,6 +294,13 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<UShr>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shrMinus254() loop_optimization (after)
+ /// CHECK-DAG: <<Dist:i\d+>> IntConstant 2 loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<UShr>>] loop:<<Loop>> outer_loop:none
static void shrMinus254() {
for (int i = 0; i < 128; i++)
a[i] >>>= $opt$inline$IntConstantMinus254(); // 2, since & 63
diff --git a/test/640-checker-short-simd/src/Main.java b/test/640-checker-short-simd/src/Main.java
index f62c726c05..4cca837efb 100644
--- a/test/640-checker-short-simd/src/Main.java
+++ b/test/640-checker-short-simd/src/Main.java
@@ -35,6 +35,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.add(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void add(int x) {
for (int i = 0; i < 128; i++)
a[i] += x;
@@ -50,6 +56,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.sub(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sub(int x) {
for (int i = 0; i < 128; i++)
a[i] -= x;
@@ -65,6 +77,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.mul(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void mul(int x) {
for (int i = 0; i < 128; i++)
a[i] *= x;
@@ -94,6 +112,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.neg() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void neg() {
for (int i = 0; i < 128; i++)
a[i] = (short) -a[i];
@@ -109,6 +133,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.not() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void not() {
for (int i = 0; i < 128; i++)
a[i] = (short) ~a[i];
@@ -124,6 +154,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.shl4() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void shl4() {
for (int i = 0; i < 128; i++)
a[i] <<= 4;
@@ -139,6 +175,12 @@ public class Main {
/// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.sar2() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
static void sar2() {
for (int i = 0; i < 128; i++)
a[i] >>= 2;
diff --git a/test/645-checker-abs-simd/src/Main.java b/test/645-checker-abs-simd/src/Main.java
index 5a63d9f539..9714a46630 100644
--- a/test/645-checker-abs-simd/src/Main.java
+++ b/test/645-checker-abs-simd/src/Main.java
@@ -39,6 +39,18 @@ public class Main {
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+ //
+ /// CHECK-START-MIPS64: void Main.doitByte(byte[]) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:none
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
+ //
+ /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
private static void doitByte(byte[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = (byte) Math.abs(x[i]);
@@ -77,6 +89,18 @@ public class Main {
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+ //
+ /// CHECK-START-MIPS64: void Main.doitShort(short[]) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:none
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
+ //
+ /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
private static void doitShort(short[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = (short) Math.abs(x[i]);
@@ -100,6 +124,18 @@ public class Main {
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+ //
+ /// CHECK-START-MIPS64: void Main.doitInt(int[]) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:none
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
+ //
+ /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
private static void doitInt(int[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = Math.abs(x[i]);
@@ -123,6 +159,18 @@ public class Main {
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+ //
+ /// CHECK-START-MIPS64: void Main.doitLong(long[]) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:none
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsLong loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
+ //
+ /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
private static void doitLong(long[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = Math.abs(x[i]);
@@ -146,6 +194,18 @@ public class Main {
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+ //
+ /// CHECK-START-MIPS64: void Main.doitFloat(float[]) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:none
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsFloat loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
+ //
+ /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
private static void doitFloat(float[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = Math.abs(x[i]);
@@ -169,6 +229,18 @@ public class Main {
/// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+ //
+ /// CHECK-START-MIPS64: void Main.doitDouble(double[]) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecLoad loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:none
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsDouble loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:none
+ //
+ /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
private static void doitDouble(double[] x) {
for (int i = 0; i < x.length; i++) {
x[i] = Math.abs(x[i]);
diff --git a/test/646-checker-hadd-alt-byte/src/Main.java b/test/646-checker-hadd-alt-byte/src/Main.java
index d1b33ea0da..9cc68287c3 100644
--- a/test/646-checker-hadd-alt-byte/src/Main.java
+++ b/test/646-checker-hadd-alt-byte/src/Main.java
@@ -45,6 +45,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_signed(byte[] b1, byte[] b2, byte[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -71,6 +78,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned(byte[] b1, byte[] b2, byte[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -95,6 +109,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_signed(byte[] b1, byte[] b2, byte[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -122,6 +143,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_unsigned(byte[] b1, byte[] b2, byte[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -146,6 +174,14 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<I127:i\d+>> IntConstant 127 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I127>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_signed_constant(byte[] b1, byte[] bo) {
int min_length = Math.min(bo.length, b1.length);
for (int i = 0; i < min_length; i++) {
@@ -171,6 +207,14 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<I255:i\d+>> IntConstant 255 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I255>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned_constant(byte[] b1, byte[] bo) {
int min_length = Math.min(bo.length, b1.length);
for (int i = 0; i < min_length; i++) {
diff --git a/test/646-checker-hadd-alt-char/src/Main.java b/test/646-checker-hadd-alt-char/src/Main.java
index 1ea8d3fe07..3f81299476 100644
--- a/test/646-checker-hadd-alt-char/src/Main.java
+++ b/test/646-checker-hadd-alt-char/src/Main.java
@@ -45,6 +45,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned(char[] b1, char[] b2, char[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -72,6 +79,13 @@ public class Main {
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
//
+ /// CHECK-START-MIPS64: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
// Note: HAnd has no impact (already a zero extension).
//
private static void halving_add_also_unsigned(char[] b1, char[] b2, char[] bo) {
@@ -98,6 +112,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_unsigned(char[] b1, char[] b2, char[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -126,6 +147,13 @@ public class Main {
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
//
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
// Note: HAnd has no impact (already a zero extension).
//
private static void rounding_halving_add_also_unsigned(char[] b1, char[] b2, char[] bo) {
@@ -152,6 +180,14 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned_constant(char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned_constant(char[] b1, char[] bo) {
int min_length = Math.min(bo.length, b1.length);
for (int i = 0; i < min_length; i++) {
@@ -178,6 +214,14 @@ public class Main {
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
//
+ /// CHECK-START-MIPS64: void Main.halving_add_also_unsigned_constant(char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
// Note: HAnd has no impact (already a zero extension).
//
private static void halving_add_also_unsigned_constant(char[] b1, char[] bo) {
diff --git a/test/646-checker-hadd-alt-short/src/Main.java b/test/646-checker-hadd-alt-short/src/Main.java
index 269e6183b4..150626cdd7 100644
--- a/test/646-checker-hadd-alt-short/src/Main.java
+++ b/test/646-checker-hadd-alt-short/src/Main.java
@@ -45,6 +45,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_signed(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -71,6 +78,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -95,6 +109,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_signed(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -122,6 +143,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -146,6 +174,14 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<SMAX>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_signed_constant(short[] b1, short[] bo) {
int min_length = Math.min(bo.length, b1.length);
for (int i = 0; i < min_length; i++) {
@@ -171,6 +207,14 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned_constant(short[] b1, short[] bo) {
int min_length = Math.min(bo.length, b1.length);
for (int i = 0; i < min_length; i++) {
diff --git a/test/646-checker-hadd-byte/src/Main.java b/test/646-checker-hadd-byte/src/Main.java
index 7e29a7e60b..5a615a429e 100644
--- a/test/646-checker-hadd-byte/src/Main.java
+++ b/test/646-checker-hadd-byte/src/Main.java
@@ -42,6 +42,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_signed(byte[] b1, byte[] b2, byte[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -68,6 +75,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned(byte[] b1, byte[] b2, byte[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -92,6 +106,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_signed(byte[] b1, byte[] b2, byte[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -119,6 +140,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_unsigned(byte[] b1, byte[] b2, byte[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -143,6 +171,14 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<I127:i\d+>> IntConstant 127 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I127>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_signed_constant(byte[] b1, byte[] bo) {
int min_length = Math.min(bo.length, b1.length);
for (int i = 0; i < min_length; i++) {
@@ -168,6 +204,14 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<I255:i\d+>> IntConstant 255 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I255>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned_constant(byte[] b1, byte[] bo) {
int min_length = Math.min(bo.length, b1.length);
for (int i = 0; i < min_length; i++) {
diff --git a/test/646-checker-hadd-char/src/Main.java b/test/646-checker-hadd-char/src/Main.java
index d24608f5af..bb8a01f2cc 100644
--- a/test/646-checker-hadd-char/src/Main.java
+++ b/test/646-checker-hadd-char/src/Main.java
@@ -42,6 +42,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned(char[] b1, char[] b2, char[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -69,6 +76,13 @@ public class Main {
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
//
+ /// CHECK-START-MIPS64: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
// Note: HAnd has no impact (already a zero extension).
//
private static void halving_add_also_unsigned(char[] b1, char[] b2, char[] bo) {
@@ -95,6 +109,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_unsigned(char[] b1, char[] b2, char[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -123,6 +144,13 @@ public class Main {
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
//
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
// Note: HAnd has no impact (already a zero extension).
//
private static void rounding_halving_add_also_unsigned(char[] b1, char[] b2, char[] bo) {
@@ -149,6 +177,14 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned_constant(char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned_constant(char[] b1, char[] bo) {
int min_length = Math.min(bo.length, b1.length);
for (int i = 0; i < min_length; i++) {
@@ -175,6 +211,14 @@ public class Main {
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
//
+ /// CHECK-START-MIPS64: void Main.halving_add_also_unsigned_constant(char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
// Note: HAnd has no impact (already a zero extension).
//
private static void halving_add_also_unsigned_constant(char[] b1, char[] bo) {
diff --git a/test/646-checker-hadd-short/src/Main.java b/test/646-checker-hadd-short/src/Main.java
index 4e6b4bde8b..07845a6038 100644
--- a/test/646-checker-hadd-short/src/Main.java
+++ b/test/646-checker-hadd-short/src/Main.java
@@ -42,6 +42,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_signed(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -69,6 +76,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_signed_alt(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -96,6 +110,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -120,6 +141,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_signed(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -144,6 +172,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_signed_alt(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -172,6 +207,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed_alt2(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_signed_alt2(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -200,6 +242,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -227,6 +276,13 @@ public class Main {
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned_alt(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void rounding_halving_add_unsigned_alt(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
@@ -252,6 +308,14 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<SMAX>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_signed_constant(short[] b1, short[] bo) {
int min_length = Math.min(bo.length, b1.length);
for (int i = 0; i < min_length; i++) {
@@ -277,6 +341,14 @@ public class Main {
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>> outer_loop:none
private static void halving_add_unsigned_constant(short[] b1, short[] bo) {
int min_length = Math.min(bo.length, b1.length);
for (int i = 0; i < min_length; i++) {
diff --git a/test/654-checker-periodic/expected.txt b/test/654-checker-periodic/expected.txt
new file mode 100644
index 0000000000..b0aad4deb5
--- /dev/null
+++ b/test/654-checker-periodic/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/654-checker-periodic/info.txt b/test/654-checker-periodic/info.txt
new file mode 100644
index 0000000000..7c8a7770ae
--- /dev/null
+++ b/test/654-checker-periodic/info.txt
@@ -0,0 +1 @@
+Periodic sequence on integer and floating-point.
diff --git a/test/654-checker-periodic/src/Main.java b/test/654-checker-periodic/src/Main.java
new file mode 100644
index 0000000000..7a0c98cfae
--- /dev/null
+++ b/test/654-checker-periodic/src/Main.java
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+/**
+ * Tests for last value of a few periodic sequences
+ * (found by fuzz testing).
+ */
+public class Main {
+
+ /// CHECK-START: int Main.doitUpInt(int) loop_optimization (before)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START: int Main.doitUpInt(int) loop_optimization (after)
+ /// CHECK-NOT: Phi
+ static int doitUpInt(int n) {
+ // Complete loop is replaced by last-value.
+ int lI = 1;
+ for (int i1 = 0; i1 < n; i1++) {
+ lI = (1486662021 - lI);
+ }
+ return lI;
+ }
+
+ /// CHECK-START: int Main.doitDownInt(int) loop_optimization (before)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START: int Main.doitDownInt(int) loop_optimization (after)
+ /// CHECK-NOT: Phi
+ static int doitDownInt(int n) {
+ // Complete loop is replaced by last-value.
+ int lI = 1;
+ for (int i1 = n - 1; i1 >= 0; i1--) {
+ lI = (1486662021 - lI);
+ }
+ return lI;
+ }
+
+ /// CHECK-START: float Main.doitUpFloat(int) loop_optimization (before)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START: float Main.doitUpFloat(int) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
+ static float doitUpFloat(int n) {
+ // FP arithmetic is not sufficiently precise.
+ // The loop remains.
+ float lF = 1.0f;
+ for (int i1 = 0; i1 < n; i1++) {
+ lF = (1486662021.0f - lF);
+ }
+ return lF;
+ }
+
+ /// CHECK-START: float Main.doitDownFloat(int) loop_optimization (before)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START: float Main.doitDownFloat(int) loop_optimization (after)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
+ static float doitDownFloat(int n) {
+ // FP arithmetic is not sufficiently precise.
+ // The loop remains.
+ float lF = 1.0f;
+ for (int i1 = n - 1; i1 >= 0; i1--) {
+ lF = (1486662021.0f - lF);
+ }
+ return lF;
+ }
+
+ /// CHECK-START: float Main.doitUpFloatAlt(int) loop_optimization (before)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START: float Main.doitUpFloatAlt(int) loop_optimization (after)
+ /// CHECK-NOT: Phi
+ static float doitUpFloatAlt(int n) {
+ // Complete loop is replaced by last-value
+ // since the values are now precise.
+ float lF = 1.0f;
+ float l2 = 1486662020.0f;
+ for (int i1 = 0; i1 < n; i1++) {
+ float old = lF;
+ lF = l2;
+ l2 = old;
+ }
+ return lF;
+ }
+
+ /// CHECK-START: float Main.doitDownFloatAlt(int) loop_optimization (before)
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START: float Main.doitDownFloatAlt(int) loop_optimization (after)
+ /// CHECK-NOT: Phi
+ static float doitDownFloatAlt(int n) {
+ // Complete loop is replaced by last-value
+ // since the values are now precise.
+ float lF = 1.0f;
+ float l2 = 1486662020.0f;
+ for (int i1 = n - 1; i1 >= 0; i1--) {
+ float old = lF;
+ lF = l2;
+ l2 = old;
+ }
+ return lF;
+ }
+
+ // Main driver.
+ public static void main(String[] args) {
+ for (int i = 0; i < 10; i++) {
+ int ei = (i & 1) == 0 ? 1 : 1486662020;
+ int ci = doitUpInt(i);
+ expectEquals(ei, ci);
+ }
+ for (int i = 0; i < 10; i++) {
+ int ei = (i & 1) == 0 ? 1 : 1486662020;
+ int ci = doitDownInt(i);
+ expectEquals(ei, ci);
+ }
+ for (int i = 0; i < 10; i++) {
+ float ef = i == 0 ? 1.0f : ((i & 1) == 0 ? 0.0f : 1486662021.0f);
+ float cf = doitUpFloat(i);
+ expectEquals(ef, cf);
+ }
+ for (int i = 0; i < 10; i++) {
+ float ef = i == 0 ? 1.0f : ((i & 1) == 0 ? 0.0f : 1486662021.0f);
+ float cf = doitDownFloat(i);
+ expectEquals(ef, cf);
+ }
+ for (int i = 0; i < 10; i++) {
+ float ef = (i & 1) == 0 ? 1.0f : 1486662020.0f;
+ float cf = doitUpFloatAlt(i);
+ expectEquals(ef, cf);
+ }
+ for (int i = 0; i < 10; i++) {
+ float ef = (i & 1) == 0 ? 1.0f : 1486662020.0f;
+ float cf = doitDownFloatAlt(i);
+ expectEquals(ef, cf);
+ }
+ System.out.println("passed");
+ }
+
+ private static void expectEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ private static void expectEquals(float expected, float result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+}
+
+
diff --git a/test/655-jit-clinit/expected.txt b/test/655-jit-clinit/expected.txt
new file mode 100644
index 0000000000..6a5618ebc6
--- /dev/null
+++ b/test/655-jit-clinit/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/655-jit-clinit/info.txt b/test/655-jit-clinit/info.txt
new file mode 100644
index 0000000000..39c6dec368
--- /dev/null
+++ b/test/655-jit-clinit/info.txt
@@ -0,0 +1,3 @@
+Regression test for the JIT compiler, which used to wait
+on a class object, meaning applocation code could just block
+all JIT compilations.
diff --git a/test/655-jit-clinit/src/Main.java b/test/655-jit-clinit/src/Main.java
new file mode 100644
index 0000000000..44b315478f
--- /dev/null
+++ b/test/655-jit-clinit/src/Main.java
@@ -0,0 +1,51 @@
+/*
+ * 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 Main {
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[0]);
+ if (!hasJit()) {
+ return;
+ }
+ Foo.hotMethod();
+ }
+
+ public native static boolean isJitCompiled(Class<?> cls, String methodName);
+ private native static boolean hasJit();
+}
+
+class Foo {
+ static void hotMethod() {
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = array;
+ }
+ }
+
+ static {
+ array = new Object[10000];
+ while (!Main.isJitCompiled(Foo.class, "hotMethod")) {
+ Foo.hotMethod();
+ try {
+ // Sleep to give a chance for the JIT to compile `hotMethod`.
+ Thread.sleep(100);
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ }
+
+ static Object[] array;
+}
diff --git a/test/802-deoptimization/src/DeoptimizationController.java b/test/802-deoptimization/src/DeoptimizationController.java
index d6e662d04d..88579ded07 100644
--- a/test/802-deoptimization/src/DeoptimizationController.java
+++ b/test/802-deoptimization/src/DeoptimizationController.java
@@ -50,7 +50,7 @@ public class DeoptimizationController {
throw new IllegalStateException("Not tracing.");
}
} catch (Exception exc) {
- exc.printStackTrace(System.err);
+ exc.printStackTrace(System.out);
} finally {
if (tempFile != null) {
tempFile.delete();
@@ -65,7 +65,7 @@ public class DeoptimizationController {
throw new IllegalStateException("Still tracing.");
}
} catch (Exception exc) {
- exc.printStackTrace(System.err);
+ exc.printStackTrace(System.out);
}
}
diff --git a/test/906-iterate-heap/expected.txt b/test/906-iterate-heap/expected.txt
index 73b7129bba..b6af8435de 100644
--- a/test/906-iterate-heap/expected.txt
+++ b/test/906-iterate-heap/expected.txt
@@ -18,14 +18,14 @@
2
1@0 (32, 2xD '0000000000000000000000000000f03f')
2
-doTestPrimitiveFieldsClasses
10000@0 (static, int, index=3) 0000000000000000
10001
10000@0 (static, int, index=11) 0000000000000000
10001
+10000@0 (static, int, index=0) 0000000000000000
10001
+10000@0 (static, int, index=1) 0000000000000000
10001
-doTestPrimitiveFieldsIntegral
10000@0 (instance, int, index=2) 0000000000000000
10001@0 (instance, byte, index=4) 0000000000000001
10002@0 (instance, char, index=5) 0000000000000061
@@ -33,7 +33,6 @@ doTestPrimitiveFieldsIntegral
10004@0 (instance, long, index=7) 0000000000000004
10005@0 (instance, short, index=9) 0000000000000002
10006
-doTestPrimitiveFieldsFloat
10000@0 (instance, int, index=3) 0000000000000000
10001@0 (instance, byte, index=5) 0000000000000001
10002@0 (instance, char, index=6) 0000000000000061
diff --git a/test/906-iterate-heap/iterate_heap.cc b/test/906-iterate-heap/iterate_heap.cc
index 02ac69942a..6534b4c3db 100644
--- a/test/906-iterate-heap/iterate_heap.cc
+++ b/test/906-iterate-heap/iterate_heap.cc
@@ -408,15 +408,5 @@ extern "C" JNIEXPORT jstring JNICALL Java_art_Test906_iterateThroughHeapPrimitiv
return env->NewStringUTF(ffc.data.c_str());
}
-extern "C" JNIEXPORT jboolean JNICALL Java_art_Test906_checkInitialized(
- JNIEnv* env, jclass, jclass c) {
- jint status;
- jvmtiError error = jvmti_env->GetClassStatus(c, &status);
- if (JvmtiErrorToException(env, jvmti_env, error)) {
- return false;
- }
- return (status & JVMTI_CLASS_STATUS_INITIALIZED) != 0;
-}
-
} // namespace Test906IterateHeap
} // namespace art
diff --git a/test/906-iterate-heap/src/art/Test906.java b/test/906-iterate-heap/src/art/Test906.java
index 65c2c8c560..fe18e38501 100644
--- a/test/906-iterate-heap/src/art/Test906.java
+++ b/test/906-iterate-heap/src/art/Test906.java
@@ -142,7 +142,6 @@ public class Test906 {
}
private static void doTestPrimitiveFieldsClasses() {
- System.out.println("doTestPrimitiveFieldsClasses");
setTag(IntObject.class, 10000);
System.out.println(iterateThroughHeapPrimitiveFields(10000));
System.out.println(getTag(IntObject.class));
@@ -153,40 +152,18 @@ public class Test906 {
System.out.println(getTag(FloatObject.class));
setTag(FloatObject.class, 0);
- boolean correctHeapValue = false;
setTag(Inf1.class, 10000);
- String heapTrace = iterateThroughHeapPrimitiveFields(10000);
-
- if (!checkInitialized(Inf1.class)) {
- correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000000");
- } else {
- correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000001");
- }
-
- if (!correctHeapValue)
- System.out.println("Heap Trace for Inf1 is not as expected:\n" + heapTrace);
-
+ System.out.println(iterateThroughHeapPrimitiveFields(10000));
System.out.println(getTag(Inf1.class));
setTag(Inf1.class, 0);
setTag(Inf2.class, 10000);
- heapTrace = iterateThroughHeapPrimitiveFields(10000);
-
- if (!checkInitialized(Inf2.class)) {
- correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000000");
- } else {
- correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000001");
- }
-
- if (!correctHeapValue)
- System.out.println("Heap Trace for Inf2 is not as expected:\n" + heapTrace);
+ System.out.println(iterateThroughHeapPrimitiveFields(10000));
System.out.println(getTag(Inf2.class));
-
setTag(Inf2.class, 0);
}
private static void doTestPrimitiveFieldsIntegral() {
- System.out.println("doTestPrimitiveFieldsIntegral");
IntObject intObject = new IntObject();
setTag(intObject, 10000);
System.out.println(iterateThroughHeapPrimitiveFields(10000));
@@ -194,7 +171,6 @@ public class Test906 {
}
private static void doTestPrimitiveFieldsFloat() {
- System.out.println("doTestPrimitiveFieldsFloat");
FloatObject floatObject = new FloatObject();
setTag(floatObject, 10000);
System.out.println(iterateThroughHeapPrimitiveFields(10000));
@@ -289,7 +265,6 @@ public class Test906 {
return Main.getTag(o);
}
- private static native boolean checkInitialized(Class<?> klass);
private static native int iterateThroughHeapCount(int heapFilter,
Class<?> klassFilter, int stopAfter);
private static native int iterateThroughHeapData(int heapFilter,
diff --git a/test/909-attach-agent/src/Main.java b/test/909-attach-agent/src/Main.java
index 569b89ad7d..25ebd57236 100644
--- a/test/909-attach-agent/src/Main.java
+++ b/test/909-attach-agent/src/Main.java
@@ -19,17 +19,17 @@ import java.io.IOException;
public class Main {
public static void main(String[] args) {
- System.err.println("Hello, world!");
+ System.out.println("Hello, world!");
for(String a : args) {
if(a.startsWith("agent:")) {
String agent = a.substring(6);
try {
VMDebug.attachAgent(agent);
} catch(IOException e) {
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
}
- System.err.println("Goodbye!");
+ System.out.println("Goodbye!");
}
}
diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt
index 80f8b9e947..b128d1cb70 100644
--- a/test/913-heaps/expected.txt
+++ b/test/913-heaps/expected.txt
@@ -140,7 +140,9 @@ root@root --(thread)--> 3000@0 [size=136, length=-1]
10001
10000@0 (static, int, index=11) 0000000000000000
10001
+10000@0 (static, int, index=0) 0000000000000000
10001
+10000@0 (static, int, index=1) 0000000000000000
10001
10000@0 (instance, int, index=2) 0000000000000000
10001@0 (instance, byte, index=4) 0000000000000001
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index bf3f7b66a5..ec36cebd43 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -1078,14 +1078,5 @@ extern "C" JNIEXPORT void JNICALL Java_art_Test913_iterateThroughHeapExt(
CHECK(gFoundExt);
}
-extern "C" JNIEXPORT jboolean JNICALL Java_art_Test913_checkInitialized(JNIEnv* env, jclass, jclass c) {
- jint status;
- jvmtiError error = jvmti_env->GetClassStatus(c, &status);
- if (JvmtiErrorToException(env, jvmti_env, error)) {
- return false;
- }
- return (status & JVMTI_CLASS_STATUS_INITIALIZED) != 0;
-}
-
} // namespace Test913Heaps
} // namespace art
diff --git a/test/913-heaps/src/art/Test913.java b/test/913-heaps/src/art/Test913.java
index b9990010ff..97f48eea03 100644
--- a/test/913-heaps/src/art/Test913.java
+++ b/test/913-heaps/src/art/Test913.java
@@ -195,33 +195,13 @@ public class Test913 {
System.out.println(getTag(FloatObject.class));
setTag(FloatObject.class, 0);
- boolean correctHeapValue = false;
setTag(Inf1.class, 10000);
- String heapTrace = followReferencesPrimitiveFields(Inf1.class);
-
- if (!checkInitialized(Inf1.class)) {
- correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000000");
- } else {
- correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000001");
- }
-
- if (!correctHeapValue)
- System.out.println("Heap Trace for Inf1 is not as expected:\n" + heapTrace);
-
+ System.out.println(followReferencesPrimitiveFields(Inf1.class));
System.out.println(getTag(Inf1.class));
setTag(Inf1.class, 0);
setTag(Inf2.class, 10000);
- heapTrace = followReferencesPrimitiveFields(Inf2.class);
-
- if (!checkInitialized(Inf2.class)) {
- correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000000");
- } else {
- correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000001");
- }
-
- if (!correctHeapValue)
- System.out.println("Heap Trace for Inf2 is not as expected:\n" + heapTrace);
+ System.out.println(followReferencesPrimitiveFields(Inf2.class));
System.out.println(getTag(Inf2.class));
setTag(Inf2.class, 0);
}
@@ -732,7 +712,6 @@ public class Test913 {
return Main.getTag(o);
}
- private static native boolean checkInitialized(Class<?> klass);
private static native void setupGcCallback();
private static native void enableGcTracking(boolean enable);
private static native int getGcStarts();
diff --git a/test/916-obsolete-jit/src/Main.java b/test/916-obsolete-jit/src/Main.java
index 17a7a86ccc..d7b32ba102 100644
--- a/test/916-obsolete-jit/src/Main.java
+++ b/test/916-obsolete-jit/src/Main.java
@@ -132,7 +132,7 @@ public class Main {
"sayHi", Runnable.class, Consumer.class);
} catch (Exception e) {
System.out.println("Unable to find methods!");
- e.printStackTrace();
+ e.printStackTrace(System.out);
return;
}
// Makes sure the stack is the way we want it for the test and does the redefinition. It will
diff --git a/test/934-load-transform/src/Main.java b/test/934-load-transform/src/Main.java
index 1401b7df01..2d0c2978e2 100644
--- a/test/934-load-transform/src/Main.java
+++ b/test/934-load-transform/src/Main.java
@@ -86,7 +86,7 @@ class Main {
run_test.invoke(null);
} catch (Exception e) {
System.out.println(e.toString());
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
}
diff --git a/test/935-non-retransformable/src/Main.java b/test/935-non-retransformable/src/Main.java
index f240224977..5098712044 100644
--- a/test/935-non-retransformable/src/Main.java
+++ b/test/935-non-retransformable/src/Main.java
@@ -97,7 +97,7 @@ class Main {
run_test.invoke(null);
} catch (Exception e) {
System.out.println(e.toString());
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
}
diff --git a/test/938-load-transform-bcp/src-ex/TestMain.java b/test/938-load-transform-bcp/src-ex/TestMain.java
index 3757a0f778..b60fe36556 100644
--- a/test/938-load-transform-bcp/src-ex/TestMain.java
+++ b/test/938-load-transform-bcp/src-ex/TestMain.java
@@ -29,7 +29,7 @@ public class TestMain {
System.out.println(
"Exception occured (did something load OptionalLong before this test method!: "
+ e.toString());
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
}
diff --git a/test/938-load-transform-bcp/src/Main.java b/test/938-load-transform-bcp/src/Main.java
index 69658c0cec..939bdbe02b 100644
--- a/test/938-load-transform-bcp/src/Main.java
+++ b/test/938-load-transform-bcp/src/Main.java
@@ -111,7 +111,7 @@ class Main {
run_test.invoke(null);
} catch (Exception e) {
System.out.println(e.toString());
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
}
diff --git a/test/941-recurive-obsolete-jit/src/Main.java b/test/941-recurive-obsolete-jit/src/Main.java
index 89d593b7cd..e3065a7117 100644
--- a/test/941-recurive-obsolete-jit/src/Main.java
+++ b/test/941-recurive-obsolete-jit/src/Main.java
@@ -116,7 +116,7 @@ public class Main {
"sayHi", int.class, Consumer.class, Runnable.class);
} catch (Exception e) {
System.out.println("Unable to find methods!");
- e.printStackTrace();
+ e.printStackTrace(System.out);
return;
}
// Makes sure the stack is the way we want it for the test and does the redefinition. It will
diff --git a/test/943-private-recursive-jit/src/Main.java b/test/943-private-recursive-jit/src/Main.java
index 871c63674f..09337bae26 100644
--- a/test/943-private-recursive-jit/src/Main.java
+++ b/test/943-private-recursive-jit/src/Main.java
@@ -129,7 +129,7 @@ public class Main {
"privateSayHi", int.class, Consumer.class, Runnable.class);
} catch (Exception e) {
System.out.println("Unable to find methods!");
- e.printStackTrace();
+ e.printStackTrace(System.out);
return;
}
// Makes sure the stack is the way we want it for the test and does the redefinition. It will
diff --git a/test/947-reflect-method/src/art/Test947.java b/test/947-reflect-method/src/art/Test947.java
index 8cb515e492..90e0f81989 100644
--- a/test/947-reflect-method/src/art/Test947.java
+++ b/test/947-reflect-method/src/art/Test947.java
@@ -76,7 +76,7 @@ public class Test947 {
Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
say_hi_method.invoke(t);
} catch (Exception e) {
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
}
diff --git a/test/953-invoke-polymorphic-compiler/src/Main.java b/test/953-invoke-polymorphic-compiler/src/Main.java
index 20a8fec112..ce3f4db5d4 100644
--- a/test/953-invoke-polymorphic-compiler/src/Main.java
+++ b/test/953-invoke-polymorphic-compiler/src/Main.java
@@ -70,30 +70,30 @@ public class Main {
}
public static void fail() {
- System.err.println("fail");
+ System.out.println("fail");
Thread.dumpStack();
}
public static void fail(String message) {
- System.err.println("fail: " + message);
+ System.out.println("fail: " + message);
Thread.dumpStack();
}
public static int Min2Print2(int a, int b) {
int[] values = new int[] { a, b };
- System.err.println("Running Main.Min2Print2(" + Arrays.toString(values) + ")");
+ System.out.println("Running Main.Min2Print2(" + Arrays.toString(values) + ")");
return a > b ? a : b;
}
public static int Min2Print3(int a, int b, int c) {
int[] values = new int[] { a, b, c };
- System.err.println("Running Main.Min2Print3(" + Arrays.toString(values) + ")");
+ System.out.println("Running Main.Min2Print3(" + Arrays.toString(values) + ")");
return a > b ? a : b;
}
public static int Min2Print6(int a, int b, int c, int d, int e, int f) {
int[] values = new int[] { a, b, c, d, e, f };
- System.err.println("Running Main.Min2Print6(" + Arrays.toString(values) + ")");
+ System.out.println("Running Main.Min2Print6(" + Arrays.toString(values) + ")");
return a > b ? a : b;
}
@@ -106,7 +106,7 @@ public class Main {
int y, int z) {
int[] values = new int[] { a, b, c, d, e, f, g, h, i, j, k, l, m,
n, o, p, q, r, s, t, u, v, w, x, y, z };
- System.err.println("Running Main.Min2Print26(" + Arrays.toString(values) + ")");
+ System.out.println("Running Main.Min2Print26(" + Arrays.toString(values) + ")");
return a > b ? a : b;
}
@@ -176,7 +176,7 @@ public class Main {
fail("No NPE for you");
} catch (NullPointerException npe) {}
- System.err.println("BasicTest done.");
+ System.out.println("BasicTest done.");
}
private static boolean And(boolean lhs, boolean rhs) {
@@ -248,7 +248,7 @@ public class Main {
assertEquals(true, (boolean) mh.invoke(false, true));
assertEquals(false, (boolean) mh.invoke(false, false));
- System.err.println("$opt$ReturnBooleanTest done.");
+ System.out.println("$opt$ReturnBooleanTest done.");
}
public static void $opt$ReturnCharTest() throws Throwable {
@@ -257,7 +257,7 @@ public class Main {
MethodType.methodType(char.class, char.class));
assertEquals('B', (char) mh.invokeExact('A'));
assertEquals((char) -55, (char) mh.invokeExact((char) -56));
- System.err.println("$opt$ReturnCharTest done.");
+ System.out.println("$opt$ReturnCharTest done.");
}
public static void $opt$ReturnByteTest() throws Throwable {
@@ -266,7 +266,7 @@ public class Main {
MethodType.methodType(byte.class, byte.class, byte.class));
assertEquals((byte) 30, (byte) mh.invokeExact((byte) 10, (byte) 3));
assertEquals((byte) -90, (byte) mh.invoke((byte) -10, (byte) 9));
- System.err.println("$opt$ReturnByteTest done.");
+ System.out.println("$opt$ReturnByteTest done.");
}
public static void $opt$ReturnShortTest() throws Throwable {
@@ -275,7 +275,7 @@ public class Main {
MethodType.methodType(short.class, short.class, short.class));
assertEquals((short) 3000, (short) mh.invokeExact((short) 1000, (short) 3));
assertEquals((short) -3000, (short) mh.invoke((short) -1000, (short) 3));
- System.err.println("$opt$ReturnShortTest done.");
+ System.out.println("$opt$ReturnShortTest done.");
}
public static void $opt$ReturnIntTest() throws Throwable {
@@ -284,7 +284,7 @@ public class Main {
MethodType.methodType(int.class, int.class, int.class));
assertEquals(3_000_000, (int) mh.invokeExact(1_000_000, 3));
assertEquals(-3_000_000, (int) mh.invoke(-1_000, 3_000));
- System.err.println("$opt$ReturnIntTest done.");
+ System.out.println("$opt$ReturnIntTest done.");
}
public static void $opt$ReturnLongTest() throws Throwable {
@@ -293,7 +293,7 @@ public class Main {
MethodType.methodType(long.class, long.class, long.class));
assertEquals(4_294_967_295_000L, (long) mh.invokeExact(1000L, 4_294_967_295L));
assertEquals(-4_294_967_295_000L, (long) mh.invoke(-1000L, 4_294_967_295L));
- System.err.println("$opt$ReturnLongTest done.");
+ System.out.println("$opt$ReturnLongTest done.");
}
public static void $opt$ReturnFloatTest() throws Throwable {
@@ -302,7 +302,7 @@ public class Main {
MethodType.methodType(float.class, float.class, float.class));
assertEquals(3.0F, (float) mh.invokeExact(1000.0F, 3e-3F));
assertEquals(-3.0F, (float) mh.invoke(-1000.0F, 3e-3F));
- System.err.println("$opt$ReturnFloatTest done.");
+ System.out.println("$opt$ReturnFloatTest done.");
}
public static void $opt$ReturnDoubleTest() throws Throwable {
@@ -311,7 +311,7 @@ public class Main {
MethodType.methodType(double.class, double.class, double.class));
assertEquals(3033000.0, (double) mh.invokeExact(1000.0, 3.033e3));
assertEquals(-3033000.0, (double) mh.invoke(-1000.0, 3.033e3));
- System.err.println("$opt$ReturnDoubleTest done.");
+ System.out.println("$opt$ReturnDoubleTest done.");
}
public static void $opt$ReturnStringTest() throws Throwable {
@@ -320,7 +320,7 @@ public class Main {
MethodType.methodType(String.class, String.class, int.class));
assertEquals("100010001000", (String) mh.invokeExact("1000", 3));
assertEquals("100010001000", (String) mh.invoke("1000", 3));
- System.err.println("$opt$ReturnStringTest done.");
+ System.out.println("$opt$ReturnStringTest done.");
}
public static void ReturnValuesTest() throws Throwable {
@@ -333,7 +333,7 @@ public class Main {
$opt$ReturnFloatTest();
$opt$ReturnDoubleTest();
$opt$ReturnStringTest();
- System.err.println("ReturnValuesTest done.");
+ System.out.println("ReturnValuesTest done.");
}
static class ValueHolder {
diff --git a/test/972-default-imt-collision/src/Main.java b/test/972-default-imt-collision/src/Main.java
index 6819e43ae7..043cef1147 100644
--- a/test/972-default-imt-collision/src/Main.java
+++ b/test/972-default-imt-collision/src/Main.java
@@ -24,7 +24,7 @@ public class Main {
Method test = c.getMethod("testMe", iface);
test.invoke(null, o);
} catch (Exception e) {
- e.printStackTrace();
+ e.printStackTrace(System.out);
System.out.println("FAILED: could not run testMe!");
}
}
diff --git a/test/972-iface-super-multidex/src/Main.java b/test/972-iface-super-multidex/src/Main.java
index 3fb3f45428..dea5f1db68 100644
--- a/test/972-iface-super-multidex/src/Main.java
+++ b/test/972-iface-super-multidex/src/Main.java
@@ -22,7 +22,7 @@ public class Main {
c = Class.forName("ConcreteClass");
} catch (Exception e) {
System.out.println("Could not load class");
- e.printStackTrace();
+ e.printStackTrace(System.out);
return;
}
try {
@@ -30,7 +30,7 @@ public class Main {
System.out.println((String)m.invoke(c.newInstance(), new Object[0]));
} catch (Exception e) {
System.out.println("Unknown exception occurred");
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
try {
Method m = c.getMethod("runConflict");
@@ -41,15 +41,15 @@ public class Main {
}
} catch (AbstractMethodError e) {
System.out.println("Unexpected AME caught");
- e.printStackTrace();
+ e.printStackTrace(System.out);
} catch (NoSuchMethodError e) {
System.out.println("Unexpected NSME caught");
- e.printStackTrace();
+ e.printStackTrace(System.out);
} catch (IncompatibleClassChangeError e) {
System.out.println("Expected ICCE caught");
} catch (Throwable e) {
System.out.println("Unknown exception caught!");
- e.printStackTrace();
+ e.printStackTrace(System.out);
}
}
}
diff --git a/test/973-default-multidex/src/Main.java b/test/973-default-multidex/src/Main.java
index b93265a5b8..c7dd6dc9a3 100644
--- a/test/973-default-multidex/src/Main.java
+++ b/test/973-default-multidex/src/Main.java
@@ -23,7 +23,7 @@ public class Main {
Method m = c.getMethod("callMethod");
System.out.println(m.invoke(c.newInstance(), new Object[0]));
} catch (Exception e) {
- e.printStackTrace();
+ e.printStackTrace(System.out);
System.out.println("FAILED: Could not call method");
return;
}
diff --git a/test/983-source-transform-verify/source_transform.cc b/test/983-source-transform-verify/source_transform.cc
index 3ef3c7cb45..a433dc9b75 100644
--- a/test/983-source-transform-verify/source_transform.cc
+++ b/test/983-source-transform-verify/source_transform.cc
@@ -34,7 +34,7 @@
#include "jvmti.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
// Test infrastructure
diff --git a/test/988-redefine-use-after-free/expected.txt b/test/988-redefine-use-after-free/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/988-redefine-use-after-free/expected.txt
diff --git a/test/988-redefine-use-after-free/info.txt b/test/988-redefine-use-after-free/info.txt
new file mode 100644
index 0000000000..2b683dd75e
--- /dev/null
+++ b/test/988-redefine-use-after-free/info.txt
@@ -0,0 +1,13 @@
+Regression test for b/62237378
+
+It was possible for the JVMTI class redefinition to encounter a use-after-free
+bug if there had been an attempted redefinition that failed due to a
+verification error in the same class loader. Actually encountering the bug
+required that a later redefinition happen to get the same native pointer for its
+dex-file as the failed redefinition.
+
+Hitting this use-after-free can cause many strange outcomes, from CHECK failures
+to segfaults to incorrect redefinition failures (for example on buggy builds
+this test will fail a DCHECK on debug builds, segfault on x86_64 hosts and have
+redefinition of LDexCacheSmash$Transform; erroneously fail with
+JVMTI_ERROR_FAILS_VERIFICATION on 32 bit hosts).
diff --git a/test/988-redefine-use-after-free/run b/test/988-redefine-use-after-free/run
new file mode 100755
index 0000000000..c6e62ae6cd
--- /dev/null
+++ b/test/988-redefine-use-after-free/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+./default-run "$@" --jvmti
diff --git a/test/988-redefine-use-after-free/src-ex/DexCacheSmash.java b/test/988-redefine-use-after-free/src-ex/DexCacheSmash.java
new file mode 100644
index 0000000000..2193a631cd
--- /dev/null
+++ b/test/988-redefine-use-after-free/src-ex/DexCacheSmash.java
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+import art.Redefinition;
+import java.util.Base64;
+
+public class DexCacheSmash {
+ static class Transform {
+ public void foo() {}
+ public void bar() {}
+ public String getId() {
+ return "TRANSFORM_INITIAL";
+ }
+ }
+
+ static class Transform2 {
+ public String getId() {
+ return "TRANSFORM2_INITIAL";
+ }
+ }
+
+ /**
+ * A base64 encoding of the dex/class file of the Transform class above.
+ */
+ static final Redefinition.CommonClassDefinition TRANSFORM_INITIAL =
+ new Redefinition.CommonClassDefinition(Transform.class,
+ Base64.getDecoder().decode(
+ "yv66vgAAADQAFwoABAAPCAAQBwASBwAVAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1i" +
+ "ZXJUYWJsZQEAA2ZvbwEAA2JhcgEABWdldElkAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3Vy" +
+ "Y2VGaWxlAQASRGV4Q2FjaGVTbWFzaC5qYXZhDAAFAAYBABFUUkFOU0ZPUk1fSU5JVElBTAcAFgEA" +
+ "F0RleENhY2hlU21hc2gkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2" +
+ "YS9sYW5nL09iamVjdAEADURleENhY2hlU21hc2gAIAADAAQAAAAAAAQAAAAFAAYAAQAHAAAAHQAB" +
+ "AAEAAAAFKrcAAbEAAAABAAgAAAAGAAEAAAATAAEACQAGAAEABwAAABkAAAABAAAAAbEAAAABAAgA" +
+ "AAAGAAEAAAAUAAEACgAGAAEABwAAABkAAAABAAAAAbEAAAABAAgAAAAGAAEAAAAVAAEACwAMAAEA" +
+ "BwAAABsAAQABAAAAAxICsAAAAAEACAAAAAYAAQAAABcAAgANAAAAAgAOABQAAAAKAAEAAwARABMA" +
+ "CA=="),
+ Base64.getDecoder().decode(
+ "ZGV4CjAzNQDhg9CfghG1SRlLClguRuFYsqihr4F7NsGQAwAAcAAAAHhWNBIAAAAAAAAAAOQCAAAS" +
+ "AAAAcAAAAAcAAAC4AAAAAgAAANQAAAAAAAAAAAAAAAUAAADsAAAAAQAAABQBAABcAgAANAEAAKgB" +
+ "AACwAQAAxAEAAMcBAADiAQAA8wEAABcCAAA3AgAASwIAAF8CAAByAgAAfQIAAIACAACNAgAAkgIA" +
+ "AJcCAACeAgAApAIAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAsAAAACAAAABQAAAAAAAAALAAAA" +
+ "BgAAAAAAAAAAAAEAAAAAAAAAAQANAAAAAAABAA4AAAAAAAAADwAAAAQAAQAAAAAAAAAAAAAAAAAE" +
+ "AAAAAAAAAAEAAACYAQAAzgIAAAAAAAACAAAAvwIAAMUCAAABAAEAAQAAAKsCAAAEAAAAcBAEAAAA" +
+ "DgABAAEAAAAAALACAAABAAAADgAAAAEAAQAAAAAAtQIAAAEAAAAOAAAAAgABAAAAAAC6AgAAAwAA" +
+ "ABoACQARAAAANAEAAAAAAAAAAAAAAAAAAAY8aW5pdD4AEkRleENhY2hlU21hc2guamF2YQABTAAZ" +
+ "TERleENhY2hlU21hc2gkVHJhbnNmb3JtOwAPTERleENhY2hlU21hc2g7ACJMZGFsdmlrL2Fubm90" +
+ "YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24vSW5uZXJDbGFzczsAEkxq" +
+ "YXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABFUUkFOU0ZPUk1fSU5JVElBTAAJ" +
+ "VHJhbnNmb3JtAAFWAAthY2Nlc3NGbGFncwADYmFyAANmb28ABWdldElkAARuYW1lAAV2YWx1ZQAT" +
+ "AAcOABUABw4AFAAHDgAXAAcOAAICAREYAQIDAgwECBAXCgAAAQMAgIAEwAIBAdgCAQHsAgEBgAMO" +
+ "AAAAAAAAAAEAAAAAAAAAAQAAABIAAABwAAAAAgAAAAcAAAC4AAAAAwAAAAIAAADUAAAABQAAAAUA" +
+ "AADsAAAABgAAAAEAAAAUAQAAAxAAAAEAAAA0AQAAASAAAAQAAABAAQAABiAAAAEAAACYAQAAAiAA" +
+ "ABIAAACoAQAAAyAAAAQAAACrAgAABCAAAAIAAAC/AgAAACAAAAEAAADOAgAAABAAAAEAAADkAgAA"));
+
+ /**
+ * A base64 encoding of the following (invalid) class.
+ *
+ * .class LDexCacheSmash$Transform2;
+ * .super Ljava/lang/Object;
+ * .source "DexCacheSmash.java"
+ *
+ * # annotations
+ * .annotation system Ldalvik/annotation/EnclosingClass;
+ * value = LDexCacheSmash;
+ * .end annotation
+ *
+ * .annotation system Ldalvik/annotation/InnerClass;
+ * accessFlags = 0x8
+ * name = "Transform2"
+ * .end annotation
+ *
+ *
+ * # direct methods
+ * .method constructor <init>()V
+ * .registers 1
+ *
+ * .prologue
+ * .line 26
+ * invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+ *
+ * return-void
+ * .end method
+ *
+ *
+ * # virtual methods
+ * .method public getId()Ljava/lang/String;
+ * .registers 2
+ *
+ * .prologue
+ * .line 28
+ * # NB Fails verification due to this function not returning a String.
+ * return-void
+ * .end method
+ */
+ static final Redefinition.CommonClassDefinition TRANSFORM2_INVALID =
+ new Redefinition.CommonClassDefinition(Transform2.class,
+ Base64.getDecoder().decode(
+ "yv66vgAAADQAEwcAEgcAEQEABjxpbml0PgEAAygpVgEABENvZGUKAAIAEAEAD0xpbmVOdW1iZXJU" +
+ "YWJsZQEABWdldElkAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQASRGV4Q2Fj" +
+ "aGVTbWFzaC5qYXZhAQAMSW5uZXJDbGFzc2VzBwAPAQAKVHJhbnNmb3JtMgEADURleENhY2hlU21h" +
+ "c2gMAAMABAEAEGphdmEvbGFuZy9PYmplY3QBABhEZXhDYWNoZVNtYXNoJFRyYW5zZm9ybTIAIAAB" +
+ "AAIAAAAAAAIAAAADAAQAAQAFAAAAHQABAAEAAAAFKrcABrEAAAABAAcAAAAGAAEAAAAaAAEACAAJ" +
+ "AAEABQAAABkAAQABAAAAAbEAAAABAAcAAAAGAAEAAAAcAAIACgAAAAIACwAMAAAACgABAAEADQAO" +
+ "AAg="),
+ Base64.getDecoder().decode(
+ "ZGV4CjAzNQCFcegr6Ns+I7iEF4uLRkUX4yGrLhP6soEgAwAAcAAAAHhWNBIAAAAAAAAAAHQCAAAP" +
+ "AAAAcAAAAAcAAACsAAAAAgAAAMgAAAAAAAAAAAAAAAMAAADgAAAAAQAAAPgAAAAIAgAAGAEAABgB" +
+ "AAAgAQAANAEAADcBAABTAQAAZAEAAIgBAACoAQAAvAEAANABAADcAQAA3wEAAOwBAADzAQAA+QEA" +
+ "AAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAoAAAACAAAABQAAAAAAAAAKAAAABgAAAAAAAAAAAAEA" +
+ "AAAAAAAAAAAMAAAABAABAAAAAAAAAAAAAAAAAAQAAAAAAAAAAQAAACACAABmAgAAAAAAAAY8aW5p" +
+ "dD4AEkRleENhY2hlU21hc2guamF2YQABTAAaTERleENhY2hlU21hc2gkVHJhbnNmb3JtMjsAD0xE" +
+ "ZXhDYWNoZVNtYXNoOwAiTGRhbHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZp" +
+ "ay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcv" +
+ "U3RyaW5nOwAKVHJhbnNmb3JtMgABVgALYWNjZXNzRmxhZ3MABWdldElkAARuYW1lAAV2YWx1ZQAC" +
+ "AwILBAgNFwkCAgEOGAEAAAAAAAIAAAAJAgAAAAIAABQCAAAAAAAAAAAAAAAAAAAaAAcOABwABw4A" +
+ "AAABAAEAAQAAADACAAAEAAAAcBACAAAADgACAAEAAAAAADUCAAABAAAADgAAAAEBAICABLwEAQHU" +
+ "BA4AAAAAAAAAAQAAAAAAAAABAAAADwAAAHAAAAACAAAABwAAAKwAAAADAAAAAgAAAMgAAAAFAAAA" +
+ "AwAAAOAAAAAGAAAAAQAAAPgAAAACIAAADwAAABgBAAAEIAAAAgAAAAACAAADEAAAAgAAABACAAAG" +
+ "IAAAAQAAACACAAADIAAAAgAAADACAAABIAAAAgAAADwCAAAAIAAAAQAAAGYCAAAAEAAAAQAAAHQC" +
+ "AAA="));
+
+ public static void run() throws Exception {
+ try {
+ Redefinition.doMultiClassRedefinition(TRANSFORM2_INVALID);
+ } catch (Exception e) {
+ if (!e.getMessage().endsWith("JVMTI_ERROR_FAILS_VERIFICATION")) {
+ throw new Error(
+ "Unexpected error: Expected failure due to JVMTI_ERROR_FAILS_VERIFICATION", e);
+ }
+ }
+ // Doing this redefinition after a redefinition that failed due to FAILS_VERIFICATION could
+ // cause a use-after-free of the Transform2's DexCache by the redefinition code if it happens
+ // that the native pointer of the art::DexFile created for the Transform redefinition aliases
+ // the one created for Transform2's failed redefinition.
+ //
+ // Due to the order of checks performed by the redefinition code FAILS_VERIFICATION is the only
+ // failure mode that can cause Use-after-frees in this way.
+ //
+ // This should never throw any exceptions (except perhaps OOME in very strange circumstances).
+ Redefinition.doMultiClassRedefinition(TRANSFORM_INITIAL);
+ }
+}
diff --git a/test/988-redefine-use-after-free/src-ex/art/Redefinition.java b/test/988-redefine-use-after-free/src-ex/art/Redefinition.java
new file mode 100644
index 0000000000..56d2938a01
--- /dev/null
+++ b/test/988-redefine-use-after-free/src-ex/art/Redefinition.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/988-redefine-use-after-free/src/Main.java b/test/988-redefine-use-after-free/src/Main.java
new file mode 100644
index 0000000000..d88c471a07
--- /dev/null
+++ b/test/988-redefine-use-after-free/src/Main.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+import java.lang.reflect.*;
+
+public class Main {
+ public static final String TEST_NAME = "988-redefine-use-after-free";
+ public static final int REPS = 1000;
+ public static final int STEP = 100;
+
+ public static void main(String[] args) throws Exception {
+ for (int i = 0; i < REPS; i += STEP) {
+ runSeveralTimes(STEP);
+ }
+ }
+
+ public static ClassLoader getClassLoaderFor(String location) throws Exception {
+ try {
+ Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader");
+ Constructor<?> ctor = class_loader_class.getConstructor(String.class, ClassLoader.class);
+ return (ClassLoader)ctor.newInstance(location + "/" + TEST_NAME + "-ex.jar",
+ Main.class.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ // Running on RI. Use URLClassLoader.
+ return new java.net.URLClassLoader(
+ new java.net.URL[] { new java.net.URL("file://" + location + "/classes-ex/") });
+ }
+ }
+
+ // Run the redefinition several times on a single class-loader to try to trigger the
+ // Use-after-free bug b/62237378
+ public static void runSeveralTimes(int times) throws Exception {
+ ClassLoader c = getClassLoaderFor(System.getenv("DEX_LOCATION"));
+
+ Class<?> klass = (Class<?>)c.loadClass("DexCacheSmash");
+ Method m = klass.getDeclaredMethod("run");
+ for (int i = 0 ; i < times; i++) {
+ m.invoke(null);
+ }
+ }
+}
diff --git a/test/Instrumentation/Instrumentation.java b/test/Instrumentation/Instrumentation.java
index 09d434213b..b44f78fc3b 100644
--- a/test/Instrumentation/Instrumentation.java
+++ b/test/Instrumentation/Instrumentation.java
@@ -15,8 +15,21 @@
*/
public class Instrumentation {
+ private static int primitiveField;
+ private static Object referenceField;
+
// Direct method
private void instanceMethod() {
System.out.println("instanceMethod");
}
+
+ private Object returnReference() {
+ System.out.println("returnReference");
+ return null;
+ }
+
+ private int returnPrimitive() {
+ System.out.println("returnPrimitive");
+ return 0;
+ }
}
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index d2cfbffc30..d8e5b571bd 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -29,7 +29,7 @@
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
@@ -148,12 +148,24 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_isAotCompiled(JNIEnv* env,
CHECK(chars.c_str() != nullptr);
ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
chars.c_str(), kRuntimePointerSize);
- const void* code = method->GetOatMethodQuickCode(kRuntimePointerSize);
- jit::Jit* jit = Runtime::Current()->GetJit();
- if (jit != nullptr && jit->GetCodeCache()->ContainsPc(code)) {
- return true;
+ return method->GetOatMethodQuickCode(kRuntimePointerSize) != nullptr;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isJitCompiled(JNIEnv* env,
+ jclass,
+ jclass cls,
+ jstring method_name) {
+ jit::Jit* jit = GetJitIfEnabled();
+ if (jit == nullptr) {
+ return false;
}
- return code != nullptr;
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+ ScopedUtfChars chars(env, method_name);
+ CHECK(chars.c_str() != nullptr);
+ ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
+ chars.c_str(), kRuntimePointerSize);
+ return jit->GetCodeCache()->ContainsPc(method->GetEntryPointFromQuickCompiledCode());
}
extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc
index ceb4ba241b..80a278012d 100644
--- a/test/common/stack_inspect.cc
+++ b/test/common/stack_inspect.cc
@@ -25,7 +25,7 @@
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "stack.h"
-#include "thread-inl.h"
+#include "thread-current-inl.h"
namespace art {
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index ca52a996ac..7677025c29 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -610,7 +610,7 @@ if [ "$PREBUILD" = "y" ]; then
if [ "$HOST" != "n" ]; then
# Use SIGRTMIN+2 to try to dump threads.
# Use -k 1m to SIGKILL it a minute later if it hasn't ended.
- dex2oat_cmdline="timeout -k 1m -s SIGRTMIN+2 1m ${dex2oat_cmdline}"
+ dex2oat_cmdline="timeout -k 1m -s SIGRTMIN+2 90s ${dex2oat_cmdline} --watchdog-timeout=60000"
fi
if [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then
vdex_cmdline="${dex2oat_cmdline} ${VDEX_FILTER} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex --output-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 36ac307c5e..214b827f6a 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -680,5 +680,31 @@
"The java.lang.Integer.valueOf intrinsic is not supported in PIC mode."
],
"variant": "optimizing & pictest | speed-profile & pictest"
+ },
+ {
+ "tests": "202-thread-oome",
+ "description": "ASAN aborts when large thread stacks are requested.",
+ "variant": "host",
+ "env_vars": {"SANITIZE_HOST": "address"}
+ },
+ {
+ "tests": "202-thread-oome",
+ "description": "ASAN aborts when large thread stacks are requested.",
+ "variant": "target",
+ "env_vars": {"SANITIZE_TARGET": "address"}
+ },
+ {
+ "tests": "071-dexfile-map-clean",
+ "description": [ "We use prebuilt zipalign on master-art-host to avoid pulling in a lot",
+ "of the framework. But a non-sanitized zipalign binary does not work with",
+ "a sanitized libc++."],
+ "env_vars": {"SANITIZE_HOST": "address"}
+ },
+ {
+ "tests": "137-cfi",
+ "description": [ "ASan is reporting out-of-bounds reads in libunwind."],
+ "variant": "host",
+ "env_vars": {"SANITIZE_HOST": "address"},
+ "bug": "b/62350406"
}
]
diff --git a/tools/add_package_property.sh b/tools/add_package_property.sh
new file mode 100644
index 0000000000..e9294a9ed2
--- /dev/null
+++ b/tools/add_package_property.sh
@@ -0,0 +1,29 @@
+#!/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.
+#
+# Sets the property of an Android package
+
+if [ "$#" -ne 2 ] ; then
+ echo "USAGE: sh add_package_property.sh [PACKAGE_NAME] [PROPERTY_SCRIPT_PATH]"
+ exit 1
+fi
+PACKAGE_NAME=$1
+PROPERTY_SCRIPT_PATH=$2
+PROPERTY_SCRIPT_NAME=`basename $PROPERTY_SCRIPT_PATH`
+adb push $PROPERTY_SCRIPT_PATH /data/data/$PACKAGE_NAME/
+adb shell chmod o+x /data/data/$PACKAGE_NAME/$PROPERTY_SCRIPT_NAME
+adb shell restorecon /data/data/$PACKAGE_NAME/$PROPERTY_SCRIPT_NAME
+adb shell setprop wrap.$PACKAGE_NAME /data/data/$PACKAGE_NAME/$PROPERTY_SCRIPT_NAME
diff --git a/tools/asan.sh b/tools/asan.sh
new file mode 100644
index 0000000000..b74954510f
--- /dev/null
+++ b/tools/asan.sh
@@ -0,0 +1,21 @@
+#!/system/bin/sh
+#
+# 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.
+#
+# NOTE: This script is used by add_package_property.sh and not meant to be executed directly
+#
+# This script contains the property and the options required to log poisoned
+# memory accesses (found in logcat)
+ASAN_OPTIONS=halt_on_error=0:verbosity=0:print_legend=0:print_full_thread_history=0:print_stats=0:print_summary=0:suppress_equal_pcs=0:fast_unwind_on_fatal=1 asanwrapper $@