summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp3
-rw-r--r--Android.mk6
-rw-r--r--adbconnection/Android.bp80
-rw-r--r--adbconnection/adbconnection.cc641
-rw-r--r--adbconnection/adbconnection.h155
-rw-r--r--build/Android.common_build.mk5
-rw-r--r--build/Android.common_test.mk8
-rw-r--r--build/Android.gtest.mk12
-rw-r--r--build/Android.oat.mk2
-rw-r--r--build/art.go11
-rw-r--r--cmdline/cmdline_parser_test.cc68
-rw-r--r--cmdline/cmdline_types.h138
-rw-r--r--compiler/Android.bp9
-rw-r--r--compiler/compiler.cc14
-rw-r--r--compiler/compiler.h2
-rw-r--r--compiler/debug/dwarf/writer.h4
-rw-r--r--compiler/debug/elf_debug_frame_writer.h7
-rw-r--r--compiler/debug/elf_debug_info_writer.h46
-rw-r--r--compiler/debug/elf_debug_line_writer.h12
-rw-r--r--compiler/debug/elf_debug_loc_writer.h10
-rw-r--r--compiler/debug/elf_debug_writer.cc40
-rw-r--r--compiler/debug/elf_debug_writer.h7
-rw-r--r--compiler/debug/elf_gnu_debugdata_writer.h10
-rw-r--r--compiler/debug/elf_symtab_writer.h5
-rw-r--r--compiler/debug/method_debug_info.h2
-rw-r--r--compiler/dex/dex_to_dex_compiler.cc18
-rw-r--r--compiler/dex/dex_to_dex_compiler.h2
-rw-r--r--compiler/dex/dex_to_dex_decompiler_test.cc8
-rw-r--r--compiler/dex/inline_method_analyser.cc21
-rw-r--r--compiler/dex/inline_method_analyser.h4
-rw-r--r--compiler/dex/quick_compiler_callbacks.cc2
-rw-r--r--compiler/dex/verification_results.cc3
-rw-r--r--compiler/dex/verified_method.cc9
-rw-r--r--compiler/dex/verified_method.h2
-rw-r--r--compiler/driver/compiled_method_storage.cc3
-rw-r--r--compiler/driver/compiler_driver-inl.h49
-rw-r--r--compiler/driver/compiler_driver.cc140
-rw-r--r--compiler/driver/compiler_driver.h65
-rw-r--r--compiler/driver/compiler_driver_test.cc30
-rw-r--r--compiler/driver/compiler_options.cc20
-rw-r--r--compiler/driver/dex_compilation_unit.cc4
-rw-r--r--compiler/driver/dex_compilation_unit.h9
-rw-r--r--compiler/exception_test.cc27
-rw-r--r--compiler/jit/jit_compiler.cc4
-rw-r--r--compiler/jni/jni_compiler_test.cc8
-rw-r--r--compiler/jni/quick/arm/calling_convention_arm.cc4
-rw-r--r--compiler/jni/quick/arm64/calling_convention_arm64.cc3
-rw-r--r--compiler/jni/quick/calling_convention.cc2
-rw-r--r--compiler/jni/quick/jni_compiler.cc4
-rw-r--r--compiler/jni/quick/mips/calling_convention_mips.cc3
-rw-r--r--compiler/jni/quick/mips64/calling_convention_mips64.cc3
-rw-r--r--compiler/jni/quick/x86/calling_convention_x86.cc3
-rw-r--r--compiler/jni/quick/x86_64/calling_convention_x86_64.cc3
-rw-r--r--compiler/linker/arm/relative_patcher_arm_base.cc2
-rw-r--r--compiler/linker/arm/relative_patcher_thumb2.cc2
-rw-r--r--compiler/linker/elf_builder.h224
-rw-r--r--compiler/linker/error_delaying_output_stream.h4
-rw-r--r--compiler/linker/linker_patch.h3
-rw-r--r--compiler/linker/output_stream_test.cc4
-rw-r--r--compiler/linker/vector_output_stream.cc2
-rw-r--r--compiler/optimizing/block_builder.cc75
-rw-r--r--compiler/optimizing/block_builder.h23
-rw-r--r--compiler/optimizing/builder.cc54
-rw-r--r--compiler/optimizing/builder.h24
-rw-r--r--compiler/optimizing/code_generator.cc55
-rw-r--r--compiler/optimizing/code_generator.h51
-rw-r--r--compiler/optimizing/code_generator_arm64.cc71
-rw-r--r--compiler/optimizing/code_generator_arm64.h2
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc100
-rw-r--r--compiler/optimizing/code_generator_mips.cc208
-rw-r--r--compiler/optimizing/code_generator_mips.h3
-rw-r--r--compiler/optimizing/code_generator_mips64.cc285
-rw-r--r--compiler/optimizing/code_generator_mips64.h1
-rw-r--r--compiler/optimizing/code_generator_utils.cc5
-rw-r--r--compiler/optimizing/code_generator_x86.cc215
-rw-r--r--compiler/optimizing/code_generator_x86.h8
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc237
-rw-r--r--compiler/optimizing/code_generator_x86_64.h5
-rw-r--r--compiler/optimizing/codegen_test.cc4
-rw-r--r--compiler/optimizing/constant_folding.cc2
-rw-r--r--compiler/optimizing/data_type.h3
-rw-r--r--compiler/optimizing/dominator_test.cc2
-rw-r--r--compiler/optimizing/find_loops_test.cc4
-rw-r--r--compiler/optimizing/gvn.cc7
-rw-r--r--compiler/optimizing/inliner.cc83
-rw-r--r--compiler/optimizing/inliner.h2
-rw-r--r--compiler/optimizing/instruction_builder.cc132
-rw-r--r--compiler/optimizing/instruction_builder.h49
-rw-r--r--compiler/optimizing/instruction_simplifier.cc75
-rw-r--r--compiler/optimizing/intrinsics.cc12
-rw-r--r--compiler/optimizing/intrinsics.h2
-rw-r--r--compiler/optimizing/licm.cc27
-rw-r--r--compiler/optimizing/linearize_test.cc4
-rw-r--r--compiler/optimizing/live_ranges_test.cc4
-rw-r--r--compiler/optimizing/liveness_test.cc4
-rw-r--r--compiler/optimizing/load_store_elimination.cc127
-rw-r--r--compiler/optimizing/loop_optimization.cc3
-rw-r--r--compiler/optimizing/loop_optimization_test.cc83
-rw-r--r--compiler/optimizing/nodes.cc171
-rw-r--r--compiler/optimizing/nodes.h71
-rw-r--r--compiler/optimizing/nodes_vector.h25
-rw-r--r--compiler/optimizing/optimization.cc9
-rw-r--r--compiler/optimizing/optimizing_cfi_test.cc4
-rw-r--r--compiler/optimizing/optimizing_compiler.cc28
-rw-r--r--compiler/optimizing/optimizing_compiler_stats.h1
-rw-r--r--compiler/optimizing/optimizing_unit_test.h8
-rw-r--r--compiler/optimizing/prepare_for_register_allocation.cc2
-rw-r--r--compiler/optimizing/pretty_printer_test.cc4
-rw-r--r--compiler/optimizing/reference_type_propagation.cc8
-rw-r--r--compiler/optimizing/register_allocator_test.cc6
-rw-r--r--compiler/optimizing/scheduler.h5
-rw-r--r--compiler/optimizing/scheduler_arm64.h14
-rw-r--r--compiler/optimizing/sharpening.cc44
-rw-r--r--compiler/optimizing/sharpening.h19
-rw-r--r--compiler/optimizing/ssa_builder.cc4
-rw-r--r--compiler/optimizing/ssa_liveness_analysis.cc7
-rw-r--r--compiler/optimizing/ssa_test.cc4
-rw-r--r--compiler/optimizing/stack_map_stream.cc2
-rw-r--r--compiler/optimizing/superblock_cloner_test.cc (renamed from compiler/optimizing/cloner_test.cc)6
-rw-r--r--compiler/optimizing/suspend_check_test.cc2
-rw-r--r--compiler/trampolines/trampoline_compiler.h1
-rw-r--r--compiler/utils/arm/assembler_arm_vixl.h4
-rw-r--r--compiler/utils/arm/constants_arm.h3
-rw-r--r--compiler/utils/arm/jni_macro_assembler_arm_vixl.h4
-rw-r--r--compiler/utils/arm/managed_register_arm.h3
-rw-r--r--compiler/utils/arm64/assembler_arm64.cc1
-rw-r--r--compiler/utils/arm64/assembler_arm64.h4
-rw-r--r--compiler/utils/arm64/jni_macro_assembler_arm64.cc1
-rw-r--r--compiler/utils/arm64/jni_macro_assembler_arm64.h4
-rw-r--r--compiler/utils/arm64/managed_register_arm64.h3
-rw-r--r--compiler/utils/assembler.h3
-rw-r--r--compiler/utils/atomic_dex_ref_map-inl.h4
-rw-r--r--compiler/utils/atomic_dex_ref_map.h2
-rw-r--r--compiler/utils/atomic_dex_ref_map_test.cc2
-rw-r--r--compiler/utils/intrusive_forward_list.h3
-rw-r--r--compiler/utils/jni_macro_assembler.h3
-rw-r--r--compiler/utils/label.h4
-rw-r--r--compiler/utils/mips/assembler_mips.cc1394
-rw-r--r--compiler/utils/mips/assembler_mips.h127
-rw-r--r--compiler/utils/mips/constants_mips.h3
-rw-r--r--compiler/utils/mips64/assembler_mips64.cc31
-rw-r--r--compiler/utils/mips64/assembler_mips64.h4
-rw-r--r--compiler/utils/mips64/assembler_mips64_test.cc31
-rw-r--r--compiler/utils/mips64/constants_mips64.h3
-rw-r--r--compiler/utils/string_reference_test.cc2
-rw-r--r--compiler/utils/swap_space.cc1
-rw-r--r--compiler/utils/swap_space.h3
-rw-r--r--compiler/utils/test_dex_file_builder.h7
-rw-r--r--compiler/utils/test_dex_file_builder_test.cc2
-rw-r--r--compiler/utils/x86/constants_x86.h3
-rw-r--r--compiler/utils/x86_64/constants_x86_64.h3
-rw-r--r--compiler/verifier_deps_test.cc11
-rw-r--r--dex2oat/dex2oat.cc30
-rw-r--r--dex2oat/dex2oat_image_test.cc7
-rw-r--r--dex2oat/dex2oat_options.h2
-rw-r--r--dex2oat/dex2oat_test.cc16
-rw-r--r--dex2oat/linker/elf_writer_quick.cc9
-rw-r--r--dex2oat/linker/image_test.h17
-rw-r--r--dex2oat/linker/image_writer.cc274
-rw-r--r--dex2oat/linker/image_writer.h139
-rw-r--r--dex2oat/linker/index_bss_mapping_encoder.h3
-rw-r--r--dex2oat/linker/multi_oat_relative_patcher.cc3
-rw-r--r--dex2oat/linker/oat_writer.cc75
-rw-r--r--dex2oat/linker/oat_writer.h2
-rw-r--r--dex2oat/linker/oat_writer_test.cc15
-rw-r--r--dexdump/dexdump.cc55
-rw-r--r--dexdump/dexdump_cfg.cc51
-rw-r--r--dexdump/dexdump_main.cc4
-rw-r--r--dexlayout/compact_dex_writer.cc16
-rw-r--r--dexlayout/compact_dex_writer.h2
-rw-r--r--dexlayout/dex_ir.cc59
-rw-r--r--dexlayout/dex_ir.h49
-rw-r--r--dexlayout/dex_ir_builder.cc3
-rw-r--r--dexlayout/dex_visualize.cc12
-rw-r--r--dexlayout/dex_writer.cc23
-rw-r--r--dexlayout/dex_writer.h3
-rw-r--r--dexlayout/dexdiag.cc3
-rw-r--r--dexlayout/dexlayout.cc25
-rw-r--r--dexlayout/dexlayout.h13
-rw-r--r--dexlayout/dexlayout_main.cc4
-rw-r--r--dexlayout/dexlayout_test.cc7
-rw-r--r--dexlist/dexlist.cc12
-rw-r--r--dexoptanalyzer/dexoptanalyzer.cc4
-rw-r--r--disassembler/disassembler_mips.cc5
-rw-r--r--dt_fd_forward/Android.bp66
-rw-r--r--dt_fd_forward/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION0
-rw-r--r--dt_fd_forward/NOTICE30
-rw-r--r--dt_fd_forward/README.md32
-rw-r--r--dt_fd_forward/dt_fd_forward.cc761
-rw-r--r--dt_fd_forward/dt_fd_forward.h154
-rw-r--r--dt_fd_forward/export/Android.bp22
-rw-r--r--dt_fd_forward/export/MODULE_LICENSE_APACHE20
-rw-r--r--dt_fd_forward/export/fd_transport.h69
-rw-r--r--imgdiag/imgdiag.cc8
-rw-r--r--oatdump/Android.mk4
-rw-r--r--oatdump/oatdump.cc28
-rw-r--r--openjdkjvm/OpenjdkJvm.cc9
-rw-r--r--openjdkjvmti/OpenjdkJvmTi.cc5
-rw-r--r--openjdkjvmti/art_jvmti.h3
-rw-r--r--openjdkjvmti/deopt_manager.cc2
-rw-r--r--openjdkjvmti/events.cc39
-rw-r--r--openjdkjvmti/events.h17
-rw-r--r--openjdkjvmti/fixed_up_dex_file.cc4
-rw-r--r--openjdkjvmti/fixed_up_dex_file.h2
-rw-r--r--openjdkjvmti/jvmti_allocator.h5
-rw-r--r--openjdkjvmti/jvmti_weak_table-inl.h3
-rw-r--r--openjdkjvmti/ti_breakpoint.cc4
-rw-r--r--openjdkjvmti/ti_class.cc6
-rw-r--r--openjdkjvmti/ti_class_definition.cc2
-rw-r--r--openjdkjvmti/ti_class_loader.cc8
-rw-r--r--openjdkjvmti/ti_class_loader.h2
-rw-r--r--openjdkjvmti/ti_ddms.cc24
-rw-r--r--openjdkjvmti/ti_extension.cc2
-rw-r--r--openjdkjvmti/ti_field.cc2
-rw-r--r--openjdkjvmti/ti_method.cc68
-rw-r--r--openjdkjvmti/ti_monitor.cc16
-rw-r--r--openjdkjvmti/ti_redefine.cc10
-rw-r--r--openjdkjvmti/ti_redefine.h2
-rw-r--r--openjdkjvmti/ti_search.cc4
-rw-r--r--openjdkjvmti/ti_stack.cc11
-rw-r--r--openjdkjvmti/ti_thread.cc5
-rw-r--r--openjdkjvmti/transform.cc4
-rw-r--r--patchoat/Android.bp13
-rw-r--r--patchoat/patchoat.cc1
-rw-r--r--patchoat/patchoat_test.cc411
-rw-r--r--profman/boot_image_profile.cc2
-rw-r--r--profman/boot_image_profile.h2
-rw-r--r--profman/profman.cc10
-rw-r--r--runtime/Android.bp40
-rw-r--r--runtime/aot_class_linker.cc6
-rw-r--r--runtime/arch/arm/context_arm.h3
-rw-r--r--runtime/arch/arm/fault_handler_arm.cc2
-rw-r--r--runtime/arch/arm/instruction_set_features_arm.cc7
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S4
-rw-r--r--runtime/arch/arm/thread_arm.cc3
-rw-r--r--runtime/arch/arm64/context_arm64.h3
-rw-r--r--runtime/arch/arm64/fault_handler_arm64.cc2
-rw-r--r--runtime/arch/arm64/instruction_set_features_arm64.cc6
-rw-r--r--runtime/arch/arm64/quick_entrypoints_arm64.S4
-rw-r--r--runtime/arch/arm64/thread_arm64.cc3
-rw-r--r--runtime/arch/code_offset.h4
-rw-r--r--runtime/arch/instruction_set_features_test.cc7
-rw-r--r--runtime/arch/mips/context_mips.h3
-rw-r--r--runtime/arch/mips/entrypoints_init_mips.cc1
-rw-r--r--runtime/arch/mips/fault_handler_mips.cc2
-rw-r--r--runtime/arch/mips/instruction_set_features_mips.cc5
-rw-r--r--runtime/arch/mips/instruction_set_features_mips.h3
-rw-r--r--runtime/arch/mips/quick_entrypoints_mips.S3
-rw-r--r--runtime/arch/mips/registers_mips.h6
-rw-r--r--runtime/arch/mips/thread_mips.cc3
-rw-r--r--runtime/arch/mips64/context_mips64.h3
-rw-r--r--runtime/arch/mips64/fault_handler_mips64.cc2
-rw-r--r--runtime/arch/mips64/quick_entrypoints_mips64.S3
-rw-r--r--runtime/arch/mips64/registers_mips64.h6
-rw-r--r--runtime/arch/mips64/thread_mips64.cc3
-rw-r--r--runtime/arch/x86/context_x86.h3
-rw-r--r--runtime/arch/x86/fault_handler_x86.cc2
-rw-r--r--runtime/arch/x86/instruction_set_features_x86.cc6
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S3
-rw-r--r--runtime/arch/x86/registers_x86.h3
-rw-r--r--runtime/arch/x86_64/context_x86_64.h3
-rw-r--r--runtime/arch/x86_64/quick_entrypoints_x86_64.S3
-rw-r--r--runtime/arch/x86_64/registers_x86_64.h3
-rw-r--r--runtime/art_field-inl.h38
-rw-r--r--runtime/art_field.cc10
-rw-r--r--runtime/art_field.h5
-rw-r--r--runtime/art_method-inl.h51
-rw-r--r--runtime/art_method.cc23
-rw-r--r--runtime/art_method.h22
-rw-r--r--runtime/atomic.h126
-rw-r--r--runtime/barrier.cc4
-rw-r--r--runtime/base/aborting.h31
-rw-r--r--runtime/base/allocator.cc3
-rw-r--r--runtime/base/allocator.h9
-rw-r--r--runtime/base/arena_allocator.cc3
-rw-r--r--runtime/base/arena_allocator.h6
-rw-r--r--runtime/base/arena_object.h6
-rw-r--r--runtime/base/array_ref.h2
-rw-r--r--runtime/base/bit_field.h3
-rw-r--r--runtime/base/bit_string.h11
-rw-r--r--runtime/base/bit_utils.h3
-rw-r--r--runtime/base/bit_utils_iterator.h3
-rw-r--r--runtime/base/bit_vector-inl.h6
-rw-r--r--runtime/base/bounded_fifo.h3
-rw-r--r--runtime/base/casts.h34
-rw-r--r--runtime/base/dchecked_vector.h2
-rw-r--r--runtime/base/debug_stack.h5
-rw-r--r--runtime/base/file_magic.cc6
-rw-r--r--runtime/base/file_utils.cc8
-rw-r--r--runtime/base/file_utils.h5
-rw-r--r--runtime/base/hash_set.h4
-rw-r--r--runtime/base/histogram-inl.h2
-rw-r--r--runtime/base/histogram.h2
-rw-r--r--runtime/base/logging.cc52
-rw-r--r--runtime/base/logging.h43
-rw-r--r--runtime/base/logging_test.cc1
-rw-r--r--runtime/base/macros.h4
-rw-r--r--runtime/base/mutex-inl.h6
-rw-r--r--runtime/base/mutex.cc67
-rw-r--r--runtime/base/mutex.h4
-rw-r--r--runtime/base/runtime_debug.cc74
-rw-r--r--runtime/base/runtime_debug.h61
-rw-r--r--runtime/base/scoped_arena_allocator.h3
-rw-r--r--runtime/base/scoped_flock.cc4
-rw-r--r--runtime/base/scoped_flock.h3
-rw-r--r--runtime/base/stl_util.h2
-rw-r--r--runtime/base/stringpiece.cc2
-rw-r--r--runtime/base/systrace.h42
-rw-r--r--runtime/base/time_utils.h9
-rw-r--r--runtime/base/timing_logger.cc3
-rw-r--r--runtime/base/unix_file/fd_file.cc2
-rw-r--r--runtime/bytecode_utils.h6
-rw-r--r--runtime/cdex/compact_dex_file.cc49
-rw-r--r--runtime/cha.cc1
-rw-r--r--runtime/check_jni.cc80
-rw-r--r--runtime/check_reference_map_visitor.h8
-rw-r--r--runtime/class_linker-inl.h130
-rw-r--r--runtime/class_linker.cc515
-rw-r--r--runtime/class_linker.h161
-rw-r--r--runtime/class_linker_test.cc69
-rw-r--r--runtime/class_loader_context.cc4
-rw-r--r--runtime/class_loader_context_test.cc2
-rw-r--r--runtime/class_reference.h2
-rw-r--r--runtime/class_status.h62
-rw-r--r--runtime/class_table-inl.h4
-rw-r--r--runtime/class_table.cc2
-rw-r--r--runtime/class_table_test.cc2
-rw-r--r--runtime/common_dex_operations.h7
-rw-r--r--runtime/common_runtime_test.cc5
-rw-r--r--runtime/common_runtime_test.h11
-rw-r--r--runtime/common_throws.cc56
-rw-r--r--runtime/compiler_callbacks.h2
-rw-r--r--runtime/debugger.cc137
-rw-r--r--runtime/debugger.h18
-rw-r--r--runtime/dex/code_item_accessors-inl.h49
-rw-r--r--runtime/dex/code_item_accessors-no_art-inl.h (renamed from runtime/code_item_accessors-inl.h)119
-rw-r--r--runtime/dex/code_item_accessors.h (renamed from runtime/code_item_accessors.h)65
-rw-r--r--runtime/dex/code_item_accessors_test.cc (renamed from runtime/code_item_accessors_test.cc)10
-rw-r--r--runtime/dex/compact_dex_file.cc90
-rw-r--r--runtime/dex/compact_dex_file.h (renamed from runtime/cdex/compact_dex_file.h)30
-rw-r--r--runtime/dex/compact_dex_file_test.cc (renamed from runtime/cdex/compact_dex_file_test.cc)4
-rw-r--r--runtime/dex/compact_dex_level.h50
-rw-r--r--runtime/dex/dex_file-inl.h (renamed from runtime/dex_file-inl.h)43
-rw-r--r--runtime/dex/dex_file.cc (renamed from runtime/dex_file.cc)119
-rw-r--r--runtime/dex/dex_file.h (renamed from runtime/dex_file.h)110
-rw-r--r--runtime/dex/dex_file_annotations.cc (renamed from runtime/dex_file_annotations.cc)35
-rw-r--r--runtime/dex/dex_file_annotations.h (renamed from runtime/dex_file_annotations.h)23
-rw-r--r--runtime/dex/dex_file_exception_helpers.cc104
-rw-r--r--runtime/dex/dex_file_exception_helpers.h68
-rw-r--r--runtime/dex/dex_file_layout.cc (renamed from runtime/dex_file_layout.cc)0
-rw-r--r--runtime/dex/dex_file_layout.h (renamed from runtime/dex_file_layout.h)8
-rw-r--r--runtime/dex/dex_file_loader.cc (renamed from runtime/dex_file_loader.cc)2
-rw-r--r--runtime/dex/dex_file_loader.h (renamed from runtime/dex_file_loader.h)6
-rw-r--r--runtime/dex/dex_file_reference.h (renamed from runtime/dex_file_reference.h)6
-rw-r--r--runtime/dex/dex_file_test.cc (renamed from runtime/dex_file_test.cc)5
-rw-r--r--runtime/dex/dex_file_tracking_registrar.cc (renamed from runtime/dex_file_tracking_registrar.cc)20
-rw-r--r--runtime/dex/dex_file_tracking_registrar.h (renamed from runtime/dex_file_tracking_registrar.h)6
-rw-r--r--runtime/dex/dex_file_types.h (renamed from runtime/dex_file_types.h)6
-rw-r--r--runtime/dex/dex_file_verifier.cc (renamed from runtime/dex_file_verifier.cc)51
-rw-r--r--runtime/dex/dex_file_verifier.h (renamed from runtime/dex_file_verifier.h)6
-rw-r--r--runtime/dex/dex_file_verifier_test.cc (renamed from runtime/dex_file_verifier_test.cc)0
-rw-r--r--runtime/dex/dex_instruction-inl.h (renamed from runtime/dex_instruction-inl.h)6
-rw-r--r--runtime/dex/dex_instruction.cc (renamed from runtime/dex_instruction.cc)0
-rw-r--r--runtime/dex/dex_instruction.h (renamed from runtime/dex_instruction.h)9
-rw-r--r--runtime/dex/dex_instruction_iterator.h (renamed from runtime/dex_instruction_iterator.h)10
-rw-r--r--runtime/dex/dex_instruction_list.h (renamed from runtime/dex_instruction_list.h)8
-rw-r--r--runtime/dex/dex_instruction_test.cc (renamed from runtime/dex_instruction_test.cc)0
-rw-r--r--runtime/dex/dex_instruction_utils.h (renamed from runtime/dex_instruction_utils.h)6
-rw-r--r--runtime/dex/standard_dex_file.cc (renamed from runtime/standard_dex_file.cc)39
-rw-r--r--runtime/dex/standard_dex_file.h (renamed from runtime/standard_dex_file.h)11
-rw-r--r--runtime/dex2oat_environment_test.h2
-rw-r--r--runtime/dex_cache_resolved_classes.h2
-rw-r--r--runtime/dex_to_dex_decompiler.cc23
-rw-r--r--runtime/dex_to_dex_decompiler.h5
-rw-r--r--runtime/dexopt_test.cc7
-rw-r--r--runtime/elf_file.cc1
-rw-r--r--runtime/elf_utils.h4
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h45
-rw-r--r--runtime/entrypoints/entrypoint_utils.cc2
-rw-r--r--runtime/entrypoints/entrypoint_utils.h17
-rw-r--r--runtime/entrypoints/jni/jni_entrypoints.cc3
-rw-r--r--runtime/entrypoints/quick/quick_alloc_entrypoints.cc2
-rw-r--r--runtime/entrypoints/quick/quick_default_init_entrypoints.h2
-rw-r--r--runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc2
-rw-r--r--runtime/entrypoints/quick/quick_dexcache_entrypoints.cc50
-rw-r--r--runtime/entrypoints/quick/quick_field_entrypoints.cc92
-rw-r--r--runtime/entrypoints/quick/quick_fillarray_entrypoints.cc2
-rw-r--r--runtime/entrypoints/quick/quick_jni_entrypoints.cc19
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc44
-rw-r--r--runtime/fault_handler.cc3
-rw-r--r--runtime/gc/accounting/atomic_stack.h7
-rw-r--r--runtime/gc/accounting/bitmap-inl.h6
-rw-r--r--runtime/gc/accounting/card_table-inl.h12
-rw-r--r--runtime/gc/accounting/card_table.cc1
-rw-r--r--runtime/gc/accounting/heap_bitmap.h5
-rw-r--r--runtime/gc/accounting/mod_union_table.cc1
-rw-r--r--runtime/gc/accounting/space_bitmap-inl.h5
-rw-r--r--runtime/gc/accounting/space_bitmap.cc2
-rw-r--r--runtime/gc/allocation_record.cc1
-rw-r--r--runtime/gc/allocator/dlmalloc.cc3
-rw-r--r--runtime/gc/allocator/rosalloc.cc1
-rw-r--r--runtime/gc/allocator/rosalloc.h3
-rw-r--r--runtime/gc/collector/concurrent_copying.cc17
-rw-r--r--runtime/gc/collector/concurrent_copying.h5
-rw-r--r--runtime/gc/collector/garbage_collector.cc2
-rw-r--r--runtime/gc/collector/immune_spaces.cc1
-rw-r--r--runtime/gc/collector/mark_compact.cc4
-rw-r--r--runtime/gc/collector/mark_sweep.cc2
-rw-r--r--runtime/gc/collector/semi_space.cc2
-rw-r--r--runtime/gc/gc_cause.cc5
-rw-r--r--runtime/gc/heap-inl.h3
-rw-r--r--runtime/gc/heap.cc48
-rw-r--r--runtime/gc/heap.h13
-rw-r--r--runtime/gc/reference_processor.cc2
-rw-r--r--runtime/gc/space/bump_pointer_space-inl.h2
-rw-r--r--runtime/gc/space/dlmalloc_space.cc1
-rw-r--r--runtime/gc/space/image_space.cc6
-rw-r--r--runtime/gc/space/image_space_fs.h2
-rw-r--r--runtime/gc/space/large_object_space.cc4
-rw-r--r--runtime/gc/space/malloc_space.cc1
-rw-r--r--runtime/gc/space/region_space-inl.h2
-rw-r--r--runtime/gc/space/region_space.h7
-rw-r--r--runtime/gc/space/rosalloc_space.cc1
-rw-r--r--runtime/gc/space/space.cc4
-rw-r--r--runtime/gc/verification.cc2
-rw-r--r--runtime/generated/asm_support_gen.h2
-rw-r--r--runtime/handle.h3
-rw-r--r--runtime/handle_scope.h3
-rw-r--r--runtime/hprof/hprof.cc8
-rw-r--r--runtime/image.cc2
-rw-r--r--runtime/image.h4
-rw-r--r--runtime/imtable-inl.h2
-rw-r--r--runtime/indenter.h3
-rw-r--r--runtime/index_bss_mapping.h3
-rw-r--r--runtime/indirect_reference_table.cc2
-rw-r--r--runtime/indirect_reference_table.h4
-rw-r--r--runtime/instrumentation.cc15
-rw-r--r--runtime/instrumentation_test.cc2
-rw-r--r--runtime/interpreter/interpreter.cc60
-rw-r--r--runtime/interpreter/interpreter.h12
-rw-r--r--runtime/interpreter/interpreter_common.cc31
-rw-r--r--runtime/interpreter/interpreter_common.h25
-rw-r--r--runtime/interpreter/interpreter_intrinsics.cc2
-rw-r--r--runtime/interpreter/interpreter_mterp_impl.h2
-rw-r--r--runtime/interpreter/interpreter_switch_impl.cc32
-rw-r--r--runtime/interpreter/interpreter_switch_impl.h5
-rw-r--r--runtime/interpreter/mterp/mips/entry.S1
-rw-r--r--runtime/interpreter/mterp/mips/footer.S1
-rw-r--r--runtime/interpreter/mterp/mips/header.S2
-rw-r--r--runtime/interpreter/mterp/mterp.cc34
-rw-r--r--runtime/interpreter/mterp/out/mterp_mips.S4
-rw-r--r--runtime/interpreter/shadow_frame.cc6
-rw-r--r--runtime/interpreter/shadow_frame.h2
-rw-r--r--runtime/interpreter/unstarted_runtime.cc8
-rw-r--r--runtime/interpreter/unstarted_runtime.h5
-rw-r--r--runtime/interpreter/unstarted_runtime_test.cc2
-rw-r--r--runtime/java_vm_ext.cc33
-rw-r--r--runtime/java_vm_ext.h6
-rw-r--r--runtime/jdwp/jdwp.h8
-rw-r--r--runtime/jdwp/jdwp_adb.cc2
-rw-r--r--runtime/jdwp/jdwp_event.cc2
-rw-r--r--runtime/jdwp/jdwp_expand_buf.cc3
-rw-r--r--runtime/jdwp/jdwp_handler.cc2
-rw-r--r--runtime/jdwp/jdwp_main.cc115
-rw-r--r--runtime/jdwp/jdwp_options_test.cc79
-rw-r--r--runtime/jdwp/jdwp_socket.cc2
-rw-r--r--runtime/jdwp_provider.h (renamed from runtime/base/type_static_if.h)30
-rw-r--r--runtime/jit/debugger_interface.cc3
-rw-r--r--runtime/jit/jit.cc10
-rw-r--r--runtime/jit/jit_code_cache.cc3
-rw-r--r--runtime/jit/profile_compilation_info.cc9
-rw-r--r--runtime/jit/profile_compilation_info.h4
-rw-r--r--runtime/jit/profile_compilation_info_test.cc2
-rw-r--r--runtime/jit/profile_saver.cc3
-rw-r--r--runtime/jit/profiling_info.cc6
-rw-r--r--runtime/jni_env_ext-inl.h8
-rw-r--r--runtime/jni_env_ext.cc85
-rw-r--r--runtime/jni_env_ext.h128
-rw-r--r--runtime/jni_internal.cc28
-rw-r--r--runtime/jni_internal_test.cc153
-rw-r--r--runtime/leb128.h4
-rw-r--r--runtime/lock_word.h3
-rw-r--r--runtime/managed_stack.h3
-rw-r--r--runtime/mem_map.cc36
-rw-r--r--runtime/memory_region.cc3
-rw-r--r--runtime/memory_region.h3
-rw-r--r--runtime/method_handles-inl.h2
-rw-r--r--runtime/method_handles.cc33
-rw-r--r--runtime/method_handles.h2
-rw-r--r--runtime/method_info.h4
-rw-r--r--runtime/method_reference.h4
-rw-r--r--runtime/mirror/array-inl.h4
-rw-r--r--runtime/mirror/array.cc2
-rw-r--r--runtime/mirror/class-inl.h4
-rw-r--r--runtime/mirror/class-refvisitor-inl.h6
-rw-r--r--runtime/mirror/class.cc56
-rw-r--r--runtime/mirror/class.h67
-rw-r--r--runtime/mirror/class_ext.cc2
-rw-r--r--runtime/mirror/dex_cache-inl.h7
-rw-r--r--runtime/mirror/dex_cache.cc1
-rw-r--r--runtime/mirror/dex_cache.h3
-rw-r--r--runtime/mirror/dex_cache_test.cc2
-rw-r--r--runtime/mirror/emulated_stack_frame.h2
-rw-r--r--runtime/mirror/method_handle_impl.cc8
-rw-r--r--runtime/mirror/method_handle_impl.h4
-rw-r--r--runtime/mirror/object-inl.h20
-rw-r--r--runtime/mirror/object-readbarrier-inl.h6
-rw-r--r--runtime/mirror/object.cc8
-rw-r--r--runtime/mirror/object_reference-inl.h5
-rw-r--r--runtime/mirror/object_test.cc2
-rw-r--r--runtime/mirror/string-inl.h9
-rw-r--r--runtime/mirror/throwable.cc2
-rw-r--r--runtime/mirror/var_handle.cc88
-rw-r--r--runtime/mirror/var_handle.h11
-rw-r--r--runtime/mirror/var_handle_test.cc74
-rw-r--r--runtime/monitor.cc112
-rw-r--r--runtime/monitor.h4
-rw-r--r--runtime/monitor_objects_stack_visitor.h159
-rw-r--r--runtime/monitor_pool.cc2
-rw-r--r--runtime/native/dalvik_system_DexFile.cc4
-rw-r--r--runtime/native/dalvik_system_VMDebug.cc59
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc14
-rw-r--r--runtime/native/dalvik_system_VMStack.cc27
-rw-r--r--runtime/native/dalvik_system_ZygoteHooks.cc7
-rw-r--r--runtime/native/java_lang_Class.cc8
-rw-r--r--runtime/native/java_lang_Thread.cc2
-rw-r--r--runtime/native/java_lang_VMClassLoader.cc2
-rw-r--r--runtime/native/java_lang_reflect_Array.cc2
-rw-r--r--runtime/native/java_lang_reflect_Constructor.cc2
-rw-r--r--runtime/native/java_lang_reflect_Executable.cc2
-rw-r--r--runtime/native/java_lang_reflect_Field.cc4
-rw-r--r--runtime/native/java_lang_reflect_Method.cc2
-rw-r--r--runtime/native/java_lang_reflect_Parameter.cc4
-rw-r--r--runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc3
-rw-r--r--runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc11
-rw-r--r--runtime/native_bridge_art_interface.cc4
-rw-r--r--runtime/native_stack_dump.cc1
-rw-r--r--runtime/non_debuggable_classes.cc1
-rw-r--r--runtime/oat.h6
-rw-r--r--runtime/oat_file.cc26
-rw-r--r--runtime/oat_file.h21
-rw-r--r--runtime/oat_file_assistant.cc4
-rw-r--r--runtime/oat_file_manager.cc8
-rw-r--r--runtime/oat_quick_method_header.cc2
-rw-r--r--runtime/os_linux.cc3
-rw-r--r--runtime/parsed_options.cc13
-rw-r--r--runtime/plugin.cc2
-rw-r--r--runtime/plugin.h3
-rw-r--r--runtime/primitive.h3
-rw-r--r--runtime/quick_exception_handler.cc14
-rw-r--r--runtime/quick_exception_handler.h3
-rw-r--r--runtime/quicken_info.h2
-rw-r--r--runtime/read_barrier-inl.h4
-rw-r--r--runtime/read_barrier.h4
-rw-r--r--runtime/reflection.cc10
-rw-r--r--runtime/runtime.cc95
-rw-r--r--runtime/runtime.h37
-rw-r--r--runtime/runtime_callbacks.cc29
-rw-r--r--runtime/runtime_callbacks.h28
-rw-r--r--runtime/runtime_common.cc8
-rw-r--r--runtime/runtime_options.def7
-rw-r--r--runtime/safe_map.h3
-rw-r--r--runtime/scoped_thread_state_change-inl.h6
-rw-r--r--runtime/scoped_thread_state_change.cc1
-rw-r--r--runtime/scoped_thread_state_change.h2
-rw-r--r--runtime/signal_catcher.cc1
-rw-r--r--runtime/signal_set.h2
-rw-r--r--runtime/stack.cc30
-rw-r--r--runtime/stack_map.h2
-rw-r--r--runtime/stride_iterator.h2
-rw-r--r--runtime/string_reference.h9
-rw-r--r--runtime/subtype_check.h64
-rw-r--r--runtime/subtype_check_info.h27
-rw-r--r--runtime/subtype_check_test.cc6
-rw-r--r--runtime/thread-inl.h7
-rw-r--r--runtime/thread.cc303
-rw-r--r--runtime/thread.h6
-rw-r--r--runtime/thread_linux.cc4
-rw-r--r--runtime/thread_list.cc11
-rw-r--r--runtime/thread_pool.cc4
-rw-r--r--runtime/ti/agent.cc209
-rw-r--r--runtime/ti/agent.h109
-rw-r--r--runtime/trace.cc4
-rw-r--r--runtime/transaction.cc3
-rw-r--r--runtime/transaction.h2
-rw-r--r--runtime/transaction_test.cc13
-rw-r--r--runtime/type_lookup_table.cc2
-rw-r--r--runtime/type_lookup_table.h2
-rw-r--r--runtime/type_lookup_table_test.cc2
-rw-r--r--runtime/type_reference.h5
-rw-r--r--runtime/utf.cc3
-rw-r--r--runtime/utils.cc2
-rw-r--r--runtime/utils.h3
-rw-r--r--runtime/utils/dex_cache_arrays_layout-inl.h3
-rw-r--r--runtime/utils/dex_cache_arrays_layout.h4
-rw-r--r--runtime/vdex_file.cc8
-rw-r--r--runtime/vdex_file.h18
-rw-r--r--runtime/verifier/method_verifier-inl.h3
-rw-r--r--runtime/verifier/method_verifier.cc160
-rw-r--r--runtime/verifier/method_verifier.h13
-rw-r--r--runtime/verifier/method_verifier_test.cc2
-rw-r--r--runtime/verifier/reg_type-inl.h14
-rw-r--r--runtime/verifier/reg_type.cc26
-rw-r--r--runtime/verifier/reg_type.h46
-rw-r--r--runtime/verifier/reg_type_cache-inl.h3
-rw-r--r--runtime/verifier/reg_type_cache.cc83
-rw-r--r--runtime/verifier/reg_type_cache.h7
-rw-r--r--runtime/verifier/reg_type_test.cc362
-rw-r--r--runtime/verifier/register_line-inl.h22
-rw-r--r--runtime/verifier/register_line.cc2
-rw-r--r--runtime/verifier/register_line.h23
-rw-r--r--runtime/verifier/verifier_deps.cc2
-rw-r--r--runtime/verifier/verifier_deps.h2
-rw-r--r--runtime/well_known_classes.cc11
-rw-r--r--runtime/well_known_classes.h1
-rw-r--r--runtime/zip_archive.h3
-rw-r--r--simulator/code_simulator_arm64.cc2
-rw-r--r--simulator/code_simulator_container.cc1
-rw-r--r--simulator/code_simulator_container.h3
-rw-r--r--test/004-JniTest/expected.txt1
-rw-r--r--test/004-JniTest/jni_test.cc12
-rw-r--r--test/004-JniTest/src/Main.java15
-rw-r--r--test/004-ThreadStress/src/Main.java9
-rw-r--r--test/008-exceptions/src/Main.java8
-rw-r--r--test/031-class-attributes/jasmin/ClassAttrs$1.j49
-rw-r--r--test/031-class-attributes/src/ClassAttrs.java11
-rw-r--r--test/044-proxy/native_proxy.cc2
-rw-r--r--test/070-nio-buffer/src/Main.java23
-rw-r--r--test/085-old-style-inner-class/build33
-rw-r--r--test/085-old-style-inner-class/jasmin/Main$1.j39
-rw-r--r--test/085-old-style-inner-class/jasmin/Main$2.j39
-rw-r--r--test/085-old-style-inner-class/src/Main.java10
-rw-r--r--test/099-vmdebug/expected.txt6
-rw-r--r--test/099-vmdebug/info.txt2
-rw-r--r--test/099-vmdebug/src/Main.java61
-rw-r--r--test/117-nopatchoat/nopatchoat.cc2
-rw-r--r--test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc2
-rw-r--r--test/137-cfi/cfi.cc4
-rwxr-xr-xtest/137-cfi/run7
-rw-r--r--test/150-loadlibrary/src/Main.java2
-rw-r--r--test/151-OpenFileLimit/src/Main.java5
-rwxr-xr-xtest/1940-ddms-ext/check21
-rw-r--r--test/1940-ddms-ext/expected.txt11
-rw-r--r--test/1940-ddms-ext/src-art/art/Test1940.java58
-rw-r--r--test/1941-dispose-stress/dispose_stress.cc11
-rw-r--r--test/1941-dispose-stress/src/art/Test1941.java15
-rw-r--r--test/1942-suspend-raw-monitor-exit/expected.txt11
-rw-r--r--test/1942-suspend-raw-monitor-exit/info.txt3
-rw-r--r--test/1942-suspend-raw-monitor-exit/native_suspend_monitor.cc80
-rwxr-xr-xtest/1942-suspend-raw-monitor-exit/run17
-rw-r--r--test/1942-suspend-raw-monitor-exit/src/Main.java21
-rw-r--r--test/1942-suspend-raw-monitor-exit/src/art/Suspension.java (renamed from runtime/cdex/compact_dex_level.h)24
-rw-r--r--test/1942-suspend-raw-monitor-exit/src/art/Test1942.java73
-rw-r--r--test/1943-suspend-raw-monitor-wait/expected.txt7
-rw-r--r--test/1943-suspend-raw-monitor-wait/info.txt4
-rw-r--r--test/1943-suspend-raw-monitor-wait/native_suspend_monitor.cc82
-rwxr-xr-xtest/1943-suspend-raw-monitor-wait/run17
-rw-r--r--test/1943-suspend-raw-monitor-wait/src/Main.java21
-rw-r--r--test/1943-suspend-raw-monitor-wait/src/art/Suspension.java30
-rw-r--r--test/1943-suspend-raw-monitor-wait/src/art/Test1943.java66
-rw-r--r--test/445-checker-licm/src/Main.java28
-rw-r--r--test/466-get-live-vreg/get_live_vreg_jni.cc3
-rw-r--r--test/518-null-array-get/expected.txt6
-rw-r--r--test/518-null-array-get/info.txt12
-rw-r--r--test/518-null-array-get/smali/NullArrayFailInt2Object.smali28
-rw-r--r--test/518-null-array-get/smali/NullArrayFailObject2Int.smali (renamed from test/518-null-array-get/smali/NullArray.smali)4
-rw-r--r--test/518-null-array-get/smali/NullArraySuccessInt.smali33
-rw-r--r--test/518-null-array-get/smali/NullArraySuccessInt2Float.smali33
-rw-r--r--test/518-null-array-get/smali/NullArraySuccessRef.smali33
-rw-r--r--test/518-null-array-get/smali/NullArraySuccessShort.smali33
-rw-r--r--test/518-null-array-get/src/Main.java36
-rw-r--r--test/530-checker-lse/src/Main.java18
-rw-r--r--test/530-checker-lse3/expected.txt0
-rw-r--r--test/530-checker-lse3/info.txt4
-rw-r--r--test/530-checker-lse3/smali/StoreLoad.smali62
-rw-r--r--test/530-checker-lse3/src/Main.java48
-rw-r--r--test/532-checker-nonnull-arrayset/src/Main.java4
-rw-r--r--test/550-checker-multiply-accumulate/src/Main.java47
-rw-r--r--test/552-checker-sharpening/src/Main.java130
-rw-r--r--test/595-profile-saving/profile-saving.cc2
-rw-r--r--test/603-checker-instanceof/src/Main.java40
-rw-r--r--test/623-checker-loop-regressions/src/Main.java105
-rw-r--r--test/626-const-class-linking/clear_dex_cache_types.cc6
-rw-r--r--test/638-checker-inline-cache-intrinsic/expected.txt (renamed from test/706-jit-skip-compilation/expected.txt)0
-rw-r--r--test/638-checker-inline-cache-intrinsic/info.txt1
-rw-r--r--test/638-checker-inline-cache-intrinsic/run (renamed from test/706-jit-skip-compilation/run)6
-rw-r--r--test/638-checker-inline-cache-intrinsic/src/Main.java95
-rw-r--r--test/640-checker-boolean-simd/src/Main.java48
-rw-r--r--test/640-checker-byte-simd/src/Main.java84
-rw-r--r--test/640-checker-char-simd/src/Main.java85
-rw-r--r--test/640-checker-double-simd/src/Main.java48
-rw-r--r--test/640-checker-float-simd/src/Main.java49
-rw-r--r--test/640-checker-int-simd/src/Main.java134
-rw-r--r--test/640-checker-long-simd/src/Main.java80
-rw-r--r--test/640-checker-short-simd/src/Main.java85
-rw-r--r--test/642-fp-callees/fp_callees.cc3
-rw-r--r--test/645-checker-abs-simd/src/Main.java96
-rw-r--r--test/646-checker-hadd-alt-byte/src/Main.java88
-rw-r--r--test/646-checker-hadd-alt-char/src/Main.java88
-rw-r--r--test/646-checker-hadd-alt-short/src/Main.java88
-rw-r--r--test/646-checker-hadd-byte/src/Main.java88
-rw-r--r--test/646-checker-hadd-short/src/Main.java144
-rw-r--r--test/651-checker-byte-simd-minmax/src/Main.java65
-rw-r--r--test/651-checker-char-simd-minmax/src/Main.java37
-rw-r--r--test/651-checker-int-simd-minmax/src/Main.java28
-rw-r--r--test/651-checker-short-simd-minmax/src/Main.java65
-rw-r--r--test/656-checker-simd-opt/src/Main.java42
-rw-r--r--test/660-checker-simd-sad-byte/src/Main.java67
-rw-r--r--test/660-checker-simd-sad-int/src/Main.java76
-rw-r--r--test/660-checker-simd-sad-long/src/Main.java42
-rw-r--r--test/660-checker-simd-sad-short/src/Main.java67
-rw-r--r--test/660-checker-simd-sad-short2/src/Main.java67
-rw-r--r--test/660-checker-simd-sad-short3/src/Main.java114
-rw-r--r--test/661-checker-simd-reduc/src/Main.java247
-rw-r--r--test/664-aget-verifier/aget-verifier.cc2
-rw-r--r--test/665-checker-simd-zero/src/Main.java64
-rw-r--r--test/667-jit-jni-stub/src/Main.java9
-rw-r--r--test/671-npe-field-opts/expected.txt0
-rw-r--r--test/671-npe-field-opts/info.txt3
-rw-r--r--test/671-npe-field-opts/src/Main.java86
-rw-r--r--test/706-checker-scheduler/src/Main.java64
-rw-r--r--test/706-jit-skip-compilation/info.txt4
-rw-r--r--test/706-jit-skip-compilation/smali/errclass.smali34
-rw-r--r--test/706-jit-skip-compilation/src/Main.java57
-rw-r--r--test/711-checker-type-conversion/src/Main.java221
-rw-r--r--test/900-hello-plugin/load_unload.cc5
-rw-r--r--test/901-hello-ti-agent/basics.cc8
-rw-r--r--test/909-attach-agent/expected.txt7
-rw-r--r--test/909-attach-agent/src-art/Main.java74
-rw-r--r--test/936-search-onload/search_onload.cc5
-rw-r--r--test/954-invoke-polymorphic-verifier/expected.txt8
-rw-r--r--test/954-invoke-polymorphic-verifier/smali/Main.smali6
-rw-r--r--test/954-invoke-polymorphic-verifier/smali/VarHandleHappyAccessors.smali72
-rw-r--r--test/954-invoke-polymorphic-verifier/smali/VarHandleUnhappyAccessors.smali70
-rw-r--r--test/954-invoke-polymorphic-verifier/smali/VarHandleUnknownAccessor.smali37
-rw-r--r--test/980-redefine-object/expected.txt4
-rw-r--r--test/983-source-transform-verify/source_transform.cc11
-rw-r--r--test/AllFields/AllFields.java2
-rw-r--r--test/AllFields/AllFieldsSub.java17
-rw-r--r--test/AllFields/AllFieldsUnrelated.java17
-rw-r--r--test/Android.bp2
-rw-r--r--test/Android.run-test.mk3
-rw-r--r--test/common/runtime_state.cc6
-rw-r--r--test/common/stack_inspect.cc6
-rwxr-xr-xtest/etc/run-test-jar7
-rw-r--r--test/knownfailures.json4
-rwxr-xr-xtest/run-test6
-rw-r--r--test/testrunner/target_config.py11
-rwxr-xr-xtest/testrunner/testrunner.py21
-rw-r--r--test/ti-agent/common_load.cc3
-rw-r--r--test/ti-agent/trace_helper.cc183
-rw-r--r--tools/ahat/Android.mk1
-rw-r--r--tools/ahat/README.txt11
-rw-r--r--tools/ahat/etc/ahat.mf2
-rw-r--r--tools/ahat/etc/ahat_api.txt23
-rw-r--r--tools/ahat/src/main/com/android/ahat/Main.java11
-rw-r--r--tools/ahat/src/main/com/android/ahat/SiteHandler.java2
-rw-r--r--tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java70
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java21
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java15
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java25
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatHeap.java12
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java204
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java56
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Diff.java20
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/DiffFields.java12
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Diffable.java15
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/DiffedFieldValue.java62
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Field.java16
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/FieldValue.java21
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/HprofFormatException.java4
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Parser.java72
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/PathElement.java40
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/RootType.java60
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Site.java124
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Size.java46
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Sort.java74
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Type.java45
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Value.java118
-rw-r--r--tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java105
-rw-r--r--tools/checker/README7
-rwxr-xr-xtools/checker/checker.py3
-rw-r--r--tools/checker/file_format/checker/parser.py37
-rw-r--r--tools/cpp-define-generator/constant_class.def2
-rwxr-xr-xtools/dt_fds_forward.py196
-rw-r--r--tools/external_oj_libjdwp_art_failures.txt (renamed from tools/libjdwp_oj_art_failures.txt)29
-rw-r--r--tools/jfuzz/README.md20
-rw-r--r--tools/jfuzz/jfuzz.cc167
-rwxr-xr-xtools/jfuzz/run_dex_fuzz_test.py40
-rwxr-xr-xtools/jfuzz/run_jfuzz_test.py136
-rw-r--r--tools/prebuilt_libjdwp_art_failures.txt (renamed from tools/libjdwp_art_failures.txt)9
-rwxr-xr-xtools/run-libjdwp-tests.sh2
-rwxr-xr-xtools/run-prebuilt-libjdwp-tests.sh2
-rw-r--r--tools/titrace/instruction_decoder.cc2
794 files changed, 15312 insertions, 8486 deletions
diff --git a/Android.bp b/Android.bp
index 295ae4c556..197860694b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -20,6 +20,7 @@ art_static_dependencies = [
]
subdirs = [
+ "adbconnection",
"benchmark",
"build",
"cmdline",
@@ -31,6 +32,8 @@ subdirs = [
"dexlist",
"dexoptanalyzer",
"disassembler",
+ "dt_fd_forward",
+ "dt_fd_forward/export",
"imgdiag",
"oatdump",
"openjdkjvm",
diff --git a/Android.mk b/Android.mk
index 174cde36ef..0a90a0bb24 100644
--- a/Android.mk
+++ b/Android.mk
@@ -135,11 +135,11 @@ test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS)
else
test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS)
$(TEST_ART_ADB_ROOT_AND_REMOUNT)
- adb wait-for-device push $(ANDROID_PRODUCT_OUT)/system $(ART_TEST_ANDROID_ROOT)
+ adb wait-for-device push $(PRODUCT_OUT)/system $(ART_TEST_ANDROID_ROOT)
# Push the contents of the `data` dir into `/data` on the device. If
# `/data` already exists on the device, it is not overwritten, but its
# contents are updated.
- adb push $(ANDROID_PRODUCT_OUT)/data /
+ adb push $(PRODUCT_OUT)/data /
endif
endif
@@ -370,6 +370,7 @@ LOCAL_REQUIRED_MODULES := \
libopenjdkjvmti \
patchoat \
profman \
+ libadbconnection \
# For nosy apps, we provide a fake library that avoids namespace issues and gives some warnings.
LOCAL_REQUIRED_MODULES += libart_fake
@@ -395,6 +396,7 @@ LOCAL_REQUIRED_MODULES += \
libopenjdkjvmtid \
patchoatd \
profmand \
+ libadbconnectiond \
endif
endif
diff --git a/adbconnection/Android.bp b/adbconnection/Android.bp
new file mode 100644
index 0000000000..441b706556
--- /dev/null
+++ b/adbconnection/Android.bp
@@ -0,0 +1,80 @@
+//
+// 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.
+//
+
+// Build variants {target,host} x {debug,ndebug} x {32,64}
+
+cc_defaults {
+ name: "adbconnection-defaults",
+ host_supported: true,
+ srcs: ["adbconnection.cc"],
+ defaults: ["art_defaults"],
+
+ // Note that this tool needs to be built for both 32-bit and 64-bit since it requires
+ // to be same ISA as what it is attached to.
+ compile_multilib: "both",
+
+ shared_libs: [
+ "libbase",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "libcutils",
+ ],
+ },
+ host: {
+ },
+ darwin: {
+ enabled: false,
+ },
+ },
+ header_libs: [
+ "libnativehelper_header_only",
+ "dt_fd_forward_export",
+ ],
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+ symlink_preferred_arch: true,
+ required: [
+ "libjdwp",
+ "libdt_fd_forward",
+ ],
+}
+
+art_cc_library {
+ name: "libadbconnection",
+ defaults: ["adbconnection-defaults"],
+ shared_libs: [
+ "libart",
+ ],
+}
+
+art_cc_library {
+ name: "libadbconnectiond",
+ defaults: [
+ "art_debug_defaults",
+ "adbconnection-defaults",
+ ],
+ shared_libs: [
+ "libartd",
+ ],
+}
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
new file mode 100644
index 0000000000..a5c885a933
--- /dev/null
+++ b/adbconnection/adbconnection.cc
@@ -0,0 +1,641 @@
+/*
+ * 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 <array>
+
+#include "adbconnection.h"
+
+#include "android-base/endian.h"
+#include "android-base/stringprintf.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "java_vm_ext.h"
+#include "jni_env_ext.h"
+#include "mirror/throwable.h"
+#include "nativehelper/ScopedLocalRef.h"
+#include "runtime-inl.h"
+#include "runtime_callbacks.h"
+#include "scoped_thread_state_change-inl.h"
+#include "well_known_classes.h"
+
+#include "jdwp/jdwp_priv.h"
+
+#include "fd_transport.h"
+
+#include "poll.h"
+
+#ifdef ART_TARGET_ANDROID
+#include "cutils/sockets.h"
+#endif
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/eventfd.h>
+#include <jni.h>
+
+namespace adbconnection {
+
+using dt_fd_forward::kListenStartMessage;
+using dt_fd_forward::kListenEndMessage;
+using dt_fd_forward::kAcceptMessage;
+using dt_fd_forward::kCloseMessage;
+
+using android::base::StringPrintf;
+
+static constexpr int kEventfdLocked = 0;
+static constexpr int kEventfdUnlocked = 1;
+static constexpr int kControlSockSendTimeout = 10;
+
+static AdbConnectionState* gState;
+
+static bool IsDebuggingPossible() {
+ // TODO We need to do this on IsJdwpAllowed not IsDebuggable in order to support userdebug
+ // workloads. For now we will only allow it when we are debuggable so that testing is easier.
+ return art::Runtime::Current()->IsJavaDebuggable() && art::Dbg::IsJdwpAllowed();
+}
+
+// Begin running the debugger.
+void AdbConnectionDebuggerController::StartDebugger() {
+ if (IsDebuggingPossible()) {
+ connection_->StartDebuggerThreads();
+ } else {
+ LOG(ERROR) << "Not starting debugger since process cannot load the jdwp agent.";
+ }
+}
+
+// The debugger should begin shutting down since the runtime is ending. We don't actually do
+// anything here. The real shutdown has already happened as far as the agent is concerned.
+void AdbConnectionDebuggerController::StopDebugger() { }
+
+bool AdbConnectionDebuggerController::IsDebuggerConfigured() {
+ return IsDebuggingPossible() && !art::Runtime::Current()->GetJdwpOptions().empty();
+}
+
+void AdbConnectionDdmCallback::DdmPublishChunk(uint32_t type,
+ const art::ArrayRef<const uint8_t>& data) {
+ connection_->PublishDdmData(type, data);
+}
+
+class ScopedEventFdLock {
+ public:
+ explicit ScopedEventFdLock(int fd) : fd_(fd), data_(0) {
+ TEMP_FAILURE_RETRY(read(fd_, &data_, sizeof(data_)));
+ }
+
+ ~ScopedEventFdLock() {
+ TEMP_FAILURE_RETRY(write(fd_, &data_, sizeof(data_)));
+ }
+
+ private:
+ int fd_;
+ uint64_t data_;
+};
+
+AdbConnectionState::AdbConnectionState(const std::string& agent_name)
+ : agent_name_(agent_name),
+ controller_(this),
+ ddm_callback_(this),
+ sleep_event_fd_(-1),
+ control_sock_(-1),
+ local_agent_control_sock_(-1),
+ remote_agent_control_sock_(-1),
+ adb_connection_socket_(-1),
+ adb_write_event_fd_(-1),
+ shutting_down_(false),
+ agent_loaded_(false),
+ agent_listening_(false),
+ next_ddm_id_(1) {
+ // Setup the addr.
+ control_addr_.controlAddrUn.sun_family = AF_UNIX;
+ control_addr_len_ = sizeof(control_addr_.controlAddrUn.sun_family) + sizeof(kJdwpControlName) - 1;
+ memcpy(control_addr_.controlAddrUn.sun_path, kJdwpControlName, sizeof(kJdwpControlName) - 1);
+
+ // Add the startup callback.
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ art::Runtime::Current()->GetRuntimeCallbacks()->AddDebuggerControlCallback(&controller_);
+}
+
+static jobject CreateAdbConnectionThread(art::Thread* thr) {
+ JNIEnv* env = thr->GetJniEnv();
+ // Move to native state to talk with the jnienv api.
+ art::ScopedThreadStateChange stsc(thr, art::kNative);
+ ScopedLocalRef<jstring> thr_name(env, env->NewStringUTF(kAdbConnectionThreadName));
+ ScopedLocalRef<jobject> thr_group(
+ env,
+ env->GetStaticObjectField(art::WellKnownClasses::java_lang_ThreadGroup,
+ art::WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup));
+ return env->NewObject(art::WellKnownClasses::java_lang_Thread,
+ art::WellKnownClasses::java_lang_Thread_init,
+ thr_group.get(),
+ thr_name.get(),
+ /*Priority*/ 0,
+ /*Daemon*/ true);
+}
+
+struct CallbackData {
+ AdbConnectionState* this_;
+ jobject thr_;
+};
+
+static void* CallbackFunction(void* vdata) {
+ std::unique_ptr<CallbackData> data(reinterpret_cast<CallbackData*>(vdata));
+ art::Thread* self = art::Thread::Attach(kAdbConnectionThreadName,
+ true,
+ data->thr_);
+ CHECK(self != nullptr) << "threads_being_born_ should have ensured thread could be attached.";
+ // The name in Attach() is only for logging. Set the thread name. This is important so
+ // that the thread is no longer seen as starting up.
+ {
+ art::ScopedObjectAccess soa(self);
+ self->SetThreadName(kAdbConnectionThreadName);
+ }
+
+ // Release the peer.
+ JNIEnv* env = self->GetJniEnv();
+ env->DeleteGlobalRef(data->thr_);
+ data->thr_ = nullptr;
+ {
+ // The StartThreadBirth was called in the parent thread. We let the runtime know we are up
+ // before going into the provided code.
+ art::MutexLock mu(self, *art::Locks::runtime_shutdown_lock_);
+ art::Runtime::Current()->EndThreadBirth();
+ }
+ data->this_->RunPollLoop(self);
+ int detach_result = art::Runtime::Current()->GetJavaVM()->DetachCurrentThread();
+ CHECK_EQ(detach_result, 0);
+
+ return nullptr;
+}
+
+void AdbConnectionState::StartDebuggerThreads() {
+ // First do all the final setup we need.
+ CHECK_EQ(adb_write_event_fd_.get(), -1);
+ CHECK_EQ(sleep_event_fd_.get(), -1);
+ CHECK_EQ(local_agent_control_sock_.get(), -1);
+ CHECK_EQ(remote_agent_control_sock_.get(), -1);
+
+ sleep_event_fd_.reset(eventfd(kEventfdLocked, EFD_CLOEXEC));
+ CHECK_NE(sleep_event_fd_.get(), -1) << "Unable to create wakeup eventfd.";
+ adb_write_event_fd_.reset(eventfd(kEventfdUnlocked, EFD_CLOEXEC));
+ CHECK_NE(adb_write_event_fd_.get(), -1) << "Unable to create write-lock eventfd.";
+
+ {
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ art::Runtime::Current()->GetRuntimeCallbacks()->AddDdmCallback(&ddm_callback_);
+ }
+ // Setup the socketpair we use to talk to the agent.
+ bool has_sockets;
+ do {
+ has_sockets = android::base::Socketpair(AF_UNIX,
+ SOCK_SEQPACKET | SOCK_CLOEXEC,
+ 0,
+ &local_agent_control_sock_,
+ &remote_agent_control_sock_);
+ } while (!has_sockets && errno == EINTR);
+ if (!has_sockets) {
+ PLOG(FATAL) << "Unable to create socketpair for agent control!";
+ }
+
+ // Next start the threads.
+ art::Thread* self = art::Thread::Current();
+ art::ScopedObjectAccess soa(self);
+ {
+ art::Runtime* runtime = art::Runtime::Current();
+ art::MutexLock mu(self, *art::Locks::runtime_shutdown_lock_);
+ if (runtime->IsShuttingDownLocked()) {
+ // The runtime is shutting down so we cannot create new threads. This shouldn't really happen.
+ LOG(ERROR) << "The runtime is shutting down when we are trying to start up the debugger!";
+ return;
+ }
+ runtime->StartThreadBirth();
+ }
+ ScopedLocalRef<jobject> thr(soa.Env(), CreateAdbConnectionThread(soa.Self()));
+ pthread_t pthread;
+ std::unique_ptr<CallbackData> data(new CallbackData { this, soa.Env()->NewGlobalRef(thr.get()) });
+ int pthread_create_result = pthread_create(&pthread,
+ nullptr,
+ &CallbackFunction,
+ data.get());
+ if (pthread_create_result != 0) {
+ // If the create succeeded the other thread will call EndThreadBirth.
+ art::Runtime* runtime = art::Runtime::Current();
+ soa.Env()->DeleteGlobalRef(data->thr_);
+ LOG(ERROR) << "Failed to create thread for adb-jdwp connection manager!";
+ art::MutexLock mu(art::Thread::Current(), *art::Locks::runtime_shutdown_lock_);
+ runtime->EndThreadBirth();
+ return;
+ }
+ data.release();
+}
+
+static bool FlagsSet(int16_t data, int16_t flags) {
+ return (data & flags) == flags;
+}
+
+void AdbConnectionState::CloseFds() {
+ // Lock the write_event_fd so that concurrent PublishDdms will see that the connection is closed.
+ ScopedEventFdLock lk(adb_write_event_fd_);
+ // shutdown(adb_connection_socket_, SHUT_RDWR);
+ adb_connection_socket_.reset();
+}
+
+uint32_t AdbConnectionState::NextDdmId() {
+ // Just have a normal counter but always set the sign bit.
+ return (next_ddm_id_++) | 0x80000000;
+}
+
+void AdbConnectionState::PublishDdmData(uint32_t type, const art::ArrayRef<const uint8_t>& data) {
+ // Get the write_event early to fail fast.
+ ScopedEventFdLock lk(adb_write_event_fd_);
+ if (adb_connection_socket_ == -1) {
+ LOG(WARNING) << "Not sending ddms data of type "
+ << StringPrintf("%c%c%c%c",
+ static_cast<char>(type >> 24),
+ static_cast<char>(type >> 16),
+ static_cast<char>(type >> 8),
+ static_cast<char>(type)) << " due to no connection!";
+ // Adb is not connected.
+ return;
+ }
+
+ // the adb_write_event_fd_ will ensure that the adb_connection_socket_ will not go away until
+ // after we have sent our data.
+ static constexpr uint32_t kDdmPacketHeaderSize =
+ kJDWPHeaderLen // jdwp command packet size
+ + sizeof(uint32_t) // Type
+ + sizeof(uint32_t); // length
+ std::array<uint8_t, kDdmPacketHeaderSize> pkt;
+ uint8_t* pkt_data = pkt.data();
+
+ // Write the length first.
+ *reinterpret_cast<uint32_t*>(pkt_data) = htonl(kDdmPacketHeaderSize + data.size());
+ pkt_data += sizeof(uint32_t);
+
+ // Write the id next;
+ *reinterpret_cast<uint32_t*>(pkt_data) = htonl(NextDdmId());
+ pkt_data += sizeof(uint32_t);
+
+ // next the flags. (0 for cmd packet because DDMS).
+ *(pkt_data++) = 0;
+ // Now the cmd-set
+ *(pkt_data++) = kJDWPDdmCmdSet;
+ // Now the command
+ *(pkt_data++) = kJDWPDdmCmd;
+
+ // now the type.
+ *reinterpret_cast<uint32_t*>(pkt_data) = htonl(type);
+ pkt_data += sizeof(uint32_t);
+
+ // Now the data.size()
+ *reinterpret_cast<uint32_t*>(pkt_data) = htonl(data.size());
+ pkt_data += sizeof(uint32_t);
+
+ static uint32_t constexpr kIovSize = 2;
+ struct iovec iovs[kIovSize] = {
+ { pkt.data(), pkt.size() },
+ { const_cast<uint8_t*>(data.data()), data.size() },
+ };
+ // now pkt_header has the header.
+ // use writev to send the actual data.
+ ssize_t res = TEMP_FAILURE_RETRY(writev(adb_connection_socket_, iovs, kIovSize));
+ if (static_cast<size_t>(res) != (kDdmPacketHeaderSize + data.size())) {
+ PLOG(ERROR) << StringPrintf("Failed to send DDMS packet %c%c%c%c to debugger (%zd of %zu)",
+ static_cast<char>(type >> 24),
+ static_cast<char>(type >> 16),
+ static_cast<char>(type >> 8),
+ static_cast<char>(type),
+ res, data.size() + kDdmPacketHeaderSize);
+ } else {
+ VLOG(jdwp) << StringPrintf("sent DDMS packet %c%c%c%c to debugger %zu",
+ static_cast<char>(type >> 24),
+ static_cast<char>(type >> 16),
+ static_cast<char>(type >> 8),
+ static_cast<char>(type),
+ data.size() + kDdmPacketHeaderSize);
+ }
+}
+
+void AdbConnectionState::SendAgentFds() {
+ // TODO
+ DCHECK(!sent_agent_fds_);
+ char dummy = '!';
+ union {
+ cmsghdr cm;
+ char buffer[CMSG_SPACE(dt_fd_forward::FdSet::kDataLength)];
+ } cm_un;
+ iovec iov;
+ iov.iov_base = &dummy;
+ iov.iov_len = 1;
+
+ msghdr msg;
+ msg.msg_name = nullptr;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+ msg.msg_control = cm_un.buffer;
+ msg.msg_controllen = sizeof(cm_un.buffer);
+
+ cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(dt_fd_forward::FdSet::kDataLength);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+
+ // Duplicate the fds before sending them.
+ android::base::unique_fd read_fd(dup(adb_connection_socket_));
+ CHECK_NE(read_fd.get(), -1) << "Failed to dup read_fd_: " << strerror(errno);
+ android::base::unique_fd write_fd(dup(adb_connection_socket_));
+ CHECK_NE(write_fd.get(), -1) << "Failed to dup write_fd: " << strerror(errno);
+ android::base::unique_fd write_lock_fd(dup(adb_write_event_fd_));
+ CHECK_NE(write_lock_fd.get(), -1) << "Failed to dup write_lock_fd: " << strerror(errno);
+
+ dt_fd_forward::FdSet {
+ read_fd.get(), write_fd.get(), write_lock_fd.get()
+ }.WriteData(CMSG_DATA(cmsg));
+
+ int res = TEMP_FAILURE_RETRY(sendmsg(local_agent_control_sock_, &msg, MSG_EOR));
+ if (res < 0) {
+ PLOG(ERROR) << "Failed to send agent adb connection fds.";
+ } else {
+ sent_agent_fds_ = true;
+ VLOG(jdwp) << "Fds have been sent to jdwp agent!";
+ }
+}
+
+android::base::unique_fd AdbConnectionState::ReadFdFromAdb() {
+ // We don't actually care about the data that is sent. We do need to receive something though.
+ char dummy = '!';
+ union {
+ cmsghdr cm;
+ char buffer[CMSG_SPACE(sizeof(int))];
+ } cm_un;
+
+ iovec iov;
+ iov.iov_base = &dummy;
+ iov.iov_len = 1;
+
+ msghdr msg;
+ msg.msg_name = nullptr;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+ msg.msg_control = cm_un.buffer;
+ msg.msg_controllen = sizeof(cm_un.buffer);
+
+ cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = msg.msg_controllen;
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ (reinterpret_cast<int*>(CMSG_DATA(cmsg)))[0] = -1;
+
+ int rc = TEMP_FAILURE_RETRY(recvmsg(control_sock_, &msg, 0));
+
+ if (rc <= 0) {
+ PLOG(WARNING) << "Receiving file descriptor from ADB failed (socket " << control_sock_ << ")";
+ return android::base::unique_fd(-1);
+ } else {
+ VLOG(jdwp) << "Fds have been received from ADB!";
+ }
+
+ return android::base::unique_fd((reinterpret_cast<int*>(CMSG_DATA(cmsg)))[0]);
+}
+
+bool AdbConnectionState::SetupAdbConnection() {
+ int sleep_ms = 500;
+ const int sleep_max_ms = 2*1000;
+ char buff[sizeof(pid_t) + 1];
+
+ android::base::unique_fd sock(socket(AF_UNIX, SOCK_SEQPACKET, 0));
+ if (sock < 0) {
+ PLOG(ERROR) << "Could not create ADB control socket";
+ return false;
+ }
+ struct timeval timeout;
+ timeout.tv_sec = kControlSockSendTimeout;
+ timeout.tv_usec = 0;
+ setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+ snprintf(buff, sizeof(buff), "%04x", getpid());
+ buff[sizeof(pid_t)] = 0;
+
+ while (!shutting_down_) {
+ // If adbd isn't running, because USB debugging was disabled or
+ // perhaps the system is restarting it for "adb root", the
+ // connect() will fail. We loop here forever waiting for it
+ // to come back.
+ //
+ // Waking up and polling every couple of seconds is generally a
+ // bad thing to do, but we only do this if the application is
+ // debuggable *and* adbd isn't running. Still, for the sake
+ // of battery life, we should consider timing out and giving
+ // up after a few minutes in case somebody ships an app with
+ // the debuggable flag set.
+ int ret = connect(sock, &control_addr_.controlAddrPlain, control_addr_len_);
+ if (ret == 0) {
+ bool trusted = sock >= 0;
+#ifdef ART_TARGET_ANDROID
+ // Needed for socket_peer_is_trusted.
+ trusted = trusted && socket_peer_is_trusted(sock);
+#endif
+ if (!trusted) {
+ LOG(ERROR) << "adb socket is not trusted. Aborting connection.";
+ if (sock >= 0 && shutdown(sock, SHUT_RDWR)) {
+ PLOG(ERROR) << "trouble shutting down socket";
+ }
+ return false;
+ }
+ /* now try to send our pid to the ADB daemon */
+ ret = TEMP_FAILURE_RETRY(send(sock, buff, sizeof(pid_t), 0));
+ if (ret == sizeof(pid_t)) {
+ LOG(INFO) << "PID " << getpid() << " send to adb";
+ control_sock_ = std::move(sock);
+ return true;
+ } else {
+ PLOG(ERROR) << "Weird, can't send JDWP process pid to ADB. Aborting connection.";
+ return false;
+ }
+ } else {
+ PLOG(ERROR) << "Can't connect to ADB control socket. Will retry.";
+
+ usleep(sleep_ms * 1000);
+
+ sleep_ms += (sleep_ms >> 1);
+ if (sleep_ms > sleep_max_ms) {
+ sleep_ms = sleep_max_ms;
+ }
+ }
+ }
+ return false;
+}
+
+void AdbConnectionState::RunPollLoop(art::Thread* self) {
+ CHECK_EQ(self->GetState(), art::kNative);
+ art::Locks::mutator_lock_->AssertNotHeld(self);
+ self->SetState(art::kWaitingInMainDebuggerLoop);
+ // shutting_down_ set by StopDebuggerThreads
+ while (!shutting_down_) {
+ // First get the control_sock_ from adb if we don't have one. We only need to do this once.
+ if (control_sock_ == -1 && !SetupAdbConnection()) {
+ LOG(ERROR) << "Failed to setup adb connection.";
+ return;
+ }
+ while (!shutting_down_ && control_sock_ != -1) {
+ struct pollfd pollfds[4] = {
+ { sleep_event_fd_, POLLIN, 0 },
+ // -1 as an fd causes it to be ignored by poll
+ { (agent_loaded_ ? local_agent_control_sock_ : -1), POLLIN, 0 },
+ // Check for the control_sock_ actually going away. Only do this if we don't have an active
+ // connection.
+ { (adb_connection_socket_ == -1 ? control_sock_ : -1), POLLIN | POLLRDHUP, 0 },
+ // if we have not loaded the agent either the adb_connection_socket_ is -1 meaning we don't
+ // have a real connection yet or the socket through adb needs to be listened to for incoming
+ // data that the agent can handle.
+ { ((!agent_has_socket_ && !sent_agent_fds_) ? adb_connection_socket_ : -1), POLLIN, 0 }
+ };
+ int res = TEMP_FAILURE_RETRY(poll(pollfds, 4, -1));
+ if (res < 0) {
+ PLOG(ERROR) << "Failed to poll!";
+ return;
+ }
+ // We don't actually care about doing this we just use it to wake us up.
+ // const struct pollfd& sleep_event_poll = pollfds[0];
+ const struct pollfd& agent_control_sock_poll = pollfds[1];
+ const struct pollfd& control_sock_poll = pollfds[2];
+ const struct pollfd& adb_socket_poll = pollfds[3];
+ if (FlagsSet(agent_control_sock_poll.revents, POLLIN)) {
+ DCHECK(agent_loaded_);
+ char buf[257];
+ res = TEMP_FAILURE_RETRY(recv(local_agent_control_sock_, buf, sizeof(buf) - 1, 0));
+ if (res < 0) {
+ PLOG(ERROR) << "Failed to read message from agent control socket! Retrying";
+ continue;
+ } else {
+ buf[res + 1] = '\0';
+ VLOG(jdwp) << "Local agent control sock has data: " << static_cast<const char*>(buf);
+ }
+ if (memcmp(kListenStartMessage, buf, sizeof(kListenStartMessage)) == 0) {
+ agent_listening_ = true;
+ if (adb_connection_socket_ != -1) {
+ SendAgentFds();
+ }
+ } else if (memcmp(kListenEndMessage, buf, sizeof(kListenEndMessage)) == 0) {
+ agent_listening_ = false;
+ } else if (memcmp(kCloseMessage, buf, sizeof(kCloseMessage)) == 0) {
+ CloseFds();
+ agent_has_socket_ = false;
+ } else if (memcmp(kAcceptMessage, buf, sizeof(kAcceptMessage)) == 0) {
+ agent_has_socket_ = true;
+ sent_agent_fds_ = false;
+ } else {
+ LOG(ERROR) << "Unknown message received from debugger! '" << std::string(buf) << "'";
+ }
+ } else if (FlagsSet(control_sock_poll.revents, POLLIN)) {
+ bool maybe_send_fds = false;
+ {
+ // Hold onto this lock so that concurrent ddm publishes don't try to use an illegal fd.
+ ScopedEventFdLock sefdl(adb_write_event_fd_);
+ android::base::unique_fd new_fd(ReadFdFromAdb());
+ if (new_fd == -1) {
+ // Something went wrong. We need to retry getting the control socket.
+ PLOG(ERROR) << "Something went wrong getting fds from adb. Retry!";
+ control_sock_.reset();
+ break;
+ } else if (adb_connection_socket_ != -1) {
+ // We already have a connection.
+ VLOG(jdwp) << "Ignoring second debugger. Accept then drop!";
+ if (new_fd >= 0) {
+ new_fd.reset();
+ }
+ } else {
+ VLOG(jdwp) << "Adb connection established with fd " << new_fd;
+ adb_connection_socket_ = std::move(new_fd);
+ maybe_send_fds = true;
+ }
+ }
+ if (maybe_send_fds && agent_loaded_ && agent_listening_) {
+ VLOG(jdwp) << "Sending fds as soon as we received them.";
+ SendAgentFds();
+ }
+ } else if (FlagsSet(control_sock_poll.revents, POLLRDHUP)) {
+ // The other end of the adb connection just dropped it.
+ // Reset the connection since we don't have an active socket through the adb server.
+ DCHECK(!agent_has_socket_) << "We shouldn't be doing anything if there is already a "
+ << "connection active";
+ control_sock_.reset();
+ break;
+ } else if (FlagsSet(adb_socket_poll.revents, POLLIN)) {
+ DCHECK(!agent_has_socket_);
+ if (!agent_loaded_) {
+ DCHECK(!agent_listening_);
+ // Load the agent now!
+ self->AssertNoPendingException();
+ art::Runtime::Current()->AttachAgent(/* JNIEnv* */ nullptr,
+ MakeAgentArg(),
+ /* classloader */ nullptr);
+ if (self->IsExceptionPending()) {
+ LOG(ERROR) << "Failed to load agent " << agent_name_;
+ art::ScopedObjectAccess soa(self);
+ self->GetException()->Dump();
+ self->ClearException();
+ return;
+ }
+ agent_loaded_ = true;
+ } else if (agent_listening_ && !sent_agent_fds_) {
+ VLOG(jdwp) << "Sending agent fds again on data.";
+ SendAgentFds();
+ }
+ } else {
+ VLOG(jdwp) << "Woke up poll without anything to do!";
+ }
+ }
+ }
+}
+
+std::string AdbConnectionState::MakeAgentArg() {
+ // TODO Get this from something user settable?
+ const std::string& opts = art::Runtime::Current()->GetJdwpOptions();
+ return agent_name_ + "=" + opts + (opts.empty() ? "" : ",")
+ + "transport=dt_fd_forward,address=" + std::to_string(remote_agent_control_sock_);
+}
+
+void AdbConnectionState::StopDebuggerThreads() {
+ // The regular agent system will take care of unloading the agent (if needed).
+ shutting_down_ = true;
+ // Wakeup the poll loop.
+ uint64_t data = 1;
+ TEMP_FAILURE_RETRY(write(sleep_event_fd_, &data, sizeof(data)));
+}
+
+// The plugin initialization function.
+extern "C" bool ArtPlugin_Initialize() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ DCHECK(art::Runtime::Current()->GetJdwpProvider() == art::JdwpProvider::kAdbConnection);
+ // TODO Provide some way for apps to set this maybe?
+ gState = new AdbConnectionState(kDefaultJdwpAgentName);
+ CHECK(gState != nullptr);
+ return true;
+}
+
+extern "C" bool ArtPlugin_Deinitialize() {
+ CHECK(gState != nullptr);
+ // Just do this a second time?
+ // TODO I don't think this should be needed.
+ gState->StopDebuggerThreads();
+ delete gState;
+ return true;
+}
+
+} // namespace adbconnection
diff --git a/adbconnection/adbconnection.h b/adbconnection/adbconnection.h
new file mode 100644
index 0000000000..28a5a05af3
--- /dev/null
+++ b/adbconnection/adbconnection.h
@@ -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.
+ */
+
+#ifndef ART_ADBCONNECTION_ADBCONNECTION_H_
+#define ART_ADBCONNECTION_ADBCONNECTION_H_
+
+#include <stdint.h>
+#include <vector>
+#include <limits>
+
+#include "android-base/unique_fd.h"
+
+#include "base/mutex.h"
+#include "runtime_callbacks.h"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <jni.h>
+
+namespace adbconnection {
+
+static constexpr char kJdwpControlName[] = "\0jdwp-control";
+static constexpr char kAdbConnectionThreadName[] = "ADB-JDWP Connection Control Thread";
+
+// The default jdwp agent name.
+static constexpr char kDefaultJdwpAgentName[] = "libjdwp.so";
+
+class AdbConnectionState;
+
+struct AdbConnectionDebuggerController : public art::DebuggerControlCallback {
+ explicit AdbConnectionDebuggerController(AdbConnectionState* connection)
+ : connection_(connection) {}
+
+ // Begin running the debugger.
+ void StartDebugger() OVERRIDE;
+
+ // The debugger should begin shutting down since the runtime is ending.
+ void StopDebugger() OVERRIDE;
+
+ bool IsDebuggerConfigured() OVERRIDE;
+
+ private:
+ AdbConnectionState* connection_;
+};
+
+struct AdbConnectionDdmCallback : public art::DdmCallback {
+ explicit AdbConnectionDdmCallback(AdbConnectionState* connection) : connection_(connection) {}
+
+ void DdmPublishChunk(uint32_t type,
+ const art::ArrayRef<const uint8_t>& data)
+ REQUIRES_SHARED(art::Locks::mutator_lock_);
+
+ private:
+ AdbConnectionState* connection_;
+};
+
+class AdbConnectionState {
+ public:
+ explicit AdbConnectionState(const std::string& agent_name);
+
+ // Called on the listening thread to start dealing with new input. thr is used to attach the new
+ // thread to the runtime.
+ void RunPollLoop(art::Thread* self);
+
+ // Sends ddms data over the socket, if there is one. This data is sent even if we haven't finished
+ // hand-shaking yet.
+ void PublishDdmData(uint32_t type, const art::ArrayRef<const uint8_t>& data);
+
+ // Stops debugger threads during shutdown.
+ void StopDebuggerThreads();
+
+ private:
+ uint32_t NextDdmId();
+
+ void StartDebuggerThreads();
+
+ // Tell adbd about the new runtime.
+ bool SetupAdbConnection();
+
+ std::string MakeAgentArg();
+
+ android::base::unique_fd ReadFdFromAdb();
+
+ void SendAgentFds();
+
+ void CloseFds();
+
+ std::string agent_name_;
+
+ AdbConnectionDebuggerController controller_;
+ AdbConnectionDdmCallback ddm_callback_;
+
+ // Eventfd used to allow the StopDebuggerThreads function to wake up sleeping threads
+ android::base::unique_fd sleep_event_fd_;
+
+ // Socket that we use to talk to adbd.
+ android::base::unique_fd control_sock_;
+
+ // Socket that we use to talk to the agent (if it's loaded).
+ android::base::unique_fd local_agent_control_sock_;
+
+ // The fd of the socket the agent uses to talk to us. We need to keep it around in order to clean
+ // it up when the runtime goes away.
+ android::base::unique_fd remote_agent_control_sock_;
+
+ // The fd that is forwarded through adb to the client. This is guarded by the
+ // adb_write_event_fd_.
+ android::base::unique_fd adb_connection_socket_;
+
+ // The fd we send to the agent to let us synchronize access to the shared adb_connection_socket_.
+ // This is also used as a general lock for the adb_connection_socket_ on any threads other than
+ // the poll thread.
+ android::base::unique_fd adb_write_event_fd_;
+
+ std::atomic<bool> shutting_down_;
+
+ // True if we have loaded the agent library.
+ std::atomic<bool> agent_loaded_;
+
+ // True if the dt_fd_forward transport is listening for a new communication channel.
+ std::atomic<bool> agent_listening_;
+
+ // True if the dt_fd_forward transport has the socket. If so we don't do anything to the agent or
+ // the adb connection socket until connection goes away.
+ std::atomic<bool> agent_has_socket_;
+
+ std::atomic<bool> sent_agent_fds_;
+
+ std::atomic<uint32_t> next_ddm_id_;
+
+ socklen_t control_addr_len_;
+ union {
+ sockaddr_un controlAddrUn;
+ sockaddr controlAddrPlain;
+ } control_addr_;
+
+ friend struct AdbConnectionDebuggerController;
+};
+
+} // namespace adbconnection
+
+#endif // ART_ADBCONNECTION_ADBCONNECTION_H_
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index f5a95fa0cf..08962526dd 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -49,6 +49,11 @@ endif
# Enable the read barrier by default.
ART_USE_READ_BARRIER ?= true
+# Default compact dex level to none.
+ifeq ($(ART_DEFAULT_COMPACT_DEX_LEVEL),)
+ART_DEFAULT_COMPACT_DEX_LEVEL := none
+endif
+
ART_CPP_EXTENSION := .cc
ifndef LIBART_IMG_HOST_BASE_ADDRESS
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 0f29f2901b..3d1f4343f1 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -23,10 +23,10 @@ include art/build/Android.common_path.mk
ifneq ($(TMPDIR),)
ART_HOST_TEST_DIR := $(TMPDIR)/test-art-$(shell echo $$PPID)
else
-# Use a BSD checksum calculated from ANDROID_BUILD_TOP and USER as one of the
-# path components for the test output. This should allow us to run tests from multiple
-# repositories at the same time.
-ART_HOST_TEST_DIR := /tmp/test-art-$(shell echo ${ANDROID_BUILD_TOP}-${USER} | sum | cut -d ' ' -f1)
+# Use a BSD checksum calculated from PPID and USER as one of the path
+# components for the test output. This should allow us to run tests from
+# multiple repositories at the same time.
+ART_HOST_TEST_DIR := /tmp/test-art-$(shell echo $$PPID-${USER} | sum | cut -d ' ' -f1)
endif
# List of known broken tests that we won't attempt to execute. The test name must be the full
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 3c8eade773..1f36cb4e46 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -124,6 +124,7 @@ ART_GTEST_image_space_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX
ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex
ART_GTEST_oat_test_DEX_DEPS := Main
ART_GTEST_object_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY
+ART_GTEST_patchoat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
ART_GTEST_proxy_test_DEX_DEPS := Interfaces
ART_GTEST_reflection_test_DEX_DEPS := Main NonStaticLeafMethods StaticLeafMethods
ART_GTEST_profile_assistant_test_DEX_DEPS := ProfileTestMultiDex
@@ -251,6 +252,11 @@ ART_GTEST_oatdump_test_TARGET_DEPS := \
ART_GTEST_oatdump_image_test_HOST_DEPS := $(ART_GTEST_oatdump_test_HOST_DEPS)
ART_GTEST_oatdump_image_test_TARGET_DEPS := $(ART_GTEST_oatdump_test_TARGET_DEPS)
+ART_GTEST_patchoat_test_HOST_DEPS := \
+ $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+ART_GTEST_patchoat_test_TARGET_DEPS := \
+ $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
+
# Profile assistant tests requires profman utility.
ART_GTEST_profile_assistant_test_HOST_DEPS := profmand-host
ART_GTEST_profile_assistant_test_TARGET_DEPS := profmand-target
@@ -270,6 +276,7 @@ ART_TEST_MODULES := \
art_dexoptanalyzer_tests \
art_imgdiag_tests \
art_oatdump_tests \
+ art_patchoat_tests \
art_profman_tests \
art_runtime_tests \
art_runtime_compiler_tests \
@@ -608,7 +615,7 @@ define define-test-art-gtest-combination
endif
.PHONY: $$(rule_name)
-$$(rule_name): $$(dependencies) dx d8-compat-dx
+$$(rule_name): $$(dependencies) dx d8-compat-dx desugar
$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
# Clear locally defined variables.
@@ -683,6 +690,9 @@ ART_GTEST_dex2oat_image_test_DEX_DEPS :=
ART_GTEST_dex2oat_image_test_HOST_DEPS :=
ART_GTEST_dex2oat_image_test_TARGET_DEPS :=
ART_GTEST_object_test_DEX_DEPS :=
+ART_GTEST_patchoat_test_DEX_DEPS :=
+ART_GTEST_patchoat_test_HOST_DEPS :=
+ART_GTEST_patchoat_test_TARGET_DEPS :=
ART_GTEST_proxy_test_DEX_DEPS :=
ART_GTEST_reflection_test_DEX_DEPS :=
ART_GTEST_stub_test_DEX_DEPS :=
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 3f9ea15fb3..517ac5c28d 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -111,6 +111,7 @@ $$(core_image_name): $$(HOST_CORE_DEX_LOCATIONS) $$(core_dex2oat_dependency)
$$(LOCAL_$(2)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES_OPTION) \
--host --android-root=$$(HOST_OUT) \
--generate-debug-info --generate-build-id --compile-pic \
+ --runtime-arg -XX:SlowDebug=true \
$$(PRIVATE_CORE_MULTI_PARAM) $$(PRIVATE_CORE_COMPILE_OPTIONS)
$$(core_oat_name): $$(core_image_name)
@@ -214,6 +215,7 @@ $$(core_image_name): $$(TARGET_CORE_DEX_FILES) $$(core_dex2oat_dependency)
--instruction-set-features=$$($(2)DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES) \
--android-root=$$(PRODUCT_OUT)/system \
--generate-debug-info --generate-build-id --compile-pic \
+ --runtime-arg -XX:SlowDebug=true \
$$(PRIVATE_CORE_COMPILE_OPTIONS) || (rm $$(PRIVATE_CORE_OAT_NAME); exit 1)
$$(core_oat_name): $$(core_image_name)
diff --git a/build/art.go b/build/art.go
index 5704b43834..bf6eee6c41 100644
--- a/build/art.go
+++ b/build/art.go
@@ -66,6 +66,9 @@ func globalFlags(ctx android.BaseContext) ([]string, []string) {
"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
}
+ cdexLevel := envDefault(ctx, "ART_DEFAULT_COMPACT_DEX_LEVEL", "none")
+ cflags = append(cflags, "-DART_DEFAULT_COMPACT_DEX_LEVEL="+cdexLevel)
+
// We need larger stack overflow guards for ASAN, as the compiled code will have
// larger frame sizes. For simplicity, just use global not-target-specific cflags.
// Note: We increase this for both debug and non-debug, as the overflow gap will
@@ -100,6 +103,10 @@ func globalFlags(ctx android.BaseContext) ([]string, []string) {
asflags = append(asflags, "-DART_MIPS32_CHECK_ALIGNMENT")
}
+ if envTrueOrDefault(ctx, "USE_D8_DESUGAR") {
+ cflags = append(cflags, "-DUSE_D8_DESUGAR=1")
+ }
+
return cflags, asflags
}
@@ -363,3 +370,7 @@ func envTrue(ctx android.BaseContext, key string) bool {
func envFalse(ctx android.BaseContext, key string) bool {
return ctx.AConfig().Getenv(key) == "false"
}
+
+func envTrueOrDefault(ctx android.BaseContext, key string) bool {
+ return ctx.AConfig().Getenv(key) != "false"
+}
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 1536339515..5d672061df 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -20,6 +20,7 @@
#include "gtest/gtest.h"
+#include "jdwp_provider.h"
#include "experimental_flags.h"
#include "parsed_options.h"
#include "runtime.h"
@@ -244,7 +245,7 @@ TEST_F(CmdlineParserTest, TestLogVerbosity) {
{
const char* log_args = "-verbose:"
"class,compiler,gc,heap,jdwp,jni,monitor,profiler,signals,simulator,startup,"
- "third-party-jni,threads,verifier";
+ "third-party-jni,threads,verifier,verifier-debug";
LogVerbosity log_verbosity = LogVerbosity();
log_verbosity.class_linker = true;
@@ -261,6 +262,7 @@ TEST_F(CmdlineParserTest, TestLogVerbosity) {
log_verbosity.third_party_jni = true;
log_verbosity.threads = true;
log_verbosity.verifier = true;
+ log_verbosity.verifier_debug = true;
EXPECT_SINGLE_PARSE_VALUE(log_verbosity, log_args, M::Verbose);
}
@@ -363,48 +365,40 @@ TEST_F(CmdlineParserTest, DISABLED_TestXGcOption) {
} // TEST_F
/*
- * {"-Xrunjdwp:_", "-agentlib:jdwp=_"}
+ * { "-XjdwpProvider:_" }
*/
-TEST_F(CmdlineParserTest, TestJdwpOptions) {
- /*
- * Test success
- */
+TEST_F(CmdlineParserTest, TestJdwpProviderEmpty) {
{
- /*
- * "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n"
- */
- JDWP::JdwpOptions opt = JDWP::JdwpOptions();
- opt.transport = JDWP::JdwpTransportType::kJdwpTransportSocket;
- opt.port = 8000;
- opt.server = true;
+ EXPECT_SINGLE_PARSE_DEFAULT_VALUE(JdwpProvider::kInternal, "", M::JdwpProvider);
+ }
+} // TEST_F
- const char *opt_args = "-Xrunjdwp:transport=dt_socket,address=8000,server=y";
+TEST_F(CmdlineParserTest, TestJdwpProviderDefault) {
+ const char* opt_args = "-XjdwpProvider:default";
+ EXPECT_SINGLE_PARSE_VALUE(JdwpProvider::kInternal, opt_args, M::JdwpProvider);
+} // TEST_F
- EXPECT_SINGLE_PARSE_VALUE(opt, opt_args, M::JdwpOptions);
- }
+TEST_F(CmdlineParserTest, TestJdwpProviderInternal) {
+ const char* opt_args = "-XjdwpProvider:internal";
+ EXPECT_SINGLE_PARSE_VALUE(JdwpProvider::kInternal, opt_args, M::JdwpProvider);
+} // TEST_F
- {
- /*
- * "Example: -agentlib:jdwp=transport=dt_socket,address=localhost:6500,server=n\n");
- */
- JDWP::JdwpOptions opt = JDWP::JdwpOptions();
- opt.transport = JDWP::JdwpTransportType::kJdwpTransportSocket;
- opt.host = "localhost";
- opt.port = 6500;
- opt.server = false;
-
- const char *opt_args = "-agentlib:jdwp=transport=dt_socket,address=localhost:6500,server=n";
-
- EXPECT_SINGLE_PARSE_VALUE(opt, opt_args, M::JdwpOptions);
- }
+TEST_F(CmdlineParserTest, TestJdwpProviderNone) {
+ const char* opt_args = "-XjdwpProvider:none";
+ EXPECT_SINGLE_PARSE_VALUE(JdwpProvider::kNone, opt_args, M::JdwpProvider);
+} // TEST_F
- /*
- * Test failures
- */
- EXPECT_SINGLE_PARSE_FAIL("-Xrunjdwp:help", CmdlineResult::kUsage); // usage for help only
- EXPECT_SINGLE_PARSE_FAIL("-Xrunjdwp:blabla", CmdlineResult::kFailure); // invalid subarg
- EXPECT_SINGLE_PARSE_FAIL("-agentlib:jdwp=help", CmdlineResult::kUsage); // usage for help only
- EXPECT_SINGLE_PARSE_FAIL("-agentlib:jdwp=blabla", CmdlineResult::kFailure); // invalid subarg
+TEST_F(CmdlineParserTest, TestJdwpProviderAdbconnection) {
+ const char* opt_args = "-XjdwpProvider:adbconnection";
+ EXPECT_SINGLE_PARSE_VALUE(JdwpProvider::kAdbConnection, opt_args, M::JdwpProvider);
+} // TEST_F
+
+TEST_F(CmdlineParserTest, TestJdwpProviderHelp) {
+ EXPECT_SINGLE_PARSE_FAIL("-XjdwpProvider:help", CmdlineResult::kUsage);
+} // TEST_F
+
+TEST_F(CmdlineParserTest, TestJdwpProviderFail) {
+ EXPECT_SINGLE_PARSE_FAIL("-XjdwpProvider:blablabla", CmdlineResult::kFailure);
} // TEST_F
/*
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 37bdcdc5e2..d0d6bfd3ce 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -34,6 +34,7 @@
#include "gc/collector_type.h"
#include "gc/space/large_object_space.h"
#include "jdwp/jdwp.h"
+#include "jdwp_provider.h"
#include "jit/profile_saver_options.h"
#include "plugin.h"
#include "read_barrier_config.h"
@@ -64,123 +65,30 @@ struct CmdlineType<Unit> : CmdlineTypeParser<Unit> {
};
template <>
-struct CmdlineType<JDWP::JdwpOptions> : CmdlineTypeParser<JDWP::JdwpOptions> {
+struct CmdlineType<JdwpProvider> : CmdlineTypeParser<JdwpProvider> {
/*
- * Handle one of the JDWP name/value pairs.
- *
- * JDWP options are:
- * help: if specified, show help message and bail
- * transport: may be dt_socket or dt_shmem
- * address: for dt_socket, "host:port", or just "port" when listening
- * server: if "y", wait for debugger to attach; if "n", attach to debugger
- * timeout: how long to wait for debugger to connect / listen
- *
- * Useful with server=n (these aren't supported yet):
- * onthrow=<exception-name>: connect to debugger when exception thrown
- * onuncaught=y|n: connect to debugger when uncaught exception thrown
- * launch=<command-line>: launch the debugger itself
- *
- * The "transport" option is required, as is "address" if server=n.
+ * Handle a single JDWP provider name. Must be either 'internal', 'default', or the file name of
+ * an agent. A plugin will make use of this and the jdwpOptions to set up jdwp when appropriate.
*/
- Result Parse(const std::string& options) {
- VLOG(jdwp) << "ParseJdwpOptions: " << options;
-
- if (options == "help") {
+ Result Parse(const std::string& option) {
+ if (option == "help") {
return Result::Usage(
- "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n"
- "Example: -Xrunjdwp:transport=dt_socket,address=localhost:6500,server=n\n");
- }
-
- const std::string s;
-
- std::vector<std::string> pairs;
- Split(options, ',', &pairs);
-
- JDWP::JdwpOptions jdwp_options;
-
- for (const std::string& jdwp_option : pairs) {
- std::string::size_type equals_pos = jdwp_option.find('=');
- if (equals_pos == std::string::npos) {
- return Result::Failure(s +
- "Can't parse JDWP option '" + jdwp_option + "' in '" + options + "'");
- }
-
- Result parse_attempt = ParseJdwpOption(jdwp_option.substr(0, equals_pos),
- jdwp_option.substr(equals_pos + 1),
- &jdwp_options);
- if (parse_attempt.IsError()) {
- // We fail to parse this JDWP option.
- return parse_attempt;
- }
- }
-
- if (jdwp_options.transport == JDWP::kJdwpTransportUnknown) {
- return Result::Failure(s + "Must specify JDWP transport: " + options);
- }
- if (!jdwp_options.server && (jdwp_options.host.empty() || jdwp_options.port == 0)) {
- return Result::Failure(s + "Must specify JDWP host and port when server=n: " + options);
- }
-
- return Result::Success(std::move(jdwp_options));
- }
-
- Result ParseJdwpOption(const std::string& name, const std::string& value,
- JDWP::JdwpOptions* jdwp_options) {
- if (name == "transport") {
- if (value == "dt_socket") {
- jdwp_options->transport = JDWP::kJdwpTransportSocket;
- } else if (value == "dt_android_adb") {
- jdwp_options->transport = JDWP::kJdwpTransportAndroidAdb;
- } else {
- return Result::Failure("JDWP transport not supported: " + value);
- }
- } else if (name == "server") {
- if (value == "n") {
- jdwp_options->server = false;
- } else if (value == "y") {
- jdwp_options->server = true;
- } else {
- return Result::Failure("JDWP option 'server' must be 'y' or 'n'");
- }
- } else if (name == "suspend") {
- if (value == "n") {
- jdwp_options->suspend = false;
- } else if (value == "y") {
- jdwp_options->suspend = true;
- } else {
- return Result::Failure("JDWP option 'suspend' must be 'y' or 'n'");
- }
- } else if (name == "address") {
- /* this is either <port> or <host>:<port> */
- std::string port_string;
- jdwp_options->host.clear();
- std::string::size_type colon = value.find(':');
- if (colon != std::string::npos) {
- jdwp_options->host = value.substr(0, colon);
- port_string = value.substr(colon + 1);
- } else {
- port_string = value;
- }
- if (port_string.empty()) {
- return Result::Failure("JDWP address missing port: " + value);
- }
- char* end;
- uint64_t port = strtoul(port_string.c_str(), &end, 10);
- if (*end != '\0' || port > 0xffff) {
- return Result::Failure("JDWP address has junk in port field: " + value);
- }
- jdwp_options->port = port;
- } else if (name == "launch" || name == "onthrow" || name == "oncaught" || name == "timeout") {
- /* valid but unsupported */
- LOG(INFO) << "Ignoring JDWP option '" << name << "'='" << value << "'";
+ "Example: -XjdwpProvider:none to disable JDWP\n"
+ "Example: -XjdwpProvider:internal for internal jdwp implementation\n"
+ "Example: -XjdwpProvider:adbconnection for adb connection mediated jdwp implementation\n"
+ "Example: -XjdwpProvider:default for the default jdwp implementation"
+ " (currently internal)\n");
+ } else if (option == "internal" || option == "default") {
+ return Result::Success(JdwpProvider::kInternal);
+ } else if (option == "adbconnection") {
+ return Result::Success(JdwpProvider::kAdbConnection);
+ } else if (option == "none") {
+ return Result::Success(JdwpProvider::kNone);
} else {
- LOG(INFO) << "Ignoring unrecognized JDWP option '" << name << "'='" << value << "'";
+ return Result::Failure(std::string("not a valid jdwp provider: ") + option);
}
-
- return Result::SuccessNoValue();
}
-
- static const char* Name() { return "JdwpOptions"; }
+ static const char* Name() { return "JdwpProvider"; }
};
template <size_t Divisor>
@@ -420,19 +328,19 @@ struct CmdlineType<std::vector<Plugin>> : CmdlineTypeParser<std::vector<Plugin>>
};
template <>
-struct CmdlineType<std::list<ti::Agent>> : CmdlineTypeParser<std::list<ti::Agent>> {
+struct CmdlineType<std::list<ti::AgentSpec>> : CmdlineTypeParser<std::list<ti::AgentSpec>> {
Result Parse(const std::string& args) {
assert(false && "Use AppendValues() for an Agent list type");
return Result::Failure("Unconditional failure: Agent list must be appended: " + args);
}
Result ParseAndAppend(const std::string& args,
- std::list<ti::Agent>& existing_value) {
+ std::list<ti::AgentSpec>& existing_value) {
existing_value.emplace_back(args);
return Result::SuccessNoValue();
}
- static const char* Name() { return "std::list<ti::Agent>"; }
+ static const char* Name() { return "std::list<ti::AgentSpec>"; }
};
template <>
@@ -669,6 +577,8 @@ struct CmdlineType<LogVerbosity> : CmdlineTypeParser<LogVerbosity> {
log_verbosity.threads = true;
} else if (verbose_options[j] == "verifier") {
log_verbosity.verifier = true;
+ } else if (verbose_options[j] == "verifier-debug") {
+ log_verbosity.verifier_debug = true;
} else if (verbose_options[j] == "image") {
log_verbosity.image = true;
} else if (verbose_options[j] == "systrace-locks") {
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 37a18cb9e9..164f9c1e8f 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -181,15 +181,10 @@ art_cc_defaults {
],
},
},
- target: {
- android: {
- // For atrace.
- shared_libs: ["libcutils"],
- },
- },
generated_sources: ["art_compiler_operator_srcs"],
shared_libs: [
"libbase",
+ "libcutils", // for atrace.
"liblzma",
],
include_dirs: ["art/disassembler"],
@@ -323,7 +318,7 @@ art_cc_test {
"linker/linker_patch_test.cc",
"linker/output_stream_test.cc",
"optimizing/bounds_check_elimination_test.cc",
- "optimizing/cloner_test.cc",
+ "optimizing/superblock_cloner_test.cc",
"optimizing/data_type_test.cc",
"optimizing/dominator_test.cc",
"optimizing/find_loops_test.cc",
diff --git a/compiler/compiler.cc b/compiler/compiler.cc
index c500921ab3..60977b6bd5 100644
--- a/compiler/compiler.cc
+++ b/compiler/compiler.cc
@@ -16,7 +16,10 @@
#include "compiler.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/macros.h"
+#include "dex/code_item_accessors-inl.h"
#include "driver/compiler_driver.h"
#include "optimizing/optimizing_compiler.h"
#include "utils.h"
@@ -44,15 +47,16 @@ bool Compiler::IsPathologicalCase(const DexFile::CodeItem& code_item,
* Dalvik uses 16-bit uints for instruction and register counts. We'll limit to a quarter
* of that, which also guarantees we cannot overflow our 16-bit internal Quick SSA name space.
*/
- if (code_item.insns_size_in_code_units_ >= UINT16_MAX / 4) {
+ CodeItemDataAccessor accessor(&dex_file, &code_item);
+ if (accessor.InsnsSizeInCodeUnits() >= UINT16_MAX / 4) {
LOG(INFO) << "Method exceeds compiler instruction limit: "
- << code_item.insns_size_in_code_units_
+ << accessor.InsnsSizeInCodeUnits()
<< " in " << dex_file.PrettyMethod(method_idx);
return true;
}
- if (code_item.registers_size_ >= UINT16_MAX / 4) {
+ if (accessor.RegistersSize() >= UINT16_MAX / 4) {
LOG(INFO) << "Method exceeds compiler virtual register limit: "
- << code_item.registers_size_ << " in " << dex_file.PrettyMethod(method_idx);
+ << accessor.RegistersSize() << " in " << dex_file.PrettyMethod(method_idx);
return true;
}
return false;
diff --git a/compiler/compiler.h b/compiler/compiler.h
index 85abd6654c..b92bff61a9 100644
--- a/compiler/compiler.h
+++ b/compiler/compiler.h
@@ -18,7 +18,7 @@
#define ART_COMPILER_COMPILER_H_
#include "base/mutex.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "os.h"
namespace art {
diff --git a/compiler/debug/dwarf/writer.h b/compiler/debug/dwarf/writer.h
index 95912ad6c9..afeb980352 100644
--- a/compiler/debug/dwarf/writer.h
+++ b/compiler/debug/dwarf/writer.h
@@ -19,8 +19,10 @@
#include <type_traits>
#include <vector>
+
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
#include "leb128.h"
namespace art {
diff --git a/compiler/debug/elf_debug_frame_writer.h b/compiler/debug/elf_debug_frame_writer.h
index d0c98a7b79..27b70c8caa 100644
--- a/compiler/debug/elf_debug_frame_writer.h
+++ b/compiler/debug/elf_debug_frame_writer.h
@@ -207,13 +207,12 @@ void WriteCFISection(linker::ElfBuilder<ElfTypes>* builder,
}
// Write .eh_frame/.debug_frame section.
- auto* cfi_section = (format == dwarf::DW_DEBUG_FRAME_FORMAT
- ? builder->GetDebugFrame()
- : builder->GetEhFrame());
+ const bool is_debug_frame = format == dwarf::DW_DEBUG_FRAME_FORMAT;
+ auto* cfi_section = (is_debug_frame ? builder->GetDebugFrame() : builder->GetEhFrame());
{
cfi_section->Start();
const bool is64bit = Is64BitInstructionSet(builder->GetIsa());
- const Elf_Addr cfi_address = cfi_section->GetAddress();
+ const Elf_Addr cfi_address = (is_debug_frame ? 0 : cfi_section->GetAddress());
const Elf_Addr cie_address = cfi_address;
Elf_Addr buffer_address = cfi_address;
std::vector<uint8_t> buffer; // Small temporary buffer.
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index d5999941d7..e2bea8e096 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -27,8 +27,9 @@
#include "debug/elf_compilation_unit.h"
#include "debug/elf_debug_loc_writer.h"
#include "debug/method_debug_info.h"
-#include "dex_file-inl.h"
-#include "dex_file.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file.h"
#include "heap_poisoning.h"
#include "linear_alloc.h"
#include "linker/elf_builder.h"
@@ -48,10 +49,10 @@ static void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) {
static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
std::vector<const char*> names;
- if (mi->code_item != nullptr) {
+ CodeItemDebugInfoAccessor accessor(mi->dex_file, mi->code_item);
+ if (accessor.HasCodeItem()) {
DCHECK(mi->dex_file != nullptr);
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*mi->dex_file, mi->code_item);
- const uint8_t* stream = mi->dex_file->GetDebugInfoStream(debug_info_offset);
+ const uint8_t* stream = mi->dex_file->GetDebugInfoStream(accessor.DebugInfoOffset());
if (stream != nullptr) {
DecodeUnsignedLeb128(&stream); // line.
uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
@@ -162,7 +163,7 @@ class ElfCompilationUnitWriter {
for (auto mi : compilation_unit.methods) {
DCHECK(mi->dex_file != nullptr);
const DexFile* dex = mi->dex_file;
- const DexFile::CodeItem* dex_code = mi->code_item;
+ CodeItemDebugInfoAccessor accessor(dex, mi->code_item);
const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index);
const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method);
const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto);
@@ -204,13 +205,13 @@ class ElfCompilationUnitWriter {
// Decode dex register locations for all stack maps.
// It might be expensive, so do it just once and reuse the result.
std::vector<DexRegisterMap> dex_reg_maps;
- if (dex_code != nullptr && mi->code_info != nullptr) {
+ if (accessor.HasCodeItem() && mi->code_info != nullptr) {
const CodeInfo code_info(mi->code_info);
CodeInfoEncoding encoding = code_info.ExtractEncoding();
for (size_t s = 0; s < code_info.GetNumberOfStackMaps(encoding); ++s) {
const StackMap& stack_map = code_info.GetStackMapAt(s, encoding);
dex_reg_maps.push_back(code_info.GetDexRegisterMapOf(
- stack_map, encoding, dex_code->registers_size_));
+ stack_map, encoding, accessor.RegistersSize()));
}
}
@@ -224,9 +225,9 @@ class ElfCompilationUnitWriter {
WriteName("this");
info_.WriteFlagPresent(DW_AT_artificial);
WriteLazyType(dex_class_desc);
- if (dex_code != nullptr) {
+ if (accessor.HasCodeItem()) {
// Write the stack location of the parameter.
- const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+ const uint32_t vreg = accessor.RegistersSize() - accessor.InsSize() + arg_reg;
const bool is64bitValue = false;
WriteRegLocation(mi, dex_reg_maps, vreg, is64bitValue, compilation_unit.code_address);
}
@@ -244,30 +245,27 @@ class ElfCompilationUnitWriter {
const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_);
WriteLazyType(type_desc);
const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J';
- if (dex_code != nullptr) {
+ if (accessor.HasCodeItem()) {
// Write the stack location of the parameter.
- const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+ const uint32_t vreg = accessor.RegistersSize() - accessor.InsSize() + arg_reg;
WriteRegLocation(mi, dex_reg_maps, vreg, is64bitValue, compilation_unit.code_address);
}
arg_reg += is64bitValue ? 2 : 1;
info_.EndTag();
}
- if (dex_code != nullptr) {
- DCHECK_EQ(arg_reg, dex_code->ins_size_);
+ if (accessor.HasCodeItem()) {
+ DCHECK_EQ(arg_reg, accessor.InsSize());
}
}
// Write local variables.
LocalInfos local_infos;
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex, dex_code);
- if (dex->DecodeDebugLocalInfo(dex_code,
- debug_info_offset,
- is_static,
- mi->dex_method_index,
- LocalInfoCallback,
- &local_infos)) {
+ if (accessor.DecodeDebugLocalInfo(is_static,
+ mi->dex_method_index,
+ LocalInfoCallback,
+ &local_infos)) {
for (const DexFile::LocalInfo& var : local_infos) {
- if (var.reg_ < dex_code->registers_size_ - dex_code->ins_size_) {
+ if (var.reg_ < accessor.RegistersSize() - accessor.InsSize()) {
info_.StartTag(DW_TAG_variable);
WriteName(var.name_);
WriteLazyType(var.descriptor_);
@@ -296,7 +294,7 @@ class ElfCompilationUnitWriter {
CHECK_EQ(info_.Depth(), 0);
std::vector<uint8_t> buffer;
buffer.reserve(info_.data()->size() + KB);
- const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+ const size_t offset = owner_->builder_->GetDebugInfo()->GetPosition();
// All compilation units share single table which is at the start of .debug_abbrev.
const size_t debug_abbrev_offset = 0;
WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
@@ -461,7 +459,7 @@ class ElfCompilationUnitWriter {
CHECK_EQ(info_.Depth(), 0);
std::vector<uint8_t> buffer;
buffer.reserve(info_.data()->size() + KB);
- const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+ const size_t offset = owner_->builder_->GetDebugInfo()->GetPosition();
// All compilation units share single table which is at the start of .debug_abbrev.
const size_t debug_abbrev_offset = 0;
WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index 943e03a765..9910e7a4ce 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -24,7 +24,7 @@
#include "debug/dwarf/headers.h"
#include "debug/elf_compilation_unit.h"
#include "debug/src_map_elem.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "linker/elf_builder.h"
#include "oat_file.h"
#include "stack_map.h"
@@ -60,7 +60,7 @@ class ElfDebugLineWriter {
? builder_->GetText()->GetAddress()
: 0;
- compilation_unit.debug_line_offset = builder_->GetDebugLine()->GetSize();
+ compilation_unit.debug_line_offset = builder_->GetDebugLine()->GetPosition();
std::vector<dwarf::FileEntry> files;
std::unordered_map<std::string, size_t> files_map;
@@ -159,9 +159,9 @@ class ElfDebugLineWriter {
PositionInfos dex2line_map;
DCHECK(mi->dex_file != nullptr);
const DexFile* dex = mi->dex_file;
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex, mi->code_item);
- if (!dex->DecodeDebugPositionInfo(
- mi->code_item, debug_info_offset, PositionInfoCallback, &dex2line_map)) {
+ CodeItemDebugInfoAccessor accessor(dex, mi->code_item);
+ const uint32_t debug_info_offset = accessor.DebugInfoOffset();
+ if (!dex->DecodeDebugPositionInfo(debug_info_offset, PositionInfoCallback, &dex2line_map)) {
continue;
}
@@ -268,7 +268,7 @@ class ElfDebugLineWriter {
}
std::vector<uint8_t> buffer;
buffer.reserve(opcodes.data()->size() + KB);
- size_t offset = builder_->GetDebugLine()->GetSize();
+ size_t offset = builder_->GetDebugLine()->GetPosition();
WriteDebugLineTable(directories, files, opcodes, offset, &buffer, &debug_line_patches_);
builder_->GetDebugLine()->WriteFully(buffer.data(), buffer.size());
return buffer.size();
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
index bb856b29f4..34c2919a21 100644
--- a/compiler/debug/elf_debug_loc_writer.h
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -149,11 +149,12 @@ static std::vector<VariableLocation> GetVariableLocations(
DCHECK_LT(stack_map_index, dex_register_maps.size());
DexRegisterMap dex_register_map = dex_register_maps[stack_map_index];
DCHECK(dex_register_map.IsValid());
+ CodeItemDataAccessor accessor(method_info->dex_file, method_info->code_item);
reg_lo = dex_register_map.GetDexRegisterLocation(
- vreg, method_info->code_item->registers_size_, code_info, encoding);
+ vreg, accessor.RegistersSize(), code_info, encoding);
if (is64bitValue) {
reg_hi = dex_register_map.GetDexRegisterLocation(
- vreg + 1, method_info->code_item->registers_size_, code_info, encoding);
+ vreg + 1, accessor.RegistersSize(), code_info, encoding);
}
// Add location entry for this address range.
@@ -251,7 +252,10 @@ static void WriteDebugLocEntry(const MethodDebugInfo* method_info,
// kInStackLargeOffset and kConstantLargeValue are hidden by GetKind().
// kInRegisterHigh and kInFpuRegisterHigh should be handled by
// the special cases above and they should not occur alone.
- LOG(ERROR) << "Unexpected register location kind: " << kind;
+ LOG(WARNING) << "Unexpected register location: " << kind
+ << " (This can indicate either a bug in the dexer when generating"
+ << " local variable information, or a bug in ART compiler."
+ << " Please file a bug at go/art-bug)";
break;
}
if (is64bitValue) {
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index 33c46d7e1f..a6267292bf 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -108,29 +108,32 @@ void WriteDebugInfo(linker::ElfBuilder<ElfTypes>* builder,
std::vector<uint8_t> MakeMiniDebugInfo(
InstructionSet isa,
const InstructionSetFeatures* features,
- size_t rodata_size,
+ uint64_t text_address,
size_t text_size,
const ArrayRef<const MethodDebugInfo>& method_infos) {
if (Is64BitInstructionSet(isa)) {
return MakeMiniDebugInfoInternal<ElfTypes64>(isa,
features,
- rodata_size,
+ text_address,
text_size,
method_infos);
} else {
return MakeMiniDebugInfoInternal<ElfTypes32>(isa,
features,
- rodata_size,
+ text_address,
text_size,
method_infos);
}
}
template <typename ElfTypes>
-static std::vector<uint8_t> WriteDebugElfFileForMethodsInternal(
+static std::vector<uint8_t> MakeElfFileForJITInternal(
InstructionSet isa,
const InstructionSetFeatures* features,
- const ArrayRef<const MethodDebugInfo>& method_infos) {
+ bool mini_debug_info,
+ const MethodDebugInfo& mi) {
+ CHECK_EQ(mi.is_code_address_text_relative, false);
+ ArrayRef<const MethodDebugInfo> method_infos(&mi, 1);
std::vector<uint8_t> buffer;
buffer.reserve(KB);
linker::VectorOutputStream out("Debug ELF file", &buffer);
@@ -138,23 +141,34 @@ static std::vector<uint8_t> WriteDebugElfFileForMethodsInternal(
new linker::ElfBuilder<ElfTypes>(isa, features, &out));
// No program headers since the ELF file is not linked and has no allocated sections.
builder->Start(false /* write_program_headers */);
- WriteDebugInfo(builder.get(),
- method_infos,
- dwarf::DW_DEBUG_FRAME_FORMAT,
- false /* write_oat_patches */);
+ if (mini_debug_info) {
+ std::vector<uint8_t> mdi = MakeMiniDebugInfo(isa,
+ features,
+ mi.code_address,
+ mi.code_size,
+ method_infos);
+ builder->WriteSection(".gnu_debugdata", &mdi);
+ } else {
+ builder->GetText()->AllocateVirtualMemory(mi.code_address, mi.code_size);
+ WriteDebugInfo(builder.get(),
+ method_infos,
+ dwarf::DW_DEBUG_FRAME_FORMAT,
+ false /* write_oat_patches */);
+ }
builder->End();
CHECK(builder->Good());
return buffer;
}
-std::vector<uint8_t> WriteDebugElfFileForMethods(
+std::vector<uint8_t> MakeElfFileForJIT(
InstructionSet isa,
const InstructionSetFeatures* features,
- const ArrayRef<const MethodDebugInfo>& method_infos) {
+ bool mini_debug_info,
+ const MethodDebugInfo& method_info) {
if (Is64BitInstructionSet(isa)) {
- return WriteDebugElfFileForMethodsInternal<ElfTypes64>(isa, features, method_infos);
+ return MakeElfFileForJITInternal<ElfTypes64>(isa, features, mini_debug_info, method_info);
} else {
- return WriteDebugElfFileForMethodsInternal<ElfTypes32>(isa, features, method_infos);
+ return MakeElfFileForJITInternal<ElfTypes32>(isa, features, mini_debug_info, method_info);
}
}
diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h
index d24ca9b203..a47bf076b9 100644
--- a/compiler/debug/elf_debug_writer.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -43,14 +43,15 @@ void WriteDebugInfo(
std::vector<uint8_t> MakeMiniDebugInfo(
InstructionSet isa,
const InstructionSetFeatures* features,
- size_t rodata_section_size,
+ uint64_t text_section_address,
size_t text_section_size,
const ArrayRef<const MethodDebugInfo>& method_infos);
-std::vector<uint8_t> WriteDebugElfFileForMethods(
+std::vector<uint8_t> MakeElfFileForJIT(
InstructionSet isa,
const InstructionSetFeatures* features,
- const ArrayRef<const MethodDebugInfo>& method_infos);
+ bool mini_debug_info,
+ const MethodDebugInfo& method_info);
std::vector<uint8_t> WriteDebugElfFileForClasses(
InstructionSet isa,
diff --git a/compiler/debug/elf_gnu_debugdata_writer.h b/compiler/debug/elf_gnu_debugdata_writer.h
index 1cdf6b0ad1..78b8e2780c 100644
--- a/compiler/debug/elf_gnu_debugdata_writer.h
+++ b/compiler/debug/elf_gnu_debugdata_writer.h
@@ -80,7 +80,7 @@ template <typename ElfTypes>
static std::vector<uint8_t> MakeMiniDebugInfoInternal(
InstructionSet isa,
const InstructionSetFeatures* features,
- size_t rodata_section_size,
+ typename ElfTypes::Addr text_section_address,
size_t text_section_size,
const ArrayRef<const MethodDebugInfo>& method_infos) {
std::vector<uint8_t> buffer;
@@ -88,11 +88,9 @@ static std::vector<uint8_t> MakeMiniDebugInfoInternal(
linker::VectorOutputStream out("Mini-debug-info ELF file", &buffer);
std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
new linker::ElfBuilder<ElfTypes>(isa, features, &out));
- builder->Start();
- // Mirror .rodata and .text as NOBITS sections.
- // It is needed to detected relocations after compression.
- builder->GetRoData()->WriteNoBitsSection(rodata_section_size);
- builder->GetText()->WriteNoBitsSection(text_section_size);
+ builder->Start(false /* write_program_headers */);
+ // Mirror .text as NOBITS section since the added symbols will reference it.
+ builder->GetText()->AllocateVirtualMemory(text_section_address, text_section_size);
WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */);
WriteCFISection(builder.get(),
method_infos,
diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h
index 0907e102a0..57e010f232 100644
--- a/compiler/debug/elf_symtab_writer.h
+++ b/compiler/debug/elf_symtab_writer.h
@@ -79,8 +79,9 @@ static void WriteDebugSymbols(linker::ElfBuilder<ElfTypes>* builder,
last_name_offset = name_offset;
}
- const auto* text = info.is_code_address_text_relative ? builder->GetText() : nullptr;
- uint64_t address = info.code_address + (text != nullptr ? text->GetAddress() : 0);
+ const auto* text = builder->GetText();
+ uint64_t address = info.code_address;
+ address += info.is_code_address_text_relative ? text->GetAddress() : 0;
// Add in code delta, e.g., thumb bit 0 for Thumb2 code.
address += CompiledMethod::CodeDelta(info.isa);
symtab->Add(name_offset, text, address, info.code_size, STB_GLOBAL, STT_FUNC);
diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h
index a8225fa2b4..43c8de26aa 100644
--- a/compiler/debug/method_debug_info.h
+++ b/compiler/debug/method_debug_info.h
@@ -21,7 +21,7 @@
#include "arch/instruction_set.h"
#include "base/array_ref.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
namespace art {
namespace debug {
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index cc452fc1ae..52cb217980 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -16,16 +16,18 @@
#include "dex_to_dex_compiler.h"
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "art_field-inl.h"
#include "art_method-inl.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG
+#include "base/macros.h"
#include "base/mutex.h"
#include "bytecode_utils.h"
#include "compiled_method.h"
-#include "dex_file-inl.h"
-#include "dex_instruction-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_instruction-inl.h"
#include "driver/compiler_driver.h"
#include "driver/dex_compilation_unit.h"
#include "mirror/dex_cache.h"
@@ -112,7 +114,8 @@ class DexCompiler {
void DexCompiler::Compile() {
DCHECK_EQ(dex_to_dex_compilation_level_, DexToDexCompilationLevel::kOptimize);
- IterationRange<DexInstructionIterator> instructions = unit_.GetCodeItem()->Instructions();
+ IterationRange<DexInstructionIterator> instructions(unit_.GetCodeItemAccessor().begin(),
+ unit_.GetCodeItemAccessor().end());
for (DexInstructionIterator it = instructions.begin(); it != instructions.end(); ++it) {
const uint32_t dex_pc = it.DexPc();
Instruction* inst = const_cast<Instruction*>(&it.Inst());
@@ -294,7 +297,6 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
ClassLinker* class_linker = unit_.GetClassLinker();
ArtMethod* resolved_method =
class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- GetDexFile(),
method_idx,
unit_.GetDexCache(),
unit_.GetClassLoader(),
@@ -363,7 +365,7 @@ CompiledMethod* ArtCompileDEX(
if (kIsDebugBuild) {
// Double check that the counts line up with the size of the quicken info.
size_t quicken_count = 0;
- for (const DexInstructionPcPair& pair : code_item->Instructions()) {
+ for (const DexInstructionPcPair& pair : unit.GetCodeItemAccessor()) {
if (QuickenInfoTable::NeedsIndexForInstruction(&pair.Inst())) {
++quicken_count;
}
@@ -375,7 +377,7 @@ CompiledMethod* ArtCompileDEX(
// Dex pc is not serialized, only used for checking the instructions. Since we access the
// array based on the index of the quickened instruction, the indexes must line up perfectly.
// The reader side uses the NeedsIndexForInstruction function too.
- const Instruction& inst = code_item->InstructionAt(info.dex_pc);
+ const Instruction& inst = unit.GetCodeItemAccessor().InstructionAt(info.dex_pc);
CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode();
// Add the index.
quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 0));
diff --git a/compiler/dex/dex_to_dex_compiler.h b/compiler/dex/dex_to_dex_compiler.h
index 87ddb395ad..80b94d2dc3 100644
--- a/compiler/dex/dex_to_dex_compiler.h
+++ b/compiler/dex/dex_to_dex_compiler.h
@@ -17,7 +17,7 @@
#ifndef ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_
#define ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "handle.h"
#include "invoke_type.h"
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index 979c4c4ce2..19b190093f 100644
--- a/compiler/dex/dex_to_dex_decompiler_test.cc
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -20,7 +20,7 @@
#include "common_compiler_test.h"
#include "compiled_method-inl.h"
#include "compiler_callbacks.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
#include "handle_scope-inl.h"
@@ -99,8 +99,10 @@ class DexToDexDecompilerTest : public CommonCompilerTest {
if (compiled_method != nullptr) {
table = compiled_method->GetVmapTable();
}
- optimizer::ArtDecompileDEX(
- *it.GetMethodCodeItem(), table, /* decompile_return_instruction */ true);
+ optimizer::ArtDecompileDEX(*updated_dex_file,
+ *it.GetMethodCodeItem(),
+ table,
+ /* decompile_return_instruction */ true);
it.Next();
}
DCHECK(!it.HasNext());
diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc
index b409eb2dbb..ce67b85b99 100644
--- a/compiler/dex/inline_method_analyser.cc
+++ b/compiler/dex/inline_method_analyser.cc
@@ -20,11 +20,11 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "class_linker-inl.h"
-#include "code_item_accessors-inl.h"
-#include "dex_file-inl.h"
-#include "dex_instruction-inl.h"
-#include "dex_instruction.h"
-#include "dex_instruction_utils.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_instruction-inl.h"
+#include "dex/dex_instruction.h"
+#include "dex/dex_instruction_utils.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
@@ -141,8 +141,11 @@ bool Matcher::DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pat
ArtMethod* GetTargetConstructor(ArtMethod* method, const Instruction* invoke_direct)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT);
- DCHECK_EQ(invoke_direct->VRegC_35c(),
- method->GetCodeItem()->registers_size_ - method->GetCodeItem()->ins_size_);
+ if (kIsDebugBuild) {
+ CodeItemDataAccessor accessor(method);
+ DCHECK_EQ(invoke_direct->VRegC_35c(),
+ accessor.RegistersSize() - accessor.InsSize());
+ }
uint32_t method_index = invoke_direct->VRegB_35c();
ArtMethod* target_method = Runtime::Current()->GetClassLinker()->LookupResolvedMethod(
method_index, method->GetDexCache(), method->GetClassLoader());
@@ -323,7 +326,7 @@ bool DoAnalyseConstructor(const CodeItemDataAccessor* code_item,
if (target_method->GetDeclaringClass()->IsObjectClass()) {
DCHECK_EQ(CodeItemDataAccessor(target_method).begin()->Opcode(), Instruction::RETURN_VOID);
} else {
- CodeItemDataAccessor target_code_item = CodeItemDataAccessor::CreateNullable(target_method);
+ CodeItemDataAccessor target_code_item(target_method);
if (!target_code_item.HasCodeItem()) {
return false; // Native constructor?
}
@@ -427,7 +430,7 @@ static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) ==
InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant");
bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* result) {
- CodeItemDataAccessor code_item = CodeItemDataAccessor::CreateNullable(method);
+ CodeItemDataAccessor code_item(method);
if (!code_item.HasCodeItem()) {
// Native or abstract.
return false;
diff --git a/compiler/dex/inline_method_analyser.h b/compiler/dex/inline_method_analyser.h
index cde2147995..837cc85456 100644
--- a/compiler/dex/inline_method_analyser.h
+++ b/compiler/dex/inline_method_analyser.h
@@ -19,8 +19,8 @@
#include "base/macros.h"
#include "base/mutex.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction.h"
#include "method_reference.h"
/*
diff --git a/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc
index 92b123013d..540bd0ce45 100644
--- a/compiler/dex/quick_compiler_callbacks.cc
+++ b/compiler/dex/quick_compiler_callbacks.cc
@@ -38,7 +38,7 @@ ClassStatus QuickCompilerCallbacks::GetPreviousClassState(ClassReference ref) {
// If we don't have class unloading enabled in the compiler, we will never see class that were
// previously verified. Return false to avoid overhead from the lookup in the compiler driver.
if (!does_class_unloading_) {
- return ClassStatus::kStatusNotReady;
+ return ClassStatus::kNotReady;
}
DCHECK(compiler_driver_ != nullptr);
// In the case of the quicken filter: avoiding verification of quickened instructions, which the
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 03c90d82c8..1e0b94de81 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -16,7 +16,8 @@
#include "verification_results.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/mutex-inl.h"
#include "base/stl_util.h"
#include "driver/compiler_driver.h"
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index 524b0a6911..f2da3ffc2f 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -19,10 +19,11 @@
#include <algorithm>
#include <memory>
-#include "base/logging.h"
-#include "code_item_accessors-inl.h"
-#include "dex_file.h"
-#include "dex_instruction-inl.h"
+#include <android-base/logging.h>
+
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction-inl.h"
#include "runtime.h"
#include "verifier/method_verifier-inl.h"
#include "verifier/reg_type-inl.h"
diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h
index 64b3f448e6..2ed17f1dfd 100644
--- a/compiler/dex/verified_method.h
+++ b/compiler/dex/verified_method.h
@@ -20,7 +20,7 @@
#include <vector>
#include "base/mutex.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "method_reference.h"
#include "safe_map.h"
diff --git a/compiler/driver/compiled_method_storage.cc b/compiler/driver/compiled_method_storage.cc
index c739333cee..c8c2b6998f 100644
--- a/compiler/driver/compiled_method_storage.cc
+++ b/compiler/driver/compiled_method_storage.cc
@@ -19,7 +19,8 @@
#include "compiled_method_storage.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "compiled_method.h"
#include "linker/linker_patch.h"
#include "thread-current-inl.h"
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index b04392918d..294072d7e7 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -32,14 +32,16 @@
namespace art {
-inline mirror::Class* CompilerDriver::ResolveClass(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, dex::TypeIndex cls_index,
+inline ObjPtr<mirror::Class> CompilerDriver::ResolveClass(
+ const ScopedObjectAccess& soa,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ dex::TypeIndex cls_index,
const DexCompilationUnit* mUnit) {
DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
- mirror::Class* cls = mUnit->GetClassLinker()->ResolveType(
- *mUnit->GetDexFile(), cls_index, dex_cache, class_loader);
+ ObjPtr<mirror::Class> cls =
+ mUnit->GetClassLinker()->ResolveType(cls_index, dex_cache, class_loader);
DCHECK_EQ(cls == nullptr, soa.Self()->IsExceptionPending());
if (UNLIKELY(cls == nullptr)) {
// Clean up any exception left by type resolution.
@@ -48,9 +50,11 @@ inline mirror::Class* CompilerDriver::ResolveClass(
return cls;
}
-inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) {
+inline ObjPtr<mirror::Class> CompilerDriver::ResolveCompilingMethodsClass(
+ const ScopedObjectAccess& soa,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ const DexCompilationUnit* mUnit) {
DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
const DexFile::MethodId& referrer_method_id =
@@ -58,13 +62,13 @@ inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass(
return ResolveClass(soa, dex_cache, class_loader, referrer_method_id.class_idx_, mUnit);
}
-inline ArtField* CompilerDriver::ResolveFieldWithDexFile(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file,
- uint32_t field_idx, bool is_static) {
- DCHECK_EQ(dex_cache->GetDexFile(), dex_file);
+inline ArtField* CompilerDriver::ResolveField(const ScopedObjectAccess& soa,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ uint32_t field_idx,
+ bool is_static) {
ArtField* resolved_field = Runtime::Current()->GetClassLinker()->ResolveField(
- *dex_file, field_idx, dex_cache, class_loader, is_static);
+ field_idx, dex_cache, class_loader, is_static);
DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending());
if (UNLIKELY(resolved_field == nullptr)) {
// Clean up any exception left by type resolution.
@@ -79,18 +83,11 @@ inline ArtField* CompilerDriver::ResolveFieldWithDexFile(
return resolved_field;
}
-inline ArtField* CompilerDriver::ResolveField(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
- uint32_t field_idx, bool is_static) {
- DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
- return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx,
- is_static);
-}
-
inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField(
- mirror::DexCache* dex_cache, mirror::Class* referrer_class,
- ArtField* resolved_field, uint16_t field_idx) {
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::Class> referrer_class,
+ ArtField* resolved_field,
+ uint16_t field_idx) {
DCHECK(!resolved_field->IsStatic());
ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
bool fast_get = referrer_class != nullptr &&
@@ -112,7 +109,7 @@ inline ArtMethod* CompilerDriver::ResolveMethod(
DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
ArtMethod* resolved_method =
mUnit->GetClassLinker()->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- *dex_cache->GetDexFile(), method_idx, dex_cache, class_loader, nullptr, invoke_type);
+ method_idx, dex_cache, class_loader, /* referrer */ nullptr, invoke_type);
if (UNLIKELY(resolved_method == nullptr)) {
DCHECK(soa.Self()->IsExceptionPending());
// Clean up any exception left by type resolution.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 0ca3c8f613..fe83a66d0f 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -32,6 +32,7 @@
#include "base/array_ref.h"
#include "base/bit_vector.h"
#include "base/enums.h"
+#include "base/logging.h" // For VLOG
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
@@ -41,13 +42,13 @@
#include "compiler.h"
#include "compiler_callbacks.h"
#include "compiler_driver-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_annotations.h"
+#include "dex/dex_instruction-inl.h"
#include "dex/dex_to_dex_compiler.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
#include "dex_compilation_unit.h"
-#include "dex_file-inl.h"
-#include "dex_file_annotations.h"
-#include "dex_instruction-inl.h"
#include "driver/compiler_options.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/accounting/heap_bitmap.h"
@@ -710,14 +711,14 @@ static void ResolveConstStrings(Handle<mirror::DexCache> dex_cache,
}
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
- for (const DexInstructionPcPair& inst : code_item->Instructions()) {
+ for (const DexInstructionPcPair& inst : CodeItemInstructionAccessor(&dex_file, code_item)) {
switch (inst->Opcode()) {
case Instruction::CONST_STRING:
case Instruction::CONST_STRING_JUMBO: {
dex::StringIndex string_index((inst->Opcode() == Instruction::CONST_STRING)
? inst->VRegB_21c()
: inst->VRegB_31c());
- mirror::String* string = class_linker->ResolveString(dex_file, string_index, dex_cache);
+ ObjPtr<mirror::String> string = class_linker->ResolveString(string_index, dex_cache);
CHECK(string != nullptr) << "Could not allocate a string when forcing determinism";
break;
}
@@ -949,14 +950,14 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor {
ArtMethod* method,
std::set<std::pair<dex::TypeIndex, const DexFile*>>* exceptions_to_resolve)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile::CodeItem* code_item = method->GetCodeItem();
- if (code_item == nullptr) {
+ if (method->GetCodeItem() == nullptr) {
return; // native or abstract method
}
- if (code_item->tries_size_ == 0) {
+ CodeItemDataAccessor accessor(method);
+ if (accessor.TriesSize() == 0) {
return; // nothing to process
}
- const uint8_t* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
+ const uint8_t* encoded_catch_handler_list = accessor.GetCatchHandlerData();
size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list);
for (size_t i = 0; i < num_encoded_catch_handlers; i++) {
int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list);
@@ -1048,22 +1049,21 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings) {
for (const auto& exception_type : unresolved_exception_types) {
dex::TypeIndex exception_type_idx = exception_type.first;
const DexFile* dex_file = exception_type.second;
- StackHandleScope<2> hs2(self);
+ StackHandleScope<1> hs2(self);
Handle<mirror::DexCache> dex_cache(hs2.NewHandle(class_linker->RegisterDexFile(*dex_file,
nullptr)));
- Handle<mirror::Class> klass(hs2.NewHandle(
+ ObjPtr<mirror::Class> klass =
(dex_cache != nullptr)
- ? class_linker->ResolveType(*dex_file,
- exception_type_idx,
+ ? class_linker->ResolveType(exception_type_idx,
dex_cache,
ScopedNullHandle<mirror::ClassLoader>())
- : nullptr));
+ : nullptr;
if (klass == nullptr) {
const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
const char* descriptor = dex_file->GetTypeDescriptor(type_id);
LOG(FATAL) << "Failed to resolve class " << descriptor;
}
- DCHECK(java_lang_Throwable->IsAssignableFrom(klass.Get()));
+ DCHECK(java_lang_Throwable->IsAssignableFrom(klass));
}
// Resolving exceptions may load classes that reference more exceptions, iterate until no
// more are found
@@ -1367,17 +1367,18 @@ void CompilerDriver::ProcessedStaticField(bool resolved, bool local) {
}
ArtField* CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx,
- const DexCompilationUnit* mUnit, bool is_put,
+ const DexCompilationUnit* mUnit,
+ bool is_put,
const ScopedObjectAccess& soa) {
// Try to resolve the field and compiling method's class.
ArtField* resolved_field;
- mirror::Class* referrer_class;
+ ObjPtr<mirror::Class> referrer_class;
Handle<mirror::DexCache> dex_cache(mUnit->GetDexCache());
{
- Handle<mirror::ClassLoader> class_loader_handle = mUnit->GetClassLoader();
- resolved_field = ResolveField(soa, dex_cache, class_loader_handle, mUnit, field_idx, false);
+ Handle<mirror::ClassLoader> class_loader = mUnit->GetClassLoader();
+ resolved_field = ResolveField(soa, dex_cache, class_loader, field_idx, /* is_static */ false);
referrer_class = resolved_field != nullptr
- ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader_handle, mUnit) : nullptr;
+ ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit) : nullptr;
}
bool can_link = false;
if (resolved_field != nullptr && referrer_class != nullptr) {
@@ -1542,7 +1543,7 @@ class ParallelCompilationManager {
// A fast version of SkipClass above if the class pointer is available
// that avoids the expensive FindInClassPath search.
-static bool SkipClass(jobject class_loader, const DexFile& dex_file, mirror::Class* klass)
+static bool SkipClass(jobject class_loader, const DexFile& dex_file, ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(klass != nullptr);
const DexFile& original_dex_file = *klass->GetDexCache()->GetDexFile();
@@ -1610,7 +1611,7 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor {
: manager_(manager) {}
void Visit(size_t class_def_index) OVERRIDE REQUIRES(!Locks::mutator_lock_) {
- ATRACE_CALL();
+ ScopedTrace trace(__FUNCTION__);
Thread* const self = Thread::Current();
jobject jclass_loader = manager_->GetClassLoader();
const DexFile& dex_file = *manager_->GetDexFile();
@@ -1636,8 +1637,8 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor {
Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(
soa.Self(), dex_file)));
// Resolve the class.
- mirror::Class* klass = class_linker->ResolveType(dex_file, class_def.class_idx_, dex_cache,
- class_loader);
+ ObjPtr<mirror::Class> klass =
+ class_linker->ResolveType(class_def.class_idx_, dex_cache, class_loader);
bool resolve_fields_and_methods;
if (klass == nullptr) {
// Class couldn't be resolved, for example, super-class is in a different dex file. Don't
@@ -1663,8 +1664,8 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor {
ClassDataItemIterator it(dex_file, class_data);
while (it.HasNextStaticField()) {
if (resolve_fields_and_methods) {
- ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
- dex_cache, class_loader, true);
+ ArtField* field = class_linker->ResolveField(
+ it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true);
if (field == nullptr) {
CheckAndClearResolveException(soa.Self());
}
@@ -1678,8 +1679,8 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor {
requires_constructor_barrier = true;
}
if (resolve_fields_and_methods) {
- ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
- dex_cache, class_loader, false);
+ ArtField* field = class_linker->ResolveField(
+ it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ false);
if (field == nullptr) {
CheckAndClearResolveException(soa.Self());
}
@@ -1689,7 +1690,10 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor {
if (resolve_fields_and_methods) {
while (it.HasNextMethod()) {
ArtMethod* method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- dex_file, it.GetMemberIndex(), dex_cache, class_loader, nullptr,
+ it.GetMemberIndex(),
+ dex_cache,
+ class_loader,
+ /* referrer */ nullptr,
it.GetMethodInvokeType(class_def));
if (method == nullptr) {
CheckAndClearResolveException(soa.Self());
@@ -1725,7 +1729,7 @@ class ResolveTypeVisitor : public CompilationVisitor {
dex_file,
class_loader.Get())));
ObjPtr<mirror::Class> klass = (dex_cache != nullptr)
- ? class_linker->ResolveType(dex_file, dex::TypeIndex(type_idx), dex_cache, class_loader)
+ ? class_linker->ResolveType(dex::TypeIndex(type_idx), dex_cache, class_loader)
: nullptr;
if (klass == nullptr) {
@@ -1805,7 +1809,7 @@ static void PopulateVerifiedMethods(const DexFile& dex_file,
static void LoadAndUpdateStatus(const DexFile& dex_file,
const DexFile::ClassDef& class_def,
- mirror::Class::Status status,
+ ClassStatus status,
Handle<mirror::ClassLoader> class_loader,
Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1864,16 +1868,16 @@ bool CompilerDriver::FastVerify(jobject jclass_loader,
// Just update the compiled_classes_ map. The compiler doesn't need to resolve
// the type.
ClassReference ref(dex_file, i);
- mirror::Class::Status existing = mirror::Class::kStatusNotReady;
+ ClassStatus existing = ClassStatus::kNotReady;
DCHECK(compiled_classes_.Get(ref, &existing)) << ref.dex_file->GetLocation();
ClassStateTable::InsertResult result =
- compiled_classes_.Insert(ref, existing, mirror::Class::kStatusVerified);
+ compiled_classes_.Insert(ref, existing, ClassStatus::kVerified);
CHECK_EQ(result, ClassStateTable::kInsertResultSuccess);
} else {
// Update the class status, so later compilation stages know they don't need to verify
// the class.
LoadAndUpdateStatus(
- *dex_file, class_def, mirror::Class::kStatusVerified, class_loader, soa.Self());
+ *dex_file, class_def, ClassStatus::kVerified, class_loader, soa.Self());
// Create `VerifiedMethod`s for each methods, the compiler expects one for
// quickening or compiling.
// Note that this means:
@@ -1887,7 +1891,7 @@ bool CompilerDriver::FastVerify(jobject jclass_loader,
// this class again.
LoadAndUpdateStatus(*dex_file,
class_def,
- mirror::Class::kStatusRetryVerificationAtRuntime,
+ ClassStatus::kRetryVerificationAtRuntime,
class_loader,
soa.Self());
}
@@ -1955,7 +1959,7 @@ class VerifyClassVisitor : public CompilationVisitor {
: manager_(manager), log_level_(log_level) {}
virtual void Visit(size_t class_def_index) REQUIRES(!Locks::mutator_lock_) OVERRIDE {
- ATRACE_CALL();
+ ScopedTrace trace(__FUNCTION__);
ScopedObjectAccess soa(Thread::Current());
const DexFile& dex_file = *manager_->GetDexFile();
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
@@ -2084,7 +2088,7 @@ class SetVerifiedClassVisitor : public CompilationVisitor {
explicit SetVerifiedClassVisitor(const ParallelCompilationManager* manager) : manager_(manager) {}
virtual void Visit(size_t class_def_index) REQUIRES(!Locks::mutator_lock_) OVERRIDE {
- ATRACE_CALL();
+ ScopedTrace trace(__FUNCTION__);
ScopedObjectAccess soa(Thread::Current());
const DexFile& dex_file = *manager_->GetDexFile();
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
@@ -2101,10 +2105,10 @@ class SetVerifiedClassVisitor : public CompilationVisitor {
// Only do this if the class is resolved. If even resolution fails, quickening will go very,
// very wrong.
if (klass->IsResolved() && !klass->IsErroneousResolved()) {
- if (klass->GetStatus() < mirror::Class::kStatusVerified) {
+ if (klass->GetStatus() < ClassStatus::kVerified) {
ObjectLock<mirror::Class> lock(soa.Self(), klass);
// Set class status to verified.
- mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, soa.Self());
+ mirror::Class::SetStatus(klass, ClassStatus::kVerified, soa.Self());
// Mark methods as pre-verified. If we don't do this, the interpreter will run with
// access checks.
klass->SetSkipAccessChecksFlagOnAllMethods(
@@ -2148,7 +2152,7 @@ class InitializeClassVisitor : public CompilationVisitor {
explicit InitializeClassVisitor(const ParallelCompilationManager* manager) : manager_(manager) {}
void Visit(size_t class_def_index) OVERRIDE {
- ATRACE_CALL();
+ ScopedTrace trace(__FUNCTION__);
jobject jclass_loader = manager_->GetClassLoader();
const DexFile& dex_file = *manager_->GetDexFile();
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
@@ -2181,7 +2185,7 @@ class InitializeClassVisitor : public CompilationVisitor {
const bool is_boot_image = manager_->GetCompiler()->GetCompilerOptions().IsBootImage();
const bool is_app_image = manager_->GetCompiler()->GetCompilerOptions().IsAppImage();
- mirror::Class::Status old_status = klass->GetStatus();
+ ClassStatus old_status = klass->GetStatus();
// Don't initialize classes in boot space when compiling app image
if (is_app_image && klass->IsBootStrapClassLoaded()) {
// Also return early and don't store the class status in the recorded class status.
@@ -2306,7 +2310,7 @@ class InitializeClassVisitor : public CompilationVisitor {
// would do so they can be skipped at runtime.
if (!klass->IsInitialized() &&
manager_->GetClassLinker()->ValidateSuperClassDescriptors(klass)) {
- old_status = mirror::Class::kStatusSuperclassValidated;
+ old_status = ClassStatus::kSuperclassValidated;
} else {
soa.Self()->ClearException();
}
@@ -2328,22 +2332,20 @@ class InitializeClassVisitor : public CompilationVisitor {
DCHECK(!klass->IsInitialized());
StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::DexCache> h_dex_cache = hs.NewHandle(klass->GetDexCache());
- const DexFile* dex_file = manager_->GetDexFile();
+ Handle<mirror::DexCache> dex_cache = hs.NewHandle(klass->GetDexCache());
const DexFile::ClassDef* class_def = klass->GetClassDef();
ClassLinker* class_linker = manager_->GetClassLinker();
// Check encoded final field values for strings and intern.
- annotations::RuntimeEncodedStaticFieldValueIterator value_it(*dex_file,
- &h_dex_cache,
- &class_loader,
+ annotations::RuntimeEncodedStaticFieldValueIterator value_it(dex_cache,
+ class_loader,
manager_->GetClassLinker(),
*class_def);
for ( ; value_it.HasNext(); value_it.Next()) {
if (value_it.GetValueType() == annotations::RuntimeEncodedStaticFieldValueIterator::kString) {
// Resolve the string. This will intern the string.
art::ObjPtr<mirror::String> resolved = class_linker->ResolveString(
- *dex_file, dex::StringIndex(value_it.GetJavaValue().i), h_dex_cache);
+ dex::StringIndex(value_it.GetJavaValue().i), dex_cache);
CHECK(resolved != nullptr);
}
}
@@ -2351,16 +2353,14 @@ class InitializeClassVisitor : public CompilationVisitor {
// Intern strings seen in <clinit>.
ArtMethod* clinit = klass->FindClassInitializer(class_linker->GetImagePointerSize());
if (clinit != nullptr) {
- const DexFile::CodeItem* code_item = clinit->GetCodeItem();
- DCHECK(code_item != nullptr);
- for (const DexInstructionPcPair& inst : code_item->Instructions()) {
+ for (const DexInstructionPcPair& inst : clinit->DexInstructions()) {
if (inst->Opcode() == Instruction::CONST_STRING) {
ObjPtr<mirror::String> s = class_linker->ResolveString(
- *dex_file, dex::StringIndex(inst->VRegB_21c()), h_dex_cache);
+ dex::StringIndex(inst->VRegB_21c()), dex_cache);
CHECK(s != nullptr);
} else if (inst->Opcode() == Instruction::CONST_STRING_JUMBO) {
ObjPtr<mirror::String> s = class_linker->ResolveString(
- *dex_file, dex::StringIndex(inst->VRegB_31c()), h_dex_cache);
+ dex::StringIndex(inst->VRegB_31c()), dex_cache);
CHECK(s != nullptr);
}
}
@@ -2664,7 +2664,7 @@ class CompileClassVisitor : public CompilationVisitor {
explicit CompileClassVisitor(const ParallelCompilationManager* manager) : manager_(manager) {}
virtual void Visit(size_t class_def_index) REQUIRES(!Locks::mutator_lock_) OVERRIDE {
- ATRACE_CALL();
+ ScopedTrace trace(__FUNCTION__);
const DexFile& dex_file = *manager_->GetDexFile();
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
ClassLinker* class_linker = manager_->GetClassLinker();
@@ -2771,36 +2771,36 @@ void CompilerDriver::AddCompiledMethod(const MethodReference& method_ref,
DCHECK(GetCompiledMethod(method_ref) != nullptr) << method_ref.PrettyMethod();
}
-bool CompilerDriver::GetCompiledClass(const ClassReference& ref,
- mirror::Class::Status* status) const {
+bool CompilerDriver::GetCompiledClass(const ClassReference& ref, ClassStatus* status) const {
DCHECK(status != nullptr);
// The table doesn't know if something wasn't inserted. For this case it will return
- // kStatusNotReady. To handle this, just assume anything we didn't try to verify is not compiled.
+ // ClassStatus::kNotReady. To handle this, just assume anything we didn't try to verify
+ // is not compiled.
if (!compiled_classes_.Get(ref, status) ||
- *status < mirror::Class::kStatusRetryVerificationAtRuntime) {
+ *status < ClassStatus::kRetryVerificationAtRuntime) {
return false;
}
return true;
}
-mirror::Class::Status CompilerDriver::GetClassStatus(const ClassReference& ref) const {
- mirror::Class::Status status = ClassStatus::kStatusNotReady;
+ClassStatus CompilerDriver::GetClassStatus(const ClassReference& ref) const {
+ ClassStatus status = ClassStatus::kNotReady;
if (!GetCompiledClass(ref, &status)) {
classpath_classes_.Get(ref, &status);
}
return status;
}
-void CompilerDriver::RecordClassStatus(const ClassReference& ref, mirror::Class::Status status) {
+void CompilerDriver::RecordClassStatus(const ClassReference& ref, ClassStatus status) {
switch (status) {
- case mirror::Class::kStatusErrorResolved:
- case mirror::Class::kStatusErrorUnresolved:
- case mirror::Class::kStatusNotReady:
- case mirror::Class::kStatusResolved:
- case mirror::Class::kStatusRetryVerificationAtRuntime:
- case mirror::Class::kStatusVerified:
- case mirror::Class::kStatusSuperclassValidated:
- case mirror::Class::kStatusInitialized:
+ case ClassStatus::kErrorResolved:
+ case ClassStatus::kErrorUnresolved:
+ case ClassStatus::kNotReady:
+ case ClassStatus::kResolved:
+ case ClassStatus::kRetryVerificationAtRuntime:
+ case ClassStatus::kVerified:
+ case ClassStatus::kSuperclassValidated:
+ case ClassStatus::kInitialized:
break; // Expected states.
default:
LOG(FATAL) << "Unexpected class status for class "
@@ -2812,7 +2812,7 @@ void CompilerDriver::RecordClassStatus(const ClassReference& ref, mirror::Class:
ClassStateTable::InsertResult result;
ClassStateTable* table = &compiled_classes_;
do {
- mirror::Class::Status existing = mirror::Class::kStatusNotReady;
+ ClassStatus existing = ClassStatus::kNotReady;
if (!table->Get(ref, &existing)) {
// A classpath class.
if (kIsDebugBuild) {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index d2141e8bc7..ef16212fb7 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -31,13 +31,13 @@
#include "base/mutex.h"
#include "base/timing_logger.h"
#include "class_reference.h"
+#include "class_status.h"
#include "compiler.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
#include "driver/compiled_method_storage.h"
#include "jit/profile_compilation_info.h"
#include "method_reference.h"
-#include "mirror/class.h" // For mirror::Class::Status.
#include "os.h"
#include "safe_map.h"
#include "thread_pool.h"
@@ -47,6 +47,7 @@
namespace art {
namespace mirror {
+class Class;
class DexCache;
} // namespace mirror
@@ -55,18 +56,21 @@ class MethodVerifier;
class VerifierDepsTest;
} // namespace verifier
+class ArtField;
class BitVector;
class CompiledMethod;
class CompilerOptions;
class DexCompilationUnit;
+template<class T> class Handle;
struct InlineIGetIPutData;
class InstructionSetFeatures;
class InternTable;
enum InvokeType : uint32_t;
+class MemberOffset;
+template<class MirrorType> class ObjPtr;
class ParallelCompilationManager;
class ScopedObjectAccess;
template <class Allocator> class SrcMap;
-template<class T> class Handle;
class TimingLogger;
class VdexFile;
class VerificationResults;
@@ -152,8 +156,8 @@ class CompilerDriver {
std::unique_ptr<const std::vector<uint8_t>> CreateQuickResolutionTrampoline() const;
std::unique_ptr<const std::vector<uint8_t>> CreateQuickToInterpreterBridge() const;
- mirror::Class::Status GetClassStatus(const ClassReference& ref) const;
- bool GetCompiledClass(const ClassReference& ref, mirror::Class::Status* status) const;
+ ClassStatus GetClassStatus(const ClassReference& ref) const;
+ bool GetCompiledClass(const ClassReference& ref, ClassStatus* status) const;
CompiledMethod* GetCompiledMethod(MethodReference ref) const;
size_t GetNonRelativeLinkerPatchCount() const;
@@ -219,36 +223,33 @@ class CompilerDriver {
REQUIRES_SHARED(Locks::mutator_lock_);
// Resolve compiling method's class. Returns null on failure.
- mirror::Class* ResolveCompilingMethodsClass(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit)
+ ObjPtr<mirror::Class> ResolveCompilingMethodsClass(const ScopedObjectAccess& soa,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ const DexCompilationUnit* mUnit)
REQUIRES_SHARED(Locks::mutator_lock_);
- mirror::Class* ResolveClass(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, dex::TypeIndex type_index,
- const DexCompilationUnit* mUnit)
+ ObjPtr<mirror::Class> ResolveClass(const ScopedObjectAccess& soa,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ dex::TypeIndex type_index,
+ const DexCompilationUnit* mUnit)
REQUIRES_SHARED(Locks::mutator_lock_);
// Resolve a field. Returns null on failure, including incompatible class change.
// NOTE: Unlike ClassLinker's ResolveField(), this method enforces is_static.
- ArtField* ResolveField(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
- uint32_t field_idx, bool is_static)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- // Resolve a field with a given dex file.
- ArtField* ResolveFieldWithDexFile(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file,
- uint32_t field_idx, bool is_static)
+ ArtField* ResolveField(const ScopedObjectAccess& soa,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ uint32_t field_idx,
+ bool is_static)
REQUIRES_SHARED(Locks::mutator_lock_);
// Can we fast-path an IGET/IPUT access to an instance field? If yes, compute the field offset.
- std::pair<bool, bool> IsFastInstanceField(
- mirror::DexCache* dex_cache, mirror::Class* referrer_class,
- ArtField* resolved_field, uint16_t field_idx)
+ std::pair<bool, bool> IsFastInstanceField(ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::Class> referrer_class,
+ ArtField* resolved_field,
+ uint16_t field_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
// Resolve a method. Returns null on failure, including incompatible class change.
@@ -270,9 +271,9 @@ class CompilerDriver {
REQUIRES(!Locks::mutator_lock_);
ArtField* ComputeInstanceFieldInfo(uint32_t field_idx,
- const DexCompilationUnit* mUnit,
- bool is_put,
- const ScopedObjectAccess& soa)
+ const DexCompilationUnit* mUnit,
+ bool is_put,
+ const ScopedObjectAccess& soa)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -324,7 +325,7 @@ class CompilerDriver {
// according to the profile file.
bool ShouldVerifyClassBasedOnProfile(const DexFile& dex_file, uint16_t class_idx) const;
- void RecordClassStatus(const ClassReference& ref, mirror::Class::Status status);
+ void RecordClassStatus(const ClassReference& ref, ClassStatus status);
// Checks if the specified method has been verified without failures. Returns
// false if the method is not in the verification results (GetVerificationResults).
@@ -479,7 +480,7 @@ class CompilerDriver {
GUARDED_BY(requires_constructor_barrier_lock_);
// All class references that this compiler has compiled. Indexed by class defs.
- using ClassStateTable = AtomicDexRefMap<ClassReference, mirror::Class::Status>;
+ using ClassStateTable = AtomicDexRefMap<ClassReference, ClassStatus>;
ClassStateTable compiled_classes_;
// All class references that are in the classpath. Indexed by class defs.
ClassStateTable classpath_classes_;
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 278358b250..162904c0e7 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -16,16 +16,18 @@
#include "driver/compiler_driver.h"
+#include <limits>
#include <stdint.h>
#include <stdio.h>
#include <memory>
#include "art_method-inl.h"
+#include "base/casts.h"
#include "class_linker-inl.h"
#include "common_compiler_test.h"
#include "compiler_callbacks.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
#include "gc/heap.h"
#include "handle_scope-inl.h"
#include "jit/profile_compilation_info.h"
@@ -344,11 +346,11 @@ class CompilerDriverVerifyTest : public CompilerDriverTest {
ASSERT_NE(klass, nullptr);
EXPECT_TRUE(klass->IsVerified());
- mirror::Class::Status status;
+ ClassStatus status;
bool found = compiler_driver_->GetCompiledClass(
ClassReference(&klass->GetDexFile(), klass->GetDexTypeIndex().index_), &status);
ASSERT_TRUE(found);
- EXPECT_EQ(status, mirror::Class::kStatusVerified);
+ EXPECT_EQ(status, ClassStatus::kVerified);
}
};
@@ -367,8 +369,8 @@ TEST_F(CompilerDriverVerifyTest, VerifyCompilation) {
CheckVerifiedClass(class_loader, "LSecond;");
}
-// Test that a class of status kStatusRetryVerificationAtRuntime is indeed recorded that way in the
-// driver.
+// Test that a class of status ClassStatus::kRetryVerificationAtRuntime is indeed
+// recorded that way in the driver.
TEST_F(CompilerDriverVerifyTest, RetryVerifcationStatusCheckVerified) {
Thread* const self = Thread::Current();
jobject class_loader;
@@ -386,17 +388,19 @@ TEST_F(CompilerDriverVerifyTest, RetryVerifcationStatusCheckVerified) {
callbacks_->SetDoesClassUnloading(true, compiler_driver_.get());
ClassReference ref(dex_file, 0u);
// Test that the status is read from the compiler driver as expected.
- for (size_t i = mirror::Class::kStatusRetryVerificationAtRuntime;
- i < mirror::Class::kStatusMax;
- ++i) {
- const mirror::Class::Status expected_status = static_cast<mirror::Class::Status>(i);
+ static_assert(enum_cast<size_t>(ClassStatus::kLast) < std::numeric_limits<size_t>::max(),
+ "Make sure incrementing the class status does not overflow.");
+ for (size_t i = enum_cast<size_t>(ClassStatus::kRetryVerificationAtRuntime);
+ i <= enum_cast<size_t>(ClassStatus::kLast);
+ ++i) {
+ const ClassStatus expected_status = enum_cast<ClassStatus>(i);
// Skip unsupported status that are not supposed to be ever recorded.
- if (expected_status == mirror::Class::kStatusVerifyingAtRuntime ||
- expected_status == mirror::Class::kStatusInitializing) {
+ if (expected_status == ClassStatus::kVerifyingAtRuntime ||
+ expected_status == ClassStatus::kInitializing) {
continue;
}
compiler_driver_->RecordClassStatus(ref, expected_status);
- mirror::Class::Status status = {};
+ ClassStatus status = {};
ASSERT_TRUE(compiler_driver_->GetCompiledClass(ref, &status));
EXPECT_EQ(status, expected_status);
}
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index c0a9a05aa6..1780b1d7ed 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -20,6 +20,7 @@
#include "android-base/stringprintf.h"
+#include "base/runtime_debug.h"
#include "base/variant_map.h"
#include "cmdline_parser.h"
#include "compiler_options_map-inl.h"
@@ -68,17 +69,16 @@ CompilerOptions::~CompilerOptions() {
// because we don't want to include the PassManagerOptions definition from the header file.
}
+namespace {
+
+bool kEmitRuntimeReadBarrierChecks = kIsDebugBuild &&
+ RegisterRuntimeDebugFlag(&kEmitRuntimeReadBarrierChecks);
+
+} // namespace
+
bool CompilerOptions::EmitRunTimeChecksInDebugMode() const {
- // Run-time checks (e.g. Marking Register checks) are only emitted
- // in debug mode, and
- // - when running on device; or
- // - when running on host, but only
- // - when compiling the core image (which is used only for testing); or
- // - when JIT compiling (only relevant for non-native methods).
- // This is to prevent these checks from being emitted into pre-opted
- // boot image or apps, as these are compiled with dex2oatd.
- return kIsDebugBuild &&
- (kIsTargetBuild || IsCoreImage() || Runtime::Current()->UseJitCompilation());
+ // Run-time checks (e.g. Marking Register checks) are only emitted in slow-debug mode.
+ return kEmitRuntimeReadBarrierChecks;
}
bool CompilerOptions::ParseDumpInitFailures(const std::string& option, std::string* error_msg) {
diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc
index 7e8e812c4a..1fe30de355 100644
--- a/compiler/driver/dex_compilation_unit.cc
+++ b/compiler/driver/dex_compilation_unit.cc
@@ -16,6 +16,7 @@
#include "dex_compilation_unit.h"
+#include "dex/code_item_accessors-inl.h"
#include "mirror/dex_cache.h"
#include "utils.h"
@@ -38,7 +39,8 @@ DexCompilationUnit::DexCompilationUnit(Handle<mirror::ClassLoader> class_loader,
dex_method_idx_(method_idx),
access_flags_(access_flags),
verified_method_(verified_method),
- dex_cache_(dex_cache) {
+ dex_cache_(dex_cache),
+ code_item_accessor_(&dex_file, code_item) {
}
const std::string& DexCompilationUnit::GetSymbol() {
diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h
index 24a9a5b653..c1ae3c938b 100644
--- a/compiler/driver/dex_compilation_unit.h
+++ b/compiler/driver/dex_compilation_unit.h
@@ -20,7 +20,8 @@
#include <stdint.h>
#include "base/arena_object.h"
-#include "dex_file.h"
+#include "dex/code_item_accessors.h"
+#include "dex/dex_file.h"
#include "handle.h"
#include "jni.h"
@@ -112,6 +113,10 @@ class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> {
return dex_cache_;
}
+ const CodeItemDataAccessor& GetCodeItemAccessor() const {
+ return code_item_accessor_;
+ }
+
private:
const Handle<mirror::ClassLoader> class_loader_;
@@ -127,6 +132,8 @@ class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> {
const Handle<mirror::DexCache> dex_cache_;
+ const CodeItemDataAccessor code_item_accessor_;
+
std::string symbol_;
};
diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc
index 897b50bdac..8f7ab05791 100644
--- a/compiler/exception_test.cc
+++ b/compiler/exception_test.cc
@@ -21,8 +21,10 @@
#include "base/enums.h"
#include "class_linker.h"
#include "common_runtime_test.h"
-#include "dex_file-inl.h"
-#include "dex_file.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_exception_helpers.h"
#include "gtest/gtest.h"
#include "handle_scope-inl.h"
#include "leb128.h"
@@ -128,19 +130,18 @@ class ExceptionTest : public CommonRuntimeTest {
TEST_F(ExceptionTest, FindCatchHandler) {
ScopedObjectAccess soa(Thread::Current());
- const DexFile::CodeItem* code_item = dex_->GetCodeItem(method_f_->GetCodeItemOffset());
+ CodeItemDataAccessor accessor(dex_, dex_->GetCodeItem(method_f_->GetCodeItemOffset()));
- ASSERT_TRUE(code_item != nullptr);
+ ASSERT_TRUE(accessor.HasCodeItem());
- ASSERT_EQ(2u, code_item->tries_size_);
- ASSERT_NE(0u, code_item->insns_size_in_code_units_);
+ ASSERT_EQ(2u, accessor.TriesSize());
+ ASSERT_NE(0u, accessor.InsnsSizeInCodeUnits());
- const DexFile::TryItem *t0, *t1;
- t0 = dex_->GetTryItems(*code_item, 0);
- t1 = dex_->GetTryItems(*code_item, 1);
- EXPECT_LE(t0->start_addr_, t1->start_addr_);
+ const DexFile::TryItem& t0 = accessor.TryItems().begin()[0];
+ const DexFile::TryItem& t1 = accessor.TryItems().begin()[1];
+ EXPECT_LE(t0.start_addr_, t1.start_addr_);
{
- CatchHandlerIterator iter(*code_item, 4 /* Dex PC in the first try block */);
+ CatchHandlerIterator iter(accessor, 4 /* Dex PC in the first try block */);
EXPECT_STREQ("Ljava/io/IOException;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex()));
ASSERT_TRUE(iter.HasNext());
iter.Next();
@@ -150,14 +151,14 @@ TEST_F(ExceptionTest, FindCatchHandler) {
EXPECT_FALSE(iter.HasNext());
}
{
- CatchHandlerIterator iter(*code_item, 8 /* Dex PC in the second try block */);
+ CatchHandlerIterator iter(accessor, 8 /* Dex PC in the second try block */);
EXPECT_STREQ("Ljava/io/IOException;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex()));
ASSERT_TRUE(iter.HasNext());
iter.Next();
EXPECT_FALSE(iter.HasNext());
}
{
- CatchHandlerIterator iter(*code_item, 11 /* Dex PC not in any try block */);
+ CatchHandlerIterator iter(accessor, 11 /* Dex PC not in any try block */);
EXPECT_FALSE(iter.HasNext());
}
}
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index f33c5e1b97..88e3e5b230 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -21,7 +21,9 @@
#include "arch/instruction_set.h"
#include "arch/instruction_set_features.h"
#include "art_method-inl.h"
+#include "base/logging.h" // For VLOG
#include "base/stringpiece.h"
+#include "base/systrace.h"
#include "base/time_utils.h"
#include "base/timing_logger.h"
#include "base/unix_file/fd_file.h"
@@ -162,6 +164,8 @@ JitCompiler::~JitCompiler() {
}
bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method, bool osr) {
+ SCOPED_TRACE << "JIT compiling " << method->PrettyMethod();
+
DCHECK(!method->IsProxyMethod());
DCHECK(method->GetDeclaringClass()->IsResolved());
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index daf64d1298..f34e9b844b 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -24,7 +24,7 @@
#include "class_linker.h"
#include "common_compiler_test.h"
#include "compiler.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "gtest/gtest.h"
#include "indirect_reference_table.h"
#include "java_vm_ext.h"
@@ -299,7 +299,6 @@ class JniCompilerTest : public CommonCompilerTest {
}
// JNI operations after runtime start.
env_ = Thread::Current()->GetJniEnv();
- library_search_path_ = env_->NewStringUTF("");
jklass_ = env_->FindClass("MyClassNatives");
ASSERT_TRUE(jklass_ != nullptr) << method_name << " " << method_sig;
@@ -380,7 +379,6 @@ class JniCompilerTest : public CommonCompilerTest {
void CriticalNativeImpl();
JNIEnv* env_;
- jstring library_search_path_;
jmethodID jmethod_;
private:
@@ -660,7 +658,7 @@ void JniCompilerTest::CompileAndRunIntMethodThroughStubImpl() {
std::string reason;
ASSERT_TRUE(Runtime::Current()->GetJavaVM()->
- LoadNativeLibrary(env_, "", class_loader_, library_search_path_, &reason))
+ LoadNativeLibrary(env_, "", class_loader_, &reason))
<< reason;
jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 24);
@@ -676,7 +674,7 @@ void JniCompilerTest::CompileAndRunStaticIntMethodThroughStubImpl() {
std::string reason;
ASSERT_TRUE(Runtime::Current()->GetJavaVM()->
- LoadNativeLibrary(env_, "", class_loader_, library_search_path_, &reason))
+ LoadNativeLibrary(env_, "", class_loader_, &reason))
<< reason;
jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 42);
diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc
index 3e637bcf43..54f193b551 100644
--- a/compiler/jni/quick/arm/calling_convention_arm.cc
+++ b/compiler/jni/quick/arm/calling_convention_arm.cc
@@ -16,7 +16,9 @@
#include "calling_convention_arm.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/macros.h"
#include "handle_scope-inl.h"
#include "utils/arm/managed_register_arm.h"
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index 3afd7011ca..328ecbbc5c 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -16,7 +16,8 @@
#include "calling_convention_arm64.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "handle_scope-inl.h"
#include "utils/arm64/managed_register_arm64.h"
diff --git a/compiler/jni/quick/calling_convention.cc b/compiler/jni/quick/calling_convention.cc
index 55c27d1a6a..ff814c8a6b 100644
--- a/compiler/jni/quick/calling_convention.cc
+++ b/compiler/jni/quick/calling_convention.cc
@@ -16,7 +16,7 @@
#include "calling_convention.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
#ifdef ART_ENABLE_CODEGEN_arm
#include "jni/quick/arm/calling_convention_arm.h"
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 37f7d632ca..fc44927231 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -25,12 +25,12 @@
#include "art_method.h"
#include "base/arena_allocator.h"
#include "base/enums.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "calling_convention.h"
#include "class_linker.h"
#include "debug/dwarf/debug_frame_opcode_writer.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
#include "entrypoints/quick/quick_entrypoints.h"
diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc
index 0e0716e911..5ec1addcb9 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.cc
+++ b/compiler/jni/quick/mips/calling_convention_mips.cc
@@ -16,7 +16,8 @@
#include "calling_convention_mips.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "handle_scope-inl.h"
#include "utils/mips/managed_register_mips.h"
diff --git a/compiler/jni/quick/mips64/calling_convention_mips64.cc b/compiler/jni/quick/mips64/calling_convention_mips64.cc
index afe6a762eb..a7012aefa8 100644
--- a/compiler/jni/quick/mips64/calling_convention_mips64.cc
+++ b/compiler/jni/quick/mips64/calling_convention_mips64.cc
@@ -16,7 +16,8 @@
#include "calling_convention_mips64.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "handle_scope-inl.h"
#include "utils/mips64/managed_register_mips64.h"
diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc
index 0bfcc3fb4d..ad58e3820d 100644
--- a/compiler/jni/quick/x86/calling_convention_x86.cc
+++ b/compiler/jni/quick/x86/calling_convention_x86.cc
@@ -16,7 +16,8 @@
#include "calling_convention_x86.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "handle_scope-inl.h"
#include "utils/x86/managed_register_x86.h"
diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
index ba654f4750..e5e96d01fc 100644
--- a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
+++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
@@ -16,8 +16,9 @@
#include "calling_convention_x86_64.h"
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
#include "handle_scope-inl.h"
#include "utils/x86_64/managed_register_x86_64.h"
diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc
index 2cb23d1710..cedbe5d97f 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.cc
+++ b/compiler/linker/arm/relative_patcher_arm_base.cc
@@ -19,7 +19,7 @@
#include "base/stl_util.h"
#include "compiled_method-inl.h"
#include "debug/method_debug_info.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "linker/linker_patch.h"
#include "linker/output_stream.h"
#include "oat.h"
diff --git a/compiler/linker/arm/relative_patcher_thumb2.cc b/compiler/linker/arm/relative_patcher_thumb2.cc
index 48747fc379..78755176e4 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2.cc
@@ -16,6 +16,8 @@
#include "linker/arm/relative_patcher_thumb2.h"
+#include <sstream>
+
#include "arch/arm/asm_support_arm.h"
#include "art_method.h"
#include "base/bit_utils.h"
diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h
index b30b55e9b4..aa3cd98595 100644
--- a/compiler/linker/elf_builder.h
+++ b/compiler/linker/elf_builder.h
@@ -108,8 +108,6 @@ class ElfBuilder FINAL {
section_index_(0),
name_(name),
link_(link),
- started_(false),
- finished_(false),
phdr_flags_(PF_R),
phdr_type_(0) {
DCHECK_GE(align, 1u);
@@ -120,90 +118,62 @@ class ElfBuilder FINAL {
header_.sh_entsize = entsize;
}
- // Start writing of this section.
- void Start() {
- CHECK(!started_);
- CHECK(!finished_);
- started_ = true;
- auto& sections = owner_->sections_;
- // Check that the previous section is complete.
- CHECK(sections.empty() || sections.back()->finished_);
- // The first ELF section index is 1. Index 0 is reserved for NULL.
- section_index_ = sections.size() + 1;
- // Page-align if we switch between allocated and non-allocated sections,
- // or if we change the type of allocation (e.g. executable vs non-executable).
- if (!sections.empty()) {
- if (header_.sh_flags != sections.back()->header_.sh_flags) {
- header_.sh_addralign = kPageSize;
- }
- }
- // Align file position.
- if (header_.sh_type != SHT_NOBITS) {
- header_.sh_offset = owner_->AlignFileOffset(header_.sh_addralign);
- } else {
- header_.sh_offset = 0;
- }
- // Align virtual memory address.
- if ((header_.sh_flags & SHF_ALLOC) != 0) {
- header_.sh_addr = owner_->AlignVirtualAddress(header_.sh_addralign);
- } else {
- header_.sh_addr = 0;
- }
- // Push this section on the list of written sections.
- sections.push_back(this);
+ // Allocate chunk of virtual memory for this section from the owning ElfBuilder.
+ // This must be done at the start for all SHF_ALLOC sections (i.e. mmaped by linker).
+ // It is fine to allocate section but never call Start/End() (e.g. the .bss section).
+ void AllocateVirtualMemory(Elf_Word size) {
+ AllocateVirtualMemory(owner_->virtual_address_, size);
}
- // Finish writing of this section.
- void End() {
- CHECK(started_);
- CHECK(!finished_);
- finished_ = true;
- if (header_.sh_type == SHT_NOBITS) {
- CHECK_GT(header_.sh_size, 0u);
- } else {
- // Use the current file position to determine section size.
- off_t file_offset = owner_->stream_.Seek(0, kSeekCurrent);
- CHECK_GE(file_offset, (off_t)header_.sh_offset);
- header_.sh_size = file_offset - header_.sh_offset;
- }
- if ((header_.sh_flags & SHF_ALLOC) != 0) {
- owner_->virtual_address_ += header_.sh_size;
- }
+ void AllocateVirtualMemory(Elf_Addr addr, Elf_Word size) {
+ CHECK_NE(header_.sh_flags & SHF_ALLOC, 0u);
+ Elf_Word align = AddSection();
+ CHECK_EQ(header_.sh_addr, 0u);
+ header_.sh_addr = RoundUp(addr, align);
+ CHECK(header_.sh_size == 0u || header_.sh_size == size);
+ header_.sh_size = size;
+ CHECK_LE(owner_->virtual_address_, header_.sh_addr);
+ owner_->virtual_address_ = header_.sh_addr + header_.sh_size;
}
- // Get the location of this section in virtual memory.
- Elf_Addr GetAddress() const {
- CHECK(started_);
- return header_.sh_addr;
+ // Start writing file data of this section.
+ void Start() {
+ CHECK(owner_->current_section_ == nullptr);
+ Elf_Word align = AddSection();
+ CHECK_EQ(header_.sh_offset, 0u);
+ header_.sh_offset = owner_->AlignFileOffset(align);
+ owner_->current_section_ = this;
}
- // Returns the size of the content of this section.
- Elf_Word GetSize() const {
- if (finished_) {
- return header_.sh_size;
- } else {
- CHECK(started_);
- CHECK_NE(header_.sh_type, (Elf_Word)SHT_NOBITS);
- return owner_->stream_.Seek(0, kSeekCurrent) - header_.sh_offset;
- }
+ // Finish writing file data of this section.
+ void End() {
+ CHECK(owner_->current_section_ == this);
+ Elf_Word position = GetPosition();
+ CHECK(header_.sh_size == 0u || header_.sh_size == position);
+ header_.sh_size = position;
+ owner_->current_section_ = nullptr;
+ }
+
+ // Get the number of bytes written so far.
+ // Only valid while writing the section.
+ Elf_Word GetPosition() const {
+ CHECK(owner_->current_section_ == this);
+ off_t file_offset = owner_->stream_.Seek(0, kSeekCurrent);
+ DCHECK_GE(file_offset, (off_t)header_.sh_offset);
+ return file_offset - header_.sh_offset;
}
- // Write this section as "NOBITS" section. (used for the .bss section)
- // This means that the ELF file does not contain the initial data for this section
- // and it will be zero-initialized when the ELF file is loaded in the running program.
- void WriteNoBitsSection(Elf_Word size) {
+ // Get the location of this section in virtual memory.
+ Elf_Addr GetAddress() const {
DCHECK_NE(header_.sh_flags & SHF_ALLOC, 0u);
- header_.sh_type = SHT_NOBITS;
- Start();
- header_.sh_size = size;
- End();
+ DCHECK_NE(header_.sh_addr, 0u);
+ return header_.sh_addr;
}
// This function always succeeds to simplify code.
// Use builder's Good() to check the actual status.
bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
- CHECK(started_);
- CHECK(!finished_);
+ CHECK(owner_->current_section_ == this);
return owner_->stream_.WriteFully(buffer, byte_count);
}
@@ -221,19 +191,32 @@ class ElfBuilder FINAL {
}
Elf_Word GetSectionIndex() const {
- DCHECK(started_);
DCHECK_NE(section_index_, 0u);
return section_index_;
}
private:
+ // Add this section to the list of generated ELF sections (if not there already).
+ // It also ensures the alignment is sufficient to generate valid program headers,
+ // since that depends on the previous section. It returns the required alignment.
+ Elf_Word AddSection() {
+ if (section_index_ == 0) {
+ std::vector<Section*>& sections = owner_->sections_;
+ Elf_Word last = sections.empty() ? PF_R : sections.back()->phdr_flags_;
+ if (phdr_flags_ != last) {
+ header_.sh_addralign = kPageSize; // Page-align if R/W/X flags changed.
+ }
+ sections.push_back(this);
+ section_index_ = sections.size(); // First ELF section has index 1.
+ }
+ return owner_->write_program_headers_ ? header_.sh_addralign : 1;
+ }
+
ElfBuilder<ElfTypes>* owner_;
Elf_Shdr header_;
Elf_Word section_index_;
const std::string name_;
const Section* const link_;
- bool started_;
- bool finished_;
Elf_Word phdr_flags_;
Elf_Word phdr_type_;
@@ -370,7 +353,7 @@ class ElfBuilder FINAL {
Elf_Word section_index;
if (section != nullptr) {
DCHECK_LE(section->GetAddress(), addr);
- DCHECK_LE(addr, section->GetAddress() + section->GetSize());
+ DCHECK_LE(addr, section->GetAddress() + section->header_.sh_size);
section_index = section->GetSectionIndex();
} else {
section_index = static_cast<Elf_Word>(SHN_ABS);
@@ -479,6 +462,10 @@ class ElfBuilder FINAL {
digest_start_(-1) {
}
+ Elf_Word GetSize() {
+ return 16 + kBuildIdLen;
+ }
+
void Write() {
// The size fields are 32-bit on both 32-bit and 64-bit systems, confirmed
// with the 64-bit linker and libbfd code. The size of name and desc must
@@ -490,6 +477,7 @@ class ElfBuilder FINAL {
digest_start_ = this->Seek(0, kSeekCurrent);
static_assert(kBuildIdLen % 4 == 0, "expecting a mutliple of 4 for build ID length");
this->WriteFully(std::string(kBuildIdLen, '\0').c_str(), kBuildIdLen); // desc.
+ DCHECK_EQ(this->GetPosition(), GetSize());
}
off_t GetDigestStart() {
@@ -530,6 +518,7 @@ class ElfBuilder FINAL {
abiflags_(this, ".MIPS.abiflags", SHT_MIPS_ABIFLAGS, SHF_ALLOC, nullptr, 0, kPageSize, 0,
isa, features),
build_id_(this, ".note.gnu.build-id", SHT_NOTE, SHF_ALLOC, nullptr, 0, 4, 0),
+ current_section_(nullptr),
started_(false),
write_program_headers_(false),
loaded_size_(0u),
@@ -545,6 +534,7 @@ class ElfBuilder FINAL {
~ElfBuilder() {}
InstructionSet GetIsa() { return isa_; }
+ BuildIdSection* GetBuildId() { return &build_id_; }
Section* GetRoData() { return &rodata_; }
Section* GetText() { return &text_; }
Section* GetBss() { return &bss_; }
@@ -622,6 +612,9 @@ class ElfBuilder FINAL {
if (section->link_ != nullptr) {
section->header_.sh_link = section->link_->GetSectionIndex();
}
+ if (section->header_.sh_offset == 0) {
+ section->header_.sh_type = SHT_NOBITS;
+ }
}
shstrtab_.End();
@@ -680,65 +673,57 @@ class ElfBuilder FINAL {
soname = soname.substr(directory_separator_pos + 1);
}
- // Calculate addresses of .text, .bss and .dynstr.
- DCHECK_EQ(rodata_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
- DCHECK_EQ(text_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
- DCHECK_EQ(bss_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
- DCHECK_EQ(dynstr_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
- Elf_Word rodata_address = rodata_.GetAddress();
- Elf_Word text_address = RoundUp(rodata_address + rodata_size, kPageSize);
- Elf_Word bss_address = RoundUp(text_address + text_size, kPageSize);
- Elf_Word abiflags_address = RoundUp(bss_address + bss_size, kPageSize);
- Elf_Word abiflags_size = 0;
+ // Allocate all pre-dynamic sections.
+ rodata_.AllocateVirtualMemory(rodata_size);
+ text_.AllocateVirtualMemory(text_size);
+ if (bss_size != 0) {
+ bss_.AllocateVirtualMemory(bss_size);
+ }
if (isa_ == InstructionSet::kMips || isa_ == InstructionSet::kMips64) {
- abiflags_size = abiflags_.GetSize();
+ abiflags_.AllocateVirtualMemory(abiflags_.GetSize());
}
- Elf_Word dynstr_address = RoundUp(abiflags_address + abiflags_size, kPageSize);
// Cache .dynstr, .dynsym and .hash data.
dynstr_.Add(""); // dynstr should start with empty string.
- Elf_Word rodata_index = rodata_.GetSectionIndex();
Elf_Word oatdata = dynstr_.Add("oatdata");
- dynsym_.Add(oatdata, rodata_index, rodata_address, rodata_size, STB_GLOBAL, STT_OBJECT);
+ dynsym_.Add(oatdata, &rodata_, rodata_.GetAddress(), rodata_size, STB_GLOBAL, STT_OBJECT);
if (text_size != 0u) {
- Elf_Word text_index = rodata_index + 1u;
Elf_Word oatexec = dynstr_.Add("oatexec");
- dynsym_.Add(oatexec, text_index, text_address, text_size, STB_GLOBAL, STT_OBJECT);
+ dynsym_.Add(oatexec, &text_, text_.GetAddress(), text_size, STB_GLOBAL, STT_OBJECT);
Elf_Word oatlastword = dynstr_.Add("oatlastword");
- Elf_Word oatlastword_address = text_address + text_size - 4;
- dynsym_.Add(oatlastword, text_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
+ Elf_Word oatlastword_address = text_.GetAddress() + text_size - 4;
+ dynsym_.Add(oatlastword, &text_, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
} else if (rodata_size != 0) {
// rodata_ can be size 0 for dwarf_test.
Elf_Word oatlastword = dynstr_.Add("oatlastword");
- Elf_Word oatlastword_address = rodata_address + rodata_size - 4;
- dynsym_.Add(oatlastword, rodata_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
+ Elf_Word oatlastword_address = rodata_.GetAddress() + rodata_size - 4;
+ dynsym_.Add(oatlastword, &rodata_, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
}
DCHECK_LE(bss_roots_offset, bss_size);
if (bss_size != 0u) {
- Elf_Word bss_index = rodata_index + 1u + (text_size != 0 ? 1u : 0u);
Elf_Word oatbss = dynstr_.Add("oatbss");
- dynsym_.Add(oatbss, bss_index, bss_address, bss_roots_offset, STB_GLOBAL, STT_OBJECT);
+ dynsym_.Add(oatbss, &bss_, bss_.GetAddress(), bss_roots_offset, STB_GLOBAL, STT_OBJECT);
DCHECK_LE(bss_methods_offset, bss_roots_offset);
DCHECK_LE(bss_roots_offset, bss_size);
// Add a symbol marking the start of the methods part of the .bss, if not empty.
if (bss_methods_offset != bss_roots_offset) {
- Elf_Word bss_methods_address = bss_address + bss_methods_offset;
+ Elf_Word bss_methods_address = bss_.GetAddress() + bss_methods_offset;
Elf_Word bss_methods_size = bss_roots_offset - bss_methods_offset;
Elf_Word oatbssroots = dynstr_.Add("oatbssmethods");
dynsym_.Add(
- oatbssroots, bss_index, bss_methods_address, bss_methods_size, STB_GLOBAL, STT_OBJECT);
+ oatbssroots, &bss_, bss_methods_address, bss_methods_size, STB_GLOBAL, STT_OBJECT);
}
// Add a symbol marking the start of the GC roots part of the .bss, if not empty.
if (bss_roots_offset != bss_size) {
- Elf_Word bss_roots_address = bss_address + bss_roots_offset;
+ Elf_Word bss_roots_address = bss_.GetAddress() + bss_roots_offset;
Elf_Word bss_roots_size = bss_size - bss_roots_offset;
Elf_Word oatbssroots = dynstr_.Add("oatbssroots");
dynsym_.Add(
- oatbssroots, bss_index, bss_roots_address, bss_roots_size, STB_GLOBAL, STT_OBJECT);
+ oatbssroots, &bss_, bss_roots_address, bss_roots_size, STB_GLOBAL, STT_OBJECT);
}
Elf_Word oatbsslastword = dynstr_.Add("oatbsslastword");
- Elf_Word bsslastword_address = bss_address + bss_size - 4;
- dynsym_.Add(oatbsslastword, bss_index, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT);
+ Elf_Word bsslastword_address = bss_.GetAddress() + bss_size - 4;
+ dynsym_.Add(oatbsslastword, &bss_, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT);
}
Elf_Word soname_offset = dynstr_.Add(soname);
@@ -759,28 +744,24 @@ class ElfBuilder FINAL {
hash.push_back(0); // Last symbol terminates the chain.
hash_.Add(hash.data(), hash.size() * sizeof(hash[0]));
- // Calculate addresses of .dynsym, .hash and .dynamic.
- DCHECK_EQ(dynstr_.header_.sh_flags, dynsym_.header_.sh_flags);
- DCHECK_EQ(dynsym_.header_.sh_flags, hash_.header_.sh_flags);
- Elf_Word dynsym_address =
- RoundUp(dynstr_address + dynstr_.GetCacheSize(), dynsym_.header_.sh_addralign);
- Elf_Word hash_address =
- RoundUp(dynsym_address + dynsym_.GetCacheSize(), hash_.header_.sh_addralign);
- DCHECK_EQ(dynamic_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
- Elf_Word dynamic_address = RoundUp(hash_address + dynsym_.GetCacheSize(), kPageSize);
+ // Allocate all remaining sections.
+ dynstr_.AllocateVirtualMemory(dynstr_.GetCacheSize());
+ dynsym_.AllocateVirtualMemory(dynsym_.GetCacheSize());
+ hash_.AllocateVirtualMemory(hash_.GetCacheSize());
Elf_Dyn dyns[] = {
- { DT_HASH, { hash_address } },
- { DT_STRTAB, { dynstr_address } },
- { DT_SYMTAB, { dynsym_address } },
+ { DT_HASH, { hash_.GetAddress() } },
+ { DT_STRTAB, { dynstr_.GetAddress() } },
+ { DT_SYMTAB, { dynsym_.GetAddress() } },
{ DT_SYMENT, { sizeof(Elf_Sym) } },
{ DT_STRSZ, { dynstr_.GetCacheSize() } },
{ DT_SONAME, { soname_offset } },
{ DT_NULL, { 0 } },
};
dynamic_.Add(&dyns, sizeof(dyns));
+ dynamic_.AllocateVirtualMemory(dynamic_.GetCacheSize());
- loaded_size_ = RoundUp(dynamic_address + dynamic_.GetCacheSize(), kPageSize);
+ loaded_size_ = RoundUp(virtual_address_, kPageSize);
}
void WriteDynamicSection() {
@@ -788,8 +769,6 @@ class ElfBuilder FINAL {
dynsym_.WriteCachedSection();
hash_.WriteCachedSection();
dynamic_.WriteCachedSection();
-
- CHECK_EQ(loaded_size_, RoundUp(dynamic_.GetAddress() + dynamic_.GetSize(), kPageSize));
}
Elf_Word GetLoadedSize() {
@@ -828,10 +807,6 @@ class ElfBuilder FINAL {
return stream_.Seek(RoundUp(stream_.Seek(0, kSeekCurrent), alignment), kSeekSet);
}
- Elf_Addr AlignVirtualAddress(size_t alignment) {
- return virtual_address_ = RoundUp(virtual_address_, alignment);
- }
-
private:
static Elf_Ehdr MakeElfHeader(InstructionSet isa, const InstructionSetFeatures* features) {
Elf_Ehdr elf_header = Elf_Ehdr();
@@ -902,7 +877,6 @@ class ElfBuilder FINAL {
elf_header.e_ehsize = sizeof(Elf_Ehdr);
elf_header.e_phentsize = sizeof(Elf_Phdr);
elf_header.e_shentsize = sizeof(Elf_Shdr);
- elf_header.e_phoff = sizeof(Elf_Ehdr);
return elf_header;
}
@@ -933,6 +907,7 @@ class ElfBuilder FINAL {
for (auto* section : sections_) {
const Elf_Shdr& shdr = section->header_;
if ((shdr.sh_flags & SHF_ALLOC) != 0 && shdr.sh_size != 0) {
+ DCHECK(shdr.sh_addr != 0u) << "Allocate virtual memory for the section";
// PT_LOAD tells the linker to mmap part of the file.
// The linker can only mmap page-aligned sections.
// Single PT_LOAD may contain several ELF sections.
@@ -1010,6 +985,7 @@ class ElfBuilder FINAL {
// List of used section in the order in which they were written.
std::vector<Section*> sections_;
+ Section* current_section_; // The section which is currently being written.
bool started_;
bool write_program_headers_;
diff --git a/compiler/linker/error_delaying_output_stream.h b/compiler/linker/error_delaying_output_stream.h
index 33e6b5ab23..659f1dc093 100644
--- a/compiler/linker/error_delaying_output_stream.h
+++ b/compiler/linker/error_delaying_output_stream.h
@@ -19,7 +19,9 @@
#include "output_stream.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/macros.h"
namespace art {
namespace linker {
diff --git a/compiler/linker/linker_patch.h b/compiler/linker/linker_patch.h
index 0ac149029a..6f4e7746a6 100644
--- a/compiler/linker/linker_patch.h
+++ b/compiler/linker/linker_patch.h
@@ -20,8 +20,9 @@
#include <iosfwd>
#include <stdint.h>
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
#include "method_reference.h"
namespace art {
diff --git a/compiler/linker/output_stream_test.cc b/compiler/linker/output_stream_test.cc
index ad298406be..f93ea7a709 100644
--- a/compiler/linker/output_stream_test.cc
+++ b/compiler/linker/output_stream_test.cc
@@ -17,7 +17,9 @@
#include "file_output_stream.h"
#include "vector_output_stream.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/macros.h"
#include "base/unix_file/fd_file.h"
#include "buffered_output_stream.h"
#include "common_runtime_test.h"
diff --git a/compiler/linker/vector_output_stream.cc b/compiler/linker/vector_output_stream.cc
index 75f90e5f94..f2cae5b1d5 100644
--- a/compiler/linker/vector_output_stream.cc
+++ b/compiler/linker/vector_output_stream.cc
@@ -16,7 +16,7 @@
#include "vector_output_stream.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
namespace art {
namespace linker {
diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc
index a6687fe258..2b568bcffd 100644
--- a/compiler/optimizing/block_builder.cc
+++ b/compiler/optimizing/block_builder.cc
@@ -16,11 +16,34 @@
#include "block_builder.h"
+#include "base/logging.h" // FOR VLOG.
#include "bytecode_utils.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file_exception_helpers.h"
#include "quicken_info.h"
namespace art {
+HBasicBlockBuilder::HBasicBlockBuilder(HGraph* graph,
+ const DexFile* const dex_file,
+ const CodeItemDebugInfoAccessor& accessor,
+ ScopedArenaAllocator* local_allocator)
+ : allocator_(graph->GetAllocator()),
+ graph_(graph),
+ dex_file_(dex_file),
+ code_item_accessor_(accessor),
+ local_allocator_(local_allocator),
+ branch_targets_(code_item_accessor_.HasCodeItem()
+ ? code_item_accessor_.InsnsSizeInCodeUnits()
+ : /* fake dex_pc=0 for intrinsic graph */ 1u,
+ nullptr,
+ local_allocator->Adapter(kArenaAllocGraphBuilder)),
+ throwing_blocks_(kDefaultNumberOfThrowingBlocks,
+ local_allocator->Adapter(kArenaAllocGraphBuilder)),
+ number_of_branches_(0u),
+ quicken_index_for_dex_pc_(std::less<uint32_t>(),
+ local_allocator->Adapter(kArenaAllocGraphBuilder)) {}
+
HBasicBlock* HBasicBlockBuilder::MaybeCreateBlockAt(uint32_t dex_pc) {
return MaybeCreateBlockAt(dex_pc, dex_pc);
}
@@ -40,30 +63,30 @@ bool HBasicBlockBuilder::CreateBranchTargets() {
// Create the first block for the dex instructions, single successor of the entry block.
MaybeCreateBlockAt(0u);
- if (code_item_->tries_size_ != 0) {
+ if (code_item_accessor_.TriesSize() != 0) {
// Create branch targets at the start/end of the TryItem range. These are
// places where the program might fall through into/out of the a block and
// where TryBoundary instructions will be inserted later. Other edges which
// enter/exit the try blocks are a result of branches/switches.
- for (size_t idx = 0; idx < code_item_->tries_size_; ++idx) {
- const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item_, idx);
- uint32_t dex_pc_start = try_item->start_addr_;
- uint32_t dex_pc_end = dex_pc_start + try_item->insn_count_;
+ for (const DexFile::TryItem& try_item : code_item_accessor_.TryItems()) {
+ uint32_t dex_pc_start = try_item.start_addr_;
+ uint32_t dex_pc_end = dex_pc_start + try_item.insn_count_;
MaybeCreateBlockAt(dex_pc_start);
- if (dex_pc_end < code_item_->insns_size_in_code_units_) {
+ if (dex_pc_end < code_item_accessor_.InsnsSizeInCodeUnits()) {
// TODO: Do not create block if the last instruction cannot fall through.
MaybeCreateBlockAt(dex_pc_end);
- } else if (dex_pc_end == code_item_->insns_size_in_code_units_) {
+ } else if (dex_pc_end == code_item_accessor_.InsnsSizeInCodeUnits()) {
// The TryItem spans until the very end of the CodeItem and therefore
// cannot have any code afterwards.
} else {
// The TryItem spans beyond the end of the CodeItem. This is invalid code.
+ VLOG(compiler) << "Not compiled: TryItem spans beyond the end of the CodeItem";
return false;
}
}
// Create branch targets for exception handlers.
- const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
+ const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData();
uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
for (uint32_t idx = 0; idx < handlers_size; ++idx) {
CatchHandlerIterator iterator(handlers_ptr);
@@ -76,8 +99,7 @@ bool HBasicBlockBuilder::CreateBranchTargets() {
// Iterate over all instructions and find branching instructions. Create blocks for
// the locations these instructions branch to.
- IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
- for (const DexInstructionPcPair& pair : instructions) {
+ for (const DexInstructionPcPair& pair : code_item_accessor_) {
const uint32_t dex_pc = pair.DexPc();
const Instruction& instruction = pair.Inst();
@@ -107,9 +129,10 @@ bool HBasicBlockBuilder::CreateBranchTargets() {
if (instruction.CanFlowThrough()) {
DexInstructionIterator next(std::next(DexInstructionIterator(pair)));
- if (next == instructions.end()) {
+ if (next == code_item_accessor_.end()) {
// In the normal case we should never hit this but someone can artificially forge a dex
// file to fall-through out the method code. In this case we bail out compilation.
+ VLOG(compiler) << "Not compiled: Fall-through beyond the CodeItem";
return false;
}
MaybeCreateBlockAt(next.DexPc());
@@ -127,7 +150,7 @@ void HBasicBlockBuilder::ConnectBasicBlocks() {
bool is_throwing_block = false;
// Calculate the qucikening index here instead of CreateBranchTargets since it's easier to
// calculate in dex_pc order.
- for (const DexInstructionPcPair& pair : code_item_->Instructions()) {
+ for (const DexInstructionPcPair& pair : code_item_accessor_) {
const uint32_t dex_pc = pair.DexPc();
const Instruction& instruction = pair.Inst();
@@ -210,10 +233,12 @@ static const DexFile::TryItem* GetTryItem(
// successors matches the order in which runtime exception delivery searches
// for a handler.
static void LinkToCatchBlocks(HTryBoundary* try_boundary,
- const DexFile::CodeItem& code_item,
+ const CodeItemDataAccessor& accessor,
const DexFile::TryItem* try_item,
const ScopedArenaSafeMap<uint32_t, HBasicBlock*>& catch_blocks) {
- for (CatchHandlerIterator it(code_item, *try_item); it.HasNext(); it.Next()) {
+ for (CatchHandlerIterator it(accessor.GetCatchHandlerData(try_item->handler_off_));
+ it.HasNext();
+ it.Next()) {
try_boundary->AddExceptionHandler(catch_blocks.Get(it.GetHandlerAddress()));
}
}
@@ -229,7 +254,7 @@ bool HBasicBlockBuilder::MightHaveLiveNormalPredecessors(HBasicBlock* catch_bloc
}
}
- const Instruction& first = code_item_->InstructionAt(catch_block->GetDexPc());
+ const Instruction& first = code_item_accessor_.InstructionAt(catch_block->GetDexPc());
if (first.Opcode() == Instruction::MOVE_EXCEPTION) {
// Verifier guarantees that if a catch block begins with MOVE_EXCEPTION then
// it has no live normal predecessors.
@@ -247,7 +272,7 @@ bool HBasicBlockBuilder::MightHaveLiveNormalPredecessors(HBasicBlock* catch_bloc
}
void HBasicBlockBuilder::InsertTryBoundaryBlocks() {
- if (code_item_->tries_size_ == 0) {
+ if (code_item_accessor_.TriesSize() == 0) {
return;
}
@@ -269,12 +294,10 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() {
// loop for synchronized blocks.
if (ContainsElement(throwing_blocks_, block)) {
// Try to find a TryItem covering the block.
- const int32_t try_item_idx = DexFile::FindTryItem(DexFile::GetTryItems(*code_item_, 0u),
- code_item_->tries_size_,
- block->GetDexPc());
- if (try_item_idx != -1) {
+ const DexFile::TryItem* try_item = code_item_accessor_.FindTryItem(block->GetDexPc());
+ if (try_item != nullptr) {
// Block throwing and in a TryItem. Store the try block information.
- try_block_info.Put(block->GetBlockId(), DexFile::GetTryItems(*code_item_, try_item_idx));
+ try_block_info.Put(block->GetBlockId(), try_item);
}
}
}
@@ -285,7 +308,7 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() {
// Iterate over catch blocks, create artifical landing pads if necessary to
// simplify the CFG, and set metadata.
- const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
+ const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData();
uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
for (uint32_t idx = 0; idx < handlers_size; ++idx) {
CatchHandlerIterator iterator(handlers_ptr);
@@ -333,7 +356,7 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() {
HTryBoundary* try_entry = new (allocator_) HTryBoundary(
HTryBoundary::BoundaryKind::kEntry, try_block->GetDexPc());
try_block->CreateImmediateDominator()->AddInstruction(try_entry);
- LinkToCatchBlocks(try_entry, *code_item_, try_item, catch_blocks);
+ LinkToCatchBlocks(try_entry, code_item_accessor_, try_item, catch_blocks);
break;
}
}
@@ -361,13 +384,13 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() {
HTryBoundary* try_exit =
new (allocator_) HTryBoundary(HTryBoundary::BoundaryKind::kExit, successor->GetDexPc());
graph_->SplitEdge(try_block, successor)->AddInstruction(try_exit);
- LinkToCatchBlocks(try_exit, *code_item_, try_item, catch_blocks);
+ LinkToCatchBlocks(try_exit, code_item_accessor_, try_item, catch_blocks);
}
}
}
bool HBasicBlockBuilder::Build() {
- DCHECK(code_item_ != nullptr);
+ DCHECK(code_item_accessor_.HasCodeItem());
DCHECK(graph_->GetBlocks().empty());
graph_->SetEntryBlock(new (allocator_) HBasicBlock(graph_, kNoDexPc));
@@ -385,7 +408,7 @@ bool HBasicBlockBuilder::Build() {
}
void HBasicBlockBuilder::BuildIntrinsic() {
- DCHECK(code_item_ == nullptr);
+ DCHECK(!code_item_accessor_.HasCodeItem());
DCHECK(graph_->GetBlocks().empty());
// Create blocks.
diff --git a/compiler/optimizing/block_builder.h b/compiler/optimizing/block_builder.h
index 7d0f56db34..2c1f034d80 100644
--- a/compiler/optimizing/block_builder.h
+++ b/compiler/optimizing/block_builder.h
@@ -19,7 +19,8 @@
#include "base/scoped_arena_allocator.h"
#include "base/scoped_arena_containers.h"
-#include "dex_file.h"
+#include "dex/code_item_accessors.h"
+#include "dex/dex_file.h"
#include "nodes.h"
namespace art {
@@ -28,22 +29,8 @@ class HBasicBlockBuilder : public ValueObject {
public:
HBasicBlockBuilder(HGraph* graph,
const DexFile* const dex_file,
- const DexFile::CodeItem* code_item,
- ScopedArenaAllocator* local_allocator)
- : allocator_(graph->GetAllocator()),
- graph_(graph),
- dex_file_(dex_file),
- code_item_(code_item),
- local_allocator_(local_allocator),
- branch_targets_(code_item != nullptr ? code_item->insns_size_in_code_units_
- : /* fake dex_pc=0 for intrinsic graph */ 1u,
- nullptr,
- local_allocator->Adapter(kArenaAllocGraphBuilder)),
- throwing_blocks_(kDefaultNumberOfThrowingBlocks,
- local_allocator->Adapter(kArenaAllocGraphBuilder)),
- number_of_branches_(0u),
- quicken_index_for_dex_pc_(std::less<uint32_t>(),
- local_allocator->Adapter(kArenaAllocGraphBuilder)) {}
+ const CodeItemDebugInfoAccessor& accessor,
+ ScopedArenaAllocator* local_allocator);
// Creates basic blocks in `graph_` at branch target dex_pc positions of the
// `code_item_`. Blocks are connected but left unpopulated with instructions.
@@ -83,7 +70,7 @@ class HBasicBlockBuilder : public ValueObject {
HGraph* const graph_;
const DexFile* const dex_file_;
- const DexFile::CodeItem* const code_item_; // null for intrinsic graph.
+ CodeItemDataAccessor code_item_accessor_; // null code item for intrinsic graph.
ScopedArenaAllocator* const local_allocator_;
ScopedArenaVector<HBasicBlock*> branch_targets_;
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index d73ef1f3a1..af537dd653 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -37,7 +37,7 @@
namespace art {
HGraphBuilder::HGraphBuilder(HGraph* graph,
- const DexFile::CodeItem* code_item,
+ const CodeItemDebugInfoAccessor& accessor,
const DexCompilationUnit* dex_compilation_unit,
const DexCompilationUnit* outer_compilation_unit,
CompilerDriver* driver,
@@ -47,7 +47,7 @@ HGraphBuilder::HGraphBuilder(HGraph* graph,
VariableSizedHandleScope* handles)
: graph_(graph),
dex_file_(&graph->GetDexFile()),
- code_item_(code_item),
+ code_item_accessor_(accessor),
dex_compilation_unit_(dex_compilation_unit),
outer_compilation_unit_(outer_compilation_unit),
compiler_driver_(driver),
@@ -57,6 +57,23 @@ HGraphBuilder::HGraphBuilder(HGraph* graph,
handles_(handles),
return_type_(DataType::FromShorty(dex_compilation_unit_->GetShorty()[0])) {}
+HGraphBuilder::HGraphBuilder(HGraph* graph,
+ const DexCompilationUnit* dex_compilation_unit,
+ const CodeItemDebugInfoAccessor& accessor,
+ VariableSizedHandleScope* handles,
+ DataType::Type return_type)
+ : graph_(graph),
+ dex_file_(&graph->GetDexFile()),
+ code_item_accessor_(accessor),
+ dex_compilation_unit_(dex_compilation_unit),
+ outer_compilation_unit_(nullptr),
+ compiler_driver_(nullptr),
+ code_generator_(nullptr),
+ compilation_stats_(nullptr),
+ interpreter_metadata_(nullptr),
+ handles_(handles),
+ return_type_(return_type) {}
+
bool HGraphBuilder::SkipCompilation(size_t number_of_branches) {
if (compiler_driver_ == nullptr) {
// Note that the compiler driver is null when unit testing.
@@ -69,20 +86,20 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) {
return false;
}
- if (compiler_options.IsHugeMethod(code_item_->insns_size_in_code_units_)) {
+ const uint32_t code_units = code_item_accessor_.InsnsSizeInCodeUnits();
+ if (compiler_options.IsHugeMethod(code_units)) {
VLOG(compiler) << "Skip compilation of huge method "
<< dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex())
- << ": " << code_item_->insns_size_in_code_units_ << " code units";
+ << ": " << code_units << " code units";
MaybeRecordStat(compilation_stats_, MethodCompilationStat::kNotCompiledHugeMethod);
return true;
}
// If it's large and contains no branches, it's likely to be machine generated initialization.
- if (compiler_options.IsLargeMethod(code_item_->insns_size_in_code_units_)
- && (number_of_branches == 0)) {
+ if (compiler_options.IsLargeMethod(code_units) && (number_of_branches == 0)) {
VLOG(compiler) << "Skip compilation of large method with no branch "
<< dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex())
- << ": " << code_item_->insns_size_in_code_units_ << " code units";
+ << ": " << code_units << " code units";
MaybeRecordStat(compilation_stats_, MethodCompilationStat::kNotCompiledLargeMethodNoBranches);
return true;
}
@@ -91,17 +108,17 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) {
}
GraphAnalysisResult HGraphBuilder::BuildGraph() {
- DCHECK(code_item_ != nullptr);
+ DCHECK(code_item_accessor_.HasCodeItem());
DCHECK(graph_->GetBlocks().empty());
- graph_->SetNumberOfVRegs(code_item_->registers_size_);
- graph_->SetNumberOfInVRegs(code_item_->ins_size_);
- graph_->SetMaximumNumberOfOutVRegs(code_item_->outs_size_);
- graph_->SetHasTryCatch(code_item_->tries_size_ != 0);
+ graph_->SetNumberOfVRegs(code_item_accessor_.RegistersSize());
+ graph_->SetNumberOfInVRegs(code_item_accessor_.InsSize());
+ graph_->SetMaximumNumberOfOutVRegs(code_item_accessor_.OutsSize());
+ graph_->SetHasTryCatch(code_item_accessor_.TriesSize() != 0);
// Use ScopedArenaAllocator for all local allocations.
ScopedArenaAllocator local_allocator(graph_->GetArenaStack());
- HBasicBlockBuilder block_builder(graph_, dex_file_, code_item_, &local_allocator);
+ HBasicBlockBuilder block_builder(graph_, dex_file_, code_item_accessor_, &local_allocator);
SsaBuilder ssa_builder(graph_,
dex_compilation_unit_->GetClassLoader(),
dex_compilation_unit_->GetDexCache(),
@@ -111,7 +128,7 @@ GraphAnalysisResult HGraphBuilder::BuildGraph() {
&block_builder,
&ssa_builder,
dex_file_,
- code_item_,
+ code_item_accessor_,
return_type_,
dex_compilation_unit_,
outer_compilation_unit_,
@@ -150,7 +167,7 @@ GraphAnalysisResult HGraphBuilder::BuildGraph() {
}
void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) {
- DCHECK(code_item_ == nullptr);
+ DCHECK(!code_item_accessor_.HasCodeItem());
DCHECK(graph_->GetBlocks().empty());
// Determine the number of arguments and associated vregs.
@@ -170,7 +187,10 @@ void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) {
// Use ScopedArenaAllocator for all local allocations.
ScopedArenaAllocator local_allocator(graph_->GetArenaStack());
- HBasicBlockBuilder block_builder(graph_, dex_file_, /* code_item */ nullptr, &local_allocator);
+ HBasicBlockBuilder block_builder(graph_,
+ dex_file_,
+ CodeItemDebugInfoAccessor(),
+ &local_allocator);
SsaBuilder ssa_builder(graph_,
dex_compilation_unit_->GetClassLoader(),
dex_compilation_unit_->GetDexCache(),
@@ -180,7 +200,7 @@ void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) {
&block_builder,
&ssa_builder,
dex_file_,
- /* code_item */ nullptr,
+ CodeItemDebugInfoAccessor(),
return_type_,
dex_compilation_unit_,
outer_compilation_unit_,
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 0bb3a051f7..c16a3a928d 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -18,8 +18,9 @@
#define ART_COMPILER_OPTIMIZING_BUILDER_H_
#include "base/arena_object.h"
-#include "dex_file-inl.h"
-#include "dex_file.h"
+#include "dex/code_item_accessors.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file.h"
#include "driver/compiler_driver.h"
#include "nodes.h"
@@ -33,7 +34,7 @@ class OptimizingCompilerStats;
class HGraphBuilder : public ValueObject {
public:
HGraphBuilder(HGraph* graph,
- const DexFile::CodeItem* code_item,
+ const CodeItemDebugInfoAccessor& accessor,
const DexCompilationUnit* dex_compilation_unit,
const DexCompilationUnit* outer_compilation_unit,
CompilerDriver* driver,
@@ -45,20 +46,9 @@ class HGraphBuilder : public ValueObject {
// Only for unit testing.
HGraphBuilder(HGraph* graph,
const DexCompilationUnit* dex_compilation_unit,
- const DexFile::CodeItem& code_item,
+ const CodeItemDebugInfoAccessor& accessor,
VariableSizedHandleScope* handles,
- DataType::Type return_type = DataType::Type::kInt32)
- : graph_(graph),
- dex_file_(&graph->GetDexFile()),
- code_item_(&code_item),
- dex_compilation_unit_(dex_compilation_unit),
- outer_compilation_unit_(nullptr),
- compiler_driver_(nullptr),
- code_generator_(nullptr),
- compilation_stats_(nullptr),
- interpreter_metadata_(nullptr),
- handles_(handles),
- return_type_(return_type) {}
+ DataType::Type return_type = DataType::Type::kInt32);
GraphAnalysisResult BuildGraph();
void BuildIntrinsicGraph(ArtMethod* method);
@@ -70,7 +60,7 @@ class HGraphBuilder : public ValueObject {
HGraph* const graph_;
const DexFile* const dex_file_;
- const DexFile::CodeItem* const code_item_; // null for intrinsic graph.
+ const CodeItemDebugInfoAccessor code_item_accessor_; // null for intrinsic graph.
// The compilation unit of the current method being compiled. Note that
// it can be an inlined method.
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index aff6f9f64f..07894fd1b1 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -46,6 +46,7 @@
#include "bytecode_utils.h"
#include "class_linker.h"
#include "compiled_method.h"
+#include "dex/code_item_accessors-inl.h"
#include "dex/verified_method.h"
#include "driver/compiler_driver.h"
#include "graph_visualizer.h"
@@ -295,15 +296,6 @@ void CodeGenerator::EmitJitRootPatches(uint8_t* code ATTRIBUTE_UNUSED,
DCHECK_EQ(code_generation_data_->GetNumberOfJitClassRoots(), 0u);
}
-size_t CodeGenerator::GetCacheOffset(uint32_t index) {
- return sizeof(GcRoot<mirror::Object>) * index;
-}
-
-size_t CodeGenerator::GetCachePointerOffset(uint32_t index) {
- PointerSize pointer_size = InstructionSetPointerSize(GetInstructionSet());
- return static_cast<size_t>(pointer_size) * index;
-}
-
uint32_t CodeGenerator::GetArrayLengthOffset(HArrayLength* array_length) {
return array_length->IsStringLength()
? mirror::String::CountOffset().Uint32Value()
@@ -919,7 +911,8 @@ static void CheckLoopEntriesCanBeUsedForOsr(const HGraph& graph,
}
ArenaVector<size_t> covered(
loop_headers.size(), 0, graph.GetAllocator()->Adapter(kArenaAllocMisc));
- for (const DexInstructionPcPair& pair : code_item.Instructions()) {
+ for (const DexInstructionPcPair& pair : CodeItemInstructionAccessor(&graph.GetDexFile(),
+ &code_item)) {
const uint32_t dex_pc = pair.DexPc();
const Instruction& instruction = pair.Inst();
if (instruction.IsBranch()) {
@@ -981,21 +974,6 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction,
}
}
- uint32_t outer_dex_pc = dex_pc;
- uint32_t outer_environment_size = 0;
- uint32_t inlining_depth = 0;
- if (instruction != nullptr) {
- for (HEnvironment* environment = instruction->GetEnvironment();
- environment != nullptr;
- environment = environment->GetParent()) {
- outer_dex_pc = environment->GetDexPc();
- outer_environment_size = environment->Size();
- if (environment != instruction->GetEnvironment()) {
- inlining_depth++;
- }
- }
- }
-
// Collect PC infos for the mapping table.
uint32_t native_pc = GetAssembler()->CodePosition();
@@ -1003,12 +981,12 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction,
if (instruction == nullptr) {
// For stack overflow checks and native-debug-info entries without dex register
// mapping (i.e. start of basic block or start of slow path).
- stack_map_stream->BeginStackMapEntry(outer_dex_pc, native_pc, 0, 0, 0, 0);
+ stack_map_stream->BeginStackMapEntry(dex_pc, native_pc, 0, 0, 0, 0);
stack_map_stream->EndStackMapEntry();
return;
}
- LocationSummary* locations = instruction->GetLocations();
+ LocationSummary* locations = instruction->GetLocations();
uint32_t register_mask = locations->GetRegisterMask();
DCHECK_EQ(register_mask & ~locations->GetLiveRegisters()->GetCoreRegisters(), 0u);
if (locations->OnlyCallsOnSlowPath()) {
@@ -1023,22 +1001,33 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction,
// The register mask must be a subset of callee-save registers.
DCHECK_EQ(register_mask & core_callee_save_mask_, register_mask);
}
+
+ uint32_t outer_dex_pc = dex_pc;
+ uint32_t outer_environment_size = 0u;
+ uint32_t inlining_depth = 0;
+ HEnvironment* const environment = instruction->GetEnvironment();
+ if (environment != nullptr) {
+ HEnvironment* outer_environment = environment;
+ while (outer_environment->GetParent() != nullptr) {
+ outer_environment = outer_environment->GetParent();
+ ++inlining_depth;
+ }
+ outer_dex_pc = outer_environment->GetDexPc();
+ outer_environment_size = outer_environment->Size();
+ }
stack_map_stream->BeginStackMapEntry(outer_dex_pc,
native_pc,
register_mask,
locations->GetStackMask(),
outer_environment_size,
inlining_depth);
-
- HEnvironment* const environment = instruction->GetEnvironment();
EmitEnvironment(environment, slow_path);
// Record invoke info, the common case for the trampoline is super and static invokes. Only
// record these to reduce oat file size.
if (kEnableDexLayoutOptimizations) {
- if (environment != nullptr &&
- instruction->IsInvoke() &&
- instruction->IsInvokeStaticOrDirect()) {
- HInvoke* const invoke = instruction->AsInvoke();
+ if (instruction->IsInvokeStaticOrDirect()) {
+ HInvoke* const invoke = instruction->AsInvokeStaticOrDirect();
+ DCHECK(environment != nullptr);
stack_map_stream->AddInvoke(invoke->GetInvokeType(), invoke->GetDexMethodIndex());
}
}
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 08e4462356..3c5a37f958 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -388,13 +388,6 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> {
bool IsBlockedCoreRegister(size_t i) { return blocked_core_registers_[i]; }
bool IsBlockedFloatingPointRegister(size_t i) { return blocked_fpu_registers_[i]; }
- // Helper that returns the pointer offset of an index in an object array.
- // Note: this method assumes we always have the same pointer size, regardless
- // of the architecture.
- static size_t GetCacheOffset(uint32_t index);
- // Pointer variant for ArtMethod and ArtField arrays.
- size_t GetCachePointerOffset(uint32_t index);
-
// Helper that returns the offset of the array's length field.
// Note: Besides the normal arrays, we also use the HArrayLength for
// accessing the String's `count` field in String intrinsics.
@@ -412,6 +405,50 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> {
Location to2,
DataType::Type type2);
+ static bool InstanceOfNeedsReadBarrier(HInstanceOf* instance_of) {
+ // Used only for kExactCheck, kAbstractClassCheck, kClassHierarchyCheck and kArrayObjectCheck.
+ DCHECK(instance_of->GetTypeCheckKind() == TypeCheckKind::kExactCheck ||
+ instance_of->GetTypeCheckKind() == TypeCheckKind::kAbstractClassCheck ||
+ instance_of->GetTypeCheckKind() == TypeCheckKind::kClassHierarchyCheck ||
+ instance_of->GetTypeCheckKind() == TypeCheckKind::kArrayObjectCheck)
+ << instance_of->GetTypeCheckKind();
+ // If the target class is in the boot image, it's non-moveable and it doesn't matter
+ // if we compare it with a from-space or to-space reference, the result is the same.
+ // It's OK to traverse a class hierarchy jumping between from-space and to-space.
+ return kEmitCompilerReadBarrier && !instance_of->GetTargetClass()->IsInBootImage();
+ }
+
+ static ReadBarrierOption ReadBarrierOptionForInstanceOf(HInstanceOf* instance_of) {
+ return InstanceOfNeedsReadBarrier(instance_of) ? kWithReadBarrier : kWithoutReadBarrier;
+ }
+
+ static bool IsTypeCheckSlowPathFatal(HCheckCast* check_cast) {
+ switch (check_cast->GetTypeCheckKind()) {
+ case TypeCheckKind::kExactCheck:
+ case TypeCheckKind::kAbstractClassCheck:
+ case TypeCheckKind::kClassHierarchyCheck:
+ case TypeCheckKind::kArrayObjectCheck:
+ case TypeCheckKind::kInterfaceCheck: {
+ bool needs_read_barrier =
+ kEmitCompilerReadBarrier && !check_cast->GetTargetClass()->IsInBootImage();
+ // We do not emit read barriers for HCheckCast, so we can get false negatives
+ // and the slow path shall re-check and simply return if the cast is actually OK.
+ return !needs_read_barrier;
+ }
+ case TypeCheckKind::kArrayCheck:
+ case TypeCheckKind::kUnresolvedCheck:
+ return false;
+ }
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+ }
+
+ static LocationSummary::CallKind GetCheckCastCallKind(HCheckCast* check_cast) {
+ return (IsTypeCheckSlowPathFatal(check_cast) && !check_cast->CanThrowIntoCatchBlock())
+ ? LocationSummary::kNoCall // In fact, call on a fatal (non-returning) slow path.
+ : LocationSummary::kCallOnSlowPath;
+ }
+
static bool StoreNeedsWriteBarrier(DataType::Type type, HInstruction* value) {
// Check that null value is not represented as an integer constant.
DCHECK(type != DataType::Type::kReference || !value->IsIntConstant());
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 5054a299d3..13886b32b3 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -478,7 +478,7 @@ class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 {
__ Bind(GetEntryLabel());
- if (!is_fatal_) {
+ if (!is_fatal_ || instruction_->CanThrowIntoCatchBlock()) {
SaveLiveRegisters(codegen, locations);
}
@@ -2103,9 +2103,8 @@ void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCod
// TODO(vixl): Let the MacroAssembler handle MemOperand.
__ Add(temp, class_reg, status_offset);
__ Ldarb(temp, HeapOperand(temp));
- __ Cmp(temp, mirror::Class::kStatusInitialized);
- __ B(ne, slow_path->GetEntryLabel());
- // Use Bne instead of Blt because ARM64 doesn't have Ldarsb.
+ __ Cmp(temp, enum_cast<>(ClassStatus::kInitialized));
+ __ B(lo, slow_path->GetEntryLabel());
__ Bind(slow_path->GetExitLabel());
}
@@ -3822,11 +3821,12 @@ void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
case TypeCheckKind::kExactCheck:
case TypeCheckKind::kAbstractClassCheck:
case TypeCheckKind::kClassHierarchyCheck:
- case TypeCheckKind::kArrayObjectCheck:
- call_kind =
- kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
- baker_read_barrier_slow_path = kUseBakerReadBarrier;
+ case TypeCheckKind::kArrayObjectCheck: {
+ bool needs_read_barrier = CodeGenerator::InstanceOfNeedsReadBarrier(instruction);
+ call_kind = needs_read_barrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
+ baker_read_barrier_slow_path = kUseBakerReadBarrier && needs_read_barrier;
break;
+ }
case TypeCheckKind::kArrayCheck:
case TypeCheckKind::kUnresolvedCheck:
case TypeCheckKind::kInterfaceCheck:
@@ -3875,13 +3875,15 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
switch (type_check_kind) {
case TypeCheckKind::kExactCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
__ Cmp(out, cls);
__ Cset(out, eq);
if (zero.IsLinked()) {
@@ -3891,13 +3893,15 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
}
case TypeCheckKind::kAbstractClassCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// If the class is abstract, we eagerly fetch the super class of the
// object to avoid doing a comparison we know will fail.
vixl::aarch64::Label loop, success;
@@ -3907,7 +3911,7 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
out_loc,
super_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// If `out` is null, we use it for the result, and jump to `done`.
__ Cbz(out, &done);
__ Cmp(out, cls);
@@ -3920,13 +3924,15 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
}
case TypeCheckKind::kClassHierarchyCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// Walk over the class hierarchy to find a match.
vixl::aarch64::Label loop, success;
__ Bind(&loop);
@@ -3937,7 +3943,7 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
out_loc,
super_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
__ Cbnz(out, &loop);
// If `out` is null, we use it for the result, and jump to `done`.
__ B(&done);
@@ -3950,13 +3956,15 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
}
case TypeCheckKind::kArrayObjectCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// Do an exact check.
vixl::aarch64::Label exact_check;
__ Cmp(out, cls);
@@ -3967,7 +3975,7 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
out_loc,
component_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// If `out` is null, we use it for the result, and jump to `done`.
__ Cbz(out, &done);
__ Ldrh(out, HeapOperand(out, primitive_offset));
@@ -4048,26 +4056,8 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
}
void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) {
- LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
- bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
-
TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
- switch (type_check_kind) {
- case TypeCheckKind::kExactCheck:
- case TypeCheckKind::kAbstractClassCheck:
- case TypeCheckKind::kClassHierarchyCheck:
- case TypeCheckKind::kArrayObjectCheck:
- call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
- LocationSummary::kCallOnSlowPath :
- LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
- break;
- case TypeCheckKind::kArrayCheck:
- case TypeCheckKind::kUnresolvedCheck:
- case TypeCheckKind::kInterfaceCheck:
- call_kind = LocationSummary::kCallOnSlowPath;
- break;
- }
-
+ LocationSummary::CallKind call_kind = CodeGenerator::GetCheckCastCallKind(instruction);
LocationSummary* locations =
new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
locations->SetInAt(0, Location::RequiresRegister());
@@ -4098,18 +4088,7 @@ void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
const uint32_t object_array_data_offset =
mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
- bool is_type_check_slow_path_fatal = false;
- // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
- // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
- // read barriers is done for performance and code size reasons.
- if (!kEmitCompilerReadBarrier) {
- is_type_check_slow_path_fatal =
- (type_check_kind == TypeCheckKind::kExactCheck ||
- type_check_kind == TypeCheckKind::kAbstractClassCheck ||
- type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
- type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
- !instruction->CanThrowIntoCatchBlock();
- }
+ bool is_type_check_slow_path_fatal = CodeGenerator::IsTypeCheckSlowPathFatal(instruction);
SlowPathCodeARM64* type_check_slow_path =
new (codegen_->GetScopedAllocator()) TypeCheckSlowPathARM64(
instruction, is_type_check_slow_path_fatal);
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index e53773c73d..f92c94fda7 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -20,7 +20,7 @@
#include "arch/arm64/quick_method_frame_info_arm64.h"
#include "code_generator.h"
#include "common_arm64.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "driver/compiler_options.h"
#include "nodes.h"
#include "parallel_move_resolver.h"
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 3f8f0c44f3..7f8353312f 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -619,7 +619,7 @@ class TypeCheckSlowPathARMVIXL : public SlowPathCodeARMVIXL {
CodeGeneratorARMVIXL* arm_codegen = down_cast<CodeGeneratorARMVIXL*>(codegen);
__ Bind(GetEntryLabel());
- if (!is_fatal_) {
+ if (!is_fatal_ || instruction_->CanThrowIntoCatchBlock()) {
SaveLiveRegisters(codegen, locations);
}
@@ -1128,7 +1128,7 @@ class LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARMVIXL
//
// Note that this field could also hold a different object, if
// another thread had concurrently changed it. In that case, the
- // LDREX/SUBS/ITNE sequence of instructions in the compare-and-set
+ // LDREX/CMP/BNE sequence of instructions in the compare-and-set
// (CAS) operation below would abort the CAS, leaving the field
// as-is.
__ Cmp(temp1_, ref_reg);
@@ -1168,28 +1168,16 @@ class LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARMVIXL
// tmp = [r_ptr] - expected;
// } while (tmp == 0 && failure([r_ptr] <- r_new_value));
- vixl32::Label loop_head, exit_loop;
+ vixl32::Label loop_head, comparison_failed, exit_loop;
__ Bind(&loop_head);
-
__ Ldrex(tmp, MemOperand(tmp_ptr));
-
- __ Subs(tmp, tmp, expected);
-
- {
- ExactAssemblyScope aas(arm_codegen->GetVIXLAssembler(),
- 2 * kMaxInstructionSizeInBytes,
- CodeBufferCheckScope::kMaximumSize);
-
- __ it(ne);
- __ clrex(ne);
- }
-
- __ B(ne, &exit_loop, /* far_target */ false);
-
+ __ Cmp(tmp, expected);
+ __ B(ne, &comparison_failed, /* far_target */ false);
__ Strex(tmp, value, MemOperand(tmp_ptr));
- __ Cmp(tmp, 1);
- __ B(eq, &loop_head, /* far_target */ false);
-
+ __ CompareAndBranchIfZero(tmp, &exit_loop, /* far_target */ false);
+ __ B(&loop_head);
+ __ Bind(&comparison_failed);
+ __ Clrex();
__ Bind(&exit_loop);
if (kPoisonHeapReferences) {
@@ -7185,12 +7173,12 @@ void InstructionCodeGeneratorARMVIXL::GenerateClassInitializationCheck(
LoadClassSlowPathARMVIXL* slow_path, vixl32::Register class_reg) {
UseScratchRegisterScope temps(GetVIXLAssembler());
vixl32::Register temp = temps.Acquire();
- GetAssembler()->LoadFromOffset(kLoadSignedByte,
+ GetAssembler()->LoadFromOffset(kLoadUnsignedByte,
temp,
class_reg,
mirror::Class::StatusOffset().Int32Value());
- __ Cmp(temp, mirror::Class::kStatusInitialized);
- __ B(lt, slow_path->GetEntryLabel());
+ __ Cmp(temp, enum_cast<>(ClassStatus::kInitialized));
+ __ B(lo, slow_path->GetEntryLabel());
// Even if the initialized flag is set, we may be in a situation where caches are not synced
// properly. Therefore, we do a memory fence.
__ Dmb(ISH);
@@ -7377,11 +7365,12 @@ void LocationsBuilderARMVIXL::VisitInstanceOf(HInstanceOf* instruction) {
case TypeCheckKind::kExactCheck:
case TypeCheckKind::kAbstractClassCheck:
case TypeCheckKind::kClassHierarchyCheck:
- case TypeCheckKind::kArrayObjectCheck:
- call_kind =
- kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
- baker_read_barrier_slow_path = kUseBakerReadBarrier;
+ case TypeCheckKind::kArrayObjectCheck: {
+ bool needs_read_barrier = CodeGenerator::InstanceOfNeedsReadBarrier(instruction);
+ call_kind = needs_read_barrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
+ baker_read_barrier_slow_path = kUseBakerReadBarrier && needs_read_barrier;
break;
+ }
case TypeCheckKind::kArrayCheck:
case TypeCheckKind::kUnresolvedCheck:
case TypeCheckKind::kInterfaceCheck:
@@ -7434,13 +7423,15 @@ void InstructionCodeGeneratorARMVIXL::VisitInstanceOf(HInstanceOf* instruction)
switch (type_check_kind) {
case TypeCheckKind::kExactCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// Classes must be equal for the instanceof to succeed.
__ Cmp(out, cls);
// We speculatively set the result to false without changing the condition
@@ -7467,13 +7458,15 @@ void InstructionCodeGeneratorARMVIXL::VisitInstanceOf(HInstanceOf* instruction)
}
case TypeCheckKind::kAbstractClassCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// If the class is abstract, we eagerly fetch the super class of the
// object to avoid doing a comparison we know will fail.
vixl32::Label loop;
@@ -7483,7 +7476,7 @@ void InstructionCodeGeneratorARMVIXL::VisitInstanceOf(HInstanceOf* instruction)
out_loc,
super_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// If `out` is null, we use it for the result, and jump to the final label.
__ CompareAndBranchIfZero(out, final_label, /* far_target */ false);
__ Cmp(out, cls);
@@ -7493,13 +7486,15 @@ void InstructionCodeGeneratorARMVIXL::VisitInstanceOf(HInstanceOf* instruction)
}
case TypeCheckKind::kClassHierarchyCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// Walk over the class hierarchy to find a match.
vixl32::Label loop, success;
__ Bind(&loop);
@@ -7510,7 +7505,7 @@ void InstructionCodeGeneratorARMVIXL::VisitInstanceOf(HInstanceOf* instruction)
out_loc,
super_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// This is essentially a null check, but it sets the condition flags to the
// proper value for the code that follows the loop, i.e. not `eq`.
__ Cmp(out, 1);
@@ -7547,13 +7542,15 @@ void InstructionCodeGeneratorARMVIXL::VisitInstanceOf(HInstanceOf* instruction)
}
case TypeCheckKind::kArrayObjectCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// Do an exact check.
vixl32::Label exact_check;
__ Cmp(out, cls);
@@ -7564,7 +7561,7 @@ void InstructionCodeGeneratorARMVIXL::VisitInstanceOf(HInstanceOf* instruction)
out_loc,
component_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// If `out` is null, we use it for the result, and jump to the final label.
__ CompareAndBranchIfZero(out, final_label, /* far_target */ false);
GetAssembler()->LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
@@ -7654,26 +7651,8 @@ void InstructionCodeGeneratorARMVIXL::VisitInstanceOf(HInstanceOf* instruction)
}
void LocationsBuilderARMVIXL::VisitCheckCast(HCheckCast* instruction) {
- LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
- bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
-
TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
- switch (type_check_kind) {
- case TypeCheckKind::kExactCheck:
- case TypeCheckKind::kAbstractClassCheck:
- case TypeCheckKind::kClassHierarchyCheck:
- case TypeCheckKind::kArrayObjectCheck:
- call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
- LocationSummary::kCallOnSlowPath :
- LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
- break;
- case TypeCheckKind::kArrayCheck:
- case TypeCheckKind::kUnresolvedCheck:
- case TypeCheckKind::kInterfaceCheck:
- call_kind = LocationSummary::kCallOnSlowPath;
- break;
- }
-
+ LocationSummary::CallKind call_kind = CodeGenerator::GetCheckCastCallKind(instruction);
LocationSummary* locations =
new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
locations->SetInAt(0, Location::RequiresRegister());
@@ -7702,18 +7681,7 @@ void InstructionCodeGeneratorARMVIXL::VisitCheckCast(HCheckCast* instruction) {
const uint32_t object_array_data_offset =
mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
- // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
- // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
- // read barriers is done for performance and code size reasons.
- bool is_type_check_slow_path_fatal = false;
- if (!kEmitCompilerReadBarrier) {
- is_type_check_slow_path_fatal =
- (type_check_kind == TypeCheckKind::kExactCheck ||
- type_check_kind == TypeCheckKind::kAbstractClassCheck ||
- type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
- type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
- !instruction->CanThrowIntoCatchBlock();
- }
+ bool is_type_check_slow_path_fatal = CodeGenerator::IsTypeCheckSlowPathFatal(instruction);
SlowPathCodeARMVIXL* type_check_slow_path =
new (codegen_->GetScopedAllocator()) TypeCheckSlowPathARMVIXL(
instruction, is_type_check_slow_path_fatal);
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index d6922d2f3f..ebe252a9c8 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1095,17 +1095,23 @@ void ParallelMoveResolverMIPS::EmitSwap(size_t index) {
__ Move(r2, r1);
__ Move(r1, TMP);
} else if (loc1.IsFpuRegister() && loc2.IsFpuRegister()) {
- FRegister f1 = loc1.AsFpuRegister<FRegister>();
- FRegister f2 = loc2.AsFpuRegister<FRegister>();
- if (type == DataType::Type::kFloat32) {
- __ MovS(FTMP, f2);
- __ MovS(f2, f1);
- __ MovS(f1, FTMP);
+ if (codegen_->GetGraph()->HasSIMD()) {
+ __ MoveV(static_cast<VectorRegister>(FTMP), VectorRegisterFrom(loc1));
+ __ MoveV(VectorRegisterFrom(loc1), VectorRegisterFrom(loc2));
+ __ MoveV(VectorRegisterFrom(loc2), static_cast<VectorRegister>(FTMP));
} else {
- DCHECK_EQ(type, DataType::Type::kFloat64);
- __ MovD(FTMP, f2);
- __ MovD(f2, f1);
- __ MovD(f1, FTMP);
+ FRegister f1 = loc1.AsFpuRegister<FRegister>();
+ FRegister f2 = loc2.AsFpuRegister<FRegister>();
+ if (type == DataType::Type::kFloat32) {
+ __ MovS(FTMP, f2);
+ __ MovS(f2, f1);
+ __ MovS(f1, FTMP);
+ } else {
+ DCHECK_EQ(type, DataType::Type::kFloat64);
+ __ MovD(FTMP, f2);
+ __ MovD(f2, f1);
+ __ MovD(f1, FTMP);
+ }
}
} else if ((loc1.IsRegister() && loc2.IsFpuRegister()) ||
(loc1.IsFpuRegister() && loc2.IsRegister())) {
@@ -1152,6 +1158,8 @@ void ParallelMoveResolverMIPS::EmitSwap(size_t index) {
Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ false);
} else if (loc1.IsDoubleStackSlot() && loc2.IsDoubleStackSlot()) {
Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ true);
+ } else if (loc1.IsSIMDStackSlot() && loc2.IsSIMDStackSlot()) {
+ ExchangeQuadSlots(loc1.GetStackIndex(), loc2.GetStackIndex());
} else if ((loc1.IsRegister() && loc2.IsStackSlot()) ||
(loc1.IsStackSlot() && loc2.IsRegister())) {
Register reg = loc1.IsRegister() ? loc1.AsRegister<Register>() : loc2.AsRegister<Register>();
@@ -1174,6 +1182,13 @@ void ParallelMoveResolverMIPS::EmitSwap(size_t index) {
__ Move(TMP, reg_h);
__ LoadFromOffset(kLoadWord, reg_h, SP, offset_h);
__ StoreToOffset(kStoreWord, TMP, SP, offset_h);
+ } else if ((loc1.IsFpuRegister() && loc2.IsSIMDStackSlot()) ||
+ (loc1.IsSIMDStackSlot() && loc2.IsFpuRegister())) {
+ Location fp_loc = loc1.IsFpuRegister() ? loc1 : loc2;
+ intptr_t offset = loc1.IsFpuRegister() ? loc2.GetStackIndex() : loc1.GetStackIndex();
+ __ MoveV(static_cast<VectorRegister>(FTMP), VectorRegisterFrom(fp_loc));
+ __ LoadQFromOffset(fp_loc.AsFpuRegister<FRegister>(), SP, offset);
+ __ StoreQToOffset(FTMP, SP, offset);
} else if (loc1.IsFpuRegister() || loc2.IsFpuRegister()) {
FRegister reg = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
: loc2.AsFpuRegister<FRegister>();
@@ -1225,6 +1240,13 @@ void ParallelMoveResolverMIPS::Exchange(int index1, int index2, bool double_slot
}
}
+void ParallelMoveResolverMIPS::ExchangeQuadSlots(int index1, int index2) {
+ __ LoadQFromOffset(FTMP, SP, index1);
+ __ LoadQFromOffset(FTMP2, SP, index2);
+ __ StoreQToOffset(FTMP, SP, index2);
+ __ StoreQToOffset(FTMP2, SP, index1);
+}
+
void CodeGeneratorMIPS::ComputeSpillMask() {
core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
@@ -1790,6 +1812,11 @@ void CodeGeneratorMIPS::SetupBlockedRegisters() const {
blocked_core_registers_[TMP] = true;
blocked_fpu_registers_[FTMP] = true;
+ if (GetInstructionSetFeatures().HasMsa()) {
+ // To be used just for MSA instructions.
+ blocked_fpu_registers_[FTMP2] = true;
+ }
+
// Reserve suspend and thread registers.
blocked_core_registers_[S0] = true;
blocked_core_registers_[TR] = true;
@@ -1888,9 +1915,9 @@ void CodeGeneratorMIPS::GenerateInvokeRuntime(int32_t entry_point_offset, bool d
void InstructionCodeGeneratorMIPS::GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path,
Register class_reg) {
- __ LoadFromOffset(kLoadSignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
- __ LoadConst32(AT, mirror::Class::kStatusInitialized);
- __ Blt(TMP, AT, slow_path->GetEntryLabel());
+ __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
+ __ LoadConst32(AT, enum_cast<>(ClassStatus::kInitialized));
+ __ Bltu(TMP, AT, slow_path->GetEntryLabel());
// Even if the initialized flag is set, we need to ensure consistent memory ordering.
__ Sync(0);
__ Bind(slow_path->GetExitLabel());
@@ -1941,6 +1968,7 @@ void LocationsBuilderMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
DCHECK_EQ(instruction->InputCount(), 2U);
LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
DataType::Type type = instruction->GetResultType();
+ bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
switch (type) {
case DataType::Type::kInt32: {
locations->SetInAt(0, Location::RequiresRegister());
@@ -1950,11 +1978,22 @@ void LocationsBuilderMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
int32_t imm = CodeGenerator::GetInt32ValueOf(right->AsConstant());
if (instruction->IsAnd() || instruction->IsOr() || instruction->IsXor()) {
can_use_imm = IsUint<16>(imm);
- } else if (instruction->IsAdd()) {
- can_use_imm = IsInt<16>(imm);
} else {
- DCHECK(instruction->IsSub());
- can_use_imm = IsInt<16>(-imm);
+ DCHECK(instruction->IsSub() || instruction->IsAdd());
+ if (instruction->IsSub()) {
+ imm = -imm;
+ }
+ if (isR6) {
+ bool single_use = right->GetUses().HasExactlyOneElement();
+ int16_t imm_high = High16Bits(imm);
+ int16_t imm_low = Low16Bits(imm);
+ if (imm_low < 0) {
+ imm_high += 1;
+ }
+ can_use_imm = !((imm_high != 0) && (imm_low != 0)) || single_use;
+ } else {
+ can_use_imm = IsInt<16>(imm);
+ }
}
}
if (can_use_imm)
@@ -1988,6 +2027,7 @@ void LocationsBuilderMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
void InstructionCodeGeneratorMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
DataType::Type type = instruction->GetType();
LocationSummary* locations = instruction->GetLocations();
+ bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
switch (type) {
case DataType::Type::kInt32: {
@@ -2019,17 +2059,32 @@ void InstructionCodeGeneratorMIPS::HandleBinaryOp(HBinaryOperation* instruction)
__ Xori(dst, lhs, rhs_imm);
else
__ Xor(dst, lhs, rhs_reg);
- } else if (instruction->IsAdd()) {
- if (use_imm)
- __ Addiu(dst, lhs, rhs_imm);
- else
- __ Addu(dst, lhs, rhs_reg);
} else {
- DCHECK(instruction->IsSub());
- if (use_imm)
- __ Addiu(dst, lhs, -rhs_imm);
- else
+ DCHECK(instruction->IsAdd() || instruction->IsSub());
+ if (use_imm) {
+ if (instruction->IsSub()) {
+ rhs_imm = -rhs_imm;
+ }
+ if (IsInt<16>(rhs_imm)) {
+ __ Addiu(dst, lhs, rhs_imm);
+ } else {
+ DCHECK(isR6);
+ int16_t rhs_imm_high = High16Bits(rhs_imm);
+ int16_t rhs_imm_low = Low16Bits(rhs_imm);
+ if (rhs_imm_low < 0) {
+ rhs_imm_high += 1;
+ }
+ __ Aui(dst, lhs, rhs_imm_high);
+ if (rhs_imm_low != 0) {
+ __ Addiu(dst, dst, rhs_imm_low);
+ }
+ }
+ } else if (instruction->IsAdd()) {
+ __ Addu(dst, lhs, rhs_reg);
+ } else {
+ DCHECK(instruction->IsSub());
__ Subu(dst, lhs, rhs_reg);
+ }
}
break;
}
@@ -3103,23 +3158,92 @@ void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RequiresRegister());
+
+ HInstruction* index = instruction->InputAt(0);
+ HInstruction* length = instruction->InputAt(1);
+
+ bool const_index = false;
+ bool const_length = false;
+
+ if (index->IsConstant()) {
+ if (length->IsConstant()) {
+ const_index = true;
+ const_length = true;
+ } else {
+ int32_t index_value = index->AsIntConstant()->GetValue();
+ if (index_value < 0 || IsInt<16>(index_value + 1)) {
+ const_index = true;
+ }
+ }
+ } else if (length->IsConstant()) {
+ int32_t length_value = length->AsIntConstant()->GetValue();
+ if (IsUint<15>(length_value)) {
+ const_length = true;
+ }
+ }
+
+ locations->SetInAt(0, const_index
+ ? Location::ConstantLocation(index->AsConstant())
+ : Location::RequiresRegister());
+ locations->SetInAt(1, const_length
+ ? Location::ConstantLocation(length->AsConstant())
+ : Location::RequiresRegister());
}
void InstructionCodeGeneratorMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
LocationSummary* locations = instruction->GetLocations();
- BoundsCheckSlowPathMIPS* slow_path =
- new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS(instruction);
- codegen_->AddSlowPath(slow_path);
-
- Register index = locations->InAt(0).AsRegister<Register>();
- Register length = locations->InAt(1).AsRegister<Register>();
+ Location index_loc = locations->InAt(0);
+ Location length_loc = locations->InAt(1);
+
+ if (length_loc.IsConstant()) {
+ int32_t length = length_loc.GetConstant()->AsIntConstant()->GetValue();
+ if (index_loc.IsConstant()) {
+ int32_t index = index_loc.GetConstant()->AsIntConstant()->GetValue();
+ if (index < 0 || index >= length) {
+ BoundsCheckSlowPathMIPS* slow_path =
+ new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS(instruction);
+ codegen_->AddSlowPath(slow_path);
+ __ B(slow_path->GetEntryLabel());
+ } else {
+ // Nothing to be done.
+ }
+ return;
+ }
- // length is limited by the maximum positive signed 32-bit integer.
- // Unsigned comparison of length and index checks for index < 0
- // and for length <= index simultaneously.
- __ Bgeu(index, length, slow_path->GetEntryLabel());
+ BoundsCheckSlowPathMIPS* slow_path =
+ new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS(instruction);
+ codegen_->AddSlowPath(slow_path);
+ Register index = index_loc.AsRegister<Register>();
+ if (length == 0) {
+ __ B(slow_path->GetEntryLabel());
+ } else if (length == 1) {
+ __ Bnez(index, slow_path->GetEntryLabel());
+ } else {
+ DCHECK(IsUint<15>(length)) << length;
+ __ Sltiu(TMP, index, length);
+ __ Beqz(TMP, slow_path->GetEntryLabel());
+ }
+ } else {
+ Register length = length_loc.AsRegister<Register>();
+ BoundsCheckSlowPathMIPS* slow_path =
+ new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS(instruction);
+ codegen_->AddSlowPath(slow_path);
+ if (index_loc.IsConstant()) {
+ int32_t index = index_loc.GetConstant()->AsIntConstant()->GetValue();
+ if (index < 0) {
+ __ B(slow_path->GetEntryLabel());
+ } else if (index == 0) {
+ __ Blez(length, slow_path->GetEntryLabel());
+ } else {
+ DCHECK(IsInt<16>(index + 1)) << index;
+ __ Sltiu(TMP, length, index + 1);
+ __ Bnez(TMP, slow_path->GetEntryLabel());
+ }
+ } else {
+ Register index = index_loc.AsRegister<Register>();
+ __ Bgeu(index, length, slow_path->GetEntryLabel());
+ }
+ }
}
// Temp is used for read barrier.
@@ -3650,8 +3774,12 @@ void InstructionCodeGeneratorMIPS::DivRemByPowerOfTwo(HBinaryOperation* instruct
if (IsUint<16>(abs_imm - 1)) {
__ Andi(out, out, abs_imm - 1);
} else {
- __ Sll(out, out, 32 - ctz_imm);
- __ Srl(out, out, 32 - ctz_imm);
+ if (codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2()) {
+ __ Ins(out, ZERO, ctz_imm, 32 - ctz_imm);
+ } else {
+ __ Sll(out, out, 32 - ctz_imm);
+ __ Srl(out, out, 32 - ctz_imm);
+ }
}
__ Subu(out, out, TMP);
}
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 7845e312cb..32b3e4221f 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -18,7 +18,7 @@
#define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS_H_
#include "code_generator.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "driver/compiler_options.h"
#include "nodes.h"
#include "parallel_move_resolver.h"
@@ -145,6 +145,7 @@ class ParallelMoveResolverMIPS : public ParallelMoveResolverWithSwap {
void RestoreScratch(int reg) OVERRIDE;
void Exchange(int index1, int index2, bool double_slot);
+ void ExchangeQuadSlots(int index1, int index2);
MipsAssembler* GetAssembler() const;
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index ee33b3f335..3ea7b827bb 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -1061,6 +1061,13 @@ void ParallelMoveResolverMIPS64::Exchange(int index1, int index2, bool double_sl
__ StoreToOffset(store_type, TMP, SP, index1 + stack_offset);
}
+void ParallelMoveResolverMIPS64::ExchangeQuadSlots(int index1, int index2) {
+ __ LoadFpuFromOffset(kLoadQuadword, FTMP, SP, index1);
+ __ LoadFpuFromOffset(kLoadQuadword, FTMP2, SP, index2);
+ __ StoreFpuToOffset(kStoreQuadword, FTMP, SP, index2);
+ __ StoreFpuToOffset(kStoreQuadword, FTMP2, SP, index1);
+}
+
static dwarf::Reg DWARFReg(GpuRegister reg) {
return dwarf::Reg::Mips64Core(static_cast<int>(reg));
}
@@ -1370,6 +1377,8 @@ void CodeGeneratorMIPS64::SwapLocations(Location loc1, Location loc2, DataType::
bool is_slot1 = loc1.IsStackSlot() || loc1.IsDoubleStackSlot();
bool is_slot2 = loc2.IsStackSlot() || loc2.IsDoubleStackSlot();
+ bool is_simd1 = loc1.IsSIMDStackSlot();
+ bool is_simd2 = loc2.IsSIMDStackSlot();
bool is_fp_reg1 = loc1.IsFpuRegister();
bool is_fp_reg2 = loc2.IsFpuRegister();
@@ -1382,17 +1391,23 @@ void CodeGeneratorMIPS64::SwapLocations(Location loc1, Location loc2, DataType::
__ Move(r1, TMP);
} else if (is_fp_reg2 && is_fp_reg1) {
// Swap 2 FPRs
- FpuRegister r1 = loc1.AsFpuRegister<FpuRegister>();
- FpuRegister r2 = loc2.AsFpuRegister<FpuRegister>();
- if (type == DataType::Type::kFloat32) {
- __ MovS(FTMP, r1);
- __ MovS(r1, r2);
- __ MovS(r2, FTMP);
+ if (GetGraph()->HasSIMD()) {
+ __ MoveV(static_cast<VectorRegister>(FTMP), VectorRegisterFrom(loc1));
+ __ MoveV(VectorRegisterFrom(loc1), VectorRegisterFrom(loc2));
+ __ MoveV(VectorRegisterFrom(loc2), static_cast<VectorRegister>(FTMP));
} else {
- DCHECK_EQ(type, DataType::Type::kFloat64);
- __ MovD(FTMP, r1);
- __ MovD(r1, r2);
- __ MovD(r2, FTMP);
+ FpuRegister r1 = loc1.AsFpuRegister<FpuRegister>();
+ FpuRegister r2 = loc2.AsFpuRegister<FpuRegister>();
+ if (type == DataType::Type::kFloat32) {
+ __ MovS(FTMP, r1);
+ __ MovS(r1, r2);
+ __ MovS(r2, FTMP);
+ } else {
+ DCHECK_EQ(type, DataType::Type::kFloat64);
+ __ MovD(FTMP, r1);
+ __ MovD(r1, r2);
+ __ MovD(r2, FTMP);
+ }
}
} else if (is_slot1 != is_slot2) {
// Swap GPR/FPR and stack slot
@@ -1421,6 +1436,17 @@ void CodeGeneratorMIPS64::SwapLocations(Location loc1, Location loc2, DataType::
move_resolver_.Exchange(loc1.GetStackIndex(),
loc2.GetStackIndex(),
loc1.IsDoubleStackSlot());
+ } else if (is_simd1 && is_simd2) {
+ move_resolver_.ExchangeQuadSlots(loc1.GetStackIndex(), loc2.GetStackIndex());
+ } else if ((is_fp_reg1 && is_simd2) || (is_fp_reg2 && is_simd1)) {
+ Location fp_reg_loc = is_fp_reg1 ? loc1 : loc2;
+ Location mem_loc = is_fp_reg1 ? loc2 : loc1;
+ __ LoadFpuFromOffset(kLoadQuadword, FTMP, SP, mem_loc.GetStackIndex());
+ __ StoreFpuToOffset(kStoreQuadword,
+ fp_reg_loc.AsFpuRegister<FpuRegister>(),
+ SP,
+ mem_loc.GetStackIndex());
+ __ MoveV(VectorRegisterFrom(fp_reg_loc), static_cast<VectorRegister>(FTMP));
} else {
LOG(FATAL) << "Unimplemented swap between locations " << loc1 << " and " << loc2;
}
@@ -1653,6 +1679,11 @@ void CodeGeneratorMIPS64::SetupBlockedRegisters() const {
blocked_core_registers_[TMP2] = true;
blocked_fpu_registers_[FTMP] = true;
+ if (GetInstructionSetFeatures().HasMsa()) {
+ // To be used just for MSA instructions.
+ blocked_fpu_registers_[FTMP2] = true;
+ }
+
// Reserve suspend and thread registers.
blocked_core_registers_[S0] = true;
blocked_core_registers_[TR] = true;
@@ -1730,9 +1761,9 @@ void CodeGeneratorMIPS64::GenerateInvokeRuntime(int32_t entry_point_offset) {
void InstructionCodeGeneratorMIPS64::GenerateClassInitializationCheck(SlowPathCodeMIPS64* slow_path,
GpuRegister class_reg) {
- __ LoadFromOffset(kLoadSignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
- __ LoadConst32(AT, mirror::Class::kStatusInitialized);
- __ Bltc(TMP, AT, slow_path->GetEntryLabel());
+ __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
+ __ LoadConst32(AT, enum_cast<>(ClassStatus::kInitialized));
+ __ Bltuc(TMP, AT, slow_path->GetEntryLabel());
// Even if the initialized flag is set, we need to ensure consistent memory ordering.
__ Sync(0);
__ Bind(slow_path->GetExitLabel());
@@ -1793,11 +1824,19 @@ void LocationsBuilderMIPS64::HandleBinaryOp(HBinaryOperation* instruction) {
int64_t imm = CodeGenerator::GetInt64ValueOf(right->AsConstant());
if (instruction->IsAnd() || instruction->IsOr() || instruction->IsXor()) {
can_use_imm = IsUint<16>(imm);
- } else if (instruction->IsAdd()) {
- can_use_imm = IsInt<16>(imm);
} else {
- DCHECK(instruction->IsSub());
- can_use_imm = IsInt<16>(-imm);
+ DCHECK(instruction->IsAdd() || instruction->IsSub());
+ bool single_use = right->GetUses().HasExactlyOneElement();
+ if (instruction->IsSub()) {
+ if (!(type == DataType::Type::kInt32 && imm == INT32_MIN)) {
+ imm = -imm;
+ }
+ }
+ if (type == DataType::Type::kInt32) {
+ can_use_imm = IsInt<16>(imm) || (Low16Bits(imm) == 0) || single_use;
+ } else {
+ can_use_imm = IsInt<16>(imm) || (IsInt<32>(imm) && (Low16Bits(imm) == 0)) || single_use;
+ }
}
}
if (can_use_imm)
@@ -1855,30 +1894,90 @@ void InstructionCodeGeneratorMIPS64::HandleBinaryOp(HBinaryOperation* instructio
__ Xori(dst, lhs, rhs_imm);
else
__ Xor(dst, lhs, rhs_reg);
- } else if (instruction->IsAdd()) {
- if (type == DataType::Type::kInt32) {
- if (use_imm)
- __ Addiu(dst, lhs, rhs_imm);
- else
- __ Addu(dst, lhs, rhs_reg);
- } else {
- if (use_imm)
- __ Daddiu(dst, lhs, rhs_imm);
- else
- __ Daddu(dst, lhs, rhs_reg);
+ } else if (instruction->IsAdd() || instruction->IsSub()) {
+ if (instruction->IsSub()) {
+ rhs_imm = -rhs_imm;
}
- } else {
- DCHECK(instruction->IsSub());
if (type == DataType::Type::kInt32) {
- if (use_imm)
- __ Addiu(dst, lhs, -rhs_imm);
- else
- __ Subu(dst, lhs, rhs_reg);
+ if (use_imm) {
+ if (IsInt<16>(rhs_imm)) {
+ __ Addiu(dst, lhs, rhs_imm);
+ } else {
+ int16_t rhs_imm_high = High16Bits(rhs_imm);
+ int16_t rhs_imm_low = Low16Bits(rhs_imm);
+ if (rhs_imm_low < 0) {
+ rhs_imm_high += 1;
+ }
+ __ Aui(dst, lhs, rhs_imm_high);
+ if (rhs_imm_low != 0) {
+ __ Addiu(dst, dst, rhs_imm_low);
+ }
+ }
+ } else {
+ if (instruction->IsAdd()) {
+ __ Addu(dst, lhs, rhs_reg);
+ } else {
+ DCHECK(instruction->IsSub());
+ __ Subu(dst, lhs, rhs_reg);
+ }
+ }
} else {
- if (use_imm)
- __ Daddiu(dst, lhs, -rhs_imm);
- else
+ if (use_imm) {
+ if (IsInt<16>(rhs_imm)) {
+ __ Daddiu(dst, lhs, rhs_imm);
+ } else if (IsInt<32>(rhs_imm)) {
+ int16_t rhs_imm_high = High16Bits(rhs_imm);
+ int16_t rhs_imm_low = Low16Bits(rhs_imm);
+ bool overflow_hi16 = false;
+ if (rhs_imm_low < 0) {
+ rhs_imm_high += 1;
+ overflow_hi16 = (rhs_imm_high == -32768);
+ }
+ __ Daui(dst, lhs, rhs_imm_high);
+ if (rhs_imm_low != 0) {
+ __ Daddiu(dst, dst, rhs_imm_low);
+ }
+ if (overflow_hi16) {
+ __ Dahi(dst, 1);
+ }
+ } else {
+ int16_t rhs_imm_low = Low16Bits(Low32Bits(rhs_imm));
+ if (rhs_imm_low < 0) {
+ rhs_imm += (INT64_C(1) << 16);
+ }
+ int16_t rhs_imm_upper = High16Bits(Low32Bits(rhs_imm));
+ if (rhs_imm_upper < 0) {
+ rhs_imm += (INT64_C(1) << 32);
+ }
+ int16_t rhs_imm_high = Low16Bits(High32Bits(rhs_imm));
+ if (rhs_imm_high < 0) {
+ rhs_imm += (INT64_C(1) << 48);
+ }
+ int16_t rhs_imm_top = High16Bits(High32Bits(rhs_imm));
+ GpuRegister tmp = lhs;
+ if (rhs_imm_low != 0) {
+ __ Daddiu(dst, tmp, rhs_imm_low);
+ tmp = dst;
+ }
+ // Dahi and Dati must use the same input and output register, so we have to initialize
+ // the dst register using Daddiu or Daui, even when the intermediate value is zero:
+ // Daui(dst, lhs, 0).
+ if ((rhs_imm_upper != 0) || (rhs_imm_low == 0)) {
+ __ Daui(dst, tmp, rhs_imm_upper);
+ }
+ if (rhs_imm_high != 0) {
+ __ Dahi(dst, rhs_imm_high);
+ }
+ if (rhs_imm_top != 0) {
+ __ Dati(dst, rhs_imm_top);
+ }
+ }
+ } else if (instruction->IsAdd()) {
+ __ Daddu(dst, lhs, rhs_reg);
+ } else {
+ DCHECK(instruction->IsSub());
__ Dsubu(dst, lhs, rhs_reg);
+ }
}
}
break;
@@ -2614,23 +2713,92 @@ void LocationsBuilderMIPS64::VisitBoundsCheck(HBoundsCheck* instruction) {
caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RequiresRegister());
+
+ HInstruction* index = instruction->InputAt(0);
+ HInstruction* length = instruction->InputAt(1);
+
+ bool const_index = false;
+ bool const_length = false;
+
+ if (index->IsConstant()) {
+ if (length->IsConstant()) {
+ const_index = true;
+ const_length = true;
+ } else {
+ int32_t index_value = index->AsIntConstant()->GetValue();
+ if (index_value < 0 || IsInt<16>(index_value + 1)) {
+ const_index = true;
+ }
+ }
+ } else if (length->IsConstant()) {
+ int32_t length_value = length->AsIntConstant()->GetValue();
+ if (IsUint<15>(length_value)) {
+ const_length = true;
+ }
+ }
+
+ locations->SetInAt(0, const_index
+ ? Location::ConstantLocation(index->AsConstant())
+ : Location::RequiresRegister());
+ locations->SetInAt(1, const_length
+ ? Location::ConstantLocation(length->AsConstant())
+ : Location::RequiresRegister());
}
void InstructionCodeGeneratorMIPS64::VisitBoundsCheck(HBoundsCheck* instruction) {
LocationSummary* locations = instruction->GetLocations();
- BoundsCheckSlowPathMIPS64* slow_path =
- new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS64(instruction);
- codegen_->AddSlowPath(slow_path);
-
- GpuRegister index = locations->InAt(0).AsRegister<GpuRegister>();
- GpuRegister length = locations->InAt(1).AsRegister<GpuRegister>();
+ Location index_loc = locations->InAt(0);
+ Location length_loc = locations->InAt(1);
+
+ if (length_loc.IsConstant()) {
+ int32_t length = length_loc.GetConstant()->AsIntConstant()->GetValue();
+ if (index_loc.IsConstant()) {
+ int32_t index = index_loc.GetConstant()->AsIntConstant()->GetValue();
+ if (index < 0 || index >= length) {
+ BoundsCheckSlowPathMIPS64* slow_path =
+ new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS64(instruction);
+ codegen_->AddSlowPath(slow_path);
+ __ Bc(slow_path->GetEntryLabel());
+ } else {
+ // Nothing to be done.
+ }
+ return;
+ }
- // length is limited by the maximum positive signed 32-bit integer.
- // Unsigned comparison of length and index checks for index < 0
- // and for length <= index simultaneously.
- __ Bgeuc(index, length, slow_path->GetEntryLabel());
+ BoundsCheckSlowPathMIPS64* slow_path =
+ new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS64(instruction);
+ codegen_->AddSlowPath(slow_path);
+ GpuRegister index = index_loc.AsRegister<GpuRegister>();
+ if (length == 0) {
+ __ Bc(slow_path->GetEntryLabel());
+ } else if (length == 1) {
+ __ Bnezc(index, slow_path->GetEntryLabel());
+ } else {
+ DCHECK(IsUint<15>(length)) << length;
+ __ Sltiu(TMP, index, length);
+ __ Beqzc(TMP, slow_path->GetEntryLabel());
+ }
+ } else {
+ GpuRegister length = length_loc.AsRegister<GpuRegister>();
+ BoundsCheckSlowPathMIPS64* slow_path =
+ new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS64(instruction);
+ codegen_->AddSlowPath(slow_path);
+ if (index_loc.IsConstant()) {
+ int32_t index = index_loc.GetConstant()->AsIntConstant()->GetValue();
+ if (index < 0) {
+ __ Bc(slow_path->GetEntryLabel());
+ } else if (index == 0) {
+ __ Blezc(length, slow_path->GetEntryLabel());
+ } else {
+ DCHECK(IsInt<16>(index + 1)) << index;
+ __ Sltiu(TMP, length, index + 1);
+ __ Bnezc(TMP, slow_path->GetEntryLabel());
+ }
+ } else {
+ GpuRegister index = index_loc.AsRegister<GpuRegister>();
+ __ Bgeuc(index, length, slow_path->GetEntryLabel());
+ }
+ }
}
// Temp is used for read barrier.
@@ -3143,12 +3311,7 @@ void InstructionCodeGeneratorMIPS64::DivRemByPowerOfTwo(HBinaryOperation* instru
__ Sra(TMP, dividend, 31);
__ Srl(TMP, TMP, 32 - ctz_imm);
__ Addu(out, dividend, TMP);
- if (IsUint<16>(abs_imm - 1)) {
- __ Andi(out, out, abs_imm - 1);
- } else {
- __ Sll(out, out, 32 - ctz_imm);
- __ Srl(out, out, 32 - ctz_imm);
- }
+ __ Ins(out, ZERO, ctz_imm, 32 - ctz_imm);
__ Subu(out, out, TMP);
}
} else {
@@ -3167,17 +3330,7 @@ void InstructionCodeGeneratorMIPS64::DivRemByPowerOfTwo(HBinaryOperation* instru
__ Dsrl32(TMP, TMP, 32 - ctz_imm);
}
__ Daddu(out, dividend, TMP);
- if (IsUint<16>(abs_imm - 1)) {
- __ Andi(out, out, abs_imm - 1);
- } else {
- if (ctz_imm > 32) {
- __ Dsll(out, out, 64 - ctz_imm);
- __ Dsrl(out, out, 64 - ctz_imm);
- } else {
- __ Dsll32(out, out, 32 - ctz_imm);
- __ Dsrl32(out, out, 32 - ctz_imm);
- }
- }
+ __ DblIns(out, ZERO, ctz_imm, 64 - ctz_imm);
__ Dsubu(out, out, TMP);
}
}
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 2a95b3775d..d479410f07 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -142,6 +142,7 @@ class ParallelMoveResolverMIPS64 : public ParallelMoveResolverWithSwap {
void RestoreScratch(int reg) OVERRIDE;
void Exchange(int index1, int index2, bool double_slot);
+ void ExchangeQuadSlots(int index1, int index2);
Mips64Assembler* GetAssembler() const;
diff --git a/compiler/optimizing/code_generator_utils.cc b/compiler/optimizing/code_generator_utils.cc
index 96fe2a17e6..dd47a1fc6c 100644
--- a/compiler/optimizing/code_generator_utils.cc
+++ b/compiler/optimizing/code_generator_utils.cc
@@ -15,9 +15,10 @@
*/
#include "code_generator_utils.h"
-#include "nodes.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "nodes.h"
namespace art {
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 2e8170ecc4..68532386e1 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -317,7 +317,14 @@ class TypeCheckSlowPathX86 : public SlowPathCode {
CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
__ Bind(GetEntryLabel());
- if (!is_fatal_) {
+ if (kPoisonHeapReferences &&
+ instruction_->IsCheckCast() &&
+ instruction_->AsCheckCast()->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) {
+ // First, unpoison the `cls` reference that was poisoned for direct memory comparison.
+ __ UnpoisonHeapReference(locations->InAt(1).AsRegister<Register>());
+ }
+
+ if (!is_fatal_ || instruction_->CanThrowIntoCatchBlock()) {
SaveLiveRegisters(codegen, locations);
}
@@ -5732,24 +5739,18 @@ X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
return codegen_->GetAssembler();
}
-void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
+void ParallelMoveResolverX86::MoveMemoryToMemory(int dst, int src, int number_of_words) {
ScratchRegisterScope ensure_scratch(
this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
- __ movl(temp_reg, Address(ESP, src + stack_offset));
- __ movl(Address(ESP, dst + stack_offset), temp_reg);
-}
-void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
- ScratchRegisterScope ensure_scratch(
- this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
- Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
- int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
- __ movl(temp_reg, Address(ESP, src + stack_offset));
- __ movl(Address(ESP, dst + stack_offset), temp_reg);
- __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
- __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
+ // Now that temp register is available (possibly spilled), move blocks of memory.
+ for (int i = 0; i < number_of_words; i++) {
+ __ movl(temp_reg, Address(ESP, src + stack_offset));
+ __ movl(Address(ESP, dst + stack_offset), temp_reg);
+ stack_offset += kX86WordSize;
+ }
}
void ParallelMoveResolverX86::EmitMove(size_t index) {
@@ -5800,7 +5801,7 @@ void ParallelMoveResolverX86::EmitMove(size_t index) {
__ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
} else {
DCHECK(destination.IsStackSlot());
- MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
+ MoveMemoryToMemory(destination.GetStackIndex(), source.GetStackIndex(), 1);
}
} else if (source.IsDoubleStackSlot()) {
if (destination.IsRegisterPair()) {
@@ -5811,11 +5812,15 @@ void ParallelMoveResolverX86::EmitMove(size_t index) {
__ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
} else {
DCHECK(destination.IsDoubleStackSlot()) << destination;
- MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
+ MoveMemoryToMemory(destination.GetStackIndex(), source.GetStackIndex(), 2);
}
} else if (source.IsSIMDStackSlot()) {
- DCHECK(destination.IsFpuRegister());
- __ movups(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
+ if (destination.IsFpuRegister()) {
+ __ movups(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
+ } else {
+ DCHECK(destination.IsSIMDStackSlot());
+ MoveMemoryToMemory(destination.GetStackIndex(), source.GetStackIndex(), 4);
+ }
} else if (source.IsConstant()) {
HConstant* constant = source.GetConstant();
if (constant->IsIntConstant() || constant->IsNullConstant()) {
@@ -5915,7 +5920,16 @@ void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
__ movd(reg, temp_reg);
}
-void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
+void ParallelMoveResolverX86::Exchange128(XmmRegister reg, int mem) {
+ size_t extra_slot = 4 * kX86WordSize;
+ __ subl(ESP, Immediate(extra_slot));
+ __ movups(Address(ESP, 0), XmmRegister(reg));
+ ExchangeMemory(0, mem + extra_slot, 4);
+ __ movups(XmmRegister(reg), Address(ESP, 0));
+ __ addl(ESP, Immediate(extra_slot));
+}
+
+void ParallelMoveResolverX86::ExchangeMemory(int mem1, int mem2, int number_of_words) {
ScratchRegisterScope ensure_scratch1(
this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
@@ -5925,10 +5939,15 @@ void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
- __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
- __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
- __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
- __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
+
+ // Now that temp registers are available (possibly spilled), exchange blocks of memory.
+ for (int i = 0; i < number_of_words; i++) {
+ __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
+ __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
+ __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
+ __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
+ stack_offset += kX86WordSize;
+ }
}
void ParallelMoveResolverX86::EmitSwap(size_t index) {
@@ -5947,7 +5966,7 @@ void ParallelMoveResolverX86::EmitSwap(size_t index) {
} else if (source.IsStackSlot() && destination.IsRegister()) {
Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
} else if (source.IsStackSlot() && destination.IsStackSlot()) {
- Exchange(destination.GetStackIndex(), source.GetStackIndex());
+ ExchangeMemory(destination.GetStackIndex(), source.GetStackIndex(), 1);
} else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
// Use XOR Swap algorithm to avoid a temporary.
DCHECK_NE(source.reg(), destination.reg());
@@ -5983,8 +6002,13 @@ void ParallelMoveResolverX86::EmitSwap(size_t index) {
// Move the high double to the low double.
__ psrldq(reg, Immediate(8));
} else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
- Exchange(destination.GetStackIndex(), source.GetStackIndex());
- Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
+ ExchangeMemory(destination.GetStackIndex(), source.GetStackIndex(), 2);
+ } else if (source.IsSIMDStackSlot() && destination.IsSIMDStackSlot()) {
+ ExchangeMemory(destination.GetStackIndex(), source.GetStackIndex(), 4);
+ } else if (source.IsFpuRegister() && destination.IsSIMDStackSlot()) {
+ Exchange128(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
+ } else if (destination.IsFpuRegister() && source.IsSIMDStackSlot()) {
+ Exchange128(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
} else {
LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
}
@@ -6196,8 +6220,8 @@ void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
SlowPathCode* slow_path, Register class_reg) {
__ cmpb(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
- Immediate(mirror::Class::kStatusInitialized));
- __ j(kLess, slow_path->GetEntryLabel());
+ Immediate(enum_cast<>(ClassStatus::kInitialized)));
+ __ j(kBelow, slow_path->GetEntryLabel());
__ Bind(slow_path->GetExitLabel());
// No need for memory fence, thanks to the X86 memory model.
}
@@ -6369,7 +6393,7 @@ static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
// interface pointer, one for loading the current interface.
// The other checks have one temp for loading the object's class.
static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
- if (type_check_kind == TypeCheckKind::kInterfaceCheck && !kPoisonHeapReferences) {
+ if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
return 2;
}
return 1 + NumberOfInstanceOfTemps(type_check_kind);
@@ -6383,11 +6407,12 @@ void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
case TypeCheckKind::kExactCheck:
case TypeCheckKind::kAbstractClassCheck:
case TypeCheckKind::kClassHierarchyCheck:
- case TypeCheckKind::kArrayObjectCheck:
- call_kind =
- kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
- baker_read_barrier_slow_path = kUseBakerReadBarrier;
+ case TypeCheckKind::kArrayObjectCheck: {
+ bool needs_read_barrier = CodeGenerator::InstanceOfNeedsReadBarrier(instruction);
+ call_kind = needs_read_barrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
+ baker_read_barrier_slow_path = kUseBakerReadBarrier && needs_read_barrier;
break;
+ }
case TypeCheckKind::kArrayCheck:
case TypeCheckKind::kUnresolvedCheck:
case TypeCheckKind::kInterfaceCheck:
@@ -6435,12 +6460,14 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
switch (type_check_kind) {
case TypeCheckKind::kExactCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
- kCompilerReadBarrierOption);
+ read_barrier_option);
if (cls.IsRegister()) {
__ cmpl(out, cls.AsRegister<Register>());
} else {
@@ -6456,12 +6483,14 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
}
case TypeCheckKind::kAbstractClassCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// If the class is abstract, we eagerly fetch the super class of the
// object to avoid doing a comparison we know will fail.
NearLabel loop;
@@ -6471,7 +6500,7 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
out_loc,
super_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
__ testl(out, out);
// If `out` is null, we use it for the result, and jump to `done`.
__ j(kEqual, &done);
@@ -6490,12 +6519,14 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
}
case TypeCheckKind::kClassHierarchyCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// Walk over the class hierarchy to find a match.
NearLabel loop, success;
__ Bind(&loop);
@@ -6511,7 +6542,7 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
out_loc,
super_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
__ testl(out, out);
__ j(kNotEqual, &loop);
// If `out` is null, we use it for the result, and jump to `done`.
@@ -6525,12 +6556,14 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
}
case TypeCheckKind::kArrayObjectCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// Do an exact check.
NearLabel exact_check;
if (cls.IsRegister()) {
@@ -6546,7 +6579,7 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
out_loc,
component_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
__ testl(out, out);
// If `out` is null, we use it for the result, and jump to `done`.
__ j(kEqual, &done);
@@ -6630,30 +6663,9 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
}
}
-static bool IsTypeCheckSlowPathFatal(TypeCheckKind type_check_kind, bool throws_into_catch) {
- switch (type_check_kind) {
- case TypeCheckKind::kExactCheck:
- case TypeCheckKind::kAbstractClassCheck:
- case TypeCheckKind::kClassHierarchyCheck:
- case TypeCheckKind::kArrayObjectCheck:
- return !throws_into_catch && !kEmitCompilerReadBarrier;
- case TypeCheckKind::kInterfaceCheck:
- return !throws_into_catch && !kEmitCompilerReadBarrier && !kPoisonHeapReferences;
- case TypeCheckKind::kArrayCheck:
- case TypeCheckKind::kUnresolvedCheck:
- return false;
- }
- LOG(FATAL) << "Unreachable";
- UNREACHABLE();
-}
-
void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
- bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
- LocationSummary::CallKind call_kind =
- IsTypeCheckSlowPathFatal(type_check_kind, throws_into_catch)
- ? LocationSummary::kNoCall
- : LocationSummary::kCallOnSlowPath;
+ LocationSummary::CallKind call_kind = CodeGenerator::GetCheckCastCallKind(instruction);
LocationSummary* locations =
new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
locations->SetInAt(0, Location::RequiresRegister());
@@ -6691,12 +6703,7 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
const uint32_t object_array_data_offset =
mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
- // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
- // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
- // read barriers is done for performance and code size reasons.
- bool is_type_check_slow_path_fatal =
- IsTypeCheckSlowPathFatal(type_check_kind, instruction->CanThrowIntoCatchBlock());
-
+ bool is_type_check_slow_path_fatal = CodeGenerator::IsTypeCheckSlowPathFatal(instruction);
SlowPathCode* type_check_slow_path =
new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86(
instruction, is_type_check_slow_path_fatal);
@@ -6849,44 +6856,40 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
break;
case TypeCheckKind::kInterfaceCheck: {
- // Fast path for the interface check. Since we compare with a memory location in the inner
- // loop we would need to have cls poisoned. However unpoisoning cls would reset the
- // conditional flags and cause the conditional jump to be incorrect. Therefore we just jump
- // to the slow path if we are running under poisoning.
- if (!kPoisonHeapReferences) {
- // Try to avoid read barriers to improve the fast path. We can not get false positives by
- // doing this.
- // /* HeapReference<Class> */ temp = obj->klass_
- GenerateReferenceLoadTwoRegisters(instruction,
- temp_loc,
- obj_loc,
- class_offset,
- kWithoutReadBarrier);
-
- // /* HeapReference<Class> */ temp = temp->iftable_
- GenerateReferenceLoadTwoRegisters(instruction,
- temp_loc,
- temp_loc,
- iftable_offset,
- kWithoutReadBarrier);
- // Iftable is never null.
- __ movl(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
- // Loop through the iftable and check if any class matches.
- NearLabel start_loop;
- __ Bind(&start_loop);
- // Need to subtract first to handle the empty array case.
- __ subl(maybe_temp2_loc.AsRegister<Register>(), Immediate(2));
- __ j(kNegative, type_check_slow_path->GetEntryLabel());
- // Go to next interface if the classes do not match.
- __ cmpl(cls.AsRegister<Register>(),
- CodeGeneratorX86::ArrayAddress(temp,
- maybe_temp2_loc,
- TIMES_4,
- object_array_data_offset));
- __ j(kNotEqual, &start_loop);
- } else {
- __ jmp(type_check_slow_path->GetEntryLabel());
- }
+ // Fast path for the interface check. Try to avoid read barriers to improve the fast path.
+ // We can not get false positives by doing this.
+ // /* HeapReference<Class> */ temp = obj->klass_
+ GenerateReferenceLoadTwoRegisters(instruction,
+ temp_loc,
+ obj_loc,
+ class_offset,
+ kWithoutReadBarrier);
+
+ // /* HeapReference<Class> */ temp = temp->iftable_
+ GenerateReferenceLoadTwoRegisters(instruction,
+ temp_loc,
+ temp_loc,
+ iftable_offset,
+ kWithoutReadBarrier);
+ // Iftable is never null.
+ __ movl(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
+ // Maybe poison the `cls` for direct comparison with memory.
+ __ MaybePoisonHeapReference(cls.AsRegister<Register>());
+ // Loop through the iftable and check if any class matches.
+ NearLabel start_loop;
+ __ Bind(&start_loop);
+ // Need to subtract first to handle the empty array case.
+ __ subl(maybe_temp2_loc.AsRegister<Register>(), Immediate(2));
+ __ j(kNegative, type_check_slow_path->GetEntryLabel());
+ // Go to next interface if the classes do not match.
+ __ cmpl(cls.AsRegister<Register>(),
+ CodeGeneratorX86::ArrayAddress(temp,
+ maybe_temp2_loc,
+ TIMES_4,
+ object_array_data_offset));
+ __ j(kNotEqual, &start_loop);
+ // If `cls` was poisoned above, unpoison it.
+ __ MaybeUnpoisonHeapReference(cls.AsRegister<Register>());
break;
}
}
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 176e4dfda0..0082853184 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -20,7 +20,7 @@
#include "arch/x86/instruction_set_features_x86.h"
#include "base/enums.h"
#include "code_generator.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "driver/compiler_options.h"
#include "nodes.h"
#include "parallel_move_resolver.h"
@@ -139,10 +139,10 @@ class ParallelMoveResolverX86 : public ParallelMoveResolverWithSwap {
private:
void Exchange(Register reg, int mem);
- void Exchange(int mem1, int mem2);
void Exchange32(XmmRegister reg, int mem);
- void MoveMemoryToMemory32(int dst, int src);
- void MoveMemoryToMemory64(int dst, int src);
+ void Exchange128(XmmRegister reg, int mem);
+ void ExchangeMemory(int mem1, int mem2, int number_of_words);
+ void MoveMemoryToMemory(int dst, int src, int number_of_words);
CodeGeneratorX86* const codegen_;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index e25688c9a3..1f8d822507 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -337,7 +337,14 @@ class TypeCheckSlowPathX86_64 : public SlowPathCode {
CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
__ Bind(GetEntryLabel());
- if (!is_fatal_) {
+ if (kPoisonHeapReferences &&
+ instruction_->IsCheckCast() &&
+ instruction_->AsCheckCast()->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) {
+ // First, unpoison the `cls` reference that was poisoned for direct memory comparison.
+ __ UnpoisonHeapReference(locations->InAt(1).AsRegister<CpuRegister>());
+ }
+
+ if (!is_fatal_ || instruction_->CanThrowIntoCatchBlock()) {
SaveLiveRegisters(codegen, locations);
}
@@ -5220,9 +5227,17 @@ void ParallelMoveResolverX86_64::EmitMove(size_t index) {
__ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
}
} else if (source.IsSIMDStackSlot()) {
- DCHECK(destination.IsFpuRegister());
- __ movups(destination.AsFpuRegister<XmmRegister>(),
- Address(CpuRegister(RSP), source.GetStackIndex()));
+ if (destination.IsFpuRegister()) {
+ __ movups(destination.AsFpuRegister<XmmRegister>(),
+ Address(CpuRegister(RSP), source.GetStackIndex()));
+ } else {
+ DCHECK(destination.IsSIMDStackSlot());
+ size_t high = kX86_64WordSize;
+ __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
+ __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
+ __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex() + high));
+ __ movq(Address(CpuRegister(RSP), destination.GetStackIndex() + high), CpuRegister(TMP));
+ }
} else if (source.IsConstant()) {
HConstant* constant = source.GetConstant();
if (constant->IsIntConstant() || constant->IsNullConstant()) {
@@ -5290,19 +5305,6 @@ void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
__ movl(reg, CpuRegister(TMP));
}
-void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
- ScratchRegisterScope ensure_scratch(
- this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
-
- int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
- __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
- __ movl(CpuRegister(ensure_scratch.GetRegister()),
- Address(CpuRegister(RSP), mem2 + stack_offset));
- __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
- __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
- CpuRegister(ensure_scratch.GetRegister()));
-}
-
void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg1, CpuRegister reg2) {
__ movq(CpuRegister(TMP), reg1);
__ movq(reg1, reg2);
@@ -5315,19 +5317,6 @@ void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
__ movq(reg, CpuRegister(TMP));
}
-void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
- ScratchRegisterScope ensure_scratch(
- this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
-
- int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
- __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
- __ movq(CpuRegister(ensure_scratch.GetRegister()),
- Address(CpuRegister(RSP), mem2 + stack_offset));
- __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
- __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
- CpuRegister(ensure_scratch.GetRegister()));
-}
-
void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
__ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
__ movss(Address(CpuRegister(RSP), mem), reg);
@@ -5340,6 +5329,48 @@ void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
__ movd(reg, CpuRegister(TMP));
}
+void ParallelMoveResolverX86_64::Exchange128(XmmRegister reg, int mem) {
+ size_t extra_slot = 2 * kX86_64WordSize;
+ __ subq(CpuRegister(RSP), Immediate(extra_slot));
+ __ movups(Address(CpuRegister(RSP), 0), XmmRegister(reg));
+ ExchangeMemory64(0, mem + extra_slot, 2);
+ __ movups(XmmRegister(reg), Address(CpuRegister(RSP), 0));
+ __ addq(CpuRegister(RSP), Immediate(extra_slot));
+}
+
+void ParallelMoveResolverX86_64::ExchangeMemory32(int mem1, int mem2) {
+ ScratchRegisterScope ensure_scratch(
+ this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
+
+ int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
+ __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
+ __ movl(CpuRegister(ensure_scratch.GetRegister()),
+ Address(CpuRegister(RSP), mem2 + stack_offset));
+ __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
+ __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
+ CpuRegister(ensure_scratch.GetRegister()));
+}
+
+void ParallelMoveResolverX86_64::ExchangeMemory64(int mem1, int mem2, int num_of_qwords) {
+ ScratchRegisterScope ensure_scratch(
+ this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
+
+ int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
+
+ // Now that temp registers are available (possibly spilled), exchange blocks of memory.
+ for (int i = 0; i < num_of_qwords; i++) {
+ __ movq(CpuRegister(TMP),
+ Address(CpuRegister(RSP), mem1 + stack_offset));
+ __ movq(CpuRegister(ensure_scratch.GetRegister()),
+ Address(CpuRegister(RSP), mem2 + stack_offset));
+ __ movq(Address(CpuRegister(RSP), mem2 + stack_offset),
+ CpuRegister(TMP));
+ __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
+ CpuRegister(ensure_scratch.GetRegister()));
+ stack_offset += kX86_64WordSize;
+ }
+}
+
void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
MoveOperands* move = moves_[index];
Location source = move->GetSource();
@@ -5352,13 +5383,13 @@ void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
} else if (source.IsStackSlot() && destination.IsRegister()) {
Exchange32(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
} else if (source.IsStackSlot() && destination.IsStackSlot()) {
- Exchange32(destination.GetStackIndex(), source.GetStackIndex());
+ ExchangeMemory32(destination.GetStackIndex(), source.GetStackIndex());
} else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
Exchange64(source.AsRegister<CpuRegister>(), destination.GetStackIndex());
} else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
Exchange64(destination.AsRegister<CpuRegister>(), source.GetStackIndex());
} else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
- Exchange64(destination.GetStackIndex(), source.GetStackIndex());
+ ExchangeMemory64(destination.GetStackIndex(), source.GetStackIndex(), 1);
} else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
__ movd(CpuRegister(TMP), source.AsFpuRegister<XmmRegister>());
__ movaps(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
@@ -5371,6 +5402,12 @@ void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
Exchange64(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
} else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
Exchange64(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
+ } else if (source.IsSIMDStackSlot() && destination.IsSIMDStackSlot()) {
+ ExchangeMemory64(destination.GetStackIndex(), source.GetStackIndex(), 2);
+ } else if (source.IsFpuRegister() && destination.IsSIMDStackSlot()) {
+ Exchange128(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
+ } else if (destination.IsFpuRegister() && source.IsSIMDStackSlot()) {
+ Exchange128(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
} else {
LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
}
@@ -5389,8 +5426,8 @@ void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
SlowPathCode* slow_path, CpuRegister class_reg) {
__ cmpb(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
- Immediate(mirror::Class::kStatusInitialized));
- __ j(kLess, slow_path->GetEntryLabel());
+ Immediate(enum_cast<>(ClassStatus::kInitialized)));
+ __ j(kBelow, slow_path->GetEntryLabel());
__ Bind(slow_path->GetExitLabel());
// No need for memory fence, thanks to the x86-64 memory model.
}
@@ -5729,7 +5766,7 @@ void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
}
static bool CheckCastTypeCheckNeedsATemporary(TypeCheckKind type_check_kind) {
- if (type_check_kind == TypeCheckKind::kInterfaceCheck && !kPoisonHeapReferences) {
+ if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
// We need a temporary for holding the iftable length.
return true;
}
@@ -5756,11 +5793,12 @@ void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
case TypeCheckKind::kExactCheck:
case TypeCheckKind::kAbstractClassCheck:
case TypeCheckKind::kClassHierarchyCheck:
- case TypeCheckKind::kArrayObjectCheck:
- call_kind =
- kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
- baker_read_barrier_slow_path = kUseBakerReadBarrier;
+ case TypeCheckKind::kArrayObjectCheck: {
+ bool needs_read_barrier = CodeGenerator::InstanceOfNeedsReadBarrier(instruction);
+ call_kind = needs_read_barrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
+ baker_read_barrier_slow_path = kUseBakerReadBarrier && needs_read_barrier;
break;
+ }
case TypeCheckKind::kArrayCheck:
case TypeCheckKind::kUnresolvedCheck:
case TypeCheckKind::kInterfaceCheck:
@@ -5811,12 +5849,14 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
switch (type_check_kind) {
case TypeCheckKind::kExactCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
- kCompilerReadBarrierOption);
+ read_barrier_option);
if (cls.IsRegister()) {
__ cmpl(out, cls.AsRegister<CpuRegister>());
} else {
@@ -5837,12 +5877,14 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
}
case TypeCheckKind::kAbstractClassCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// If the class is abstract, we eagerly fetch the super class of the
// object to avoid doing a comparison we know will fail.
NearLabel loop, success;
@@ -5852,7 +5894,7 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
out_loc,
super_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
__ testl(out, out);
// If `out` is null, we use it for the result, and jump to `done`.
__ j(kEqual, &done);
@@ -5871,12 +5913,14 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
}
case TypeCheckKind::kClassHierarchyCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// Walk over the class hierarchy to find a match.
NearLabel loop, success;
__ Bind(&loop);
@@ -5892,7 +5936,7 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
out_loc,
super_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
__ testl(out, out);
__ j(kNotEqual, &loop);
// If `out` is null, we use it for the result, and jump to `done`.
@@ -5906,12 +5950,14 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
}
case TypeCheckKind::kArrayObjectCheck: {
+ ReadBarrierOption read_barrier_option =
+ CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
// /* HeapReference<Class> */ out = obj->klass_
GenerateReferenceLoadTwoRegisters(instruction,
out_loc,
obj_loc,
class_offset,
- kCompilerReadBarrierOption);
+ read_barrier_option);
// Do an exact check.
NearLabel exact_check;
if (cls.IsRegister()) {
@@ -5927,7 +5973,7 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
out_loc,
component_offset,
maybe_temp_loc,
- kCompilerReadBarrierOption);
+ read_barrier_option);
__ testl(out, out);
// If `out` is null, we use it for the result, and jump to `done`.
__ j(kEqual, &done);
@@ -6011,30 +6057,9 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
}
}
-static bool IsTypeCheckSlowPathFatal(TypeCheckKind type_check_kind, bool throws_into_catch) {
- switch (type_check_kind) {
- case TypeCheckKind::kExactCheck:
- case TypeCheckKind::kAbstractClassCheck:
- case TypeCheckKind::kClassHierarchyCheck:
- case TypeCheckKind::kArrayObjectCheck:
- return !throws_into_catch && !kEmitCompilerReadBarrier;
- case TypeCheckKind::kInterfaceCheck:
- return !throws_into_catch && !kEmitCompilerReadBarrier && !kPoisonHeapReferences;
- case TypeCheckKind::kArrayCheck:
- case TypeCheckKind::kUnresolvedCheck:
- return false;
- }
- LOG(FATAL) << "Unreachable";
- UNREACHABLE();
-}
-
void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
- bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
- bool is_fatal_slow_path = IsTypeCheckSlowPathFatal(type_check_kind, throws_into_catch);
- LocationSummary::CallKind call_kind = is_fatal_slow_path
- ? LocationSummary::kNoCall
- : LocationSummary::kCallOnSlowPath;
+ LocationSummary::CallKind call_kind = CodeGenerator::GetCheckCastCallKind(instruction);
LocationSummary* locations =
new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
locations->SetInAt(0, Location::RequiresRegister());
@@ -6075,11 +6100,7 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
const uint32_t object_array_data_offset =
mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
- // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
- // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
- // read barriers is done for performance and code size reasons.
- bool is_type_check_slow_path_fatal =
- IsTypeCheckSlowPathFatal(type_check_kind, instruction->CanThrowIntoCatchBlock());
+ bool is_type_check_slow_path_fatal = CodeGenerator::IsTypeCheckSlowPathFatal(instruction);
SlowPathCode* type_check_slow_path =
new (codegen_->GetScopedAllocator()) TypeCheckSlowPathX86_64(
instruction, is_type_check_slow_path_fatal);
@@ -6233,42 +6254,40 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
}
case TypeCheckKind::kInterfaceCheck:
- // Fast path for the interface check. We always go slow path for heap poisoning since
- // unpoisoning cls would require an extra temp.
- if (!kPoisonHeapReferences) {
- // Try to avoid read barriers to improve the fast path. We can not get false positives by
- // doing this.
- // /* HeapReference<Class> */ temp = obj->klass_
- GenerateReferenceLoadTwoRegisters(instruction,
- temp_loc,
- obj_loc,
- class_offset,
- kWithoutReadBarrier);
-
- // /* HeapReference<Class> */ temp = temp->iftable_
- GenerateReferenceLoadTwoRegisters(instruction,
- temp_loc,
- temp_loc,
- iftable_offset,
- kWithoutReadBarrier);
- // Iftable is never null.
- __ movl(maybe_temp2_loc.AsRegister<CpuRegister>(), Address(temp, array_length_offset));
- // Loop through the iftable and check if any class matches.
- NearLabel start_loop;
- __ Bind(&start_loop);
- // Need to subtract first to handle the empty array case.
- __ subl(maybe_temp2_loc.AsRegister<CpuRegister>(), Immediate(2));
- __ j(kNegative, type_check_slow_path->GetEntryLabel());
- // Go to next interface if the classes do not match.
- __ cmpl(cls.AsRegister<CpuRegister>(),
- CodeGeneratorX86_64::ArrayAddress(temp,
- maybe_temp2_loc,
- TIMES_4,
- object_array_data_offset));
- __ j(kNotEqual, &start_loop); // Return if same class.
- } else {
- __ jmp(type_check_slow_path->GetEntryLabel());
- }
+ // Fast path for the interface check. Try to avoid read barriers to improve the fast path.
+ // We can not get false positives by doing this.
+ // /* HeapReference<Class> */ temp = obj->klass_
+ GenerateReferenceLoadTwoRegisters(instruction,
+ temp_loc,
+ obj_loc,
+ class_offset,
+ kWithoutReadBarrier);
+
+ // /* HeapReference<Class> */ temp = temp->iftable_
+ GenerateReferenceLoadTwoRegisters(instruction,
+ temp_loc,
+ temp_loc,
+ iftable_offset,
+ kWithoutReadBarrier);
+ // Iftable is never null.
+ __ movl(maybe_temp2_loc.AsRegister<CpuRegister>(), Address(temp, array_length_offset));
+ // Maybe poison the `cls` for direct comparison with memory.
+ __ MaybePoisonHeapReference(cls.AsRegister<CpuRegister>());
+ // Loop through the iftable and check if any class matches.
+ NearLabel start_loop;
+ __ Bind(&start_loop);
+ // Need to subtract first to handle the empty array case.
+ __ subl(maybe_temp2_loc.AsRegister<CpuRegister>(), Immediate(2));
+ __ j(kNegative, type_check_slow_path->GetEntryLabel());
+ // Go to next interface if the classes do not match.
+ __ cmpl(cls.AsRegister<CpuRegister>(),
+ CodeGeneratorX86_64::ArrayAddress(temp,
+ maybe_temp2_loc,
+ TIMES_4,
+ object_array_data_offset));
+ __ j(kNotEqual, &start_loop); // Return if same class.
+ // If `cls` was poisoned above, unpoison it.
+ __ MaybeUnpoisonHeapReference(cls.AsRegister<CpuRegister>());
break;
}
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 00c5c27470..e86123ef01 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -139,11 +139,12 @@ class ParallelMoveResolverX86_64 : public ParallelMoveResolverWithSwap {
private:
void Exchange32(CpuRegister reg, int mem);
void Exchange32(XmmRegister reg, int mem);
- void Exchange32(int mem1, int mem2);
void Exchange64(CpuRegister reg1, CpuRegister reg2);
void Exchange64(CpuRegister reg, int mem);
void Exchange64(XmmRegister reg, int mem);
- void Exchange64(int mem1, int mem2);
+ void Exchange128(XmmRegister reg, int mem);
+ void ExchangeMemory32(int mem1, int mem2);
+ void ExchangeMemory64(int mem1, int mem2, int num_of_qwords);
CodeGeneratorX86_64* const codegen_;
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index ba431a5b08..6eda289861 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -20,8 +20,8 @@
#include "base/macros.h"
#include "builder.h"
#include "codegen_test_utils.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction.h"
#include "driver/compiler_options.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index bb586bf096..6f11e628ee 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -113,7 +113,7 @@ void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) {
void HConstantFoldingVisitor::VisitTypeConversion(HTypeConversion* inst) {
// Constant folding: replace `TypeConversion(a)' with a constant at
// compile time if `a' is a constant.
- HConstant* constant = inst->AsTypeConversion()->TryStaticEvaluation();
+ HConstant* constant = inst->TryStaticEvaluation();
if (constant != nullptr) {
inst->ReplaceWith(constant);
inst->GetBlock()->RemoveInstruction(inst);
diff --git a/compiler/optimizing/data_type.h b/compiler/optimizing/data_type.h
index d253036479..548fe28cee 100644
--- a/compiler/optimizing/data_type.h
+++ b/compiler/optimizing/data_type.h
@@ -19,7 +19,8 @@
#include <iosfwd>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
namespace art {
diff --git a/compiler/optimizing/dominator_test.cc b/compiler/optimizing/dominator_test.cc
index 6bf3a5943f..572466eec8 100644
--- a/compiler/optimizing/dominator_test.cc
+++ b/compiler/optimizing/dominator_test.cc
@@ -16,7 +16,7 @@
#include "base/arena_allocator.h"
#include "builder.h"
-#include "dex_instruction.h"
+#include "dex/dex_instruction.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
diff --git a/compiler/optimizing/find_loops_test.cc b/compiler/optimizing/find_loops_test.cc
index c91752855b..b799fb4688 100644
--- a/compiler/optimizing/find_loops_test.cc
+++ b/compiler/optimizing/find_loops_test.cc
@@ -16,8 +16,8 @@
#include "base/arena_allocator.h"
#include "builder.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
#include "pretty_printer.h"
diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc
index 813772e9af..71c394ec1f 100644
--- a/compiler/optimizing/gvn.cc
+++ b/compiler/optimizing/gvn.cc
@@ -301,8 +301,11 @@ class ValueSet : public ArenaObject<kArenaAllocGvn> {
// Pure instructions are put into odd buckets to speed up deletion. Note that in the
// case of irreducible loops, we don't put pure instructions in odd buckets, as we
// need to delete them when entering the loop.
- if (instruction->GetSideEffects().HasDependencies() ||
- instruction->GetBlock()->GetGraph()->HasIrreducibleLoops()) {
+ // ClinitCheck is treated as a pure instruction since it's only executed
+ // once.
+ bool pure = !instruction->GetSideEffects().HasDependencies() ||
+ instruction->IsClinitCheck();
+ if (!pure || instruction->GetBlock()->GetGraph()->HasIrreducibleLoops()) {
return (hash_code << 1) | 0;
} else {
return (hash_code << 1) | 1;
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 2444e43d64..7a66d807cf 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -294,7 +294,7 @@ static dex::TypeIndex FindClassIndexIn(mirror::Class* cls,
// as there may be different class loaders. So only return the index if it's
// the right class already resolved with the class loader.
if (index.IsValid()) {
- ObjPtr<mirror::Class> resolved = ClassLinker::LookupResolvedType(
+ ObjPtr<mirror::Class> resolved = compilation_unit.GetClassLinker()->LookupResolvedType(
index, compilation_unit.GetDexCache().Get(), compilation_unit.GetClassLoader().Get());
if (resolved != cls) {
index = dex::TypeIndex::Invalid();
@@ -682,7 +682,7 @@ HInliner::InlineCacheType HInliner::ExtractClassesFromOfflineProfile(
<< "is invalid in location" << dex_cache->GetDexFile()->GetLocation();
return kInlineCacheNoData;
}
- ObjPtr<mirror::Class> clazz = ClassLinker::LookupResolvedType(
+ ObjPtr<mirror::Class> clazz = caller_compilation_unit_.GetClassLinker()->LookupResolvedType(
class_ref.type_index,
dex_cache,
caller_compilation_unit_.GetClassLoader().Get());
@@ -876,9 +876,9 @@ HInstruction* HInliner::AddTypeGuard(HInstruction* receiver,
load_class, codegen_, compiler_driver_, caller_compilation_unit_);
DCHECK(kind != HLoadClass::LoadKind::kInvalid)
<< "We should always be able to reference a class for inline caches";
- // Insert before setting the kind, as setting the kind affects the inputs.
- bb_cursor->InsertInstructionAfter(load_class, receiver_class);
+ // Load kind must be set before inserting the instruction into the graph.
load_class->SetLoadKind(kind);
+ bb_cursor->InsertInstructionAfter(load_class, receiver_class);
// In AOT mode, we will most likely load the class from BSS, which will involve a call
// to the runtime. In this case, the load instruction will need an environment so copy
// it from the invoke instruction.
@@ -1211,11 +1211,49 @@ bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction,
ReferenceTypeInfo receiver_type,
bool do_rtp,
bool cha_devirtualize) {
+ DCHECK(!invoke_instruction->IsIntrinsic());
HInstruction* return_replacement = nullptr;
uint32_t dex_pc = invoke_instruction->GetDexPc();
HInstruction* cursor = invoke_instruction->GetPrevious();
HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
- if (!TryBuildAndInline(invoke_instruction, method, receiver_type, &return_replacement)) {
+ bool should_remove_invoke_instruction = false;
+
+ // If invoke_instruction is devirtualized to a different method, give intrinsics
+ // another chance before we try to inline it.
+ bool wrong_invoke_type = false;
+ if (invoke_instruction->GetResolvedMethod() != method &&
+ IntrinsicsRecognizer::Recognize(invoke_instruction, method, &wrong_invoke_type)) {
+ MaybeRecordStat(stats_, MethodCompilationStat::kIntrinsicRecognized);
+ if (invoke_instruction->IsInvokeInterface()) {
+ // We don't intrinsify an invoke-interface directly.
+ // Replace the invoke-interface with an invoke-virtual.
+ HInvokeVirtual* new_invoke = new (graph_->GetAllocator()) HInvokeVirtual(
+ graph_->GetAllocator(),
+ invoke_instruction->GetNumberOfArguments(),
+ invoke_instruction->GetType(),
+ invoke_instruction->GetDexPc(),
+ invoke_instruction->GetDexMethodIndex(), // Use interface method's dex method index.
+ method,
+ method->GetMethodIndex());
+ HInputsRef inputs = invoke_instruction->GetInputs();
+ for (size_t index = 0; index != inputs.size(); ++index) {
+ new_invoke->SetArgumentAt(index, inputs[index]);
+ }
+ invoke_instruction->GetBlock()->InsertInstructionBefore(new_invoke, invoke_instruction);
+ new_invoke->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
+ if (invoke_instruction->GetType() == DataType::Type::kReference) {
+ new_invoke->SetReferenceTypeInfo(invoke_instruction->GetReferenceTypeInfo());
+ }
+ // Run intrinsic recognizer again to set new_invoke's intrinsic.
+ IntrinsicsRecognizer::Recognize(new_invoke, method, &wrong_invoke_type);
+ DCHECK_NE(new_invoke->GetIntrinsic(), Intrinsics::kNone);
+ return_replacement = new_invoke;
+ // invoke_instruction is replaced with new_invoke.
+ should_remove_invoke_instruction = true;
+ } else {
+ // invoke_instruction is intrinsified and stays.
+ }
+ } else if (!TryBuildAndInline(invoke_instruction, method, receiver_type, &return_replacement)) {
if (invoke_instruction->IsInvokeInterface()) {
DCHECK(!method->IsProxyMethod());
// Turn an invoke-interface into an invoke-virtual. An invoke-virtual is always
@@ -1258,26 +1296,27 @@ bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction,
new_invoke->SetReferenceTypeInfo(invoke_instruction->GetReferenceTypeInfo());
}
return_replacement = new_invoke;
- // Directly check if the new virtual can be recognized as an intrinsic.
- // This way, we avoid running a full recognition pass just to detect
- // these relative rare cases.
- bool wrong_invoke_type = false;
- if (IntrinsicsRecognizer::Recognize(new_invoke, &wrong_invoke_type)) {
- MaybeRecordStat(stats_, MethodCompilationStat::kIntrinsicRecognized);
- }
+ // invoke_instruction is replaced with new_invoke.
+ should_remove_invoke_instruction = true;
} else {
// TODO: Consider sharpening an invoke virtual once it is not dependent on the
// compiler driver.
return false;
}
+ } else {
+ // invoke_instruction is inlined.
+ should_remove_invoke_instruction = true;
}
+
if (cha_devirtualize) {
AddCHAGuard(invoke_instruction, dex_pc, cursor, bb_cursor);
}
if (return_replacement != nullptr) {
invoke_instruction->ReplaceWith(return_replacement);
}
- invoke_instruction->GetBlock()->RemoveInstruction(invoke_instruction);
+ if (should_remove_invoke_instruction) {
+ invoke_instruction->GetBlock()->RemoveInstruction(invoke_instruction);
+ }
FixUpReturnReferenceType(method, return_replacement);
if (do_rtp && ReturnTypeMoreSpecific(invoke_instruction, return_replacement)) {
// Actual return value has a more specific type than the method's declared
@@ -1342,26 +1381,26 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction,
bool same_dex_file = IsSameDexFile(*outer_compilation_unit_.GetDexFile(), *method->GetDexFile());
- const DexFile::CodeItem* code_item = method->GetCodeItem();
+ CodeItemDataAccessor accessor(method);
- if (code_item == nullptr) {
+ if (!accessor.HasCodeItem()) {
LOG_FAIL_NO_STAT()
<< "Method " << method->PrettyMethod() << " is not inlined because it is native";
return false;
}
size_t inline_max_code_units = compiler_driver_->GetCompilerOptions().GetInlineMaxCodeUnits();
- if (code_item->insns_size_in_code_units_ > inline_max_code_units) {
+ if (accessor.InsnsSizeInCodeUnits() > inline_max_code_units) {
LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedCodeItem)
<< "Method " << method->PrettyMethod()
<< " is not inlined because its code item is too big: "
- << code_item->insns_size_in_code_units_
+ << accessor.InsnsSizeInCodeUnits()
<< " > "
<< inline_max_code_units;
return false;
}
- if (code_item->tries_size_ != 0) {
+ if (accessor.TriesSize() != 0) {
LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedTryCatch)
<< "Method " << method->PrettyMethod() << " is not inlined because of try block";
return false;
@@ -1621,6 +1660,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction,
const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
const DexFile& callee_dex_file = *resolved_method->GetDexFile();
uint32_t method_index = resolved_method->GetDexMethodIndex();
+ CodeItemDebugInfoAccessor code_item_accessor(&callee_dex_file, code_item);
ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
Handle<mirror::DexCache> dex_cache = NewHandleIfDifferent(resolved_method->GetDexCache(),
caller_compilation_unit_.GetDexCache(),
@@ -1675,7 +1715,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction,
}
}
HGraphBuilder builder(callee_graph,
- code_item,
+ code_item_accessor,
&dex_compilation_unit,
&outer_compilation_unit_,
compiler_driver_,
@@ -1893,7 +1933,7 @@ void HInliner::RunOptimizations(HGraph* callee_graph,
// optimization that could lead to a HDeoptimize. The following optimizations do not.
HDeadCodeElimination dce(callee_graph, inline_stats_, "dead_code_elimination$inliner");
HConstantFolding fold(callee_graph, "constant_folding$inliner");
- HSharpening sharpening(callee_graph, codegen_, dex_compilation_unit, compiler_driver_, handles_);
+ HSharpening sharpening(callee_graph, codegen_, compiler_driver_);
InstructionSimplifier simplify(callee_graph, codegen_, compiler_driver_, inline_stats_);
IntrinsicsRecognizer intrinsics(callee_graph, inline_stats_);
@@ -1928,6 +1968,7 @@ void HInliner::RunOptimizations(HGraph* callee_graph,
return;
}
+ CodeItemDataAccessor accessor(&callee_graph->GetDexFile(), code_item);
HInliner inliner(callee_graph,
outermost_graph_,
codegen_,
@@ -1936,7 +1977,7 @@ void HInliner::RunOptimizations(HGraph* callee_graph,
compiler_driver_,
handles_,
inline_stats_,
- total_number_of_dex_registers_ + code_item->registers_size_,
+ total_number_of_dex_registers_ + accessor.RegistersSize(),
total_number_of_instructions_ + number_of_instructions,
this,
depth_ + 1);
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 042eee3204..e81d97b0a8 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -17,7 +17,7 @@
#ifndef ART_COMPILER_OPTIMIZING_INLINER_H_
#define ART_COMPILER_OPTIMIZING_INLINER_H_
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "invoke_type.h"
#include "jit/profile_compilation_info.h"
#include "optimization.h"
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 978d0c2225..72a93c1f77 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -23,7 +23,7 @@
#include "bytecode_utils.h"
#include "class_linker.h"
#include "data_type-inl.h"
-#include "dex_instruction-inl.h"
+#include "dex/dex_instruction-inl.h"
#include "driver/compiler_driver-inl.h"
#include "driver/dex_compilation_unit.h"
#include "driver/compiler_options.h"
@@ -39,6 +39,44 @@
namespace art {
+HInstructionBuilder::HInstructionBuilder(HGraph* graph,
+ HBasicBlockBuilder* block_builder,
+ SsaBuilder* ssa_builder,
+ const DexFile* dex_file,
+ const CodeItemDebugInfoAccessor& accessor,
+ DataType::Type return_type,
+ const DexCompilationUnit* dex_compilation_unit,
+ const DexCompilationUnit* outer_compilation_unit,
+ CompilerDriver* compiler_driver,
+ CodeGenerator* code_generator,
+ const uint8_t* interpreter_metadata,
+ OptimizingCompilerStats* compiler_stats,
+ VariableSizedHandleScope* handles,
+ ScopedArenaAllocator* local_allocator)
+ : allocator_(graph->GetAllocator()),
+ graph_(graph),
+ handles_(handles),
+ dex_file_(dex_file),
+ code_item_accessor_(accessor),
+ return_type_(return_type),
+ block_builder_(block_builder),
+ ssa_builder_(ssa_builder),
+ compiler_driver_(compiler_driver),
+ code_generator_(code_generator),
+ dex_compilation_unit_(dex_compilation_unit),
+ outer_compilation_unit_(outer_compilation_unit),
+ quicken_info_(interpreter_metadata),
+ compilation_stats_(compiler_stats),
+ local_allocator_(local_allocator),
+ locals_for_(local_allocator->Adapter(kArenaAllocGraphBuilder)),
+ current_block_(nullptr),
+ current_locals_(nullptr),
+ latest_result_(nullptr),
+ current_this_parameter_(nullptr),
+ loop_headers_(local_allocator->Adapter(kArenaAllocGraphBuilder)) {
+ loop_headers_.reserve(kDefaultNumberOfLoops);
+}
+
HBasicBlock* HInstructionBuilder::FindBlockStartingAt(uint32_t dex_pc) const {
return block_builder_->GetBlockAt(dex_pc);
}
@@ -273,7 +311,7 @@ static bool IsBlockPopulated(HBasicBlock* block) {
}
bool HInstructionBuilder::Build() {
- DCHECK(code_item_ != nullptr);
+ DCHECK(code_item_accessor_.HasCodeItem());
locals_for_.resize(
graph_->GetBlocks().size(),
ScopedArenaVector<HInstruction*>(local_allocator_->Adapter(kArenaAllocGraphBuilder)));
@@ -323,7 +361,7 @@ bool HInstructionBuilder::Build() {
quicken_index = block_builder_->GetQuickenIndex(block_dex_pc);
}
- for (const DexInstructionPcPair& pair : code_item_->Instructions(block_dex_pc)) {
+ for (const DexInstructionPcPair& pair : code_item_accessor_.InstructionsFrom(block_dex_pc)) {
if (current_block_ == nullptr) {
// The previous instruction ended this block.
break;
@@ -367,7 +405,7 @@ bool HInstructionBuilder::Build() {
}
void HInstructionBuilder::BuildIntrinsic(ArtMethod* method) {
- DCHECK(code_item_ == nullptr);
+ DCHECK(!code_item_accessor_.HasCodeItem());
DCHECK(method->IsIntrinsic());
locals_for_.resize(
@@ -442,17 +480,16 @@ ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() {
return false;
}
};
- const uint32_t num_instructions = code_item_->insns_size_in_code_units_;
ArenaBitVector* locations = ArenaBitVector::Create(local_allocator_,
- num_instructions,
+ code_item_accessor_.InsnsSizeInCodeUnits(),
/* expandable */ false,
kArenaAllocGraphBuilder);
locations->ClearAllBits();
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex_file_, code_item_);
- dex_file_->DecodeDebugPositionInfo(code_item_, debug_info_offset, Callback::Position, locations);
+ dex_file_->DecodeDebugPositionInfo(code_item_accessor_.DebugInfoOffset(),
+ Callback::Position,
+ locations);
// Instruction-specific tweaks.
- IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
- for (const DexInstructionPcPair& inst : instructions) {
+ for (const DexInstructionPcPair& inst : code_item_accessor_) {
switch (inst->Opcode()) {
case Instruction::MOVE_EXCEPTION: {
// Stop in native debugger after the exception has been moved.
@@ -461,7 +498,7 @@ ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() {
locations->ClearBit(inst.DexPc());
DexInstructionIterator next = std::next(DexInstructionIterator(inst));
DCHECK(next.DexPc() != inst.DexPc());
- if (next != instructions.end()) {
+ if (next != code_item_accessor_.end()) {
locations->SetBit(next.DexPc());
}
break;
@@ -796,7 +833,6 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in
ArtMethod* resolved_method =
class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- *dex_compilation_unit_->GetDexFile(),
method_idx,
dex_compilation_unit_->GetDexCache(),
class_loader,
@@ -831,7 +867,6 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in
return nullptr;
}
ObjPtr<mirror::Class> referenced_class = class_linker->LookupResolvedType(
- *dex_compilation_unit_->GetDexFile(),
dex_compilation_unit_->GetDexFile()->GetMethodId(method_idx).class_idx_,
dex_compilation_unit_->GetDexCache().Get(),
class_loader.Get());
@@ -1128,7 +1163,7 @@ void HInstructionBuilder::BuildConstructorFenceForAllocation(HInstruction* alloc
MethodCompilationStat::kConstructorFenceGeneratedNew);
}
-static bool IsSubClass(mirror::Class* to_test, mirror::Class* super_class)
+static bool IsSubClass(ObjPtr<mirror::Class> to_test, ObjPtr<mirror::Class> super_class)
REQUIRES_SHARED(Locks::mutator_lock_) {
return to_test != nullptr && !to_test->IsInterface() && to_test->IsSubClass(super_class);
}
@@ -1351,6 +1386,8 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio
uint16_t field_index;
if (instruction.IsQuickened()) {
if (!CanDecodeQuickenedInfo()) {
+ VLOG(compiler) << "Not compiled: Could not decode quickened instruction "
+ << instruction.Opcode();
return false;
}
field_index = LookupQuickenedInfo(quicken_index);
@@ -1422,8 +1459,8 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio
return true;
}
-static mirror::Class* GetClassFrom(CompilerDriver* driver,
- const DexCompilationUnit& compilation_unit) {
+static ObjPtr<mirror::Class> GetClassFrom(CompilerDriver* driver,
+ const DexCompilationUnit& compilation_unit) {
ScopedObjectAccess soa(Thread::Current());
Handle<mirror::ClassLoader> class_loader = compilation_unit.GetClassLoader();
Handle<mirror::DexCache> dex_cache = compilation_unit.GetDexCache();
@@ -1431,11 +1468,11 @@ static mirror::Class* GetClassFrom(CompilerDriver* driver,
return driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, &compilation_unit);
}
-mirror::Class* HInstructionBuilder::GetOutermostCompilingClass() const {
+ObjPtr<mirror::Class> HInstructionBuilder::GetOutermostCompilingClass() const {
return GetClassFrom(compiler_driver_, *outer_compilation_unit_);
}
-mirror::Class* HInstructionBuilder::GetCompilingClass() const {
+ObjPtr<mirror::Class> HInstructionBuilder::GetCompilingClass() const {
return GetClassFrom(compiler_driver_, *dex_compilation_unit_);
}
@@ -1482,12 +1519,10 @@ ArtField* HInstructionBuilder::ResolveField(uint16_t field_idx, bool is_static,
Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader();
Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass()));
- ArtField* resolved_field = class_linker->ResolveField(*dex_compilation_unit_->GetDexFile(),
- field_idx,
+ ArtField* resolved_field = class_linker->ResolveField(field_idx,
dex_compilation_unit_->GetDexCache(),
class_loader,
is_static);
-
if (UNLIKELY(resolved_field == nullptr)) {
// Clean up any exception left by type resolution.
soa.Self()->ClearException();
@@ -1523,7 +1558,7 @@ ArtField* HInstructionBuilder::ResolveField(uint16_t field_idx, bool is_static,
return resolved_field;
}
-bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction,
+void HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction,
uint32_t dex_pc,
bool is_put) {
uint32_t source_or_dest_reg = instruction.VRegA_21c();
@@ -1537,7 +1572,7 @@ bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction,
MethodCompilationStat::kUnresolvedField);
DataType::Type field_type = GetFieldAccessType(*dex_file_, field_index);
BuildUnresolvedStaticFieldAccess(instruction, dex_pc, is_put, field_type);
- return true;
+ return;
}
DataType::Type field_type = GetFieldAccessType(*dex_file_, field_index);
@@ -1555,7 +1590,7 @@ bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction,
MaybeRecordStat(compilation_stats_,
MethodCompilationStat::kUnresolvedFieldNotAFastAccess);
BuildUnresolvedStaticFieldAccess(instruction, dex_pc, is_put, field_type);
- return true;
+ return;
}
HInstruction* cls = constant;
@@ -1591,7 +1626,6 @@ bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction,
dex_pc));
UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
}
- return true;
}
void HInstructionBuilder::BuildCheckedDivRem(uint16_t out_vreg,
@@ -1711,7 +1745,8 @@ void HInstructionBuilder::BuildFillArrayData(const Instruction& instruction, uin
int32_t payload_offset = instruction.VRegB_31t() + dex_pc;
const Instruction::ArrayDataPayload* payload =
- reinterpret_cast<const Instruction::ArrayDataPayload*>(code_item_->insns_ + payload_offset);
+ reinterpret_cast<const Instruction::ArrayDataPayload*>(
+ code_item_accessor_.Insns() + payload_offset);
const uint8_t* data = payload->data;
uint32_t element_count = payload->element_count;
@@ -1799,6 +1834,17 @@ static TypeCheckKind ComputeTypeCheckKind(Handle<mirror::Class> cls)
}
}
+void HInstructionBuilder::BuildLoadString(dex::StringIndex string_index, uint32_t dex_pc) {
+ HLoadString* load_string =
+ new (allocator_) HLoadString(graph_->GetCurrentMethod(), string_index, *dex_file_, dex_pc);
+ HSharpening::ProcessLoadString(load_string,
+ code_generator_,
+ compiler_driver_,
+ *dex_compilation_unit_,
+ handles_);
+ AppendInstruction(load_string);
+}
+
HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index, uint32_t dex_pc) {
ScopedObjectAccess soa(Thread::Current());
const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
@@ -1811,7 +1857,7 @@ HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index, uint3
if (klass->IsPublic()) {
needs_access_check = false;
} else {
- mirror::Class* compiling_class = GetCompilingClass();
+ ObjPtr<mirror::Class> compiling_class = GetCompilingClass();
if (compiling_class != nullptr && compiling_class->CanAccess(klass.Get())) {
needs_access_check = false;
}
@@ -1856,9 +1902,9 @@ HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index,
// We actually cannot reference this class, we're forced to bail.
return nullptr;
}
- // Append the instruction first, as setting the load kind affects the inputs.
- AppendInstruction(load_class);
+ // Load kind must be set before inserting the instruction into the graph.
load_class->SetLoadKind(load_kind);
+ AppendInstruction(load_class);
return load_class;
}
@@ -2058,6 +2104,8 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
uint16_t method_idx;
if (instruction.Opcode() == Instruction::INVOKE_VIRTUAL_QUICK) {
if (!CanDecodeQuickenedInfo()) {
+ VLOG(compiler) << "Not compiled: Could not decode quickened instruction "
+ << instruction.Opcode();
return false;
}
method_idx = LookupQuickenedInfo(quicken_index);
@@ -2083,6 +2131,8 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
uint16_t method_idx;
if (instruction.Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK) {
if (!CanDecodeQuickenedInfo()) {
+ VLOG(compiler) << "Not compiled: Could not decode quickened instruction "
+ << instruction.Opcode();
return false;
}
method_idx = LookupQuickenedInfo(quicken_index);
@@ -2758,7 +2808,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
case Instruction::IGET_CHAR_QUICK:
case Instruction::IGET_SHORT:
case Instruction::IGET_SHORT_QUICK: {
- if (!BuildInstanceFieldAccess(instruction, dex_pc, false, quicken_index)) {
+ if (!BuildInstanceFieldAccess(instruction, dex_pc, /* is_put */ false, quicken_index)) {
return false;
}
break;
@@ -2778,7 +2828,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
case Instruction::IPUT_CHAR_QUICK:
case Instruction::IPUT_SHORT:
case Instruction::IPUT_SHORT_QUICK: {
- if (!BuildInstanceFieldAccess(instruction, dex_pc, true, quicken_index)) {
+ if (!BuildInstanceFieldAccess(instruction, dex_pc, /* is_put */ true, quicken_index)) {
return false;
}
break;
@@ -2791,9 +2841,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
case Instruction::SGET_BYTE:
case Instruction::SGET_CHAR:
case Instruction::SGET_SHORT: {
- if (!BuildStaticFieldAccess(instruction, dex_pc, false)) {
- return false;
- }
+ BuildStaticFieldAccess(instruction, dex_pc, /* is_put */ false);
break;
}
@@ -2804,9 +2852,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
case Instruction::SPUT_BYTE:
case Instruction::SPUT_CHAR:
case Instruction::SPUT_SHORT: {
- if (!BuildStaticFieldAccess(instruction, dex_pc, true)) {
- return false;
- }
+ BuildStaticFieldAccess(instruction, dex_pc, /* is_put */ true);
break;
}
@@ -2837,20 +2883,14 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
case Instruction::CONST_STRING: {
dex::StringIndex string_index(instruction.VRegB_21c());
- AppendInstruction(new (allocator_) HLoadString(graph_->GetCurrentMethod(),
- string_index,
- *dex_file_,
- dex_pc));
+ BuildLoadString(string_index, dex_pc);
UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
break;
}
case Instruction::CONST_STRING_JUMBO: {
dex::StringIndex string_index(instruction.VRegB_31c());
- AppendInstruction(new (allocator_) HLoadString(graph_->GetCurrentMethod(),
- string_index,
- *dex_file_,
- dex_pc));
+ BuildLoadString(string_index, dex_pc);
UpdateLocal(instruction.VRegA_31c(), current_block_->GetLastInstruction());
break;
}
@@ -2930,7 +2970,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
ObjPtr<mirror::Class> HInstructionBuilder::LookupResolvedType(
dex::TypeIndex type_index,
const DexCompilationUnit& compilation_unit) const {
- return ClassLinker::LookupResolvedType(
+ return compilation_unit.GetClassLinker()->LookupResolvedType(
type_index, compilation_unit.GetDexCache().Get(), compilation_unit.GetClassLoader().Get());
}
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index f551ac4280..708a09711a 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -20,8 +20,9 @@
#include "base/scoped_arena_allocator.h"
#include "base/scoped_arena_containers.h"
#include "data_type.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/code_item_accessors.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
#include "handle.h"
#include "nodes.h"
#include "quicken_info.h"
@@ -50,7 +51,7 @@ class HInstructionBuilder : public ValueObject {
HBasicBlockBuilder* block_builder,
SsaBuilder* ssa_builder,
const DexFile* dex_file,
- const DexFile::CodeItem* code_item,
+ const CodeItemDebugInfoAccessor& accessor,
DataType::Type return_type,
const DexCompilationUnit* dex_compilation_unit,
const DexCompilationUnit* outer_compilation_unit,
@@ -59,30 +60,7 @@ class HInstructionBuilder : public ValueObject {
const uint8_t* interpreter_metadata,
OptimizingCompilerStats* compiler_stats,
VariableSizedHandleScope* handles,
- ScopedArenaAllocator* local_allocator)
- : allocator_(graph->GetAllocator()),
- graph_(graph),
- handles_(handles),
- dex_file_(dex_file),
- code_item_(code_item),
- return_type_(return_type),
- block_builder_(block_builder),
- ssa_builder_(ssa_builder),
- compiler_driver_(compiler_driver),
- code_generator_(code_generator),
- dex_compilation_unit_(dex_compilation_unit),
- outer_compilation_unit_(outer_compilation_unit),
- quicken_info_(interpreter_metadata),
- compilation_stats_(compiler_stats),
- local_allocator_(local_allocator),
- locals_for_(local_allocator->Adapter(kArenaAllocGraphBuilder)),
- current_block_(nullptr),
- current_locals_(nullptr),
- latest_result_(nullptr),
- current_this_parameter_(nullptr),
- loop_headers_(local_allocator->Adapter(kArenaAllocGraphBuilder)) {
- loop_headers_.reserve(kDefaultNumberOfLoops);
- }
+ ScopedArenaAllocator* local_allocator);
bool Build();
void BuildIntrinsic(ArtMethod* method);
@@ -175,8 +153,8 @@ class HInstructionBuilder : public ValueObject {
uint32_t dex_pc,
bool is_put,
DataType::Type field_type);
- // Builds a static field access node and returns whether the instruction is supported.
- bool BuildStaticFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put);
+ // Builds a static field access node.
+ void BuildStaticFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put);
void BuildArrayAccess(const Instruction& instruction,
uint32_t dex_pc,
@@ -240,9 +218,10 @@ class HInstructionBuilder : public ValueObject {
// Builds an instruction sequence for a switch statement.
void BuildSwitch(const Instruction& instruction, uint32_t dex_pc);
- // Builds a `HLoadClass` loading the given `type_index`. If `outer` is true,
- // this method will use the outer class's dex file to lookup the type at
- // `type_index`.
+ // Builds a `HLoadString` loading the given `string_index`.
+ void BuildLoadString(dex::StringIndex string_index, uint32_t dex_pc);
+
+ // Builds a `HLoadClass` loading the given `type_index`.
HLoadClass* BuildLoadClass(dex::TypeIndex type_index, uint32_t dex_pc);
HLoadClass* BuildLoadClass(dex::TypeIndex type_index,
@@ -253,10 +232,10 @@ class HInstructionBuilder : public ValueObject {
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns the outer-most compiling method's class.
- mirror::Class* GetOutermostCompilingClass() const;
+ ObjPtr<mirror::Class> GetOutermostCompilingClass() const;
// Returns the class whose method is being compiled.
- mirror::Class* GetCompilingClass() const;
+ ObjPtr<mirror::Class> GetCompilingClass() const;
// Returns whether `type_index` points to the outer-most compiling method's class.
bool IsOutermostCompilingClass(dex::TypeIndex type_index) const;
@@ -328,7 +307,7 @@ class HInstructionBuilder : public ValueObject {
// The dex file where the method being compiled is, and the bytecode data.
const DexFile* const dex_file_;
- const DexFile::CodeItem* const code_item_; // null for intrinsic graph.
+ const CodeItemDebugInfoAccessor code_item_accessor_; // null for intrinsic graph.
// The return type of the method being compiled.
const DataType::Type return_type_;
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index bd20d28992..a42a85dc1d 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -1081,6 +1081,58 @@ static inline bool TryReplaceFieldOrArrayGetType(HInstruction* maybe_get, DataTy
}
}
+// The type conversion is only used for storing into a field/element of the
+// same/narrower size.
+static bool IsTypeConversionForStoringIntoNoWiderFieldOnly(HTypeConversion* type_conversion) {
+ if (type_conversion->HasEnvironmentUses()) {
+ return false;
+ }
+ DataType::Type input_type = type_conversion->GetInputType();
+ DataType::Type result_type = type_conversion->GetResultType();
+ if (!DataType::IsIntegralType(input_type) ||
+ !DataType::IsIntegralType(result_type) ||
+ input_type == DataType::Type::kInt64 ||
+ result_type == DataType::Type::kInt64) {
+ // Type conversion is needed if non-integer types are involved, or 64-bit
+ // types are involved, which may use different number of registers.
+ return false;
+ }
+ if (DataType::Size(input_type) >= DataType::Size(result_type)) {
+ // Type conversion is not necessary when storing to a field/element of the
+ // same/smaller size.
+ } else {
+ // We do not handle this case here.
+ return false;
+ }
+
+ // Check if the converted value is only used for storing into heap.
+ for (const HUseListNode<HInstruction*>& use : type_conversion->GetUses()) {
+ HInstruction* instruction = use.GetUser();
+ if (instruction->IsInstanceFieldSet() &&
+ instruction->AsInstanceFieldSet()->GetFieldType() == result_type) {
+ DCHECK_EQ(instruction->AsInstanceFieldSet()->GetValue(), type_conversion);
+ continue;
+ }
+ if (instruction->IsStaticFieldSet() &&
+ instruction->AsStaticFieldSet()->GetFieldType() == result_type) {
+ DCHECK_EQ(instruction->AsStaticFieldSet()->GetValue(), type_conversion);
+ continue;
+ }
+ if (instruction->IsArraySet() &&
+ instruction->AsArraySet()->GetComponentType() == result_type &&
+ // not index use.
+ instruction->AsArraySet()->GetIndex() != type_conversion) {
+ DCHECK_EQ(instruction->AsArraySet()->GetValue(), type_conversion);
+ continue;
+ }
+ // The use is not as a store value, or the field/element type is not the
+ // same as the result_type, keep the type conversion.
+ return false;
+ }
+ // Codegen automatically handles the type conversion during the store.
+ return true;
+}
+
void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
HInstruction* input = instruction->GetInput();
DataType::Type input_type = input->GetType();
@@ -1168,16 +1220,13 @@ void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruct
RecordSimplification();
return;
}
- } else if (input->IsIntConstant()) {
- // Try to eliminate type conversion on int constant whose value falls into
- // the range of the result type.
- int32_t value = input->AsIntConstant()->GetValue();
- if (DataType::IsTypeConversionImplicit(value, result_type)) {
- instruction->ReplaceWith(input);
- instruction->GetBlock()->RemoveInstruction(instruction);
- RecordSimplification();
- return;
- }
+ }
+
+ if (IsTypeConversionForStoringIntoNoWiderFieldOnly(instruction)) {
+ instruction->ReplaceWith(input);
+ instruction->GetBlock()->RemoveInstruction(instruction);
+ RecordSimplification();
+ return;
}
}
@@ -2045,7 +2094,9 @@ void InstructionSimplifierVisitor::SimplifyStringEquals(HInvoke* instruction) {
optimizations.SetArgumentIsString();
} else if (kUseReadBarrier) {
DCHECK(instruction->GetResolvedMethod() != nullptr);
- DCHECK(instruction->GetResolvedMethod()->GetDeclaringClass()->IsStringClass());
+ DCHECK(instruction->GetResolvedMethod()->GetDeclaringClass()->IsStringClass() ||
+ // Object.equals() can be devirtualized to String.equals().
+ instruction->GetResolvedMethod()->GetDeclaringClass()->IsObjectClass());
Runtime* runtime = Runtime::Current();
// For AOT, we always assume that the boot image shall contain the String.class and
// we do not need a read barrier for boot image classes as they are non-moveable.
@@ -2276,7 +2327,7 @@ void InstructionSimplifierVisitor::SimplifyStringCharAt(HInvoke* invoke) {
HArrayLength* length = new (allocator) HArrayLength(str, dex_pc, /* is_string_length */ true);
invoke->GetBlock()->InsertInstructionBefore(length, invoke);
HBoundsCheck* bounds_check = new (allocator) HBoundsCheck(
- index, length, dex_pc, invoke->GetDexMethodIndex());
+ index, length, dex_pc, /* is_string_char_at */ true);
invoke->GetBlock()->InsertInstructionBefore(bounds_check, invoke);
HArrayGet* array_get = new (allocator) HArrayGet(str,
bounds_check,
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 77199242f5..6928b70df7 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -137,7 +137,7 @@ static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke)
case kVirtual:
// Call might be devirtualized.
- return (invoke_type == kVirtual || invoke_type == kDirect);
+ return (invoke_type == kVirtual || invoke_type == kDirect || invoke_type == kInterface);
case kSuper:
case kInterface:
@@ -148,8 +148,12 @@ static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke)
UNREACHABLE();
}
-bool IntrinsicsRecognizer::Recognize(HInvoke* invoke, /*out*/ bool* wrong_invoke_type) {
- ArtMethod* art_method = invoke->GetResolvedMethod();
+bool IntrinsicsRecognizer::Recognize(HInvoke* invoke,
+ ArtMethod* art_method,
+ /*out*/ bool* wrong_invoke_type) {
+ if (art_method == nullptr) {
+ art_method = invoke->GetResolvedMethod();
+ }
*wrong_invoke_type = false;
if (art_method == nullptr || !art_method->IsIntrinsic()) {
return false;
@@ -182,7 +186,7 @@ void IntrinsicsRecognizer::Run() {
HInstruction* inst = inst_it.Current();
if (inst->IsInvoke()) {
bool wrong_invoke_type = false;
- if (Recognize(inst->AsInvoke(), &wrong_invoke_type)) {
+ if (Recognize(inst->AsInvoke(), /* art_method */ nullptr, &wrong_invoke_type)) {
MaybeRecordStat(stats_, MethodCompilationStat::kIntrinsicRecognized);
} else if (wrong_invoke_type) {
LOG(WARNING)
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index c07a99032a..62991435c7 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -47,7 +47,7 @@ class IntrinsicsRecognizer : public HOptimization {
// Static helper that recognizes intrinsic call. Returns true on success.
// If it fails due to invoke type mismatch, wrong_invoke_type is set.
// Useful to recognize intrinsics on individual calls outside this full pass.
- static bool Recognize(HInvoke* invoke, /*out*/ bool* wrong_invoke_type)
+ static bool Recognize(HInvoke* invoke, ArtMethod* method, /*out*/ bool* wrong_invoke_type)
REQUIRES_SHARED(Locks::mutator_lock_);
static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition";
diff --git a/compiler/optimizing/licm.cc b/compiler/optimizing/licm.cc
index 7af1a20f98..d3a0376e9c 100644
--- a/compiler/optimizing/licm.cc
+++ b/compiler/optimizing/licm.cc
@@ -129,10 +129,25 @@ void LICM::Run() {
!inst_it.Done();
inst_it.Advance()) {
HInstruction* instruction = inst_it.Current();
- if (instruction->CanBeMoved()
- && (!instruction->CanThrow() || !found_first_non_hoisted_visible_instruction_in_loop)
- && !instruction->GetSideEffects().MayDependOn(loop_effects)
- && InputsAreDefinedBeforeLoop(instruction)) {
+ bool can_move = false;
+ if (instruction->CanBeMoved() && InputsAreDefinedBeforeLoop(instruction)) {
+ if (instruction->CanThrow()) {
+ if (!found_first_non_hoisted_visible_instruction_in_loop) {
+ DCHECK(instruction->GetBlock()->IsLoopHeader());
+ if (instruction->IsClinitCheck()) {
+ // clinit is only done once, and since all visible instructions
+ // in the loop header so far have been hoisted out, we can hoist
+ // the clinit check out also.
+ can_move = true;
+ } else if (!instruction->GetSideEffects().MayDependOn(loop_effects)) {
+ can_move = true;
+ }
+ }
+ } else if (!instruction->GetSideEffects().MayDependOn(loop_effects)) {
+ can_move = true;
+ }
+ }
+ if (can_move) {
// We need to update the environment if the instruction has a loop header
// phi in it.
if (instruction->NeedsEnvironment()) {
@@ -142,7 +157,9 @@ void LICM::Run() {
}
instruction->MoveBefore(pre_header->GetLastInstruction());
MaybeRecordStat(stats_, MethodCompilationStat::kLoopInvariantMoved);
- } else if (instruction->CanThrow() || instruction->DoesAnyWrite()) {
+ }
+
+ if (!can_move && (instruction->CanThrow() || instruction->DoesAnyWrite())) {
// If `instruction` can do something visible (throw or write),
// we cannot move further instructions that can throw.
found_first_non_hoisted_visible_instruction_in_loop = true;
diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc
index b2a9c0a8e7..43b63a73ef 100644
--- a/compiler/optimizing/linearize_test.cc
+++ b/compiler/optimizing/linearize_test.cc
@@ -21,8 +21,8 @@
#include "builder.h"
#include "code_generator.h"
#include "code_generator_x86.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction.h"
#include "driver/compiler_options.h"
#include "graph_visualizer.h"
#include "nodes.h"
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index ddcad5aed8..e45d7c820c 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -19,8 +19,8 @@
#include "builder.h"
#include "code_generator.h"
#include "code_generator_x86.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction.h"
#include "driver/compiler_options.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc
index 3eadc8f8fc..35bc4ff8b3 100644
--- a/compiler/optimizing/liveness_test.cc
+++ b/compiler/optimizing/liveness_test.cc
@@ -19,8 +19,8 @@
#include "builder.h"
#include "code_generator.h"
#include "code_generator_x86.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction.h"
#include "driver/compiler_options.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 89ad85e0b4..88326d321b 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -74,25 +74,116 @@ class LSEVisitor : public HGraphDelegateVisitor {
HGraphVisitor::VisitBasicBlock(block);
}
+ HTypeConversion* AddTypeConversionIfNecessary(HInstruction* instruction,
+ HInstruction* value,
+ DataType::Type expected_type) {
+ HTypeConversion* type_conversion = nullptr;
+ // Should never add type conversion into boolean value.
+ if (expected_type != DataType::Type::kBool &&
+ !DataType::IsTypeConversionImplicit(value->GetType(), expected_type)) {
+ type_conversion = new (GetGraph()->GetAllocator()) HTypeConversion(
+ expected_type, value, instruction->GetDexPc());
+ instruction->GetBlock()->InsertInstructionBefore(type_conversion, instruction);
+ }
+ return type_conversion;
+ }
+
+ // Find an instruction's substitute if it should be removed.
+ // Return the same instruction if it should not be removed.
+ HInstruction* FindSubstitute(HInstruction* instruction) {
+ size_t size = removed_loads_.size();
+ for (size_t i = 0; i < size; i++) {
+ if (removed_loads_[i] == instruction) {
+ return substitute_instructions_for_loads_[i];
+ }
+ }
+ return instruction;
+ }
+
+ void AddRemovedLoad(HInstruction* load, HInstruction* heap_value) {
+ DCHECK_EQ(FindSubstitute(heap_value), heap_value) <<
+ "Unexpected heap_value that has a substitute " << heap_value->DebugName();
+ removed_loads_.push_back(load);
+ substitute_instructions_for_loads_.push_back(heap_value);
+ }
+
+ // Scan the list of removed loads to see if we can reuse `type_conversion`, if
+ // the other removed load has the same substitute and type and is dominated
+ // by `type_conversioni`.
+ void TryToReuseTypeConversion(HInstruction* type_conversion, size_t index) {
+ size_t size = removed_loads_.size();
+ HInstruction* load = removed_loads_[index];
+ HInstruction* substitute = substitute_instructions_for_loads_[index];
+ for (size_t j = index + 1; j < size; j++) {
+ HInstruction* load2 = removed_loads_[j];
+ HInstruction* substitute2 = substitute_instructions_for_loads_[j];
+ if (load2 == nullptr) {
+ DCHECK(substitute2->IsTypeConversion());
+ continue;
+ }
+ DCHECK(load2->IsInstanceFieldGet() ||
+ load2->IsStaticFieldGet() ||
+ load2->IsArrayGet());
+ DCHECK(substitute2 != nullptr);
+ if (substitute2 == substitute &&
+ load2->GetType() == load->GetType() &&
+ type_conversion->GetBlock()->Dominates(load2->GetBlock()) &&
+ // Don't share across irreducible loop headers.
+ // TODO: can be more fine-grained than this by testing each dominator.
+ (load2->GetBlock() == type_conversion->GetBlock() ||
+ !GetGraph()->HasIrreducibleLoops())) {
+ // The removed_loads_ are added in reverse post order.
+ DCHECK(type_conversion->StrictlyDominates(load2));
+ load2->ReplaceWith(type_conversion);
+ load2->GetBlock()->RemoveInstruction(load2);
+ removed_loads_[j] = nullptr;
+ substitute_instructions_for_loads_[j] = type_conversion;
+ }
+ }
+ }
+
// Remove recorded instructions that should be eliminated.
void RemoveInstructions() {
size_t size = removed_loads_.size();
DCHECK_EQ(size, substitute_instructions_for_loads_.size());
for (size_t i = 0; i < size; i++) {
HInstruction* load = removed_loads_[i];
- DCHECK(load != nullptr);
+ if (load == nullptr) {
+ // The load has been handled in the scan for type conversion below.
+ DCHECK(substitute_instructions_for_loads_[i]->IsTypeConversion());
+ continue;
+ }
DCHECK(load->IsInstanceFieldGet() ||
load->IsStaticFieldGet() ||
load->IsArrayGet());
HInstruction* substitute = substitute_instructions_for_loads_[i];
DCHECK(substitute != nullptr);
- // Keep tracing substitute till one that's not removed.
- HInstruction* sub_sub = FindSubstitute(substitute);
- while (sub_sub != substitute) {
- substitute = sub_sub;
- sub_sub = FindSubstitute(substitute);
+ // We proactively retrieve the substitute for a removed load, so
+ // a load that has a substitute should not be observed as a heap
+ // location value.
+ DCHECK_EQ(FindSubstitute(substitute), substitute);
+
+ // The load expects to load the heap value as type load->GetType().
+ // However the tracked heap value may not be of that type. An explicit
+ // type conversion may be needed.
+ // There are actually three types involved here:
+ // (1) tracked heap value's type (type A)
+ // (2) heap location (field or element)'s type (type B)
+ // (3) load's type (type C)
+ // We guarantee that type A stored as type B and then fetched out as
+ // type C is the same as casting from type A to type C directly, since
+ // type B and type C will have the same size which is guarenteed in
+ // HInstanceFieldGet/HStaticFieldGet/HArrayGet's SetType().
+ // So we only need one type conversion from type A to type C.
+ HTypeConversion* type_conversion = AddTypeConversionIfNecessary(
+ load, substitute, load->GetType());
+ if (type_conversion != nullptr) {
+ TryToReuseTypeConversion(type_conversion, i);
+ load->ReplaceWith(type_conversion);
+ substitute_instructions_for_loads_[i] = type_conversion;
+ } else {
+ load->ReplaceWith(substitute);
}
- load->ReplaceWith(substitute);
load->GetBlock()->RemoveInstruction(load);
}
@@ -328,8 +419,7 @@ class LSEVisitor : public HGraphDelegateVisitor {
HInstruction* heap_value = heap_values[idx];
if (heap_value == kDefaultHeapValue) {
HInstruction* constant = GetDefaultValue(instruction->GetType());
- removed_loads_.push_back(instruction);
- substitute_instructions_for_loads_.push_back(constant);
+ AddRemovedLoad(instruction, constant);
heap_values[idx] = constant;
return;
}
@@ -342,6 +432,8 @@ class LSEVisitor : public HGraphDelegateVisitor {
DCHECK(ref_info->IsSingleton());
// Get the real heap value of the store.
heap_value = heap_value->IsInstanceFieldSet() ? store->InputAt(1) : store->InputAt(2);
+ // heap_value may already have a substitute.
+ heap_value = FindSubstitute(heap_value);
}
}
if (heap_value == kUnknownHeapValue) {
@@ -362,8 +454,7 @@ class LSEVisitor : public HGraphDelegateVisitor {
}
return;
}
- removed_loads_.push_back(instruction);
- substitute_instructions_for_loads_.push_back(heap_value);
+ AddRemovedLoad(instruction, heap_value);
TryRemovingNullCheck(instruction);
}
}
@@ -385,6 +476,8 @@ class LSEVisitor : public HGraphDelegateVisitor {
size_t vector_length,
int16_t declaring_class_def_index,
HInstruction* value) {
+ // value may already have a substitute.
+ value = FindSubstitute(value);
HInstruction* original_ref = heap_location_collector_.HuntForOriginalReference(ref);
ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(original_ref);
size_t idx = heap_location_collector_.FindHeapLocationIndex(
@@ -679,18 +772,6 @@ class LSEVisitor : public HGraphDelegateVisitor {
}
}
- // Find an instruction's substitute if it should be removed.
- // Return the same instruction if it should not be removed.
- HInstruction* FindSubstitute(HInstruction* instruction) {
- size_t size = removed_loads_.size();
- for (size_t i = 0; i < size; i++) {
- if (removed_loads_[i] == instruction) {
- return substitute_instructions_for_loads_[i];
- }
- }
- return instruction;
- }
-
const HeapLocationCollector& heap_location_collector_;
const SideEffectsAnalysis& side_effects_;
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 1ca096035e..3dc1ef7534 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -1749,7 +1749,8 @@ void HLoopOptimization::GenerateVecReductionPhiInputs(HPhi* phi, HInstruction* r
HInstruction* HLoopOptimization::ReduceAndExtractIfNeeded(HInstruction* instruction) {
if (instruction->IsPhi()) {
HInstruction* input = instruction->InputAt(1);
- if (input->IsVecOperation() && !input->IsVecExtractScalar()) {
+ if (HVecOperation::ReturnsSIMDValue(input)) {
+ DCHECK(!input->IsPhi());
HVecOperation* input_vector = input->AsVecOperation();
uint32_t vector_length = input_vector->GetVectorLength();
DataType::Type type = input_vector->GetPackedType();
diff --git a/compiler/optimizing/loop_optimization_test.cc b/compiler/optimizing/loop_optimization_test.cc
index 4e1857df5b..db8368986c 100644
--- a/compiler/optimizing/loop_optimization_test.cc
+++ b/compiler/optimizing/loop_optimization_test.cc
@@ -194,7 +194,9 @@ TEST_F(LoopOptimizationTest, LoopNestWithSequence) {
// Check that SimplifyLoop() doesn't invalidate data flow when ordering loop headers'
// predecessors.
-TEST_F(LoopOptimizationTest, SimplifyLoop) {
+//
+// This is a test for nodes.cc functionality - HGraph::SimplifyLoop.
+TEST_F(LoopOptimizationTest, SimplifyLoopReoderPredecessors) {
// Can't use AddLoop as we want special order for blocks predecessors.
HBasicBlock* header = new (GetAllocator()) HBasicBlock(graph_);
HBasicBlock* body = new (GetAllocator()) HBasicBlock(graph_);
@@ -232,4 +234,83 @@ TEST_F(LoopOptimizationTest, SimplifyLoop) {
ASSERT_TRUE(input->GetBlock()->Dominates(header->GetPredecessors()[i]));
}
}
+
+// Test that SimplifyLoop() processes the multiple-preheaders loops correctly.
+//
+// This is a test for nodes.cc functionality - HGraph::SimplifyLoop.
+TEST_F(LoopOptimizationTest, SimplifyLoopSinglePreheader) {
+ HBasicBlock* header = AddLoop(entry_block_, return_block_);
+
+ header->InsertInstructionBefore(
+ new (GetAllocator()) HSuspendCheck(), header->GetLastInstruction());
+
+ // Insert an if construct before the loop so it will have two preheaders.
+ HBasicBlock* if_block = new (GetAllocator()) HBasicBlock(graph_);
+ HBasicBlock* preheader0 = new (GetAllocator()) HBasicBlock(graph_);
+ HBasicBlock* preheader1 = new (GetAllocator()) HBasicBlock(graph_);
+
+ graph_->AddBlock(if_block);
+ graph_->AddBlock(preheader0);
+ graph_->AddBlock(preheader1);
+
+ // Fix successors/predecessors.
+ entry_block_->ReplaceSuccessor(header, if_block);
+ if_block->AddSuccessor(preheader0);
+ if_block->AddSuccessor(preheader1);
+ preheader0->AddSuccessor(header);
+ preheader1->AddSuccessor(header);
+
+ if_block->AddInstruction(new (GetAllocator()) HIf(parameter_));
+ preheader0->AddInstruction(new (GetAllocator()) HGoto());
+ preheader1->AddInstruction(new (GetAllocator()) HGoto());
+
+ HBasicBlock* body = header->GetSuccessors()[0];
+ DCHECK(body != return_block_);
+
+ // Add some data flow.
+ HIntConstant* const_0 = graph_->GetIntConstant(0);
+ HIntConstant* const_1 = graph_->GetIntConstant(1);
+ HIntConstant* const_2 = graph_->GetIntConstant(2);
+
+ HAdd* preheader0_add = new (GetAllocator()) HAdd(DataType::Type::kInt32, parameter_, const_0);
+ preheader0->AddInstruction(preheader0_add);
+ HAdd* preheader1_add = new (GetAllocator()) HAdd(DataType::Type::kInt32, parameter_, const_1);
+ preheader1->AddInstruction(preheader1_add);
+
+ HPhi* header_phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
+ header->AddPhi(header_phi);
+
+ HAdd* body_add = new (GetAllocator()) HAdd(DataType::Type::kInt32, parameter_, const_2);
+ body->AddInstruction(body_add);
+
+ DCHECK(header->GetPredecessors()[0] == body);
+ DCHECK(header->GetPredecessors()[1] == preheader0);
+ DCHECK(header->GetPredecessors()[2] == preheader1);
+
+ header_phi->AddInput(body_add);
+ header_phi->AddInput(preheader0_add);
+ header_phi->AddInput(preheader1_add);
+
+ graph_->ClearLoopInformation();
+ graph_->ClearDominanceInformation();
+ graph_->BuildDominatorTree();
+
+ EXPECT_EQ(header->GetPredecessors().size(), 2u);
+ EXPECT_EQ(header->GetPredecessors()[1], body);
+
+ HBasicBlock* new_preheader = header->GetLoopInformation()->GetPreHeader();
+ EXPECT_EQ(preheader0->GetSingleSuccessor(), new_preheader);
+ EXPECT_EQ(preheader1->GetSingleSuccessor(), new_preheader);
+
+ EXPECT_EQ(new_preheader->GetPhis().CountSize(), 1u);
+ HPhi* new_preheader_phi = new_preheader->GetFirstPhi()->AsPhi();
+ EXPECT_EQ(new_preheader_phi->InputCount(), 2u);
+ EXPECT_EQ(new_preheader_phi->InputAt(0), preheader0_add);
+ EXPECT_EQ(new_preheader_phi->InputAt(1), preheader1_add);
+
+ EXPECT_EQ(header_phi->InputCount(), 2u);
+ EXPECT_EQ(header_phi->InputAt(0), new_preheader_phi);
+ EXPECT_EQ(header_phi->InputAt(1), body_add);
+}
+
} // namespace art
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index fa580d9bed..727431a493 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -397,6 +397,117 @@ void HGraph::OrderLoopHeaderPredecessors(HBasicBlock* header) {
}
}
+// Transform control flow of the loop to a single preheader format (don't touch the data flow).
+// New_preheader can be already among the header predecessors - this situation will be correctly
+// processed.
+static void FixControlForNewSinglePreheader(HBasicBlock* header, HBasicBlock* new_preheader) {
+ HLoopInformation* loop_info = header->GetLoopInformation();
+ for (size_t pred = 0; pred < header->GetPredecessors().size(); ++pred) {
+ HBasicBlock* predecessor = header->GetPredecessors()[pred];
+ if (!loop_info->IsBackEdge(*predecessor) && predecessor != new_preheader) {
+ predecessor->ReplaceSuccessor(header, new_preheader);
+ pred--;
+ }
+ }
+}
+
+// == Before == == After ==
+// _________ _________ _________ _________
+// | B0 | | B1 | (old preheaders) | B0 | | B1 |
+// |=========| |=========| |=========| |=========|
+// | i0 = .. | | i1 = .. | | i0 = .. | | i1 = .. |
+// |_________| |_________| |_________| |_________|
+// \ / \ /
+// \ / ___v____________v___
+// \ / (new preheader) | B20 <- B0, B1 |
+// | | |====================|
+// | | | i20 = phi(i0, i1) |
+// | | |____________________|
+// | | |
+// /\ | | /\ /\ | /\
+// / v_______v_________v_______v \ / v___________v_____________v \
+// | | B10 <- B0, B1, B2, B3 | | | | B10 <- B20, B2, B3 | |
+// | |===========================| | (header) | |===========================| |
+// | | i10 = phi(i0, i1, i2, i3) | | | | i10 = phi(i20, i2, i3) | |
+// | |___________________________| | | |___________________________| |
+// | / \ | | / \ |
+// | ... ... | | ... ... |
+// | _________ _________ | | _________ _________ |
+// | | B2 | | B3 | | | | B2 | | B3 | |
+// | |=========| |=========| | (back edges) | |=========| |=========| |
+// | | i2 = .. | | i3 = .. | | | | i2 = .. | | i3 = .. | |
+// | |_________| |_________| | | |_________| |_________| |
+// \ / \ / \ / \ /
+// \___/ \___/ \___/ \___/
+//
+void HGraph::TransformLoopToSinglePreheaderFormat(HBasicBlock* header) {
+ HLoopInformation* loop_info = header->GetLoopInformation();
+
+ HBasicBlock* preheader = new (allocator_) HBasicBlock(this, header->GetDexPc());
+ AddBlock(preheader);
+ preheader->AddInstruction(new (allocator_) HGoto(header->GetDexPc()));
+
+ // If the old header has no Phis then we only need to fix the control flow.
+ if (header->GetPhis().IsEmpty()) {
+ FixControlForNewSinglePreheader(header, preheader);
+ preheader->AddSuccessor(header);
+ return;
+ }
+
+ // Find the first non-back edge block in the header's predecessors list.
+ size_t first_nonbackedge_pred_pos = 0;
+ bool found = false;
+ for (size_t pred = 0; pred < header->GetPredecessors().size(); ++pred) {
+ HBasicBlock* predecessor = header->GetPredecessors()[pred];
+ if (!loop_info->IsBackEdge(*predecessor)) {
+ first_nonbackedge_pred_pos = pred;
+ found = true;
+ break;
+ }
+ }
+
+ DCHECK(found);
+
+ // Fix the data-flow.
+ for (HInstructionIterator it(header->GetPhis()); !it.Done(); it.Advance()) {
+ HPhi* header_phi = it.Current()->AsPhi();
+
+ HPhi* preheader_phi = new (GetAllocator()) HPhi(GetAllocator(),
+ header_phi->GetRegNumber(),
+ 0,
+ header_phi->GetType());
+ if (header_phi->GetType() == DataType::Type::kReference) {
+ preheader_phi->SetReferenceTypeInfo(header_phi->GetReferenceTypeInfo());
+ }
+ preheader->AddPhi(preheader_phi);
+
+ HInstruction* orig_input = header_phi->InputAt(first_nonbackedge_pred_pos);
+ header_phi->ReplaceInput(preheader_phi, first_nonbackedge_pred_pos);
+ preheader_phi->AddInput(orig_input);
+
+ for (size_t input_pos = first_nonbackedge_pred_pos + 1;
+ input_pos < header_phi->InputCount();
+ input_pos++) {
+ HInstruction* input = header_phi->InputAt(input_pos);
+ HBasicBlock* pred_block = header->GetPredecessors()[input_pos];
+
+ if (loop_info->Contains(*pred_block)) {
+ DCHECK(loop_info->IsBackEdge(*pred_block));
+ } else {
+ preheader_phi->AddInput(input);
+ header_phi->RemoveInputAt(input_pos);
+ input_pos--;
+ }
+ }
+ }
+
+ // Fix the control-flow.
+ HBasicBlock* first_pred = header->GetPredecessors()[first_nonbackedge_pred_pos];
+ preheader->InsertBetween(first_pred, header);
+
+ FixControlForNewSinglePreheader(header, preheader);
+}
+
void HGraph::SimplifyLoop(HBasicBlock* header) {
HLoopInformation* info = header->GetLoopInformation();
@@ -406,18 +517,7 @@ void HGraph::SimplifyLoop(HBasicBlock* header) {
// this graph.
size_t number_of_incomings = header->GetPredecessors().size() - info->NumberOfBackEdges();
if (number_of_incomings != 1 || (GetEntryBlock()->GetSingleSuccessor() == header)) {
- HBasicBlock* pre_header = new (allocator_) HBasicBlock(this, header->GetDexPc());
- AddBlock(pre_header);
- pre_header->AddInstruction(new (allocator_) HGoto(header->GetDexPc()));
-
- for (size_t pred = 0; pred < header->GetPredecessors().size(); ++pred) {
- HBasicBlock* predecessor = header->GetPredecessors()[pred];
- if (!info->IsBackEdge(*predecessor)) {
- predecessor->ReplaceSuccessor(header, pre_header);
- pred--;
- }
- }
- pre_header->AddSuccessor(header);
+ TransformLoopToSinglePreheaderFormat(header);
}
OrderLoopHeaderPredecessors(header);
@@ -507,6 +607,7 @@ GraphAnalysisResult HGraph::AnalyzeLoops() const {
if (block->IsCatchBlock()) {
// TODO: Dealing with exceptional back edges could be tricky because
// they only approximate the real control flow. Bail out for now.
+ VLOG(compiler) << "Not compiled: Exceptional back edges";
return kAnalysisFailThrowCatchLoop;
}
block->GetLoopInformation()->Populate();
@@ -1403,6 +1504,14 @@ HConstant* HTypeConversion::TryStaticEvaluation() const {
if (GetInput()->IsIntConstant()) {
int32_t value = GetInput()->AsIntConstant()->GetValue();
switch (GetResultType()) {
+ case DataType::Type::kInt8:
+ return graph->GetIntConstant(static_cast<int8_t>(value), GetDexPc());
+ case DataType::Type::kUint8:
+ return graph->GetIntConstant(static_cast<uint8_t>(value), GetDexPc());
+ case DataType::Type::kInt16:
+ return graph->GetIntConstant(static_cast<int16_t>(value), GetDexPc());
+ case DataType::Type::kUint16:
+ return graph->GetIntConstant(static_cast<uint16_t>(value), GetDexPc());
case DataType::Type::kInt64:
return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
case DataType::Type::kFloat32:
@@ -1415,6 +1524,14 @@ HConstant* HTypeConversion::TryStaticEvaluation() const {
} else if (GetInput()->IsLongConstant()) {
int64_t value = GetInput()->AsLongConstant()->GetValue();
switch (GetResultType()) {
+ case DataType::Type::kInt8:
+ return graph->GetIntConstant(static_cast<int8_t>(value), GetDexPc());
+ case DataType::Type::kUint8:
+ return graph->GetIntConstant(static_cast<uint8_t>(value), GetDexPc());
+ case DataType::Type::kInt16:
+ return graph->GetIntConstant(static_cast<int16_t>(value), GetDexPc());
+ case DataType::Type::kUint16:
+ return graph->GetIntConstant(static_cast<uint16_t>(value), GetDexPc());
case DataType::Type::kInt32:
return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
case DataType::Type::kFloat32:
@@ -2814,21 +2931,6 @@ bool HLoadClass::InstructionDataEquals(const HInstruction* other) const {
}
}
-void HLoadClass::SetLoadKind(LoadKind load_kind) {
- SetPackedField<LoadKindField>(load_kind);
-
- if (load_kind != LoadKind::kRuntimeCall &&
- load_kind != LoadKind::kReferrersClass) {
- RemoveAsUserOfInput(0u);
- SetRawInputAt(0u, nullptr);
- }
-
- if (!NeedsEnvironment()) {
- RemoveEnvironment();
- SetSideEffects(SideEffects::None());
- }
-}
-
std::ostream& operator<<(std::ostream& os, HLoadClass::LoadKind rhs) {
switch (rhs) {
case HLoadClass::LoadKind::kReferrersClass:
@@ -2871,21 +2973,6 @@ 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::kRuntimeCall);
- SetPackedField<LoadKindField>(load_kind);
-
- if (load_kind != LoadKind::kRuntimeCall) {
- RemoveAsUserOfInput(0u);
- SetRawInputAt(0u, nullptr);
- }
- if (!NeedsEnvironment()) {
- RemoveEnvironment();
- SetSideEffects(SideEffects::None());
- }
-}
-
std::ostream& operator<<(std::ostream& os, HLoadString::LoadKind rhs) {
switch (rhs) {
case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 66d5bfea32..d4382c6b4c 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -30,8 +30,8 @@
#include "base/transform_array_ref.h"
#include "data_type.h"
#include "deoptimization_kind.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "handle.h"
#include "handle_scope.h"
@@ -423,6 +423,17 @@ class HGraph : public ArenaObject<kArenaAllocGraph> {
void SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor);
void OrderLoopHeaderPredecessors(HBasicBlock* header);
+
+ // Transform a loop into a format with a single preheader.
+ //
+ // Each phi in the header should be split: original one in the header should only hold
+ // inputs reachable from the back edges and a single input from the preheader. The newly created
+ // phi in the preheader should collate the inputs from the original multiple incoming blocks.
+ //
+ // Loops in the graph typically have a single preheader, so this method is used to "repair" loops
+ // that no longer have this property.
+ void TransformLoopToSinglePreheaderFormat(HBasicBlock* header);
+
void SimplifyLoop(HBasicBlock* header);
int32_t GetNextInstructionId() {
@@ -4614,7 +4625,6 @@ class HInvokeInterface FINAL : public HInvoke {
}
uint32_t GetImtIndex() const { return imt_index_; }
- uint32_t GetDexMethodIndex() const { return dex_method_index_; }
DECLARE_INSTRUCTION(InvokeInterface);
@@ -5787,10 +5797,10 @@ class HBoundsCheck FINAL : public HExpression<2> {
HBoundsCheck(HInstruction* index,
HInstruction* length,
uint32_t dex_pc,
- bool string_char_at = false)
+ bool is_string_char_at = false)
: HExpression(index->GetType(), SideEffects::CanTriggerGC(), dex_pc) {
DCHECK_EQ(DataType::Type::kInt32, DataType::Kind(index->GetType()));
- SetPackedFlag<kFlagIsStringCharAt>(string_char_at);
+ SetPackedFlag<kFlagIsStringCharAt>(is_string_char_at);
SetRawInputAt(0, index);
SetRawInputAt(1, length);
}
@@ -6062,6 +6072,20 @@ class HLoadClass FINAL : public HInstruction {
std::ostream& operator<<(std::ostream& os, HLoadClass::LoadKind rhs);
// Note: defined outside class to see operator<<(., HLoadClass::LoadKind).
+inline void HLoadClass::SetLoadKind(LoadKind load_kind) {
+ // The load kind should be determined before inserting the instruction to the graph.
+ DCHECK(GetBlock() == nullptr);
+ DCHECK(GetEnvironment() == nullptr);
+ SetPackedField<LoadKindField>(load_kind);
+ if (load_kind != LoadKind::kRuntimeCall && load_kind != LoadKind::kReferrersClass) {
+ special_input_ = HUserRecord<HInstruction*>(nullptr);
+ }
+ if (!NeedsEnvironment()) {
+ SetSideEffects(SideEffects::None());
+ }
+}
+
+// Note: defined outside class to see operator<<(., HLoadClass::LoadKind).
inline void HLoadClass::AddSpecialInput(HInstruction* special_input) {
// The special input is used for PC-relative loads on some architectures,
// including literal pool loads, which are PC-relative too.
@@ -6209,6 +6233,21 @@ class HLoadString FINAL : public HInstruction {
std::ostream& operator<<(std::ostream& os, HLoadString::LoadKind rhs);
// Note: defined outside class to see operator<<(., HLoadString::LoadKind).
+inline void HLoadString::SetLoadKind(LoadKind load_kind) {
+ // The load kind should be determined before inserting the instruction to the graph.
+ DCHECK(GetBlock() == nullptr);
+ DCHECK(GetEnvironment() == nullptr);
+ DCHECK_EQ(GetLoadKind(), LoadKind::kRuntimeCall);
+ SetPackedField<LoadKindField>(load_kind);
+ if (load_kind != LoadKind::kRuntimeCall) {
+ special_input_ = HUserRecord<HInstruction*>(nullptr);
+ }
+ if (!NeedsEnvironment()) {
+ SetSideEffects(SideEffects::None());
+ }
+}
+
+// Note: defined outside class to see operator<<(., HLoadString::LoadKind).
inline void HLoadString::AddSpecialInput(HInstruction* special_input) {
// The special input is used for PC-relative loads on some architectures,
// including literal pool loads, which are PC-relative too.
@@ -6231,7 +6270,7 @@ class HClinitCheck FINAL : public HExpression<1> {
HClinitCheck(HLoadClass* constant, uint32_t dex_pc)
: HExpression(
DataType::Type::kReference,
- SideEffects::AllChanges(), // Assume write/read on all fields/arrays.
+ SideEffects::AllExceptGCDependency(), // Assume write/read on all fields/arrays.
dex_pc) {
SetRawInputAt(0, constant);
}
@@ -6562,7 +6601,7 @@ std::ostream& operator<<(std::ostream& os, TypeCheckKind rhs);
class HInstanceOf FINAL : public HExpression<2> {
public:
HInstanceOf(HInstruction* object,
- HLoadClass* constant,
+ HLoadClass* target_class,
TypeCheckKind check_kind,
uint32_t dex_pc)
: HExpression(DataType::Type::kBool,
@@ -6571,7 +6610,13 @@ class HInstanceOf FINAL : public HExpression<2> {
SetPackedField<TypeCheckKindField>(check_kind);
SetPackedFlag<kFlagMustDoNullCheck>(true);
SetRawInputAt(0, object);
- SetRawInputAt(1, constant);
+ SetRawInputAt(1, target_class);
+ }
+
+ HLoadClass* GetTargetClass() const {
+ HInstruction* load_class = InputAt(1);
+ DCHECK(load_class->IsLoadClass());
+ return load_class->AsLoadClass();
}
bool IsClonable() const OVERRIDE { return true; }
@@ -6665,14 +6710,20 @@ class HBoundType FINAL : public HExpression<1> {
class HCheckCast FINAL : public HTemplateInstruction<2> {
public:
HCheckCast(HInstruction* object,
- HLoadClass* constant,
+ HLoadClass* target_class,
TypeCheckKind check_kind,
uint32_t dex_pc)
: HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc) {
SetPackedField<TypeCheckKindField>(check_kind);
SetPackedFlag<kFlagMustDoNullCheck>(true);
SetRawInputAt(0, object);
- SetRawInputAt(1, constant);
+ SetRawInputAt(1, target_class);
+ }
+
+ HLoadClass* GetTargetClass() const {
+ HInstruction* load_class = InputAt(1);
+ DCHECK(load_class->IsLoadClass());
+ return load_class->AsLoadClass();
}
bool IsClonable() const OVERRIDE { return true; }
diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h
index 59d5b9f847..87dff8403b 100644
--- a/compiler/optimizing/nodes_vector.h
+++ b/compiler/optimizing/nodes_vector.h
@@ -109,6 +109,16 @@ class HVecOperation : public HVariableInputSizeInstruction {
// Assumes vector nodes cannot be moved by default. Each concrete implementation
// that can be moved should override this method and return true.
+ //
+ // Note: similar approach is used for instruction scheduling (if it is turned on for the target):
+ // by default HScheduler::IsSchedulable returns false for a particular HVecOperation.
+ // HScheduler${ARCH}::IsSchedulable can be overridden to return true for an instruction (see
+ // scheduler_arm64.h for example) if it is safe to schedule it; in this case one *must* also
+ // look at/update HScheduler${ARCH}::IsSchedulingBarrier for this instruction.
+ //
+ // Note: For newly introduced vector instructions HScheduler${ARCH}::IsSchedulingBarrier must be
+ // altered to return true if the instruction might reside outside the SIMD loop body since SIMD
+ // registers are not kept alive across vector loop boundaries (yet).
bool CanBeMoved() const OVERRIDE { return false; }
// Tests if all data of a vector node (vector length and packed type) is equal.
@@ -150,6 +160,19 @@ class HVecOperation : public HVariableInputSizeInstruction {
}
}
+ // Helper method to determine if an instruction returns a SIMD value.
+ // TODO: This method is needed until we introduce SIMD as proper type.
+ static bool ReturnsSIMDValue(HInstruction* instruction) {
+ if (instruction->IsVecOperation()) {
+ return !instruction->IsVecExtractScalar(); // only scalar returning vec op
+ } else if (instruction->IsPhi()) {
+ return
+ instruction->GetType() == kSIMDType &&
+ instruction->InputAt(1)->IsVecOperation(); // vectorizer does not go deeper
+ }
+ return false;
+ }
+
DECLARE_ABSTRACT_INSTRUCTION(VecOperation);
protected:
@@ -879,7 +902,7 @@ class HVecSetScalars FINAL : public HVecOperation {
vector_length,
dex_pc) {
for (size_t i = 0; i < number_of_scalars; i++) {
- DCHECK(!scalars[i]->IsVecOperation() || scalars[i]->IsVecExtractScalar());
+ DCHECK(!ReturnsSIMDValue(scalars[i]));
SetRawInputAt(0, scalars[i]);
}
}
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
index 7edb642c5b..92b427cafa 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -39,6 +39,7 @@
#include "constant_folding.h"
#include "constructor_fence_redundancy_elimination.h"
#include "dead_code_elimination.h"
+#include "dex/code_item_accessors-inl.h"
#include "driver/dex_compilation_unit.h"
#include "gvn.h"
#include "induction_var_analysis.h"
@@ -241,7 +242,8 @@ ArenaVector<HOptimization*> ConstructOptimizations(
opt = new (allocator) HDeadCodeElimination(graph, stats, name);
break;
case OptimizationPass::kInliner: {
- size_t number_of_dex_registers = dex_compilation_unit.GetCodeItem()->registers_size_;
+ CodeItemDataAccessor accessor(dex_compilation_unit.GetDexFile(),
+ dex_compilation_unit.GetCodeItem());
opt = new (allocator) HInliner(graph, // outer_graph
graph, // outermost_graph
codegen,
@@ -250,7 +252,7 @@ ArenaVector<HOptimization*> ConstructOptimizations(
driver,
handles,
stats,
- number_of_dex_registers,
+ accessor.RegistersSize(),
/* total_number_of_instructions */ 0,
/* parent */ nullptr,
/* depth */ 0,
@@ -258,8 +260,7 @@ ArenaVector<HOptimization*> ConstructOptimizations(
break;
}
case OptimizationPass::kSharpening:
- opt = new (allocator) HSharpening(
- graph, codegen, dex_compilation_unit, driver, handles, name);
+ opt = new (allocator) HSharpening(graph, codegen, driver, name);
break;
case OptimizationPass::kSelectGenerator:
opt = new (allocator) HSelectGenerator(graph, handles, stats, name);
diff --git a/compiler/optimizing/optimizing_cfi_test.cc b/compiler/optimizing/optimizing_cfi_test.cc
index 4ad29961be..e2b2106f65 100644
--- a/compiler/optimizing/optimizing_cfi_test.cc
+++ b/compiler/optimizing/optimizing_cfi_test.cc
@@ -18,6 +18,7 @@
#include <vector>
#include "arch/instruction_set.h"
+#include "base/runtime_debug.h"
#include "cfi_test.h"
#include "driver/compiler_options.h"
#include "gtest/gtest.h"
@@ -56,6 +57,9 @@ class OptimizingCFITest : public CFITest {
ArenaAllocator* GetAllocator() { return pool_and_allocator_.GetAllocator(); }
void SetUpFrame(InstructionSet isa) {
+ // Ensure that slow-debug is off, so that there is no unexpected read-barrier check emitted.
+ SetRuntimeDebugFlagsEnabled(false);
+
// Setup simple context.
std::string error;
isa_features_ = InstructionSetFeatures::FromVariant(isa, "default", &error);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 73c72fc57a..b64f82caee 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -36,9 +36,9 @@
#include "compiler.h"
#include "debug/elf_debug_writer.h"
#include "debug/method_debug_info.h"
+#include "dex/dex_file_types.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
-#include "dex_file_types.h"
#include "driver/compiler_driver-inl.h"
#include "driver/compiler_options.h"
#include "driver/dex_compilation_unit.h"
@@ -766,11 +766,13 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator,
static constexpr size_t kSpaceFilterOptimizingThreshold = 128;
const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions();
if ((compiler_options.GetCompilerFilter() == CompilerFilter::kSpace)
- && (code_item->insns_size_in_code_units_ > kSpaceFilterOptimizingThreshold)) {
+ && (CodeItemInstructionAccessor(&dex_file, code_item).InsnsSizeInCodeUnits() >
+ kSpaceFilterOptimizingThreshold)) {
MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kNotCompiledSpaceFilter);
return nullptr;
}
+ CodeItemDebugInfoAccessor code_item_accessor(&dex_file, code_item);
HGraph* graph = new (allocator) HGraph(
allocator,
arena_stack,
@@ -814,7 +816,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator,
VLOG(compiler) << "Building " << pass_observer.GetMethodName();
PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer);
HGraphBuilder builder(graph,
- code_item,
+ code_item_accessor,
&dex_compilation_unit,
&dex_compilation_unit,
compiler_driver,
@@ -932,7 +934,7 @@ CodeGenerator* OptimizingCompiler::TryCompileIntrinsic(
VLOG(compiler) << "Building intrinsic graph " << pass_observer.GetMethodName();
PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer);
HGraphBuilder builder(graph,
- /* code_item */ nullptr,
+ CodeItemDebugInfoAccessor(), // Null code item.
&dex_compilation_unit,
&dex_compilation_unit,
compiler_driver,
@@ -1224,7 +1226,7 @@ bool OptimizingCompiler::JitCompile(Thread* self,
}
const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();
- if (compiler_options.GetGenerateDebugInfo()) {
+ if (compiler_options.GenerateAnyDebugInfo()) {
const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code);
const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode());
debug::MethodDebugInfo info = {};
@@ -1244,10 +1246,13 @@ bool OptimizingCompiler::JitCompile(Thread* self,
info.frame_size_in_bytes = method_header->GetFrameSizeInBytes();
info.code_info = nullptr;
info.cfi = jni_compiled_method.GetCfi();
- std::vector<uint8_t> elf_file = debug::WriteDebugElfFileForMethods(
+ // If both flags are passed, generate full debug info.
+ const bool mini_debug_info = !compiler_options.GetGenerateDebugInfo();
+ std::vector<uint8_t> elf_file = debug::MakeElfFileForJIT(
GetCompilerDriver()->GetInstructionSet(),
GetCompilerDriver()->GetInstructionSetFeatures(),
- ArrayRef<const debug::MethodDebugInfo>(&info, 1));
+ mini_debug_info,
+ info);
CreateJITCodeEntryForAddress(code_address, std::move(elf_file));
}
@@ -1352,7 +1357,7 @@ bool OptimizingCompiler::JitCompile(Thread* self,
}
const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();
- if (compiler_options.GetGenerateDebugInfo()) {
+ if (compiler_options.GenerateAnyDebugInfo()) {
const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code);
const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode());
debug::MethodDebugInfo info = {};
@@ -1372,10 +1377,13 @@ bool OptimizingCompiler::JitCompile(Thread* self,
info.frame_size_in_bytes = method_header->GetFrameSizeInBytes();
info.code_info = stack_map_size == 0 ? nullptr : stack_map_data;
info.cfi = ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data());
- std::vector<uint8_t> elf_file = debug::WriteDebugElfFileForMethods(
+ // If both flags are passed, generate full debug info.
+ const bool mini_debug_info = !compiler_options.GetGenerateDebugInfo();
+ std::vector<uint8_t> elf_file = debug::MakeElfFileForJIT(
GetCompilerDriver()->GetInstructionSet(),
GetCompilerDriver()->GetInstructionSetFeatures(),
- ArrayRef<const debug::MethodDebugInfo>(&info, 1));
+ mini_debug_info,
+ info);
CreateJITCodeEntryForAddress(code_address, std::move(elf_file));
}
diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h
index a2e92d2931..32a94ab5e4 100644
--- a/compiler/optimizing/optimizing_compiler_stats.h
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -23,6 +23,7 @@
#include <type_traits>
#include "atomic.h"
+#include "base/logging.h" // For VLOG_IS_ON.
#include "globals.h"
namespace art {
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 158c252f45..661abb125c 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -20,8 +20,9 @@
#include "base/scoped_arena_allocator.h"
#include "builder.h"
#include "common_compiler_test.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction.h"
#include "driver/dex_compilation_unit.h"
#include "handle_scope-inl.h"
#include "mirror/class_loader.h"
@@ -145,7 +146,8 @@ class OptimizingUnitTest : public CommonCompilerTest {
/* access_flags */ 0u,
/* verified_method */ nullptr,
handles_->NewHandle<mirror::DexCache>(nullptr));
- HGraphBuilder builder(graph, dex_compilation_unit, *code_item, handles_.get(), return_type);
+ CodeItemDebugInfoAccessor accessor(&graph->GetDexFile(), code_item);
+ HGraphBuilder builder(graph, dex_compilation_unit, accessor, handles_.get(), return_type);
bool graph_built = (builder.BuildGraph() == kAnalysisSuccess);
return graph_built ? graph : nullptr;
}
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index 1ed190d328..f843c008d8 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -16,7 +16,7 @@
#include "prepare_for_register_allocation.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "jni_internal.h"
#include "optimizing_compiler_stats.h"
#include "well_known_classes.h"
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
index 4aec6d3999..4fc7fe9427 100644
--- a/compiler/optimizing/pretty_printer_test.cc
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -18,8 +18,8 @@
#include "base/arena_allocator.h"
#include "builder.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 7246129e25..8bb124e066 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -544,7 +544,7 @@ void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* inst
// the method is from the String class, the null loader is good enough.
Handle<mirror::ClassLoader> loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
ArtMethod* method = cl->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- dex_file, invoke->GetDexMethodIndex(), dex_cache, loader, nullptr, kDirect);
+ invoke->GetDexMethodIndex(), dex_cache, loader, /* referrer */ nullptr, kDirect);
DCHECK(method != nullptr);
mirror::Class* declaring_class = method->GetDeclaringClass();
DCHECK(declaring_class != nullptr);
@@ -576,8 +576,8 @@ void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction*
ScopedObjectAccess soa(Thread::Current());
ObjPtr<mirror::DexCache> dex_cache = FindDexCacheWithHint(soa.Self(), dex_file, hint_dex_cache_);
- ObjPtr<mirror::Class> klass =
- ClassLinker::LookupResolvedType(type_idx, dex_cache, class_loader_.Get());
+ ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->LookupResolvedType(
+ type_idx, dex_cache, class_loader_.Get());
SetClassAsTypeInfo(instr, klass, is_exact);
}
@@ -612,7 +612,7 @@ void ReferenceTypePropagation::RTPVisitor::UpdateFieldAccessTypeInfo(HInstructio
// The field is unknown only during tests.
if (info.GetField() != nullptr) {
- klass = info.GetField()->LookupType();
+ klass = info.GetField()->LookupResolvedType();
}
SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 69ed8c7fcc..3748d599a3 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -21,9 +21,9 @@
#include "builder.h"
#include "code_generator.h"
#include "code_generator_x86.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
-#include "dex_instruction.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
+#include "dex/dex_instruction.h"
#include "driver/compiler_options.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
diff --git a/compiler/optimizing/scheduler.h b/compiler/optimizing/scheduler.h
index bb7c353bc2..dfa077f7de 100644
--- a/compiler/optimizing/scheduler.h
+++ b/compiler/optimizing/scheduler.h
@@ -462,6 +462,11 @@ class HScheduler {
// containing basic block from being scheduled.
// This method is used to restrict scheduling to instructions that we know are
// safe to handle.
+ //
+ // For newly introduced instructions by default HScheduler::IsSchedulable returns false.
+ // HScheduler${ARCH}::IsSchedulable can be overridden to return true for an instruction (see
+ // scheduler_arm64.h for example) if it is safe to schedule it; in this case one *must* also
+ // look at/update HScheduler${ARCH}::IsSchedulingBarrier for this instruction.
virtual bool IsSchedulable(const HInstruction* instruction) const;
bool IsSchedulable(const HBasicBlock* block) const;
diff --git a/compiler/optimizing/scheduler_arm64.h b/compiler/optimizing/scheduler_arm64.h
index 32f161f26a..f71cb5b784 100644
--- a/compiler/optimizing/scheduler_arm64.h
+++ b/compiler/optimizing/scheduler_arm64.h
@@ -151,6 +151,20 @@ class HSchedulerARM64 : public HScheduler {
#undef CASE_INSTRUCTION_KIND
}
+ // Treat as scheduling barriers those vector instructions whose live ranges exceed the vectorized
+ // loop boundaries. This is a workaround for the lack of notion of SIMD register in the compiler;
+ // around a call we have to save/restore all live SIMD&FP registers (only lower 64 bits of
+ // SIMD&FP registers are callee saved) so don't reorder such vector instructions.
+ //
+ // TODO: remove this when a proper support of SIMD registers is introduced to the compiler.
+ bool IsSchedulingBarrier(const HInstruction* instr) const OVERRIDE {
+ return HScheduler::IsSchedulingBarrier(instr) ||
+ instr->IsVecReduce() ||
+ instr->IsVecExtractScalar() ||
+ instr->IsVecSetScalars() ||
+ instr->IsVecReplicateScalar();
+ }
+
private:
SchedulingLatencyVisitorARM64 arm64_latency_visitor_;
DISALLOW_COPY_AND_ASSIGN(HSchedulerARM64);
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index e46c9a7081..1e49411c72 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -45,8 +45,6 @@ void HSharpening::Run() {
SharpenInvokeStaticOrDirect(instruction->AsInvokeStaticOrDirect(),
codegen_,
compiler_driver_);
- } else if (instruction->IsLoadString()) {
- ProcessLoadString(instruction->AsLoadString());
}
// TODO: Move the sharpening of invoke-virtual/-interface/-super from HGraphBuilder
// here. Rewrite it to avoid the CompilerDriver's reliance on verifier data
@@ -147,10 +145,11 @@ void HSharpening::SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke,
invoke->SetDispatchInfo(dispatch_info);
}
-HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(HLoadClass* load_class,
- CodeGenerator* codegen,
- CompilerDriver* compiler_driver,
- const DexCompilationUnit& dex_compilation_unit) {
+HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(
+ HLoadClass* load_class,
+ CodeGenerator* codegen,
+ CompilerDriver* compiler_driver,
+ const DexCompilationUnit& dex_compilation_unit) {
Handle<mirror::Class> klass = load_class->GetClass();
DCHECK(load_class->GetLoadKind() == HLoadClass::LoadKind::kRuntimeCall ||
load_class->GetLoadKind() == HLoadClass::LoadKind::kReferrersClass)
@@ -237,7 +236,12 @@ HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(HLoadClass* load_class,
return load_kind;
}
-void HSharpening::ProcessLoadString(HLoadString* load_string) {
+void HSharpening::ProcessLoadString(
+ HLoadString* load_string,
+ CodeGenerator* codegen,
+ CompilerDriver* compiler_driver,
+ const DexCompilationUnit& dex_compilation_unit,
+ VariableSizedHandleScope* handles) {
DCHECK_EQ(load_string->GetLoadKind(), HLoadString::LoadKind::kRuntimeCall);
const DexFile& dex_file = load_string->GetDexFile();
@@ -249,27 +253,27 @@ void HSharpening::ProcessLoadString(HLoadString* load_string) {
ClassLinker* class_linker = runtime->GetClassLinker();
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::DexCache> dex_cache = IsSameDexFile(dex_file, *compilation_unit_.GetDexFile())
- ? compilation_unit_.GetDexCache()
+ Handle<mirror::DexCache> dex_cache = IsSameDexFile(dex_file, *dex_compilation_unit.GetDexFile())
+ ? dex_compilation_unit.GetDexCache()
: hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file));
- mirror::String* string = nullptr;
+ ObjPtr<mirror::String> string = nullptr;
- if (codegen_->GetCompilerOptions().IsBootImage()) {
+ if (codegen->GetCompilerOptions().IsBootImage()) {
// Compiling boot image. Resolve the string and allocate it if needed, to ensure
// the string will be added to the boot image.
DCHECK(!runtime->UseJitCompilation());
- string = class_linker->ResolveString(dex_file, string_index, dex_cache);
+ string = class_linker->ResolveString(string_index, dex_cache);
CHECK(string != nullptr);
- if (compiler_driver_->GetSupportBootImageFixup()) {
- DCHECK(ContainsElement(compiler_driver_->GetDexFilesForOatFile(), &dex_file));
+ if (compiler_driver->GetSupportBootImageFixup()) {
+ DCHECK(ContainsElement(compiler_driver->GetDexFilesForOatFile(), &dex_file));
desired_load_kind = HLoadString::LoadKind::kBootImageLinkTimePcRelative;
} else {
// compiler_driver_test. Do not sharpen.
desired_load_kind = HLoadString::LoadKind::kRuntimeCall;
}
} else if (runtime->UseJitCompilation()) {
- DCHECK(!codegen_->GetCompilerOptions().GetCompilePic());
- string = class_linker->LookupString(dex_file, string_index, dex_cache.Get());
+ DCHECK(!codegen->GetCompilerOptions().GetCompilePic());
+ string = class_linker->LookupString(string_index, dex_cache.Get());
if (string != nullptr) {
if (runtime->GetHeap()->ObjectIsInBootImageSpace(string)) {
desired_load_kind = HLoadString::LoadKind::kBootImageAddress;
@@ -281,9 +285,9 @@ void HSharpening::ProcessLoadString(HLoadString* load_string) {
}
} else {
// AOT app compilation. Try to lookup the string without allocating if not found.
- string = class_linker->LookupString(dex_file, string_index, dex_cache.Get());
+ string = class_linker->LookupString(string_index, dex_cache.Get());
if (string != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(string)) {
- if (codegen_->GetCompilerOptions().GetCompilePic()) {
+ if (codegen->GetCompilerOptions().GetCompilePic()) {
desired_load_kind = HLoadString::LoadKind::kBootImageInternTable;
} else {
desired_load_kind = HLoadString::LoadKind::kBootImageAddress;
@@ -293,12 +297,12 @@ void HSharpening::ProcessLoadString(HLoadString* load_string) {
}
}
if (string != nullptr) {
- load_string->SetString(handles_->NewHandle(string));
+ load_string->SetString(handles->NewHandle(string));
}
}
DCHECK_NE(desired_load_kind, static_cast<HLoadString::LoadKind>(-1));
- HLoadString::LoadKind load_kind = codegen_->GetSupportedLoadStringKind(desired_load_kind);
+ HLoadString::LoadKind load_kind = codegen->GetSupportedLoadStringKind(desired_load_kind);
load_string->SetLoadKind(load_kind);
}
diff --git a/compiler/optimizing/sharpening.h b/compiler/optimizing/sharpening.h
index bb1954eeeb..6df7d6d91e 100644
--- a/compiler/optimizing/sharpening.h
+++ b/compiler/optimizing/sharpening.h
@@ -34,26 +34,29 @@ class HSharpening : public HOptimization {
public:
HSharpening(HGraph* graph,
CodeGenerator* codegen,
- const DexCompilationUnit& compilation_unit,
CompilerDriver* compiler_driver,
- VariableSizedHandleScope* handles,
const char* name = kSharpeningPassName)
: HOptimization(graph, name),
codegen_(codegen),
- compilation_unit_(compilation_unit),
- compiler_driver_(compiler_driver),
- handles_(handles) { }
+ compiler_driver_(compiler_driver) { }
void Run() OVERRIDE;
static constexpr const char* kSharpeningPassName = "sharpening";
+ // Used by the builder.
+ static void ProcessLoadString(HLoadString* load_string,
+ CodeGenerator* codegen,
+ CompilerDriver* compiler_driver,
+ const DexCompilationUnit& dex_compilation_unit,
+ VariableSizedHandleScope* handles);
+
// Used by the builder and the inliner.
static HLoadClass::LoadKind ComputeLoadClassKind(HLoadClass* load_class,
CodeGenerator* codegen,
CompilerDriver* compiler_driver,
const DexCompilationUnit& dex_compilation_unit)
- REQUIRES_SHARED(Locks::mutator_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Used by Sharpening and InstructionSimplifier.
static void SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke,
@@ -61,12 +64,8 @@ class HSharpening : public HOptimization {
CompilerDriver* compiler_driver);
private:
- void ProcessLoadString(HLoadString* load_string);
-
CodeGenerator* codegen_;
- const DexCompilationUnit& compilation_unit_;
CompilerDriver* compiler_driver_;
- VariableSizedHandleScope* handles_;
};
} // namespace art
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index e4edbfdc24..cb384768b7 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -328,6 +328,8 @@ bool SsaBuilder::FixAmbiguousArrayOps() {
HInstruction* array = aget_int->GetArray();
if (!array->GetReferenceTypeInfo().IsPrimitiveArrayClass()) {
// RTP did not type the input array. Bail.
+ VLOG(compiler) << "Not compiled: Could not infer an array type for array operation at "
+ << aget_int->GetDexPc();
return false;
}
@@ -368,6 +370,8 @@ bool SsaBuilder::FixAmbiguousArrayOps() {
HInstruction* array = aset->GetArray();
if (!array->GetReferenceTypeInfo().IsPrimitiveArrayClass()) {
// RTP did not type the input array. Bail.
+ VLOG(compiler) << "Not compiled: Could not infer an array type for array operation at "
+ << aset->GetDexPc();
return false;
}
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index 9ab7a89b33..f6bd05269e 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -474,9 +474,10 @@ size_t LiveInterval::NumberOfSpillSlotsNeeded() const {
// For a SIMD operation, compute the number of needed spill slots.
// TODO: do through vector type?
HInstruction* definition = GetParent()->GetDefinedBy();
- if (definition != nullptr &&
- definition->IsVecOperation() &&
- !definition->IsVecExtractScalar()) {
+ if (definition != nullptr && HVecOperation::ReturnsSIMDValue(definition)) {
+ if (definition->IsPhi()) {
+ definition = definition->InputAt(1); // SIMD always appears on back-edge
+ }
return definition->AsVecOperation()->GetVectorNumberOfBytes() / kVRegSize;
}
// Return number of needed spill slots based on type.
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index e08904e84b..77e70d733e 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -18,8 +18,8 @@
#include "base/arena_allocator.h"
#include "builder.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
#include "pretty_printer.h"
diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc
index 4f43eb374c..7010e3f380 100644
--- a/compiler/optimizing/stack_map_stream.cc
+++ b/compiler/optimizing/stack_map_stream.cc
@@ -18,7 +18,7 @@
#include "art_method-inl.h"
#include "base/stl_util.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "optimizing/optimizing_compiler.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/compiler/optimizing/cloner_test.cc b/compiler/optimizing/superblock_cloner_test.cc
index d34dd81767..fd77eb81fc 100644
--- a/compiler/optimizing/cloner_test.cc
+++ b/compiler/optimizing/superblock_cloner_test.cc
@@ -24,9 +24,9 @@ namespace art {
// This class provides methods and helpers for testing various cloning and copying routines:
// individual instruction cloning and cloning of the more coarse-grain structures.
-class ClonerTest : public OptimizingUnitTest {
+class SuperblockClonerTest : public OptimizingUnitTest {
public:
- ClonerTest()
+ SuperblockClonerTest()
: graph_(CreateGraph()), entry_block_(nullptr), exit_block_(nullptr), parameter_(nullptr) {}
void CreateBasicLoopControlFlow(/* out */ HBasicBlock** header_p,
@@ -154,7 +154,7 @@ class ClonerTest : public OptimizingUnitTest {
HInstruction* parameter_;
};
-TEST_F(ClonerTest, IndividualInstrCloner) {
+TEST_F(SuperblockClonerTest, IndividualInstrCloner) {
HBasicBlock* header = nullptr;
HBasicBlock* loop_body = nullptr;
diff --git a/compiler/optimizing/suspend_check_test.cc b/compiler/optimizing/suspend_check_test.cc
index 88336b0009..7e83f8ce5f 100644
--- a/compiler/optimizing/suspend_check_test.cc
+++ b/compiler/optimizing/suspend_check_test.cc
@@ -15,7 +15,7 @@
*/
#include "builder.h"
-#include "dex_instruction.h"
+#include "dex/dex_instruction.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
#include "pretty_printer.h"
diff --git a/compiler/trampolines/trampoline_compiler.h b/compiler/trampolines/trampoline_compiler.h
index 1a10e4c799..64c1eb5022 100644
--- a/compiler/trampolines/trampoline_compiler.h
+++ b/compiler/trampolines/trampoline_compiler.h
@@ -21,6 +21,7 @@
#include <vector>
#include "driver/compiler_driver.h"
+#include "offsets.h"
namespace art {
diff --git a/compiler/utils/arm/assembler_arm_vixl.h b/compiler/utils/arm/assembler_arm_vixl.h
index 0e73e6bf9e..1377e64073 100644
--- a/compiler/utils/arm/assembler_arm_vixl.h
+++ b/compiler/utils/arm/assembler_arm_vixl.h
@@ -17,8 +17,10 @@
#ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_VIXL_H_
#define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_VIXL_H_
+#include <android-base/logging.h>
+
#include "base/arena_containers.h"
-#include "base/logging.h"
+#include "base/macros.h"
#include "constants_arm.h"
#include "offsets.h"
#include "utils/arm/assembler_arm_shared.h"
diff --git a/compiler/utils/arm/constants_arm.h b/compiler/utils/arm/constants_arm.h
index 5b87e3e7f8..66252bed86 100644
--- a/compiler/utils/arm/constants_arm.h
+++ b/compiler/utils/arm/constants_arm.h
@@ -21,9 +21,10 @@
#include <iosfwd>
+#include <android-base/logging.h>
+
#include "arch/arm/registers_arm.h"
#include "base/casts.h"
-#include "base/logging.h"
#include "globals.h"
namespace art {
diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.h b/compiler/utils/arm/jni_macro_assembler_arm_vixl.h
index c13c9af819..4bc5d69f4d 100644
--- a/compiler/utils/arm/jni_macro_assembler_arm_vixl.h
+++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.h
@@ -17,8 +17,10 @@
#ifndef ART_COMPILER_UTILS_ARM_JNI_MACRO_ASSEMBLER_ARM_VIXL_H_
#define ART_COMPILER_UTILS_ARM_JNI_MACRO_ASSEMBLER_ARM_VIXL_H_
+#include <android-base/logging.h>
+
#include "base/arena_containers.h"
-#include "base/logging.h"
+#include "base/macros.h"
#include "constants_arm.h"
#include "offsets.h"
#include "utils/arm/assembler_arm_shared.h"
diff --git a/compiler/utils/arm/managed_register_arm.h b/compiler/utils/arm/managed_register_arm.h
index 2be2d5638e..26f23b2ed6 100644
--- a/compiler/utils/arm/managed_register_arm.h
+++ b/compiler/utils/arm/managed_register_arm.h
@@ -17,7 +17,8 @@
#ifndef ART_COMPILER_UTILS_ARM_MANAGED_REGISTER_ARM_H_
#define ART_COMPILER_UTILS_ARM_MANAGED_REGISTER_ARM_H_
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "constants_arm.h"
#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index bb989588d6..c83fd4404a 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -15,7 +15,6 @@
*/
#include "assembler_arm64.h"
-#include "base/logging.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "heap_poisoning.h"
#include "offsets.h"
diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h
index e5ec24add0..8983af2677 100644
--- a/compiler/utils/arm64/assembler_arm64.h
+++ b/compiler/utils/arm64/assembler_arm64.h
@@ -21,8 +21,10 @@
#include <memory>
#include <vector>
+#include <android-base/logging.h>
+
#include "base/arena_containers.h"
-#include "base/logging.h"
+#include "base/macros.h"
#include "offsets.h"
#include "utils/arm64/managed_register_arm64.h"
#include "utils/assembler.h"
diff --git a/compiler/utils/arm64/jni_macro_assembler_arm64.cc b/compiler/utils/arm64/jni_macro_assembler_arm64.cc
index 573bb6d4be..a5aa1c12b3 100644
--- a/compiler/utils/arm64/jni_macro_assembler_arm64.cc
+++ b/compiler/utils/arm64/jni_macro_assembler_arm64.cc
@@ -16,7 +16,6 @@
#include "jni_macro_assembler_arm64.h"
-#include "base/logging.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "managed_register_arm64.h"
#include "offsets.h"
diff --git a/compiler/utils/arm64/jni_macro_assembler_arm64.h b/compiler/utils/arm64/jni_macro_assembler_arm64.h
index ce39a13692..f531b2aa51 100644
--- a/compiler/utils/arm64/jni_macro_assembler_arm64.h
+++ b/compiler/utils/arm64/jni_macro_assembler_arm64.h
@@ -21,10 +21,12 @@
#include <memory>
#include <vector>
+#include <android-base/logging.h>
+
#include "assembler_arm64.h"
#include "base/arena_containers.h"
#include "base/enums.h"
-#include "base/logging.h"
+#include "base/macros.h"
#include "offsets.h"
#include "utils/assembler.h"
#include "utils/jni_macro_assembler.h"
diff --git a/compiler/utils/arm64/managed_register_arm64.h b/compiler/utils/arm64/managed_register_arm64.h
index 7378a0a081..9ce7ec9a97 100644
--- a/compiler/utils/arm64/managed_register_arm64.h
+++ b/compiler/utils/arm64/managed_register_arm64.h
@@ -17,8 +17,9 @@
#ifndef ART_COMPILER_UTILS_ARM64_MANAGED_REGISTER_ARM64_H_
#define ART_COMPILER_UTILS_ARM64_MANAGED_REGISTER_ARM64_H_
+#include <android-base/logging.h>
+
#include "arch/arm64/registers_arm64.h"
-#include "base/logging.h"
#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index e0cef859e1..5b0cd6baa8 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -19,6 +19,8 @@
#include <vector>
+#include <android-base/logging.h>
+
#include "arch/instruction_set.h"
#include "arch/instruction_set_features.h"
#include "arm/constants_arm.h"
@@ -26,7 +28,6 @@
#include "base/arena_object.h"
#include "base/array_ref.h"
#include "base/enums.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "debug/dwarf/debug_frame_opcode_writer.h"
#include "label.h"
diff --git a/compiler/utils/atomic_dex_ref_map-inl.h b/compiler/utils/atomic_dex_ref_map-inl.h
index 33d59f9d42..203e484fb7 100644
--- a/compiler/utils/atomic_dex_ref_map-inl.h
+++ b/compiler/utils/atomic_dex_ref_map-inl.h
@@ -21,8 +21,8 @@
#include <type_traits>
-#include "dex_file-inl.h"
#include "class_reference.h"
+#include "dex/dex_file-inl.h"
#include "method_reference.h"
#include "type_reference.h"
@@ -58,7 +58,7 @@ inline typename AtomicDexRefMap<DexFileReferenceType, Value>::InsertResult
return kInsertResultInvalidDexFile;
}
DCHECK_LT(ref.index, array->size());
- return (*array)[ref.index].CompareExchangeStrongSequentiallyConsistent(expected, desired)
+ return (*array)[ref.index].CompareAndSetStrongSequentiallyConsistent(expected, desired)
? kInsertResultSuccess
: kInsertResultCASFailure;
}
diff --git a/compiler/utils/atomic_dex_ref_map.h b/compiler/utils/atomic_dex_ref_map.h
index 205543f31d..9ff506d6a4 100644
--- a/compiler/utils/atomic_dex_ref_map.h
+++ b/compiler/utils/atomic_dex_ref_map.h
@@ -18,7 +18,7 @@
#define ART_COMPILER_UTILS_ATOMIC_DEX_REF_MAP_H_
#include "base/dchecked_vector.h"
-#include "dex_file_reference.h"
+#include "dex/dex_file_reference.h"
#include "safe_map.h"
namespace art {
diff --git a/compiler/utils/atomic_dex_ref_map_test.cc b/compiler/utils/atomic_dex_ref_map_test.cc
index 8fce36f021..d58d60b4f3 100644
--- a/compiler/utils/atomic_dex_ref_map_test.cc
+++ b/compiler/utils/atomic_dex_ref_map_test.cc
@@ -19,7 +19,7 @@
#include <memory>
#include "common_runtime_test.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "method_reference.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/compiler/utils/intrusive_forward_list.h b/compiler/utils/intrusive_forward_list.h
index 5a358ac2c4..ccdd32aad4 100644
--- a/compiler/utils/intrusive_forward_list.h
+++ b/compiler/utils/intrusive_forward_list.h
@@ -23,8 +23,9 @@
#include <memory>
#include <type_traits>
+#include <android-base/logging.h>
+
#include "base/casts.h"
-#include "base/logging.h"
#include "base/macros.h"
namespace art {
diff --git a/compiler/utils/jni_macro_assembler.h b/compiler/utils/jni_macro_assembler.h
index 0fc1353bf5..f5df926749 100644
--- a/compiler/utils/jni_macro_assembler.h
+++ b/compiler/utils/jni_macro_assembler.h
@@ -19,12 +19,13 @@
#include <vector>
+#include <android-base/logging.h>
+
#include "arch/instruction_set.h"
#include "base/arena_allocator.h"
#include "base/arena_object.h"
#include "base/array_ref.h"
#include "base/enums.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "managed_register.h"
#include "offsets.h"
diff --git a/compiler/utils/label.h b/compiler/utils/label.h
index b9d4e9c521..3c91b2ffd1 100644
--- a/compiler/utils/label.h
+++ b/compiler/utils/label.h
@@ -17,8 +17,8 @@
#ifndef ART_COMPILER_UTILS_LABEL_H_
#define ART_COMPILER_UTILS_LABEL_H_
-#include "base/logging.h"
-#include "base/macros.h"
+#include <android-base/logging.h>
+#include <android-base/macros.h>
namespace art {
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index eb75f8b67c..2218ef9af2 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -42,26 +42,13 @@ std::ostream& operator<<(std::ostream& os, const DRegister& rhs) {
MipsAssembler::DelaySlot::DelaySlot()
: instruction_(0),
- gpr_outs_mask_(0),
- gpr_ins_mask_(0),
- fpr_outs_mask_(0),
- fpr_ins_mask_(0),
- cc_outs_mask_(0),
- cc_ins_mask_(0),
patcher_label_(nullptr) {}
-void MipsAssembler::DsFsmInstr(uint32_t instruction,
- uint32_t gpr_outs_mask,
- uint32_t gpr_ins_mask,
- uint32_t fpr_outs_mask,
- uint32_t fpr_ins_mask,
- uint32_t cc_outs_mask,
- uint32_t cc_ins_mask,
- MipsLabel* patcher_label) {
+InOutRegMasks& MipsAssembler::DsFsmInstr(uint32_t instruction, MipsLabel* patcher_label) {
if (!reordering_) {
CHECK_EQ(ds_fsm_state_, kExpectingLabel);
CHECK_EQ(delay_slot_.instruction_, 0u);
- return;
+ return delay_slot_.masks_;
}
switch (ds_fsm_state_) {
case kExpectingLabel:
@@ -92,13 +79,9 @@ void MipsAssembler::DsFsmInstr(uint32_t instruction,
break;
}
delay_slot_.instruction_ = instruction;
- delay_slot_.gpr_outs_mask_ = gpr_outs_mask & ~1u; // Ignore register ZERO.
- delay_slot_.gpr_ins_mask_ = gpr_ins_mask & ~1u; // Ignore register ZERO.
- delay_slot_.fpr_outs_mask_ = fpr_outs_mask;
- delay_slot_.fpr_ins_mask_ = fpr_ins_mask;
- delay_slot_.cc_outs_mask_ = cc_outs_mask;
- delay_slot_.cc_ins_mask_ = cc_ins_mask;
+ delay_slot_.masks_ = InOutRegMasks();
delay_slot_.patcher_label_ = patcher_label;
+ return delay_slot_.masks_;
}
void MipsAssembler::DsFsmLabel() {
@@ -167,73 +150,7 @@ size_t MipsAssembler::CodePosition() {
}
void MipsAssembler::DsFsmInstrNop(uint32_t instruction ATTRIBUTE_UNUSED) {
- DsFsmInstr(0, 0, 0, 0, 0, 0, 0);
-}
-
-void MipsAssembler::DsFsmInstrRrr(uint32_t instruction,
- Register out,
- Register in1,
- Register in2,
- MipsLabel* patcher_label) {
- DsFsmInstr(instruction, (1u << out), (1u << in1) | (1u << in2), 0, 0, 0, 0, patcher_label);
-}
-
-void MipsAssembler::DsFsmInstrRrrr(uint32_t instruction,
- Register in1_out,
- Register in2,
- Register in3) {
- DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0, 0, 0);
-}
-
-void MipsAssembler::DsFsmInstrFff(uint32_t instruction,
- FRegister out,
- FRegister in1,
- FRegister in2) {
- DsFsmInstr(instruction, 0, 0, (1u << out), (1u << in1) | (1u << in2), 0, 0);
-}
-
-void MipsAssembler::DsFsmInstrFfff(uint32_t instruction,
- FRegister in1_out,
- FRegister in2,
- FRegister in3) {
- DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2) | (1u << in3), 0, 0);
-}
-
-void MipsAssembler::DsFsmInstrFffr(uint32_t instruction,
- FRegister in1_out,
- FRegister in2,
- Register in3) {
- DsFsmInstr(instruction, 0, (1u << in3), (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0);
-}
-
-void MipsAssembler::DsFsmInstrRf(uint32_t instruction, Register out, FRegister in) {
- DsFsmInstr(instruction, (1u << out), 0, 0, (1u << in), 0, 0);
-}
-
-void MipsAssembler::DsFsmInstrFr(uint32_t instruction, FRegister out, Register in) {
- DsFsmInstr(instruction, 0, (1u << in), (1u << out), 0, 0, 0);
-}
-
-void MipsAssembler::DsFsmInstrFR(uint32_t instruction, FRegister in1, Register in2) {
- DsFsmInstr(instruction, 0, (1u << in2), 0, (1u << in1), 0, 0);
-}
-
-void MipsAssembler::DsFsmInstrCff(uint32_t instruction, int cc_out, FRegister in1, FRegister in2) {
- DsFsmInstr(instruction, 0, 0, 0, (1u << in1) | (1u << in2), (1 << cc_out), 0);
-}
-
-void MipsAssembler::DsFsmInstrRrrc(uint32_t instruction,
- Register in1_out,
- Register in2,
- int cc_in) {
- DsFsmInstr(instruction, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, 0, 0, (1 << cc_in));
-}
-
-void MipsAssembler::DsFsmInstrFffc(uint32_t instruction,
- FRegister in1_out,
- FRegister in2,
- int cc_in) {
- DsFsmInstr(instruction, 0, 0, (1u << in1_out), (1u << in1_out) | (1u << in2), 0, (1 << cc_in));
+ DsFsmInstr(0);
}
void MipsAssembler::FinalizeCode() {
@@ -535,14 +452,14 @@ uint32_t MipsAssembler::EmitMsa2RF(int operation,
}
void MipsAssembler::Addu(Register rd, Register rs, Register rt) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x21), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x21)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) {
if (patcher_label != nullptr) {
Bind(patcher_label);
}
- DsFsmInstrRrr(EmitI(0x9, rs, rt, imm16), rt, rs, rs, patcher_label);
+ DsFsmInstr(EmitI(0x9, rs, rt, imm16), patcher_label).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
@@ -550,32 +467,32 @@ void MipsAssembler::Addiu(Register rt, Register rs, uint16_t imm16) {
}
void MipsAssembler::Subu(Register rd, Register rs, Register rt) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x23), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x23)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::MultR2(Register rs, Register rt) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18), ZERO, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x18)).GprIns(rs, rt);
}
void MipsAssembler::MultuR2(Register rs, Register rt) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19), ZERO, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x19)).GprIns(rs, rt);
}
void MipsAssembler::DivR2(Register rs, Register rt) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a), ZERO, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1a)).GprIns(rs, rt);
}
void MipsAssembler::DivuR2(Register rs, Register rt) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b), ZERO, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, static_cast<Register>(0), 0, 0x1b)).GprIns(rs, rt);
}
void MipsAssembler::MulR2(Register rd, Register rs, Register rt) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitR(0x1c, rs, rt, rd, 0, 2), rd, rs, rt);
+ DsFsmInstr(EmitR(0x1c, rs, rt, rd, 0, 2)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::DivR2(Register rd, Register rs, Register rt) {
@@ -604,179 +521,181 @@ void MipsAssembler::ModuR2(Register rd, Register rs, Register rt) {
void MipsAssembler::MulR6(Register rd, Register rs, Register rt) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x18), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x18)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::MuhR6(Register rd, Register rs, Register rt) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x18), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x18)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::MuhuR6(Register rd, Register rs, Register rt) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x19), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x19)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::DivR6(Register rd, Register rs, Register rt) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1a), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x1a)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::ModR6(Register rd, Register rs, Register rt) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1a), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x1a)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::DivuR6(Register rd, Register rs, Register rt) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 2, 0x1b), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 2, 0x1b)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::ModuR6(Register rd, Register rs, Register rt) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 3, 0x1b), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 3, 0x1b)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::And(Register rd, Register rs, Register rt) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x24), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x24)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Andi(Register rt, Register rs, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0xc, rs, rt, imm16), rt, rs, rs);
+ DsFsmInstr(EmitI(0xc, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::Or(Register rd, Register rs, Register rt) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x25), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x25)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Ori(Register rt, Register rs, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0xd, rs, rt, imm16), rt, rs, rs);
+ DsFsmInstr(EmitI(0xd, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::Xor(Register rd, Register rs, Register rt) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x26), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x26)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Xori(Register rt, Register rs, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0xe, rs, rt, imm16), rt, rs, rs);
+ DsFsmInstr(EmitI(0xe, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::Nor(Register rd, Register rs, Register rt) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x27), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x27)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Movz(Register rd, Register rs, Register rt) {
CHECK(!IsR6());
- DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0A), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x0A)).GprInOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Movn(Register rd, Register rs, Register rt) {
CHECK(!IsR6());
- DsFsmInstrRrrr(EmitR(0, rs, rt, rd, 0, 0x0B), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x0B)).GprInOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x35), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x35)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Selnez(Register rd, Register rs, Register rt) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x37), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x37)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::ClzR6(Register rd, Register rs) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10), rd, rs, rs);
+ DsFsmInstr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10)).GprOuts(rd).GprIns(rs);
}
void MipsAssembler::ClzR2(Register rd, Register rs) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x20), rd, rs, rs);
+ DsFsmInstr(EmitR(0x1C, rs, rd, rd, 0, 0x20)).GprOuts(rd).GprIns(rs);
}
void MipsAssembler::CloR6(Register rd, Register rs) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11), rd, rs, rs);
+ DsFsmInstr(EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11)).GprOuts(rd).GprIns(rs);
}
void MipsAssembler::CloR2(Register rd, Register rs) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitR(0x1C, rs, rd, rd, 0, 0x21), rd, rs, rs);
+ DsFsmInstr(EmitR(0x1C, rs, rd, rd, 0, 0x21)).GprOuts(rd).GprIns(rs);
}
void MipsAssembler::Seb(Register rd, Register rt) {
- DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20), rd, rt, rt);
+ DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20)).GprOuts(rd).GprIns(rt);
}
void MipsAssembler::Seh(Register rd, Register rt) {
- DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20), rd, rt, rt);
+ DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x18, 0x20)).GprOuts(rd).GprIns(rt);
}
void MipsAssembler::Wsbh(Register rd, Register rt) {
- DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20), rd, rt, rt);
+ DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20)).GprOuts(rd).GprIns(rt);
}
void MipsAssembler::Bitswap(Register rd, Register rt) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20), rd, rt, rt);
+ DsFsmInstr(EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20)).GprOuts(rd).GprIns(rt);
}
void MipsAssembler::Sll(Register rd, Register rt, int shamt) {
CHECK(IsUint<5>(shamt)) << shamt;
- DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00), rd, rt, rt);
+ DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00)).GprOuts(rd).GprIns(rt);
}
void MipsAssembler::Srl(Register rd, Register rt, int shamt) {
CHECK(IsUint<5>(shamt)) << shamt;
- DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02), rd, rt, rt);
+ DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x02)).GprOuts(rd).GprIns(rt);
}
void MipsAssembler::Rotr(Register rd, Register rt, int shamt) {
CHECK(IsUint<5>(shamt)) << shamt;
- DsFsmInstrRrr(EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02), rd, rt, rt);
+ DsFsmInstr(EmitR(0, static_cast<Register>(1), rt, rd, shamt, 0x02)).GprOuts(rd).GprIns(rt);
}
void MipsAssembler::Sra(Register rd, Register rt, int shamt) {
CHECK(IsUint<5>(shamt)) << shamt;
- DsFsmInstrRrr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03), rd, rt, rt);
+ DsFsmInstr(EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x03)).GprOuts(rd).GprIns(rt);
}
void MipsAssembler::Sllv(Register rd, Register rt, Register rs) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x04), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x04)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Srlv(Register rd, Register rt, Register rs) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x06), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x06)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 1, 0x06), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 1, 0x06)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Srav(Register rd, Register rt, Register rs) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x07), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x07)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Ext(Register rd, Register rt, int pos, int size) {
CHECK(IsUint<5>(pos)) << pos;
CHECK(0 < size && size <= 32) << size;
CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
- DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00), rd, rt, rt);
+ DsFsmInstr(EmitR(0x1f, rt, rd, static_cast<Register>(size - 1), pos, 0x00))
+ .GprOuts(rd).GprIns(rt);
}
void MipsAssembler::Ins(Register rd, Register rt, int pos, int size) {
CHECK(IsUint<5>(pos)) << pos;
CHECK(0 < size && size <= 32) << size;
CHECK(0 < pos + size && pos + size <= 32) << pos << " + " << size;
- DsFsmInstrRrr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04), rd, rd, rt);
+ DsFsmInstr(EmitR(0x1f, rt, rd, static_cast<Register>(pos + size - 1), pos, 0x04))
+ .GprInOuts(rd).GprIns(rt);
}
void MipsAssembler::Lsa(Register rd, Register rs, Register rt, int saPlusOne) {
CHECK(IsR6() || HasMsa());
CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
int sa = saPlusOne - 1;
- DsFsmInstrRrr(EmitR(0x0, rs, rt, rd, sa, 0x05), rd, rs, rt);
+ DsFsmInstr(EmitR(0x0, rs, rt, rd, sa, 0x05)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::ShiftAndAdd(Register dst,
@@ -798,18 +717,18 @@ void MipsAssembler::ShiftAndAdd(Register dst,
}
void MipsAssembler::Lb(Register rt, Register rs, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0x20, rs, rt, imm16), rt, rs, rs);
+ DsFsmInstr(EmitI(0x20, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::Lh(Register rt, Register rs, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0x21, rs, rt, imm16), rt, rs, rs);
+ DsFsmInstr(EmitI(0x21, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) {
if (patcher_label != nullptr) {
Bind(patcher_label);
}
- DsFsmInstrRrr(EmitI(0x23, rs, rt, imm16), rt, rs, rs, patcher_label);
+ DsFsmInstr(EmitI(0x23, rs, rt, imm16), patcher_label).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
@@ -818,20 +737,20 @@ void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitI(0x22, rs, rt, imm16), rt, rt, rs);
+ DsFsmInstr(EmitI(0x22, rs, rt, imm16)).GprInOuts(rt).GprIns(rs);
}
void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitI(0x26, rs, rt, imm16), rt, rt, rs);
+ DsFsmInstr(EmitI(0x26, rs, rt, imm16)).GprInOuts(rt).GprIns(rs);
}
void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0x24, rs, rt, imm16), rt, rs, rs);
+ DsFsmInstr(EmitI(0x24, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::Lhu(Register rt, Register rs, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0x25, rs, rt, imm16), rt, rs, rs);
+ DsFsmInstr(EmitI(0x25, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::Lwpc(Register rs, uint32_t imm19) {
@@ -841,12 +760,12 @@ void MipsAssembler::Lwpc(Register rs, uint32_t imm19) {
}
void MipsAssembler::Lui(Register rt, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0xf, static_cast<Register>(0), rt, imm16), rt, ZERO, ZERO);
+ DsFsmInstr(EmitI(0xf, static_cast<Register>(0), rt, imm16)).GprOuts(rt);
}
void MipsAssembler::Aui(Register rt, Register rs, uint16_t imm16) {
CHECK(IsR6());
- DsFsmInstrRrr(EmitI(0xf, rs, rt, imm16), rt, rt, rs);
+ DsFsmInstr(EmitI(0xf, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::AddUpper(Register rt, Register rs, uint16_t imm16, Register tmp) {
@@ -871,27 +790,27 @@ void MipsAssembler::Sync(uint32_t stype) {
void MipsAssembler::Mfhi(Register rd) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x10), rd, ZERO, ZERO);
+ DsFsmInstr(EmitR(0, ZERO, ZERO, rd, 0, 0x10)).GprOuts(rd);
}
void MipsAssembler::Mflo(Register rd) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitR(0, ZERO, ZERO, rd, 0, 0x12), rd, ZERO, ZERO);
+ DsFsmInstr(EmitR(0, ZERO, ZERO, rd, 0, 0x12)).GprOuts(rd);
}
void MipsAssembler::Sb(Register rt, Register rs, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0x28, rs, rt, imm16), ZERO, rt, rs);
+ DsFsmInstr(EmitI(0x28, rs, rt, imm16)).GprIns(rt, rs);
}
void MipsAssembler::Sh(Register rt, Register rs, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0x29, rs, rt, imm16), ZERO, rt, rs);
+ DsFsmInstr(EmitI(0x29, rs, rt, imm16)).GprIns(rt, rs);
}
void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16, MipsLabel* patcher_label) {
if (patcher_label != nullptr) {
Bind(patcher_label);
}
- DsFsmInstrRrr(EmitI(0x2b, rs, rt, imm16), ZERO, rt, rs, patcher_label);
+ DsFsmInstr(EmitI(0x2b, rs, rt, imm16), patcher_label).GprIns(rt, rs);
}
void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
@@ -900,50 +819,50 @@ void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitI(0x2a, rs, rt, imm16), ZERO, rt, rs);
+ DsFsmInstr(EmitI(0x2a, rs, rt, imm16)).GprIns(rt, rs);
}
void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitI(0x2e, rs, rt, imm16), ZERO, rt, rs);
+ DsFsmInstr(EmitI(0x2e, rs, rt, imm16)).GprIns(rt, rs);
}
void MipsAssembler::LlR2(Register rt, Register base, int16_t imm16) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitI(0x30, base, rt, imm16), rt, base, base);
+ DsFsmInstr(EmitI(0x30, base, rt, imm16)).GprOuts(rt).GprIns(base);
}
void MipsAssembler::ScR2(Register rt, Register base, int16_t imm16) {
CHECK(!IsR6());
- DsFsmInstrRrr(EmitI(0x38, base, rt, imm16), rt, rt, base);
+ DsFsmInstr(EmitI(0x38, base, rt, imm16)).GprInOuts(rt).GprIns(base);
}
void MipsAssembler::LlR6(Register rt, Register base, int16_t imm9) {
CHECK(IsR6());
CHECK(IsInt<9>(imm9));
- DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36), rt, base, base);
+ DsFsmInstr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x36)).GprOuts(rt).GprIns(base);
}
void MipsAssembler::ScR6(Register rt, Register base, int16_t imm9) {
CHECK(IsR6());
CHECK(IsInt<9>(imm9));
- DsFsmInstrRrr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26), rt, rt, base);
+ DsFsmInstr(EmitI(0x1f, base, rt, ((imm9 & 0x1ff) << 7) | 0x26)).GprInOuts(rt).GprIns(base);
}
void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2a), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x2a)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Sltu(Register rd, Register rs, Register rt) {
- DsFsmInstrRrr(EmitR(0, rs, rt, rd, 0, 0x2b), rd, rs, rt);
+ DsFsmInstr(EmitR(0, rs, rt, rd, 0, 0x2b)).GprOuts(rd).GprIns(rs, rt);
}
void MipsAssembler::Slti(Register rt, Register rs, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0xa, rs, rt, imm16), rt, rs, rs);
+ DsFsmInstr(EmitI(0xa, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::Sltiu(Register rt, Register rs, uint16_t imm16) {
- DsFsmInstrRrr(EmitI(0xb, rs, rt, imm16), rt, rs, rs);
+ DsFsmInstr(EmitI(0xb, rs, rt, imm16)).GprOuts(rt).GprIns(rs);
}
void MipsAssembler::B(uint16_t imm16) {
@@ -1021,8 +940,8 @@ void MipsAssembler::Jalr(Register rd, Register rs) {
uint32_t last_instruction = delay_slot_.instruction_;
MipsLabel* patcher_label = delay_slot_.patcher_label_;
bool exchange = (last_instruction != 0 &&
- (delay_slot_.gpr_outs_mask_ & (1u << rs)) == 0 &&
- ((delay_slot_.gpr_ins_mask_ | delay_slot_.gpr_outs_mask_) & (1u << rd)) == 0);
+ (delay_slot_.masks_.gpr_outs_ & (1u << rs)) == 0 &&
+ ((delay_slot_.masks_.gpr_ins_ | delay_slot_.masks_.gpr_outs_) & (1u << rd)) == 0);
if (exchange) {
// The last instruction cannot be used in a different delay slot,
// do not commit the label before it (if any).
@@ -1305,67 +1224,67 @@ void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt,
}
void MipsAssembler::AddS(FRegister fd, FRegister fs, FRegister ft) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x0), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x0)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::SubS(FRegister fd, FRegister fs, FRegister ft) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::MulS(FRegister fd, FRegister fs, FRegister ft) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x2), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x2)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::DivS(FRegister fd, FRegister fs, FRegister ft) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x3), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x3)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::AddD(FRegister fd, FRegister fs, FRegister ft) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x0), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x0)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::SubD(FRegister fd, FRegister fs, FRegister ft) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::MulD(FRegister fd, FRegister fs, FRegister ft) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x2), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x2)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::DivD(FRegister fd, FRegister fs, FRegister ft) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x3), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x3)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::SqrtS(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x4)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::SqrtD(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x4)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::AbsS(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x5)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::AbsD(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x5)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::MovS(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x6)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::MovD(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x6)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::NegS(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x7)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::NegD(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::CunS(FRegister fs, FRegister ft) {
@@ -1375,7 +1294,8 @@ void MipsAssembler::CunS(FRegister fs, FRegister ft) {
void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::CeqS(FRegister fs, FRegister ft) {
@@ -1385,7 +1305,8 @@ void MipsAssembler::CeqS(FRegister fs, FRegister ft) {
void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::CueqS(FRegister fs, FRegister ft) {
@@ -1395,7 +1316,8 @@ void MipsAssembler::CueqS(FRegister fs, FRegister ft) {
void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::ColtS(FRegister fs, FRegister ft) {
@@ -1405,7 +1327,8 @@ void MipsAssembler::ColtS(FRegister fs, FRegister ft) {
void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::CultS(FRegister fs, FRegister ft) {
@@ -1415,7 +1338,8 @@ void MipsAssembler::CultS(FRegister fs, FRegister ft) {
void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::ColeS(FRegister fs, FRegister ft) {
@@ -1425,7 +1349,8 @@ void MipsAssembler::ColeS(FRegister fs, FRegister ft) {
void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::CuleS(FRegister fs, FRegister ft) {
@@ -1435,7 +1360,8 @@ void MipsAssembler::CuleS(FRegister fs, FRegister ft) {
void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::CunD(FRegister fs, FRegister ft) {
@@ -1445,7 +1371,8 @@ void MipsAssembler::CunD(FRegister fs, FRegister ft) {
void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::CeqD(FRegister fs, FRegister ft) {
@@ -1455,7 +1382,8 @@ void MipsAssembler::CeqD(FRegister fs, FRegister ft) {
void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::CueqD(FRegister fs, FRegister ft) {
@@ -1465,7 +1393,8 @@ void MipsAssembler::CueqD(FRegister fs, FRegister ft) {
void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::ColtD(FRegister fs, FRegister ft) {
@@ -1475,7 +1404,8 @@ void MipsAssembler::ColtD(FRegister fs, FRegister ft) {
void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::CultD(FRegister fs, FRegister ft) {
@@ -1485,7 +1415,8 @@ void MipsAssembler::CultD(FRegister fs, FRegister ft) {
void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::ColeD(FRegister fs, FRegister ft) {
@@ -1495,7 +1426,8 @@ void MipsAssembler::ColeD(FRegister fs, FRegister ft) {
void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::CuleD(FRegister fs, FRegister ft) {
@@ -1505,301 +1437,323 @@ void MipsAssembler::CuleD(FRegister fs, FRegister ft) {
void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrCff(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37), cc, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37))
+ .CcOuts(cc).FprIns(fs, ft);
}
void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x01), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x01)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x02), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x02)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x03), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x03)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x04), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x04)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x05), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x05)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x06), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x06)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x07), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x07)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x11), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x11)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x12), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x12)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x14, ft, fs, fd, 0x13), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x14, ft, fs, fd, 0x13)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x01), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x01)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x02), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x02)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x03), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x03)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x04), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x04)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x05), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x05)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x06), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x06)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x07), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x07)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x11), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x11)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x12), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x12)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x15, ft, fs, fd, 0x13), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x15, ft, fs, fd, 0x13)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::Movf(Register rd, Register rs, int cc) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01), rd, rs, cc);
+ DsFsmInstr(EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01))
+ .GprInOuts(rd).GprIns(rs).CcIns(cc);
}
void MipsAssembler::Movt(Register rd, Register rs, int cc) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrRrrc(EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01), rd, rs, cc);
+ DsFsmInstr(EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01))
+ .GprInOuts(rd).GprIns(rs).CcIns(cc);
}
void MipsAssembler::MovfS(FRegister fd, FRegister fs, int cc) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(cc << 2), fs, fd, 0x11))
+ .FprInOuts(fd).FprIns(fs).CcIns(cc);
}
void MipsAssembler::MovfD(FRegister fd, FRegister fs, int cc) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11), fd, fs, cc);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(cc << 2), fs, fd, 0x11))
+ .FprInOuts(fd).FprIns(fs).CcIns(cc);
}
void MipsAssembler::MovtS(FRegister fd, FRegister fs, int cc) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrFffc(EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11),
- fd,
- fs,
- cc);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11))
+ .FprInOuts(fd).FprIns(fs).CcIns(cc);
}
void MipsAssembler::MovtD(FRegister fd, FRegister fs, int cc) {
CHECK(!IsR6());
CHECK(IsUint<3>(cc)) << cc;
- DsFsmInstrFffc(EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11),
- fd,
- fs,
- cc);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>((cc << 2) | 1), fs, fd, 0x11))
+ .FprInOuts(fd).FprIns(fs).CcIns(cc);
}
void MipsAssembler::MovzS(FRegister fd, FRegister fs, Register rt) {
CHECK(!IsR6());
- DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x12))
+ .FprInOuts(fd).FprIns(fs).GprIns(rt);
}
void MipsAssembler::MovzD(FRegister fd, FRegister fs, Register rt) {
CHECK(!IsR6());
- DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x12), fd, fs, rt);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x12))
+ .FprInOuts(fd).FprIns(fs).GprIns(rt);
}
void MipsAssembler::MovnS(FRegister fd, FRegister fs, Register rt) {
CHECK(!IsR6());
- DsFsmInstrFffr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(rt), fs, fd, 0x13))
+ .FprInOuts(fd).FprIns(fs).GprIns(rt);
}
void MipsAssembler::MovnD(FRegister fd, FRegister fs, Register rt) {
CHECK(!IsR6());
- DsFsmInstrFffr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x13), fd, fs, rt);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(rt), fs, fd, 0x13))
+ .FprInOuts(fd).FprIns(fs).GprIns(rt);
}
void MipsAssembler::SelS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFfff(EmitFR(0x11, 0x10, ft, fs, fd, 0x10), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x10)).FprInOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::SelD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFfff(EmitFR(0x11, 0x11, ft, fs, fd, 0x10), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x10)).FprInOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::SeleqzS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x14), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x14)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::SeleqzD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x14), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x14)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::SelnezS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x17), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x17)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::SelnezD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x17), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x17)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::ClassS(FRegister fd, FRegister fs) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x1b)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::ClassD(FRegister fd, FRegister fs) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x1b)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::MinS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1c), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1c)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::MinD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1c), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1c)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::MaxS(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x10, ft, fs, fd, 0x1e), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x10, ft, fs, fd, 0x1e)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::MaxD(FRegister fd, FRegister fs, FRegister ft) {
CHECK(IsR6());
- DsFsmInstrFff(EmitFR(0x11, 0x11, ft, fs, fd, 0x1e), fd, fs, ft);
+ DsFsmInstr(EmitFR(0x11, 0x11, ft, fs, fd, 0x1e)).FprOuts(fd).FprIns(fs, ft);
}
void MipsAssembler::TruncLS(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x09)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::TruncLD(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x09)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::TruncWS(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x0D)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::TruncWD(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x0D)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::Cvtdw(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::Cvtsd(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::Cvtds(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::Cvtsl(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x20)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::Cvtdl(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x15, static_cast<FRegister>(0), fs, fd, 0x21)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::FloorWS(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x10, static_cast<FRegister>(0), fs, fd, 0xf)).FprOuts(fd).FprIns(fs);
}
void MipsAssembler::FloorWD(FRegister fd, FRegister fs) {
- DsFsmInstrFff(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf), fd, fs, fs);
+ DsFsmInstr(EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0xf)).FprOuts(fd).FprIns(fs);
+}
+
+FRegister MipsAssembler::GetFpuRegLow(FRegister reg) {
+ // If FPRs are 32-bit (and get paired to hold 64-bit values), accesses to
+ // odd-numbered FPRs are reattributed to even-numbered FPRs. This lets us
+ // use only even-numbered FPRs irrespective of whether we're doing single-
+ // or double-precision arithmetic. (We don't use odd-numbered 32-bit FPRs
+ // to hold single-precision values).
+ return Is32BitFPU() ? static_cast<FRegister>(reg & ~1u) : reg;
}
void MipsAssembler::Mfc1(Register rt, FRegister fs) {
- DsFsmInstrRf(EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
- rt,
- fs);
+ DsFsmInstr(EmitFR(0x11, 0x00, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0))
+ .GprOuts(rt).FprIns(GetFpuRegLow(fs));
}
+// Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs
+// when loading the value as 32-bit halves.
void MipsAssembler::Mtc1(Register rt, FRegister fs) {
- DsFsmInstrFr(EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
- fs,
- rt);
+ uint32_t encoding =
+ EmitFR(0x11, 0x04, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0);
+ if (Is32BitFPU() && (fs % 2 != 0)) {
+ // If mtc1 is used to simulate mthc1 by writing to the odd-numbered FPR in
+ // a pair of 32-bit FPRs, the associated even-numbered FPR is an in/out.
+ DsFsmInstr(encoding).FprInOuts(GetFpuRegLow(fs)).GprIns(rt);
+ } else {
+ // Otherwise (the FPR is 64-bit or even-numbered), the FPR is an out.
+ DsFsmInstr(encoding).FprOuts(fs).GprIns(rt);
+ }
}
void MipsAssembler::Mfhc1(Register rt, FRegister fs) {
- DsFsmInstrRf(EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
- rt,
- fs);
+ DsFsmInstr(EmitFR(0x11, 0x03, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0))
+ .GprOuts(rt).FprIns(fs);
}
+// Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs
+// when loading the value as 32-bit halves.
void MipsAssembler::Mthc1(Register rt, FRegister fs) {
- DsFsmInstrFr(EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0),
- fs,
- rt);
+ DsFsmInstr(EmitFR(0x11, 0x07, static_cast<FRegister>(rt), fs, static_cast<FRegister>(0), 0x0))
+ .FprInOuts(fs).GprIns(rt);
}
void MipsAssembler::MoveFromFpuHigh(Register rt, FRegister fs) {
@@ -1820,20 +1774,30 @@ void MipsAssembler::MoveToFpuHigh(Register rt, FRegister fs) {
}
}
+// Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs
+// when loading the value as 32-bit halves.
void MipsAssembler::Lwc1(FRegister ft, Register rs, uint16_t imm16) {
- DsFsmInstrFr(EmitI(0x31, rs, static_cast<Register>(ft), imm16), ft, rs);
+ uint32_t encoding = EmitI(0x31, rs, static_cast<Register>(ft), imm16);
+ if (Is32BitFPU() && (ft % 2 != 0)) {
+ // If lwc1 is used to load the odd-numbered FPR in a pair of 32-bit FPRs,
+ // the associated even-numbered FPR is an in/out.
+ DsFsmInstr(encoding).FprInOuts(GetFpuRegLow(ft)).GprIns(rs);
+ } else {
+ // Otherwise (the FPR is 64-bit or even-numbered), the FPR is an out.
+ DsFsmInstr(encoding).FprOuts(ft).GprIns(rs);
+ }
}
void MipsAssembler::Ldc1(FRegister ft, Register rs, uint16_t imm16) {
- DsFsmInstrFr(EmitI(0x35, rs, static_cast<Register>(ft), imm16), ft, rs);
+ DsFsmInstr(EmitI(0x35, rs, static_cast<Register>(ft), imm16)).FprOuts(ft).GprIns(rs);
}
void MipsAssembler::Swc1(FRegister ft, Register rs, uint16_t imm16) {
- DsFsmInstrFR(EmitI(0x39, rs, static_cast<Register>(ft), imm16), ft, rs);
+ DsFsmInstr(EmitI(0x39, rs, static_cast<Register>(ft), imm16)).FprIns(GetFpuRegLow(ft)).GprIns(rs);
}
void MipsAssembler::Sdc1(FRegister ft, Register rs, uint16_t imm16) {
- DsFsmInstrFR(EmitI(0x3d, rs, static_cast<Register>(ft), imm16), ft, rs);
+ DsFsmInstr(EmitI(0x3d, rs, static_cast<Register>(ft), imm16)).FprIns(ft).GprIns(rs);
}
void MipsAssembler::Break() {
@@ -1882,1447 +1846,951 @@ void MipsAssembler::PopAndReturn(Register rd, Register rt) {
void MipsAssembler::AndV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::OrV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::NorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::XorV(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::AddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::AddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::AddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::AddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MulvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MulvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MulvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MulvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Div_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Div_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Div_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Div_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Div_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Div_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Div_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Div_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Mod_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Mod_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Mod_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Mod_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Mod_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Mod_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Mod_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Mod_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x12)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Add_aB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Add_aH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Add_aW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Add_aD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Ave_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Ave_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Ave_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Ave_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Ave_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Ave_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Ave_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Ave_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Aver_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Aver_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Aver_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Aver_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Aver_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Aver_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Aver_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Aver_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x10)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Max_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Max_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Max_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Max_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Max_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x3, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Max_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x3, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Max_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x3, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Max_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x3, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Min_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Min_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Min_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Min_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Min_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Min_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Min_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Min_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0xe)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FmulW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FmulD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FdivW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FdivD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FmaxW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FmaxD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FminW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FminD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x1b)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Ffint_sW(VectorRegister wd, VectorRegister ws) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsa2RF(0x19e, 0x0, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::Ffint_sD(VectorRegister wd, VectorRegister ws) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsa2RF(0x19e, 0x1, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::Ftint_sW(VectorRegister wd, VectorRegister ws) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsa2RF(0x19c, 0x0, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::Ftint_sD(VectorRegister wd, VectorRegister ws) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsa2RF(0x19c, 0x1, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SllB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SllH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SllW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SllD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x0, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SraB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SraH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SraW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SraD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SrlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SrlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SrlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SrlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0xd)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::SlliB(VectorRegister wd, VectorRegister ws, int shamt3) {
CHECK(HasMsa());
CHECK(IsUint<3>(shamt3)) << shamt3;
- DsFsmInstrFff(EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x0, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SlliH(VectorRegister wd, VectorRegister ws, int shamt4) {
CHECK(HasMsa());
CHECK(IsUint<4>(shamt4)) << shamt4;
- DsFsmInstrFff(EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x0, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SlliW(VectorRegister wd, VectorRegister ws, int shamt5) {
CHECK(HasMsa());
CHECK(IsUint<5>(shamt5)) << shamt5;
- DsFsmInstrFff(EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x0, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SlliD(VectorRegister wd, VectorRegister ws, int shamt6) {
CHECK(HasMsa());
CHECK(IsUint<6>(shamt6)) << shamt6;
- DsFsmInstrFff(EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x0, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SraiB(VectorRegister wd, VectorRegister ws, int shamt3) {
CHECK(HasMsa());
CHECK(IsUint<3>(shamt3)) << shamt3;
- DsFsmInstrFff(EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x1, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SraiH(VectorRegister wd, VectorRegister ws, int shamt4) {
CHECK(HasMsa());
CHECK(IsUint<4>(shamt4)) << shamt4;
- DsFsmInstrFff(EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x1, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SraiW(VectorRegister wd, VectorRegister ws, int shamt5) {
CHECK(HasMsa());
CHECK(IsUint<5>(shamt5)) << shamt5;
- DsFsmInstrFff(EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x1, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SraiD(VectorRegister wd, VectorRegister ws, int shamt6) {
CHECK(HasMsa());
CHECK(IsUint<6>(shamt6)) << shamt6;
- DsFsmInstrFff(EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x1, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SrliB(VectorRegister wd, VectorRegister ws, int shamt3) {
CHECK(HasMsa());
CHECK(IsUint<3>(shamt3)) << shamt3;
- DsFsmInstrFff(EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x2, shamt3 | kMsaDfMByteMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SrliH(VectorRegister wd, VectorRegister ws, int shamt4) {
CHECK(HasMsa());
CHECK(IsUint<4>(shamt4)) << shamt4;
- DsFsmInstrFff(EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x2, shamt4 | kMsaDfMHalfwordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SrliW(VectorRegister wd, VectorRegister ws, int shamt5) {
CHECK(HasMsa());
CHECK(IsUint<5>(shamt5)) << shamt5;
- DsFsmInstrFff(EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x2, shamt5 | kMsaDfMWordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SrliD(VectorRegister wd, VectorRegister ws, int shamt6) {
CHECK(HasMsa());
CHECK(IsUint<6>(shamt6)) << shamt6;
- DsFsmInstrFff(EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x2, shamt6 | kMsaDfMDoublewordMask, ws, wd, 0x9)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::MoveV(VectorRegister wd, VectorRegister ws) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaBIT(0x1, 0x3e, ws, wd, 0x19)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SplatiB(VectorRegister wd, VectorRegister ws, int n4) {
CHECK(HasMsa());
CHECK(IsUint<4>(n4)) << n4;
- DsFsmInstrFff(EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaELM(0x1, n4 | kMsaDfNByteMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SplatiH(VectorRegister wd, VectorRegister ws, int n3) {
CHECK(HasMsa());
CHECK(IsUint<3>(n3)) << n3;
- DsFsmInstrFff(EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaELM(0x1, n3 | kMsaDfNHalfwordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SplatiW(VectorRegister wd, VectorRegister ws, int n2) {
CHECK(HasMsa());
CHECK(IsUint<2>(n2)) << n2;
- DsFsmInstrFff(EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaELM(0x1, n2 | kMsaDfNWordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::SplatiD(VectorRegister wd, VectorRegister ws, int n1) {
CHECK(HasMsa());
CHECK(IsUint<1>(n1)) << n1;
- DsFsmInstrFff(EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaELM(0x1, n1 | kMsaDfNDoublewordMask, ws, wd, 0x19)).FprOuts(wd).FprIns(ws);
}
void MipsAssembler::Copy_sB(Register rd, VectorRegister ws, int n4) {
CHECK(HasMsa());
CHECK(IsUint<4>(n4)) << n4;
- DsFsmInstrRf(EmitMsaELM(0x2, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19),
- rd,
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaELM(0x2, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19))
+ .GprOuts(rd).FprIns(ws);
}
void MipsAssembler::Copy_sH(Register rd, VectorRegister ws, int n3) {
CHECK(HasMsa());
CHECK(IsUint<3>(n3)) << n3;
- DsFsmInstrRf(EmitMsaELM(0x2, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19),
- rd,
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaELM(0x2, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19))
+ .GprOuts(rd).FprIns(ws);
}
void MipsAssembler::Copy_sW(Register rd, VectorRegister ws, int n2) {
CHECK(HasMsa());
CHECK(IsUint<2>(n2)) << n2;
- DsFsmInstrRf(EmitMsaELM(0x2, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19),
- rd,
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaELM(0x2, n2 | kMsaDfNWordMask, ws, static_cast<VectorRegister>(rd), 0x19))
+ .GprOuts(rd).FprIns(ws);
}
void MipsAssembler::Copy_uB(Register rd, VectorRegister ws, int n4) {
CHECK(HasMsa());
CHECK(IsUint<4>(n4)) << n4;
- DsFsmInstrRf(EmitMsaELM(0x3, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19),
- rd,
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaELM(0x3, n4 | kMsaDfNByteMask, ws, static_cast<VectorRegister>(rd), 0x19))
+ .GprOuts(rd).FprIns(ws);
}
void MipsAssembler::Copy_uH(Register rd, VectorRegister ws, int n3) {
CHECK(HasMsa());
CHECK(IsUint<3>(n3)) << n3;
- DsFsmInstrRf(EmitMsaELM(0x3, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19),
- rd,
- static_cast<FRegister>(ws));
+ DsFsmInstr(EmitMsaELM(0x3, n3 | kMsaDfNHalfwordMask, ws, static_cast<VectorRegister>(rd), 0x19))
+ .GprOuts(rd).FprIns(ws);
}
void MipsAssembler::InsertB(VectorRegister wd, Register rs, int n4) {
CHECK(HasMsa());
CHECK(IsUint<4>(n4)) << n4;
- DsFsmInstrFffr(EmitMsaELM(0x4, n4 | kMsaDfNByteMask, static_cast<VectorRegister>(rs), wd, 0x19),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsaELM(0x4, n4 | kMsaDfNByteMask, static_cast<VectorRegister>(rs), wd, 0x19))
+ .FprInOuts(wd).GprIns(rs);
}
void MipsAssembler::InsertH(VectorRegister wd, Register rs, int n3) {
CHECK(HasMsa());
CHECK(IsUint<3>(n3)) << n3;
- DsFsmInstrFffr(
- EmitMsaELM(0x4, n3 | kMsaDfNHalfwordMask, static_cast<VectorRegister>(rs), wd, 0x19),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsaELM(0x4, n3 | kMsaDfNHalfwordMask, static_cast<VectorRegister>(rs), wd, 0x19))
+ .FprInOuts(wd).GprIns(rs);
}
void MipsAssembler::InsertW(VectorRegister wd, Register rs, int n2) {
CHECK(HasMsa());
CHECK(IsUint<2>(n2)) << n2;
- DsFsmInstrFffr(EmitMsaELM(0x4, n2 | kMsaDfNWordMask, static_cast<VectorRegister>(rs), wd, 0x19),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsaELM(0x4, n2 | kMsaDfNWordMask, static_cast<VectorRegister>(rs), wd, 0x19))
+ .FprInOuts(wd).GprIns(rs);
}
void MipsAssembler::FillB(VectorRegister wd, Register rs) {
CHECK(HasMsa());
- DsFsmInstrFr(EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsa2R(0xc0, 0x0, static_cast<VectorRegister>(rs), wd, 0x1e))
+ .FprOuts(wd).GprIns(rs);
}
void MipsAssembler::FillH(VectorRegister wd, Register rs) {
CHECK(HasMsa());
- DsFsmInstrFr(EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsa2R(0xc0, 0x1, static_cast<VectorRegister>(rs), wd, 0x1e))
+ .FprOuts(wd).GprIns(rs);
}
void MipsAssembler::FillW(VectorRegister wd, Register rs) {
CHECK(HasMsa());
- DsFsmInstrFr(EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsa2R(0xc0, 0x2, static_cast<VectorRegister>(rs), wd, 0x1e))
+ .FprOuts(wd).GprIns(rs);
}
void MipsAssembler::LdiB(VectorRegister wd, int imm8) {
CHECK(HasMsa());
CHECK(IsInt<8>(imm8)) << imm8;
- DsFsmInstrFr(EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7),
- static_cast<FRegister>(wd),
- ZERO);
+ DsFsmInstr(EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7)).FprOuts(wd);
}
void MipsAssembler::LdiH(VectorRegister wd, int imm10) {
CHECK(HasMsa());
CHECK(IsInt<10>(imm10)) << imm10;
- DsFsmInstrFr(EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7),
- static_cast<FRegister>(wd),
- ZERO);
+ DsFsmInstr(EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd);
}
void MipsAssembler::LdiW(VectorRegister wd, int imm10) {
CHECK(HasMsa());
CHECK(IsInt<10>(imm10)) << imm10;
- DsFsmInstrFr(EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7),
- static_cast<FRegister>(wd),
- ZERO);
+ DsFsmInstr(EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd);
}
void MipsAssembler::LdiD(VectorRegister wd, int imm10) {
CHECK(HasMsa());
CHECK(IsInt<10>(imm10)) << imm10;
- DsFsmInstrFr(EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7),
- static_cast<FRegister>(wd),
- ZERO);
+ DsFsmInstr(EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7)).FprOuts(wd);
}
void MipsAssembler::LdB(VectorRegister wd, Register rs, int offset) {
CHECK(HasMsa());
CHECK(IsInt<10>(offset)) << offset;
- DsFsmInstrFr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x8, 0x0)).FprOuts(wd).GprIns(rs);
}
void MipsAssembler::LdH(VectorRegister wd, Register rs, int offset) {
CHECK(HasMsa());
CHECK(IsInt<11>(offset)) << offset;
CHECK_ALIGNED(offset, kMipsHalfwordSize);
- DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x8, 0x1))
+ .FprOuts(wd).GprIns(rs);
}
void MipsAssembler::LdW(VectorRegister wd, Register rs, int offset) {
CHECK(HasMsa());
CHECK(IsInt<12>(offset)) << offset;
CHECK_ALIGNED(offset, kMipsWordSize);
- DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x8, 0x2))
+ .FprOuts(wd).GprIns(rs);
}
void MipsAssembler::LdD(VectorRegister wd, Register rs, int offset) {
CHECK(HasMsa());
CHECK(IsInt<13>(offset)) << offset;
CHECK_ALIGNED(offset, kMipsDoublewordSize);
- DsFsmInstrFr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x8, 0x3))
+ .FprOuts(wd).GprIns(rs);
}
void MipsAssembler::StB(VectorRegister wd, Register rs, int offset) {
CHECK(HasMsa());
CHECK(IsInt<10>(offset)) << offset;
- DsFsmInstrFR(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0), static_cast<FRegister>(wd), rs);
+ DsFsmInstr(EmitMsaMI10(offset & kMsaS10Mask, rs, wd, 0x9, 0x0)).FprIns(wd).GprIns(rs);
}
void MipsAssembler::StH(VectorRegister wd, Register rs, int offset) {
CHECK(HasMsa());
CHECK(IsInt<11>(offset)) << offset;
CHECK_ALIGNED(offset, kMipsHalfwordSize);
- DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsaMI10((offset >> TIMES_2) & kMsaS10Mask, rs, wd, 0x9, 0x1))
+ .FprIns(wd).GprIns(rs);
}
void MipsAssembler::StW(VectorRegister wd, Register rs, int offset) {
CHECK(HasMsa());
CHECK(IsInt<12>(offset)) << offset;
CHECK_ALIGNED(offset, kMipsWordSize);
- DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsaMI10((offset >> TIMES_4) & kMsaS10Mask, rs, wd, 0x9, 0x2))
+ .FprIns(wd).GprIns(rs);
}
void MipsAssembler::StD(VectorRegister wd, Register rs, int offset) {
CHECK(HasMsa());
CHECK(IsInt<13>(offset)) << offset;
CHECK_ALIGNED(offset, kMipsDoublewordSize);
- DsFsmInstrFR(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3),
- static_cast<FRegister>(wd),
- rs);
+ DsFsmInstr(EmitMsaMI10((offset >> TIMES_8) & kMsaS10Mask, rs, wd, 0x9, 0x3))
+ .FprIns(wd).GprIns(rs);
}
void MipsAssembler::IlvlB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvlH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvlW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvlD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvrB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvrH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvrW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvrD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvevB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvevH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvevW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvevD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x6, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvodB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x0, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvodH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x1, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvodW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x2, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::IlvodD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x14),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x7, 0x3, wt, ws, wd, 0x14)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MaddvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x0, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MaddvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x1, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MaddvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x2, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MaddvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x1, 0x3, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MsubvB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MsubvH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MsubvW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::MsubvD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x12),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x12)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Asub_sB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x11),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x0, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Asub_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x11),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Asub_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x11),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Asub_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x11),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Asub_uB(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x11),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x0, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Asub_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x11),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Asub_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x11),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Asub_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x11),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x11)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FmaddW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x0, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FmaddD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x1, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FmsubW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x2, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::FmsubD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x1b),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x2, 0x3, wt, ws, wd, 0x1b)).FprInOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Hadd_sH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x15),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x1, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Hadd_sW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x15),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x2, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Hadd_sD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x15),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x4, 0x3, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Hadd_uH(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x15),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x1, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x15),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x2, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt) {
CHECK(HasMsa());
- DsFsmInstrFff(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15),
- static_cast<FRegister>(wd),
- static_cast<FRegister>(ws),
- static_cast<FRegister>(wt));
+ DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt);
}
void MipsAssembler::ReplicateFPToVectorRegister(VectorRegister dst,
@@ -4144,7 +3612,7 @@ bool MipsAssembler::Branch::CanHaveDelayedInstruction(const DelaySlot& delay_slo
case kLongCall:
// Instructions depending on or modifying RA should not be moved into delay slots
// of branches modifying RA.
- return ((delay_slot.gpr_ins_mask_ | delay_slot.gpr_outs_mask_) & (1u << RA)) == 0;
+ return ((delay_slot.masks_.gpr_ins_ | delay_slot.masks_.gpr_outs_) & (1u << RA)) == 0;
// R2 conditional branches.
case kCondBranch:
@@ -4157,17 +3625,17 @@ bool MipsAssembler::Branch::CanHaveDelayedInstruction(const DelaySlot& delay_slo
case kCondGTZ:
case kCondEQZ:
case kCondNEZ:
- return (delay_slot.gpr_outs_mask_ & (1u << lhs_reg_)) == 0;
+ return (delay_slot.masks_.gpr_outs_ & (1u << lhs_reg_)) == 0;
// Branches with two GPR sources.
case kCondEQ:
case kCondNE:
- return (delay_slot.gpr_outs_mask_ & ((1u << lhs_reg_) | (1u << rhs_reg_))) == 0;
+ return (delay_slot.masks_.gpr_outs_ & ((1u << lhs_reg_) | (1u << rhs_reg_))) == 0;
// Branches with one FPU condition code source.
case kCondF:
case kCondT:
- return (delay_slot.cc_outs_mask_ & (1u << lhs_reg_)) == 0;
+ return (delay_slot.masks_.cc_outs_ & (1u << lhs_reg_)) == 0;
default:
// We don't support synthetic R2 branches (preceded with slt[u]) at this level
@@ -4192,7 +3660,7 @@ bool MipsAssembler::Branch::CanHaveDelayedInstruction(const DelaySlot& delay_slo
// Branches with one FPU register source.
case kCondF:
case kCondT:
- return (delay_slot.fpr_outs_mask_ & (1u << lhs_reg_)) == 0;
+ return (delay_slot.masks_.fpr_outs_ & (1u << lhs_reg_)) == 0;
// Others have a forbidden slot instead of a delay slot.
default:
return false;
@@ -4858,8 +4326,8 @@ bool MipsAssembler::CanExchangeWithSlt(Register rs, Register rt) const {
// Likewise, if the instruction depends on AT, it can't be exchanged with slt[u]
// because slt[u] changes AT.
return (delay_slot_.instruction_ != 0 &&
- (delay_slot_.gpr_outs_mask_ & ((1u << AT) | (1u << rs) | (1u << rt))) == 0 &&
- (delay_slot_.gpr_ins_mask_ & (1u << AT)) == 0);
+ (delay_slot_.masks_.gpr_outs_ & ((1u << AT) | (1u << rs) | (1u << rt))) == 0 &&
+ (delay_slot_.masks_.gpr_ins_ & (1u << AT)) == 0);
}
void MipsAssembler::ExchangeWithSlt(const DelaySlot& forwarded_slot) {
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 1c3097ac58..7de8e2e366 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -74,6 +74,81 @@ enum FPClassMaskType {
kPositiveZero = 0x200,
};
+// Instruction description in terms of input and output registers.
+// Used for instruction reordering.
+struct InOutRegMasks {
+ InOutRegMasks()
+ : gpr_outs_(0), gpr_ins_(0), fpr_outs_(0), fpr_ins_(0), cc_outs_(0), cc_ins_(0) {}
+
+ inline InOutRegMasks& GprOuts(Register reg) {
+ gpr_outs_ |= (1u << reg);
+ gpr_outs_ &= ~1u; // Ignore register ZERO.
+ return *this;
+ }
+ template<typename T, typename... Ts>
+ inline InOutRegMasks& GprOuts(T one, Ts... more) { GprOuts(one); GprOuts(more...); return *this; }
+
+ inline InOutRegMasks& GprIns(Register reg) {
+ gpr_ins_ |= (1u << reg);
+ gpr_ins_ &= ~1u; // Ignore register ZERO.
+ return *this;
+ }
+ template<typename T, typename... Ts>
+ inline InOutRegMasks& GprIns(T one, Ts... more) { GprIns(one); GprIns(more...); return *this; }
+
+ inline InOutRegMasks& GprInOuts(Register reg) { GprIns(reg); GprOuts(reg); return *this; }
+ template<typename T, typename... Ts>
+ inline InOutRegMasks& GprInOuts(T one, Ts... more) {
+ GprInOuts(one);
+ GprInOuts(more...);
+ return *this;
+ }
+
+ inline InOutRegMasks& FprOuts(FRegister reg) { fpr_outs_ |= (1u << reg); return *this; }
+ inline InOutRegMasks& FprOuts(VectorRegister reg) { return FprOuts(static_cast<FRegister>(reg)); }
+ template<typename T, typename... Ts>
+ inline InOutRegMasks& FprOuts(T one, Ts... more) { FprOuts(one); FprOuts(more...); return *this; }
+
+ inline InOutRegMasks& FprIns(FRegister reg) { fpr_ins_ |= (1u << reg); return *this; }
+ inline InOutRegMasks& FprIns(VectorRegister reg) { return FprIns(static_cast<FRegister>(reg)); }
+ template<typename T, typename... Ts>
+ inline InOutRegMasks& FprIns(T one, Ts... more) { FprIns(one); FprIns(more...); return *this; }
+
+ inline InOutRegMasks& FprInOuts(FRegister reg) { FprIns(reg); FprOuts(reg); return *this; }
+ inline InOutRegMasks& FprInOuts(VectorRegister reg) {
+ return FprInOuts(static_cast<FRegister>(reg));
+ }
+ template<typename T, typename... Ts>
+ inline InOutRegMasks& FprInOuts(T one, Ts... more) {
+ FprInOuts(one);
+ FprInOuts(more...);
+ return *this;
+ }
+
+ inline InOutRegMasks& CcOuts(int cc) { cc_outs_ |= (1u << cc); return *this; }
+ template<typename T, typename... Ts>
+ inline InOutRegMasks& CcOuts(T one, Ts... more) { CcOuts(one); CcOuts(more...); return *this; }
+
+ inline InOutRegMasks& CcIns(int cc) { cc_ins_ |= (1u << cc); return *this; }
+ template<typename T, typename... Ts>
+ inline InOutRegMasks& CcIns(T one, Ts... more) { CcIns(one); CcIns(more...); return *this; }
+
+ // Mask of output GPRs for the instruction.
+ uint32_t gpr_outs_;
+ // Mask of input GPRs for the instruction.
+ uint32_t gpr_ins_;
+ // Mask of output FPRs for the instruction.
+ uint32_t fpr_outs_;
+ // Mask of input FPRs for the instruction.
+ uint32_t fpr_ins_;
+ // Mask of output FPU condition code flags for the instruction.
+ uint32_t cc_outs_;
+ // Mask of input FPU condition code flags for the instruction.
+ uint32_t cc_ins_;
+
+ // TODO: add LO and HI.
+};
+
class MipsLabel : public Label {
public:
MipsLabel() : prev_branch_id_plus_one_(0) {}
@@ -462,6 +537,16 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
void FloorWS(FRegister fd, FRegister fs);
void FloorWD(FRegister fd, FRegister fs);
+ // Note, the 32 LSBs of a 64-bit value must be loaded into an FPR before the 32 MSBs
+ // when loading the value as 32-bit halves. This applies to all 32-bit FPR loads:
+ // Mtc1(), Mthc1(), MoveToFpuHigh(), Lwc1(). Even if you need two Mtc1()'s or two
+ // Lwc1()'s to load a pair of 32-bit FPRs and these loads do not interfere with one
+ // another (unlike Mtc1() and Mthc1() with 64-bit FPRs), maintain the order:
+ // low then high.
+ //
+ // Also, prefer MoveFromFpuHigh()/MoveToFpuHigh() over Mfhc1()/Mthc1() and Mfc1()/Mtc1().
+ // This will save you some if statements.
+ FRegister GetFpuRegLow(FRegister reg);
void Mfc1(Register rt, FRegister fs);
void Mtc1(Register rt, FRegister fs);
void Mfhc1(Register rt, FRegister fs);
@@ -1337,23 +1422,13 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
// Used to make the decision of moving the instruction into a delay slot.
struct DelaySlot {
DelaySlot();
+
// Encoded instruction that may be used to fill the delay slot or 0
// (0 conveniently represents NOP).
uint32_t instruction_;
- // Mask of output GPRs for the instruction.
- uint32_t gpr_outs_mask_;
- // Mask of input GPRs for the instruction.
- uint32_t gpr_ins_mask_;
- // Mask of output FPRs for the instruction.
- uint32_t fpr_outs_mask_;
- // Mask of input FPRs for the instruction.
- uint32_t fpr_ins_mask_;
- // Mask of output FPU condition code flags for the instruction.
- uint32_t cc_outs_mask_;
- // Mask of input FPU condition code flags for the instruction.
- uint32_t cc_ins_mask_;
- // Branches never operate on the LO and HI registers, hence there's
- // no mask for LO and HI.
+
+ // Input/output register masks.
+ InOutRegMasks masks_;
// Label for patchable instructions to allow moving them into delay slots.
MipsLabel* patcher_label_;
@@ -1646,30 +1721,8 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
void FinalizeLabeledBranch(MipsLabel* label);
// Various helpers for branch delay slot management.
- void DsFsmInstr(uint32_t instruction,
- uint32_t gpr_outs_mask,
- uint32_t gpr_ins_mask,
- uint32_t fpr_outs_mask,
- uint32_t fpr_ins_mask,
- uint32_t cc_outs_mask,
- uint32_t cc_ins_mask,
- MipsLabel* patcher_label = nullptr);
+ InOutRegMasks& DsFsmInstr(uint32_t instruction, MipsLabel* patcher_label = nullptr);
void DsFsmInstrNop(uint32_t instruction);
- void DsFsmInstrRrr(uint32_t instruction,
- Register out,
- Register in1,
- Register in2,
- MipsLabel* patcher_label = nullptr);
- void DsFsmInstrRrrr(uint32_t instruction, Register in1_out, Register in2, Register in3);
- void DsFsmInstrFff(uint32_t instruction, FRegister out, FRegister in1, FRegister in2);
- void DsFsmInstrFfff(uint32_t instruction, FRegister in1_out, FRegister in2, FRegister in3);
- void DsFsmInstrFffr(uint32_t instruction, FRegister in1_out, FRegister in2, Register in3);
- void DsFsmInstrRf(uint32_t instruction, Register out, FRegister in);
- void DsFsmInstrFr(uint32_t instruction, FRegister out, Register in);
- void DsFsmInstrFR(uint32_t instruction, FRegister in1, Register in2);
- void DsFsmInstrCff(uint32_t instruction, int cc_out, FRegister in1, FRegister in2);
- void DsFsmInstrRrrc(uint32_t instruction, Register in1_out, Register in2, int cc_in);
- void DsFsmInstrFffc(uint32_t instruction, FRegister in1_out, FRegister in2, int cc_in);
void DsFsmLabel();
void DsFsmCommitLabel();
void DsFsmDropLabel();
diff --git a/compiler/utils/mips/constants_mips.h b/compiler/utils/mips/constants_mips.h
index b4dfdbd8d3..016c0dbb2e 100644
--- a/compiler/utils/mips/constants_mips.h
+++ b/compiler/utils/mips/constants_mips.h
@@ -19,8 +19,9 @@
#include <iosfwd>
+#include <android-base/logging.h>
+
#include "arch/mips/registers_mips.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "globals.h"
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index bf56877499..e1b0e75108 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -430,6 +430,20 @@ void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) {
EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3);
}
+void Mips64Assembler::Ins(GpuRegister rd, GpuRegister rt, int pos, int size) {
+ CHECK(IsUint<5>(pos)) << pos;
+ CHECK(IsUint<5>(size - 1)) << size;
+ CHECK(IsUint<5>(pos + size - 1)) << pos << " + " << size;
+ EmitR(0x1f, rt, rd, static_cast<GpuRegister>(pos + size - 1), pos, 0x04);
+}
+
+void Mips64Assembler::Dinsm(GpuRegister rt, GpuRegister rs, int pos, int size) {
+ CHECK(IsUint<5>(pos)) << pos;
+ CHECK(2 <= size && size <= 64) << size;
+ CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
+ EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos, 0x5);
+}
+
void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
CHECK(IsUint<5>(pos - 32)) << pos;
CHECK(IsUint<5>(size - 1)) << size;
@@ -437,6 +451,23 @@ void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) {
EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6);
}
+void Mips64Assembler::Dins(GpuRegister rt, GpuRegister rs, int pos, int size) {
+ CHECK(IsUint<5>(pos)) << pos;
+ CHECK(IsUint<5>(size - 1)) << size;
+ CHECK(IsUint<5>(pos + size - 1)) << pos << " + " << size;
+ EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 1), pos, 0x7);
+}
+
+void Mips64Assembler::DblIns(GpuRegister rt, GpuRegister rs, int pos, int size) {
+ if (pos >= 32) {
+ Dinsu(rt, rs, pos, size);
+ } else if ((static_cast<int64_t>(pos) + size - 1) >= 32) {
+ Dinsm(rt, rs, pos, size);
+ } else {
+ Dins(rt, rs, pos, size);
+ }
+}
+
void Mips64Assembler::Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) {
CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne;
int sa = saPlusOne - 1;
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index 9f5e6aaa88..7a61f39e64 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -478,7 +478,11 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer
void Dsbh(GpuRegister rd, GpuRegister rt); // MIPS64
void Dshd(GpuRegister rd, GpuRegister rt); // MIPS64
void Dext(GpuRegister rs, GpuRegister rt, int pos, int size); // MIPS64
+ void Ins(GpuRegister rt, GpuRegister rs, int pos, int size);
+ void Dins(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64
+ void Dinsm(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64
void Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64
+ void DblIns(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64
void Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne);
void Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne); // MIPS64
void Wsbh(GpuRegister rd, GpuRegister rt);
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index d89ca3d6ea..b0e1d91c3f 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -1353,23 +1353,42 @@ TEST_F(AssemblerMIPS64Test, Dext) {
DriverStr(expected.str(), "Dext");
}
-TEST_F(AssemblerMIPS64Test, Dinsu) {
+TEST_F(AssemblerMIPS64Test, Ins) {
+ std::vector<mips64::GpuRegister*> regs = GetRegisters();
+ WarnOnCombinations(regs.size() * regs.size() * 33 * 16);
+ std::string expected;
+ for (mips64::GpuRegister* reg1 : regs) {
+ for (mips64::GpuRegister* reg2 : regs) {
+ for (int32_t pos = 0; pos < 32; pos++) {
+ for (int32_t size = 1; pos + size <= 32; size++) {
+ __ Ins(*reg1, *reg2, pos, size);
+ std::ostringstream instr;
+ instr << "ins $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n";
+ expected += instr.str();
+ }
+ }
+ }
+ }
+ DriverStr(expected, "Ins");
+}
+
+TEST_F(AssemblerMIPS64Test, DblIns) {
std::vector<mips64::GpuRegister*> reg1_registers = GetRegisters();
std::vector<mips64::GpuRegister*> reg2_registers = GetRegisters();
- WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * 33 * 16);
+ WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * 65 * 32);
std::ostringstream expected;
for (mips64::GpuRegister* reg1 : reg1_registers) {
for (mips64::GpuRegister* reg2 : reg2_registers) {
- for (int32_t pos = 32; pos < 64; pos++) {
+ for (int32_t pos = 0; pos < 64; pos++) {
for (int32_t size = 1; pos + size <= 64; size++) {
- __ Dinsu(*reg1, *reg2, pos, size);
- expected << "dinsu $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n";
+ __ DblIns(*reg1, *reg2, pos, size);
+ expected << "dins $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n";
}
}
}
}
- DriverStr(expected.str(), "Dinsu");
+ DriverStr(expected.str(), "DblIns");
}
TEST_F(AssemblerMIPS64Test, Lsa) {
diff --git a/compiler/utils/mips64/constants_mips64.h b/compiler/utils/mips64/constants_mips64.h
index bc8e40b437..310f23c287 100644
--- a/compiler/utils/mips64/constants_mips64.h
+++ b/compiler/utils/mips64/constants_mips64.h
@@ -19,8 +19,9 @@
#include <iosfwd>
+#include <android-base/logging.h>
+
#include "arch/mips64/registers_mips64.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "globals.h"
diff --git a/compiler/utils/string_reference_test.cc b/compiler/utils/string_reference_test.cc
index 90335eb048..4b07e65771 100644
--- a/compiler/utils/string_reference_test.cc
+++ b/compiler/utils/string_reference_test.cc
@@ -18,7 +18,7 @@
#include <memory>
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "gtest/gtest.h"
#include "utils/test_dex_file_builder.h"
diff --git a/compiler/utils/swap_space.cc b/compiler/utils/swap_space.cc
index 12d113d420..1f9ad4242d 100644
--- a/compiler/utils/swap_space.cc
+++ b/compiler/utils/swap_space.cc
@@ -22,7 +22,6 @@
#include <numeric>
#include "base/bit_utils.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "thread-current-inl.h"
diff --git a/compiler/utils/swap_space.h b/compiler/utils/swap_space.h
index 2280f8b993..76df527108 100644
--- a/compiler/utils/swap_space.h
+++ b/compiler/utils/swap_space.h
@@ -24,7 +24,8 @@
#include <set>
#include <vector>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/macros.h"
#include "base/mutex.h"
diff --git a/compiler/utils/test_dex_file_builder.h b/compiler/utils/test_dex_file_builder.h
index 0da30fe768..04fba51dc1 100644
--- a/compiler/utils/test_dex_file_builder.h
+++ b/compiler/utils/test_dex_file_builder.h
@@ -24,10 +24,11 @@
#include <set>
#include <vector>
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
-#include "dex_file_loader.h"
-#include "standard_dex_file.h"
+#include "dex/dex_file_loader.h"
+#include "dex/standard_dex_file.h"
namespace art {
diff --git a/compiler/utils/test_dex_file_builder_test.cc b/compiler/utils/test_dex_file_builder_test.cc
index c76739b3b1..736a17edac 100644
--- a/compiler/utils/test_dex_file_builder_test.cc
+++ b/compiler/utils/test_dex_file_builder_test.cc
@@ -16,7 +16,7 @@
#include "test_dex_file_builder.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "gtest/gtest.h"
#include "utils.h"
diff --git a/compiler/utils/x86/constants_x86.h b/compiler/utils/x86/constants_x86.h
index 0bc1560ed7..2e03b9fc3c 100644
--- a/compiler/utils/x86/constants_x86.h
+++ b/compiler/utils/x86/constants_x86.h
@@ -19,8 +19,9 @@
#include <iosfwd>
+#include <android-base/logging.h>
+
#include "arch/x86/registers_x86.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "globals.h"
diff --git a/compiler/utils/x86_64/constants_x86_64.h b/compiler/utils/x86_64/constants_x86_64.h
index cc508a196b..2af3e7be16 100644
--- a/compiler/utils/x86_64/constants_x86_64.h
+++ b/compiler/utils/x86_64/constants_x86_64.h
@@ -19,8 +19,9 @@
#include <iosfwd>
+#include <android-base/logging.h>
+
#include "arch/x86_64/registers_x86_64.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "globals.h"
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 4709fd0e9e..76448d819c 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -21,10 +21,10 @@
#include "class_linker.h"
#include "common_compiler_test.h"
#include "compiler_callbacks.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_types.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
-#include "dex_file-inl.h"
-#include "dex_file_types.h"
#include "driver/compiler_driver-inl.h"
#include "driver/compiler_options.h"
#include "handle_scope-inl.h"
@@ -158,11 +158,10 @@ class VerifierDepsTest : public CommonCompilerTest {
while (it.HasNextDirectMethod()) {
ArtMethod* resolved_method =
class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- *primary_dex_file_,
it.GetMemberIndex(),
dex_cache_handle,
class_loader_handle,
- nullptr,
+ /* referrer */ nullptr,
it.GetMethodInvokeType(*class_def));
CHECK(resolved_method != nullptr);
if (method_name == resolved_method->GetName()) {
@@ -238,9 +237,9 @@ class VerifierDepsTest : public CommonCompilerTest {
CHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
} else if (unverified_classes.find(class_def.class_idx_) == unverified_classes.end()) {
- ASSERT_EQ(cls->GetStatus(), mirror::Class::kStatusVerified);
+ ASSERT_EQ(cls->GetStatus(), ClassStatus::kVerified);
} else {
- ASSERT_LT(cls->GetStatus(), mirror::Class::kStatusVerified);
+ ASSERT_LT(cls->GetStatus(), ClassStatus::kVerified);
}
}
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 27bec1d3e1..dabe07f9ce 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -58,11 +58,12 @@
#include "compiler_callbacks.h"
#include "debug/elf_debug_writer.h"
#include "debug/method_debug_info.h"
+#include "dexlayout.h"
+#include "dex/dex_file-inl.h"
#include "dex/quick_compiler_callbacks.h"
#include "dex/verification_results.h"
#include "dex2oat_options.h"
#include "dex2oat_return_codes.h"
-#include "dex_file-inl.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
#include "driver/compiler_options_map-inl.h"
@@ -345,7 +346,7 @@ NO_RETURN static void Usage(const char* fmt, ...) {
CompilerOptions::kDefaultInlineMaxCodeUnits);
UsageError(" Default: %d", CompilerOptions::kDefaultInlineMaxCodeUnits);
UsageError("");
- UsageError(" --dump-timing: display a breakdown of where time was spent");
+ UsageError(" --dump-timings: display a breakdown of where time was spent");
UsageError("");
UsageError(" -g");
UsageError(" --generate-debug-info: Generate debug information for native debugging,");
@@ -537,11 +538,8 @@ class WatchDog {
// it's rather easy to hang in unwinding.
// LogLine also avoids ART logging lock issues, as it's really only a wrapper around
// logcat logging or stderr output.
- android::base::LogMessage::LogLine(__FILE__,
- __LINE__,
- android::base::LogId::DEFAULT,
- LogSeverity::FATAL,
- message.c_str());
+ LogHelper::LogLineLowStack(__FILE__, __LINE__, 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.
@@ -1686,10 +1684,10 @@ class Dex2Oat FINAL {
CHECK(class_loader != nullptr);
ScopedObjectAccess soa(Thread::Current());
// Unload class loader to free RAM.
- jweak weak_class_loader = soa.Env()->vm->AddWeakGlobalRef(
+ jweak weak_class_loader = soa.Env()->GetVm()->AddWeakGlobalRef(
soa.Self(),
soa.Decode<mirror::ClassLoader>(class_loader));
- soa.Env()->vm->DeleteGlobalRef(soa.Self(), class_loader);
+ soa.Env()->GetVm()->DeleteGlobalRef(soa.Self(), class_loader);
runtime_->GetHeap()->CollectGarbage(/*clear_soft_references*/ true);
ObjPtr<mirror::ClassLoader> decoded_weak = soa.Decode<mirror::ClassLoader>(weak_class_loader);
if (decoded_weak != nullptr) {
@@ -2233,12 +2231,16 @@ class Dex2Oat FINAL {
return DoProfileGuidedOptimizations();
}
- bool DoEagerUnquickeningOfVdex() const {
- // DexLayout can invalidate the vdex metadata, so we need to unquicken
- // the vdex file eagerly, before passing it to dexlayout.
+ bool MayInvalidateVdexMetadata() const {
+ // DexLayout can invalidate the vdex metadata if changing the class def order is enabled, so
+ // we need to unquicken the vdex file eagerly, before passing it to dexlayout.
return DoDexLayoutOptimizations();
}
+ bool DoEagerUnquickeningOfVdex() const {
+ return MayInvalidateVdexMetadata();
+ }
+
bool LoadProfile() {
DCHECK(UseProfile());
// TODO(calin): We should be using the runtime arena pool (instead of the
@@ -2814,7 +2816,7 @@ class Dex2Oat FINAL {
// Dex files we are compiling, does not include the class path dex files.
std::vector<const DexFile*> dex_files_;
std::string no_inline_from_string_;
- CompactDexLevel compact_dex_level_ = CompactDexLevel::kCompactDexLevelNone;
+ CompactDexLevel compact_dex_level_ = kDefaultCompactDexLevel;
std::vector<std::unique_ptr<linker::ElfWriter>> elf_writers_;
std::vector<std::unique_ptr<linker::OatWriter>> oat_writers_;
@@ -2885,7 +2887,7 @@ class ScopedGlobalRef {
~ScopedGlobalRef() {
if (obj_ != nullptr) {
ScopedObjectAccess soa(Thread::Current());
- soa.Env()->vm->DeleteGlobalRef(soa.Self(), obj_);
+ soa.Env()->GetVm()->DeleteGlobalRef(soa.Self(), obj_);
}
}
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index a02fbf862f..980363b1bb 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -22,14 +22,15 @@
#include <sys/wait.h>
#include <unistd.h>
+#include <android-base/logging.h>
+
#include "common_runtime_test.h"
#include "base/file_utils.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/unix_file/fd_file.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_loader.h"
#include "jit/profile_compilation_info.h"
#include "method_reference.h"
#include "runtime.h"
diff --git a/dex2oat/dex2oat_options.h b/dex2oat/dex2oat_options.h
index f8198ee08b..ccc85c8951 100644
--- a/dex2oat/dex2oat_options.h
+++ b/dex2oat/dex2oat_options.h
@@ -22,9 +22,9 @@
#include <vector>
#include "base/variant_map.h"
-#include "cdex/compact_dex_level.h"
#include "cmdline_types.h" // TODO: don't need to include this file here
#include "compiler.h"
+#include "dex/compact_dex_level.h"
#include "driver/compiler_options_map.h"
#include "image.h"
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index ad287b0745..c91240e19d 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -22,18 +22,19 @@
#include <sys/wait.h>
#include <unistd.h>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "common_runtime_test.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/mutex-inl.h"
#include "bytecode_utils.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_loader.h"
#include "dex2oat_environment_test.h"
#include "dex2oat_return_codes.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
#include "jit/profile_compilation_info.h"
#include "oat.h"
#include "oat_file.h"
@@ -875,6 +876,8 @@ TEST_F(Dex2oatLayoutTest, TestLayoutAppImage) {
}
TEST_F(Dex2oatLayoutTest, TestVdexLayout) {
+ // Disabled until figure out running compact dex + DexLayout causes quickening errors.
+ TEST_DISABLED_FOR_COMPACT_DEX();
RunTestVDex();
}
@@ -941,7 +944,7 @@ class Dex2oatUnquickenTest : public Dex2oatTest {
class_it.Next()) {
if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
for (const DexInstructionPcPair& inst :
- class_it.GetMethodCodeItem()->Instructions()) {
+ CodeItemInstructionAccessor(dex_file.get(), class_it.GetMethodCodeItem())) {
ASSERT_FALSE(inst->IsQuickened());
}
}
@@ -953,6 +956,8 @@ class Dex2oatUnquickenTest : public Dex2oatTest {
};
TEST_F(Dex2oatUnquickenTest, UnquickenMultiDex) {
+ // Disabled until figure out running compact dex + DexLayout causes quickening errors.
+ TEST_DISABLED_FOR_COMPACT_DEX();
RunUnquickenMultiDex();
}
@@ -991,6 +996,7 @@ TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) {
TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
TEST_DISABLED_FOR_MEMORY_TOOL_VALGRIND(); // b/63052624
+ TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS(); // b/63052624
// Check with ten milliseconds.
RunTest(false, { "--watchdog-timeout=10" });
}
diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc
index b139a12fd4..aa64b7d59e 100644
--- a/dex2oat/linker/elf_writer_quick.cc
+++ b/dex2oat/linker/elf_writer_quick.cc
@@ -20,8 +20,9 @@
#include <unordered_map>
#include <unordered_set>
+#include <android-base/logging.h>
+
#include "base/casts.h"
-#include "base/logging.h"
#include "compiled_method.h"
#include "debug/elf_debug_writer.h"
#include "debug/method_debug_info.h"
@@ -66,7 +67,7 @@ class DebugInfoTask : public Task {
void Run(Thread*) {
result_ = debug::MakeMiniDebugInfo(isa_,
instruction_set_features_,
- rodata_section_size_,
+ kPageSize + rodata_section_size_, // .text address.
text_section_size_,
method_infos_);
}
@@ -172,6 +173,7 @@ template <typename ElfTypes>
void ElfWriterQuick<ElfTypes>::Start() {
builder_->Start();
if (compiler_options_->GetGenerateBuildId()) {
+ builder_->GetBuildId()->AllocateVirtualMemory(builder_->GetBuildId()->GetSize());
builder_->WriteBuildIdSection();
}
}
@@ -224,9 +226,6 @@ void ElfWriterQuick<ElfTypes>::EndText(OutputStream* text) {
template <typename ElfTypes>
void ElfWriterQuick<ElfTypes>::WriteDynamicSection() {
- if (bss_size_ != 0u) {
- builder_->GetBss()->WriteNoBitsSection(bss_size_);
- }
if (builder_->GetIsa() == InstructionSet::kMips ||
builder_->GetIsa() == InstructionSet::kMips64) {
builder_->WriteMIPSabiflagsSection();
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index cedbccf7cc..85145d3d64 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -293,14 +293,7 @@ inline void CompilationHelper::Compile(CompilerDriver* driver,
bool image_space_ok = writer->PrepareImageAddressSpace();
ASSERT_TRUE(image_space_ok);
- for (size_t i = 0, size = vdex_files.size(); i != size; ++i) {
- std::unique_ptr<BufferedOutputStream> vdex_out =
- std::make_unique<BufferedOutputStream>(
- std::make_unique<FileOutputStream>(vdex_files[i].GetFile()));
- oat_writers[i]->WriteVerifierDeps(vdex_out.get(), nullptr);
- oat_writers[i]->WriteChecksumsAndVdexHeader(vdex_out.get());
- }
-
+ DCHECK_EQ(vdex_files.size(), oat_files.size());
for (size_t i = 0, size = oat_files.size(); i != size; ++i) {
MultiOatRelativePatcher patcher(driver->GetInstructionSet(),
driver->GetInstructionSetFeatures());
@@ -308,6 +301,14 @@ inline void CompilationHelper::Compile(CompilerDriver* driver,
ElfWriter* const elf_writer = elf_writers[i].get();
std::vector<const DexFile*> cur_dex_files(1u, class_path[i]);
oat_writer->Initialize(driver, writer.get(), cur_dex_files);
+
+ std::unique_ptr<BufferedOutputStream> vdex_out =
+ std::make_unique<BufferedOutputStream>(
+ std::make_unique<FileOutputStream>(vdex_files[i].GetFile()));
+ oat_writer->WriteVerifierDeps(vdex_out.get(), nullptr);
+ oat_writer->WriteQuickeningInfo(vdex_out.get());
+ oat_writer->WriteChecksumsAndVdexHeader(vdex_out.get());
+
oat_writer->PrepareLayout(&patcher);
size_t rodata_size = oat_writer->GetOatHeader().GetExecutableOffset();
size_t text_size = oat_writer->GetOatSize() - rodata_size;
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 68c9f80a44..73eaad47a1 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -29,12 +29,12 @@
#include "art_method-inl.h"
#include "base/callee_save_type.h"
#include "base/enums.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/unix_file/fd_file.h"
#include "class_linker-inl.h"
#include "compiled_method.h"
-#include "dex_file-inl.h"
-#include "dex_file_types.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_types.h"
#include "driver/compiler_driver.h"
#include "elf_file.h"
#include "elf_utils.h"
@@ -365,7 +365,7 @@ void ImageWriter::AssignImageOffset(mirror::Object* object, ImageWriter::BinSlot
size_t oat_index = GetOatIndex(object);
ImageInfo& image_info = GetImageInfo(oat_index);
- size_t bin_slot_offset = image_info.bin_slot_offsets_[bin_slot.GetBin()];
+ size_t bin_slot_offset = image_info.GetBinSlotOffset(bin_slot.GetBin());
size_t new_offset = bin_slot_offset + bin_slot.GetIndex();
DCHECK_ALIGNED(new_offset, kObjectAlignment);
@@ -436,9 +436,10 @@ void ImageWriter::PrepareDexCacheArraySlots() {
auto it = dex_file_oat_index_map_.find(dex_file);
DCHECK(it != dex_file_oat_index_map_.end()) << dex_file->GetLocation();
ImageInfo& image_info = GetImageInfo(it->second);
- image_info.dex_cache_array_starts_.Put(dex_file, image_info.bin_slot_sizes_[kBinDexCacheArray]);
+ image_info.dex_cache_array_starts_.Put(
+ dex_file, image_info.GetBinSlotSize(Bin::kDexCacheArray));
DexCacheArraysLayout layout(target_ptr_size_, dex_file);
- image_info.bin_slot_sizes_[kBinDexCacheArray] += layout.Size();
+ image_info.IncrementBinSlotSize(Bin::kDexCacheArray, layout.Size());
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -494,7 +495,7 @@ void ImageWriter::AddDexCacheArrayRelocation(void* array,
DCHECK(!IsInBootImage(array));
size_t oat_index = GetOatIndexForDexCache(dex_cache);
native_object_relocations_.emplace(array,
- NativeObjectRelocation { oat_index, offset, kNativeObjectRelocationTypeDexCacheArray });
+ NativeObjectRelocation { oat_index, offset, NativeObjectRelocationType::kDexCacheArray });
}
}
@@ -512,7 +513,7 @@ void ImageWriter::AddMethodPointerArray(mirror::PointerArray* arr) {
}
// kBinArtMethodClean picked arbitrarily, just required to differentiate between ArtFields and
// ArtMethods.
- pointer_arrays_.emplace(arr, kBinArtMethodClean);
+ pointer_arrays_.emplace(arr, Bin::kArtMethodClean);
}
void ImageWriter::AssignImageBinSlot(mirror::Object* object, size_t oat_index) {
@@ -528,8 +529,7 @@ void ImageWriter::AssignImageBinSlot(mirror::Object* object, size_t oat_index) {
//
// This means more pages will stay either clean or shared dirty (with zygote) and
// the app will use less of its own (private) memory.
- Bin bin = kBinRegular;
- size_t current_offset = 0u;
+ Bin bin = Bin::kRegular;
if (kBinObjects) {
//
@@ -563,7 +563,7 @@ void ImageWriter::AssignImageBinSlot(mirror::Object* object, size_t oat_index) {
// so packing them together will not result in a noticeably tighter dirty-to-clean ratio.
//
if (object->IsClass()) {
- bin = kBinClassVerified;
+ bin = Bin::kClassVerified;
mirror::Class* klass = object->AsClass();
// Add non-embedded vtable to the pointer array table if there is one.
@@ -584,15 +584,15 @@ void ImageWriter::AssignImageBinSlot(mirror::Object* object, size_t oat_index) {
// - classes with dirty static fields.
if (dirty_image_objects_ != nullptr &&
dirty_image_objects_->find(klass->PrettyDescriptor()) != dirty_image_objects_->end()) {
- bin = kBinKnownDirty;
- } else if (klass->GetStatus() == Class::kStatusInitialized) {
- bin = kBinClassInitialized;
+ bin = Bin::kKnownDirty;
+ } else if (klass->GetStatus() == ClassStatus::kInitialized) {
+ bin = Bin::kClassInitialized;
// If the class's static fields are all final, put it into a separate bin
// since it's very likely it will stay clean.
uint32_t num_static_fields = klass->NumStaticFields();
if (num_static_fields == 0) {
- bin = kBinClassInitializedFinalStatics;
+ bin = Bin::kClassInitializedFinalStatics;
} else {
// Maybe all the statics are final?
bool all_final = true;
@@ -605,20 +605,20 @@ void ImageWriter::AssignImageBinSlot(mirror::Object* object, size_t oat_index) {
}
if (all_final) {
- bin = kBinClassInitializedFinalStatics;
+ bin = Bin::kClassInitializedFinalStatics;
}
}
}
} else if (object->GetClass<kVerifyNone>()->IsStringClass()) {
- bin = kBinString; // Strings are almost always immutable (except for object header).
+ bin = Bin::kString; // Strings are almost always immutable (except for object header).
} else if (object->GetClass<kVerifyNone>() ==
Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kJavaLangObject)) {
// Instance of java lang object, probably a lock object. This means it will be dirty when we
// synchronize on it.
- bin = kBinMiscDirty;
+ bin = Bin::kMiscDirty;
} else if (object->IsDexCache()) {
// Dex file field becomes dirty when the image is loaded.
- bin = kBinMiscDirty;
+ bin = Bin::kMiscDirty;
}
// else bin = kBinRegular
}
@@ -630,14 +630,15 @@ void ImageWriter::AssignImageBinSlot(mirror::Object* object, size_t oat_index) {
ImageInfo& image_info = GetImageInfo(oat_index);
size_t offset_delta = RoundUp(object_size, kObjectAlignment); // 64-bit alignment
- current_offset = image_info.bin_slot_sizes_[bin]; // How many bytes the current bin is at (aligned).
+ // How many bytes the current bin is at (aligned).
+ size_t current_offset = image_info.GetBinSlotSize(bin);
// Move the current bin size up to accommodate the object we just assigned a bin slot.
- image_info.bin_slot_sizes_[bin] += offset_delta;
+ image_info.IncrementBinSlotSize(bin, offset_delta);
BinSlot new_bin_slot(bin, current_offset);
SetImageBinSlot(object, new_bin_slot);
- ++image_info.bin_slot_count_[bin];
+ image_info.IncrementBinSlotCount(bin, 1u);
// Grow the image closer to the end by the object we just assigned.
image_info.image_end_ += offset_delta;
@@ -649,7 +650,7 @@ bool ImageWriter::WillMethodBeDirty(ArtMethod* m) const {
}
mirror::Class* declaring_class = m->GetDeclaringClass();
// Initialized is highly unlikely to dirty since there's no entry points to mutate.
- return declaring_class == nullptr || declaring_class->GetStatus() != Class::kStatusInitialized;
+ return declaring_class == nullptr || declaring_class->GetStatus() != ClassStatus::kInitialized;
}
bool ImageWriter::IsImageBinSlotAssigned(mirror::Object* object) const {
@@ -665,7 +666,7 @@ bool ImageWriter::IsImageBinSlotAssigned(mirror::Object* object) const {
BinSlot bin_slot(offset);
size_t oat_index = GetOatIndex(object);
const ImageInfo& image_info = GetImageInfo(oat_index);
- DCHECK_LT(bin_slot.GetIndex(), image_info.bin_slot_sizes_[bin_slot.GetBin()])
+ DCHECK_LT(bin_slot.GetIndex(), image_info.GetBinSlotSize(bin_slot.GetBin()))
<< "bin slot offset should not exceed the size of that bin";
}
return true;
@@ -682,7 +683,7 @@ ImageWriter::BinSlot ImageWriter::GetImageBinSlot(mirror::Object* object) const
BinSlot bin_slot(static_cast<uint32_t>(offset));
size_t oat_index = GetOatIndex(object);
const ImageInfo& image_info = GetImageInfo(oat_index);
- DCHECK_LT(bin_slot.GetIndex(), image_info.bin_slot_sizes_[bin_slot.GetBin()]);
+ DCHECK_LT(bin_slot.GetIndex(), image_info.GetBinSlotSize(bin_slot.GetBin()));
return bin_slot;
}
@@ -1049,8 +1050,7 @@ void ImageWriter::PruneAndPreloadDexCache(ObjPtr<mirror::DexCache> dex_cache,
const DexFile::MethodId& method_id = dex_file.GetMethodId(i);
if (method_id.class_idx_ != last_class_idx) {
last_class_idx = method_id.class_idx_;
- last_class = class_linker->LookupResolvedType(
- dex_file, last_class_idx, dex_cache, class_loader);
+ last_class = class_linker->LookupResolvedType(last_class_idx, dex_cache, class_loader);
if (last_class != nullptr && !KeepClass(last_class)) {
last_class = nullptr;
}
@@ -1095,8 +1095,7 @@ void ImageWriter::PruneAndPreloadDexCache(ObjPtr<mirror::DexCache> dex_cache,
const DexFile::FieldId& field_id = dex_file.GetFieldId(i);
if (field_id.class_idx_ != last_class_idx) {
last_class_idx = field_id.class_idx_;
- last_class = class_linker->LookupResolvedType(
- dex_file, last_class_idx, dex_cache, class_loader);
+ last_class = class_linker->LookupResolvedType(last_class_idx, dex_cache, class_loader);
if (last_class != nullptr && !KeepClass(last_class)) {
last_class = nullptr;
}
@@ -1129,7 +1128,7 @@ void ImageWriter::PruneAndPreloadDexCache(ObjPtr<mirror::DexCache> dex_cache,
uint32_t stored_index = pair.index;
ObjPtr<mirror::Class> klass = pair.object.Read();
if (klass == nullptr || i < stored_index) {
- klass = class_linker->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader);
+ klass = class_linker->LookupResolvedType(type_idx, dex_cache, class_loader);
if (klass != nullptr) {
DCHECK_EQ(dex_cache->GetResolvedType(type_idx), klass);
stored_index = i; // For correct clearing below if not keeping the `klass`.
@@ -1147,7 +1146,7 @@ void ImageWriter::PruneAndPreloadDexCache(ObjPtr<mirror::DexCache> dex_cache,
uint32_t stored_index = pair.index;
ObjPtr<mirror::String> string = pair.object.Read();
if (string == nullptr || i < stored_index) {
- string = class_linker->LookupString(dex_file, string_idx, dex_cache);
+ string = class_linker->LookupString(string_idx, dex_cache);
DCHECK(string == nullptr || dex_cache->GetResolvedString(string_idx) == string);
}
}
@@ -1402,12 +1401,12 @@ mirror::Object* ImageWriter::TryAssignBinSlot(WorkStack& work_stack,
auto it = native_object_relocations_.find(cur_fields);
CHECK(it == native_object_relocations_.end()) << "Field array " << cur_fields
<< " already forwarded";
- size_t& offset = image_info.bin_slot_sizes_[kBinArtField];
+ size_t offset = image_info.GetBinSlotSize(Bin::kArtField);
DCHECK(!IsInBootImage(cur_fields));
native_object_relocations_.emplace(
cur_fields,
NativeObjectRelocation {
- oat_index, offset, kNativeObjectRelocationTypeArtFieldArray
+ oat_index, offset, NativeObjectRelocationType::kArtFieldArray
});
offset += header_size;
// Forward individual fields so that we can quickly find where they belong.
@@ -1420,9 +1419,14 @@ mirror::Object* ImageWriter::TryAssignBinSlot(WorkStack& work_stack,
DCHECK(!IsInBootImage(field));
native_object_relocations_.emplace(
field,
- NativeObjectRelocation { oat_index, offset, kNativeObjectRelocationTypeArtField });
+ NativeObjectRelocation { oat_index,
+ offset,
+ NativeObjectRelocationType::kArtField });
offset += sizeof(ArtField);
}
+ image_info.IncrementBinSlotSize(
+ Bin::kArtField, header_size + cur_fields->size() * sizeof(ArtField));
+ DCHECK_EQ(offset, image_info.GetBinSlotSize(Bin::kArtField));
}
}
// Visit and assign offsets for methods.
@@ -1436,8 +1440,8 @@ mirror::Object* ImageWriter::TryAssignBinSlot(WorkStack& work_stack,
}
}
NativeObjectRelocationType type = any_dirty
- ? kNativeObjectRelocationTypeArtMethodDirty
- : kNativeObjectRelocationTypeArtMethodClean;
+ ? NativeObjectRelocationType::kArtMethodDirty
+ : NativeObjectRelocationType::kArtMethodClean;
Bin bin_type = BinTypeForNativeRelocationType(type);
// Forward the entire array at once, but header first.
const size_t method_alignment = ArtMethod::Alignment(target_ptr_size_);
@@ -1449,15 +1453,15 @@ mirror::Object* ImageWriter::TryAssignBinSlot(WorkStack& work_stack,
auto it = native_object_relocations_.find(array);
CHECK(it == native_object_relocations_.end())
<< "Method array " << array << " already forwarded";
- size_t& offset = image_info.bin_slot_sizes_[bin_type];
+ size_t offset = image_info.GetBinSlotSize(bin_type);
DCHECK(!IsInBootImage(array));
native_object_relocations_.emplace(array,
NativeObjectRelocation {
oat_index,
offset,
- any_dirty ? kNativeObjectRelocationTypeArtMethodArrayDirty
- : kNativeObjectRelocationTypeArtMethodArrayClean });
- offset += header_size;
+ any_dirty ? NativeObjectRelocationType::kArtMethodArrayDirty
+ : NativeObjectRelocationType::kArtMethodArrayClean });
+ image_info.IncrementBinSlotSize(bin_type, header_size);
for (auto& m : as_klass->GetMethods(target_ptr_size_)) {
AssignMethodOffset(&m, type, oat_index);
}
@@ -1476,7 +1480,7 @@ mirror::Object* ImageWriter::TryAssignBinSlot(WorkStack& work_stack,
if (imt_method->IsRuntimeMethod() &&
!IsInBootImage(imt_method) &&
!NativeRelocationAssigned(imt_method)) {
- AssignMethodOffset(imt_method, kNativeObjectRelocationTypeRuntimeMethod, oat_index);
+ AssignMethodOffset(imt_method, NativeObjectRelocationType::kRuntimeMethod, oat_index);
}
}
}
@@ -1526,9 +1530,9 @@ bool ImageWriter::TryAssignImTableOffset(ImTable* imt, size_t oat_index) {
imt,
NativeObjectRelocation {
oat_index,
- image_info.bin_slot_sizes_[kBinImTable],
- kNativeObjectRelocationTypeIMTable});
- image_info.bin_slot_sizes_[kBinImTable] += size;
+ image_info.GetBinSlotSize(Bin::kImTable),
+ NativeObjectRelocationType::kIMTable});
+ image_info.IncrementBinSlotSize(Bin::kImTable, size);
return true;
}
@@ -1545,9 +1549,9 @@ void ImageWriter::TryAssignConflictTableOffset(ImtConflictTable* table, size_t o
table,
NativeObjectRelocation {
oat_index,
- image_info.bin_slot_sizes_[kBinIMTConflictTable],
- kNativeObjectRelocationTypeIMTConflictTable});
- image_info.bin_slot_sizes_[kBinIMTConflictTable] += size;
+ image_info.GetBinSlotSize(Bin::kIMTConflictTable),
+ NativeObjectRelocationType::kIMTConflictTable});
+ image_info.IncrementBinSlotSize(Bin::kIMTConflictTable, size);
}
void ImageWriter::AssignMethodOffset(ArtMethod* method,
@@ -1560,9 +1564,10 @@ void ImageWriter::AssignMethodOffset(ArtMethod* method,
TryAssignConflictTableOffset(method->GetImtConflictTable(target_ptr_size_), oat_index);
}
ImageInfo& image_info = GetImageInfo(oat_index);
- size_t& offset = image_info.bin_slot_sizes_[BinTypeForNativeRelocationType(type)];
+ Bin bin_type = BinTypeForNativeRelocationType(type);
+ size_t offset = image_info.GetBinSlotSize(bin_type);
native_object_relocations_.emplace(method, NativeObjectRelocation { oat_index, offset, type });
- offset += ArtMethod::Size(target_ptr_size_);
+ image_info.IncrementBinSlotSize(bin_type, ArtMethod::Size(target_ptr_size_));
}
void ImageWriter::UnbinObjectsIntoOffset(mirror::Object* obj) {
@@ -1697,7 +1702,7 @@ void ImageWriter::CalculateNewObjectOffsets() {
CHECK(m->IsRuntimeMethod());
DCHECK_EQ(compile_app_image_, IsInBootImage(m)) << "Trampolines should be in boot image";
if (!IsInBootImage(m)) {
- AssignMethodOffset(m, kNativeObjectRelocationTypeRuntimeMethod, GetDefaultOatIndex());
+ AssignMethodOffset(m, NativeObjectRelocationType::kRuntimeMethod, GetDefaultOatIndex());
}
}
@@ -1803,18 +1808,18 @@ void ImageWriter::CalculateNewObjectOffsets() {
// Calculate bin slot offsets.
for (ImageInfo& image_info : image_infos_) {
size_t bin_offset = image_objects_offset_begin_;
- for (size_t i = 0; i != kBinSize; ++i) {
- switch (i) {
- case kBinArtMethodClean:
- case kBinArtMethodDirty: {
+ for (size_t i = 0; i != kNumberOfBins; ++i) {
+ switch (static_cast<Bin>(i)) {
+ case Bin::kArtMethodClean:
+ case Bin::kArtMethodDirty: {
bin_offset = RoundUp(bin_offset, method_alignment);
break;
}
- case kBinDexCacheArray:
+ case Bin::kDexCacheArray:
bin_offset = RoundUp(bin_offset, DexCacheArraysLayout::Alignment(target_ptr_size_));
break;
- case kBinImTable:
- case kBinIMTConflictTable: {
+ case Bin::kImTable:
+ case Bin::kIMTConflictTable: {
bin_offset = RoundUp(bin_offset, static_cast<size_t>(target_ptr_size_));
break;
}
@@ -1827,7 +1832,7 @@ void ImageWriter::CalculateNewObjectOffsets() {
}
// NOTE: There may be additional padding between the bin slots and the intern table.
DCHECK_EQ(image_info.image_end_,
- GetBinSizeSum(image_info, kBinMirrorCount) + image_objects_offset_begin_);
+ image_info.GetBinSizeSum(Bin::kMirrorCount) + image_objects_offset_begin_);
}
// Calculate image offsets.
@@ -1864,7 +1869,7 @@ void ImageWriter::CalculateNewObjectOffsets() {
NativeObjectRelocation& relocation = pair.second;
Bin bin_type = BinTypeForNativeRelocationType(relocation.type);
ImageInfo& image_info = GetImageInfo(relocation.oat_index);
- relocation.offset += image_info.bin_slot_offsets_[bin_type];
+ relocation.offset += image_info.GetBinSlotOffset(bin_type);
}
}
@@ -1881,33 +1886,32 @@ size_t ImageWriter::ImageInfo::CreateImageSections(ImageSection* out_sections,
// Add field section.
ImageSection* field_section = &out_sections[ImageHeader::kSectionArtFields];
- *field_section = ImageSection(bin_slot_offsets_[kBinArtField], bin_slot_sizes_[kBinArtField]);
- CHECK_EQ(bin_slot_offsets_[kBinArtField], field_section->Offset());
+ *field_section = ImageSection(GetBinSlotOffset(Bin::kArtField), GetBinSlotSize(Bin::kArtField));
// Add method section.
ImageSection* methods_section = &out_sections[ImageHeader::kSectionArtMethods];
*methods_section = ImageSection(
- bin_slot_offsets_[kBinArtMethodClean],
- bin_slot_sizes_[kBinArtMethodClean] + bin_slot_sizes_[kBinArtMethodDirty]);
+ GetBinSlotOffset(Bin::kArtMethodClean),
+ GetBinSlotSize(Bin::kArtMethodClean) + GetBinSlotSize(Bin::kArtMethodDirty));
// IMT section.
ImageSection* imt_section = &out_sections[ImageHeader::kSectionImTables];
- *imt_section = ImageSection(bin_slot_offsets_[kBinImTable], bin_slot_sizes_[kBinImTable]);
+ *imt_section = ImageSection(GetBinSlotOffset(Bin::kImTable), GetBinSlotSize(Bin::kImTable));
// Conflict tables section.
ImageSection* imt_conflict_tables_section = &out_sections[ImageHeader::kSectionIMTConflictTables];
- *imt_conflict_tables_section = ImageSection(bin_slot_offsets_[kBinIMTConflictTable],
- bin_slot_sizes_[kBinIMTConflictTable]);
+ *imt_conflict_tables_section = ImageSection(GetBinSlotOffset(Bin::kIMTConflictTable),
+ GetBinSlotSize(Bin::kIMTConflictTable));
// Runtime methods section.
ImageSection* runtime_methods_section = &out_sections[ImageHeader::kSectionRuntimeMethods];
- *runtime_methods_section = ImageSection(bin_slot_offsets_[kBinRuntimeMethod],
- bin_slot_sizes_[kBinRuntimeMethod]);
+ *runtime_methods_section = ImageSection(GetBinSlotOffset(Bin::kRuntimeMethod),
+ GetBinSlotSize(Bin::kRuntimeMethod));
// Add dex cache arrays section.
ImageSection* dex_cache_arrays_section = &out_sections[ImageHeader::kSectionDexCacheArrays];
- *dex_cache_arrays_section = ImageSection(bin_slot_offsets_[kBinDexCacheArray],
- bin_slot_sizes_[kBinDexCacheArray]);
+ *dex_cache_arrays_section = ImageSection(GetBinSlotOffset(Bin::kDexCacheArray),
+ GetBinSlotSize(Bin::kDexCacheArray));
// For boot image, round up to the page boundary to separate the interned strings and
// class table from the modifiable data. We shall mprotect() these pages read-only when
// we load the boot image. This is more than sufficient for the string table alignment,
@@ -2060,16 +2064,16 @@ void ImageWriter::CopyAndFixupNativeData(size_t oat_index) {
DCHECK_GE(dest, image_info.image_->Begin() + image_info.image_end_);
DCHECK(!IsInBootImage(pair.first));
switch (relocation.type) {
- case kNativeObjectRelocationTypeArtField: {
+ case NativeObjectRelocationType::kArtField: {
memcpy(dest, pair.first, sizeof(ArtField));
CopyReference(
reinterpret_cast<ArtField*>(dest)->GetDeclaringClassAddressWithoutBarrier(),
reinterpret_cast<ArtField*>(pair.first)->GetDeclaringClass().Ptr());
break;
}
- case kNativeObjectRelocationTypeRuntimeMethod:
- case kNativeObjectRelocationTypeArtMethodClean:
- case kNativeObjectRelocationTypeArtMethodDirty: {
+ case NativeObjectRelocationType::kRuntimeMethod:
+ case NativeObjectRelocationType::kArtMethodClean:
+ case NativeObjectRelocationType::kArtMethodDirty: {
CopyAndFixupMethod(reinterpret_cast<ArtMethod*>(pair.first),
reinterpret_cast<ArtMethod*>(dest),
image_info);
@@ -2077,12 +2081,12 @@ void ImageWriter::CopyAndFixupNativeData(size_t oat_index) {
}
// For arrays, copy just the header since the elements will get copied by their corresponding
// relocations.
- case kNativeObjectRelocationTypeArtFieldArray: {
+ case NativeObjectRelocationType::kArtFieldArray: {
memcpy(dest, pair.first, LengthPrefixedArray<ArtField>::ComputeSize(0));
break;
}
- case kNativeObjectRelocationTypeArtMethodArrayClean:
- case kNativeObjectRelocationTypeArtMethodArrayDirty: {
+ case NativeObjectRelocationType::kArtMethodArrayClean:
+ case NativeObjectRelocationType::kArtMethodArrayDirty: {
size_t size = ArtMethod::Size(target_ptr_size_);
size_t alignment = ArtMethod::Alignment(target_ptr_size_);
memcpy(dest, pair.first, LengthPrefixedArray<ArtMethod>::ComputeSize(0, size, alignment));
@@ -2090,16 +2094,16 @@ void ImageWriter::CopyAndFixupNativeData(size_t oat_index) {
reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(dest)->ClearPadding(size, alignment);
break;
}
- case kNativeObjectRelocationTypeDexCacheArray:
+ case NativeObjectRelocationType::kDexCacheArray:
// Nothing to copy here, everything is done in FixupDexCache().
break;
- case kNativeObjectRelocationTypeIMTable: {
+ case NativeObjectRelocationType::kIMTable: {
ImTable* orig_imt = reinterpret_cast<ImTable*>(pair.first);
ImTable* dest_imt = reinterpret_cast<ImTable*>(dest);
CopyAndFixupImTable(orig_imt, dest_imt);
break;
}
- case kNativeObjectRelocationTypeIMTConflictTable: {
+ case NativeObjectRelocationType::kIMTConflictTable: {
auto* orig_table = reinterpret_cast<ImtConflictTable*>(pair.first);
CopyAndFixupImtConflictTable(
orig_table,
@@ -2197,7 +2201,7 @@ void ImageWriter::FixupPointerArray(mirror::Object* dst,
<< method << " idx=" << i << "/" << num_elements << " with declaring class "
<< Class::PrettyClass(method->GetDeclaringClass());
} else {
- CHECK_EQ(array_type, kBinArtField);
+ CHECK_EQ(array_type, Bin::kArtField);
auto* field = reinterpret_cast<ArtField*>(elem);
LOG(FATAL) << "No relocation entry for ArtField " << field->PrettyField() << " @ "
<< field << " idx=" << i << "/" << num_elements << " with declaring class "
@@ -2518,8 +2522,8 @@ void ImageWriter::FixupDexCache(mirror::DexCache* orig_dex_cache,
copy_dex_cache->SetDexFile(nullptr);
}
-const uint8_t* ImageWriter::GetOatAddress(OatAddress type) const {
- DCHECK_LT(type, kOatAddressCount);
+const uint8_t* ImageWriter::GetOatAddress(StubType type) const {
+ DCHECK_LE(type, StubType::kLast);
// If we are compiling an app image, we need to use the stubs of the boot image.
if (compile_app_image_) {
// Use the current image pointers.
@@ -2531,26 +2535,26 @@ const uint8_t* ImageWriter::GetOatAddress(OatAddress type) const {
const OatHeader& header = oat_file->GetOatHeader();
switch (type) {
// TODO: We could maybe clean this up if we stored them in an array in the oat header.
- case kOatAddressQuickGenericJNITrampoline:
+ case StubType::kQuickGenericJNITrampoline:
return static_cast<const uint8_t*>(header.GetQuickGenericJniTrampoline());
- case kOatAddressInterpreterToInterpreterBridge:
+ case StubType::kInterpreterToInterpreterBridge:
return static_cast<const uint8_t*>(header.GetInterpreterToInterpreterBridge());
- case kOatAddressInterpreterToCompiledCodeBridge:
+ case StubType::kInterpreterToCompiledCodeBridge:
return static_cast<const uint8_t*>(header.GetInterpreterToCompiledCodeBridge());
- case kOatAddressJNIDlsymLookup:
+ case StubType::kJNIDlsymLookup:
return static_cast<const uint8_t*>(header.GetJniDlsymLookup());
- case kOatAddressQuickIMTConflictTrampoline:
+ case StubType::kQuickIMTConflictTrampoline:
return static_cast<const uint8_t*>(header.GetQuickImtConflictTrampoline());
- case kOatAddressQuickResolutionTrampoline:
+ case StubType::kQuickResolutionTrampoline:
return static_cast<const uint8_t*>(header.GetQuickResolutionTrampoline());
- case kOatAddressQuickToInterpreterBridge:
+ case StubType::kQuickToInterpreterBridge:
return static_cast<const uint8_t*>(header.GetQuickToInterpreterBridge());
default:
UNREACHABLE();
}
}
const ImageInfo& primary_image_info = GetImageInfo(0);
- return GetOatAddressForOffset(primary_image_info.oat_address_offsets_[type], primary_image_info);
+ return GetOatAddressForOffset(primary_image_info.GetStubOffset(type), primary_image_info);
}
const uint8_t* ImageWriter::GetQuickCode(ArtMethod* method,
@@ -2586,16 +2590,16 @@ const uint8_t* ImageWriter::GetQuickCode(ArtMethod* method,
} else if (quick_code == nullptr && method->IsNative() &&
(!method->IsStatic() || method->GetDeclaringClass()->IsInitialized())) {
// Non-static or initialized native method missing compiled code, use generic JNI version.
- quick_code = GetOatAddress(kOatAddressQuickGenericJNITrampoline);
+ quick_code = GetOatAddress(StubType::kQuickGenericJNITrampoline);
} else if (quick_code == nullptr && !method->IsNative()) {
// We don't have code at all for a non-native method, use the interpreter.
- quick_code = GetOatAddress(kOatAddressQuickToInterpreterBridge);
+ quick_code = GetOatAddress(StubType::kQuickToInterpreterBridge);
*quick_is_interpreted = true;
} else {
CHECK(!method->GetDeclaringClass()->IsInitialized());
// We have code for a static method, but need to go through the resolution stub for class
// initialization.
- quick_code = GetOatAddress(kOatAddressQuickResolutionTrampoline);
+ quick_code = GetOatAddress(StubType::kQuickResolutionTrampoline);
}
if (!IsInBootOatFile(quick_code)) {
// DCHECK_GE(quick_code, oat_data_begin_);
@@ -2630,11 +2634,11 @@ void ImageWriter::CopyAndFixupMethod(ArtMethod* orig,
if (orig_table != nullptr) {
// Special IMT conflict method, normal IMT conflict method or unimplemented IMT method.
copy->SetEntryPointFromQuickCompiledCodePtrSize(
- GetOatAddress(kOatAddressQuickIMTConflictTrampoline), target_ptr_size_);
+ GetOatAddress(StubType::kQuickIMTConflictTrampoline), target_ptr_size_);
copy->SetImtConflictTable(NativeLocationInImage(orig_table), target_ptr_size_);
} else if (UNLIKELY(orig == runtime->GetResolutionMethod())) {
copy->SetEntryPointFromQuickCompiledCodePtrSize(
- GetOatAddress(kOatAddressQuickResolutionTrampoline), target_ptr_size_);
+ GetOatAddress(StubType::kQuickResolutionTrampoline), target_ptr_size_);
} else {
bool found_one = false;
for (size_t i = 0; i < static_cast<size_t>(CalleeSaveType::kLastCalleeSaveType); ++i) {
@@ -2653,7 +2657,7 @@ void ImageWriter::CopyAndFixupMethod(ArtMethod* orig,
// use results in an AbstractMethodError. We use the interpreter to achieve this.
if (UNLIKELY(!orig->IsInvokable())) {
copy->SetEntryPointFromQuickCompiledCodePtrSize(
- GetOatAddress(kOatAddressQuickToInterpreterBridge), target_ptr_size_);
+ GetOatAddress(StubType::kQuickToInterpreterBridge), target_ptr_size_);
} else {
bool quick_is_interpreted;
const uint8_t* quick_code = GetQuickCode(orig, image_info, &quick_is_interpreted);
@@ -2664,17 +2668,17 @@ void ImageWriter::CopyAndFixupMethod(ArtMethod* orig,
// The native method's pointer is set to a stub to lookup via dlsym.
// Note this is not the code_ pointer, that is handled above.
copy->SetEntryPointFromJniPtrSize(
- GetOatAddress(kOatAddressJNIDlsymLookup), target_ptr_size_);
+ GetOatAddress(StubType::kJNIDlsymLookup), target_ptr_size_);
}
}
}
}
-size_t ImageWriter::GetBinSizeSum(ImageWriter::ImageInfo& image_info, ImageWriter::Bin up_to) const {
- DCHECK_LE(up_to, kBinSize);
- return std::accumulate(&image_info.bin_slot_sizes_[0],
- &image_info.bin_slot_sizes_[up_to],
- /*init*/0);
+size_t ImageWriter::ImageInfo::GetBinSizeSum(Bin up_to) const {
+ DCHECK_LE(static_cast<size_t>(up_to), kNumberOfBins);
+ return std::accumulate(&bin_slot_sizes_[0],
+ &bin_slot_sizes_[0] + static_cast<size_t>(up_to),
+ /*init*/ static_cast<size_t>(0));
}
ImageWriter::BinSlot::BinSlot(uint32_t lockword) : lockword_(lockword) {
@@ -2683,7 +2687,7 @@ ImageWriter::BinSlot::BinSlot(uint32_t lockword) : lockword_(lockword) {
static_assert(kBinShift == 27, "wrong number of shift");
static_assert(sizeof(BinSlot) == sizeof(LockWord), "BinSlot/LockWord must have equal sizes");
- DCHECK_LT(GetBin(), kBinSize);
+ DCHECK_LT(GetBin(), Bin::kMirrorCount);
DCHECK_ALIGNED(GetIndex(), kObjectAlignment);
}
@@ -2702,23 +2706,23 @@ uint32_t ImageWriter::BinSlot::GetIndex() const {
ImageWriter::Bin ImageWriter::BinTypeForNativeRelocationType(NativeObjectRelocationType type) {
switch (type) {
- case kNativeObjectRelocationTypeArtField:
- case kNativeObjectRelocationTypeArtFieldArray:
- return kBinArtField;
- case kNativeObjectRelocationTypeArtMethodClean:
- case kNativeObjectRelocationTypeArtMethodArrayClean:
- return kBinArtMethodClean;
- case kNativeObjectRelocationTypeArtMethodDirty:
- case kNativeObjectRelocationTypeArtMethodArrayDirty:
- return kBinArtMethodDirty;
- case kNativeObjectRelocationTypeDexCacheArray:
- return kBinDexCacheArray;
- case kNativeObjectRelocationTypeRuntimeMethod:
- return kBinRuntimeMethod;
- case kNativeObjectRelocationTypeIMTable:
- return kBinImTable;
- case kNativeObjectRelocationTypeIMTConflictTable:
- return kBinIMTConflictTable;
+ case NativeObjectRelocationType::kArtField:
+ case NativeObjectRelocationType::kArtFieldArray:
+ return Bin::kArtField;
+ case NativeObjectRelocationType::kArtMethodClean:
+ case NativeObjectRelocationType::kArtMethodArrayClean:
+ return Bin::kArtMethodClean;
+ case NativeObjectRelocationType::kArtMethodDirty:
+ case NativeObjectRelocationType::kArtMethodArrayDirty:
+ return Bin::kArtMethodDirty;
+ case NativeObjectRelocationType::kDexCacheArray:
+ return Bin::kDexCacheArray;
+ case NativeObjectRelocationType::kRuntimeMethod:
+ return Bin::kRuntimeMethod;
+ case NativeObjectRelocationType::kIMTable:
+ return Bin::kImTable;
+ case NativeObjectRelocationType::kIMTConflictTable:
+ return Bin::kIMTConflictTable;
}
UNREACHABLE();
}
@@ -2782,20 +2786,20 @@ void ImageWriter::UpdateOatFileHeader(size_t oat_index, const OatHeader& oat_hea
if (oat_index == GetDefaultOatIndex()) {
// Primary oat file, read the trampolines.
- cur_image_info.oat_address_offsets_[kOatAddressInterpreterToInterpreterBridge] =
- oat_header.GetInterpreterToInterpreterBridgeOffset();
- cur_image_info.oat_address_offsets_[kOatAddressInterpreterToCompiledCodeBridge] =
- oat_header.GetInterpreterToCompiledCodeBridgeOffset();
- cur_image_info.oat_address_offsets_[kOatAddressJNIDlsymLookup] =
- oat_header.GetJniDlsymLookupOffset();
- cur_image_info.oat_address_offsets_[kOatAddressQuickGenericJNITrampoline] =
- oat_header.GetQuickGenericJniTrampolineOffset();
- cur_image_info.oat_address_offsets_[kOatAddressQuickIMTConflictTrampoline] =
- oat_header.GetQuickImtConflictTrampolineOffset();
- cur_image_info.oat_address_offsets_[kOatAddressQuickResolutionTrampoline] =
- oat_header.GetQuickResolutionTrampolineOffset();
- cur_image_info.oat_address_offsets_[kOatAddressQuickToInterpreterBridge] =
- oat_header.GetQuickToInterpreterBridgeOffset();
+ cur_image_info.SetStubOffset(StubType::kInterpreterToInterpreterBridge,
+ oat_header.GetInterpreterToInterpreterBridgeOffset());
+ cur_image_info.SetStubOffset(StubType::kInterpreterToCompiledCodeBridge,
+ oat_header.GetInterpreterToCompiledCodeBridgeOffset());
+ cur_image_info.SetStubOffset(StubType::kJNIDlsymLookup,
+ oat_header.GetJniDlsymLookupOffset());
+ cur_image_info.SetStubOffset(StubType::kQuickGenericJNITrampoline,
+ oat_header.GetQuickGenericJniTrampolineOffset());
+ cur_image_info.SetStubOffset(StubType::kQuickIMTConflictTrampoline,
+ oat_header.GetQuickImtConflictTrampolineOffset());
+ cur_image_info.SetStubOffset(StubType::kQuickResolutionTrampoline,
+ oat_header.GetQuickResolutionTrampolineOffset());
+ cur_image_info.SetStubOffset(StubType::kQuickToInterpreterBridge,
+ oat_header.GetQuickToInterpreterBridgeOffset());
}
}
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 68c7b594fb..a7c14395dd 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -62,6 +62,7 @@ class ClassLoader;
} // namespace mirror
class ClassLoaderVisitor;
+class ImTable;
class ImtConflictTable;
static constexpr int kInvalidFd = -1;
@@ -161,70 +162,70 @@ class ImageWriter FINAL {
// Classify different kinds of bins that objects end up getting packed into during image writing.
// Ordered from dirtiest to cleanest (until ArtMethods).
- enum Bin {
- kBinKnownDirty, // Known dirty objects from --dirty-image-objects list
- kBinMiscDirty, // Dex caches, object locks, etc...
- kBinClassVerified, // Class verified, but initializers haven't been run
+ enum class Bin {
+ kKnownDirty, // Known dirty objects from --dirty-image-objects list
+ kMiscDirty, // Dex caches, object locks, etc...
+ kClassVerified, // Class verified, but initializers haven't been run
// Unknown mix of clean/dirty:
- kBinRegular,
- kBinClassInitialized, // Class initializers have been run
+ kRegular,
+ kClassInitialized, // Class initializers have been run
// All classes get their own bins since their fields often dirty
- kBinClassInitializedFinalStatics, // Class initializers have been run, no non-final statics
+ kClassInitializedFinalStatics, // Class initializers have been run, no non-final statics
// Likely-clean:
- kBinString, // [String] Almost always immutable (except for obj header).
+ kString, // [String] Almost always immutable (except for obj header).
// Add more bins here if we add more segregation code.
// Non mirror fields must be below.
// ArtFields should be always clean.
- kBinArtField,
+ kArtField,
// If the class is initialized, then the ArtMethods are probably clean.
- kBinArtMethodClean,
+ kArtMethodClean,
// ArtMethods may be dirty if the class has native methods or a declaring class that isn't
// initialized.
- kBinArtMethodDirty,
+ kArtMethodDirty,
// IMT (clean)
- kBinImTable,
+ kImTable,
// Conflict tables (clean).
- kBinIMTConflictTable,
+ kIMTConflictTable,
// Runtime methods (always clean, do not have a length prefix array).
- kBinRuntimeMethod,
+ kRuntimeMethod,
// Dex cache arrays have a special slot for PC-relative addressing. Since they are
// huge, and as such their dirtiness is not important for the clean/dirty separation,
// we arbitrarily keep them at the end of the native data.
- kBinDexCacheArray, // Arrays belonging to dex cache.
- kBinSize,
+ kDexCacheArray, // Arrays belonging to dex cache.
+ kLast = kDexCacheArray,
// Number of bins which are for mirror objects.
- kBinMirrorCount = kBinArtField,
+ kMirrorCount = kArtField,
};
friend std::ostream& operator<<(std::ostream& stream, const Bin& bin);
- enum NativeObjectRelocationType {
- kNativeObjectRelocationTypeArtField,
- kNativeObjectRelocationTypeArtFieldArray,
- kNativeObjectRelocationTypeArtMethodClean,
- kNativeObjectRelocationTypeArtMethodArrayClean,
- kNativeObjectRelocationTypeArtMethodDirty,
- kNativeObjectRelocationTypeArtMethodArrayDirty,
- kNativeObjectRelocationTypeRuntimeMethod,
- kNativeObjectRelocationTypeIMTable,
- kNativeObjectRelocationTypeIMTConflictTable,
- kNativeObjectRelocationTypeDexCacheArray,
+ enum class NativeObjectRelocationType {
+ kArtField,
+ kArtFieldArray,
+ kArtMethodClean,
+ kArtMethodArrayClean,
+ kArtMethodDirty,
+ kArtMethodArrayDirty,
+ kRuntimeMethod,
+ kIMTable,
+ kIMTConflictTable,
+ kDexCacheArray,
};
friend std::ostream& operator<<(std::ostream& stream, const NativeObjectRelocationType& type);
- enum OatAddress {
- kOatAddressInterpreterToInterpreterBridge,
- kOatAddressInterpreterToCompiledCodeBridge,
- kOatAddressJNIDlsymLookup,
- kOatAddressQuickGenericJNITrampoline,
- kOatAddressQuickIMTConflictTrampoline,
- kOatAddressQuickResolutionTrampoline,
- kOatAddressQuickToInterpreterBridge,
- // Number of elements in the enum.
- kOatAddressCount,
+ enum class StubType {
+ kInterpreterToInterpreterBridge,
+ kInterpreterToCompiledCodeBridge,
+ kJNIDlsymLookup,
+ kQuickGenericJNITrampoline,
+ kQuickIMTConflictTrampoline,
+ kQuickResolutionTrampoline,
+ kQuickToInterpreterBridge,
+ kLast = kQuickToInterpreterBridge,
};
- friend std::ostream& operator<<(std::ostream& stream, const OatAddress& oat_address);
+ friend std::ostream& operator<<(std::ostream& stream, const StubType& stub_type);
- static constexpr size_t kBinBits = MinimumBitsToStore<uint32_t>(kBinMirrorCount - 1);
+ static constexpr size_t kBinBits =
+ MinimumBitsToStore<uint32_t>(static_cast<size_t>(Bin::kMirrorCount) - 1);
// uint32 = typeof(lockword_)
// Subtract read barrier bits since we want these to remain 0, or else it may result in DCHECK
// failures due to invalid read barrier bits during object field reads.
@@ -232,6 +233,12 @@ class ImageWriter FINAL {
// 111000.....0
static const size_t kBinMask = ((static_cast<size_t>(1) << kBinBits) - 1) << kBinShift;
+ // Number of bins, including non-mirror bins.
+ static constexpr size_t kNumberOfBins = static_cast<size_t>(Bin::kLast) + 1u;
+
+ // Number of stub types.
+ static constexpr size_t kNumberOfStubTypes = static_cast<size_t>(StubType::kLast) + 1u;
+
// We use the lock word to store the bin # and bin index of the object in the image.
//
// The struct size must be exactly sizeof(LockWord), currently 32-bits, since this will end up
@@ -262,6 +269,39 @@ class ImageWriter FINAL {
// excluding the bitmap.
size_t CreateImageSections(ImageSection* out_sections, bool app_image) const;
+ size_t GetStubOffset(StubType stub_type) const {
+ DCHECK_LT(static_cast<size_t>(stub_type), kNumberOfStubTypes);
+ return stub_offsets_[static_cast<size_t>(stub_type)];
+ }
+
+ void SetStubOffset(StubType stub_type, size_t offset) {
+ DCHECK_LT(static_cast<size_t>(stub_type), kNumberOfStubTypes);
+ stub_offsets_[static_cast<size_t>(stub_type)] = offset;
+ }
+
+ size_t GetBinSlotOffset(Bin bin) const {
+ DCHECK_LT(static_cast<size_t>(bin), kNumberOfBins);
+ return bin_slot_offsets_[static_cast<size_t>(bin)];
+ }
+
+ void IncrementBinSlotSize(Bin bin, size_t size_to_add) {
+ DCHECK_LT(static_cast<size_t>(bin), kNumberOfBins);
+ bin_slot_sizes_[static_cast<size_t>(bin)] += size_to_add;
+ }
+
+ size_t GetBinSlotSize(Bin bin) const {
+ DCHECK_LT(static_cast<size_t>(bin), kNumberOfBins);
+ return bin_slot_sizes_[static_cast<size_t>(bin)];
+ }
+
+ void IncrementBinSlotCount(Bin bin, size_t count_to_add) {
+ DCHECK_LT(static_cast<size_t>(bin), kNumberOfBins);
+ bin_slot_count_[static_cast<size_t>(bin)] += count_to_add;
+ }
+
+ // Calculate the sum total of the bin slot sizes in [0, up_to). Defaults to all bins.
+ size_t GetBinSizeSum(Bin up_to) const;
+
std::unique_ptr<MemMap> image_; // Memory mapped for generating the image.
// Target begin of this image. Notes: It is not valid to write here, this is the address
@@ -300,12 +340,12 @@ class ImageWriter FINAL {
SafeMap<const DexFile*, size_t> dex_cache_array_starts_;
// Offset from oat_data_begin_ to the stubs.
- uint32_t oat_address_offsets_[kOatAddressCount] = {};
+ uint32_t stub_offsets_[kNumberOfStubTypes] = {};
// Bin slot tracking for dirty object packing.
- size_t bin_slot_sizes_[kBinSize] = {}; // Number of bytes in a bin.
- size_t bin_slot_offsets_[kBinSize] = {}; // Number of bytes in previous bins.
- size_t bin_slot_count_[kBinSize] = {}; // Number of objects in a bin.
+ size_t bin_slot_sizes_[kNumberOfBins] = {}; // Number of bytes in a bin.
+ size_t bin_slot_offsets_[kNumberOfBins] = {}; // Number of bytes in previous bins.
+ size_t bin_slot_count_[kNumberOfBins] = {}; // Number of objects in a bin.
// Cached size of the intern table for when we allocate memory.
size_t intern_table_bytes_ = 0;
@@ -367,7 +407,7 @@ class ImageWriter FINAL {
}
// Returns the address in the boot image if we are compiling the app image.
- const uint8_t* GetOatAddress(OatAddress type) const;
+ const uint8_t* GetOatAddress(StubType type) const;
const uint8_t* GetOatAddressForOffset(uint32_t offset, const ImageInfo& image_info) const {
// With Quick, code is within the OatFile, as there are all in one
@@ -443,9 +483,6 @@ class ImageWriter FINAL {
bool* quick_is_interpreted)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Calculate the sum total of the bin slot sizes in [0, up_to). Defaults to all bins.
- size_t GetBinSizeSum(ImageInfo& image_info, Bin up_to = kBinSize) const;
-
// Return true if a method is likely to be dirtied at runtime.
bool WillMethodBeDirty(ArtMethod* m) const REQUIRES_SHARED(Locks::mutator_lock_);
@@ -572,9 +609,9 @@ class ImageWriter FINAL {
NativeObjectRelocationType type;
bool IsArtMethodRelocation() const {
- return type == kNativeObjectRelocationTypeArtMethodClean ||
- type == kNativeObjectRelocationTypeArtMethodDirty ||
- type == kNativeObjectRelocationTypeRuntimeMethod;
+ return type == NativeObjectRelocationType::kArtMethodClean ||
+ type == NativeObjectRelocationType::kArtMethodDirty ||
+ type == NativeObjectRelocationType::kRuntimeMethod;
}
};
std::unordered_map<void*, NativeObjectRelocation> native_object_relocations_;
diff --git a/dex2oat/linker/index_bss_mapping_encoder.h b/dex2oat/linker/index_bss_mapping_encoder.h
index 9bc14329ff..c6326ed1cf 100644
--- a/dex2oat/linker/index_bss_mapping_encoder.h
+++ b/dex2oat/linker/index_bss_mapping_encoder.h
@@ -17,9 +17,10 @@
#ifndef ART_DEX2OAT_LINKER_INDEX_BSS_MAPPING_ENCODER_H_
#define ART_DEX2OAT_LINKER_INDEX_BSS_MAPPING_ENCODER_H_
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
#include "base/bit_vector-inl.h"
-#include "base/logging.h"
#include "index_bss_mapping.h"
namespace art {
diff --git a/dex2oat/linker/multi_oat_relative_patcher.cc b/dex2oat/linker/multi_oat_relative_patcher.cc
index 178a78f0bb..1abaf7dfd1 100644
--- a/dex2oat/linker/multi_oat_relative_patcher.cc
+++ b/dex2oat/linker/multi_oat_relative_patcher.cc
@@ -16,8 +16,9 @@
#include "multi_oat_relative_patcher.h"
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
#include "globals.h"
namespace art {
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 293078acee..cb1b80d590 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -26,16 +26,18 @@
#include "base/bit_vector-inl.h"
#include "base/enums.h"
#include "base/file_magic.h"
+#include "base/logging.h" // For VLOG
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
#include "class_table-inl.h"
#include "compiled_method-inl.h"
#include "debug/method_debug_info.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_loader.h"
+#include "dex/dex_file_types.h"
+#include "dex/standard_dex_file.h"
#include "dex/verification_results.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
-#include "dex_file_types.h"
#include "dexlayout.h"
#include "driver/compiler_driver-inl.h"
#include "driver/compiler_options.h"
@@ -53,7 +55,6 @@
#include "mirror/class_loader.h"
#include "mirror/dex_cache-inl.h"
#include "mirror/object-inl.h"
-#include "standard_dex_file.h"
#include "oat_quick_method_header.h"
#include "os.h"
#include "safe_map.h"
@@ -187,8 +188,8 @@ class OatWriter::OatClassHeader {
OatClassHeader(uint32_t offset,
uint32_t num_non_null_compiled_methods,
uint32_t num_methods,
- mirror::Class::Status status)
- : status_(status),
+ ClassStatus status)
+ : status_(enum_cast<uint16_t>(status)),
offset_(offset) {
// We just arbitrarily say that 0 methods means kOatClassNoneCompiled and that we won't use
// kOatClassAllCompiled unless there is at least one compiled method. This means in an
@@ -209,8 +210,8 @@ class OatWriter::OatClassHeader {
}
// Data to write.
- static_assert(mirror::Class::Status::kStatusMax < (1 << 16), "class status won't fit in 16bits");
- int16_t status_;
+ static_assert(enum_cast<>(ClassStatus::kLast) < (1 << 16), "class status won't fit in 16bits");
+ uint16_t status_;
static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits");
uint16_t type_;
@@ -930,17 +931,17 @@ class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
bool EndClass() OVERRIDE {
ClassReference class_ref(dex_file_, class_def_index_);
- mirror::Class::Status status;
+ ClassStatus status;
bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
if (!found) {
VerificationResults* results = writer_->compiler_driver_->GetVerificationResults();
if (results != nullptr && results->IsClassRejected(class_ref)) {
// The oat class status is used only for verification of resolved classes,
- // so use kStatusErrorResolved whether the class was resolved or unresolved
+ // so use ClassStatus::kErrorResolved whether the class was resolved or unresolved
// during compile-time verification.
- status = mirror::Class::kStatusErrorResolved;
+ status = ClassStatus::kErrorResolved;
} else {
- status = mirror::Class::kStatusNotReady;
+ status = ClassStatus::kNotReady;
}
}
@@ -1591,11 +1592,10 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
ScopedObjectAccessUnchecked soa(self);
StackHandleScope<1> hs(self);
method = class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- *dex_file_,
it.GetMemberIndex(),
hs.NewHandle(dex_cache),
ScopedNullHandle<mirror::ClassLoader>(),
- nullptr,
+ /* referrer */ nullptr,
invoke_type);
if (method == nullptr) {
LOG(FATAL_WITHOUT_ABORT) << "Unexpected failure to resolve a method: "
@@ -1951,20 +1951,21 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor {
: class_linker_->FindDexCache(Thread::Current(), *target_dex_file);
}
- mirror::Class* GetTargetType(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ObjPtr<mirror::Class> GetTargetType(const LinkerPatch& patch)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(writer_->HasImage());
ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile());
ObjPtr<mirror::Class> type =
- ClassLinker::LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_);
+ class_linker_->LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_);
CHECK(type != nullptr);
- return type.Ptr();
+ return type;
}
- mirror::String* GetTargetString(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ObjPtr<mirror::String> GetTargetString(const LinkerPatch& patch)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
ClassLinker* linker = Runtime::Current()->GetClassLinker();
- mirror::String* string = linker->LookupString(*patch.TargetStringDexFile(),
- patch.TargetStringIndex(),
- GetDexCache(patch.TargetStringDexFile()));
+ ObjPtr<mirror::String> string =
+ linker->LookupString(patch.TargetStringIndex(), GetDexCache(patch.TargetStringDexFile()));
DCHECK(string != nullptr);
DCHECK(writer_->HasBootImage() ||
Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string));
@@ -1980,13 +1981,14 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor {
return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method) - oat_data_begin);
}
- uint32_t GetTargetObjectOffset(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
+ uint32_t GetTargetObjectOffset(ObjPtr<mirror::Object> object)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(writer_->HasBootImage());
- object = writer_->image_writer_->GetImageAddress(object);
+ object = writer_->image_writer_->GetImageAddress(object.Ptr());
size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
// TODO: Clean up offset types. The target offset must be treated as signed.
- return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object) - oat_data_begin);
+ return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object.Ptr()) - oat_data_begin);
}
void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
@@ -2694,7 +2696,8 @@ class OatWriter::WriteQuickeningIndicesMethodVisitor {
CompiledMethod* compiled_method =
driver.GetCompiledMethod(MethodReference(dex_file, method_idx));
const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem();
- uint32_t existing_debug_info_offset = OatFile::GetDebugInfoOffset(*dex_file, code_item);
+ CodeItemDebugInfoAccessor accessor(dex_file, code_item);
+ const uint32_t existing_debug_info_offset = accessor.DebugInfoOffset();
// If the existing offset is already out of bounds (and not magic marker 0xFFFFFFFF)
// we will pretend the method has been quickened.
bool existing_offset_out_of_bounds =
@@ -2742,10 +2745,6 @@ bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
size_t initial_offset = vdex_size_;
size_t start_offset = RoundUp(initial_offset, 4u);
- vdex_size_ = start_offset;
- vdex_quickening_info_offset_ = vdex_size_;
- size_quickening_info_alignment_ = start_offset - initial_offset;
-
off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
if (actual_offset != static_cast<off_t>(start_offset)) {
PLOG(ERROR) << "Failed to seek to quickening info section. Actual: " << actual_offset
@@ -2789,7 +2788,16 @@ bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
size_quickening_info_ = 0;
}
- vdex_size_ += size_quickening_info_;
+ if (size_quickening_info_ == 0) {
+ // Nothing was written. Leave `vdex_size_` untouched and unaligned.
+ vdex_quickening_info_offset_ = initial_offset;
+ size_quickening_info_alignment_ = 0;
+ } else {
+ vdex_size_ = start_offset + size_quickening_info_;
+ vdex_quickening_info_offset_ = start_offset;
+ size_quickening_info_alignment_ = start_offset - initial_offset;
+ }
+
return true;
}
@@ -3314,8 +3322,9 @@ bool OatWriter::WriteDexFile(OutputStream* out,
if (!SeekToDexFile(out, file, oat_dex_file)) {
return false;
}
- if (profile_compilation_info_ != nullptr ||
- compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) {
+ // update_input_vdex disables compact dex and layout.
+ if (!update_input_vdex && (profile_compilation_info_ != nullptr ||
+ compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone)) {
CHECK(!update_input_vdex) << "We should never update the input vdex when doing dexlayout";
if (!LayoutAndWriteDexFile(out, oat_dex_file)) {
return false;
@@ -3433,6 +3442,7 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil
Options options;
options.output_to_memmap_ = true;
options.compact_dex_level_ = compact_dex_level_;
+ options.update_checksum_ = true;
DexLayout dex_layout(options, profile_compilation_info_, nullptr);
dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0);
std::unique_ptr<MemMap> mem_map(dex_layout.GetAndReleaseMemMap());
@@ -3864,6 +3874,7 @@ bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
DCHECK_NE(vdex_dex_files_offset_, 0u);
DCHECK_NE(vdex_verifier_deps_offset_, 0u);
+ DCHECK_NE(vdex_quickening_info_offset_, 0u);
size_t dex_section_size = vdex_verifier_deps_offset_ - vdex_dex_files_offset_;
size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index 4055878b55..ba29e3b3a2 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -24,7 +24,7 @@
#include "base/array_ref.h"
#include "base/dchecked_vector.h"
-#include "cdex/compact_dex_level.h"
+#include "dex/compact_dex_level.h"
#include "linker/relative_patcher.h" // For RelativePatcherTargetProvider.
#include "mem_map.h"
#include "method_reference.h"
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index fec05cc393..488806092b 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -26,7 +26,7 @@
#include "compiled_method-inl.h"
#include "compiler.h"
#include "debug/method_debug_info.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file_loader.h"
#include "dex/quick_compiler_callbacks.h"
#include "dex/verification_results.h"
#include "driver/compiler_driver.h"
@@ -45,6 +45,7 @@
#include "oat_writer.h"
#include "scoped_thread_state_change-inl.h"
#include "utils/test_dex_file_builder.h"
+#include "vdex_file.h"
namespace art {
namespace linker {
@@ -225,6 +226,9 @@ class OatTest : public CommonCompilerTest {
if (!oat_writer.WriteVerifierDeps(vdex_out.get(), nullptr)) {
return false;
}
+ if (!oat_writer.WriteQuickeningInfo(vdex_out.get())) {
+ return false;
+ }
if (!oat_writer.WriteChecksumsAndVdexHeader(vdex_out.get())) {
return false;
}
@@ -451,7 +455,7 @@ TEST_F(OatTest, WriteRead) {
ScopedNullHandle<mirror::ClassLoader>());
const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(i);
- CHECK_EQ(mirror::Class::Status::kStatusNotReady, oat_class.GetStatus()) << descriptor;
+ CHECK_EQ(ClassStatus::kNotReady, oat_class.GetStatus()) << descriptor;
CHECK_EQ(kCompile ? OatClassType::kOatClassAllCompiled : OatClassType::kOatClassNoneCompiled,
oat_class.GetType()) << descriptor;
@@ -652,6 +656,13 @@ void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) {
&opened_dex_file2->GetHeader(),
dex_file2_data->GetHeader().file_size_));
ASSERT_EQ(dex_file2_data->GetLocation(), opened_dex_file2->GetLocation());
+
+ const VdexFile::Header &vdex_header = opened_oat_file->GetVdexFile()->GetHeader();
+ ASSERT_EQ(vdex_header.GetQuickeningInfoSize(), 0u);
+
+ int64_t actual_vdex_size = vdex_file.GetFile()->GetLength();
+ ASSERT_GE(actual_vdex_size, 0);
+ ASSERT_EQ((uint64_t) actual_vdex_size, vdex_header.GetComputedFileSize());
}
TEST_F(OatTest, DexFileInputCheckOutput) {
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index a7af193f0a..8a06f44628 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -44,10 +44,12 @@
#include "android-base/stringprintf.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
-#include "dex_file_types.h"
-#include "dex_instruction-inl.h"
+#include "dex/code_item_accessors-no_art-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_exception_helpers.h"
+#include "dex/dex_file_loader.h"
+#include "dex/dex_file_types.h"
+#include "dex/dex_instruction-inl.h"
#include "dexdump_cfg.h"
namespace art {
@@ -734,7 +736,8 @@ static void dumpInterface(const DexFile* pDexFile, const DexFile::TypeItem& pTyp
* Dumps the catches table associated with the code.
*/
static void dumpCatches(const DexFile* pDexFile, const DexFile::CodeItem* pCode) {
- const u4 triesSize = pCode->tries_size_;
+ CodeItemDataAccessor accessor(pDexFile, pCode);
+ const u4 triesSize = accessor.TriesSize();
// No catch table.
if (triesSize == 0) {
@@ -744,12 +747,11 @@ static void dumpCatches(const DexFile* pDexFile, const DexFile::CodeItem* pCode)
// Dump all table entries.
fprintf(gOutFile, " catches : %d\n", triesSize);
- for (u4 i = 0; i < triesSize; i++) {
- const DexFile::TryItem* pTry = pDexFile->GetTryItems(*pCode, i);
- const u4 start = pTry->start_addr_;
- const u4 end = start + pTry->insn_count_;
+ for (const DexFile::TryItem& try_item : accessor.TryItems()) {
+ const u4 start = try_item.start_addr_;
+ const u4 end = start + try_item.insn_count_;
fprintf(gOutFile, " 0x%04x - 0x%04x\n", start, end);
- for (CatchHandlerIterator it(*pCode, *pTry); it.HasNext(); it.Next()) {
+ for (CatchHandlerIterator it(accessor, try_item); it.HasNext(); it.Next()) {
const dex::TypeIndex tidx = it.GetHandlerTypeIndex();
const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
fprintf(gOutFile, " %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
@@ -949,14 +951,14 @@ static void dumpInstruction(const DexFile* pDexFile,
fprintf(gOutFile, "%06x:", codeOffset + 0x10 + insnIdx * 2);
// Dump (part of) raw bytes.
- const u2* insns = pCode->insns_;
+ CodeItemInstructionAccessor accessor(pDexFile, pCode);
for (u4 i = 0; i < 8; i++) {
if (i < insnWidth) {
if (i == 7) {
fprintf(gOutFile, " ... ");
} else {
// Print 16-bit value in little-endian order.
- const u1* bytePtr = (const u1*) &insns[insnIdx + i];
+ const u1* bytePtr = (const u1*) &accessor.Insns()[insnIdx + i];
fprintf(gOutFile, " %02x%02x", bytePtr[0], bytePtr[1]);
}
} else {
@@ -966,7 +968,7 @@ static void dumpInstruction(const DexFile* pDexFile,
// Dump pseudo-instruction or opcode.
if (pDecInsn->Opcode() == Instruction::NOP) {
- const u2 instr = get2LE((const u1*) &insns[insnIdx]);
+ const u2 instr = get2LE((const u1*) &accessor.Insns()[insnIdx]);
if (instr == Instruction::kPackedSwitchSignature) {
fprintf(gOutFile, "|%04x: packed-switch-data (%d units)", insnIdx, insnWidth);
} else if (instr == Instruction::kSparseSwitchSignature) {
@@ -1167,16 +1169,15 @@ static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
codeOffset, codeOffset, dot.get(), name, signature.ToString().c_str());
// Iterate over all instructions.
- const u2* insns = pCode->insns_;
- for (u4 insnIdx = 0; insnIdx < pCode->insns_size_in_code_units_;) {
- const Instruction* instruction = Instruction::At(&insns[insnIdx]);
+ CodeItemDataAccessor accessor(pDexFile, pCode);
+ for (const DexInstructionPcPair& pair : accessor) {
+ const Instruction* instruction = &pair.Inst();
const u4 insnWidth = instruction->SizeInCodeUnits();
if (insnWidth == 0) {
- fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
+ fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", pair.DexPc());
break;
}
- dumpInstruction(pDexFile, pCode, codeOffset, insnIdx, insnWidth, instruction);
- insnIdx += insnWidth;
+ dumpInstruction(pDexFile, pCode, codeOffset, pair.DexPc(), insnWidth, instruction);
} // for
}
@@ -1185,11 +1186,13 @@ static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
*/
static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
const DexFile::CodeItem* pCode, u4 codeOffset) {
- fprintf(gOutFile, " registers : %d\n", pCode->registers_size_);
- fprintf(gOutFile, " ins : %d\n", pCode->ins_size_);
- fprintf(gOutFile, " outs : %d\n", pCode->outs_size_);
+ CodeItemDebugInfoAccessor accessor(pDexFile, pCode, pDexFile->GetDebugInfoOffset(pCode));
+
+ fprintf(gOutFile, " registers : %d\n", accessor.RegistersSize());
+ fprintf(gOutFile, " ins : %d\n", accessor.InsSize());
+ fprintf(gOutFile, " outs : %d\n", accessor.OutsSize());
fprintf(gOutFile, " insns size : %d 16-bit code units\n",
- pCode->insns_size_in_code_units_);
+ accessor.InsnsSizeInCodeUnits());
// Bytecode disassembly, if requested.
if (gOptions.disassemble) {
@@ -1202,11 +1205,9 @@ static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
// Positions and locals table in the debug info.
bool is_static = (flags & kAccStatic) != 0;
fprintf(gOutFile, " positions : \n");
- uint32_t debug_info_offset = pDexFile->GetDebugInfoOffset(pCode);
- pDexFile->DecodeDebugPositionInfo(pCode, debug_info_offset, dumpPositionsCb, nullptr);
+ pDexFile->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), dumpPositionsCb, nullptr);
fprintf(gOutFile, " locals : \n");
- pDexFile->DecodeDebugLocalInfo(
- pCode, debug_info_offset, is_static, idx, dumpLocalsCb, nullptr);
+ accessor.DecodeDebugLocalInfo(is_static, idx, dumpLocalsCb, nullptr);
}
/*
diff --git a/dexdump/dexdump_cfg.cc b/dexdump/dexdump_cfg.cc
index 62c970de8a..f08ea746d3 100644
--- a/dexdump/dexdump_cfg.cc
+++ b/dexdump/dexdump_cfg.cc
@@ -23,9 +23,12 @@
#include <map>
#include <ostream>
#include <set>
+#include <sstream>
-#include "dex_file-inl.h"
-#include "dex_instruction-inl.h"
+#include "dex/code_item_accessors-no_art-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_exception_helpers.h"
+#include "dex/dex_instruction-inl.h"
namespace art {
@@ -36,17 +39,17 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
os << "digraph {\n";
os << " # /* " << dex_file->PrettyMethod(dex_method_idx, true) << " */\n";
+ CodeItemDataAccessor accessor(dex_file, code_item);
+
std::set<uint32_t> dex_pc_is_branch_target;
{
// Go and populate.
- const Instruction* inst = Instruction::At(code_item->insns_);
- for (uint32_t dex_pc = 0;
- dex_pc < code_item->insns_size_in_code_units_;
- dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) {
+ for (const DexInstructionPcPair& pair : accessor) {
+ const Instruction* inst = &pair.Inst();
if (inst->IsBranch()) {
- dex_pc_is_branch_target.insert(dex_pc + inst->GetTargetOffset());
+ dex_pc_is_branch_target.insert(pair.DexPc() + inst->GetTargetOffset());
} else if (inst->IsSwitch()) {
- const uint16_t* insns = code_item->insns_ + dex_pc;
+ const uint16_t* insns = reinterpret_cast<const uint16_t*>(inst);
int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
const uint16_t* switch_insns = insns + switch_offset;
uint32_t switch_count = switch_insns[1];
@@ -62,7 +65,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
int32_t offset =
static_cast<int32_t>(switch_insns[targets_offset + targ * 2]) |
static_cast<int32_t>(switch_insns[targets_offset + targ * 2 + 1] << 16);
- dex_pc_is_branch_target.insert(dex_pc + offset);
+ dex_pc_is_branch_target.insert(pair.DexPc() + offset);
}
}
}
@@ -73,12 +76,10 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
std::map<uint32_t, uint32_t> dex_pc_to_incl_id; // This has entries for all dex pcs.
{
- const Instruction* inst = Instruction::At(code_item->insns_);
bool first_in_block = true;
bool force_new_block = false;
- for (uint32_t dex_pc = 0;
- dex_pc < code_item->insns_size_in_code_units_;
- dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) {
+ for (const DexInstructionPcPair& pair : accessor) {
+ const uint32_t dex_pc = pair.DexPc();
if (dex_pc == 0 ||
(dex_pc_is_branch_target.find(dex_pc) != dex_pc_is_branch_target.end()) ||
force_new_block) {
@@ -107,7 +108,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
// Dump the instruction. Need to escape '"', '<', '>', '{' and '}'.
os << "<" << "p" << dex_pc << ">";
os << " 0x" << std::hex << dex_pc << std::dec << ": ";
- std::string inst_str = inst->DumpString(dex_file);
+ std::string inst_str = pair.Inst().DumpString(dex_file);
size_t cur_start = 0; // It's OK to start at zero, instruction dumps don't start with chars
// we need to escape.
while (cur_start != std::string::npos) {
@@ -136,7 +137,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
// Force a new block for some fall-throughs and some instructions that terminate the "local"
// control flow.
- force_new_block = inst->IsSwitch() || inst->IsBasicBlockEnd();
+ force_new_block = pair.Inst().IsSwitch() || pair.Inst().IsBasicBlockEnd();
}
// Close last node.
if (dex_pc_to_node_id.size() > 0) {
@@ -161,10 +162,9 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
uint32_t last_node_id = std::numeric_limits<uint32_t>::max();
uint32_t old_dex_pc = 0;
uint32_t block_start_dex_pc = std::numeric_limits<uint32_t>::max();
- const Instruction* inst = Instruction::At(code_item->insns_);
- for (uint32_t dex_pc = 0;
- dex_pc < code_item->insns_size_in_code_units_;
- old_dex_pc = dex_pc, dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) {
+ for (const DexInstructionPcPair& pair : accessor) {
+ const Instruction* inst = &pair.Inst();
+ const uint32_t dex_pc = pair.DexPc();
{
auto it = dex_pc_to_node_id.find(dex_pc);
if (it != dex_pc_to_node_id.end()) {
@@ -196,7 +196,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
}
// Look at the exceptions of the first entry.
- CatchHandlerIterator catch_it(*code_item, dex_pc);
+ CatchHandlerIterator catch_it(accessor, dex_pc);
for (; catch_it.HasNext(); catch_it.Next()) {
exception_targets.insert(catch_it.GetHandlerAddress());
}
@@ -221,7 +221,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
}
} else if (inst->IsSwitch()) {
// TODO: Iterate through all switch targets.
- const uint16_t* insns = code_item->insns_ + dex_pc;
+ const uint16_t* insns = reinterpret_cast<const uint16_t*>(inst);
/* make sure the start of the switch is in range */
int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
/* offset to switch table is a relative branch-style offset */
@@ -255,7 +255,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
// Exception edges. If this is not the first instruction in the block
if (block_start_dex_pc != dex_pc) {
std::set<uint32_t> current_handler_pcs;
- CatchHandlerIterator catch_it(*code_item, dex_pc);
+ CatchHandlerIterator catch_it(accessor, dex_pc);
for (; catch_it.HasNext(); catch_it.Next()) {
current_handler_pcs.insert(catch_it.GetHandlerAddress());
}
@@ -271,6 +271,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
// No fall-through.
last_node_id = std::numeric_limits<uint32_t>::max();
}
+ old_dex_pc = pair.DexPc();
}
// Finish up the last block, if it had common exceptions.
if (!exception_targets.empty()) {
@@ -292,10 +293,10 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
// TODO
// Exception edges. If this is not the first instruction in the block
for (uint32_t dex_pc : blocks_with_detailed_exceptions) {
- const Instruction* inst = Instruction::At(&code_item->insns_[dex_pc]);
+ const Instruction* inst = &accessor.InstructionAt(dex_pc);
uint32_t this_node_id = dex_pc_to_incl_id.find(dex_pc)->second;
while (true) {
- CatchHandlerIterator catch_it(*code_item, dex_pc);
+ CatchHandlerIterator catch_it(accessor, dex_pc);
if (catch_it.HasNext()) {
std::set<uint32_t> handled_targets;
for (; catch_it.HasNext(); catch_it.Next()) {
@@ -321,7 +322,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file,
// Loop update. Have a break-out if the next instruction is a branch target and thus in
// another block.
dex_pc += inst->SizeInCodeUnits();
- if (dex_pc >= code_item->insns_size_in_code_units_) {
+ if (dex_pc >= accessor.InsnsSizeInCodeUnits()) {
break;
}
if (dex_pc_to_node_id.find(dex_pc) != dex_pc_to_node_id.end()) {
diff --git a/dexdump/dexdump_main.cc b/dexdump/dexdump_main.cc
index 43c3d12de5..382b551a1a 100644
--- a/dexdump/dexdump_main.cc
+++ b/dexdump/dexdump_main.cc
@@ -28,7 +28,9 @@
#include <string.h>
#include <unistd.h>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include <base/logging.h> // For InitLogging.
#include "mem_map.h"
#include "runtime.h"
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index f2d46199a2..1c5b16d84b 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -16,7 +16,7 @@
#include "compact_dex_writer.h"
-#include "cdex/compact_dex_file.h"
+#include "dex/compact_dex_file.h"
namespace art {
@@ -27,7 +27,9 @@ void CompactDexWriter::WriteHeader() {
header.checksum_ = header_->Checksum();
std::copy_n(header_->Signature(), DexFile::kSha1DigestSize, header.signature_);
header.file_size_ = header_->FileSize();
- header.header_size_ = header_->GetSize();
+ // Since we are not necessarily outputting the same format as the input, avoid using the stored
+ // header size.
+ header.header_size_ = GetHeaderSize();
header.endian_tag_ = header_->EndianTag();
header.link_size_ = header_->LinkSize();
header.link_off_ = header_->LinkOffset();
@@ -47,7 +49,17 @@ void CompactDexWriter::WriteHeader() {
header.class_defs_off_ = collections.ClassDefsOffset();
header.data_size_ = header_->DataSize();
header.data_off_ = header_->DataOffset();
+ header.feature_flags_ = 0u;
+ // In cases where apps are converted to cdex during install, maintain feature flags so that
+ // the verifier correctly verifies apps that aren't targetting default methods.
+ if (header_->SupportDefaultMethods()) {
+ header.feature_flags_ |= static_cast<uint32_t>(CompactDexFile::FeatureFlags::kDefaultMethods);
+ }
UNUSED(Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u));
}
+size_t CompactDexWriter::GetHeaderSize() const {
+ return sizeof(CompactDexFile::Header);
+}
+
} // namespace art
diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h
index e28efab5c1..d13333bb18 100644
--- a/dexlayout/compact_dex_writer.h
+++ b/dexlayout/compact_dex_writer.h
@@ -35,6 +35,8 @@ class CompactDexWriter : public DexWriter {
protected:
void WriteHeader() OVERRIDE;
+ size_t GetHeaderSize() const OVERRIDE;
+
const CompactDexLevel compact_dex_level_;
private:
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 2af579c73c..8ed3a79542 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -21,7 +21,10 @@
*/
#include "dex_ir.h"
-#include "dex_instruction-inl.h"
+
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file_exception_helpers.h"
+#include "dex/dex_instruction-inl.h"
#include "dex_ir_builder.h"
namespace art {
@@ -564,13 +567,14 @@ ParameterAnnotation* Collections::GenerateParameterAnnotation(
CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
const DexFile::CodeItem& disk_code_item, uint32_t offset) {
- uint16_t registers_size = disk_code_item.registers_size_;
- uint16_t ins_size = disk_code_item.ins_size_;
- uint16_t outs_size = disk_code_item.outs_size_;
- uint32_t tries_size = disk_code_item.tries_size_;
+ CodeItemDebugInfoAccessor accessor(&dex_file, &disk_code_item);
+ const uint16_t registers_size = accessor.RegistersSize();
+ const uint16_t ins_size = accessor.InsSize();
+ const uint16_t outs_size = accessor.OutsSize();
+ const uint32_t tries_size = accessor.TriesSize();
// TODO: Calculate the size of the debug info.
- uint32_t debug_info_offset = dex_file.GetDebugInfoOffset(&disk_code_item);
+ const uint32_t debug_info_offset = accessor.DebugInfoOffset();
const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(debug_info_offset);
DebugInfoItem* debug_info = nullptr;
if (debug_info_stream != nullptr) {
@@ -584,20 +588,19 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
}
}
- uint32_t insns_size = disk_code_item.insns_size_in_code_units_;
+ uint32_t insns_size = accessor.InsnsSizeInCodeUnits();
uint16_t* insns = new uint16_t[insns_size];
- memcpy(insns, disk_code_item.insns_, insns_size * sizeof(uint16_t));
+ memcpy(insns, accessor.Insns(), insns_size * sizeof(uint16_t));
TryItemVector* tries = nullptr;
CatchHandlerVector* handler_list = nullptr;
if (tries_size > 0) {
tries = new TryItemVector();
handler_list = new CatchHandlerVector();
- for (uint32_t i = 0; i < tries_size; ++i) {
- const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i);
- uint32_t start_addr = disk_try_item->start_addr_;
- uint16_t insn_count = disk_try_item->insn_count_;
- uint16_t handler_off = disk_try_item->handler_off_;
+ for (const DexFile::TryItem& disk_try_item : accessor.TryItems()) {
+ uint32_t start_addr = disk_try_item.start_addr_;
+ uint16_t insn_count = disk_try_item.insn_count_;
+ uint16_t handler_off = disk_try_item.handler_off_;
const CatchHandler* handlers = nullptr;
for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
if (handler_off == existing_handlers->GetListOffset()) {
@@ -608,7 +611,7 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
if (handlers == nullptr) {
bool catch_all = false;
TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
- for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) {
+ for (CatchHandlerIterator it(accessor, disk_try_item); it.HasNext(); it.Next()) {
const dex::TypeIndex type_index = it.GetHandlerTypeIndex();
const TypeId* type_id = GetTypeIdOrNullPtr(type_index.index_);
catch_all |= type_id == nullptr;
@@ -622,7 +625,7 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
tries->push_back(std::unique_ptr<const TryItem>(try_item));
}
// Manually walk catch handlers list and add any missing handlers unreferenced by try items.
- const uint8_t* handlers_base = DexFile::GetCatchHandlerData(disk_code_item, 0);
+ const uint8_t* handlers_base = accessor.GetCatchHandlerData();
const uint8_t* handlers_data = handlers_base;
uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_data);
while (handlers_size > handler_list->size()) {
@@ -666,7 +669,7 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
}
}
- uint32_t size = DexFile::GetCodeItemSize(disk_code_item);
+ uint32_t size = dex_file.GetCodeItemSize(disk_code_item);
CodeItem* code_item = new CodeItem(
registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list);
code_item->SetSize(size);
@@ -674,20 +677,20 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
// Add "fixup" references to types, strings, methods, and fields.
// This is temporary, as we will probably want more detailed parsing of the
// instructions here.
- std::unique_ptr<std::vector<TypeId*>> type_ids(new std::vector<TypeId*>());
- std::unique_ptr<std::vector<StringId*>> string_ids(new std::vector<StringId*>());
- std::unique_ptr<std::vector<MethodId*>> method_ids(new std::vector<MethodId*>());
- std::unique_ptr<std::vector<FieldId*>> field_ids(new std::vector<FieldId*>());
+ std::vector<TypeId*> type_ids;
+ std::vector<StringId*> string_ids;
+ std::vector<MethodId*> method_ids;
+ std::vector<FieldId*> field_ids;
if (GetIdsFromByteCode(*this,
code_item,
- type_ids.get(),
- string_ids.get(),
- method_ids.get(),
- field_ids.get())) {
- CodeFixups* fixups = new CodeFixups(type_ids.release(),
- string_ids.release(),
- method_ids.release(),
- field_ids.release());
+ /*out*/ &type_ids,
+ /*out*/ &string_ids,
+ /*out*/ &method_ids,
+ /*out*/ &field_ids)) {
+ CodeFixups* fixups = new CodeFixups(std::move(type_ids),
+ std::move(string_ids),
+ std::move(method_ids),
+ std::move(field_ids));
code_item->SetCodeFixups(fixups);
}
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 8421774104..6797fa5dd6 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -25,8 +25,8 @@
#include <vector>
#include "base/stl_util.h"
-#include "dex_file-inl.h"
-#include "dex_file_types.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_types.h"
#include "leb128.h"
#include "utf.h"
@@ -524,7 +524,8 @@ class Header : public Item {
uint32_t link_size,
uint32_t link_offset,
uint32_t data_size,
- uint32_t data_offset)
+ uint32_t data_offset,
+ bool support_default_methods)
: Item(0, kHeaderItemSize),
checksum_(checksum),
endian_tag_(endian_tag),
@@ -533,7 +534,8 @@ class Header : public Item {
link_size_(link_size),
link_offset_(link_offset),
data_size_(data_size),
- data_offset_(data_offset) {
+ data_offset_(data_offset),
+ support_default_methods_(support_default_methods) {
memcpy(magic_, magic, sizeof(magic_));
memcpy(signature_, signature, sizeof(signature_));
}
@@ -567,6 +569,10 @@ class Header : public Item {
void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
+ bool SupportDefaultMethods() const {
+ return support_default_methods_;
+ }
+
private:
uint8_t magic_[8];
uint32_t checksum_;
@@ -578,6 +584,7 @@ class Header : public Item {
uint32_t link_offset_;
uint32_t data_size_;
uint32_t data_offset_;
+ const bool support_default_methods_;
Collections collections_;
@@ -1013,25 +1020,25 @@ using TryItemVector = std::vector<std::unique_ptr<const TryItem>>;
class CodeFixups {
public:
- CodeFixups(std::vector<TypeId*>* type_ids,
- std::vector<StringId*>* string_ids,
- std::vector<MethodId*>* method_ids,
- std::vector<FieldId*>* field_ids)
- : type_ids_(type_ids),
- string_ids_(string_ids),
- method_ids_(method_ids),
- field_ids_(field_ids) { }
-
- std::vector<TypeId*>* TypeIds() const { return type_ids_.get(); }
- std::vector<StringId*>* StringIds() const { return string_ids_.get(); }
- std::vector<MethodId*>* MethodIds() const { return method_ids_.get(); }
- std::vector<FieldId*>* FieldIds() const { return field_ids_.get(); }
+ CodeFixups(std::vector<TypeId*> type_ids,
+ std::vector<StringId*> string_ids,
+ std::vector<MethodId*> method_ids,
+ std::vector<FieldId*> field_ids)
+ : type_ids_(std::move(type_ids)),
+ string_ids_(std::move(string_ids)),
+ method_ids_(std::move(method_ids)),
+ field_ids_(std::move(field_ids)) { }
+
+ const std::vector<TypeId*>& TypeIds() const { return type_ids_; }
+ const std::vector<StringId*>& StringIds() const { return string_ids_; }
+ const std::vector<MethodId*>& MethodIds() const { return method_ids_; }
+ const std::vector<FieldId*>& FieldIds() const { return field_ids_; }
private:
- std::unique_ptr<std::vector<TypeId*>> type_ids_;
- std::unique_ptr<std::vector<StringId*>> string_ids_;
- std::unique_ptr<std::vector<MethodId*>> method_ids_;
- std::unique_ptr<std::vector<FieldId*>> field_ids_;
+ std::vector<TypeId*> type_ids_;
+ std::vector<StringId*> string_ids_;
+ std::vector<MethodId*> method_ids_;
+ std::vector<FieldId*> field_ids_;
DISALLOW_COPY_AND_ASSIGN(CodeFixups);
};
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 1fd963fe22..231826b7a8 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -37,7 +37,8 @@ Header* DexIrBuilder(const DexFile& dex_file, bool eagerly_assign_offsets) {
disk_header.link_size_,
disk_header.link_off_,
disk_header.data_size_,
- disk_header.data_off_);
+ disk_header.data_off_,
+ dex_file.SupportsDefaultMethods());
Collections& collections = header->GetCollections();
collections.SetEagerlyAssignOffsets(eagerly_assign_offsets);
// Walk the rest of the header fields.
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
index 4b46341ada..e4ed69b8d2 100644
--- a/dexlayout/dex_visualize.cc
+++ b/dexlayout/dex_visualize.cc
@@ -188,20 +188,16 @@ class Dumper {
DumpAddressRange(code_item, class_index);
const dex_ir::CodeFixups* fixups = code_item->GetCodeFixups();
if (fixups != nullptr) {
- std::vector<dex_ir::TypeId*>* type_ids = fixups->TypeIds();
- for (dex_ir::TypeId* type_id : *type_ids) {
+ for (dex_ir::TypeId* type_id : fixups->TypeIds()) {
DumpTypeId(type_id, class_index);
}
- std::vector<dex_ir::StringId*>* string_ids = fixups->StringIds();
- for (dex_ir::StringId* string_id : *string_ids) {
+ for (dex_ir::StringId* string_id : fixups->StringIds()) {
DumpStringId(string_id, class_index);
}
- std::vector<dex_ir::MethodId*>* method_ids = fixups->MethodIds();
- for (dex_ir::MethodId* method_id : *method_ids) {
+ for (dex_ir::MethodId* method_id : fixups->MethodIds()) {
DumpMethodId(method_id, class_index);
}
- std::vector<dex_ir::FieldId*>* field_ids = fixups->FieldIds();
- for (dex_ir::FieldId* field_id : *field_ids) {
+ for (dex_ir::FieldId* field_id : fixups->FieldIds()) {
DumpFieldId(field_id, class_index);
}
}
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 1fac2359b0..a18a2cfd8a 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -20,12 +20,12 @@
#include <vector>
-#include "cdex/compact_dex_file.h"
#include "compact_dex_writer.h"
-#include "dex_file_layout.h"
-#include "dex_file_types.h"
+#include "dex/compact_dex_file.h"
+#include "dex/dex_file_layout.h"
+#include "dex/dex_file_types.h"
+#include "dex/standard_dex_file.h"
#include "dexlayout.h"
-#include "standard_dex_file.h"
#include "utf.h"
namespace art {
@@ -780,7 +780,7 @@ void DexWriter::WriteHeader() {
header.checksum_ = header_->Checksum();
std::copy_n(header_->Signature(), DexFile::kSha1DigestSize, header.signature_);
header.file_size_ = header_->FileSize();
- header.header_size_ = header_->GetSize();
+ header.header_size_ = GetHeaderSize();
header.endian_tag_ = header_->EndianTag();
header.link_size_ = header_->LinkSize();
header.link_off_ = header_->LinkOffset();
@@ -801,13 +801,18 @@ void DexWriter::WriteHeader() {
header.data_size_ = header_->DataSize();
header.data_off_ = header_->DataOffset();
+ CHECK_EQ(sizeof(header), GetHeaderSize());
static_assert(sizeof(header) == 0x70, "Size doesn't match dex spec");
UNUSED(Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u));
}
+size_t DexWriter::GetHeaderSize() const {
+ return sizeof(StandardDexFile::Header);
+}
+
void DexWriter::WriteMemMap() {
// Starting offset is right after the header.
- uint32_t offset = sizeof(StandardDexFile::Header);
+ uint32_t offset = GetHeaderSize();
dex_ir::Collections& collection = header_->GetCollections();
@@ -893,6 +898,12 @@ void DexWriter::WriteMemMap() {
header_->SetFileSize(offset);
}
WriteHeader();
+
+ if (dex_layout_->GetOptions().update_checksum_) {
+ header_->SetChecksum(DexFile::CalculateChecksum(mem_map_->Begin(), offset));
+ // Rewrite the header with the calculated checksum.
+ WriteHeader();
+ }
}
void DexWriter::Output(dex_ir::Header* header,
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index c47898e533..92a002edc7 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -22,7 +22,7 @@
#include <functional>
#include "base/unix_file/fd_file.h"
-#include "cdex/compact_dex_level.h"
+#include "dex/compact_dex_level.h"
#include "dex_ir.h"
#include "mem_map.h"
#include "os.h"
@@ -91,6 +91,7 @@ class DexWriter {
// Header and id section
virtual void WriteHeader();
+ virtual size_t GetHeaderSize() const;
// reserve_only means don't write, only reserve space. This is required since the string data
// offsets must be assigned.
uint32_t WriteStringIds(uint32_t offset, bool reserve_only);
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index e83f98ee6b..99b1f38f73 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -26,9 +26,10 @@
#include "android-base/stringprintf.h"
+#include "base/logging.h" // For InitLogging.
#include "base/stringpiece.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "dex_ir.h"
#include "dex_ir_builder.h"
#ifdef ART_TARGET_ANDROID
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index d904a52f0c..47a3e943a5 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -33,12 +33,13 @@
#include "android-base/stringprintf.h"
-#include "dex_file-inl.h"
-#include "dex_file_layout.h"
-#include "dex_file_loader.h"
-#include "dex_file_types.h"
-#include "dex_file_verifier.h"
-#include "dex_instruction-inl.h"
+#include "base/logging.h" // For VLOG_IS_ON.
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_layout.h"
+#include "dex/dex_file_loader.h"
+#include "dex/dex_file_types.h"
+#include "dex/dex_file_verifier.h"
+#include "dex/dex_instruction-inl.h"
#include "dex_ir_builder.h"
#include "dex_verify.h"
#include "dex_visualize.h"
@@ -52,10 +53,6 @@ namespace art {
using android::base::StringPrintf;
-// Setting this to false disables class def layout entirely, which is stronger than strictly
-// necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550).
-static constexpr bool kChangeClassDefOrder = false;
-
/*
* Flags for use with createAccessFlagStr().
*/
@@ -1593,7 +1590,7 @@ void DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
}
CHECK_EQ(class_data_index, class_datas.size());
- if (kChangeClassDefOrder) {
+ if (DexLayout::kChangeClassDefOrder) {
// This currently produces dex files that violate the spec since the super class class_def is
// supposed to occur before any subclasses.
dex_ir::CollectionVector<dex_ir::ClassDef>::Vector& class_defs =
@@ -1656,11 +1653,11 @@ void DexLayout::LayoutStringData(const DexFile* dex_file) {
continue;
}
// Add const-strings.
- for (dex_ir::StringId* id : *fixups->StringIds()) {
+ for (dex_ir::StringId* id : fixups->StringIds()) {
from_hot_method[id->GetIndex()] = true;
}
// Add field classes, names, and types.
- for (dex_ir::FieldId* id : *fixups->FieldIds()) {
+ for (dex_ir::FieldId* id : fixups->FieldIds()) {
// TODO: Only visit field ids from static getters and setters.
from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
from_hot_method[id->Name()->GetIndex()] = true;
@@ -1668,7 +1665,7 @@ void DexLayout::LayoutStringData(const DexFile* dex_file) {
}
// For clinits, add referenced method classes, names, and protos.
if (is_clinit) {
- for (dex_ir::MethodId* id : *fixups->MethodIds()) {
+ for (dex_ir::MethodId* id : fixups->MethodIds()) {
from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
from_hot_method[id->Name()->GetIndex()] = true;
is_shorty[id->Proto()->Shorty()->GetIndex()] = true;
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index 8a277b7afe..25afb773bd 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -27,8 +27,8 @@
#include <stdio.h>
#include <unordered_map>
-#include "cdex/compact_dex_level.h"
-#include "dex_file_layout.h"
+#include "dex/compact_dex_level.h"
+#include "dex/dex_file_layout.h"
#include "dex_ir.h"
#include "mem_map.h"
@@ -63,6 +63,7 @@ class Options {
bool verbose_ = false;
bool verify_output_ = kIsDebugBuild;
bool visualize_pattern_ = false;
+ bool update_checksum_ = false;
CompactDexLevel compact_dex_level_ = CompactDexLevel::kCompactDexLevelNone;
OutputFormat output_format_ = kOutputPlain;
const char* output_dex_directory_ = nullptr;
@@ -79,6 +80,10 @@ class DexLayoutHotnessInfo {
class DexLayout {
public:
+ // Setting this to false disables class def layout entirely, which is stronger than strictly
+ // necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550).
+ static constexpr bool kChangeClassDefOrder = false;
+
DexLayout(Options& options,
ProfileCompilationInfo* info,
FILE* out_file,
@@ -102,6 +107,10 @@ class DexLayout {
return layout_hotness_info_;
}
+ const Options& GetOptions() const {
+ return options_;
+ }
+
private:
void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item);
void DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index 17097f1728..5bb7196531 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -29,7 +29,9 @@
#include <sys/types.h>
#include <unistd.h>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/logging.h" // For InitLogging.
#include "jit/profile_compilation_info.h"
#include "mem_map.h"
#include "runtime.h"
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index f994fd6533..b8cff6dc59 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -23,8 +23,9 @@
#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_loader.h"
#include "exec_utils.h"
#include "jit/profile_compilation_info.h"
#include "utils.h"
@@ -698,7 +699,7 @@ TEST_F(DexLayoutTest, CodeItemOverrun) {
while (it.HasNextMethod()) {
DexFile::CodeItem* item = const_cast<DexFile::CodeItem*>(it.GetMethodCodeItem());
if (item != nullptr) {
- IterationRange<DexInstructionIterator> instructions = item->Instructions();
+ CodeItemInstructionAccessor instructions(dex, item);
if (instructions.begin() != instructions.end()) {
DexInstructionIterator last_instruction = instructions.begin();
for (auto dex_it = instructions.begin(); dex_it != instructions.end(); ++dex_it) {
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 3bd903de5b..348f501ef5 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -26,8 +26,10 @@
#include <stdio.h>
#include <stdlib.h>
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
+#include "base/logging.h" // For InitLogging.
+#include "dex/code_item_accessors-no_art-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_loader.h"
#include "mem_map.h"
#include "runtime.h"
@@ -98,6 +100,7 @@ static void dumpMethod(const DexFile* pDexFile,
if (pCode == nullptr || codeOffset == 0) {
return;
}
+ CodeItemDebugInfoAccessor accessor(pDexFile, pCode, pDexFile->GetDebugInfoOffset(pCode));
// Method information.
const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
@@ -120,8 +123,7 @@ static void dumpMethod(const DexFile* pDexFile,
// Find the first line.
int firstLine = -1;
- uint32_t debug_info_offset = pDexFile->GetDebugInfoOffset(pCode);
- pDexFile->DecodeDebugPositionInfo(pCode, debug_info_offset, positionsCb, &firstLine);
+ pDexFile->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), positionsCb, &firstLine);
// Method signature.
const Signature signature = pDexFile->GetMethodSignature(pMethodId);
@@ -129,7 +131,7 @@ static void dumpMethod(const DexFile* pDexFile,
// Dump actual method information.
fprintf(gOutFile, "0x%08x %d %s %s %s %s %d\n",
- insnsOff, pCode->insns_size_in_code_units_ * 2,
+ insnsOff, accessor.InsnsSizeInCodeUnits() * 2,
className.get(), methodName, typeDesc, fileName, firstLine);
free(typeDesc);
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index 39c9b9993b..bedc4576d5 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -16,12 +16,14 @@
#include <string>
+#include "base/logging.h" // For InitLogging.
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
#include "base/file_utils.h"
+#include "base/logging.h" // For InitLogging.
#include "compiler_filter.h"
#include "class_loader_context.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "noop_compiler_callbacks.h"
#include "oat_file_assistant.h"
#include "os.h"
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index 2c800e7af3..b5f5d6ff10 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -177,7 +177,9 @@ static const MipsInstruction gMipsInstructions[] = {
{ kSpecial3Mask | 0x3f, (31 << kOpcodeShift), "ext", "TSAZ", },
{ kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 3, "dext", "TSAZ", },
{ kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 4, "ins", "TSAz", },
+ { kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 5, "dinsm", "TSAJ", },
{ kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 6, "dinsu", "TSFz", },
+ { kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 7, "dins", "TSAz", },
{ kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f,
(31 << kOpcodeShift) | (16 << 6) | 32,
"seb",
@@ -584,6 +586,9 @@ size_t DisassemblerMips::Dump(std::ostream& os, const uint8_t* instr_ptr) {
case 'i': // Sign-extended lower 16-bit immediate.
args << static_cast<int16_t>(instruction & 0xffff);
break;
+ case 'J': // sz (dinsm size).
+ args << (rd - sa + 33);
+ break;
case 'j': // sa value for lsa/dlsa.
args << (sa + 1);
break;
diff --git a/dt_fd_forward/Android.bp b/dt_fd_forward/Android.bp
new file mode 100644
index 0000000000..1ba2323a15
--- /dev/null
+++ b/dt_fd_forward/Android.bp
@@ -0,0 +1,66 @@
+//
+// 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.
+//
+
+// Build variants {target,host} x {debug,ndebug} x {32,64}
+
+cc_defaults {
+ name: "dt_fd_forward-defaults",
+ host_supported: true,
+ srcs: ["dt_fd_forward.cc"],
+ defaults: ["art_defaults"],
+
+ // Note that this tool needs to be built for both 32-bit and 64-bit since it needs to be same
+ // ISA as what it is attached to.
+ compile_multilib: "both",
+
+ shared_libs: [
+ "libbase",
+ ],
+ target: {
+ android: {
+ },
+ host: {
+ },
+ darwin: {
+ enabled: false,
+ },
+ },
+ header_libs: [
+ "javavm_headers",
+ "dt_fd_forward_export",
+ ],
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+}
+
+art_cc_library {
+ name: "libdt_fd_forward",
+ defaults: ["dt_fd_forward-defaults"],
+}
+
+art_cc_library {
+ name: "libdt_fd_forwardd",
+ defaults: [
+ "art_debug_defaults",
+ "dt_fd_forward-defaults",
+ ],
+}
diff --git a/dt_fd_forward/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION b/dt_fd_forward/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dt_fd_forward/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION
diff --git a/dt_fd_forward/NOTICE b/dt_fd_forward/NOTICE
new file mode 100644
index 0000000000..4fd88fa841
--- /dev/null
+++ b/dt_fd_forward/NOTICE
@@ -0,0 +1,30 @@
+Copyright (C) 2017 The Android Open Source Project
+DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+This file implements interfaces from the file jdwpTransport.h. This
+implementation is licensed under the same terms as the file
+jdwpTransport.h. The copyright and license information for the file
+jdwpTransport.h follows.
+
+Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+This code is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 only, as
+published by the Free Software Foundation. Oracle designates this
+particular file as subject to the "Classpath" exception as provided
+by Oracle in the LICENSE file that accompanied this code.
+
+This code is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+version 2 for more details (a copy is included in the LICENSE file that
+accompanied this code).
+
+You should have received a copy of the GNU General Public License version
+2 along with this work; if not, write to the Free Software Foundation,
+Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+or visit www.oracle.com if you need additional information or have any
+questions.
diff --git a/dt_fd_forward/README.md b/dt_fd_forward/README.md
new file mode 100644
index 0000000000..c7ac840928
--- /dev/null
+++ b/dt_fd_forward/README.md
@@ -0,0 +1,32 @@
+# dt_fd_forward
+
+dt_fd_forward is a jdwpTransport library. It implements the [Java Debug Wire
+Protocol Transport Interface
+(jdwpTransport)](https://docs.oracle.com/javase/7/docs/technotes/guides/jpda/jdwpTransport.html).
+It allows one to handle and proxy JDWP traffic by supplying the implementation
+for Attach. This transport requires an address. The address is a single integer
+value that is the file-descriptor of an open AF\_UNIX socket.
+
+When this transport begins listening or attaching it will send the
+null-terminated string "dt_fd_forward:START-LISTEN\0" over the given socket.
+
+When this transport stops listening for connections it will send the
+null-terminated string "dt_fd_forward:END-LISTEN\0" over the socket.
+
+When this transport has successfully received fds from the proxy it sends the
+message "dt_fd_forward:ATTACHED\0" over the socket.
+
+When this transport has closed its copies of the fds it will send the proxy the
+message "dt_fd_forward:CLOSING\0" over the socket.
+
+When this transport accepts or attaches to a connection it will read from the
+socket a 1 byte message and 3 file-descriptors. The file descriptors are, in
+order, an fd that will be read from to get incoming JDWP packets (read\_fd\_),
+an fd that outgoing JDWP packets will be written to (write\_fd\_), and an
+_eventfd_ (write\_lock\_fd\_). The eventfd should not have any flags set. Prior
+to writing any data to write\_fd\_ the transport will _read_ from the
+write\_lock\_fd\_ and after finishing the write it will _write_ to it. This
+allows one to safely multiplex data on the write\_fd\_.
+
+This transport implements no optional capabilities, though this may change in
+the future.
diff --git a/dt_fd_forward/dt_fd_forward.cc b/dt_fd_forward/dt_fd_forward.cc
new file mode 100644
index 0000000000..cf3088dc60
--- /dev/null
+++ b/dt_fd_forward/dt_fd_forward.cc
@@ -0,0 +1,761 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jdwpTransport.h. This
+ * implementation is licensed under the same terms as the file
+ * jdwpTransport.h. The copyright and license information for the file
+ * jdwpTransport.h follows.
+ *
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "dt_fd_forward.h"
+
+#include <string>
+#include <vector>
+
+#include <android-base/endian.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+
+#include <sys/ioctl.h>
+#include <sys/eventfd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <poll.h>
+
+#include <jni.h>
+#include <jdwpTransport.h>
+
+namespace dt_fd_forward {
+
+// Helper that puts line-number in error message.
+#define DT_IO_ERROR(f) \
+ SetLastError(::android::base::StringPrintf("%s:%d - %s: %s", \
+ __FILE__, __LINE__, f, strerror(errno)))
+
+extern const jdwpTransportNativeInterface_ gTransportInterface;
+
+template <typename T> static T HostToNetwork(T in);
+template <typename T> static T NetworkToHost(T in);
+
+template<> int8_t HostToNetwork(int8_t in) { return in; }
+template<> int8_t NetworkToHost(int8_t in) { return in; }
+template<> int16_t HostToNetwork(int16_t in) { return htons(in); }
+template<> int16_t NetworkToHost(int16_t in) { return ntohs(in); }
+template<> int32_t HostToNetwork(int32_t in) { return htonl(in); }
+template<> int32_t NetworkToHost(int32_t in) { return ntohl(in); }
+
+FdForwardTransport::FdForwardTransport(jdwpTransportCallback* cb)
+ : mem_(*cb),
+ read_fd_(-1),
+ write_fd_(-1),
+ wakeup_fd_(eventfd(0, EFD_NONBLOCK)),
+ listen_fd_(-1),
+ close_notify_fd_(-1),
+ state_(TransportState::kClosed),
+ current_seq_num_(0) {}
+
+FdForwardTransport::~FdForwardTransport() { }
+
+bool FdForwardTransport::ChangeState(TransportState old_state, TransportState new_state) {
+ if (old_state == state_) {
+ state_ = new_state;
+ state_cv_.notify_all();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+jdwpTransportError FdForwardTransport::PerformAttach(int listen_fd) {
+ jdwpTransportError err = SetupListen(listen_fd);
+ if (err != OK) {
+ return OK;
+ }
+ err = Accept();
+ StopListening();
+ return err;
+}
+
+static void SendListenMessage(const android::base::unique_fd& fd) {
+ TEMP_FAILURE_RETRY(send(fd, kListenStartMessage, sizeof(kListenStartMessage), MSG_EOR));
+}
+
+jdwpTransportError FdForwardTransport::SetupListen(int listen_fd) {
+ std::lock_guard<std::mutex> lk(state_mutex_);
+ if (!ChangeState(TransportState::kClosed, TransportState::kListenSetup)) {
+ return ERR(ILLEGAL_STATE);
+ } else {
+ listen_fd_.reset(dup(listen_fd));
+ SendListenMessage(listen_fd_);
+ CHECK(ChangeState(TransportState::kListenSetup, TransportState::kListening));
+ return OK;
+ }
+}
+
+static void SendListenEndMessage(const android::base::unique_fd& fd) {
+ TEMP_FAILURE_RETRY(send(fd, kListenEndMessage, sizeof(kListenEndMessage), MSG_EOR));
+}
+
+jdwpTransportError FdForwardTransport::StopListening() {
+ std::lock_guard<std::mutex> lk(state_mutex_);
+ if (listen_fd_ != -1) {
+ SendListenEndMessage(listen_fd_);
+ }
+ // Don't close the listen_fd_ since we might need it for later calls to listen.
+ if (ChangeState(TransportState::kListening, TransportState::kClosed) ||
+ state_ == TransportState::kOpen) {
+ listen_fd_.reset();
+ }
+ return OK;
+}
+
+// Last error message.
+thread_local std::string global_last_error_;
+
+void FdForwardTransport::SetLastError(const std::string& desc) {
+ LOG(ERROR) << desc;
+ global_last_error_ = desc;
+}
+
+IOResult FdForwardTransport::ReadFullyWithoutChecks(void* data, size_t ndata) {
+ uint8_t* bdata = reinterpret_cast<uint8_t*>(data);
+ size_t nbytes = 0;
+ while (nbytes < ndata) {
+ int res = TEMP_FAILURE_RETRY(read(read_fd_, bdata + nbytes, ndata - nbytes));
+ if (res < 0) {
+ DT_IO_ERROR("Failed read()");
+ return IOResult::kError;
+ } else if (res == 0) {
+ return IOResult::kEOF;
+ } else {
+ nbytes += res;
+ }
+ }
+ return IOResult::kOk;
+}
+
+IOResult FdForwardTransport::ReadUpToMax(void* data, size_t ndata, /*out*/size_t* read_amount) {
+ CHECK_GE(read_fd_.get(), 0);
+ int avail;
+ int res = ioctl(read_fd_, FIONREAD, &avail);
+ if (res < 0) {
+ DT_IO_ERROR("Failed ioctl(read_fd_, FIONREAD, &avail)");
+ return IOResult::kError;
+ }
+ size_t to_read = std::min(static_cast<size_t>(avail), ndata);
+ *read_amount = to_read;
+ if (*read_amount == 0) {
+ // Check if the read would cause an EOF.
+ struct pollfd pollfd = { read_fd_, POLLRDHUP, 0 };
+ res = poll(&pollfd, /*nfds*/1, /*timeout*/0);
+ if (res < 0 || (pollfd.revents & POLLERR) == POLLERR) {
+ DT_IO_ERROR("Failed poll on read fd.");
+ return IOResult::kError;
+ }
+ return ((pollfd.revents & (POLLRDHUP | POLLHUP)) == 0) ? IOResult::kOk : IOResult::kEOF;
+ }
+
+ return ReadFullyWithoutChecks(data, to_read);
+}
+
+IOResult FdForwardTransport::ReadFully(void* data, size_t ndata) {
+ uint64_t seq_num = current_seq_num_;
+ size_t nbytes = 0;
+ while (nbytes < ndata) {
+ size_t read_len;
+ struct pollfd pollfds[2];
+ {
+ std::lock_guard<std::mutex> lk(state_mutex_);
+ // Operations in this block must not cause an unbounded pause.
+ if (state_ != TransportState::kOpen || seq_num != current_seq_num_) {
+ // Async-close occurred!
+ return IOResult::kInterrupt;
+ } else {
+ CHECK_GE(read_fd_.get(), 0);
+ }
+ IOResult res = ReadUpToMax(reinterpret_cast<uint8_t*>(data) + nbytes,
+ ndata - nbytes,
+ /*out*/&read_len);
+ if (res != IOResult::kOk) {
+ return res;
+ } else {
+ nbytes += read_len;
+ }
+
+ pollfds[0] = { read_fd_, POLLRDHUP | POLLIN, 0 };
+ pollfds[1] = { wakeup_fd_, POLLIN, 0 };
+ }
+ if (read_len == 0) {
+ // No more data. Sleep without locks until more is available. We don't actually check for any
+ // errors since possible ones are (1) the read_fd_ is closed or wakeup happens which are both
+ // fine since the wakeup_fd_ or the poll failing will wake us up.
+ int poll_res = poll(pollfds, 2, -1);
+ if (poll_res < 0) {
+ DT_IO_ERROR("Failed to poll!");
+ }
+ // Clear the wakeup_fd regardless.
+ uint64_t val;
+ int unused = read(wakeup_fd_, &val, sizeof(val));
+ DCHECK(unused == sizeof(val) || errno == EAGAIN);
+ if (poll_res < 0) {
+ return IOResult::kError;
+ }
+ }
+ }
+ return IOResult::kOk;
+}
+
+// A helper that allows us to lock the eventfd 'fd'.
+class ScopedEventFdLock {
+ public:
+ explicit ScopedEventFdLock(const android::base::unique_fd& fd) : fd_(fd), data_(0) {
+ TEMP_FAILURE_RETRY(read(fd_, &data_, sizeof(data_)));
+ }
+
+ ~ScopedEventFdLock() {
+ TEMP_FAILURE_RETRY(write(fd_, &data_, sizeof(data_)));
+ }
+
+ private:
+ const android::base::unique_fd& fd_;
+ uint64_t data_;
+};
+
+IOResult FdForwardTransport::WriteFullyWithoutChecks(const void* data, size_t ndata) {
+ ScopedEventFdLock sefdl(write_lock_fd_);
+ const uint8_t* bdata = static_cast<const uint8_t*>(data);
+ size_t nbytes = 0;
+ while (nbytes < ndata) {
+ int res = TEMP_FAILURE_RETRY(write(write_fd_, bdata + nbytes, ndata - nbytes));
+ if (res < 0) {
+ DT_IO_ERROR("Failed write()");
+ return IOResult::kError;
+ } else if (res == 0) {
+ return IOResult::kEOF;
+ } else {
+ nbytes += res;
+ }
+ }
+ return IOResult::kOk;
+}
+
+IOResult FdForwardTransport::WriteFully(const void* data, size_t ndata) {
+ std::lock_guard<std::mutex> lk(state_mutex_);
+ if (state_ != TransportState::kOpen) {
+ return IOResult::kInterrupt;
+ }
+ return WriteFullyWithoutChecks(data, ndata);
+}
+
+static void SendAcceptMessage(int fd) {
+ TEMP_FAILURE_RETRY(send(fd, kAcceptMessage, sizeof(kAcceptMessage), MSG_EOR));
+}
+
+IOResult FdForwardTransport::ReceiveFdsFromSocket() {
+ union {
+ cmsghdr cm;
+ uint8_t buffer[CMSG_SPACE(sizeof(FdSet))];
+ } msg_union;
+ // We don't actually care about the data. Only FDs. We need to have an iovec anyway to tell if we
+ // got the values or not though.
+ char dummy = '\0';
+ iovec iov;
+ iov.iov_base = &dummy;
+ iov.iov_len = sizeof(dummy);
+
+ msghdr msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = msg_union.buffer;
+ msg.msg_controllen = sizeof(msg_union.buffer);
+
+ cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = msg.msg_controllen;
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ memset(reinterpret_cast<int*>(CMSG_DATA(cmsg)), -1, FdSet::kDataLength);
+
+ int res = TEMP_FAILURE_RETRY(recvmsg(listen_fd_, &msg, 0));
+ if (res <= 0) {
+ DT_IO_ERROR("Failed to receive fds!");
+ return IOResult::kError;
+ }
+ FdSet out_fds = FdSet::ReadData(CMSG_DATA(cmsg));
+ if (out_fds.read_fd_ < 0 || out_fds.write_fd_ < 0 || out_fds.write_lock_fd_ < 0) {
+ DT_IO_ERROR("Received fds were invalid!");
+ if (out_fds.read_fd_ >= 0) {
+ close(out_fds.read_fd_);
+ }
+ if (out_fds.write_fd_ >= 0) {
+ close(out_fds.write_fd_);
+ }
+ if (out_fds.write_lock_fd_ >= 0) {
+ close(out_fds.write_lock_fd_);
+ }
+ return IOResult::kError;
+ }
+
+ read_fd_.reset(out_fds.read_fd_);
+ write_fd_.reset(out_fds.write_fd_);
+ write_lock_fd_.reset(out_fds.write_lock_fd_);
+
+ // We got the fds. Send ack.
+ close_notify_fd_.reset(dup(listen_fd_));
+ SendAcceptMessage(close_notify_fd_);
+
+ return IOResult::kOk;
+}
+
+// Accept the connection. Note that we match the behavior of other transports which is to just close
+// the connection and try again if we get a bad handshake.
+jdwpTransportError FdForwardTransport::Accept() {
+ // TODO Work with timeouts.
+ while (true) {
+ std::unique_lock<std::mutex> lk(state_mutex_);
+ while (!ChangeState(TransportState::kListening, TransportState::kOpening)) {
+ if (state_ == TransportState::kClosed ||
+ state_ == TransportState::kOpen) {
+ return ERR(ILLEGAL_STATE);
+ }
+ state_cv_.wait(lk);
+ }
+
+ DCHECK_NE(listen_fd_.get(), -1);
+ if (ReceiveFdsFromSocket() != IOResult::kOk) {
+ CHECK(ChangeState(TransportState::kOpening, TransportState::kListening));
+ return ERR(IO_ERROR);
+ }
+
+ current_seq_num_++;
+
+ // Moved to the opening state.
+ char handshake_recv[sizeof(kJdwpHandshake)];
+ memset(handshake_recv, 0, sizeof(handshake_recv));
+ IOResult res = ReadFullyWithoutChecks(handshake_recv, sizeof(handshake_recv));
+ if (res != IOResult::kOk ||
+ strncmp(handshake_recv, kJdwpHandshake, sizeof(kJdwpHandshake)) != 0) {
+ DT_IO_ERROR("Failed to read handshake");
+ CHECK(ChangeState(TransportState::kOpening, TransportState::kListening));
+ CloseFdsLocked();
+ // Retry.
+ continue;
+ }
+ res = WriteFullyWithoutChecks(kJdwpHandshake, sizeof(kJdwpHandshake));
+ if (res != IOResult::kOk) {
+ DT_IO_ERROR("Failed to write handshake");
+ CHECK(ChangeState(TransportState::kOpening, TransportState::kListening));
+ CloseFdsLocked();
+ // Retry.
+ continue;
+ }
+ break;
+ }
+ CHECK(ChangeState(TransportState::kOpening, TransportState::kOpen));
+ return OK;
+}
+
+void SendClosingMessage(int fd) {
+ if (fd >= 0) {
+ TEMP_FAILURE_RETRY(send(fd, kCloseMessage, sizeof(kCloseMessage), MSG_EOR));
+ }
+}
+
+// Actually close the fds associated with this transport.
+void FdForwardTransport::CloseFdsLocked() {
+ // We have a different set of fd's now. Increase the seq number.
+ current_seq_num_++;
+
+ // All access to these is locked under the state_mutex_ so we are safe to close these.
+ {
+ ScopedEventFdLock sefdl(write_lock_fd_);
+ if (close_notify_fd_ >= 0) {
+ SendClosingMessage(close_notify_fd_);
+ }
+ close_notify_fd_.reset();
+ read_fd_.reset();
+ write_fd_.reset();
+ close_notify_fd_.reset();
+ }
+ write_lock_fd_.reset();
+
+ // Send a wakeup in case we have any in-progress reads/writes.
+ uint64_t data = 1;
+ TEMP_FAILURE_RETRY(write(wakeup_fd_, &data, sizeof(data)));
+}
+
+jdwpTransportError FdForwardTransport::Close() {
+ std::lock_guard<std::mutex> lk(state_mutex_);
+ jdwpTransportError res =
+ ChangeState(TransportState::kOpen, TransportState::kClosed) ? OK : ERR(ILLEGAL_STATE);
+ // Send a wakeup after changing the state even if nothing actually happened.
+ uint64_t data = 1;
+ TEMP_FAILURE_RETRY(write(wakeup_fd_, &data, sizeof(data)));
+ if (res == OK) {
+ CloseFdsLocked();
+ }
+ return res;
+}
+
+// A helper class to read and parse the JDWP packet.
+class PacketReader {
+ public:
+ PacketReader(FdForwardTransport* transport, jdwpPacket* pkt)
+ : transport_(transport),
+ pkt_(pkt),
+ is_eof_(false),
+ is_err_(false) {}
+ bool ReadFully() {
+ // Zero out.
+ memset(pkt_, 0, sizeof(jdwpPacket));
+ int32_t len = ReadInt32(); // read len
+ if (is_err_) {
+ return false;
+ } else if (is_eof_) {
+ return true;
+ } else if (len < 11) {
+ transport_->DT_IO_ERROR("Packet with len < 11 received!");
+ return false;
+ }
+ pkt_->type.cmd.len = len;
+ pkt_->type.cmd.id = ReadInt32();
+ pkt_->type.cmd.flags = ReadByte();
+ if (is_err_) {
+ return false;
+ } else if (is_eof_) {
+ return true;
+ } else if ((pkt_->type.reply.flags & JDWPTRANSPORT_FLAGS_REPLY) == JDWPTRANSPORT_FLAGS_REPLY) {
+ ReadReplyPacket();
+ } else {
+ ReadCmdPacket();
+ }
+ return !is_err_;
+ }
+
+ private:
+ void ReadReplyPacket() {
+ pkt_->type.reply.errorCode = ReadInt16();
+ pkt_->type.reply.data = ReadRemaining();
+ }
+
+ void ReadCmdPacket() {
+ pkt_->type.cmd.cmdSet = ReadByte();
+ pkt_->type.cmd.cmd = ReadByte();
+ pkt_->type.cmd.data = ReadRemaining();
+ }
+
+ template <typename T>
+ T HandleResult(IOResult res, T val, T fail) {
+ switch (res) {
+ case IOResult::kError:
+ is_err_ = true;
+ return fail;
+ case IOResult::kOk:
+ return val;
+ case IOResult::kEOF:
+ is_eof_ = true;
+ pkt_->type.cmd.len = 0;
+ return fail;
+ case IOResult::kInterrupt:
+ transport_->DT_IO_ERROR("Failed to read, concurrent close!");
+ is_err_ = true;
+ return fail;
+ }
+ }
+
+ jbyte* ReadRemaining() {
+ if (is_eof_ || is_err_) {
+ return nullptr;
+ }
+ jbyte* out = nullptr;
+ jint rem = pkt_->type.cmd.len - 11;
+ CHECK_GE(rem, 0);
+ if (rem == 0) {
+ return nullptr;
+ } else {
+ out = reinterpret_cast<jbyte*>(transport_->Alloc(rem));
+ IOResult res = transport_->ReadFully(out, rem);
+ jbyte* ret = HandleResult(res, out, static_cast<jbyte*>(nullptr));
+ if (ret != out) {
+ transport_->Free(out);
+ }
+ return ret;
+ }
+ }
+
+ jbyte ReadByte() {
+ if (is_eof_ || is_err_) {
+ return -1;
+ }
+ jbyte out;
+ IOResult res = transport_->ReadFully(&out, sizeof(out));
+ return HandleResult(res, NetworkToHost(out), static_cast<jbyte>(-1));
+ }
+
+ jshort ReadInt16() {
+ if (is_eof_ || is_err_) {
+ return -1;
+ }
+ jshort out;
+ IOResult res = transport_->ReadFully(&out, sizeof(out));
+ return HandleResult(res, NetworkToHost(out), static_cast<jshort>(-1));
+ }
+
+ jint ReadInt32() {
+ if (is_eof_ || is_err_) {
+ return -1;
+ }
+ jint out;
+ IOResult res = transport_->ReadFully(&out, sizeof(out));
+ return HandleResult(res, NetworkToHost(out), -1);
+ }
+
+ FdForwardTransport* transport_;
+ jdwpPacket* pkt_;
+ bool is_eof_;
+ bool is_err_;
+};
+
+jdwpTransportError FdForwardTransport::ReadPacket(jdwpPacket* pkt) {
+ if (pkt == nullptr) {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+ PacketReader reader(this, pkt);
+ if (reader.ReadFully()) {
+ return OK;
+ } else {
+ return ERR(IO_ERROR);
+ }
+}
+
+// A class that writes a packet to the transport.
+class PacketWriter {
+ public:
+ PacketWriter(FdForwardTransport* transport, const jdwpPacket* pkt)
+ : transport_(transport), pkt_(pkt), data_() {}
+
+ bool WriteFully() {
+ PushInt32(pkt_->type.cmd.len);
+ PushInt32(pkt_->type.cmd.id);
+ PushByte(pkt_->type.cmd.flags);
+ if ((pkt_->type.reply.flags & JDWPTRANSPORT_FLAGS_REPLY) == JDWPTRANSPORT_FLAGS_REPLY) {
+ PushInt16(pkt_->type.reply.errorCode);
+ PushData(pkt_->type.reply.data, pkt_->type.reply.len - 11);
+ } else {
+ PushByte(pkt_->type.cmd.cmdSet);
+ PushByte(pkt_->type.cmd.cmd);
+ PushData(pkt_->type.cmd.data, pkt_->type.cmd.len - 11);
+ }
+ IOResult res = transport_->WriteFully(data_.data(), data_.size());
+ return res == IOResult::kOk;
+ }
+
+ private:
+ void PushInt32(int32_t data) {
+ data = HostToNetwork(data);
+ PushData(&data, sizeof(data));
+ }
+ void PushInt16(int16_t data) {
+ data = HostToNetwork(data);
+ PushData(&data, sizeof(data));
+ }
+ void PushByte(jbyte data) {
+ data_.push_back(HostToNetwork(data));
+ }
+
+ void PushData(void* d, size_t size) {
+ uint8_t* bytes = reinterpret_cast<uint8_t*>(d);
+ data_.insert(data_.end(), bytes, bytes + size);
+ }
+
+ FdForwardTransport* transport_;
+ const jdwpPacket* pkt_;
+ std::vector<uint8_t> data_;
+};
+
+jdwpTransportError FdForwardTransport::WritePacket(const jdwpPacket* pkt) {
+ if (pkt == nullptr) {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+ PacketWriter writer(this, pkt);
+ if (writer.WriteFully()) {
+ return OK;
+ } else {
+ return ERR(IO_ERROR);
+ }
+}
+
+jboolean FdForwardTransport::IsOpen() {
+ return state_ == TransportState::kOpen;
+}
+
+void* FdForwardTransport::Alloc(size_t s) {
+ return mem_.alloc(s);
+}
+
+void FdForwardTransport::Free(void* data) {
+ mem_.free(data);
+}
+
+jdwpTransportError FdForwardTransport::GetLastError(/*out*/char** err) {
+ std::string data = global_last_error_;
+ *err = reinterpret_cast<char*>(Alloc(data.size() + 1));
+ strcpy(*err, data.c_str());
+ return OK;
+}
+
+static FdForwardTransport* AsFdForward(jdwpTransportEnv* env) {
+ return reinterpret_cast<FdForwardTransport*>(env);
+}
+
+static jdwpTransportError ParseAddress(const std::string& addr,
+ /*out*/int* listen_sock) {
+ if (!android::base::ParseInt(addr.c_str(), listen_sock) || *listen_sock < 0) {
+ LOG(ERROR) << "address format is <fd_num> not " << addr;
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+ return OK;
+}
+
+class JdwpTransportFunctions {
+ public:
+ static jdwpTransportError GetCapabilities(jdwpTransportEnv* env ATTRIBUTE_UNUSED,
+ /*out*/ JDWPTransportCapabilities* capabilities_ptr) {
+ // We don't support any of the optional capabilities (can_timeout_attach, can_timeout_accept,
+ // can_timeout_handshake) so just return a zeroed capabilities ptr.
+ // TODO We should maybe support these timeout options.
+ memset(capabilities_ptr, 0, sizeof(JDWPTransportCapabilities));
+ return OK;
+ }
+
+ // Address is <sock_fd>
+ static jdwpTransportError Attach(jdwpTransportEnv* env,
+ const char* address,
+ jlong attach_timeout ATTRIBUTE_UNUSED,
+ jlong handshake_timeout ATTRIBUTE_UNUSED) {
+ if (address == nullptr || *address == '\0') {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+ int listen_fd;
+ jdwpTransportError err = ParseAddress(address, &listen_fd);
+ if (err != OK) {
+ return err;
+ }
+ return AsFdForward(env)->PerformAttach(listen_fd);
+ }
+
+ static jdwpTransportError StartListening(jdwpTransportEnv* env,
+ const char* address,
+ /*out*/ char** actual_address) {
+ if (address == nullptr || *address == '\0') {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+ int listen_fd;
+ jdwpTransportError err = ParseAddress(address, &listen_fd);
+ if (err != OK) {
+ return err;
+ }
+ err = AsFdForward(env)->SetupListen(listen_fd);
+ if (err != OK) {
+ return err;
+ }
+ if (actual_address != nullptr) {
+ *actual_address = reinterpret_cast<char*>(AsFdForward(env)->Alloc(strlen(address) + 1));
+ memcpy(*actual_address, address, strlen(address) + 1);
+ }
+ return OK;
+ }
+
+ static jdwpTransportError StopListening(jdwpTransportEnv* env) {
+ return AsFdForward(env)->StopListening();
+ }
+
+ static jdwpTransportError Accept(jdwpTransportEnv* env,
+ jlong accept_timeout ATTRIBUTE_UNUSED,
+ jlong handshake_timeout ATTRIBUTE_UNUSED) {
+ return AsFdForward(env)->Accept();
+ }
+
+ static jboolean IsOpen(jdwpTransportEnv* env) {
+ return AsFdForward(env)->IsOpen();
+ }
+
+ static jdwpTransportError Close(jdwpTransportEnv* env) {
+ return AsFdForward(env)->Close();
+ }
+
+ static jdwpTransportError ReadPacket(jdwpTransportEnv* env, jdwpPacket *pkt) {
+ return AsFdForward(env)->ReadPacket(pkt);
+ }
+
+ static jdwpTransportError WritePacket(jdwpTransportEnv* env, const jdwpPacket* pkt) {
+ return AsFdForward(env)->WritePacket(pkt);
+ }
+
+ static jdwpTransportError GetLastError(jdwpTransportEnv* env, char** error) {
+ return AsFdForward(env)->GetLastError(error);
+ }
+};
+
+// The actual struct holding all the entrypoints into the jdwpTransport interface.
+const jdwpTransportNativeInterface_ gTransportInterface = {
+ nullptr, // reserved1
+ JdwpTransportFunctions::GetCapabilities,
+ JdwpTransportFunctions::Attach,
+ JdwpTransportFunctions::StartListening,
+ JdwpTransportFunctions::StopListening,
+ JdwpTransportFunctions::Accept,
+ JdwpTransportFunctions::IsOpen,
+ JdwpTransportFunctions::Close,
+ JdwpTransportFunctions::ReadPacket,
+ JdwpTransportFunctions::WritePacket,
+ JdwpTransportFunctions::GetLastError,
+};
+
+extern "C"
+JNIEXPORT jint JNICALL jdwpTransport_OnLoad(JavaVM* vm ATTRIBUTE_UNUSED,
+ jdwpTransportCallback* cb,
+ jint version,
+ jdwpTransportEnv** /*out*/env) {
+ if (version != JDWPTRANSPORT_VERSION_1_0) {
+ LOG(ERROR) << "unknown version " << version;
+ return JNI_EVERSION;
+ }
+ void* data = cb->alloc(sizeof(FdForwardTransport));
+ if (data == nullptr) {
+ LOG(ERROR) << "Failed to allocate data for transport!";
+ return JNI_ENOMEM;
+ }
+ FdForwardTransport* transport =
+ new (data) FdForwardTransport(cb);
+ transport->functions = &gTransportInterface;
+ *env = transport;
+ return JNI_OK;
+}
+
+} // namespace dt_fd_forward
diff --git a/dt_fd_forward/dt_fd_forward.h b/dt_fd_forward/dt_fd_forward.h
new file mode 100644
index 0000000000..9303c59acd
--- /dev/null
+++ b/dt_fd_forward/dt_fd_forward.h
@@ -0,0 +1,154 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jdwpTransport.h. This implementation
+ * is licensed under the same terms as the file jdwpTransport.h. The
+ * copyright and license information for the file jdwpTranport.h follows.
+ *
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef ART_DT_FD_FORWARD_DT_FD_FORWARD_H_
+#define ART_DT_FD_FORWARD_DT_FD_FORWARD_H_
+
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/thread_annotations.h>
+#include <android-base/unique_fd.h>
+
+#include <arpa/inet.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+#include <poll.h>
+
+#include <jni.h>
+#include <jvmti.h>
+#include <jdwpTransport.h>
+
+#include "fd_transport.h"
+
+namespace dt_fd_forward {
+
+static constexpr uint8_t kReplyFlag = 0x80;
+// Macro and constexpr to make error values less annoying to write.
+#define ERR(e) JDWPTRANSPORT_ERROR_ ## e
+static constexpr jdwpTransportError OK = ERR(NONE);
+
+static constexpr const char kJdwpHandshake[14] = {
+ 'J', 'D', 'W', 'P', '-', 'H', 'a', 'n', 'd', 's', 'h', 'a', 'k', 'e'
+}; // "JDWP-Handshake"
+
+enum class TransportState {
+ kClosed, // Main state.
+ kListenSetup, // Transient, wait for the state to change before proceeding.
+ kListening, // Main state.
+ kOpening, // Transient, wait for the state to change before proceeding.
+ kOpen, // Main state.
+};
+
+enum class IOResult {
+ kOk, kInterrupt, kError, kEOF,
+};
+
+class PacketReader;
+class PacketWriter;
+
+// TODO It would be good to get the thread-safety analysis checks working but first we would need to
+// use something other than std::mutex which does not have the annotations required.
+class FdForwardTransport : public jdwpTransportEnv {
+ public:
+ explicit FdForwardTransport(jdwpTransportCallback* cb);
+ ~FdForwardTransport();
+
+ jdwpTransportError PerformAttach(int listen_fd);
+ jdwpTransportError SetupListen(int listen_fd);
+ jdwpTransportError StopListening();
+
+ jboolean IsOpen();
+
+ jdwpTransportError WritePacket(const jdwpPacket* pkt);
+ jdwpTransportError ReadPacket(jdwpPacket* pkt);
+ jdwpTransportError Close();
+ jdwpTransportError Accept();
+ jdwpTransportError GetLastError(/*out*/char** description);
+
+ void* Alloc(size_t data);
+ void Free(void* data);
+
+ private:
+ void SetLastError(const std::string& desc);
+
+ bool ChangeState(TransportState old_state, TransportState new_state); // REQUIRES(state_mutex_);
+
+ IOResult ReceiveFdsFromSocket();
+
+ IOResult WriteFully(const void* data, size_t ndata); // REQUIRES(!state_mutex_);
+ IOResult WriteFullyWithoutChecks(const void* data, size_t ndata); // REQUIRES(state_mutex_);
+ IOResult ReadFully(void* data, size_t ndata); // REQUIRES(!state_mutex_);
+ IOResult ReadUpToMax(void* data, size_t ndata, /*out*/size_t* amount_read);
+ // REQUIRES(state_mutex_);
+ IOResult ReadFullyWithoutChecks(void* data, size_t ndata); // REQUIRES(state_mutex_);
+
+ void CloseFdsLocked(); // REQUIRES(state_mutex_)
+
+ // The allocation/deallocation functions.
+ jdwpTransportCallback mem_;
+
+ // Input from the server;
+ android::base::unique_fd read_fd_; // GUARDED_BY(state_mutex_);
+ // Output to the server;
+ android::base::unique_fd write_fd_; // GUARDED_BY(state_mutex_);
+
+ // an eventfd passed with the write_fd to the transport that we will 'read' from to get a lock on
+ // the write_fd_. The other side must not hold it for unbounded time.
+ android::base::unique_fd write_lock_fd_; // GUARDED_BY(state_mutex_);
+
+ // Eventfd we will use to wake-up paused reads for close().
+ android::base::unique_fd wakeup_fd_;
+
+ // Socket we will get the read/write fd's from.
+ android::base::unique_fd listen_fd_;
+
+ // Fd we will write close notification to. This is a dup of listen_fd_.
+ android::base::unique_fd close_notify_fd_;
+
+ TransportState state_; // GUARDED_BY(state_mutex_);
+
+ std::mutex state_mutex_;
+ std::condition_variable state_cv_;
+
+ // A counter that we use to make sure we don't do half a read on one and half on another fd.
+ std::atomic<uint64_t> current_seq_num_;
+
+ friend class PacketReader; // For ReadFullyWithInterrupt
+ friend class PacketWriter; // For WriteFullyWithInterrupt
+};
+
+} // namespace dt_fd_forward
+
+#endif // ART_DT_FD_FORWARD_DT_FD_FORWARD_H_
diff --git a/dt_fd_forward/export/Android.bp b/dt_fd_forward/export/Android.bp
new file mode 100644
index 0000000000..c3a63212b9
--- /dev/null
+++ b/dt_fd_forward/export/Android.bp
@@ -0,0 +1,22 @@
+//
+// 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.
+//
+
+cc_library_headers {
+ name: "dt_fd_forward_export",
+ export_include_dirs: [ "." ],
+ host_supported: true,
+ device_supported: true,
+}
diff --git a/dt_fd_forward/export/MODULE_LICENSE_APACHE2 b/dt_fd_forward/export/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dt_fd_forward/export/MODULE_LICENSE_APACHE2
diff --git a/dt_fd_forward/export/fd_transport.h b/dt_fd_forward/export/fd_transport.h
new file mode 100644
index 0000000000..245f0c2275
--- /dev/null
+++ b/dt_fd_forward/export/fd_transport.h
@@ -0,0 +1,69 @@
+// 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_DT_FD_FORWARD_EXPORT_FD_TRANSPORT_H_
+#define ART_DT_FD_FORWARD_EXPORT_FD_TRANSPORT_H_
+
+#include <stdint.h>
+
+namespace dt_fd_forward {
+
+// The file-descriptors sent over a socket to the dt_fd_forward transport.
+struct FdSet {
+ // A fd that can be read from which provides the JDWP data.
+ int read_fd_;
+
+ // A fd that can be written to in order to provide JDWP responses and events.
+ int write_fd_;
+
+ // A eventfd that can be locked to ensure that writes to write_fd_ are atomic. This must be held
+ // when writing to write_fd_. This allows the proxy to insert packets into the response stream
+ // without having to parse it.
+ int write_lock_fd_;
+
+ static constexpr size_t kDataLength = sizeof(int) * 3;
+ void WriteData(void* buf) {
+ int* ibuf = reinterpret_cast<int*>(buf);
+ ibuf[0] = read_fd_;
+ ibuf[1] = write_fd_;
+ ibuf[2] = write_lock_fd_;
+ }
+
+ static FdSet ReadData(void* buf) {
+ int* ibuf = reinterpret_cast<int*>(buf);
+ return FdSet { ibuf[0], ibuf[1], ibuf[2] };
+ }
+};
+
+// This message is sent over the fd associated with the transport when we are listening for fds.
+static constexpr char kListenStartMessage[] = "dt_fd_forward:START-LISTEN";
+
+// This message is sent over the fd associated with the transport when we stop listening for fds.
+static constexpr char kListenEndMessage[] = "dt_fd_forward:END-LISTEN";
+
+// This message is sent over the fd associated with the transport when we have accepted a
+// connection. This is sent before any handshaking has occurred. It is simply an acknowledgment
+// that the FdSet has been received. This will be paired with a single CLOSING message when these
+// fds are closed.
+static constexpr char kAcceptMessage[] = "dt_fd_forward:ACCEPTED";
+
+// This message is sent over the fd associated with the transport when we are closing the fds. This
+// can be used by the proxy to send additional data on a dup'd fd. The write_lock_fd_ will be held
+// until the other two fds are closed and then it will be released and closed.
+static constexpr char kCloseMessage[] = "dt_fd_forward:CLOSING";
+
+} // namespace dt_fd_forward
+
+#endif // ART_DT_FD_FORWARD_EXPORT_FD_TRANSPORT_H_
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index 05fce96780..8aa638a0e0 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -1150,10 +1150,10 @@ class ImgDiagDumper {
bool found_boot_map = false;
// Find the memory map only for boot.art
- for (const backtrace_map_t& map : *tmp_proc_maps) {
- if (EndsWith(map.name, GetImageLocationBaseName())) {
- if ((map.flags & PROT_WRITE) != 0) {
- boot_map_ = map;
+ for (const backtrace_map_t* map : *tmp_proc_maps) {
+ if (EndsWith(map->name, GetImageLocationBaseName())) {
+ if ((map->flags & PROT_WRITE) != 0) {
+ boot_map_ = *map;
found_boot_map = true;
break;
}
diff --git a/oatdump/Android.mk b/oatdump/Android.mk
index 906404b18c..667c37c33d 100644
--- a/oatdump/Android.mk
+++ b/oatdump/Android.mk
@@ -41,7 +41,7 @@ endif
.PHONY: dump-oat-core-target-$(TARGET_ARCH)
ifeq ($(ART_BUILD_TARGET),true)
-dump-oat-core-target-$(TARGET_ARCH): $(TARGET_CORE_IMAGE_default_$(ART_PHONY_TEST_TARGET_SUFFIX)) $(OATDUMP)
+dump-oat-core-target-$(TARGET_ARCH): $(TARGET_CORE_IMAGE_DEFAULT_$(ART_PHONY_TEST_TARGET_SUFFIX)) $(OATDUMP)
$(OATDUMP) --image=$(TARGET_CORE_IMG_LOCATION) \
--output=$(ART_DUMP_OAT_PATH)/core.target.$(TARGET_ARCH).oatdump.txt --instruction-set=$(TARGET_ARCH)
@echo Output in $(ART_DUMP_OAT_PATH)/core.target.$(TARGET_ARCH).oatdump.txt
@@ -50,7 +50,7 @@ endif
ifdef TARGET_2ND_ARCH
.PHONY: dump-oat-core-target-$(TARGET_2ND_ARCH)
ifeq ($(ART_BUILD_TARGET),true)
-dump-oat-core-target-$(TARGET_2ND_ARCH): $(TARGET_CORE_IMAGE_default_$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)) $(OATDUMP)
+dump-oat-core-target-$(TARGET_2ND_ARCH): $(TARGET_CORE_IMAGE_DEFAULT_$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)) $(OATDUMP)
$(OATDUMP) --image=$(TARGET_CORE_IMG_LOCATION) \
--output=$(ART_DUMP_OAT_PATH)/core.target.$(TARGET_2ND_ARCH).oatdump.txt --instruction-set=$(TARGET_2ND_ARCH)
@echo Output in $(ART_DUMP_OAT_PATH)/core.target.$(TARGET_2ND_ARCH).oatdump.txt
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 2c15087612..6a99c5ab2f 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -37,12 +37,12 @@
#include "base/unix_file/fd_file.h"
#include "class_linker-inl.h"
#include "class_linker.h"
-#include "code_item_accessors-inl.h"
#include "compiled_method.h"
#include "debug/elf_debug_writer.h"
#include "debug/method_debug_info.h"
-#include "dex_file-inl.h"
-#include "dex_instruction-inl.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_instruction-inl.h"
#include "disassembler.h"
#include "gc/accounting/space_bitmap-inl.h"
#include "gc/space/image_space.h"
@@ -146,13 +146,10 @@ class OatSymbolizer FINAL {
auto* rodata = builder_->GetRoData();
auto* text = builder_->GetText();
- auto* bss = builder_->GetBss();
const uint8_t* rodata_begin = oat_file_->Begin();
const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
- if (no_bits_) {
- rodata->WriteNoBitsSection(rodata_size);
- } else {
+ if (!no_bits_) {
rodata->Start();
rodata->WriteFully(rodata_begin, rodata_size);
rodata->End();
@@ -160,18 +157,12 @@ class OatSymbolizer FINAL {
const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
const size_t text_size = oat_file_->End() - text_begin;
- if (no_bits_) {
- text->WriteNoBitsSection(text_size);
- } else {
+ if (!no_bits_) {
text->Start();
text->WriteFully(text_begin, text_size);
text->End();
}
- if (oat_file_->BssSize() != 0) {
- bss->WriteNoBitsSection(oat_file_->BssSize());
- }
-
if (isa == InstructionSet::kMips || isa == InstructionSet::kMips64) {
builder_->WriteMIPSabiflagsSection();
}
@@ -1270,8 +1261,7 @@ class OatDumper {
bool* addr_found) {
bool success = true;
- CodeItemDataAccessor code_item_accessor(CodeItemDataAccessor::CreateNullable(&dex_file,
- code_item));
+ CodeItemDataAccessor code_item_accessor(&dex_file, code_item);
// TODO: Support regex
std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
@@ -2269,7 +2259,7 @@ class ImageDumper {
os << StringPrintf("null %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str());
} else {
// Grab the field type without causing resolution.
- ObjPtr<mirror::Class> field_type = field->LookupType();
+ ObjPtr<mirror::Class> field_type = field->LookupResolvedType();
if (field_type != nullptr) {
PrettyObjectValue(os, field_type, value);
} else {
@@ -2385,10 +2375,10 @@ class ImageDumper {
PrettyObjectValue(os, value_class, value);
}
} else if (obj->IsClass()) {
- mirror::Class* klass = obj->AsClass();
+ ObjPtr<mirror::Class> klass = obj->AsClass();
os << "SUBTYPE_CHECK_BITS: ";
- SubtypeCheck<mirror::Class*>::Dump(klass, os);
+ SubtypeCheck<ObjPtr<mirror::Class>>::Dump(klass, os);
os << "\n";
if (klass->NumStaticFields() != 0) {
diff --git a/openjdkjvm/OpenjdkJvm.cc b/openjdkjvm/OpenjdkJvm.cc
index 29ebefddea..3c87fe2303 100644
--- a/openjdkjvm/OpenjdkJvm.cc
+++ b/openjdkjvm/OpenjdkJvm.cc
@@ -40,9 +40,10 @@
#include <sys/time.h>
#include <unistd.h>
+#include <android-base/logging.h>
+
#include "../../libcore/ojluni/src/main/native/jvm.h" // TODO(narayan): fix it
-#include "base/logging.h"
#include "base/macros.h"
#include "common_throws.h"
#include "gc/heap.h"
@@ -321,8 +322,7 @@ JNIEXPORT __attribute__((noreturn)) void JVM_Exit(jint status) {
JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,
jstring javaFilename,
- jobject javaLoader,
- jstring javaLibrarySearchPath) {
+ jobject javaLoader) {
ScopedUtfChars filename(env, javaFilename);
if (filename.c_str() == NULL) {
return NULL;
@@ -334,7 +334,6 @@ JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,
bool success = vm->LoadNativeLibrary(env,
filename.c_str(),
javaLoader,
- javaLibrarySearchPath,
&error_msg);
if (success) {
return nullptr;
@@ -386,7 +385,7 @@ JNIEXPORT void JVM_Interrupt(JNIEnv* env, jobject jthread) {
JNIEXPORT jboolean JVM_IsInterrupted(JNIEnv* env, jobject jthread, jboolean clearInterrupted) {
if (clearInterrupted) {
- return static_cast<art::JNIEnvExt*>(env)->self->Interrupted() ? JNI_TRUE : JNI_FALSE;
+ return static_cast<art::JNIEnvExt*>(env)->GetSelf()->Interrupted() ? JNI_TRUE : JNI_FALSE;
} else {
art::ScopedFastNativeObjectAccess soa(env);
art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index 62f723dec1..aae805569f 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -33,12 +33,14 @@
#include <type_traits>
#include <vector>
+#include <android-base/logging.h>
+
#include <jni.h>
#include "jvmti.h"
#include "art_jvmti.h"
-#include "base/logging.h"
+#include "base/logging.h" // For gLogVerbosity.
#include "base/mutex.h"
#include "events-inl.h"
#include "jni_env_ext-inl.h"
@@ -1437,6 +1439,7 @@ class JvmtiFunctions {
art::gLogVerbosity.third_party_jni = val;
art::gLogVerbosity.threads = val;
art::gLogVerbosity.verifier = val;
+ // Do not set verifier-debug.
art::gLogVerbosity.image = val;
// Note: can't switch systrace_lock_logging. That requires changing entrypoints.
diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h
index e8e62c2b40..2a8c2e91df 100644
--- a/openjdkjvmti/art_jvmti.h
+++ b/openjdkjvmti/art_jvmti.h
@@ -39,9 +39,10 @@
#include <jni.h>
+#include <android-base/logging.h>
+
#include "deopt_manager.h"
#include "base/casts.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/strlcpy.h"
#include "base/mutex.h"
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc
index f843054681..aced769cb5 100644
--- a/openjdkjvmti/deopt_manager.cc
+++ b/openjdkjvmti/deopt_manager.cc
@@ -37,7 +37,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "base/mutex-inl.h"
-#include "dex_file_annotations.h"
+#include "dex/dex_file_annotations.h"
#include "events-inl.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index 05f9125df9..d98fda5f9c 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -36,9 +36,8 @@
#include "art_field-inl.h"
#include "art_jvmti.h"
#include "art_method-inl.h"
-#include "base/logging.h"
#include "deopt_manager.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "gc/allocation_listener.h"
#include "gc/gc_pause_listener.h"
#include "gc/heap.h"
@@ -139,7 +138,9 @@ EventMask* EventMasks::GetEventMaskOrNull(art::Thread* thread) {
}
-void EventMasks::EnableEvent(art::Thread* thread, ArtJvmtiEvent event) {
+void EventMasks::EnableEvent(ArtJvmTiEnv* env, art::Thread* thread, ArtJvmtiEvent event) {
+ DCHECK_EQ(&env->event_masks, this);
+ env->event_info_mutex_.AssertExclusiveHeld(art::Thread::Current());
DCHECK(EventMask::EventIsInRange(event));
GetEventMask(thread).Set(event);
if (thread != nullptr) {
@@ -147,7 +148,9 @@ void EventMasks::EnableEvent(art::Thread* thread, ArtJvmtiEvent event) {
}
}
-void EventMasks::DisableEvent(art::Thread* thread, ArtJvmtiEvent event) {
+void EventMasks::DisableEvent(ArtJvmTiEnv* env, art::Thread* thread, ArtJvmtiEvent event) {
+ DCHECK_EQ(&env->event_masks, this);
+ env->event_info_mutex_.AssertExclusiveHeld(art::Thread::Current());
DCHECK(EventMask::EventIsInRange(event));
GetEventMask(thread).Set(event, false);
if (thread != nullptr) {
@@ -1134,20 +1137,28 @@ jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env,
return ERR(MUST_POSSESS_CAPABILITY);
}
- bool old_state = global_mask.Test(event);
+ bool old_state;
+ bool new_state;
- if (mode == JVMTI_ENABLE) {
- env->event_masks.EnableEvent(thread, event);
- global_mask.Set(event);
- } else {
- DCHECK_EQ(mode, JVMTI_DISABLE);
+ {
+ // Change the event masks atomically.
+ art::Thread* self = art::Thread::Current();
+ art::MutexLock mu(self, envs_lock_);
+ art::WriterMutexLock mu_env_info(self, env->event_info_mutex_);
+ old_state = global_mask.Test(event);
+ if (mode == JVMTI_ENABLE) {
+ env->event_masks.EnableEvent(env, thread, event);
+ global_mask.Set(event);
+ new_state = true;
+ } else {
+ DCHECK_EQ(mode, JVMTI_DISABLE);
- env->event_masks.DisableEvent(thread, event);
- RecalculateGlobalEventMask(event);
+ env->event_masks.DisableEvent(env, thread, event);
+ RecalculateGlobalEventMaskLocked(event);
+ new_state = global_mask.Test(event);
+ }
}
- bool new_state = global_mask.Test(event);
-
// Handle any special work required for the event type.
if (new_state != old_state) {
HandleEventType(event, mode == JVMTI_ENABLE);
diff --git a/openjdkjvmti/events.h b/openjdkjvmti/events.h
index b05136661b..81edb931cd 100644
--- a/openjdkjvmti/events.h
+++ b/openjdkjvmti/events.h
@@ -20,7 +20,10 @@
#include <bitset>
#include <vector>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/macros.h"
+#include "base/mutex.h"
#include "jvmti.h"
#include "thread.h"
@@ -149,8 +152,16 @@ struct EventMasks {
EventMask& GetEventMask(art::Thread* thread);
EventMask* GetEventMaskOrNull(art::Thread* thread);
- void EnableEvent(art::Thread* thread, ArtJvmtiEvent event);
- void DisableEvent(art::Thread* thread, ArtJvmtiEvent event);
+ // Circular dependencies mean we cannot see the definition of ArtJvmTiEnv so the mutex is simply
+ // asserted in the function.
+ // Note that the 'env' passed in must be the same env this EventMasks is associated with.
+ void EnableEvent(ArtJvmTiEnv* env, art::Thread* thread, ArtJvmtiEvent event);
+ // REQUIRES(env->event_info_mutex_);
+ // Circular dependencies mean we cannot see the definition of ArtJvmTiEnv so the mutex is simply
+ // asserted in the function.
+ // Note that the 'env' passed in must be the same env this EventMasks is associated with.
+ void DisableEvent(ArtJvmTiEnv* env, art::Thread* thread, ArtJvmtiEvent event);
+ // REQUIRES(env->event_info_mutex_);
bool IsEnabledAnywhere(ArtJvmtiEvent event);
// Make any changes to event masks needed for the given capability changes. If caps_added is true
// then caps is all the newly set capabilities of the jvmtiEnv. If it is false then caps is the
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index 64dc3a5f02..ad928d9b37 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -30,8 +30,8 @@
*/
#include "fixed_up_dex_file.h"
-#include "dex_file_loader.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_loader.h"
// Runtime includes.
#include "dex_to_dex_decompiler.h"
diff --git a/openjdkjvmti/fixed_up_dex_file.h b/openjdkjvmti/fixed_up_dex_file.h
index 4cb39cfe93..b8f349cf8c 100644
--- a/openjdkjvmti/fixed_up_dex_file.h
+++ b/openjdkjvmti/fixed_up_dex_file.h
@@ -39,7 +39,7 @@
#include "jvmti.h"
#include "base/mutex.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
namespace openjdkjvmti {
diff --git a/openjdkjvmti/jvmti_allocator.h b/openjdkjvmti/jvmti_allocator.h
index 11af7b67e7..bd4c85bd7c 100644
--- a/openjdkjvmti/jvmti_allocator.h
+++ b/openjdkjvmti/jvmti_allocator.h
@@ -32,8 +32,9 @@
#ifndef ART_OPENJDKJVMTI_JVMTI_ALLOCATOR_H_
#define ART_OPENJDKJVMTI_JVMTI_ALLOCATOR_H_
-#include "base/logging.h"
-#include "base/macros.h"
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
#include "jvmti.h"
#include "ti_allocator.h"
diff --git a/openjdkjvmti/jvmti_weak_table-inl.h b/openjdkjvmti/jvmti_weak_table-inl.h
index 5d20946070..699004298e 100644
--- a/openjdkjvmti/jvmti_weak_table-inl.h
+++ b/openjdkjvmti/jvmti_weak_table-inl.h
@@ -36,8 +36,9 @@
#include <limits>
+#include <android-base/logging.h>
+
#include "art_jvmti.h"
-#include "base/logging.h"
#include "gc/allocation_listener.h"
#include "instrumentation.h"
#include "jni_env_ext-inl.h"
diff --git a/openjdkjvmti/ti_breakpoint.cc b/openjdkjvmti/ti_breakpoint.cc
index 8e5b56e9bf..fa7a34401d 100644
--- a/openjdkjvmti/ti_breakpoint.cc
+++ b/openjdkjvmti/ti_breakpoint.cc
@@ -38,7 +38,7 @@
#include "base/enums.h"
#include "base/mutex-inl.h"
#include "deopt_manager.h"
-#include "dex_file_annotations.h"
+#include "dex/dex_file_annotations.h"
#include "events-inl.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
@@ -98,7 +98,7 @@ jvmtiError BreakpointUtil::SetBreakpoint(jvmtiEnv* jenv, jmethodID method, jloca
art::ScopedObjectAccess soa(art::Thread::Current());
art::ArtMethod* art_method = art::jni::DecodeArtMethod(method)->GetCanonicalMethod();
if (location < 0 || static_cast<uint32_t>(location) >=
- art_method->GetCodeItem()->insns_size_in_code_units_) {
+ art_method->DexInstructions().InsnsSizeInCodeUnits()) {
return ERR(INVALID_LOCATION);
}
DeoptManager::Get()->AddMethodBreakpoint(art_method);
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index e69c78bab1..f9eb008af2 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -42,8 +42,8 @@
#include "class_linker.h"
#include "class_table-inl.h"
#include "common_throws.h"
-#include "dex_file_annotations.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file_annotations.h"
+#include "dex/dex_file_loader.h"
#include "events-inl.h"
#include "fixed_up_dex_file.h"
#include "gc/heap-visit-objects-inl.h"
@@ -490,7 +490,7 @@ struct ClassCallback : public art::ClassLoadCallback {
// Fix up the local table with a root visitor.
RootUpdater local_update(local->input_, local->output_);
- t->GetJniEnv()->locals.VisitRoots(
+ t->GetJniEnv()->VisitJniLocalRoots(
&local_update, art::RootInfo(art::kRootJNILocal, t->GetThreadId()));
}
diff --git a/openjdkjvmti/ti_class_definition.cc b/openjdkjvmti/ti_class_definition.cc
index c73ef0d31c..6560570136 100644
--- a/openjdkjvmti/ti_class_definition.cc
+++ b/openjdkjvmti/ti_class_definition.cc
@@ -33,7 +33,7 @@
#include "base/array_slice.h"
#include "class_linker-inl.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "fixed_up_dex_file.h"
#include "handle.h"
#include "handle_scope-inl.h"
diff --git a/openjdkjvmti/ti_class_loader.cc b/openjdkjvmti/ti_class_loader.cc
index b551b55e18..d594d6ee29 100644
--- a/openjdkjvmti/ti_class_loader.cc
+++ b/openjdkjvmti/ti_class_loader.cc
@@ -33,13 +33,13 @@
#include <limits>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "art_field-inl.h"
#include "art_jvmti.h"
-#include "base/logging.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
#include "events-inl.h"
#include "gc/allocation_listener.h"
#include "gc/heap.h"
diff --git a/openjdkjvmti/ti_class_loader.h b/openjdkjvmti/ti_class_loader.h
index 767e258a77..27ea3f5191 100644
--- a/openjdkjvmti/ti_class_loader.h
+++ b/openjdkjvmti/ti_class_loader.h
@@ -40,7 +40,7 @@
#include "art_method.h"
#include "base/array_slice.h"
#include "class_linker.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "gc_root-inl.h"
#include "globals.h"
#include "jni_env_ext-inl.h"
diff --git a/openjdkjvmti/ti_ddms.cc b/openjdkjvmti/ti_ddms.cc
index 500a453f78..0b4906d798 100644
--- a/openjdkjvmti/ti_ddms.cc
+++ b/openjdkjvmti/ti_ddms.cc
@@ -49,14 +49,16 @@ jvmtiError DDMSUtil::HandleChunk(jvmtiEnv* env,
/*out*/jint* type_out,
/*out*/jint* data_length_out,
/*out*/jbyte** data_out) {
- constexpr uint32_t kDdmHeaderSize = sizeof(uint32_t) * 2;
- if (env == nullptr || data_in == nullptr || data_out == nullptr || data_length_out == nullptr) {
+ if (env == nullptr || type_out == nullptr || data_out == nullptr || data_length_out == nullptr) {
return ERR(NULL_POINTER);
- } else if (length_in < static_cast<jint>(kDdmHeaderSize)) {
- // need to get type and length at least.
+ } else if (data_in == nullptr && length_in != 0) {
+ // Data-in shouldn't be null if we have data.
return ERR(ILLEGAL_ARGUMENT);
}
+ *data_length_out = 0;
+ *data_out = nullptr;
+
art::Thread* self = art::Thread::Current();
art::ScopedThreadStateChange(self, art::ThreadState::kNative);
@@ -71,13 +73,15 @@ jvmtiError DDMSUtil::HandleChunk(jvmtiEnv* env,
return ERR(INTERNAL);
} else {
jvmtiError error = OK;
- JvmtiUniquePtr<jbyte[]> ret = AllocJvmtiUniquePtr<jbyte[]>(env, out_data.size(), &error);
- if (error != OK) {
- return error;
+ if (!out_data.empty()) {
+ JvmtiUniquePtr<jbyte[]> ret = AllocJvmtiUniquePtr<jbyte[]>(env, out_data.size(), &error);
+ if (error != OK) {
+ return error;
+ }
+ memcpy(ret.get(), out_data.data(), out_data.size());
+ *data_out = ret.release();
+ *data_length_out = static_cast<jint>(out_data.size());
}
- memcpy(ret.get(), out_data.data(), out_data.size());
- *data_out = ret.release();
- *data_length_out = static_cast<jint>(out_data.size());
return OK;
}
}
diff --git a/openjdkjvmti/ti_extension.cc b/openjdkjvmti/ti_extension.cc
index afd0723d0f..79a8cd6304 100644
--- a/openjdkjvmti/ti_extension.cc
+++ b/openjdkjvmti/ti_extension.cc
@@ -216,7 +216,7 @@ jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
{
{ "type_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
{ "length_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
- { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, false },
+ { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, true },
{ "type_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
{ "data_len_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
{ "data_out", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_JBYTE, false }
diff --git a/openjdkjvmti/ti_field.cc b/openjdkjvmti/ti_field.cc
index b8691837eb..db5c31c43d 100644
--- a/openjdkjvmti/ti_field.cc
+++ b/openjdkjvmti/ti_field.cc
@@ -34,7 +34,7 @@
#include "art_field-inl.h"
#include "art_jvmti.h"
#include "base/enums.h"
-#include "dex_file_annotations.h"
+#include "dex/dex_file_annotations.h"
#include "jni_internal.h"
#include "mirror/object_array-inl.h"
#include "modifiers.h"
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 448ce41d0f..57fb699435 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -37,8 +37,9 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "base/mutex-inl.h"
-#include "dex_file_annotations.h"
-#include "dex_file_types.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file_annotations.h"
+#include "dex/dex_file_types.h"
#include "events-inl.h"
#include "jit/jit.h"
#include "jni_internal.h"
@@ -122,19 +123,19 @@ jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env,
}
art::ScopedObjectAccess soa(art::Thread::Current());
- const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
- if (code_item == nullptr) {
+ art::CodeItemInstructionAccessor accessor(art_method);
+ if (!accessor.HasCodeItem()) {
*size_ptr = 0;
*bytecode_ptr = nullptr;
return OK;
}
// 2 bytes per instruction for dex code.
- *size_ptr = code_item->insns_size_in_code_units_ * 2;
+ *size_ptr = accessor.InsnsSizeInCodeUnits() * 2;
jvmtiError err = env->Allocate(*size_ptr, bytecode_ptr);
if (err != OK) {
return err;
}
- memcpy(*bytecode_ptr, code_item->insns_, *size_ptr);
+ memcpy(*bytecode_ptr, accessor.Insns(), *size_ptr);
return OK;
}
@@ -167,7 +168,7 @@ jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
}
DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
- *size_ptr = art_method->GetCodeItem()->ins_size_;
+ *size_ptr = art::CodeItemDataAccessor(art_method).InsSize();
return ERR(NONE);
}
@@ -190,12 +191,17 @@ jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
}
art::ScopedObjectAccess soa(art::Thread::Current());
- const art::DexFile* dex_file = art_method->GetDexFile();
- const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
- // TODO code_item == nullptr means that the method is abstract (or native, but we check that
+
+ const art::DexFile* const dex_file = art_method->GetDexFile();
+ if (dex_file == nullptr) {
+ return ERR(ABSENT_INFORMATION);
+ }
+
+ // TODO HasCodeItem == false means that the method is abstract (or native, but we check that
// earlier). We should check what is returned by the RI in this situation since it's not clear
// what the appropriate return value is from the spec.
- if (dex_file == nullptr || code_item == nullptr) {
+ art::CodeItemDebugInfoAccessor accessor(art_method);
+ if (!accessor.HasCodeItem()) {
return ERR(ABSENT_INFORMATION);
}
@@ -260,13 +266,10 @@ jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
};
LocalVariableContext context(env);
- uint32_t debug_info_offset = art::OatFile::GetDebugInfoOffset(*dex_file, code_item);
- if (!dex_file->DecodeDebugLocalInfo(code_item,
- debug_info_offset,
- art_method->IsStatic(),
- art_method->GetDexMethodIndex(),
- LocalVariableContext::Callback,
- &context)) {
+ if (!accessor.DecodeDebugLocalInfo(art_method->IsStatic(),
+ art_method->GetDexMethodIndex(),
+ LocalVariableContext::Callback,
+ &context)) {
// Something went wrong with decoding the debug information. It might as well not be there.
return ERR(ABSENT_INFORMATION);
} else {
@@ -298,7 +301,7 @@ jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
}
DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
- *max_ptr = art_method->GetCodeItem()->registers_size_;
+ *max_ptr = art::CodeItemDataAccessor(art_method).RegistersSize();
return ERR(NONE);
}
@@ -413,7 +416,7 @@ jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
*start_location_ptr = 0;
- *end_location_ptr = art_method->GetCodeItem()->insns_size_in_code_units_ - 1;
+ *end_location_ptr = art_method->DexInstructions().InsnsSizeInCodeUnits() - 1;
return ERR(NONE);
}
@@ -462,7 +465,7 @@ jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
DCHECK(!art_method->IsRuntimeMethod());
- const art::DexFile::CodeItem* code_item;
+ art::CodeItemDebugInfoAccessor accessor;
const art::DexFile* dex_file;
{
art::ScopedObjectAccess soa(art::Thread::Current());
@@ -477,15 +480,14 @@ jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
return ERR(NULL_POINTER);
}
- code_item = art_method->GetCodeItem();
+ accessor = art::CodeItemDebugInfoAccessor(art_method);
dex_file = art_method->GetDexFile();
- DCHECK(code_item != nullptr) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
+ DCHECK(accessor.HasCodeItem()) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
}
LineNumberContext context;
- uint32_t debug_info_offset = art::OatFile::GetDebugInfoOffset(*dex_file, code_item);
bool success = dex_file->DecodeDebugPositionInfo(
- code_item, debug_info_offset, CollectLineNumbers, &context);
+ accessor.DebugInfoOffset(), CollectLineNumbers, &context);
if (!success) {
return ERR(ABSENT_INFORMATION);
}
@@ -565,7 +567,7 @@ class CommonLocalVariableClosure : public art::Closure {
// TODO It might be useful to fake up support for get at least on proxy frames.
result_ = ERR(OPAQUE_FRAME);
return;
- } else if (method->GetCodeItem()->registers_size_ <= slot_) {
+ } else if (art::CodeItemDataAccessor(method).RegistersSize() <= slot_) {
result_ = ERR(INVALID_SLOT);
return;
}
@@ -613,8 +615,11 @@ class CommonLocalVariableClosure : public art::Closure {
/*out*/art::Primitive::Type* type)
REQUIRES(art::Locks::mutator_lock_) {
const art::DexFile* dex_file = method->GetDexFile();
- const art::DexFile::CodeItem* code_item = method->GetCodeItem();
- if (dex_file == nullptr || code_item == nullptr) {
+ if (dex_file == nullptr) {
+ return ERR(OPAQUE_FRAME);
+ }
+ art::CodeItemDebugInfoAccessor accessor(method);
+ if (!accessor.HasCodeItem()) {
return ERR(OPAQUE_FRAME);
}
@@ -653,9 +658,10 @@ class CommonLocalVariableClosure : public art::Closure {
};
GetLocalVariableInfoContext context(slot_, dex_pc, descriptor, type);
- uint32_t debug_info_offset = art::OatFile::GetDebugInfoOffset(*dex_file, code_item);
- if (!dex_file->DecodeDebugLocalInfo(code_item,
- debug_info_offset,
+ if (!dex_file->DecodeDebugLocalInfo(accessor.RegistersSize(),
+ accessor.InsSize(),
+ accessor.InsnsSizeInCodeUnits(),
+ accessor.DebugInfoOffset(),
method->IsStatic(),
method->GetDexMethodIndex(),
GetLocalVariableInfoContext::Callback,
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc
index 7db0566a2e..94408ba186 100644
--- a/openjdkjvmti/ti_monitor.cc
+++ b/openjdkjvmti/ti_monitor.cc
@@ -169,6 +169,7 @@ class JvmtiMonitor {
}
size_t old_count = count_;
+ DCHECK_GT(old_count, 0u);
count_ = 0;
owner_.store(nullptr, std::memory_order_relaxed);
@@ -176,12 +177,19 @@ class JvmtiMonitor {
{
std::unique_lock<std::mutex> lk(mutex_, std::adopt_lock);
how_to_wait(lk);
- lk.release(); // Do not unlock the mutex.
+ // Here we release the mutex. We will get it back below. We first need to do a suspend-check
+ // without holding it however. This is done in the MonitorEnter function.
+ // TODO We could do this more efficiently.
+ // We hold the mutex_ but the overall monitor is not owned at this point.
+ CHECK(owner_.load(std::memory_order_relaxed) == nullptr);
+ DCHECK_EQ(0u, count_);
}
- DCHECK(owner_.load(std::memory_order_relaxed) == nullptr);
- owner_.store(self, std::memory_order_relaxed);
- DCHECK_EQ(0u, count_);
+ // Reaquire the mutex/monitor, also go to sleep if we were suspended.
+ MonitorEnter(self);
+ CHECK(owner_.load(std::memory_order_relaxed) == self);
+ DCHECK_EQ(1u, count_);
+ // Reset the count.
count_ = old_count;
return true;
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index 5b125f6990..6194d1e42c 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -33,19 +33,19 @@
#include <limits>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "art_field-inl.h"
#include "art_jvmti.h"
#include "art_method-inl.h"
#include "base/array_ref.h"
-#include "base/logging.h"
#include "base/stringpiece.h"
#include "class_linker-inl.h"
#include "debugger.h"
-#include "dex_file.h"
-#include "dex_file_loader.h"
-#include "dex_file_types.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_loader.h"
+#include "dex/dex_file_types.h"
#include "events-inl.h"
#include "gc/allocation_listener.h"
#include "gc/heap.h"
diff --git a/openjdkjvmti/ti_redefine.h b/openjdkjvmti/ti_redefine.h
index 528563bd07..b537e1b01c 100644
--- a/openjdkjvmti/ti_redefine.h
+++ b/openjdkjvmti/ti_redefine.h
@@ -40,7 +40,7 @@
#include "art_method.h"
#include "base/array_ref.h"
#include "class_linker.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "gc_root-inl.h"
#include "globals.h"
#include "jni_env_ext-inl.h"
diff --git a/openjdkjvmti/ti_search.cc b/openjdkjvmti/ti_search.cc
index fe12a25151..9d5f4ea3f9 100644
--- a/openjdkjvmti/ti_search.cc
+++ b/openjdkjvmti/ti_search.cc
@@ -38,8 +38,8 @@
#include "base/enums.h"
#include "base/macros.h"
#include "class_linker.h"
-#include "dex_file.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_loader.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object.h"
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index b43eaa0286..bc77753f8f 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -44,9 +44,10 @@
#include "base/bit_utils.h"
#include "base/enums.h"
#include "base/mutex.h"
-#include "dex_file.h"
-#include "dex_file_annotations.h"
-#include "dex_file_types.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_annotations.h"
+#include "dex/dex_file_types.h"
#include "gc_root.h"
#include "handle_scope-inl.h"
#include "jni_env_ext.h"
@@ -891,7 +892,7 @@ struct MonitorInfoClosure : public art::Closure {
visitor.WalkStack(/* include_transitions */ false);
// Find any other monitors, including ones acquired in native code.
art::RootInfo root_info(art::kRootVMInternal);
- target->GetJniEnv()->monitors.VisitRoots(&visitor, root_info);
+ target->GetJniEnv()->VisitMonitorRoots(&visitor, root_info);
err_ = handle_results_(soa_, visitor);
}
@@ -1044,7 +1045,7 @@ jvmtiError StackUtil::NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth)
if (shadow_frame == nullptr) {
needs_instrument = true;
const size_t frame_id = visitor.GetFrameId();
- const uint16_t num_regs = method->GetCodeItem()->registers_size_;
+ const uint16_t num_regs = art::CodeItemDataAccessor(method).RegistersSize();
shadow_frame = target->FindOrCreateDebuggerShadowFrame(frame_id,
num_regs,
method,
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index b7b81ce358..555c5a725b 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -31,10 +31,11 @@
#include "ti_thread.h"
-#include "android-base/strings.h"
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
#include "art_field-inl.h"
#include "art_jvmti.h"
-#include "base/logging.h"
#include "base/mutex.h"
#include "events-inl.h"
#include "gc/system_weak.h"
diff --git a/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc
index 1d7f137f2b..3a5fcccf35 100644
--- a/openjdkjvmti/transform.cc
+++ b/openjdkjvmti/transform.cc
@@ -37,8 +37,8 @@
#include "art_method.h"
#include "base/array_ref.h"
#include "class_linker.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
#include "events-inl.h"
#include "gc_root-inl.h"
#include "globals.h"
diff --git a/patchoat/Android.bp b/patchoat/Android.bp
index d3bc2a754b..0902823644 100644
--- a/patchoat/Android.bp
+++ b/patchoat/Android.bp
@@ -47,3 +47,16 @@ art_cc_binary {
"libartd",
],
}
+
+art_cc_test {
+ name: "art_patchoat_tests",
+ defaults: [
+ "art_gtest_defaults",
+ ],
+ srcs: [
+ "patchoat_test.cc",
+ ],
+ shared_libs: [
+ "libartd",
+ ],
+}
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index ae82d72c0f..eb648cba18 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -30,6 +30,7 @@
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/dumpable.h"
+#include "base/logging.h" // For InitLogging.
#include "base/memory_tool.h"
#include "base/scoped_flock.h"
#include "base/stringpiece.h"
diff --git a/patchoat/patchoat_test.cc b/patchoat/patchoat_test.cc
new file mode 100644
index 0000000000..86e851c72b
--- /dev/null
+++ b/patchoat/patchoat_test.cc
@@ -0,0 +1,411 @@
+/*
+ * 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 <dirent.h>
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+
+#include "android-base/stringprintf.h"
+#include "android-base/strings.h"
+
+#include "dexopt_test.h"
+#include "runtime.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+using android::base::StringPrintf;
+
+class PatchoatTest : public DexoptTest {
+ public:
+ static bool ListDirFilesEndingWith(
+ const std::string& dir,
+ const std::string& suffix,
+ std::vector<std::string>* filenames,
+ std::string* error_msg) {
+ DIR* d = opendir(dir.c_str());
+ if (d == nullptr) {
+ *error_msg = "Failed to open directory";
+ return false;
+ }
+ dirent* e;
+ struct stat s;
+ size_t suffix_len = suffix.size();
+ while ((e = readdir(d)) != nullptr) {
+ if ((strcmp(e->d_name, ".") == 0) || (strcmp(e->d_name, "..") == 0)) {
+ continue;
+ }
+ size_t name_len = strlen(e->d_name);
+ if ((name_len < suffix_len) || (strcmp(&e->d_name[name_len - suffix_len], suffix.c_str()))) {
+ continue;
+ }
+ std::string basename(e->d_name);
+ std::string filename = dir + "/" + basename;
+ int stat_result = lstat(filename.c_str(), &s);
+ if (stat_result != 0) {
+ *error_msg =
+ StringPrintf("Failed to stat %s: stat returned %d", filename.c_str(), stat_result);
+ return false;
+ }
+ if (S_ISDIR(s.st_mode)) {
+ continue;
+ }
+ filenames->push_back(basename);
+ }
+ closedir(d);
+ return true;
+ }
+
+ static void AddRuntimeArg(std::vector<std::string>& args, const std::string& arg) {
+ args.push_back("--runtime-arg");
+ args.push_back(arg);
+ }
+
+ bool CompileBootImage(const std::vector<std::string>& extra_args,
+ const std::string& image_file_name_prefix,
+ uint32_t base_addr,
+ std::string* error_msg) {
+ Runtime* const runtime = Runtime::Current();
+ std::vector<std::string> argv;
+ argv.push_back(runtime->GetCompilerExecutable());
+ AddRuntimeArg(argv, "-Xms64m");
+ AddRuntimeArg(argv, "-Xmx64m");
+ std::vector<std::string> dex_files = GetLibCoreDexFileNames();
+ for (const std::string& dex_file : dex_files) {
+ argv.push_back("--dex-file=" + dex_file);
+ argv.push_back("--dex-location=" + dex_file);
+ }
+ if (runtime->IsJavaDebuggable()) {
+ argv.push_back("--debuggable");
+ }
+ runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
+
+ AddRuntimeArg(argv, "-Xverify:softfail");
+
+ if (!kIsTargetBuild) {
+ argv.push_back("--host");
+ }
+
+ argv.push_back("--image=" + image_file_name_prefix + ".art");
+ argv.push_back("--oat-file=" + image_file_name_prefix + ".oat");
+ argv.push_back("--oat-location=" + image_file_name_prefix + ".oat");
+ argv.push_back(StringPrintf("--base=0x%" PRIx32, base_addr));
+ argv.push_back("--compile-pic");
+ argv.push_back("--multi-image");
+ argv.push_back("--no-generate-debug-info");
+
+ std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
+ argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
+
+ // We must set --android-root.
+ const char* android_root = getenv("ANDROID_ROOT");
+ CHECK(android_root != nullptr);
+ argv.push_back("--android-root=" + std::string(android_root));
+ argv.insert(argv.end(), extra_args.begin(), extra_args.end());
+
+ return RunDex2OatOrPatchoat(argv, error_msg);
+ }
+
+ bool RelocateBootImage(const std::string& input_image_location,
+ const std::string& output_image_filename,
+ off_t base_offset_delta,
+ std::string* error_msg) {
+ Runtime* const runtime = Runtime::Current();
+ std::vector<std::string> argv;
+ argv.push_back(runtime->GetPatchoatExecutable());
+ argv.push_back("--input-image-location=" + input_image_location);
+ argv.push_back("--output-image-file=" + output_image_filename);
+ argv.push_back(StringPrintf("--base-offset-delta=0x%jx", (intmax_t) base_offset_delta));
+ argv.push_back(StringPrintf("--instruction-set=%s", GetInstructionSetString(kRuntimeISA)));
+
+ return RunDex2OatOrPatchoat(argv, error_msg);
+ }
+
+ bool RunDex2OatOrPatchoat(const std::vector<std::string>& args, std::string* error_msg) {
+ int link[2];
+
+ if (pipe(link) == -1) {
+ return false;
+ }
+
+ pid_t pid = fork();
+ if (pid == -1) {
+ return false;
+ }
+
+ if (pid == 0) {
+ // We need dex2oat to actually log things.
+ setenv("ANDROID_LOG_TAGS", "*:e", 1);
+ dup2(link[1], STDERR_FILENO);
+ close(link[0]);
+ close(link[1]);
+ std::vector<const char*> c_args;
+ for (const std::string& str : args) {
+ c_args.push_back(str.c_str());
+ }
+ c_args.push_back(nullptr);
+ execv(c_args[0], const_cast<char* const*>(c_args.data()));
+ exit(1);
+ UNREACHABLE();
+ } else {
+ close(link[1]);
+ char buffer[128];
+ memset(buffer, 0, 128);
+ ssize_t bytes_read = 0;
+
+ while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) {
+ *error_msg += std::string(buffer, bytes_read);
+ }
+ close(link[0]);
+ int status = -1;
+ if (waitpid(pid, &status, 0) != -1) {
+ return (status == 0);
+ }
+ return false;
+ }
+ }
+
+ bool CompileBootImageToDir(
+ const std::string& output_dir,
+ const std::vector<std::string>& dex2oat_extra_args,
+ uint32_t base_addr,
+ std::string* error_msg) {
+ return CompileBootImage(dex2oat_extra_args, output_dir + "/boot", base_addr, error_msg);
+ }
+
+ bool CopyImageChecksumAndSetPatchDelta(
+ const std::string& src_image_filename,
+ const std::string& dest_image_filename,
+ off_t dest_patch_delta,
+ std::string* error_msg) {
+ std::unique_ptr<File> src_file(OS::OpenFileForReading(src_image_filename.c_str()));
+ if (src_file.get() == nullptr) {
+ *error_msg = StringPrintf("Failed to open source image file %s", src_image_filename.c_str());
+ return false;
+ }
+ ImageHeader src_header;
+ if (!src_file->ReadFully(&src_header, sizeof(src_header))) {
+ *error_msg = StringPrintf("Failed to read source image file %s", src_image_filename.c_str());
+ return false;
+ }
+
+ std::unique_ptr<File> dest_file(OS::OpenFileReadWrite(dest_image_filename.c_str()));
+ if (dest_file.get() == nullptr) {
+ *error_msg =
+ StringPrintf("Failed to open destination image file %s", dest_image_filename.c_str());
+ return false;
+ }
+ ImageHeader dest_header;
+ if (!dest_file->ReadFully(&dest_header, sizeof(dest_header))) {
+ *error_msg =
+ StringPrintf("Failed to read destination image file %s", dest_image_filename.c_str());
+ return false;
+ }
+ dest_header.SetOatChecksum(src_header.GetOatChecksum());
+ dest_header.SetPatchDelta(dest_patch_delta);
+ if (!dest_file->ResetOffset()) {
+ *error_msg =
+ StringPrintf(
+ "Failed to seek to start of destination image file %s", dest_image_filename.c_str());
+ return false;
+ }
+ if (!dest_file->WriteFully(&dest_header, sizeof(dest_header))) {
+ *error_msg =
+ StringPrintf("Failed to write to destination image file %s", dest_image_filename.c_str());
+ dest_file->Erase();
+ return false;
+ }
+ if (dest_file->FlushCloseOrErase() != 0) {
+ *error_msg =
+ StringPrintf(
+ "Failed to flush/close destination image file %s", dest_image_filename.c_str());
+ return false;
+ }
+
+ return true;
+ }
+
+ bool ReadFully(
+ const std::string& filename, std::vector<uint8_t>* contents, std::string* error_msg) {
+ std::unique_ptr<File> file(OS::OpenFileForReading(filename.c_str()));
+ if (file.get() == nullptr) {
+ *error_msg = "Failed to open";
+ return false;
+ }
+ int64_t size = file->GetLength();
+ if (size < 0) {
+ *error_msg = "Failed to get size";
+ return false;
+ }
+ contents->resize(size);
+ if (!file->ReadFully(&(*contents)[0], size)) {
+ *error_msg = "Failed to read";
+ contents->clear();
+ return false;
+ }
+ return true;
+ }
+
+ bool BinaryDiff(
+ const std::string& filename1, const std::string& filename2, std::string* error_msg) {
+ std::string read_error_msg;
+ std::vector<uint8_t> image1;
+ if (!ReadFully(filename1, &image1, &read_error_msg)) {
+ *error_msg = StringPrintf("Failed to read %s: %s", filename1.c_str(), read_error_msg.c_str());
+ return true;
+ }
+ std::vector<uint8_t> image2;
+ if (!ReadFully(filename2, &image2, &read_error_msg)) {
+ *error_msg = StringPrintf("Failed to read %s: %s", filename2.c_str(), read_error_msg.c_str());
+ return true;
+ }
+ if (image1.size() != image2.size()) {
+ *error_msg =
+ StringPrintf(
+ "%s and %s are of different size: %zu vs %zu",
+ filename1.c_str(),
+ filename2.c_str(),
+ image1.size(),
+ image2.size());
+ return true;
+ }
+ size_t size = image1.size();
+ for (size_t i = 0; i < size; i++) {
+ if (image1[i] != image2[i]) {
+ *error_msg =
+ StringPrintf("%s and %s differ at offset %zu", filename1.c_str(), filename2.c_str(), i);
+ return true;
+ }
+ }
+
+ return false;
+ }
+};
+
+TEST_F(PatchoatTest, PatchoatRelocationSameAsDex2oatRelocation) {
+#if defined(ART_USE_READ_BARRIER)
+ // This test checks that relocating a boot image using patchoat produces the same result as
+ // producing the boot image for that relocated base address using dex2oat. To be precise, these
+ // two files will have two small differences: the OAT checksum and base address. However, this
+ // test takes this into account.
+
+ // Compile boot image into a random directory using dex2oat
+ ScratchFile dex2oat_orig_scratch;
+ dex2oat_orig_scratch.Unlink();
+ std::string dex2oat_orig_dir = dex2oat_orig_scratch.GetFilename();
+ ASSERT_EQ(0, mkdir(dex2oat_orig_dir.c_str(), 0700));
+ const uint32_t orig_base_addr = 0x60000000;
+ // Force deterministic output. We want the boot images created by this dex2oat run and the run
+ // below to differ only in their base address.
+ std::vector<std::string> dex2oat_extra_args;
+ dex2oat_extra_args.push_back("--force-determinism");
+ dex2oat_extra_args.push_back("-j1"); // Might not be needed. Causes a 3-5x slowdown.
+ std::string error_msg;
+ if (!CompileBootImageToDir(dex2oat_orig_dir, dex2oat_extra_args, orig_base_addr, &error_msg)) {
+ FAIL() << "CompileBootImage1 failed: " << error_msg;
+ }
+
+ // Compile a "relocated" boot image into a random directory using dex2oat. This image is relocated
+ // in the sense that it uses a different base address.
+ ScratchFile dex2oat_reloc_scratch;
+ dex2oat_reloc_scratch.Unlink();
+ std::string dex2oat_reloc_dir = dex2oat_reloc_scratch.GetFilename();
+ ASSERT_EQ(0, mkdir(dex2oat_reloc_dir.c_str(), 0700));
+ const uint32_t reloc_base_addr = 0x70000000;
+ if (!CompileBootImageToDir(dex2oat_reloc_dir, dex2oat_extra_args, reloc_base_addr, &error_msg)) {
+ FAIL() << "CompileBootImage2 failed: " << error_msg;
+ }
+ const off_t base_addr_delta = reloc_base_addr - orig_base_addr;
+
+ // Relocate the original boot image using patchoat. The image is relocated by the same amount
+ // as the second/relocated image produced by dex2oat.
+ ScratchFile patchoat_scratch;
+ patchoat_scratch.Unlink();
+ std::string patchoat_dir = patchoat_scratch.GetFilename();
+ ASSERT_EQ(0, mkdir(patchoat_dir.c_str(), 0700));
+ std::string dex2oat_orig_with_arch_dir =
+ dex2oat_orig_dir + "/" + GetInstructionSetString(kRuntimeISA);
+ // The arch-including symlink is needed by patchoat
+ ASSERT_EQ(0, symlink(dex2oat_orig_dir.c_str(), dex2oat_orig_with_arch_dir.c_str()));
+ if (!RelocateBootImage(
+ dex2oat_orig_dir + "/boot.art",
+ patchoat_dir + "/boot.art",
+ base_addr_delta,
+ &error_msg)) {
+ FAIL() << "RelocateBootImage failed: " << error_msg;
+ }
+
+ // Assert that patchoat created the same set of .art files as dex2oat
+ std::vector<std::string> dex2oat_image_basenames;
+ std::vector<std::string> patchoat_image_basenames;
+ if (!ListDirFilesEndingWith(dex2oat_reloc_dir, ".art", &dex2oat_image_basenames, &error_msg)) {
+ FAIL() << "Failed to list *.art files in " << dex2oat_reloc_dir << ": " << error_msg;
+ }
+ if (!ListDirFilesEndingWith(patchoat_dir, ".art", &patchoat_image_basenames, &error_msg)) {
+ FAIL() << "Failed to list *.art files in " << patchoat_dir << ": " << error_msg;
+ }
+ std::sort(dex2oat_image_basenames.begin(), dex2oat_image_basenames.end());
+ std::sort(patchoat_image_basenames.begin(), patchoat_image_basenames.end());
+ // .art file names output by patchoat look like tmp@art-data-<random>-<random>@boot*.art. To
+ // compare these with .art file names output by dex2oat we retain only the part of the file name
+ // after the last @.
+ std::vector<std::string> patchoat_image_shortened_basenames(patchoat_image_basenames.size());
+ for (size_t i = 0; i < patchoat_image_basenames.size(); i++) {
+ patchoat_image_shortened_basenames[i] =
+ patchoat_image_basenames[i].substr(patchoat_image_basenames[i].find_last_of("@") + 1);
+ }
+ ASSERT_EQ(dex2oat_image_basenames, patchoat_image_shortened_basenames);
+
+ // Patch up the dex2oat-relocated image files so that it looks as though they were relocated by
+ // patchoat. patchoat preserves the OAT checksum header field and sets patch delta header field.
+ for (const std::string& image_basename : dex2oat_image_basenames) {
+ if (!CopyImageChecksumAndSetPatchDelta(
+ dex2oat_orig_dir + "/" + image_basename,
+ dex2oat_reloc_dir + "/" + image_basename,
+ base_addr_delta,
+ &error_msg)) {
+ FAIL() << "Unable to patch up " << image_basename << ": " << error_msg;
+ }
+ }
+
+ // Assert that the patchoat-relocated images are identical to the dex2oat-relocated images
+ for (size_t i = 0; i < dex2oat_image_basenames.size(); i++) {
+ const std::string& dex2oat_image_basename = dex2oat_image_basenames[i];
+ const std::string& dex2oat_image_filename = dex2oat_reloc_dir + "/" + dex2oat_image_basename;
+ const std::string& patchoat_image_filename = patchoat_dir + "/" + patchoat_image_basenames[i];
+ if (BinaryDiff(dex2oat_image_filename, patchoat_image_filename, &error_msg)) {
+ FAIL() << "patchoat- and dex2oat-relocated variants of " << dex2oat_image_basename
+ << " differ: " << error_msg;
+ }
+ }
+
+ ClearDirectory(dex2oat_orig_dir.c_str(), /*recursive*/ true);
+ ClearDirectory(dex2oat_reloc_dir.c_str(), /*recursive*/ true);
+ ClearDirectory(patchoat_dir.c_str(), /*recursive*/ true);
+ rmdir(dex2oat_orig_dir.c_str());
+ rmdir(dex2oat_reloc_dir.c_str());
+ rmdir(patchoat_dir.c_str());
+#else
+ LOG(INFO) << "Skipping PatchoatRelocationSameAsDex2oatRelocation";
+ // Force-print to std::cout so it's also outside the logcat.
+ std::cout << "Skipping PatchoatRelocationSameAsDex2oatRelocation" << std::endl;
+#endif
+}
+
+} // namespace art
diff --git a/profman/boot_image_profile.cc b/profman/boot_image_profile.cc
index 48b87c9a6d..a750105e72 100644
--- a/profman/boot_image_profile.cc
+++ b/profman/boot_image_profile.cc
@@ -18,7 +18,7 @@
#include <set>
#include "boot_image_profile.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "method_reference.h"
#include "type_reference.h"
diff --git a/profman/boot_image_profile.h b/profman/boot_image_profile.h
index d02e408cd5..eb43b7ca7f 100644
--- a/profman/boot_image_profile.h
+++ b/profman/boot_image_profile.h
@@ -21,7 +21,7 @@
#include <memory>
#include <vector>
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "jit/profile_compilation_info.h"
namespace art {
diff --git a/profman/profman.cc b/profman/profman.cc
index a5a5546323..71f7f9d669 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -32,15 +32,17 @@
#include "android-base/strings.h"
#include "base/dumpable.h"
+#include "base/logging.h" // For InitLogging.
#include "base/scoped_flock.h"
#include "base/stringpiece.h"
#include "base/time_utils.h"
#include "base/unix_file/fd_file.h"
#include "boot_image_profile.h"
#include "bytecode_utils.h"
-#include "dex_file.h"
-#include "dex_file_loader.h"
-#include "dex_file_types.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_loader.h"
+#include "dex/dex_file_types.h"
#include "jit/profile_compilation_info.h"
#include "profile_assistant.h"
#include "runtime.h"
@@ -725,7 +727,7 @@ class ProfMan FINAL {
const DexFile::CodeItem* code_item = dex_file->GetCodeItem(offset);
bool found_invoke = false;
- for (const DexInstructionPcPair& inst : code_item->Instructions()) {
+ for (const DexInstructionPcPair& inst : CodeItemInstructionAccessor(dex_file, code_item)) {
if (inst->Opcode() == Instruction::INVOKE_VIRTUAL) {
if (found_invoke) {
LOG(ERROR) << "Multiple invoke INVOKE_VIRTUAL found: "
diff --git a/runtime/Android.bp b/runtime/Android.bp
index a136ccb9d0..2657f4fa86 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -39,6 +39,7 @@ cc_defaults {
"base/hex_dump.cc",
"base/logging.cc",
"base/mutex.cc",
+ "base/runtime_debug.cc",
"base/safe_copy.cc",
"base/scoped_arena_allocator.cc",
"base/scoped_flock.cc",
@@ -47,7 +48,6 @@ cc_defaults {
"base/timing_logger.cc",
"base/unix_file/fd_file.cc",
"base/unix_file/random_access_file_utils.cc",
- "cdex/compact_dex_file.cc",
"cha.cc",
"check_jni.cc",
"class_linker.cc",
@@ -56,13 +56,16 @@ cc_defaults {
"common_throws.cc",
"compiler_filter.cc",
"debugger.cc",
- "dex_file.cc",
- "dex_file_loader.cc",
- "dex_file_annotations.cc",
- "dex_file_layout.cc",
- "dex_file_tracking_registrar.cc",
- "dex_file_verifier.cc",
- "dex_instruction.cc",
+ "dex/compact_dex_file.cc",
+ "dex/dex_file.cc",
+ "dex/dex_file_annotations.cc",
+ "dex/dex_file_exception_helpers.cc",
+ "dex/dex_file_layout.cc",
+ "dex/dex_file_loader.cc",
+ "dex/dex_file_tracking_registrar.cc",
+ "dex/dex_file_verifier.cc",
+ "dex/dex_instruction.cc",
+ "dex/standard_dex_file.cc",
"dex_to_dex_decompiler.cc",
"elf_file.cc",
"exec_utils.cc",
@@ -212,7 +215,6 @@ cc_defaults {
"signal_catcher.cc",
"stack.cc",
"stack_map.cc",
- "standard_dex_file.cc",
"thread.cc",
"thread_list.cc",
"thread_pool.cc",
@@ -452,10 +454,10 @@ gensrcs {
"debugger.h",
"base/unix_file/fd_file.h",
"class_status.h",
- "dex_file.h",
- "dex_file_layout.h",
- "dex_instruction.h",
- "dex_instruction_utils.h",
+ "dex/dex_file.h",
+ "dex/dex_file_layout.h",
+ "dex/dex_instruction.h",
+ "dex/dex_instruction_utils.h",
"gc_root.h",
"gc/allocator_type.h",
"gc/allocator/rosalloc.h",
@@ -469,6 +471,7 @@ gensrcs {
"instrumentation.h",
"indirect_reference_table.h",
"invoke_type.h",
+ "jdwp_provider.h",
"jdwp/jdwp.h",
"jdwp/jdwp_constants.h",
"lock_word.h",
@@ -563,16 +566,16 @@ art_cc_test {
"base/transform_iterator_test.cc",
"base/variant_map_test.cc",
"base/unix_file/fd_file_test.cc",
- "cdex/compact_dex_file_test.cc",
"cha_test.cc",
"class_linker_test.cc",
"class_loader_context_test.cc",
"class_table_test.cc",
- "code_item_accessors_test.cc",
"compiler_filter_test.cc",
- "dex_file_test.cc",
- "dex_file_verifier_test.cc",
- "dex_instruction_test.cc",
+ "dex/code_item_accessors_test.cc",
+ "dex/compact_dex_file_test.cc",
+ "dex/dex_file_test.cc",
+ "dex/dex_file_verifier_test.cc",
+ "dex/dex_instruction_test.cc",
"entrypoints/math_entrypoints_test.cc",
"entrypoints/quick/quick_trampoline_entrypoints_test.cc",
"entrypoints_order_test.cc",
@@ -601,6 +604,7 @@ art_cc_test {
"intern_table_test.cc",
"interpreter/safe_math_test.cc",
"interpreter/unstarted_runtime_test.cc",
+ "jdwp/jdwp_options_test.cc",
"java_vm_ext_test.cc",
"jit/profile_compilation_info_test.cc",
"leb128_test.cc",
diff --git a/runtime/aot_class_linker.cc b/runtime/aot_class_linker.cc
index a62cbec1be..93e02eff69 100644
--- a/runtime/aot_class_linker.cc
+++ b/runtime/aot_class_linker.cc
@@ -44,7 +44,7 @@ bool AotClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
// Don't initialize klass if it's superclass is not initialized, because superclass might abort
// the transaction and rolled back after klass's change is commited.
if (strict_mode_ && !klass->IsInterface() && klass->HasSuperClass()) {
- if (klass->GetSuperClass()->GetStatus() == mirror::Class::kStatusInitializing) {
+ if (klass->GetSuperClass()->GetStatus() == ClassStatus::kInitializing) {
runtime->AbortTransactionAndThrowAbortError(self, "Can't resolve "
+ klass->PrettyTypeOf() + " because it's superclass is not initialized.");
return false;
@@ -79,11 +79,11 @@ verifier::FailureKind AotClassLinker::PerformClassVerification(Thread* self,
ClassStatus old_status = callbacks->GetPreviousClassState(
ClassReference(&klass->GetDexFile(), klass->GetDexClassDefIndex()));
// Was it verified? Report no failure.
- if (old_status >= ClassStatus::kStatusVerified) {
+ if (old_status >= ClassStatus::kVerified) {
return verifier::FailureKind::kNoFailure;
}
// Does it need to be verified at runtime? Report soft failure.
- if (old_status >= ClassStatus::kStatusRetryVerificationAtRuntime) {
+ if (old_status >= ClassStatus::kRetryVerificationAtRuntime) {
// Error messages from here are only reported through -verbose:class. It is not worth it to
// create a message.
return verifier::FailureKind::kSoftFailure;
diff --git a/runtime/arch/arm/context_arm.h b/runtime/arch/arm/context_arm.h
index fa9aa46d4d..b9802967fe 100644
--- a/runtime/arch/arm/context_arm.h
+++ b/runtime/arch/arm/context_arm.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_ARCH_ARM_CONTEXT_ARM_H_
#define ART_RUNTIME_ARCH_ARM_CONTEXT_ARM_H_
+#include <android-base/logging.h>
+
#include "arch/context.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "registers_arm.h"
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index ef2b34236f..315bf957cc 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -21,7 +21,7 @@
#include "art_method.h"
#include "base/enums.h"
#include "base/hex_dump.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "globals.h"
#include "thread-current-inl.h"
diff --git a/runtime/arch/arm/instruction_set_features_arm.cc b/runtime/arch/arm/instruction_set_features_arm.cc
index b789fc7481..801254fd30 100644
--- a/runtime/arch/arm/instruction_set_features_arm.cc
+++ b/runtime/arch/arm/instruction_set_features_arm.cc
@@ -25,10 +25,9 @@
#include <fstream>
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
-
-#include "base/logging.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#if defined(__arm__)
extern "C" bool artCheckForArmSdivInstruction();
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 6ec9c48b92..c09baea72a 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1026,8 +1026,8 @@ ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitia
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
-// Note: Functions `art{Get,Set}<Kind>{Static,Instance>FromCompiledCode` are
-// defined by macros in runtime/entrypoints/quick/quick_field_entrypoints.cc.
+// Note: Functions `art{Get,Set}<Kind>{Static,Instance}FromCompiledCode` are
+// defined with a macro in runtime/entrypoints/quick/quick_field_entrypoints.cc.
/*
* Called by managed code to resolve a static field and load a non-wide value.
diff --git a/runtime/arch/arm/thread_arm.cc b/runtime/arch/arm/thread_arm.cc
index ff4f81be0f..18585c7973 100644
--- a/runtime/arch/arm/thread_arm.cc
+++ b/runtime/arch/arm/thread_arm.cc
@@ -16,9 +16,10 @@
#include "thread.h"
+#include <android-base/logging.h>
+
#include "asm_support_arm.h"
#include "base/enums.h"
-#include "base/logging.h"
namespace art {
diff --git a/runtime/arch/arm64/context_arm64.h b/runtime/arch/arm64/context_arm64.h
index 36aded07c4..e64cfb86ea 100644
--- a/runtime/arch/arm64/context_arm64.h
+++ b/runtime/arch/arm64/context_arm64.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_ARCH_ARM64_CONTEXT_ARM64_H_
#define ART_RUNTIME_ARCH_ARM64_CONTEXT_ARM64_H_
+#include <android-base/logging.h>
+
#include "arch/context.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "registers_arm64.h"
diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc
index d535c7e3c6..d282c8cfc0 100644
--- a/runtime/arch/arm64/fault_handler_arm64.cc
+++ b/runtime/arch/arm64/fault_handler_arm64.cc
@@ -21,7 +21,7 @@
#include "art_method.h"
#include "base/enums.h"
#include "base/hex_dump.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "globals.h"
#include "registers_arm64.h"
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.cc b/runtime/arch/arm64/instruction_set_features_arm64.cc
index d830ccffbb..9e9cb16008 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64.cc
+++ b/runtime/arch/arm64/instruction_set_features_arm64.cc
@@ -19,10 +19,10 @@
#include <fstream>
#include <sstream>
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
-#include "base/logging.h"
#include "base/stl_util.h"
namespace art {
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 47efeb9200..96a1cadab9 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1638,8 +1638,8 @@ ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitia
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
-// Note: Functions `art{Get,Set}<Kind>{Static,Instance>FromCompiledCode` are
-// defined by macros in runtime/entrypoints/quick/quick_field_entrypoints.cc.
+// Note: Functions `art{Get,Set}<Kind>{Static,Instance}FromCompiledCode` are
+// defined with a macro in runtime/entrypoints/quick/quick_field_entrypoints.cc.
ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCompiledCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCompiledCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
diff --git a/runtime/arch/arm64/thread_arm64.cc b/runtime/arch/arm64/thread_arm64.cc
index 3483b704ea..19c4a6ac85 100644
--- a/runtime/arch/arm64/thread_arm64.cc
+++ b/runtime/arch/arm64/thread_arm64.cc
@@ -16,9 +16,10 @@
#include "thread.h"
+#include <android-base/logging.h>
+
#include "asm_support_arm64.h"
#include "base/enums.h"
-#include "base/logging.h"
namespace art {
diff --git a/runtime/arch/code_offset.h b/runtime/arch/code_offset.h
index ab04b1eaa7..8e8dde4c4c 100644
--- a/runtime/arch/code_offset.h
+++ b/runtime/arch/code_offset.h
@@ -19,8 +19,10 @@
#include <iosfwd>
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
+#include "base/macros.h"
#include "instruction_set.h"
namespace art {
diff --git a/runtime/arch/instruction_set_features_test.cc b/runtime/arch/instruction_set_features_test.cc
index 67e2f358c8..1e3275cc00 100644
--- a/runtime/arch/instruction_set_features_test.cc
+++ b/runtime/arch/instruction_set_features_test.cc
@@ -19,12 +19,11 @@
#include <gtest/gtest.h>
#ifdef ART_TARGET_ANDROID
-#include "android-base/properties.h"
+#include <android-base/properties.h>
#endif
-#include "android-base/stringprintf.h"
-
-#include "base/logging.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
namespace art {
diff --git a/runtime/arch/mips/context_mips.h b/runtime/arch/mips/context_mips.h
index 7dcff630d1..7e073b288a 100644
--- a/runtime/arch/mips/context_mips.h
+++ b/runtime/arch/mips/context_mips.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_ARCH_MIPS_CONTEXT_MIPS_H_
#define ART_RUNTIME_ARCH_MIPS_CONTEXT_MIPS_H_
+#include <android-base/logging.h>
+
#include "arch/context.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "registers_mips.h"
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index dca3382664..209f36705a 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -18,6 +18,7 @@
#include "arch/mips/asm_support_mips.h"
#include "atomic.h"
+#include "base/logging.h"
#include "entrypoints/entrypoint_utils.h"
#include "entrypoints/jni/jni_entrypoints.h"
#include "entrypoints/math_entrypoints.h"
diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc
index 6dce54e5c5..f82dc08cb2 100644
--- a/runtime/arch/mips/fault_handler_mips.cc
+++ b/runtime/arch/mips/fault_handler_mips.cc
@@ -20,7 +20,7 @@
#include "art_method.h"
#include "base/callee_save_type.h"
#include "base/hex_dump.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "globals.h"
#include "quick_method_frame_info_mips.h"
diff --git a/runtime/arch/mips/instruction_set_features_mips.cc b/runtime/arch/mips/instruction_set_features_mips.cc
index 6d4145bc98..952ed250d2 100644
--- a/runtime/arch/mips/instruction_set_features_mips.cc
+++ b/runtime/arch/mips/instruction_set_features_mips.cc
@@ -19,10 +19,9 @@
#include <fstream>
#include <sstream>
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
-#include "base/logging.h"
#include "base/stl_util.h"
namespace art {
diff --git a/runtime/arch/mips/instruction_set_features_mips.h b/runtime/arch/mips/instruction_set_features_mips.h
index ee539edf3a..76bc639277 100644
--- a/runtime/arch/mips/instruction_set_features_mips.h
+++ b/runtime/arch/mips/instruction_set_features_mips.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
#define ART_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
+#include <android-base/logging.h>
+
#include "arch/instruction_set_features.h"
-#include "base/logging.h"
#include "base/macros.h"
namespace art {
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index fc77a641b3..b2f7e10f52 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -1637,6 +1637,9 @@ END \name
/*
* Called by managed code to resolve a static/instance field and load/store a value.
+ *
+ * Note: Functions `art{Get,Set}<Kind>{Static,Instance}FromCompiledCode` are
+ * defined with a macro in runtime/entrypoints/quick/quick_field_entrypoints.cc.
*/
ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
diff --git a/runtime/arch/mips/registers_mips.h b/runtime/arch/mips/registers_mips.h
index 57af150b33..c7f9a3e74e 100644
--- a/runtime/arch/mips/registers_mips.h
+++ b/runtime/arch/mips/registers_mips.h
@@ -19,7 +19,8 @@
#include <iosfwd>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/macros.h"
#include "globals.h"
@@ -100,7 +101,8 @@ enum FRegister {
F29 = 29,
F30 = 30,
F31 = 31,
- FTMP = F6, // scratch register
+ FTMP = F6, // scratch register
+ FTMP2 = F7, // scratch register (in addition to FTMP, reserved for MSA instructions)
kNumberOfFRegisters = 32,
kNoFRegister = -1,
};
diff --git a/runtime/arch/mips/thread_mips.cc b/runtime/arch/mips/thread_mips.cc
index 0a9ab7aacd..0be7a7f4cb 100644
--- a/runtime/arch/mips/thread_mips.cc
+++ b/runtime/arch/mips/thread_mips.cc
@@ -16,9 +16,10 @@
#include "thread.h"
+#include <android-base/logging.h>
+
#include "asm_support_mips.h"
#include "base/enums.h"
-#include "base/logging.h"
namespace art {
diff --git a/runtime/arch/mips64/context_mips64.h b/runtime/arch/mips64/context_mips64.h
index 89fbf8ffc3..b2a6138471 100644
--- a/runtime/arch/mips64/context_mips64.h
+++ b/runtime/arch/mips64/context_mips64.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_ARCH_MIPS64_CONTEXT_MIPS64_H_
#define ART_RUNTIME_ARCH_MIPS64_CONTEXT_MIPS64_H_
+#include <android-base/logging.h>
+
#include "arch/context.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "registers_mips64.h"
diff --git a/runtime/arch/mips64/fault_handler_mips64.cc b/runtime/arch/mips64/fault_handler_mips64.cc
index bdce520937..ba6fff05ad 100644
--- a/runtime/arch/mips64/fault_handler_mips64.cc
+++ b/runtime/arch/mips64/fault_handler_mips64.cc
@@ -21,7 +21,7 @@
#include "art_method.h"
#include "base/callee_save_type.h"
#include "base/hex_dump.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "globals.h"
#include "quick_method_frame_info_mips64.h"
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index 3fb83d9232..63f4f6cb8c 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -1565,6 +1565,9 @@ END \name
/*
* Called by managed code to resolve a static/instance field and load/store a value.
+ *
+ * Note: Functions `art{Get,Set}<Kind>{Static,Instance}FromCompiledCode` are
+ * defined with a macro in runtime/entrypoints/quick/quick_field_entrypoints.cc.
*/
ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
diff --git a/runtime/arch/mips64/registers_mips64.h b/runtime/arch/mips64/registers_mips64.h
index 30de2cc009..d3a24b6202 100644
--- a/runtime/arch/mips64/registers_mips64.h
+++ b/runtime/arch/mips64/registers_mips64.h
@@ -19,7 +19,8 @@
#include <iosfwd>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/macros.h"
#include "globals.h"
@@ -101,7 +102,8 @@ enum FpuRegister {
F29 = 29,
F30 = 30,
F31 = 31,
- FTMP = F8, // scratch register
+ FTMP = F8, // scratch register
+ FTMP2 = F9, // scratch register (in addition to FTMP, reserved for MSA instructions)
kNumberOfFpuRegisters = 32,
kNoFpuRegister = -1,
};
diff --git a/runtime/arch/mips64/thread_mips64.cc b/runtime/arch/mips64/thread_mips64.cc
index 3ce5e50d57..c1c390beeb 100644
--- a/runtime/arch/mips64/thread_mips64.cc
+++ b/runtime/arch/mips64/thread_mips64.cc
@@ -16,9 +16,10 @@
#include "thread.h"
+#include <android-base/logging.h>
+
#include "asm_support_mips64.h"
#include "base/enums.h"
-#include "base/logging.h"
namespace art {
diff --git a/runtime/arch/x86/context_x86.h b/runtime/arch/x86/context_x86.h
index 303dfe361c..0ebb22bd6d 100644
--- a/runtime/arch/x86/context_x86.h
+++ b/runtime/arch/x86/context_x86.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_ARCH_X86_CONTEXT_X86_H_
#define ART_RUNTIME_ARCH_X86_CONTEXT_X86_H_
+#include <android-base/logging.h>
+
#include "arch/context.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "registers_x86.h"
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index 527332fe9a..e6a91247cb 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -21,7 +21,7 @@
#include "art_method.h"
#include "base/enums.h"
#include "base/hex_dump.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "base/safe_copy.h"
#include "globals.h"
diff --git a/runtime/arch/x86/instruction_set_features_x86.cc b/runtime/arch/x86/instruction_set_features_x86.cc
index ea5a90d8ee..98462512da 100644
--- a/runtime/arch/x86/instruction_set_features_x86.cc
+++ b/runtime/arch/x86/instruction_set_features_x86.cc
@@ -19,11 +19,11 @@
#include <fstream>
#include <sstream>
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include "arch/x86_64/instruction_set_features_x86_64.h"
-#include "base/logging.h"
namespace art {
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index a46ceeba12..93cb6656dc 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1709,6 +1709,9 @@ DEFINE_FUNCTION art_quick_lushr
ret
END_FUNCTION art_quick_lushr
+// Note: Functions `art{Get,Set}<Kind>{Static,Instance}FromCompiledCode` are
+// defined with a macro in runtime/entrypoints/quick/quick_field_entrypoints.cc.
+
ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCompiledCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCompiledCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
ONE_ARG_REF_DOWNCALL art_quick_get_char_static, artGetCharStaticFromCompiledCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
diff --git a/runtime/arch/x86/registers_x86.h b/runtime/arch/x86/registers_x86.h
index 23027ed7d7..ded3520c76 100644
--- a/runtime/arch/x86/registers_x86.h
+++ b/runtime/arch/x86/registers_x86.h
@@ -19,7 +19,8 @@
#include <iosfwd>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/macros.h"
#include "globals.h"
diff --git a/runtime/arch/x86_64/context_x86_64.h b/runtime/arch/x86_64/context_x86_64.h
index f8e2845983..d242693f81 100644
--- a/runtime/arch/x86_64/context_x86_64.h
+++ b/runtime/arch/x86_64/context_x86_64.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_ARCH_X86_64_CONTEXT_X86_64_H_
#define ART_RUNTIME_ARCH_X86_64_CONTEXT_X86_64_H_
+#include <android-base/logging.h>
+
#include "arch/context.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "registers_x86_64.h"
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 463e5a279f..85f972309b 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1594,6 +1594,9 @@ UNIMPLEMENTED art_quick_lshl
UNIMPLEMENTED art_quick_lshr
UNIMPLEMENTED art_quick_lushr
+// Note: Functions `art{Get,Set}<Kind>{Static,Instance}FromCompiledCode` are
+// defined with a macro in runtime/entrypoints/quick/quick_field_entrypoints.cc.
+
THREE_ARG_REF_DOWNCALL art_quick_set8_instance, artSet8InstanceFromCompiledCode, RETURN_IF_EAX_ZERO
THREE_ARG_REF_DOWNCALL art_quick_set16_instance, artSet16InstanceFromCompiledCode, RETURN_IF_EAX_ZERO
THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCompiledCode, RETURN_IF_EAX_ZERO
diff --git a/runtime/arch/x86_64/registers_x86_64.h b/runtime/arch/x86_64/registers_x86_64.h
index dda1d5f569..4f2243170e 100644
--- a/runtime/arch/x86_64/registers_x86_64.h
+++ b/runtime/arch/x86_64/registers_x86_64.h
@@ -19,7 +19,8 @@
#include <iosfwd>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/macros.h"
#include "globals.h"
diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h
index 4a328e8d60..99634a067b 100644
--- a/runtime/art_field-inl.h
+++ b/runtime/art_field-inl.h
@@ -19,9 +19,10 @@
#include "art_field.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "class_linker.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "gc_root-inl.h"
#include "jvalue.h"
@@ -299,23 +300,17 @@ inline bool ArtField::IsPrimitiveType() REQUIRES_SHARED(Locks::mutator_lock_) {
return GetTypeAsPrimitiveType() != Primitive::kPrimNot;
}
-inline ObjPtr<mirror::Class> ArtField::LookupType() {
+inline ObjPtr<mirror::Class> ArtField::LookupResolvedType() {
ScopedAssertNoThreadSuspension ants(__FUNCTION__);
const uint32_t field_index = GetDexFieldIndex();
ObjPtr<mirror::Class> declaring_class = GetDeclaringClass();
if (UNLIKELY(declaring_class->IsProxyClass())) {
return ProxyFindSystemClass(GetTypeDescriptor());
}
- ObjPtr<mirror::DexCache> dex_cache = declaring_class->GetDexCache();
- const DexFile* const dex_file = dex_cache->GetDexFile();
- dex::TypeIndex type_idx = dex_file->GetFieldId(field_index).type_idx_;
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (UNLIKELY(type == nullptr)) {
- type = Runtime::Current()->GetClassLinker()->LookupResolvedType(
- *dex_file, type_idx, dex_cache, declaring_class->GetClassLoader());
- DCHECK(!Thread::Current()->IsExceptionPending());
- }
- return type.Ptr();
+ ObjPtr<mirror::Class> type = Runtime::Current()->GetClassLinker()->LookupResolvedType(
+ declaring_class->GetDexFile().GetFieldId(field_index).type_idx_, declaring_class);
+ DCHECK(!Thread::Current()->IsExceptionPending());
+ return type;
}
inline ObjPtr<mirror::Class> ArtField::ResolveType() {
@@ -324,15 +319,9 @@ inline ObjPtr<mirror::Class> ArtField::ResolveType() {
if (UNLIKELY(declaring_class->IsProxyClass())) {
return ProxyFindSystemClass(GetTypeDescriptor());
}
- auto* dex_cache = declaring_class->GetDexCache();
- const DexFile* const dex_file = dex_cache->GetDexFile();
- dex::TypeIndex type_idx = dex_file->GetFieldId(field_index).type_idx_;
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (UNLIKELY(type == nullptr)) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- type = class_linker->ResolveType(*dex_file, type_idx, declaring_class);
- DCHECK_EQ(type == nullptr, Thread::Current()->IsExceptionPending());
- }
+ ObjPtr<mirror::Class> type = Runtime::Current()->GetClassLinker()->ResolveType(
+ declaring_class->GetDexFile().GetFieldId(field_index).type_idx_, declaring_class);
+ DCHECK_EQ(type == nullptr, Thread::Current()->IsExceptionPending());
return type;
}
@@ -352,11 +341,10 @@ inline ObjPtr<mirror::String> ArtField::GetStringName(Thread* self, bool resolve
auto dex_field_index = GetDexFieldIndex();
CHECK_NE(dex_field_index, dex::kDexNoIndex);
ObjPtr<mirror::DexCache> dex_cache = GetDexCache();
- const auto* dex_file = dex_cache->GetDexFile();
- const auto& field_id = dex_file->GetFieldId(dex_field_index);
+ const DexFile::FieldId& field_id = dex_cache->GetDexFile()->GetFieldId(dex_field_index);
ObjPtr<mirror::String> name = dex_cache->GetResolvedString(field_id.name_idx_);
if (resolve && name == nullptr) {
- name = ResolveGetStringName(self, *dex_file, field_id.name_idx_, dex_cache);
+ name = ResolveGetStringName(self, field_id.name_idx_, dex_cache);
}
return name;
}
diff --git a/runtime/art_field.cc b/runtime/art_field.cc
index bc728f4476..dbba2b0918 100644
--- a/runtime/art_field.cc
+++ b/runtime/art_field.cc
@@ -45,17 +45,17 @@ void ArtField::SetOffset(MemberOffset num_bytes) {
ObjPtr<mirror::Class> ArtField::ProxyFindSystemClass(const char* descriptor) {
DCHECK(GetDeclaringClass()->IsProxyClass());
- return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), descriptor);
+ ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->LookupClass(
+ Thread::Current(), descriptor, /* class_loader */ nullptr);
+ DCHECK(klass != nullptr);
+ return klass;
}
ObjPtr<mirror::String> ArtField::ResolveGetStringName(Thread* self,
- const DexFile& dex_file,
dex::StringIndex string_idx,
ObjPtr<mirror::DexCache> dex_cache) {
StackHandleScope<1> hs(self);
- return Runtime::Current()->GetClassLinker()->ResolveString(dex_file,
- string_idx,
- hs.NewHandle(dex_cache));
+ return Runtime::Current()->GetClassLinker()->ResolveString(string_idx, hs.NewHandle(dex_cache));
}
std::string ArtField::PrettyField(ArtField* f, bool with_type) {
diff --git a/runtime/art_field.h b/runtime/art_field.h
index 866bf0bc70..46b013da7e 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -19,7 +19,7 @@
#include <jni.h>
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "gc_root.h"
#include "modifiers.h"
#include "obj_ptr.h"
@@ -205,7 +205,7 @@ class ArtField FINAL {
bool IsPrimitiveType() REQUIRES_SHARED(Locks::mutator_lock_);
- ObjPtr<mirror::Class> LookupType() REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<mirror::Class> LookupResolvedType() REQUIRES_SHARED(Locks::mutator_lock_);
ObjPtr<mirror::Class> ResolveType() REQUIRES_SHARED(Locks::mutator_lock_);
size_t FieldSize() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -234,7 +234,6 @@ class ArtField FINAL {
ObjPtr<mirror::Class> ProxyFindSystemClass(const char* descriptor)
REQUIRES_SHARED(Locks::mutator_lock_);
ObjPtr<mirror::String> ResolveGetStringName(Thread* self,
- const DexFile& dex_file,
dex::StringIndex string_idx,
ObjPtr<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 31abf94889..bdebe2d9e9 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -21,13 +21,12 @@
#include "art_field.h"
#include "base/callee_save_type.h"
-#include "base/logging.h"
#include "class_linker-inl.h"
-#include "code_item_accessors-inl.h"
#include "common_throws.h"
-#include "dex_file-inl.h"
-#include "dex_file_annotations.h"
-#include "dex_file_types.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_annotations.h"
+#include "dex/dex_file_types.h"
#include "gc_root-inl.h"
#include "invoke_type.h"
#include "jit/profiling_info.h"
@@ -81,9 +80,8 @@ inline bool ArtMethod::CASDeclaringClass(mirror::Class* expected_class,
mirror::Class* desired_class) {
GcRoot<mirror::Class> expected_root(expected_class);
GcRoot<mirror::Class> desired_root(desired_class);
- return reinterpret_cast<Atomic<GcRoot<mirror::Class>>*>(&declaring_class_)->
- CompareExchangeStrongSequentiallyConsistent(
- expected_root, desired_root);
+ auto atomic_root_class = reinterpret_cast<Atomic<GcRoot<mirror::Class>>*>(&declaring_class_);
+ return atomic_root_class->CompareAndSetStrongSequentiallyConsistent(expected_root, desired_root);
}
inline uint16_t ArtMethod::GetMethodIndex() {
@@ -107,23 +105,16 @@ inline uint32_t ArtMethod::GetDexMethodIndex() {
inline ObjPtr<mirror::Class> ArtMethod::LookupResolvedClassFromTypeIndex(dex::TypeIndex type_idx) {
ScopedAssertNoThreadSuspension ants(__FUNCTION__);
- ObjPtr<mirror::DexCache> dex_cache = GetDexCache();
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (UNLIKELY(type == nullptr)) {
- type = Runtime::Current()->GetClassLinker()->LookupResolvedType(
- *dex_cache->GetDexFile(), type_idx, dex_cache, GetClassLoader());
- }
- return type.Ptr();
+ ObjPtr<mirror::Class> type =
+ Runtime::Current()->GetClassLinker()->LookupResolvedType(type_idx, this);
+ DCHECK(!Thread::Current()->IsExceptionPending());
+ return type;
}
inline ObjPtr<mirror::Class> ArtMethod::ResolveClassFromTypeIndex(dex::TypeIndex type_idx) {
- ObjPtr<mirror::DexCache> dex_cache = GetDexCache();
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (UNLIKELY(type == nullptr)) {
- type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
- CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
- }
- return type.Ptr();
+ ObjPtr<mirror::Class> type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
+ DCHECK_EQ(type == nullptr, Thread::Current()->IsExceptionPending());
+ return type;
}
inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) {
@@ -306,9 +297,7 @@ inline const DexFile::ClassDef& ArtMethod::GetClassDef() {
inline const char* ArtMethod::GetReturnTypeDescriptor() {
DCHECK(!IsProxyMethod());
const DexFile* dex_file = GetDexFile();
- const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
- const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
- return dex_file->GetTypeDescriptor(dex_file->GetTypeId(proto_id.return_type_idx_));
+ return dex_file->GetTypeDescriptor(dex_file->GetTypeId(GetReturnTypeIndex()));
}
inline Primitive::Type ArtMethod::GetReturnTypePrimitive() {
@@ -469,16 +458,8 @@ inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor, PointerSize poi
}
}
-inline IterationRange<DexInstructionIterator> ArtMethod::DexInstructions() {
- CodeItemInstructionAccessor accessor(this);
- return { accessor.begin(),
- accessor.end() };
-}
-
-inline IterationRange<DexInstructionIterator> ArtMethod::NullableDexInstructions() {
- CodeItemInstructionAccessor accessor(CodeItemInstructionAccessor::CreateNullable(this));
- return { accessor.begin(),
- accessor.end() };
+inline CodeItemInstructionAccessor ArtMethod::DexInstructions() {
+ return CodeItemInstructionAccessor(this);
}
} // namespace art
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 43a51391b9..44a5dde485 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -25,8 +25,9 @@
#include "base/stringpiece.h"
#include "class_linker-inl.h"
#include "debugger.h"
-#include "dex_file-inl.h"
-#include "dex_instruction.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_exception_helpers.h"
+#include "dex/dex_instruction.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
#include "interpreter/interpreter.h"
@@ -134,15 +135,14 @@ uint16_t ArtMethod::FindObsoleteDexClassDefIndex() {
return dex_file->GetIndexForClassDef(*class_def);
}
-mirror::String* ArtMethod::GetNameAsString(Thread* self) {
+ObjPtr<mirror::String> ArtMethod::GetNameAsString(Thread* self) {
CHECK(!IsProxyMethod());
StackHandleScope<1> hs(self);
Handle<mirror::DexCache> dex_cache(hs.NewHandle(GetDexCache()));
auto* dex_file = dex_cache->GetDexFile();
uint32_t dex_method_idx = GetDexMethodIndex();
const DexFile::MethodId& method_id = dex_file->GetMethodId(dex_method_idx);
- return Runtime::Current()->GetClassLinker()->ResolveString(*dex_file, method_id.name_idx_,
- dex_cache);
+ return Runtime::Current()->GetClassLinker()->ResolveString(method_id.name_idx_, dex_cache);
}
void ArtMethod::ThrowInvocationTimeError() {
@@ -264,7 +264,6 @@ uint32_t ArtMethod::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfil
uint32_t ArtMethod::FindCatchBlock(Handle<mirror::Class> exception_type,
uint32_t dex_pc, bool* has_no_move_exception) {
- const DexFile::CodeItem* code_item = GetCodeItem();
// Set aside the exception while we resolve its type.
Thread* self = Thread::Current();
StackHandleScope<1> hs(self);
@@ -273,7 +272,8 @@ uint32_t ArtMethod::FindCatchBlock(Handle<mirror::Class> exception_type,
// Default to handler not found.
uint32_t found_dex_pc = dex::kDexNoIndex;
// Iterate over the catch handlers associated with dex_pc.
- for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) {
+ CodeItemDataAccessor accessor(this);
+ for (CatchHandlerIterator it(accessor, dex_pc); it.HasNext(); it.Next()) {
dex::TypeIndex iter_type_idx = it.GetHandlerTypeIndex();
// Catch all case
if (!iter_type_idx.IsValid()) {
@@ -298,9 +298,8 @@ uint32_t ArtMethod::FindCatchBlock(Handle<mirror::Class> exception_type,
}
}
if (found_dex_pc != dex::kDexNoIndex) {
- const Instruction* first_catch_instr =
- Instruction::At(&code_item->insns_[found_dex_pc]);
- *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION);
+ const Instruction& first_catch_instr = accessor.InstructionAt(found_dex_pc);
+ *has_no_move_exception = (first_catch_instr.Opcode() != Instruction::MOVE_EXCEPTION);
}
// Put the exception back.
if (exception != nullptr) {
@@ -550,8 +549,8 @@ bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> param
}
auto* cl = Runtime::Current()->GetClassLinker();
for (size_t i = 0; i < count; ++i) {
- auto type_idx = proto_params->GetTypeItem(i).type_idx_;
- auto* type = cl->ResolveType(type_idx, this);
+ dex::TypeIndex type_idx = proto_params->GetTypeItem(i).type_idx_;
+ ObjPtr<mirror::Class> type = cl->ResolveType(type_idx, this);
if (type == nullptr) {
Thread::Current()->AssertPendingException();
return false;
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 0a592e0528..c4a586ed92 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -19,13 +19,17 @@
#include <cstddef>
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
#include "base/casts.h"
#include "base/enums.h"
#include "base/iteration_range.h"
-#include "base/logging.h"
-#include "dex_file.h"
-#include "dex_instruction_iterator.h"
+#include "base/macros.h"
+#include "base/runtime_debug.h"
+#include "dex/code_item_accessors.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction_iterator.h"
#include "gc_root.h"
#include "modifiers.h"
#include "obj_ptr.h"
@@ -575,7 +579,7 @@ class ArtMethod FINAL {
ALWAYS_INLINE const char* GetName() REQUIRES_SHARED(Locks::mutator_lock_);
- mirror::String* GetNameAsString(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<mirror::String> GetNameAsString(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
const DexFile::CodeItem* GetCodeItem() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -713,13 +717,9 @@ class ArtMethod FINAL {
"ptr_sized_fields_.entry_point_from_quick_compiled_code_");
}
- // Returns the dex instructions of the code item for the art method. Must not be called on null
- // code items.
- ALWAYS_INLINE IterationRange<DexInstructionIterator> DexInstructions()
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- // Handles a null code item by returning iterators that have a null address.
- ALWAYS_INLINE IterationRange<DexInstructionIterator> NullableDexInstructions()
+ // Returns the dex instructions of the code item for the art method. Returns an empty array for
+ // the null code item case.
+ ALWAYS_INLINE CodeItemInstructionAccessor DexInstructions()
REQUIRES_SHARED(Locks::mutator_lock_);
protected:
diff --git a/runtime/atomic.h b/runtime/atomic.h
index d8621cc2e6..0e2f056d3a 100644
--- a/runtime/atomic.h
+++ b/runtime/atomic.h
@@ -22,8 +22,9 @@
#include <limits>
#include <vector>
+#include <android-base/logging.h>
+
#include "arch/instruction_set.h"
-#include "base/logging.h"
#include "base/macros.h"
namespace art {
@@ -216,70 +217,109 @@ class PACKED(sizeof(T)) Atomic : public std::atomic<T> {
}
// Store to memory without ordering or synchronization constraints.
- void StoreRelaxed(T desired) {
- this->store(desired, std::memory_order_relaxed);
+ void StoreRelaxed(T desired_value) {
+ this->store(desired_value, std::memory_order_relaxed);
}
// Word tearing allowed, but may race.
- void StoreJavaData(T desired) {
- this->store(desired, std::memory_order_relaxed);
+ void StoreJavaData(T desired_value) {
+ this->store(desired_value, std::memory_order_relaxed);
}
// Store to memory with release ordering.
- void StoreRelease(T desired) {
- this->store(desired, std::memory_order_release);
+ void StoreRelease(T desired_value) {
+ this->store(desired_value, std::memory_order_release);
}
// Store to memory with a total ordering.
- void StoreSequentiallyConsistent(T desired) {
- this->store(desired, std::memory_order_seq_cst);
+ void StoreSequentiallyConsistent(T desired_value) {
+ this->store(desired_value, std::memory_order_seq_cst);
}
- // Atomically replace the value with desired value.
+ // Atomically replace the value with desired_value.
T ExchangeRelaxed(T desired_value) {
return this->exchange(desired_value, std::memory_order_relaxed);
}
- // Atomically replace the value with desired value if it matches the expected value.
+ // Atomically replace the value with desired_value.
+ T ExchangeSequentiallyConsistent(T desired_value) {
+ return this->exchange(desired_value, std::memory_order_seq_cst);
+ }
+
+ // Atomically replace the value with desired_value.
+ T ExchangeAcquire(T desired_value) {
+ return this->exchange(desired_value, std::memory_order_acquire);
+ }
+
+ // Atomically replace the value with desired_value.
+ T ExchangeRelease(T desired_value) {
+ return this->exchange(desired_value, std::memory_order_release);
+ }
+
+ // Atomically replace the value with desired_value if it matches the expected_value.
+ // Participates in total ordering of atomic operations. Returns true on success, false otherwise.
+ // If the value does not match, updates the expected_value argument with the value that was
+ // atomically read for the failed comparison.
+ bool CompareAndExchangeStrongSequentiallyConsistent(T* expected_value, T desired_value) {
+ return this->compare_exchange_strong(*expected_value, desired_value, std::memory_order_seq_cst);
+ }
+
+ // Atomically replace the value with desired_value if it matches the expected_value.
+ // Participates in total ordering of atomic operations. Returns true on success, false otherwise.
+ // If the value does not match, updates the expected_value argument with the value that was
+ // atomically read for the failed comparison.
+ bool CompareAndExchangeStrongAcquire(T* expected_value, T desired_value) {
+ return this->compare_exchange_strong(*expected_value, desired_value, std::memory_order_acquire);
+ }
+
+ // Atomically replace the value with desired_value if it matches the expected_value.
+ // Participates in total ordering of atomic operations. Returns true on success, false otherwise.
+ // If the value does not match, updates the expected_value argument with the value that was
+ // atomically read for the failed comparison.
+ bool CompareAndExchangeStrongRelease(T* expected_value, T desired_value) {
+ return this->compare_exchange_strong(*expected_value, desired_value, std::memory_order_release);
+ }
+
+ // Atomically replace the value with desired_value if it matches the expected_value.
// Participates in total ordering of atomic operations.
- bool CompareExchangeStrongSequentiallyConsistent(T expected_value, T desired_value) {
+ bool CompareAndSetStrongSequentiallyConsistent(T expected_value, T desired_value) {
return this->compare_exchange_strong(expected_value, desired_value, std::memory_order_seq_cst);
}
// The same, except it may fail spuriously.
- bool CompareExchangeWeakSequentiallyConsistent(T expected_value, T desired_value) {
+ bool CompareAndSetWeakSequentiallyConsistent(T expected_value, T desired_value) {
return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_seq_cst);
}
- // Atomically replace the value with desired value if it matches the expected value. Doesn't
+ // Atomically replace the value with desired_value if it matches the expected_value. Doesn't
// imply ordering or synchronization constraints.
- bool CompareExchangeStrongRelaxed(T expected_value, T desired_value) {
+ bool CompareAndSetStrongRelaxed(T expected_value, T desired_value) {
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
+ // 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) {
+ bool CompareAndSetStrongRelease(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) {
+ bool CompareAndSetWeakRelaxed(T expected_value, T desired_value) {
return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_relaxed);
}
- // Atomically replace the value with desired value if it matches the expected value. Prior writes
+ // Atomically replace the value with desired_value if it matches the expected_value. Prior writes
// made to other memory locations by the thread that did the release become visible in this
// thread.
- bool CompareExchangeWeakAcquire(T expected_value, T desired_value) {
+ bool CompareAndSetWeakAcquire(T expected_value, T desired_value) {
return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_acquire);
}
- // Atomically replace the value with desired value if it matches the expected value. prior writes
+ // 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 CompareExchangeWeakRelease(T expected_value, T desired_value) {
+ bool CompareAndSetWeakRelease(T expected_value, T desired_value) {
return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_release);
}
@@ -291,6 +331,14 @@ class PACKED(sizeof(T)) Atomic : public std::atomic<T> {
return this->fetch_add(value, std::memory_order_relaxed); // Return old_value.
}
+ T FetchAndAddAcquire(const T value) {
+ return this->fetch_add(value, std::memory_order_acquire); // Return old_value.
+ }
+
+ T FetchAndAddRelease(const T value) {
+ return this->fetch_add(value, std::memory_order_acquire); // Return old_value.
+ }
+
T FetchAndSubSequentiallyConsistent(const T value) {
return this->fetch_sub(value, std::memory_order_seq_cst); // Return old value.
}
@@ -299,12 +347,40 @@ class PACKED(sizeof(T)) Atomic : public std::atomic<T> {
return this->fetch_sub(value, std::memory_order_relaxed); // Return old value.
}
- T FetchAndOrSequentiallyConsistent(const T value) {
+ T FetchAndBitwiseAndSequentiallyConsistent(const T value) {
+ return this->fetch_and(value, std::memory_order_seq_cst); // Return old_value.
+ }
+
+ T FetchAndBitwiseAndAcquire(const T value) {
+ return this->fetch_and(value, std::memory_order_acquire); // Return old_value.
+ }
+
+ T FetchAndBitwiseAndRelease(const T value) {
+ return this->fetch_and(value, std::memory_order_release); // Return old_value.
+ }
+
+ T FetchAndBitwiseOrSequentiallyConsistent(const T value) {
return this->fetch_or(value, std::memory_order_seq_cst); // Return old_value.
}
- T FetchAndAndSequentiallyConsistent(const T value) {
- return this->fetch_and(value, std::memory_order_seq_cst); // Return old_value.
+ T FetchAndBitwiseOrAcquire(const T value) {
+ return this->fetch_or(value, std::memory_order_acquire); // Return old_value.
+ }
+
+ T FetchAndBitwiseOrRelease(const T value) {
+ return this->fetch_or(value, std::memory_order_release); // Return old_value.
+ }
+
+ T FetchAndBitwiseXorSequentiallyConsistent(const T value) {
+ return this->fetch_xor(value, std::memory_order_seq_cst); // Return old_value.
+ }
+
+ T FetchAndBitwiseXorAcquire(const T value) {
+ return this->fetch_xor(value, std::memory_order_acquire); // Return old_value.
+ }
+
+ T FetchAndBitwiseXorRelease(const T value) {
+ return this->fetch_xor(value, std::memory_order_release); // Return old_value.
}
volatile T* Address() {
diff --git a/runtime/barrier.cc b/runtime/barrier.cc
index 9bcda35a9d..4329a5a245 100644
--- a/runtime/barrier.cc
+++ b/runtime/barrier.cc
@@ -16,7 +16,9 @@
#include "barrier.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/aborting.h"
#include "base/mutex.h"
#include "base/time_utils.h"
#include "thread.h"
diff --git a/runtime/base/aborting.h b/runtime/base/aborting.h
new file mode 100644
index 0000000000..8906c96ea7
--- /dev/null
+++ b/runtime/base/aborting.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_BASE_ABORTING_H_
+#define ART_RUNTIME_BASE_ABORTING_H_
+
+#include <atomic>
+
+namespace art {
+
+// 0 if not abort, non-zero if an abort is in progress. Used on fatal exit to prevents recursive
+// aborts. Global declaration allows us to disable some error checking to ensure fatal shutdown
+// makes forward progress.
+extern std::atomic<unsigned int> gAborting;
+
+} // namespace art
+
+#endif // ART_RUNTIME_BASE_ABORTING_H_
diff --git a/runtime/base/allocator.cc b/runtime/base/allocator.cc
index bb006389fa..2da88c3830 100644
--- a/runtime/base/allocator.cc
+++ b/runtime/base/allocator.cc
@@ -19,8 +19,9 @@
#include <inttypes.h>
#include <stdlib.h>
+#include <android-base/logging.h>
+
#include "atomic.h"
-#include "base/logging.h"
namespace art {
diff --git a/runtime/base/allocator.h b/runtime/base/allocator.h
index 99cdb49984..3cedb66abe 100644
--- a/runtime/base/allocator.h
+++ b/runtime/base/allocator.h
@@ -17,10 +17,11 @@
#ifndef ART_RUNTIME_BASE_ALLOCATOR_H_
#define ART_RUNTIME_BASE_ALLOCATOR_H_
+#include <type_traits>
+
#include "atomic.h"
#include "base/macros.h"
#include "base/mutex.h"
-#include "base/type_static_if.h"
namespace art {
@@ -147,9 +148,9 @@ class TrackingAllocatorImpl : public std::allocator<T> {
template<class T, AllocatorTag kTag>
// C++ doesn't allow template typedefs. This is a workaround template typedef which is
// TrackingAllocatorImpl<T> if kEnableTrackingAllocator is true, std::allocator<T> otherwise.
-using TrackingAllocator = typename TypeStaticIf<kEnableTrackingAllocator,
- TrackingAllocatorImpl<T, kTag>,
- std::allocator<T>>::type;
+using TrackingAllocator = typename std::conditional<kEnableTrackingAllocator,
+ TrackingAllocatorImpl<T, kTag>,
+ std::allocator<T>>::type;
} // namespace art
diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc
index 2e35f8ac4f..cc413c5ab9 100644
--- a/runtime/base/arena_allocator.cc
+++ b/runtime/base/arena_allocator.cc
@@ -23,7 +23,8 @@
#include <iomanip>
#include <numeric>
-#include "logging.h"
+#include <android-base/logging.h>
+
#include "mem_map.h"
#include "mutex.h"
#include "systrace.h"
diff --git a/runtime/base/arena_allocator.h b/runtime/base/arena_allocator.h
index a327cb0a8b..9e03658aef 100644
--- a/runtime/base/arena_allocator.h
+++ b/runtime/base/arena_allocator.h
@@ -20,11 +20,11 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/bit_utils.h"
-#include "base/dchecked_vector.h"
-#include "base/memory_tool.h"
+#include "bit_utils.h"
+#include "dchecked_vector.h"
#include "debug_stack.h"
#include "macros.h"
+#include "memory_tool.h"
#include "mutex.h"
namespace art {
diff --git a/runtime/base/arena_object.h b/runtime/base/arena_object.h
index ed00babd62..06884c23d4 100644
--- a/runtime/base/arena_object.h
+++ b/runtime/base/arena_object.h
@@ -17,8 +17,10 @@
#ifndef ART_RUNTIME_BASE_ARENA_OBJECT_H_
#define ART_RUNTIME_BASE_ARENA_OBJECT_H_
-#include "base/arena_allocator.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "arena_allocator.h"
+#include "macros.h"
#include "scoped_arena_allocator.h"
namespace art {
diff --git a/runtime/base/array_ref.h b/runtime/base/array_ref.h
index 630a036f3d..ef86512cf7 100644
--- a/runtime/base/array_ref.h
+++ b/runtime/base/array_ref.h
@@ -20,7 +20,7 @@
#include <type_traits>
#include <vector>
-#include "base/logging.h"
+#include <android-base/logging.h>
namespace art {
diff --git a/runtime/base/bit_field.h b/runtime/base/bit_field.h
index a80ca28d2e..86007d6a35 100644
--- a/runtime/base/bit_field.h
+++ b/runtime/base/bit_field.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_BASE_BIT_FIELD_H_
#define ART_RUNTIME_BASE_BIT_FIELD_H_
+#include <android-base/logging.h>
+
#include "globals.h"
-#include "logging.h"
namespace art {
diff --git a/runtime/base/bit_string.h b/runtime/base/bit_string.h
index a2164f335d..bfbe8eaf71 100644
--- a/runtime/base/bit_string.h
+++ b/runtime/base/bit_string.h
@@ -114,7 +114,7 @@ inline std::ostream& operator<<(std::ostream& os, const BitStringChar& bc) {
/**
* BitString
*
- * MSB LSB
+ * lsb (least significant bit) msb
* +------------+------------+------------+-----+------------+
* | | | | | |
* | Char0 | Char1 | Char2 | ... | CharN |
@@ -131,8 +131,9 @@ inline std::ostream& operator<<(std::ostream& os, const BitStringChar& bc) {
* "ABCDE...K" := [A,B,C,D,E, ... K] + [0]*(N-idx(K)) s.t. N >= K.
* // Padded with trailing 0s to fit (N+1) bitstring chars.
* MaxBitstringLen := N+1
- * StrLen(Bitstring) := MaxBitStringLen - | forall char in CharI..CharN : char == 0 AND Char(I-1) != 0 |
- * // Maximum length - the # of consecutive trailing zeroes.
+ * StrLen(Bitstring) := I s.t. (I == 0 OR Char(I-1) != 0)
+ * AND forall char in CharI..CharN : char == 0
+ * // = Maximum length - the # of consecutive trailing zeroes.
* Bitstring[N] := CharN
* Bitstring[I..N) := [CharI, CharI+1, ... CharN-1]
*
@@ -278,8 +279,8 @@ struct BitString {
private:
friend std::ostream& operator<<(std::ostream& os, const BitString& bit_string);
- // Data is stored with the "highest" position in the least-significant-bit.
- // As positions approach 0, the bits are stored with increasing significance.
+ // Data is stored with the first character in the least-significant-bit.
+ // Unused bits are zero.
StorageType storage_;
};
diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h
index 5d836545e9..34cddbff6a 100644
--- a/runtime/base/bit_utils.h
+++ b/runtime/base/bit_utils.h
@@ -20,7 +20,8 @@
#include <limits>
#include <type_traits>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/stl_util_identity.h"
namespace art {
diff --git a/runtime/base/bit_utils_iterator.h b/runtime/base/bit_utils_iterator.h
index 8514de6b75..2d3d0508cc 100644
--- a/runtime/base/bit_utils_iterator.h
+++ b/runtime/base/bit_utils_iterator.h
@@ -21,9 +21,10 @@
#include <limits>
#include <type_traits>
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
#include "base/iteration_range.h"
-#include "base/logging.h"
#include "base/stl_util.h"
namespace art {
diff --git a/runtime/base/bit_vector-inl.h b/runtime/base/bit_vector-inl.h
index 0e67f77e19..e67d4e25eb 100644
--- a/runtime/base/bit_vector-inl.h
+++ b/runtime/base/bit_vector-inl.h
@@ -17,9 +17,11 @@
#ifndef ART_RUNTIME_BASE_BIT_VECTOR_INL_H_
#define ART_RUNTIME_BASE_BIT_VECTOR_INL_H_
-#include "base/bit_utils.h"
#include "bit_vector.h"
-#include "logging.h"
+
+#include <android-base/logging.h>
+
+#include "base/bit_utils.h"
namespace art {
diff --git a/runtime/base/bounded_fifo.h b/runtime/base/bounded_fifo.h
index 7bcd382022..1520770fe6 100644
--- a/runtime/base/bounded_fifo.h
+++ b/runtime/base/bounded_fifo.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_BASE_BOUNDED_FIFO_H_
#define ART_RUNTIME_BASE_BOUNDED_FIFO_H_
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
namespace art {
diff --git a/runtime/base/casts.h b/runtime/base/casts.h
index 92c493ace7..3c6b2be355 100644
--- a/runtime/base/casts.h
+++ b/runtime/base/casts.h
@@ -24,8 +24,9 @@
#include <limits>
#include <type_traits>
-#include "base/logging.h"
-#include "base/macros.h"
+#include <android-base/logging.h>
+
+#include "stl_util_identity.h"
namespace art {
@@ -98,7 +99,7 @@ inline Dest bit_cast(const Source& source) {
// A version of static_cast that DCHECKs that the value can be precisely represented
// when converting to Dest.
template <typename Dest, typename Source>
-inline Dest dchecked_integral_cast(const Source source) {
+constexpr Dest dchecked_integral_cast(Source source) {
DCHECK(
// Check that the value is within the lower limit of Dest.
(static_cast<intmax_t>(std::numeric_limits<Dest>::min()) <=
@@ -114,6 +115,33 @@ inline Dest dchecked_integral_cast(const Source source) {
return static_cast<Dest>(source);
}
+// A version of dchecked_integral_cast casting between an integral type and an enum type.
+// When casting to an enum type, the cast does not check if the value corresponds to an enumerator.
+// When casting from an enum type, the target type can be omitted and the enum's underlying type
+// shall be used.
+
+template <typename Dest, typename Source>
+constexpr
+typename std::enable_if<!std::is_enum<Source>::value, Dest>::type
+enum_cast(Source value) {
+ return static_cast<Dest>(
+ dchecked_integral_cast<typename std::underlying_type<Dest>::type>(value));
+}
+
+template <typename Dest = void, typename Source>
+constexpr
+typename std::enable_if<std::is_enum<Source>::value,
+ typename std::conditional<std::is_same<Dest, void>::value,
+ std::underlying_type<Source>,
+ Identity<Dest>>::type>::type::type
+enum_cast(Source value) {
+ using return_type = typename std::conditional<std::is_same<Dest, void>::value,
+ std::underlying_type<Source>,
+ Identity<Dest>>::type::type;
+ return dchecked_integral_cast<return_type>(
+ static_cast<typename std::underlying_type<Source>::type>(value));
+}
+
// A version of reinterpret_cast<>() between pointers and int64_t/uint64_t
// that goes through uintptr_t to avoid treating the pointer as "signed."
diff --git a/runtime/base/dchecked_vector.h b/runtime/base/dchecked_vector.h
index 77f0ea2b7c..7236ac301a 100644
--- a/runtime/base/dchecked_vector.h
+++ b/runtime/base/dchecked_vector.h
@@ -21,7 +21,7 @@
#include <type_traits>
#include <vector>
-#include "base/logging.h"
+#include <android-base/logging.h>
namespace art {
diff --git a/runtime/base/debug_stack.h b/runtime/base/debug_stack.h
index 886065db30..1331e10a02 100644
--- a/runtime/base/debug_stack.h
+++ b/runtime/base/debug_stack.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_BASE_DEBUG_STACK_H_
#define ART_RUNTIME_BASE_DEBUG_STACK_H_
-#include "base/logging.h"
-#include "base/macros.h"
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
#include "globals.h"
namespace art {
diff --git a/runtime/base/file_magic.cc b/runtime/base/file_magic.cc
index dffb9b43a1..e668699a0b 100644
--- a/runtime/base/file_magic.cc
+++ b/runtime/base/file_magic.cc
@@ -20,11 +20,11 @@
#include <sys/stat.h>
#include <sys/types.h>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
-#include "base/logging.h"
#include "base/unix_file/fd_file.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
namespace art {
diff --git a/runtime/base/file_utils.cc b/runtime/base/file_utils.cc
index 323a06519d..63b4ac56d0 100644
--- a/runtime/base/file_utils.cc
+++ b/runtime/base/file_utils.cc
@@ -47,9 +47,9 @@
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
-#include "dex_instruction.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_loader.h"
+#include "dex/dex_instruction.h"
#include "oat_quick_method_header.h"
#include "os.h"
#include "scoped_thread_state_change-inl.h"
@@ -89,7 +89,7 @@ bool ReadFileToString(const std::string& file_name, std::string* result) {
}
}
-bool PrintFileToLog(const std::string& file_name, LogSeverity level) {
+bool PrintFileToLog(const std::string& file_name, android::base::LogSeverity level) {
File file(file_name, O_RDONLY, false);
if (!file.IsOpened()) {
return false;
diff --git a/runtime/base/file_utils.h b/runtime/base/file_utils.h
index 007f3b443d..e4555ad3cb 100644
--- a/runtime/base/file_utils.h
+++ b/runtime/base/file_utils.h
@@ -21,13 +21,14 @@
#include <string>
+#include <android-base/logging.h>
+
#include "arch/instruction_set.h"
-#include "base/logging.h"
namespace art {
bool ReadFileToString(const std::string& file_name, std::string* result);
-bool PrintFileToLog(const std::string& file_name, LogSeverity level);
+bool PrintFileToLog(const std::string& file_name, android::base::LogSeverity level);
// Find $ANDROID_ROOT, /system, or abort.
std::string GetAndroidRoot();
diff --git a/runtime/base/hash_set.h b/runtime/base/hash_set.h
index c743342a98..47e6d93346 100644
--- a/runtime/base/hash_set.h
+++ b/runtime/base/hash_set.h
@@ -25,8 +25,10 @@
#include <type_traits>
#include <utility>
+#include <android-base/logging.h>
+
#include "bit_utils.h"
-#include "logging.h"
+#include "macros.h"
namespace art {
diff --git a/runtime/base/histogram-inl.h b/runtime/base/histogram-inl.h
index be2092040d..3ce0140c84 100644
--- a/runtime/base/histogram-inl.h
+++ b/runtime/base/histogram-inl.h
@@ -24,6 +24,8 @@
#include "histogram.h"
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
#include "base/time_utils.h"
#include "utils.h"
diff --git a/runtime/base/histogram.h b/runtime/base/histogram.h
index e0c921e408..7544a9c918 100644
--- a/runtime/base/histogram.h
+++ b/runtime/base/histogram.h
@@ -19,7 +19,7 @@
#include <string>
#include <vector>
-#include "base/logging.h"
+#include <android-base/macros.h>
namespace art {
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index 4776357fdf..90eb74c75c 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -20,7 +20,8 @@
#include <limits>
#include <sstream>
-#include "base/mutex.h"
+#include "aborting.h"
+#include "mutex.h"
#include "thread-current-inl.h"
#include "utils.h"
@@ -34,55 +35,6 @@
namespace art {
-// We test here that the runtime-debug-checks are actually a no-op constexpr false in release
-// builds, as we can't check that in gtests (which are always debug).
-
-#ifdef NDEBUG
-namespace {
-DECLARE_RUNTIME_DEBUG_FLAG(kTestForConstexpr);
-static_assert(!kTestForConstexpr, "Issue with DECLARE_RUNTIME_DEBUG_FLAG in NDEBUG.");
-}
-#endif
-
-// Implementation of runtime debug flags. This should be compile-time optimized away in release
-// builds.
-namespace {
-bool gSlowEnabled = false; // Default for slow flags is "off."
-
-// Use a function with a static to ensure our vector storage doesn't have initialization order
-// issues.
-std::vector<bool*>& GetFlagPtrs() {
- static std::vector<bool*> g_flag_ptrs;
- return g_flag_ptrs;
-}
-
-bool RegisterRuntimeDebugFlagImpl(bool* flag_ptr) {
- GetFlagPtrs().push_back(flag_ptr);
- return gSlowEnabled;
-}
-
-void SetRuntimeDebugFlagsEnabledImpl(bool enabled) {
- gSlowEnabled = enabled;
- for (bool* flag_ptr : GetFlagPtrs()) {
- *flag_ptr = enabled;
- }
-}
-
-} // namespace
-
-bool RegisterRuntimeDebugFlag(bool* flag_ptr) {
- if (kIsDebugBuild) {
- return RegisterRuntimeDebugFlagImpl(flag_ptr);
- }
- return false;
-}
-
-void SetRuntimeDebugFlagsEnabled(bool enabled) {
- if (kIsDebugBuild) {
- SetRuntimeDebugFlagsEnabledImpl(enabled);
- }
-}
-
LogVerbosity gLogVerbosity;
std::atomic<unsigned int> gAborting(0);
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index 15f935395e..c562bdf59f 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -53,6 +53,7 @@ struct LogVerbosity {
bool third_party_jni; // Enabled with "-verbose:third-party-jni".
bool threads;
bool verifier;
+ bool verifier_debug; // Only works in debug builds.
bool image;
bool systrace_lock_logging; // Enabled with "-verbose:sys-locks".
bool agents;
@@ -62,48 +63,6 @@ struct LogVerbosity {
// Global log verbosity setting, initialized by InitLogging.
extern LogVerbosity gLogVerbosity;
-// Runtime debug flags are flags that have a runtime component, that is, their value can be changed.
-// This is meant to implement fast vs slow debug builds, in that certain debug flags can be turned
-// on and off. To that effect, expose two macros to help implement and globally drive these flags:
-//
-// In the header, declare a (class) flag like this:
-//
-// class C {
-// DECLARE_RUNTIME_DEBUG_FLAG(kFlag);
-// };
-//
-// This will declare a flag kFlag that is a constexpr false in release builds, and a static field
-// in debug builds. Usage is than uniform as C::kFlag.
-//
-// In the cc file, define the flag like this:
-//
-// DEFINE_RUNTIME_DEBUG_FLAG(C, kFlag);
-//
-// This will define the static storage, as necessary, and register the flag with the runtime
-// infrastructure to toggle the value.
-
-#ifdef NDEBUG
-#define DECLARE_RUNTIME_DEBUG_FLAG(x) \
- static constexpr bool x = false;
-// Note: the static_assert in the following only works for public flags. Fix this when we cross
-// the line at some point.
-#define DEFINE_RUNTIME_DEBUG_FLAG(C, x) \
- static_assert(!C::x, "Unexpected enabled flag in release build");
-#else
-#define DECLARE_RUNTIME_DEBUG_FLAG(x) \
- static bool x;
-#define DEFINE_RUNTIME_DEBUG_FLAG(C, x) \
- bool C::x = RegisterRuntimeDebugFlag(&C::x);
-#endif // NDEBUG
-
-bool RegisterRuntimeDebugFlag(bool* runtime_debug_flag);
-void SetRuntimeDebugFlagsEnabled(bool enabled);
-
-// 0 if not abort, non-zero if an abort is in progress. Used on fatal exit to prevents recursive
-// aborts. Global declaration allows us to disable some error checking to ensure fatal shutdown
-// makes forward progress.
-extern std::atomic<unsigned int> gAborting;
-
// Configure logging based on ANDROID_LOG_TAGS environment variable.
// We need to parse a string that looks like
//
diff --git a/runtime/base/logging_test.cc b/runtime/base/logging_test.cc
index d380b9eccc..404e080b03 100644
--- a/runtime/base/logging_test.cc
+++ b/runtime/base/logging_test.cc
@@ -22,6 +22,7 @@
#include "base/bit_utils.h"
#include "base/macros.h"
#include "common_runtime_test.h"
+#include "runtime_debug.h"
namespace art {
diff --git a/runtime/base/macros.h b/runtime/base/macros.h
index 6cd7d60253..512e5ce651 100644
--- a/runtime/base/macros.h
+++ b/runtime/base/macros.h
@@ -59,6 +59,10 @@ template<typename T> ART_FRIEND_TEST(test_set_name, individual_test)
#define QUOTE(x) #x
#define STRINGIFY(x) QUOTE(x)
+// Append tokens after evaluating.
+#define APPEND_TOKENS_AFTER_EVAL_2(a, b) a ## b
+#define APPEND_TOKENS_AFTER_EVAL(a, b) APPEND_TOKENS_AFTER_EVAL_2(a, b)
+
#ifndef NDEBUG
#define ALWAYS_INLINE
#else
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index 587b092ab7..01adbf17e2 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -164,7 +164,7 @@ inline void ReaderWriterMutex::SharedLock(Thread* self) {
int32_t cur_state = state_.LoadRelaxed();
if (LIKELY(cur_state >= 0)) {
// Add as an extra reader.
- done = state_.CompareExchangeWeakAcquire(cur_state, cur_state + 1);
+ done = state_.CompareAndSetWeakAcquire(cur_state, cur_state + 1);
} else {
HandleSharedLockContention(self, cur_state);
}
@@ -188,10 +188,10 @@ inline void ReaderWriterMutex::SharedUnlock(Thread* self) {
int32_t cur_state = state_.LoadRelaxed();
if (LIKELY(cur_state > 0)) {
// Reduce state by 1 and impose lock release load/store ordering.
- // Note, the relaxed loads below musn't reorder before the CompareExchange.
+ // Note, the relaxed loads below musn't reorder before the CompareAndSet.
// TODO: the ordering here is non-trivial as state is split across 3 fields, fix by placing
// a status bit into the state on contention.
- done = state_.CompareExchangeWeakSequentiallyConsistent(cur_state, cur_state - 1);
+ done = state_.CompareAndSetWeakSequentiallyConsistent(cur_state, cur_state - 1);
if (done && (cur_state - 1) == 0) { // Weak CAS may fail spuriously.
if (num_pending_writers_.LoadRelaxed() > 0 ||
num_pending_readers_.LoadRelaxed() > 0) {
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 3adebe7e00..9f17ad051c 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -102,18 +102,40 @@ static bool ComputeRelativeTimeSpec(timespec* result_ts, const timespec& lhs, co
}
#endif
+// Wait for an amount of time that roughly increases in the argument i.
+// Spin for small arguments and yield/sleep for longer ones.
+static void BackOff(uint32_t i) {
+ static constexpr uint32_t kSpinMax = 10;
+ static constexpr uint32_t kYieldMax = 20;
+ if (i <= kSpinMax) {
+ // TODO: Esp. in very latency-sensitive cases, consider replacing this with an explicit
+ // test-and-test-and-set loop in the caller. Possibly skip entirely on a uniprocessor.
+ volatile uint32_t x = 0;
+ const uint32_t spin_count = 10 * i;
+ for (uint32_t spin = 0; spin < spin_count; ++spin) {
+ ++x; // Volatile; hence should not be optimized away.
+ }
+ // TODO: Consider adding x86 PAUSE and/or ARM YIELD here.
+ } else if (i <= kYieldMax) {
+ sched_yield();
+ } else {
+ NanoSleep(1000ull * (i - kYieldMax));
+ }
+}
+
class ScopedAllMutexesLock FINAL {
public:
explicit ScopedAllMutexesLock(const BaseMutex* mutex) : mutex_(mutex) {
- while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakAcquire(0, mutex)) {
- NanoSleep(100);
+ for (uint32_t i = 0;
+ !gAllMutexData->all_mutexes_guard.CompareAndSetWeakAcquire(0, mutex);
+ ++i) {
+ BackOff(i);
}
}
~ScopedAllMutexesLock() {
- while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakRelease(mutex_, 0)) {
- NanoSleep(100);
- }
+ DCHECK_EQ(gAllMutexData->all_mutexes_guard.LoadRelaxed(), mutex_);
+ gAllMutexData->all_mutexes_guard.StoreRelease(0);
}
private:
@@ -123,17 +145,16 @@ class ScopedAllMutexesLock FINAL {
class Locks::ScopedExpectedMutexesOnWeakRefAccessLock FINAL {
public:
explicit ScopedExpectedMutexesOnWeakRefAccessLock(const BaseMutex* mutex) : mutex_(mutex) {
- while (!Locks::expected_mutexes_on_weak_ref_access_guard_.CompareExchangeWeakAcquire(0,
- mutex)) {
- NanoSleep(100);
+ for (uint32_t i = 0;
+ !Locks::expected_mutexes_on_weak_ref_access_guard_.CompareAndSetWeakAcquire(0, mutex);
+ ++i) {
+ BackOff(i);
}
}
~ScopedExpectedMutexesOnWeakRefAccessLock() {
- while (!Locks::expected_mutexes_on_weak_ref_access_guard_.CompareExchangeWeakRelease(mutex_,
- 0)) {
- NanoSleep(100);
- }
+ DCHECK_EQ(Locks::expected_mutexes_on_weak_ref_access_guard_.LoadRelaxed(), mutex_);
+ Locks::expected_mutexes_on_weak_ref_access_guard_.StoreRelease(0);
}
private:
@@ -293,7 +314,7 @@ void BaseMutex::RecordContention(uint64_t blocked_tid,
do {
slot = data->cur_content_log_entry.LoadRelaxed();
new_slot = (slot + 1) % kContentionLogSize;
- } while (!data->cur_content_log_entry.CompareExchangeWeakRelaxed(slot, new_slot));
+ } while (!data->cur_content_log_entry.CompareAndSetWeakRelaxed(slot, new_slot));
log[new_slot].blocked_tid = blocked_tid;
log[new_slot].owner_tid = owner_tid;
log[new_slot].count.StoreRelaxed(1);
@@ -417,7 +438,7 @@ void Mutex::ExclusiveLock(Thread* self) {
int32_t cur_state = state_.LoadRelaxed();
if (LIKELY(cur_state == 0)) {
// Change state from 0 to 1 and impose load/store ordering appropriate for lock acquisition.
- done = state_.CompareExchangeWeakAcquire(0 /* cur_state */, 1 /* new state */);
+ done = state_.CompareAndSetWeakAcquire(0 /* cur_state */, 1 /* new state */);
} else {
// Failed to acquire, hang up.
ScopedContentionRecorder scr(this, SafeGetTid(self), GetExclusiveOwnerTid());
@@ -463,7 +484,7 @@ bool Mutex::ExclusiveTryLock(Thread* self) {
int32_t cur_state = state_.LoadRelaxed();
if (cur_state == 0) {
// Change state from 0 to 1 and impose load/store ordering appropriate for lock acquisition.
- done = state_.CompareExchangeWeakAcquire(0 /* cur_state */, 1 /* new state */);
+ done = state_.CompareAndSetWeakAcquire(0 /* cur_state */, 1 /* new state */);
} else {
return false;
}
@@ -522,10 +543,10 @@ void Mutex::ExclusiveUnlock(Thread* self) {
// We're no longer the owner.
exclusive_owner_.StoreRelaxed(0);
// Change state to 0 and impose load/store ordering appropriate for lock release.
- // Note, the relaxed loads below mustn't reorder before the CompareExchange.
+ // Note, the relaxed loads below mustn't reorder before the CompareAndSet.
// TODO: the ordering here is non-trivial as state is split across 3 fields, fix by placing
// a status bit into the state on contention.
- done = state_.CompareExchangeWeakSequentiallyConsistent(cur_state, 0 /* new state */);
+ done = state_.CompareAndSetWeakSequentiallyConsistent(cur_state, 0 /* new state */);
if (LIKELY(done)) { // Spurious fail?
// Wake a contender.
if (UNLIKELY(num_contenders_.LoadRelaxed() > 0)) {
@@ -618,7 +639,7 @@ void ReaderWriterMutex::ExclusiveLock(Thread* self) {
int32_t cur_state = state_.LoadRelaxed();
if (LIKELY(cur_state == 0)) {
// Change state from 0 to -1 and impose load/store ordering appropriate for lock acquisition.
- done = state_.CompareExchangeWeakAcquire(0 /* cur_state*/, -1 /* new state */);
+ done = state_.CompareAndSetWeakAcquire(0 /* cur_state*/, -1 /* new state */);
} else {
// Failed to acquire, hang up.
ScopedContentionRecorder scr(this, SafeGetTid(self), GetExclusiveOwnerTid());
@@ -659,10 +680,10 @@ void ReaderWriterMutex::ExclusiveUnlock(Thread* self) {
// We're no longer the owner.
exclusive_owner_.StoreRelaxed(0);
// Change state from -1 to 0 and impose load/store ordering appropriate for lock release.
- // Note, the relaxed loads below musn't reorder before the CompareExchange.
+ // Note, the relaxed loads below musn't reorder before the CompareAndSet.
// TODO: the ordering here is non-trivial as state is split across 3 fields, fix by placing
// a status bit into the state on contention.
- done = state_.CompareExchangeWeakSequentiallyConsistent(-1 /* cur_state*/, 0 /* new state */);
+ done = state_.CompareAndSetWeakSequentiallyConsistent(-1 /* cur_state*/, 0 /* new state */);
if (LIKELY(done)) { // Weak CAS may fail spuriously.
// Wake any waiters.
if (UNLIKELY(num_pending_readers_.LoadRelaxed() > 0 ||
@@ -691,7 +712,7 @@ bool ReaderWriterMutex::ExclusiveLockWithTimeout(Thread* self, int64_t ms, int32
int32_t cur_state = state_.LoadRelaxed();
if (cur_state == 0) {
// Change state from 0 to -1 and impose load/store ordering appropriate for lock acquisition.
- done = state_.CompareExchangeWeakAcquire(0 /* cur_state */, -1 /* new state */);
+ done = state_.CompareAndSetWeakAcquire(0 /* cur_state */, -1 /* new state */);
} else {
// Failed to acquire, hang up.
timespec now_abs_ts;
@@ -763,7 +784,7 @@ bool ReaderWriterMutex::SharedTryLock(Thread* self) {
int32_t cur_state = state_.LoadRelaxed();
if (cur_state >= 0) {
// Add as an extra reader and impose load/store ordering appropriate for lock acquisition.
- done = state_.CompareExchangeWeakAcquire(cur_state, cur_state + 1);
+ done = state_.CompareAndSetWeakAcquire(cur_state, cur_state + 1);
} else {
// Owner holds it exclusively.
return false;
@@ -938,7 +959,7 @@ void ConditionVariable::WaitHoldingLocks(Thread* self) {
}
if (self != nullptr) {
JNIEnvExt* const env = self->GetJniEnv();
- if (UNLIKELY(env != nullptr && env->runtime_deleted)) {
+ if (UNLIKELY(env != nullptr && env->IsRuntimeDeleted())) {
CHECK(self->IsDaemon());
// If the runtime has been deleted, then we cannot proceed. Just sleep forever. This may
// occur for user daemon threads that get a spurious wakeup. This occurs for test 132 with
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index c0cf4872de..7077298ca9 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -24,8 +24,10 @@
#include <iosfwd>
#include <string>
+#include <android-base/logging.h>
+
#include "atomic.h"
-#include "base/logging.h"
+#include "base/aborting.h"
#include "base/macros.h"
#include "globals.h"
diff --git a/runtime/base/runtime_debug.cc b/runtime/base/runtime_debug.cc
new file mode 100644
index 0000000000..4f8a8ec9c6
--- /dev/null
+++ b/runtime/base/runtime_debug.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "runtime_debug.h"
+
+#include <vector>
+
+#include "globals.h"
+
+namespace art {
+
+// We test here that the runtime-debug-checks are actually a no-op constexpr false in release
+// builds, as we can't check that in gtests (which are always debug).
+
+#ifdef NDEBUG
+namespace {
+DECLARE_RUNTIME_DEBUG_FLAG(kTestForConstexpr);
+static_assert(!kTestForConstexpr, "Issue with DECLARE_RUNTIME_DEBUG_FLAG in NDEBUG.");
+}
+#endif
+
+// Implementation of runtime debug flags. This should be compile-time optimized away in release
+// builds.
+namespace {
+bool gSlowEnabled = false; // Default for slow flags is "off."
+
+// Use a function with a static to ensure our vector storage doesn't have initialization order
+// issues.
+std::vector<bool*>& GetFlagPtrs() {
+ static std::vector<bool*> g_flag_ptrs;
+ return g_flag_ptrs;
+}
+
+bool RegisterRuntimeDebugFlagImpl(bool* flag_ptr) {
+ GetFlagPtrs().push_back(flag_ptr);
+ return gSlowEnabled;
+}
+
+void SetRuntimeDebugFlagsEnabledImpl(bool enabled) {
+ gSlowEnabled = enabled;
+ for (bool* flag_ptr : GetFlagPtrs()) {
+ *flag_ptr = enabled;
+ }
+}
+
+} // namespace
+
+bool RegisterRuntimeDebugFlag(bool* flag_ptr) {
+ if (kIsDebugBuild) {
+ return RegisterRuntimeDebugFlagImpl(flag_ptr);
+ }
+ return false;
+}
+
+void SetRuntimeDebugFlagsEnabled(bool enabled) {
+ if (kIsDebugBuild) {
+ SetRuntimeDebugFlagsEnabledImpl(enabled);
+ }
+}
+
+} // namespace art
diff --git a/runtime/base/runtime_debug.h b/runtime/base/runtime_debug.h
new file mode 100644
index 0000000000..89a0361fa7
--- /dev/null
+++ b/runtime/base/runtime_debug.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_BASE_RUNTIME_DEBUG_H_
+#define ART_RUNTIME_BASE_RUNTIME_DEBUG_H_
+
+namespace art {
+
+// Runtime debug flags are flags that have a runtime component, that is, their value can be changed.
+// This is meant to implement fast vs slow debug builds, in that certain debug flags can be turned
+// on and off. To that effect, expose two macros to help implement and globally drive these flags:
+//
+// In the header, declare a (class) flag like this:
+//
+// class C {
+// DECLARE_RUNTIME_DEBUG_FLAG(kFlag);
+// };
+//
+// This will declare a flag kFlag that is a constexpr false in release builds, and a static field
+// in debug builds. Usage is than uniform as C::kFlag.
+//
+// In the cc file, define the flag like this:
+//
+// DEFINE_RUNTIME_DEBUG_FLAG(C, kFlag);
+//
+// This will define the static storage, as necessary, and register the flag with the runtime
+// infrastructure to toggle the value.
+
+#ifdef NDEBUG
+#define DECLARE_RUNTIME_DEBUG_FLAG(x) \
+ static constexpr bool x = false;
+// Note: the static_assert in the following only works for public flags. Fix this when we cross
+// the line at some point.
+#define DEFINE_RUNTIME_DEBUG_FLAG(C, x) \
+ static_assert(!C::x, "Unexpected enabled flag in release build");
+#else
+#define DECLARE_RUNTIME_DEBUG_FLAG(x) \
+ static bool x;
+#define DEFINE_RUNTIME_DEBUG_FLAG(C, x) \
+ bool C::x = RegisterRuntimeDebugFlag(&C::x);
+#endif // NDEBUG
+
+bool RegisterRuntimeDebugFlag(bool* runtime_debug_flag);
+void SetRuntimeDebugFlagsEnabled(bool enabled);
+
+} // namespace art
+
+#endif // ART_RUNTIME_BASE_RUNTIME_DEBUG_H_
diff --git a/runtime/base/scoped_arena_allocator.h b/runtime/base/scoped_arena_allocator.h
index 8f50fd443b..35e337f0d6 100644
--- a/runtime/base/scoped_arena_allocator.h
+++ b/runtime/base/scoped_arena_allocator.h
@@ -17,10 +17,11 @@
#ifndef ART_RUNTIME_BASE_SCOPED_ARENA_ALLOCATOR_H_
#define ART_RUNTIME_BASE_SCOPED_ARENA_ALLOCATOR_H_
+#include <android-base/logging.h>
+
#include "arena_allocator.h"
#include "debug_stack.h"
#include "globals.h"
-#include "logging.h"
#include "macros.h"
namespace art {
diff --git a/runtime/base/scoped_flock.cc b/runtime/base/scoped_flock.cc
index b8df6897e4..514b97bfb1 100644
--- a/runtime/base/scoped_flock.cc
+++ b/runtime/base/scoped_flock.cc
@@ -19,9 +19,9 @@
#include <sys/file.h>
#include <sys/stat.h>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
-#include "base/logging.h"
#include "base/unix_file/fd_file.h"
namespace art {
diff --git a/runtime/base/scoped_flock.h b/runtime/base/scoped_flock.h
index 1b933c07f3..db6c819c6c 100644
--- a/runtime/base/scoped_flock.h
+++ b/runtime/base/scoped_flock.h
@@ -20,9 +20,8 @@
#include <memory>
#include <string>
-#include "android-base/unique_fd.h"
+#include <android-base/unique_fd.h>
-#include "base/logging.h"
#include "base/macros.h"
#include "base/unix_file/fd_file.h"
#include "os.h"
diff --git a/runtime/base/stl_util.h b/runtime/base/stl_util.h
index b27297241d..02f37652cf 100644
--- a/runtime/base/stl_util.h
+++ b/runtime/base/stl_util.h
@@ -21,7 +21,7 @@
#include <set>
#include <sstream>
-#include "base/logging.h"
+#include <android-base/logging.h>
namespace art {
diff --git a/runtime/base/stringpiece.cc b/runtime/base/stringpiece.cc
index 2570bad85d..672431cf9d 100644
--- a/runtime/base/stringpiece.cc
+++ b/runtime/base/stringpiece.cc
@@ -19,7 +19,7 @@
#include <ostream>
#include <utility>
-#include "logging.h"
+#include <android-base/logging.h>
namespace art {
diff --git a/runtime/base/systrace.h b/runtime/base/systrace.h
index 06db48a576..dc2206e420 100644
--- a/runtime/base/systrace.h
+++ b/runtime/base/systrace.h
@@ -19,10 +19,12 @@
#define ATRACE_TAG ATRACE_TAG_DALVIK
#include <cutils/trace.h>
-#include <utils/Trace.h>
+#include <sstream>
#include <string>
+#include "android-base/stringprintf.h"
+
namespace art {
class ScopedTrace {
@@ -30,6 +32,12 @@ class ScopedTrace {
explicit ScopedTrace(const char* name) {
ATRACE_BEGIN(name);
}
+ template <typename Fn>
+ explicit ScopedTrace(Fn fn) {
+ if (ATRACE_ENABLED()) {
+ ATRACE_BEGIN(fn().c_str());
+ }
+ }
explicit ScopedTrace(const std::string& name) : ScopedTrace(name.c_str()) {}
@@ -38,6 +46,38 @@ class ScopedTrace {
}
};
+// Helper for the SCOPED_TRACE macro. Do not use directly.
+class ScopedTraceNoStart {
+ public:
+ ScopedTraceNoStart() {
+ }
+
+ ~ScopedTraceNoStart() {
+ ATRACE_END();
+ }
+
+ // Message helper for the macro. Do not use directly.
+ class ScopedTraceMessageHelper {
+ public:
+ ScopedTraceMessageHelper() {
+ }
+ ~ScopedTraceMessageHelper() {
+ ATRACE_BEGIN(buffer_.str().c_str());
+ }
+
+ std::ostream& stream() {
+ return buffer_;
+ }
+
+ private:
+ std::ostringstream buffer_;
+ };
+};
+
+#define SCOPED_TRACE \
+ ::art::ScopedTraceNoStart trace ## __LINE__; \
+ (ATRACE_ENABLED()) && ::art::ScopedTraceNoStart::ScopedTraceMessageHelper().stream()
+
} // namespace art
#endif // ART_RUNTIME_BASE_SYSTRACE_H_
diff --git a/runtime/base/time_utils.h b/runtime/base/time_utils.h
index 919937f5ba..7648a109fa 100644
--- a/runtime/base/time_utils.h
+++ b/runtime/base/time_utils.h
@@ -76,6 +76,15 @@ static constexpr inline uint64_t MsToNs(uint64_t ms) {
return ms * 1000 * 1000;
}
+// Converts the given number of milliseconds to microseconds
+static constexpr inline uint64_t MsToUs(uint64_t ms) {
+ return ms * 1000;
+}
+
+static constexpr inline uint64_t UsToNs(uint64_t us) {
+ return us * 1000;
+}
+
#if defined(__APPLE__)
#ifndef CLOCK_REALTIME
// No clocks to specify on OS/X < 10.12, fake value to pass to routines that require a clock.
diff --git a/runtime/base/timing_logger.cc b/runtime/base/timing_logger.cc
index b8d6931a83..23ec3e1aea 100644
--- a/runtime/base/timing_logger.cc
+++ b/runtime/base/timing_logger.cc
@@ -18,8 +18,9 @@
#include "timing_logger.h"
+#include <android-base/logging.h>
+
#include "base/histogram-inl.h"
-#include "base/logging.h"
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc
index 792c58172e..37f239da23 100644
--- a/runtime/base/unix_file/fd_file.cc
+++ b/runtime/base/unix_file/fd_file.cc
@@ -23,7 +23,7 @@
#include <limits>
-#include "base/logging.h"
+#include <android-base/logging.h>
// Includes needed for FdFile::Copy().
#ifdef __linux__
diff --git a/runtime/bytecode_utils.h b/runtime/bytecode_utils.h
index 815e0baf27..a7e0abf4e3 100644
--- a/runtime/bytecode_utils.h
+++ b/runtime/bytecode_utils.h
@@ -18,9 +18,9 @@
#define ART_RUNTIME_BYTECODE_UTILS_H_
#include "base/arena_object.h"
-#include "dex_file-inl.h"
-#include "dex_file.h"
-#include "dex_instruction-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction-inl.h"
namespace art {
diff --git a/runtime/cdex/compact_dex_file.cc b/runtime/cdex/compact_dex_file.cc
deleted file mode 100644
index 82ffdb0adb..0000000000
--- a/runtime/cdex/compact_dex_file.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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 "compact_dex_file.h"
-
-namespace art {
-
-constexpr uint8_t CompactDexFile::kDexMagic[kDexMagicSize];
-constexpr uint8_t CompactDexFile::kDexMagicVersion[];
-
-void CompactDexFile::WriteMagic(uint8_t* magic) {
- std::copy_n(kDexMagic, kDexMagicSize, magic);
-}
-
-void CompactDexFile::WriteCurrentVersion(uint8_t* magic) {
- std::copy_n(kDexMagicVersion, kDexVersionLen, magic + kDexMagicSize);
-}
-
-bool CompactDexFile::IsMagicValid(const uint8_t* magic) {
- return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0);
-}
-
-bool CompactDexFile::IsVersionValid(const uint8_t* magic) {
- const uint8_t* version = &magic[sizeof(kDexMagic)];
- return memcmp(version, kDexMagicVersion, kDexVersionLen) == 0;
-}
-
-bool CompactDexFile::IsMagicValid() const {
- return IsMagicValid(header_->magic_);
-}
-
-bool CompactDexFile::IsVersionValid() const {
- return IsVersionValid(header_->magic_);
-}
-
-} // namespace art
diff --git a/runtime/cha.cc b/runtime/cha.cc
index 6c011e8e39..a53d7e5b25 100644
--- a/runtime/cha.cc
+++ b/runtime/cha.cc
@@ -17,6 +17,7 @@
#include "cha.h"
#include "art_method-inl.h"
+#include "base/logging.h" // For VLOG
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
#include "linear_alloc.h"
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index c3dd702446..5549122c34 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -21,15 +21,17 @@
#include <iomanip>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "art_field-inl.h"
#include "art_method-inl.h"
-#include "base/logging.h"
+#include "base/macros.h"
#include "base/to_str.h"
+#include "base/time_utils.h"
#include "class_linker-inl.h"
#include "class_linker.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "gc/space/space.h"
#include "java_vm_ext.h"
#include "jni_internal.h"
@@ -54,24 +56,37 @@ using android::base::StringPrintf;
* ===========================================================================
*/
+// Warn if a JNI critical is held for longer than 16ms.
+static constexpr uint64_t kCriticalWarnTimeUs = MsToUs(16);
+static_assert(kCriticalWarnTimeUs > 0, "No JNI critical warn time set");
+
// Flags passed into ScopedCheck.
-#define kFlag_Default 0x0000
+static constexpr uint16_t kFlag_Default = 0x0000;
-#define kFlag_CritBad 0x0000 // Calling while in critical is not allowed.
-#define kFlag_CritOkay 0x0001 // Calling while in critical is allowed.
-#define kFlag_CritGet 0x0002 // This is a critical "get".
-#define kFlag_CritRelease 0x0003 // This is a critical "release".
-#define kFlag_CritMask 0x0003 // Bit mask to get "crit" value.
+// Calling while in critical is not allowed.
+static constexpr uint16_t kFlag_CritBad = 0x0000;
+// Calling while in critical is allowed.
+static constexpr uint16_t kFlag_CritOkay = 0x0001;
+// This is a critical "get".
+static constexpr uint16_t kFlag_CritGet = 0x0002;
+// This is a critical "release".
+static constexpr uint16_t kFlag_CritRelease = 0x0003;
+// Bit mask to get "crit" value.
+static constexpr uint16_t kFlag_CritMask = 0x0003;
-#define kFlag_ExcepBad 0x0000 // Raised exceptions are not allowed.
-#define kFlag_ExcepOkay 0x0004 // Raised exceptions are allowed.
+// Raised exceptions are allowed.
+static constexpr uint16_t kFlag_ExcepOkay = 0x0004;
-#define kFlag_Release 0x0010 // Are we in a non-critical release function?
-#define kFlag_NullableUtf 0x0020 // Are our UTF parameters nullable?
+// Are we in a non-critical release function?
+static constexpr uint16_t kFlag_Release = 0x0010;
+// Are our UTF parameters nullable?
+static constexpr uint16_t kFlag_NullableUtf = 0x0020;
-#define kFlag_Invocation 0x8000 // Part of the invocation interface (JavaVM*).
+// Part of the invocation interface (JavaVM*).
+static constexpr uint16_t kFlag_Invocation = 0x0100;
-#define kFlag_ForceTrace 0x80000000 // Add this to a JNI function's flags if you want to trace every call.
+// Add this to a JNI function's flags if you want to trace every call.
+static constexpr uint16_t kFlag_ForceTrace = 0x8000;
class VarArgs;
/*
@@ -248,8 +263,8 @@ class VarArgs {
class ScopedCheck {
public:
- ScopedCheck(int flags, const char* functionName, bool has_method = true)
- : function_name_(functionName), flags_(flags), indent_(0), has_method_(has_method) {
+ ScopedCheck(uint16_t flags, const char* functionName, bool has_method = true)
+ : function_name_(functionName), indent_(0), flags_(flags), has_method_(has_method) {
}
~ScopedCheck() {}
@@ -372,7 +387,7 @@ class ScopedCheck {
if (f == nullptr) {
return false;
}
- if (c != f->GetDeclaringClass()) {
+ if (!f->GetDeclaringClass()->IsAssignableFrom(c)) {
AbortF("static jfieldID %p not valid for class %s", fid,
mirror::Class::PrettyClass(c).c_str());
return false;
@@ -709,7 +724,7 @@ class ScopedCheck {
return false;
}
ObjPtr<mirror::Class> c = o->AsClass();
- if (c != field->GetDeclaringClass()) {
+ if (!field->GetDeclaringClass()->IsAssignableFrom(c)) {
AbortF("attempt to access static field %s with an incompatible class argument of %s: %p",
field->PrettyField().c_str(), mirror::Class::PrettyDescriptor(c).c_str(), fid);
return false;
@@ -1196,7 +1211,7 @@ class ScopedCheck {
// this particular instance of JNIEnv.
if (env != threadEnv) {
// Get the thread owning the JNIEnv that's being used.
- Thread* envThread = reinterpret_cast<JNIEnvExt*>(env)->self;
+ Thread* envThread = reinterpret_cast<JNIEnvExt*>(env)->self_;
AbortF("thread %s using JNIEnv* from thread %s",
ToStr<Thread>(*self).c_str(), ToStr<Thread>(*envThread).c_str());
return false;
@@ -1208,7 +1223,7 @@ class ScopedCheck {
case kFlag_CritOkay: // okay to call this method
break;
case kFlag_CritBad: // not okay to call
- if (threadEnv->critical) {
+ if (threadEnv->critical_ > 0) {
AbortF("thread %s using JNI after critical get",
ToStr<Thread>(*self).c_str());
return false;
@@ -1216,15 +1231,25 @@ class ScopedCheck {
break;
case kFlag_CritGet: // this is a "get" call
// Don't check here; we allow nested gets.
- threadEnv->critical++;
+ if (threadEnv->critical_ == 0) {
+ threadEnv->critical_start_us_ = self->GetCpuMicroTime();
+ }
+ threadEnv->critical_++;
break;
case kFlag_CritRelease: // this is a "release" call
- threadEnv->critical--;
- if (threadEnv->critical < 0) {
+ if (threadEnv->critical_ == 0) {
AbortF("thread %s called too many critical releases",
ToStr<Thread>(*self).c_str());
return false;
+ } else if (threadEnv->critical_ == 1) {
+ // Leaving the critical region, possibly warn about long critical regions.
+ uint64_t critical_duration_us = self->GetCpuMicroTime() - threadEnv->critical_start_us_;
+ if (critical_duration_us > kCriticalWarnTimeUs) {
+ LOG(WARNING) << "JNI critical lock held for "
+ << PrettyDuration(UsToNs(critical_duration_us)) << " on " << *self;
+ }
}
+ threadEnv->critical_--;
break;
default:
LOG(FATAL) << "Bad flags (internal error): " << flags_;
@@ -1356,9 +1381,10 @@ class ScopedCheck {
// The name of the JNI function being checked.
const char* const function_name_;
- const int flags_;
int indent_;
+ const uint16_t flags_;
+
const bool has_method_;
DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
@@ -2591,11 +2617,11 @@ class CheckJNI {
private:
static JavaVMExt* GetJavaVMExt(JNIEnv* env) {
- return reinterpret_cast<JNIEnvExt*>(env)->vm;
+ return reinterpret_cast<JNIEnvExt*>(env)->GetVm();
}
static const JNINativeInterface* baseEnv(JNIEnv* env) {
- return reinterpret_cast<JNIEnvExt*>(env)->unchecked_functions;
+ return reinterpret_cast<JNIEnvExt*>(env)->unchecked_functions_;
}
static jobject NewRef(const char* function_name, JNIEnv* env, jobject obj, IndirectRefKind kind) {
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index d9e89159f5..0c29e257a1 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -18,7 +18,8 @@
#define ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
#include "art_method-inl.h"
-#include "dex_file_types.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file_types.h"
#include "oat_quick_method_header.h"
#include "scoped_thread_state_change-inl.h"
#include "stack.h"
@@ -66,14 +67,15 @@ class CheckReferenceMapVisitor : public StackVisitor {
CodeInfo code_info = GetCurrentOatQuickMethodHeader()->GetOptimizedCodeInfo();
CodeInfoEncoding encoding = code_info.ExtractEncoding();
StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
- uint16_t number_of_dex_registers = m->GetCodeItem()->registers_size_;
+ CodeItemDataAccessor accessor(m);
+ uint16_t number_of_dex_registers = accessor.RegistersSize();
DexRegisterMap dex_register_map =
code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers);
uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, stack_map);
BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map);
for (int i = 0; i < number_of_references; ++i) {
int reg = registers[i];
- CHECK(reg < m->GetCodeItem()->registers_size_);
+ CHECK_LT(reg, accessor.RegistersSize());
DexRegisterLocation location = dex_register_map.GetDexRegisterLocation(
reg, number_of_dex_registers, code_info, encoding);
switch (location.GetKind()) {
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index d6f003027b..cd6e8d59e8 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -61,33 +61,94 @@ inline mirror::Class* ClassLinker::FindArrayClass(Thread* self,
return array_class.Ptr();
}
-inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(
- dex::TypeIndex type_idx,
- ObjPtr<mirror::DexCache> dex_cache,
- ObjPtr<mirror::ClassLoader> class_loader) {
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (type == nullptr) {
- type = Runtime::Current()->GetClassLinker()->LookupResolvedType(
- *dex_cache->GetDexFile(), type_idx, dex_cache, class_loader);
+inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::Class> referrer) {
+ if (kObjPtrPoisoning) {
+ StackHandleScope<1> hs(Thread::Current());
+ HandleWrapperObjPtr<mirror::Class> referrer_wrapper = hs.NewHandleWrapper(&referrer);
+ Thread::Current()->PoisonObjectPointers();
}
- return type;
+ if (kIsDebugBuild) {
+ Thread::Current()->AssertNoPendingException();
+ }
+ // We do not need the read barrier for getting the DexCache for the initial resolved type
+ // lookup as both from-space and to-space copies point to the same native resolved types array.
+ ObjPtr<mirror::Class> resolved_type =
+ referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx);
+ if (resolved_type == nullptr) {
+ StackHandleScope<2> hs(Thread::Current());
+ Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache()));
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
+ resolved_type = DoResolveType(type_idx, h_dex_cache, class_loader);
+ }
+ return resolved_type;
}
-inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer) {
+inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
+ ArtMethod* referrer) {
Thread::PoisonObjectPointersIfDebug();
if (kIsDebugBuild) {
Thread::Current()->AssertNoPendingException();
}
- ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx);
+ // We do not need the read barrier for getting the DexCache for the initial resolved type
+ // lookup as both from-space and to-space copies point to the same native resolved types array.
+ ObjPtr<mirror::Class> resolved_type =
+ referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
if (UNLIKELY(resolved_type == nullptr)) {
StackHandleScope<2> hs(Thread::Current());
- ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
+ ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
- const DexFile& dex_file = *dex_cache->GetDexFile();
- resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader()));
+ resolved_type = DoResolveType(type_idx, dex_cache, class_loader);
+ }
+ return resolved_type;
+}
+
+inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader) {
+ DCHECK(dex_cache != nullptr);
+ Thread::PoisonObjectPointersIfDebug();
+ ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx);
+ if (resolved == nullptr) {
+ resolved = DoResolveType(type_idx, dex_cache, class_loader);
+ }
+ return resolved;
+}
+
+inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::Class> referrer) {
+ // We do not need the read barrier for getting the DexCache for the initial resolved type
+ // lookup as both from-space and to-space copies point to the same native resolved types array.
+ ObjPtr<mirror::Class> type =
+ referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx);
+ if (type == nullptr) {
+ type = DoLookupResolvedType(type_idx, referrer->GetDexCache(), referrer->GetClassLoader());
+ }
+ return type;
+}
+
+inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
+ ArtMethod* referrer) {
+ // We do not need the read barrier for getting the DexCache for the initial resolved type
+ // lookup as both from-space and to-space copies point to the same native resolved types array.
+ ObjPtr<mirror::Class> type =
+ referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
+ if (type == nullptr) {
+ type = DoLookupResolvedType(type_idx, referrer->GetDexCache(), referrer->GetClassLoader());
+ }
+ return type;
+}
+
+inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(
+ dex::TypeIndex type_idx,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader) {
+ ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
+ if (type == nullptr) {
+ type = DoLookupResolvedType(type_idx, dex_cache, class_loader);
}
- return resolved_type.Ptr();
+ return type;
}
template <bool kThrowOnError, typename ClassGetter>
@@ -113,7 +174,7 @@ inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_c
break;
}
case kDirect:
- if (dex_cache->GetDexFile()->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+ if (dex_cache->GetDexFile()->SupportsDefaultMethods()) {
break;
}
FALLTHROUGH_INTENDED;
@@ -147,10 +208,9 @@ inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_c
dex_cache,
type,
[this, dex_cache, method_idx, class_loader]() REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile& dex_file = *dex_cache->GetDexFile();
- const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
+ const DexFile::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(method_idx);
ObjPtr<mirror::Class> klass =
- LookupResolvedType(dex_file, method_id.class_idx_, dex_cache, class_loader);
+ LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
DCHECK(klass != nullptr);
return klass;
});
@@ -186,6 +246,8 @@ inline ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx, ArtMethod*
// lookup in the context of the original method from where it steals the code.
// However, we delay the GetInterfaceMethodIfProxy() until needed.
DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor());
+ // We do not need the read barrier for getting the DexCache for the initial resolved method
+ // lookup as both from-space and to-space copies point to the same native resolved methods array.
ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod(
method_idx, image_pointer_size_);
if (resolved_method == nullptr) {
@@ -227,6 +289,8 @@ inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
// However, we delay the GetInterfaceMethodIfProxy() until needed.
DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor());
Thread::PoisonObjectPointersIfDebug();
+ // We do not need the read barrier for getting the DexCache for the initial resolved method
+ // lookup as both from-space and to-space copies point to the same native resolved methods array.
ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod(
method_idx, image_pointer_size_);
DCHECK(resolved_method == nullptr || !resolved_method->IsRuntimeMethod());
@@ -236,9 +300,7 @@ inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
StackHandleScope<2> hs(self);
Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache()));
Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
- const DexFile* dex_file = h_dex_cache->GetDexFile();
- resolved_method = ResolveMethod<kResolveMode>(*dex_file,
- method_idx,
+ resolved_method = ResolveMethod<kResolveMode>(method_idx,
h_dex_cache,
h_class_loader,
referrer,
@@ -279,10 +341,13 @@ inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
ArtMethod* referrer,
bool is_static) {
- ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
- ArtField* field = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
+ // We do not need the read barrier for getting the DexCache for the initial resolved field
+ // lookup as both from-space and to-space copies point to the same native resolved fields array.
+ ArtField* field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField(
+ field_idx, image_pointer_size_);
if (field == nullptr) {
- field = LookupResolvedField(field_idx, dex_cache, referrer->GetClassLoader(), is_static);
+ ObjPtr<mirror::ClassLoader> class_loader = referrer->GetDeclaringClass()->GetClassLoader();
+ field = LookupResolvedField(field_idx, referrer->GetDexCache(), class_loader, is_static);
}
return field;
}
@@ -291,15 +356,16 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
ArtMethod* referrer,
bool is_static) {
Thread::PoisonObjectPointersIfDebug();
- ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
- ArtField* resolved_field =
- referrer->GetDexCache()->GetResolvedField(field_idx, image_pointer_size_);
+ // We do not need the read barrier for getting the DexCache for the initial resolved field
+ // lookup as both from-space and to-space copies point to the same native resolved fields array.
+ ArtField* resolved_field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField(
+ field_idx, image_pointer_size_);
if (UNLIKELY(resolved_field == nullptr)) {
StackHandleScope<2> hs(Thread::Current());
+ ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
- const DexFile& dex_file = *dex_cache->GetDexFile();
- resolved_field = ResolveField(dex_file, field_idx, dex_cache, class_loader, is_static);
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader()));
+ resolved_field = ResolveField(field_idx, dex_cache, class_loader, is_static);
// Note: We cannot check here to see whether we added the field to the cache. The type
// might be an erroneous class, which results in it being hidden from us.
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ccf431969a..877654247c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -50,8 +50,9 @@
#include "class_table-inl.h"
#include "compiler_callbacks.h"
#include "debugger.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_exception_helpers.h"
+#include "dex/dex_file_loader.h"
#include "entrypoints/entrypoint_utils.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "experimental_flags.h"
@@ -444,7 +445,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
CHECK(java_lang_Object != nullptr);
// backfill Object as the super class of Class.
java_lang_Class->SetSuperClass(java_lang_Object.Get());
- mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusLoaded, self);
+ mirror::Class::SetStatus(java_lang_Object, ClassStatus::kLoaded, self);
java_lang_Object->SetObjectSize(sizeof(mirror::Object));
// Allocate in non-movable so that it's possible to check if a JNI weak global ref has been
@@ -461,10 +462,8 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
//
// We take the lock here to avoid using NO_THREAD_SAFETY_ANALYSIS.
MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
- mirror::Class* java_lang_Object_ptr = java_lang_Object.Get();
- SubtypeCheck<mirror::Class*>::EnsureInitialized(java_lang_Object_ptr);
- mirror::Class* java_lang_Class_ptr = java_lang_Class.Get();
- SubtypeCheck<mirror::Class*>::EnsureInitialized(java_lang_Class_ptr);
+ SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(java_lang_Object.Get());
+ SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(java_lang_Class.Get());
}
// Object[] next to hold class roots.
@@ -495,14 +494,14 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_))));
java_lang_String->SetStringClass();
mirror::String::SetClass(java_lang_String.Get());
- mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusResolved, self);
+ mirror::Class::SetStatus(java_lang_String, ClassStatus::kResolved, self);
// Setup java.lang.ref.Reference.
Handle<mirror::Class> java_lang_ref_Reference(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(), mirror::Reference::ClassSize(image_pointer_size_))));
mirror::Reference::SetClass(java_lang_ref_Reference.Get());
java_lang_ref_Reference->SetObjectSize(mirror::Reference::InstanceSize());
- mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusResolved, self);
+ mirror::Class::SetStatus(java_lang_ref_Reference, ClassStatus::kResolved, self);
// Create storage for root classes, save away our work so far (requires descriptors).
class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(
@@ -555,7 +554,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get());
java_lang_DexCache->SetDexCacheClass();
java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize());
- mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusResolved, self);
+ mirror::Class::SetStatus(java_lang_DexCache, ClassStatus::kResolved, self);
// Setup dalvik.system.ClassExt
@@ -563,7 +562,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
AllocClass(self, java_lang_Class.Get(), mirror::ClassExt::ClassSize(image_pointer_size_))));
SetClassRoot(kDalvikSystemClassExt, dalvik_system_ClassExt.Get());
mirror::ClassExt::SetClass(dalvik_system_ClassExt.Get());
- mirror::Class::SetStatus(dalvik_system_ClassExt, mirror::Class::kStatusResolved, self);
+ mirror::Class::SetStatus(dalvik_system_ClassExt, ClassStatus::kResolved, self);
// Set up array classes for string, field, method
Handle<mirror::Class> object_array_string(hs.NewHandle(
@@ -611,15 +610,15 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
}
// Object, String, ClassExt and DexCache need to be rerun through FindSystemClass to finish init
- mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusNotReady, self);
+ mirror::Class::SetStatus(java_lang_Object, ClassStatus::kNotReady, self);
CheckSystemClass(self, java_lang_Object, "Ljava/lang/Object;");
CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize());
- mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusNotReady, self);
+ mirror::Class::SetStatus(java_lang_String, ClassStatus::kNotReady, self);
CheckSystemClass(self, java_lang_String, "Ljava/lang/String;");
- mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusNotReady, self);
+ mirror::Class::SetStatus(java_lang_DexCache, ClassStatus::kNotReady, self);
CheckSystemClass(self, java_lang_DexCache, "Ljava/lang/DexCache;");
CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::InstanceSize());
- mirror::Class::SetStatus(dalvik_system_ClassExt, mirror::Class::kStatusNotReady, self);
+ mirror::Class::SetStatus(dalvik_system_ClassExt, ClassStatus::kNotReady, self);
CheckSystemClass(self, dalvik_system_ClassExt, "Ldalvik/system/ClassExt;");
CHECK_EQ(dalvik_system_ClassExt->GetObjectSize(), mirror::ClassExt::InstanceSize());
@@ -773,7 +772,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
// java.lang.ref classes need to be specially flagged, but otherwise are normal classes
// finish initializing Reference class
- mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self);
+ mirror::Class::SetStatus(java_lang_ref_Reference, ClassStatus::kNotReady, self);
CheckSystemClass(self, java_lang_ref_Reference, "Ljava/lang/ref/Reference;");
CHECK_EQ(java_lang_ref_Reference->GetObjectSize(), mirror::Reference::InstanceSize());
CHECK_EQ(java_lang_ref_Reference->GetClassSize(),
@@ -1871,8 +1870,7 @@ bool ClassLinker::AddImageSpace(
ScopedTrace trace("Recalculate app image SubtypeCheck bitstrings");
MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
for (const ClassTable::TableSlot& root : temp_set) {
- mirror::Class* root_klass = root.Read();
- SubtypeCheck<mirror::Class*>::EnsureInitialized(root_klass);
+ SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(root.Read());
}
}
}
@@ -2311,7 +2309,7 @@ mirror::Class* ClassLinker::EnsureResolved(Thread* self,
// Check for circular dependencies between classes, the lock is required for SetStatus.
if (!h_class->IsResolved() && h_class->GetClinitThreadId() == self->GetTid()) {
ThrowClassCircularityError(h_class.Get());
- mirror::Class::SetStatus(h_class, mirror::Class::kStatusErrorUnresolved, self);
+ mirror::Class::SetStatus(h_class, ClassStatus::kErrorUnresolved, self);
return nullptr;
}
}
@@ -2773,7 +2771,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self,
// An exception occured during load, set status to erroneous while holding klass' lock in case
// notification is necessary.
if (!klass->IsErroneous()) {
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
}
return nullptr;
}
@@ -2783,7 +2781,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self,
if (!LoadSuperAndInterfaces(klass, *new_dex_file)) {
// Loading failed.
if (!klass->IsErroneous()) {
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
}
return nullptr;
}
@@ -2802,7 +2800,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self,
if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) {
// Linking failed.
if (!klass->IsErroneous()) {
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
}
return nullptr;
}
@@ -3089,7 +3087,7 @@ void ClassLinker::SetupClass(const DexFile& dex_file,
ObjPtr<mirror::ClassLoader> class_loader) {
CHECK(klass != nullptr);
CHECK(klass->GetDexCache() != nullptr);
- CHECK_EQ(mirror::Class::kStatusNotReady, klass->GetStatus());
+ CHECK_EQ(ClassStatus::kNotReady, klass->GetStatus());
const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
CHECK(descriptor != nullptr);
@@ -3099,7 +3097,7 @@ void ClassLinker::SetupClass(const DexFile& dex_file,
klass->SetAccessFlags(access_flags);
klass->SetClassLoader(class_loader);
DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
- mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, nullptr);
+ mirror::Class::SetStatus(klass, ClassStatus::kIdx, nullptr);
klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def));
klass->SetDexTypeIndex(dex_class_def.class_idx_);
@@ -3391,7 +3389,7 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
// Clean up pass to remove null dex caches. Also check if we need to initialize OatFile .bss.
// Null dex caches can occur due to class unloading and we are lazily removing null entries.
bool initialize_oat_file_bss = (oat_file != nullptr);
- JavaVMExt* const vm = self->GetJniEnv()->vm;
+ JavaVMExt* const vm = self->GetJniEnv()->GetVm();
for (auto it = dex_caches_.begin(); it != dex_caches_.end(); ) {
DexCacheData data = *it;
if (self->IsJWeakCleared(data.weak_root)) {
@@ -3625,7 +3623,7 @@ mirror::Class* ClassLinker::InitializePrimitiveClass(ObjPtr<mirror::Class> primi
h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
h_class->SetPrimitiveType(type);
h_class->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
- mirror::Class::SetStatus(h_class, mirror::Class::kStatusInitialized, self);
+ mirror::Class::SetStatus(h_class, ClassStatus::kInitialized, self);
const char* descriptor = Primitive::Descriptor(type);
ObjPtr<mirror::Class> existing = InsertClass(descriptor,
h_class.Get(),
@@ -3740,11 +3738,11 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto
} else {
new_class->SetClassFlags(mirror::kClassFlagObjectArray);
}
- mirror::Class::SetStatus(new_class, mirror::Class::kStatusLoaded, self);
+ mirror::Class::SetStatus(new_class, ClassStatus::kLoaded, self);
new_class->PopulateEmbeddedVTable(image_pointer_size_);
ImTable* object_imt = java_lang_Object->GetImt(image_pointer_size_);
new_class->SetImt(object_imt, image_pointer_size_);
- mirror::Class::SetStatus(new_class, mirror::Class::kStatusInitialized, self);
+ mirror::Class::SetStatus(new_class, ClassStatus::kInitialized, self);
// don't need to set new_class->SetObjectSize(..)
// because Object::SizeOf delegates to Array::SizeOf
@@ -4002,7 +4000,7 @@ bool ClassLinker::AttemptSupertypeVerification(Thread* self,
}
// Need to grab the lock to change status.
ObjectLock<mirror::Class> super_lock(self, klass);
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
return false;
}
@@ -4024,9 +4022,9 @@ verifier::FailureKind ClassLinker::VerifyClass(
ObjectLock<mirror::Class> lock(self, klass);
// Is somebody verifying this now?
- mirror::Class::Status old_status = klass->GetStatus();
- while (old_status == mirror::Class::kStatusVerifying ||
- old_status == mirror::Class::kStatusVerifyingAtRuntime) {
+ ClassStatus old_status = klass->GetStatus();
+ while (old_status == ClassStatus::kVerifying ||
+ old_status == ClassStatus::kVerifyingAtRuntime) {
lock.WaitIgnoringInterrupts();
// WaitIgnoringInterrupts can still receive an interrupt and return early, in this
// case we may see the same status again. b/62912904. This is why the check is
@@ -4057,18 +4055,18 @@ verifier::FailureKind ClassLinker::VerifyClass(
return verifier::FailureKind::kSoftFailure;
}
- if (klass->GetStatus() == mirror::Class::kStatusResolved) {
- mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifying, self);
+ if (klass->GetStatus() == ClassStatus::kResolved) {
+ mirror::Class::SetStatus(klass, ClassStatus::kVerifying, self);
} else {
- CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime)
+ CHECK_EQ(klass->GetStatus(), ClassStatus::kRetryVerificationAtRuntime)
<< klass->PrettyClass();
CHECK(!Runtime::Current()->IsAotCompiler());
- mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifyingAtRuntime, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kVerifyingAtRuntime, self);
}
// Skip verification if disabled.
if (!Runtime::Current()->IsVerificationEnabled()) {
- mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kVerified, self);
EnsureSkipAccessChecksMethods(klass, image_pointer_size_);
return verifier::FailureKind::kNoFailure;
}
@@ -4130,7 +4128,7 @@ verifier::FailureKind ClassLinker::VerifyClass(
// Try to use verification information from the oat file, otherwise do runtime verification.
const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
- mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady);
+ ClassStatus oat_file_class_status(ClassStatus::kNotReady);
bool preverified = VerifyClassUsingOatFile(dex_file, klass.Get(), oat_file_class_status);
VLOG(class_linker) << "Class preverified status for class "
@@ -4167,10 +4165,10 @@ verifier::FailureKind ClassLinker::VerifyClass(
// Even though there were no verifier failures we need to respect whether the super-class and
// super-default-interfaces were verified or requiring runtime reverification.
if (supertype == nullptr || supertype->IsVerified()) {
- mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kVerified, self);
} else {
- CHECK_EQ(supertype->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
- mirror::Class::SetStatus(klass, mirror::Class::kStatusRetryVerificationAtRuntime, self);
+ CHECK_EQ(supertype->GetStatus(), ClassStatus::kRetryVerificationAtRuntime);
+ mirror::Class::SetStatus(klass, ClassStatus::kRetryVerificationAtRuntime, self);
// Pretend a soft failure occurred so that we don't consider the class verified below.
verifier_failure = verifier::FailureKind::kSoftFailure;
}
@@ -4180,9 +4178,9 @@ verifier::FailureKind ClassLinker::VerifyClass(
// failures at runtime will be handled by slow paths in the generated
// code. Set status accordingly.
if (Runtime::Current()->IsAotCompiler()) {
- mirror::Class::SetStatus(klass, mirror::Class::kStatusRetryVerificationAtRuntime, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kRetryVerificationAtRuntime, self);
} else {
- mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kVerified, self);
// As this is a fake verified status, make sure the methods are _not_ marked
// kAccSkipAccessChecks later.
klass->SetVerificationAttempted();
@@ -4194,7 +4192,7 @@ verifier::FailureKind ClassLinker::VerifyClass(
<< " because: " << error_msg;
self->AssertNoPendingException();
ThrowVerifyError(klass.Get(), "%s", error_msg.c_str());
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
}
if (preverified || verifier_failure == verifier::FailureKind::kNoFailure) {
// Class is verified so we don't need to do any access check on its methods.
@@ -4236,7 +4234,7 @@ verifier::FailureKind ClassLinker::PerformClassVerification(Thread* self,
bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file,
ObjPtr<mirror::Class> klass,
- mirror::Class::Status& oat_file_class_status) {
+ ClassStatus& oat_file_class_status) {
// If we're compiling, we can only verify the class using the oat file if
// we are not compiling the image or if the class we're verifying is not part of
// the app. In other words, we will only check for preverification of bootclasspath
@@ -4262,15 +4260,15 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file,
uint16_t class_def_index = klass->GetDexClassDefIndex();
oat_file_class_status = oat_dex_file->GetOatClass(class_def_index).GetStatus();
- if (oat_file_class_status >= mirror::Class::kStatusVerified) {
+ if (oat_file_class_status >= ClassStatus::kVerified) {
return true;
}
// If we only verified a subset of the classes at compile time, we can end up with classes that
// were resolved by the verifier.
- if (oat_file_class_status == mirror::Class::kStatusResolved) {
+ if (oat_file_class_status == ClassStatus::kResolved) {
return false;
}
- if (oat_file_class_status == mirror::Class::kStatusRetryVerificationAtRuntime) {
+ if (oat_file_class_status == ClassStatus::kRetryVerificationAtRuntime) {
// Compile time verification failed with a soft error. Compile time verification can fail
// because we have incomplete type information. Consider the following:
// class ... {
@@ -4295,7 +4293,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file,
// in the class. These errors are unrecoverable.
return false;
}
- if (oat_file_class_status == mirror::Class::kStatusNotReady) {
+ if (oat_file_class_status == ClassStatus::kNotReady) {
// Status is uninitialized if we couldn't determine the status at compile time, for example,
// not loading the class.
// TODO: when the verifier doesn't rely on Class-es failing to resolve/load the type hierarchy
@@ -4317,15 +4315,14 @@ void ClassLinker::ResolveClassExceptionHandlerTypes(Handle<mirror::Class> klass)
void ClassLinker::ResolveMethodExceptionHandlerTypes(ArtMethod* method) {
// similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod.
- const DexFile::CodeItem* code_item =
- method->GetDexFile()->GetCodeItem(method->GetCodeItemOffset());
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(method);
+ if (!accessor.HasCodeItem()) {
return; // native or abstract method
}
- if (code_item->tries_size_ == 0) {
+ if (accessor.TriesSize() == 0) {
return; // nothing to process
}
- const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0);
+ const uint8_t* handlers_ptr = accessor.GetCatchHandlerData(0);
uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
for (uint32_t idx = 0; idx < handlers_size; idx++) {
CatchHandlerIterator iterator(handlers_ptr);
@@ -4369,7 +4366,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable&
temp_klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
// Object has an empty iftable, copy it for that reason.
temp_klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
- mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusIdx, self);
+ mirror::Class::SetStatus(temp_klass, ClassStatus::kIdx, self);
std::string descriptor(GetDescriptorForProxy(temp_klass.Get()));
const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str());
@@ -4437,7 +4434,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable&
// The super class is java.lang.reflect.Proxy
temp_klass->SetSuperClass(GetClassRoot(kJavaLangReflectProxy));
// Now effectively in the loaded state.
- mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusLoaded, self);
+ mirror::Class::SetStatus(temp_klass, ClassStatus::kLoaded, self);
self->AssertNoPendingException();
// At this point the class is loaded. Publish a ClassLoad event.
@@ -4453,7 +4450,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable&
Handle<mirror::ObjectArray<mirror::Class>> h_interfaces(
hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces)));
if (!LinkClass(self, descriptor.c_str(), temp_klass, h_interfaces, &klass)) {
- mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusErrorUnresolved, self);
+ mirror::Class::SetStatus(temp_klass, ClassStatus::kErrorUnresolved, self);
return nullptr;
}
}
@@ -4474,7 +4471,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable&
{
// Lock on klass is released. Lock new class object.
ObjectLock<mirror::Class> initialization_lock(self, klass);
- mirror::Class::SetStatus(klass, mirror::Class::kStatusInitialized, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kInitialized, self);
}
// sanity checks
@@ -4515,7 +4512,7 @@ std::string ClassLinker::GetDescriptorForProxy(ObjPtr<mirror::Class> proxy_class
void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) {
// Create constructor for Proxy that must initialize the method.
- CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 23u);
+ CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 21u);
// Find the <init>(InvocationHandler)V method. The exact method offset varies depending
// on which front-end compiler was used to build the libcore DEX files.
@@ -4690,7 +4687,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
VlogClassInitializationFailure(klass);
} else {
CHECK(Runtime::Current()->IsAotCompiler());
- CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
+ CHECK_EQ(klass->GetStatus(), ClassStatus::kRetryVerificationAtRuntime);
}
return false;
} else {
@@ -4706,12 +4703,12 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
}
}
- // If the class is kStatusInitializing, either this thread is
+ // If the class is ClassStatus::kInitializing, either this thread is
// initializing higher up the stack or another thread has beat us
// to initializing and we need to wait. Either way, this
// invocation of InitializeClass will not be responsible for
// running <clinit> and will return.
- if (klass->GetStatus() == mirror::Class::kStatusInitializing) {
+ if (klass->GetStatus() == ClassStatus::kInitializing) {
// Could have got an exception during verification.
if (self->IsExceptionPending()) {
VlogClassInitializationFailure(klass);
@@ -4736,20 +4733,20 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler())
? OatFile::FindOatClass(klass->GetDexFile(), klass->GetDexClassDefIndex(), &has_oat_class)
: OatFile::OatClass::Invalid();
- if (oat_class.GetStatus() < mirror::Class::kStatusSuperclassValidated &&
+ if (oat_class.GetStatus() < ClassStatus::kSuperclassValidated &&
!ValidateSuperClassDescriptors(klass)) {
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
return false;
}
self->AllowThreadSuspension();
- CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << klass->PrettyClass()
+ CHECK_EQ(klass->GetStatus(), ClassStatus::kVerified) << klass->PrettyClass()
<< " self.tid=" << self->GetTid() << " clinit.tid=" << klass->GetClinitThreadId();
// From here out other threads may observe that we're initializing and so changes of state
// require the a notification.
klass->SetClinitThreadId(self->GetTid());
- mirror::Class::SetStatus(klass, mirror::Class::kStatusInitializing, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kInitializing, self);
t0 = NanoTime();
}
@@ -4776,7 +4773,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
<< (self->GetException() != nullptr ? self->GetException()->Dump() : "");
ObjectLock<mirror::Class> lock(self, klass);
// Initialization failed because the super-class is erroneous.
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
return false;
}
}
@@ -4807,7 +4804,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
if (!iface_initialized) {
ObjectLock<mirror::Class> lock(self, klass);
// Initialization failed because one of our interfaces with default methods is erroneous.
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
return false;
}
}
@@ -4818,7 +4815,6 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
if (num_static_fields > 0) {
const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
CHECK(dex_class_def != nullptr);
- const DexFile& dex_file = klass->GetDexFile();
StackHandleScope<3> hs(self);
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
@@ -4836,11 +4832,11 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
}
}
- annotations::RuntimeEncodedStaticFieldValueIterator value_it(dex_file,
- &dex_cache,
- &class_loader,
+ annotations::RuntimeEncodedStaticFieldValueIterator value_it(dex_cache,
+ class_loader,
this,
*dex_class_def);
+ const DexFile& dex_file = *dex_cache->GetDexFile();
const uint8_t* class_data = dex_file.GetClassData(*dex_class_def);
ClassDataItemIterator field_it(dex_file, class_data);
if (value_it.HasNext()) {
@@ -4848,7 +4844,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
CHECK(can_init_statics);
for ( ; value_it.HasNext(); value_it.Next(), field_it.Next()) {
ArtField* field = ResolveField(
- dex_file, field_it.GetMemberIndex(), dex_cache, class_loader, true);
+ field_it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true);
if (Runtime::Current()->IsActiveTransaction()) {
value_it.ReadValueToField<true>(field);
} else {
@@ -4880,7 +4876,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
if (self->IsExceptionPending()) {
WrapExceptionInInitializer(klass);
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
success = false;
} else if (Runtime::Current()->IsTransactionAborted()) {
// The exception thrown when the transaction aborted has been caught and cleared
@@ -4889,7 +4885,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
<< mirror::Class::PrettyDescriptor(klass.Get())
<< " without exception while transaction was aborted: re-throw it now.";
Runtime::Current()->ThrowTransactionAbortError(self);
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
success = false;
} else {
RuntimeStats* global_stats = Runtime::Current()->GetStats();
@@ -4899,7 +4895,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
global_stats->class_init_time_ns += (t1 - t0);
thread_stats->class_init_time_ns += (t1 - t0);
// Set the class as initialized except if failed to initialize static fields.
- mirror::Class::SetStatus(klass, mirror::Class::kStatusInitialized, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kInitialized, self);
if (VLOG_IS_ON(class_linker)) {
std::string temp;
LOG(INFO) << "Initialized class " << klass->GetDescriptor(&temp) << " from " <<
@@ -4973,14 +4969,14 @@ bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass,
// we were not using WaitIgnoringInterrupts), bail out.
if (self->IsExceptionPending()) {
WrapExceptionInInitializer(klass);
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorResolved, self);
return false;
}
// Spurious wakeup? Go back to waiting.
- if (klass->GetStatus() == mirror::Class::kStatusInitializing) {
+ if (klass->GetStatus() == ClassStatus::kInitializing) {
continue;
}
- if (klass->GetStatus() == mirror::Class::kStatusVerified &&
+ if (klass->GetStatus() == ClassStatus::kVerified &&
Runtime::Current()->IsAotCompiler()) {
// Compile time initialization failed.
return false;
@@ -5221,8 +5217,7 @@ bool ClassLinker::EnsureInitialized(Thread* self,
// or Overflowed (can be used as a source for IsSubClass check).
{
MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
- ObjPtr<mirror::Class> c_ptr(c.Get());
- SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(c_ptr);
+ SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(c.Get());
// TODO: Avoid taking subtype_check_lock_ if SubtypeCheck is already initialized.
}
const bool success = InitializeClass(self, c, can_init_fields, can_init_parents);
@@ -5270,7 +5265,7 @@ void ClassLinker::RegisterClassLoader(ObjPtr<mirror::ClassLoader> class_loader)
CHECK(class_loader->GetClassTable() == nullptr);
Thread* const self = Thread::Current();
ClassLoaderData data;
- data.weak_root = self->GetJniEnv()->vm->AddWeakGlobalRef(self, class_loader);
+ data.weak_root = self->GetJniEnv()->GetVm()->AddWeakGlobalRef(self, class_loader);
// Create and set the class table.
data.class_table = new ClassTable;
class_loader->SetClassTable(data.class_table);
@@ -5314,7 +5309,7 @@ bool ClassLinker::LinkClass(Thread* self,
Handle<mirror::Class> klass,
Handle<mirror::ObjectArray<mirror::Class>> interfaces,
MutableHandle<mirror::Class>* h_new_class_out) {
- CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
+ CHECK_EQ(ClassStatus::kLoaded, klass->GetStatus());
if (!LinkSuperClass(klass)) {
return false;
@@ -5334,7 +5329,7 @@ bool ClassLinker::LinkClass(Thread* self,
return false;
}
CreateReferenceInstanceOffsets(klass);
- CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
+ CHECK_EQ(ClassStatus::kLoaded, klass->GetStatus());
ImTable* imt = nullptr;
if (klass->ShouldHaveImt()) {
@@ -5387,7 +5382,7 @@ bool ClassLinker::LinkClass(Thread* self,
// This will notify waiters on klass that saw the not yet resolved
// class in the class_table_ during EnsureResolved.
- mirror::Class::SetStatus(klass, mirror::Class::kStatusResolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kResolved, self);
h_new_class_out->Assign(klass.Get());
} else {
CHECK(!klass->IsResolved());
@@ -5403,7 +5398,7 @@ bool ClassLinker::LinkClass(Thread* self,
klass->SetIFieldsPtrUnchecked(nullptr);
if (UNLIKELY(h_new_class == nullptr)) {
self->AssertPendingOOMException();
- mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
return false;
}
@@ -5437,12 +5432,12 @@ bool ClassLinker::LinkClass(Thread* self,
// This will notify waiters on temp class that saw the not yet resolved class in the
// class_table_ during EnsureResolved.
- mirror::Class::SetStatus(klass, mirror::Class::kStatusRetired, self);
+ mirror::Class::SetStatus(klass, ClassStatus::kRetired, self);
- CHECK_EQ(h_new_class->GetStatus(), mirror::Class::kStatusResolving);
+ CHECK_EQ(h_new_class->GetStatus(), ClassStatus::kResolving);
// This will notify waiters on new_class that saw the not yet resolved
// class in the class_table_ during EnsureResolved.
- mirror::Class::SetStatus(h_new_class, mirror::Class::kStatusResolved, self);
+ mirror::Class::SetStatus(h_new_class, ClassStatus::kResolved, self);
// Return the new class.
h_new_class_out->Assign(h_new_class.Get());
}
@@ -5450,7 +5445,7 @@ bool ClassLinker::LinkClass(Thread* self,
}
bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) {
- CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus());
+ CHECK_EQ(ClassStatus::kIdx, klass->GetStatus());
const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
dex::TypeIndex super_class_idx = class_def.superclass_idx_;
if (super_class_idx.IsValid()) {
@@ -5467,7 +5462,7 @@ bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexF
return false;
}
- ObjPtr<mirror::Class> super_class = ResolveType(dex_file, super_class_idx, klass.Get());
+ ObjPtr<mirror::Class> super_class = ResolveType(super_class_idx, klass.Get());
if (super_class == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return false;
@@ -5486,7 +5481,7 @@ bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexF
if (interfaces != nullptr) {
for (size_t i = 0; i < interfaces->Size(); i++) {
dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
- ObjPtr<mirror::Class> interface = ResolveType(dex_file, idx, klass.Get());
+ ObjPtr<mirror::Class> interface = ResolveType(idx, klass.Get());
if (interface == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return false;
@@ -5503,7 +5498,7 @@ bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexF
}
}
// Mark the class as loaded.
- mirror::Class::SetStatus(klass, mirror::Class::kStatusLoaded, nullptr);
+ mirror::Class::SetStatus(klass, ClassStatus::kLoaded, nullptr);
return true;
}
@@ -7727,32 +7722,32 @@ void ClassLinker::CreateReferenceInstanceOffsets(Handle<mirror::Class> klass) {
klass->SetReferenceInstanceOffsets(reference_offsets);
}
-mirror::String* ClassLinker::ResolveString(const DexFile& dex_file,
- dex::StringIndex string_idx,
- Handle<mirror::DexCache> dex_cache) {
+ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
+ Handle<mirror::DexCache> dex_cache) {
DCHECK(dex_cache != nullptr);
Thread::PoisonObjectPointersIfDebug();
ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
if (resolved != nullptr) {
- return resolved.Ptr();
+ return resolved;
}
+ const DexFile& dex_file = *dex_cache->GetDexFile();
uint32_t utf16_length;
const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length);
ObjPtr<mirror::String> string = intern_table_->InternStrong(utf16_length, utf8_data);
if (string != nullptr) {
dex_cache->SetResolvedString(string_idx, string);
}
- return string.Ptr();
+ return string;
}
-mirror::String* ClassLinker::LookupString(const DexFile& dex_file,
- dex::StringIndex string_idx,
- ObjPtr<mirror::DexCache> dex_cache) {
+ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx,
+ ObjPtr<mirror::DexCache> dex_cache) {
DCHECK(dex_cache != nullptr);
ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
if (resolved != nullptr) {
- return resolved.Ptr();
+ return resolved;
}
+ const DexFile& dex_file = *dex_cache->GetDexFile();
uint32_t utf16_length;
const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length);
ObjPtr<mirror::String> string =
@@ -7760,87 +7755,168 @@ mirror::String* ClassLinker::LookupString(const DexFile& dex_file,
if (string != nullptr) {
dex_cache->SetResolvedString(string_idx, string);
}
- return string.Ptr();
+ return string;
}
-ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
- ObjPtr<mirror::DexCache> dex_cache,
- ObjPtr<mirror::ClassLoader> class_loader) {
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (type == nullptr) {
- const char* descriptor = dex_file.StringByTypeIdx(type_idx);
- DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
- if (descriptor[1] == '\0') {
- // only the descriptors of primitive types should be 1 character long, also avoid class lookup
- // for primitive classes that aren't backed by dex files.
- type = FindPrimitiveClass(descriptor[0]);
+ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader) {
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ const char* descriptor = dex_file.StringByTypeIdx(type_idx);
+ DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
+ ObjPtr<mirror::Class> type = nullptr;
+ if (descriptor[1] == '\0') {
+ // only the descriptors of primitive types should be 1 character long, also avoid class lookup
+ // for primitive classes that aren't backed by dex files.
+ type = FindPrimitiveClass(descriptor[0]);
+ } else {
+ Thread* const self = Thread::Current();
+ DCHECK(self != nullptr);
+ const size_t hash = ComputeModifiedUtf8Hash(descriptor);
+ // Find the class in the loaded classes table.
+ type = LookupClass(self, descriptor, hash, class_loader.Ptr());
+ }
+ if (type != nullptr) {
+ if (type->IsResolved()) {
+ dex_cache->SetResolvedType(type_idx, type);
} else {
- Thread* const self = Thread::Current();
- DCHECK(self != nullptr);
- const size_t hash = ComputeModifiedUtf8Hash(descriptor);
- // Find the class in the loaded classes table.
- type = LookupClass(self, descriptor, hash, class_loader.Ptr());
- }
- if (type != nullptr) {
- if (type->IsResolved()) {
- dex_cache->SetResolvedType(type_idx, type);
- } else {
- type = nullptr;
- }
+ type = nullptr;
}
}
- DCHECK(type == nullptr || type->IsResolved());
return type;
}
-mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
- ObjPtr<mirror::Class> referrer) {
- StackHandleScope<2> hs(Thread::Current());
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
- return ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader) {
+ Thread* self = Thread::Current();
+ const char* descriptor = dex_cache->GetDexFile()->StringByTypeIdx(type_idx);
+ ObjPtr<mirror::Class> resolved = FindClass(self, descriptor, class_loader);
+ if (resolved != nullptr) {
+ // TODO: we used to throw here if resolved's class loader was not the
+ // boot class loader. This was to permit different classes with the
+ // same name to be loaded simultaneously by different loaders
+ dex_cache->SetResolvedType(type_idx, resolved);
+ } else {
+ CHECK(self->IsExceptionPending())
+ << "Expected pending exception for failed resolution of: " << descriptor;
+ // Convert a ClassNotFoundException to a NoClassDefFoundError.
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException()));
+ if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
+ DCHECK(resolved == nullptr); // No Handle needed to preserve resolved.
+ self->ClearException();
+ ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
+ self->GetException()->SetCause(cause.Get());
+ }
+ }
+ DCHECK((resolved == nullptr) || resolved->IsResolved())
+ << resolved->PrettyDescriptor() << " " << resolved->GetStatus();
+ return resolved;
}
-mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader) {
- DCHECK(dex_cache != nullptr);
- Thread::PoisonObjectPointersIfDebug();
- ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx);
- if (resolved == nullptr) {
- Thread* self = Thread::Current();
- const char* descriptor = dex_file.StringByTypeIdx(type_idx);
- resolved = FindClass(self, descriptor, class_loader);
- if (resolved != nullptr) {
- // TODO: we used to throw here if resolved's class loader was not the
- // boot class loader. This was to permit different classes with the
- // same name to be loaded simultaneously by different loaders
- dex_cache->SetResolvedType(type_idx, resolved);
+std::string DescribeSpace(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
+ std::ostringstream oss;
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ gc::space::ContinuousSpace* cs = heap->FindContinuousSpaceFromAddress(klass.Ptr());
+ if (cs != nullptr) {
+ if (cs->IsImageSpace()) {
+ oss << "image;" << cs->GetName() << ";" << cs->AsImageSpace()->GetImageFilename();
} else {
- CHECK(self->IsExceptionPending())
- << "Expected pending exception for failed resolution of: " << descriptor;
- // Convert a ClassNotFoundException to a NoClassDefFoundError.
- StackHandleScope<1> hs(self);
- Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException()));
- if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
- DCHECK(resolved == nullptr); // No Handle needed to preserve resolved.
- self->ClearException();
- ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
- self->GetException()->SetCause(cause.Get());
+ oss << "continuous;" << cs->GetName();
+ }
+ } else {
+ gc::space::DiscontinuousSpace* ds =
+ heap->FindDiscontinuousSpaceFromObject(klass, /* fail_ok */ true);
+ if (ds != nullptr) {
+ oss << "discontinuous;" << ds->GetName();
+ } else {
+ oss << "invalid";
+ }
+ }
+ return oss.str();
+}
+
+std::string DescribeLoaders(ObjPtr<mirror::ClassLoader> loader, const char* class_descriptor)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ std::ostringstream oss;
+ uint32_t hash = ComputeModifiedUtf8Hash(class_descriptor);
+ ObjPtr<mirror::Class> path_class_loader =
+ WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_PathClassLoader);
+ ObjPtr<mirror::Class> dex_class_loader =
+ WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_DexClassLoader);
+ ObjPtr<mirror::Class> delegate_last_class_loader =
+ WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_DelegateLastClassLoader);
+
+ // Print the class loader chain.
+ bool found_class = false;
+ const char* loader_separator = "";
+ if (loader == nullptr) {
+ oss << "BootClassLoader"; // This would be unexpected.
+ }
+ for (; loader != nullptr; loader = loader->GetParent()) {
+ oss << loader_separator << loader->GetClass()->PrettyDescriptor();
+ loader_separator = ";";
+ // If we didn't find the interface yet, try to find it in the current class loader.
+ if (!found_class) {
+ ClassTable* table = Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(loader);
+ ObjPtr<mirror::Class> klass =
+ (table != nullptr) ? table->Lookup(class_descriptor, hash) : nullptr;
+ if (klass != nullptr) {
+ found_class = true;
+ oss << "[hit:" << DescribeSpace(klass) << "]";
+ }
+ }
+
+ // For PathClassLoader, DexClassLoader or DelegateLastClassLoader
+ // also dump the dex file locations.
+ if (loader->GetClass() == path_class_loader ||
+ loader->GetClass() == dex_class_loader ||
+ loader->GetClass() == delegate_last_class_loader) {
+ ArtField* const cookie_field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie);
+ ArtField* const dex_file_field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
+ ObjPtr<mirror::Object> dex_path_list =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList)->
+ GetObject(loader);
+ if (dex_path_list != nullptr && dex_file_field != nullptr && cookie_field != nullptr) {
+ ObjPtr<mirror::Object> dex_elements_obj =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
+ GetObject(dex_path_list);
+ if (dex_elements_obj != nullptr) {
+ ObjPtr<mirror::ObjectArray<mirror::Object>> dex_elements =
+ dex_elements_obj->AsObjectArray<mirror::Object>();
+ oss << "(";
+ const char* path_separator = "";
+ for (int32_t i = 0; i != dex_elements->GetLength(); ++i) {
+ ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i);
+ ObjPtr<mirror::Object> dex_file =
+ (element != nullptr) ? dex_file_field->GetObject(element) : nullptr;
+ ObjPtr<mirror::LongArray> long_array =
+ (dex_file != nullptr) ? cookie_field->GetObject(dex_file)->AsLongArray() : nullptr;
+ if (long_array != nullptr) {
+ int32_t long_array_size = long_array->GetLength();
+ // First element is the oat file.
+ for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) {
+ const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(
+ static_cast<uintptr_t>(long_array->GetWithoutChecks(j)));
+ oss << path_separator << cp_dex_file->GetLocation();
+ path_separator = ":";
+ }
+ }
+ }
+ oss << ")";
+ }
}
}
}
- DCHECK((resolved == nullptr) || resolved->IsResolved())
- << resolved->PrettyDescriptor() << " " << resolved->GetStatus();
- return resolved.Ptr();
+
+ return oss.str();
}
template <ClassLinker::ResolveMode kResolveMode>
-ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
- uint32_t method_idx,
+ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
ArtMethod* referrer,
@@ -7858,17 +7934,24 @@ ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
return resolved;
}
+ const DexFile& dex_file = *dex_cache->GetDexFile();
const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
ObjPtr<mirror::Class> klass = nullptr;
if (valid_dex_cache_method) {
// We have a valid method from the DexCache but we need to perform ICCE and IAE checks.
DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
- klass = LookupResolvedType(dex_file, method_id.class_idx_, dex_cache.Get(), class_loader.Get());
- CHECK(klass != nullptr) << resolved->PrettyMethod() << " " << resolved << " "
- << resolved->GetAccessFlags();
+ klass = LookupResolvedType(method_id.class_idx_, dex_cache.Get(), class_loader.Get());
+ if (UNLIKELY(klass == nullptr)) {
+ const char* descriptor = dex_file.StringByTypeIdx(method_id.class_idx_);
+ LOG(FATAL) << "Check failed: klass != nullptr Bug: 64759619 Method: "
+ << resolved->PrettyMethod() << ";" << resolved
+ << "/0x" << std::hex << resolved->GetAccessFlags()
+ << " ReferencedClass: " << descriptor
+ << " ClassLoader: " << DescribeLoaders(class_loader.Get(), descriptor);
+ }
} else {
// The method was not in the DexCache, resolve the declaring class.
- klass = ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader);
+ klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return nullptr;
@@ -7943,8 +8026,7 @@ ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
}
}
-ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(const DexFile& dex_file,
- uint32_t method_idx,
+ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader) {
ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);
@@ -7955,9 +8037,8 @@ ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(const DexFile& dex_file,
return resolved;
}
// Fail, get the declaring class.
- const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
- ObjPtr<mirror::Class> klass =
- ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader);
+ const DexFile::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(method_idx);
+ ObjPtr<mirror::Class> klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
Thread::Current()->AssertPendingException();
return nullptr;
@@ -7979,7 +8060,7 @@ ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(field_id.class_idx_);
if (klass == nullptr) {
- klass = LookupResolvedType(dex_file, field_id.class_idx_, dex_cache, class_loader);
+ klass = LookupResolvedType(field_id.class_idx_, dex_cache, class_loader);
}
if (klass == nullptr) {
// The class has not been resolved yet, so the field is also unresolved.
@@ -8008,8 +8089,7 @@ ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
return resolved_field;
}
-ArtField* ClassLinker::ResolveField(const DexFile& dex_file,
- uint32_t field_idx,
+ArtField* ClassLinker::ResolveField(uint32_t field_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
bool is_static) {
@@ -8019,9 +8099,10 @@ ArtField* ClassLinker::ResolveField(const DexFile& dex_file,
if (resolved != nullptr) {
return resolved;
}
+ const DexFile& dex_file = *dex_cache->GetDexFile();
const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
Thread* const self = Thread::Current();
- ObjPtr<mirror::Class> klass = ResolveType(dex_file, field_id.class_idx_, dex_cache, class_loader);
+ ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return nullptr;
@@ -8050,8 +8131,7 @@ ArtField* ClassLinker::ResolveField(const DexFile& dex_file,
return resolved;
}
-ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file,
- uint32_t field_idx,
+ArtField* ClassLinker::ResolveFieldJLS(uint32_t field_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader) {
DCHECK(dex_cache != nullptr);
@@ -8060,9 +8140,10 @@ ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file,
if (resolved != nullptr) {
return resolved;
}
+ const DexFile& dex_file = *dex_cache->GetDexFile();
const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
Thread* self = Thread::Current();
- ObjPtr<mirror::Class> klass(ResolveType(dex_file, field_id.class_idx_, dex_cache, class_loader));
+ ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return nullptr;
@@ -8079,11 +8160,11 @@ ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file,
return resolved;
}
-mirror::MethodType* ClassLinker::ResolveMethodType(Thread* self,
- const DexFile& dex_file,
- uint32_t proto_idx,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader) {
+ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(
+ Thread* self,
+ uint32_t proto_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader) {
DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
DCHECK(dex_cache != nullptr);
@@ -8095,9 +8176,10 @@ mirror::MethodType* ClassLinker::ResolveMethodType(Thread* self,
StackHandleScope<4> hs(self);
// First resolve the return type.
+ const DexFile& dex_file = *dex_cache->GetDexFile();
const DexFile::ProtoId& proto_id = dex_file.GetProtoId(proto_idx);
Handle<mirror::Class> return_type(hs.NewHandle(
- ResolveType(dex_file, proto_id.return_type_idx_, dex_cache, class_loader)));
+ ResolveType(proto_id.return_type_idx_, dex_cache, class_loader)));
if (return_type == nullptr) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -8123,7 +8205,7 @@ mirror::MethodType* ClassLinker::ResolveMethodType(Thread* self,
MutableHandle<mirror::Class> param_class = hs.NewHandle<mirror::Class>(nullptr);
for (; it.HasNext(); it.Next()) {
const dex::TypeIndex type_idx = it.GetTypeIdx();
- param_class.Assign(ResolveType(dex_file, type_idx, dex_cache, class_loader));
+ param_class.Assign(ResolveType(type_idx, dex_cache, class_loader));
if (param_class == nullptr) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -8141,14 +8223,13 @@ mirror::MethodType* ClassLinker::ResolveMethodType(Thread* self,
return type.Get();
}
-mirror::MethodType* ClassLinker::ResolveMethodType(Thread* self,
- uint32_t proto_idx,
- ArtMethod* referrer) {
+ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(Thread* self,
+ uint32_t proto_idx,
+ ArtMethod* referrer) {
StackHandleScope<2> hs(self);
- const DexFile* dex_file = referrer->GetDexFile();
Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
- return ResolveMethodType(self, *dex_file, proto_idx, dex_cache, class_loader);
+ return ResolveMethodType(self, proto_idx, dex_cache, class_loader);
}
mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
@@ -8326,8 +8407,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod(
// the invocation type to determine if the method is private. We
// then resolve again specifying the intended invocation type to
// force the appropriate checks.
- target_method = ResolveMethodWithoutInvokeType(*dex_file,
- method_handle.field_or_method_idx_,
+ target_method = ResolveMethodWithoutInvokeType(method_handle.field_or_method_idx_,
hs.NewHandle(referrer->GetDexCache()),
hs.NewHandle(referrer->GetClassLoader()));
if (UNLIKELY(target_method == nullptr)) {
@@ -8410,7 +8490,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod(
DexFileParameterIterator it(*dex_file, target_method->GetPrototype());
while (it.HasNext()) {
const dex::TypeIndex type_idx = it.GetTypeIdx();
- mirror::Class* klass = ResolveType(*dex_file, type_idx, dex_cache, class_loader);
+ ObjPtr<mirror::Class> klass = ResolveType(type_idx, dex_cache, class_loader);
if (nullptr == klass) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -8443,9 +8523,9 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod(
return mirror::MethodHandleImpl::Create(self, target, kind, method_type);
}
-mirror::MethodHandle* ClassLinker::ResolveMethodHandle(Thread* self,
- uint32_t method_handle_idx,
- ArtMethod* referrer)
+ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandle(Thread* self,
+ uint32_t method_handle_idx,
+ ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_) {
const DexFile* const dex_file = referrer->GetDexFile();
const DexFile::MethodHandleItem& method_handle = dex_file->GetMethodHandle(method_handle_idx);
@@ -8626,9 +8706,9 @@ const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) {
}
jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
- const std::vector<const DexFile*>& dex_files,
- jclass loader_class,
- jobject parent_loader) {
+ const std::vector<const DexFile*>& dex_files,
+ jclass loader_class,
+ jobject parent_loader) {
CHECK(self->GetJniEnv()->IsSameObject(loader_class,
WellKnownClasses::dalvik_system_PathClassLoader) ||
self->GetJniEnv()->IsSameObject(loader_class,
@@ -8659,10 +8739,10 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
DCHECK_EQ(h_dex_element_class.Get(), element_file_field->GetDeclaringClass());
ArtField* cookie_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie);
- DCHECK_EQ(cookie_field->GetDeclaringClass(), element_file_field->LookupType());
+ DCHECK_EQ(cookie_field->GetDeclaringClass(), element_file_field->LookupResolvedType());
ArtField* file_name_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_fileName);
- DCHECK_EQ(file_name_field->GetDeclaringClass(), element_file_field->LookupType());
+ DCHECK_EQ(file_name_field->GetDeclaringClass(), element_file_field->LookupResolvedType());
// Fill the elements array.
int32_t index = 0;
@@ -8704,6 +8784,29 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
DCHECK(h_dex_path_list != nullptr);
// Set elements.
dex_elements_field->SetObject<false>(h_dex_path_list.Get(), h_dex_elements.Get());
+ // Create an empty List for the "nativeLibraryDirectories," required for native tests.
+ // Note: this code is uncommon(oatdump)/testing-only, so don't add further WellKnownClasses
+ // elements.
+ {
+ ArtField* native_lib_dirs = dex_elements_field->GetDeclaringClass()->
+ FindDeclaredInstanceField("nativeLibraryDirectories", "Ljava/util/List;");
+ DCHECK(native_lib_dirs != nullptr);
+ ObjPtr<mirror::Class> list_class = FindSystemClass(self, "Ljava/util/ArrayList;");
+ DCHECK(list_class != nullptr);
+ {
+ StackHandleScope<1> h_list_scope(self);
+ Handle<mirror::Class> h_list_class(h_list_scope.NewHandle<mirror::Class>(list_class));
+ bool list_init = EnsureInitialized(self, h_list_class, true, true);
+ DCHECK(list_init);
+ list_class = h_list_class.Get();
+ }
+ ObjPtr<mirror::Object> list_object = list_class->AllocObject(self);
+ // Note: we leave the object uninitialized. This must never leak into any non-testing code, but
+ // is fine for testing. While it violates a Java-code invariant (the elementData field is
+ // normally never null), as long as one does not try to add elements, this will still
+ // work.
+ native_lib_dirs->SetObject<false>(h_dex_path_list.Get(), list_object);
+ }
// Create the class loader..
Handle<mirror::Class> h_loader_class = hs.NewHandle(soa.Decode<mirror::Class>(loader_class));
@@ -8928,14 +9031,12 @@ mirror::IfTable* ClassLinker::AllocIfTable(Thread* self, size_t ifcount) {
// Instantiate ResolveMethod.
template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- const DexFile& dex_file,
uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
ArtMethod* referrer,
InvokeType type);
template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- const DexFile& dex_file,
uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index a4c4f3d9ab..3e3425f5ac 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -27,9 +27,9 @@
#include "base/enums.h"
#include "base/macros.h"
#include "base/mutex.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
#include "dex_cache_resolved_classes.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
#include "gc_root.h"
#include "handle.h"
#include "jni.h"
@@ -243,58 +243,61 @@ class ClassLinker {
REQUIRES(!Locks::classlinker_classes_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Resolve a String with the given index from the DexFile, storing the
- // result in the DexCache.
- mirror::String* ResolveString(const DexFile& dex_file,
- dex::StringIndex string_idx,
- Handle<mirror::DexCache> dex_cache)
+ // Resolve a String with the given index from the DexFile associated with the given DexCache,
+ // storing the result in the DexCache.
+ ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx,
+ Handle<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Find a String with the given index from the DexFile, storing the
- // result in the DexCache if found. Return null if not found.
- mirror::String* LookupString(const DexFile& dex_file,
- dex::StringIndex string_idx,
- ObjPtr<mirror::DexCache> dex_cache)
+ // Find a String with the given index from the DexFile associated with the given DexCache,
+ // storing the result in the DexCache if found. Return null if not found.
+ ObjPtr<mirror::String> LookupString(dex::StringIndex string_idx,
+ ObjPtr<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Resolve a Type with the given index from the DexFile, storing the
- // result in the DexCache. The referrer is used to identify the
- // target DexCache and ClassLoader to use for resolution.
- mirror::Class* ResolveType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
- ObjPtr<mirror::Class> referrer)
+ // Resolve a Type with the given index from the DexFile associated with the given `referrer`,
+ // storing the result in the DexCache. The `referrer` is used to identify the target DexCache
+ // and ClassLoader to use for resolution.
+ ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx, ObjPtr<mirror::Class> referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- // Resolve a Type with the given index from the DexFile, storing the
- // result in the DexCache. The referrer is used to identify the
- // target DexCache and ClassLoader to use for resolution.
- mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer)
+ // Resolve a type with the given index from the DexFile associated with the given `referrer`,
+ // storing the result in the DexCache. The `referrer` is used to identify the target DexCache
+ // and ClassLoader to use for resolution.
+ ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- // Look up a resolved type with the given ID from the DexFile. The ClassLoader is used to search
- // for the type, since it may be referenced from but not contained within the given DexFile.
- ObjPtr<mirror::Class> LookupResolvedType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
- ObjPtr<mirror::DexCache> dex_cache,
- ObjPtr<mirror::ClassLoader> class_loader)
+ // Resolve a type with the given index from the DexFile associated with the given DexCache
+ // and ClassLoader, storing the result in DexCache. The ClassLoader is used to search for
+ // the type, since it may be referenced from but not contained within the DexFile.
+ ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+
+ // Look up a resolved type with the given index from the DexFile associated with the given
+ // `referrer`, storing the result in the DexCache. The `referrer` is used to identify the
+ // target DexCache and ClassLoader to use for lookup.
+ ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::Class> referrer)
REQUIRES_SHARED(Locks::mutator_lock_);
- static ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx,
- ObjPtr<mirror::DexCache> dex_cache,
- ObjPtr<mirror::ClassLoader> class_loader)
+
+ // Look up a resolved type with the given index from the DexFile associated with the given
+ // `referrer`, storing the result in the DexCache. The `referrer` is used to identify the
+ // target DexCache and ClassLoader to use for lookup.
+ ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx, ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Resolve a type with the given ID from the DexFile, storing the
- // result in DexCache. The ClassLoader is used to search for the
- // type, since it may be referenced from but not contained within
- // the given DexFile.
- mirror::Class* ResolveType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+ // Look up a resolved type with the given index from the DexFile associated with the given
+ // DexCache and ClassLoader. The ClassLoader is used to search for the type, since it may
+ // be referenced from but not contained within the DexFile.
+ ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Determine whether a dex cache result should be trusted, or an IncompatibleClassChangeError
// check and IllegalAccessError check should be performed even after a hit.
@@ -309,14 +312,12 @@ class ClassLinker {
ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Resolve a method with a given ID from the DexFile, storing the
- // result in DexCache. The ClassLinker and ClassLoader are used as
- // in ResolveType. What is unique is the method type argument which
- // is used to determine if this method is a direct, static, or
- // virtual method.
+ // Resolve a method with a given ID from the DexFile associated with the given DexCache
+ // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader are
+ // used as in ResolveType. What is unique is the method type argument which is used to
+ // determine if this method is a direct, static, or virtual method.
template <ResolveMode kResolveMode>
- ArtMethod* ResolveMethod(const DexFile& dex_file,
- uint32_t method_idx,
+ ArtMethod* ResolveMethod(uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
ArtMethod* referrer,
@@ -332,8 +333,7 @@ class ClassLinker {
ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- ArtMethod* ResolveMethodWithoutInvokeType(const DexFile& dex_file,
- uint32_t method_idx,
+ ArtMethod* ResolveMethodWithoutInvokeType(uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
@@ -345,47 +345,47 @@ class ClassLinker {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- // Resolve a field with a given ID from the DexFile, storing the
- // result in DexCache. The ClassLinker and ClassLoader are used as
- // in ResolveType. What is unique is the is_static argument which is
- // used to determine if we are resolving a static or non-static
- // field.
- ArtField* ResolveField(const DexFile& dex_file, uint32_t field_idx,
+ // Resolve a field with a given ID from the DexFile associated with the given DexCache
+ // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader
+ // are used as in ResolveType. What is unique is the is_static argument which is used
+ // to determine if we are resolving a static or non-static field.
+ ArtField* ResolveField(uint32_t field_idx,
Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, bool is_static)
+ Handle<mirror::ClassLoader> class_loader,
+ bool is_static)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- // Resolve a field with a given ID from the DexFile, storing the
- // result in DexCache. The ClassLinker and ClassLoader are used as
- // in ResolveType. No is_static argument is provided so that Java
+ // Resolve a field with a given ID from the DexFile associated with the given DexCache
+ // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader
+ // are used as in ResolveType. No is_static argument is provided so that Java
// field resolution semantics are followed.
- ArtField* ResolveFieldJLS(const DexFile& dex_file,
- uint32_t field_idx,
+ ArtField* ResolveFieldJLS(uint32_t field_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- // Resolve a method type with a given ID from the DexFile, storing
- // the result in the DexCache.
- mirror::MethodType* ResolveMethodType(Thread* self,
- const DexFile& dex_file,
- uint32_t proto_idx,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader)
+ // Resolve a method type with a given ID from the DexFile associated with a given DexCache
+ // and ClassLoader, storing the result in the DexCache.
+ ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self,
+ uint32_t proto_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- mirror::MethodType* ResolveMethodType(Thread* self, uint32_t proto_idx, ArtMethod* referrer)
+ ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self,
+ uint32_t proto_idx,
+ ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_);
// Resolve a method handle with a given ID from the DexFile. The
// result is not cached in the DexCache as the instance will only be
// used once in most circumstances.
- mirror::MethodHandle* ResolveMethodHandle(Thread* self,
- uint32_t method_handle_idx,
- ArtMethod* referrer)
+ ObjPtr<mirror::MethodHandle> ResolveMethodHandle(Thread* self,
+ uint32_t method_handle_idx,
+ ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns true on success, false if there's an exception pending.
@@ -478,7 +478,7 @@ class ClassLinker {
REQUIRES(!Locks::dex_lock_);
bool VerifyClassUsingOatFile(const DexFile& dex_file,
ObjPtr<mirror::Class> klass,
- mirror::Class::Status& oat_file_class_status)
+ ClassStatus& oat_file_class_status)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
void ResolveClassExceptionHandlerTypes(Handle<mirror::Class> klass)
@@ -881,6 +881,19 @@ class ClassLinker {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
+ // Implementation of LookupResolvedType() called when the type was not found in the dex cache.
+ ObjPtr<mirror::Class> DoLookupResolvedType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Implementation of ResolveType() called when the type was not found in the dex cache.
+ ObjPtr<mirror::Class> DoResolveType(dex::TypeIndex type_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+
// Finds a class by its descriptor, returning NULL if it isn't wasn't loaded
// by the given 'class_loader'. Uses the provided hash for the descriptor.
mirror::Class* LookupClass(Thread* self,
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 892a850997..80ef6544e8 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -26,7 +26,8 @@
#include "base/enums.h"
#include "class_linker-inl.h"
#include "common_runtime_test.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
+#include "dex/standard_dex_file.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "experimental_flags.h"
#include "gc/heap.h"
@@ -50,7 +51,6 @@
#include "mirror/string-inl.h"
#include "mirror/var_handle.h"
#include "scoped_thread_state_change-inl.h"
-#include "standard_dex_file.h"
#include "thread-current-inl.h"
namespace art {
@@ -86,7 +86,7 @@ class ClassLinkerTest : public CommonRuntimeTest {
EXPECT_TRUE(primitive->GetSuperClass() == nullptr);
EXPECT_FALSE(primitive->HasSuperClass());
EXPECT_TRUE(primitive->GetClassLoader() == nullptr);
- EXPECT_EQ(mirror::Class::kStatusInitialized, primitive->GetStatus());
+ EXPECT_EQ(ClassStatus::kInitialized, primitive->GetStatus());
EXPECT_FALSE(primitive->IsErroneous());
EXPECT_TRUE(primitive->IsLoaded());
EXPECT_TRUE(primitive->IsResolved());
@@ -125,7 +125,7 @@ class ClassLinkerTest : public CommonRuntimeTest {
EXPECT_TRUE(JavaLangObject->GetSuperClass() == nullptr);
EXPECT_FALSE(JavaLangObject->HasSuperClass());
EXPECT_TRUE(JavaLangObject->GetClassLoader() == nullptr);
- EXPECT_EQ(mirror::Class::kStatusInitialized, JavaLangObject->GetStatus());
+ EXPECT_EQ(ClassStatus::kInitialized, JavaLangObject->GetStatus());
EXPECT_FALSE(JavaLangObject->IsErroneous());
EXPECT_TRUE(JavaLangObject->IsLoaded());
EXPECT_TRUE(JavaLangObject->IsResolved());
@@ -200,7 +200,7 @@ class ClassLinkerTest : public CommonRuntimeTest {
EXPECT_TRUE(array->HasSuperClass());
ASSERT_TRUE(array->GetComponentType() != nullptr);
ASSERT_GT(strlen(array->GetComponentType()->GetDescriptor(&temp)), 0U);
- EXPECT_EQ(mirror::Class::kStatusInitialized, array->GetStatus());
+ EXPECT_EQ(ClassStatus::kInitialized, array->GetStatus());
EXPECT_FALSE(array->IsErroneous());
EXPECT_TRUE(array->IsLoaded());
EXPECT_TRUE(array->IsResolved());
@@ -795,6 +795,12 @@ struct FieldVarHandleOffsets : public CheckOffsets<mirror::FieldVarHandle> {
}
};
+struct ArrayElementVarHandleOffsets : public CheckOffsets<mirror::ArrayElementVarHandle> {
+ ArrayElementVarHandleOffsets() : CheckOffsets<mirror::ArrayElementVarHandle>(
+ false, "Ljava/lang/invoke/ArrayElementVarHandle;") {
+ }
+};
+
struct ByteArrayViewVarHandleOffsets : public CheckOffsets<mirror::ByteArrayViewVarHandle> {
ByteArrayViewVarHandleOffsets() : CheckOffsets<mirror::ByteArrayViewVarHandle>(
false, "Ljava/lang/invoke/ByteArrayViewVarHandle;") {
@@ -838,6 +844,7 @@ TEST_F(ClassLinkerTest, ValidateFieldOrderOfJavaCppUnionClasses) {
EXPECT_TRUE(CallSiteOffsets().Check());
EXPECT_TRUE(VarHandleOffsets().Check());
EXPECT_TRUE(FieldVarHandleOffsets().Check());
+ EXPECT_TRUE(ArrayElementVarHandleOffsets().Check());
EXPECT_TRUE(ByteArrayViewVarHandleOffsets().Check());
EXPECT_TRUE(ByteBufferViewVarHandleOffsets().Check());
}
@@ -912,7 +919,7 @@ TEST_F(ClassLinkerTest, FindClass) {
EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
EXPECT_TRUE(MyClass->HasSuperClass());
EXPECT_EQ(class_loader.Get(), MyClass->GetClassLoader());
- EXPECT_EQ(mirror::Class::kStatusResolved, MyClass->GetStatus());
+ EXPECT_EQ(ClassStatus::kResolved, MyClass->GetStatus());
EXPECT_FALSE(MyClass->IsErroneous());
EXPECT_TRUE(MyClass->IsLoaded());
EXPECT_TRUE(MyClass->IsResolved());
@@ -954,15 +961,14 @@ TEST_F(ClassLinkerTest, LookupResolvedType) {
ObjPtr<mirror::Class> klass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader);
dex::TypeIndex type_idx = klass->GetClassDef()->class_idx_;
ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
- const DexFile& dex_file = klass->GetDexFile();
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache, class_loader.Get()),
klass);
// Zero out the resolved type and make sure LookupResolvedType still finds it.
dex_cache->ClearResolvedType(type_idx);
EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr);
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache, class_loader.Get()),
klass);
}
@@ -983,7 +989,7 @@ TEST_F(ClassLinkerTest, LookupResolvedTypeArray) {
dex::TypeIndex array_idx = dex_file.GetIndexForTypeId(*array_id);
// Check that the array class wasn't resolved yet.
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, array_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(array_idx, dex_cache.Get(), class_loader.Get()),
ObjPtr<mirror::Class>(nullptr));
// Resolve the array class we want to test.
ObjPtr<mirror::Class> array_klass
@@ -991,13 +997,13 @@ TEST_F(ClassLinkerTest, LookupResolvedTypeArray) {
ASSERT_OBJ_PTR_NE(array_klass, ObjPtr<mirror::Class>(nullptr));
// Test that LookupResolvedType() finds the array class.
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, array_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(array_idx, dex_cache.Get(), class_loader.Get()),
array_klass);
// Zero out the resolved type and make sure LookupResolvedType() still finds it.
dex_cache->ClearResolvedType(array_idx);
EXPECT_TRUE(dex_cache->GetResolvedType(array_idx) == nullptr);
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, array_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(array_idx, dex_cache.Get(), class_loader.Get()),
array_klass);
}
@@ -1012,15 +1018,14 @@ TEST_F(ClassLinkerTest, LookupResolvedTypeErroneousInit) {
ASSERT_OBJ_PTR_NE(klass.Get(), ObjPtr<mirror::Class>(nullptr));
dex::TypeIndex type_idx = klass->GetClassDef()->class_idx_;
Handle<mirror::DexCache> dex_cache = hs.NewHandle(klass->GetDexCache());
- const DexFile& dex_file = klass->GetDexFile();
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
klass.Get());
// Zero out the resolved type and make sure LookupResolvedType still finds it.
dex_cache->ClearResolvedType(type_idx);
EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr);
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
klass.Get());
// Force initialization to turn the class erroneous.
bool initialized = class_linker_->EnsureInitialized(soa.Self(),
@@ -1032,13 +1037,13 @@ TEST_F(ClassLinkerTest, LookupResolvedTypeErroneousInit) {
soa.Self()->ClearException();
// Check that the LookupResolvedType() can still find the resolved type.
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
klass.Get());
// Zero out the resolved type and make sure LookupResolvedType() still finds it.
dex_cache->ClearResolvedType(type_idx);
EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr);
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
klass.Get());
}
@@ -1304,10 +1309,18 @@ TEST_F(ClassLinkerTest, ResolveVerifyAndClinit) {
const DexFile::TypeId* type_id = dex_file->FindTypeId("LStaticsFromCode;");
ASSERT_TRUE(type_id != nullptr);
dex::TypeIndex type_idx = dex_file->GetIndexForTypeId(*type_id);
- mirror::Class* uninit = ResolveVerifyAndClinit(type_idx, clinit, soa.Self(), true, false);
+ ObjPtr<mirror::Class> uninit = ResolveVerifyAndClinit(type_idx,
+ clinit,
+ soa.Self(),
+ /* can_run_clinit */ true,
+ /* verify_access */ false);
EXPECT_TRUE(uninit != nullptr);
EXPECT_FALSE(uninit->IsInitialized());
- mirror::Class* init = ResolveVerifyAndClinit(type_idx, getS0, soa.Self(), true, false);
+ ObjPtr<mirror::Class> init = ResolveVerifyAndClinit(type_idx,
+ getS0,
+ soa.Self(),
+ /* can_run_clinit */ true,
+ /* verify_access */ false);
EXPECT_TRUE(init != nullptr);
EXPECT_TRUE(init->IsInitialized());
}
@@ -1541,11 +1554,7 @@ TEST_F(ClassLinkerMethodHandlesTest, TestResolveMethodTypes) {
// Its RType = Ljava/lang/String;
// Its PTypes = { Ljava/lang/String; }
Handle<mirror::MethodType> method1_type = hs.NewHandle(
- class_linker_->ResolveMethodType(soa.Self(),
- dex_file,
- method1_id.proto_idx_,
- dex_cache,
- class_loader));
+ class_linker_->ResolveMethodType(soa.Self(), method1_id.proto_idx_, dex_cache, class_loader));
// Assert that the method type was resolved successfully.
ASSERT_TRUE(method1_type != nullptr);
@@ -1559,11 +1568,7 @@ TEST_F(ClassLinkerMethodHandlesTest, TestResolveMethodTypes) {
// Resolve the method type again and assert that we get back the same value.
Handle<mirror::MethodType> method1_type2 = hs.NewHandle(
- class_linker_->ResolveMethodType(soa.Self(),
- dex_file,
- method1_id.proto_idx_,
- dex_cache,
- class_loader));
+ class_linker_->ResolveMethodType(soa.Self(), method1_id.proto_idx_, dex_cache, class_loader));
ASSERT_EQ(method1_type.Get(), method1_type2.Get());
// Resolve the MethodType associated with a different method signature
@@ -1576,11 +1581,7 @@ TEST_F(ClassLinkerMethodHandlesTest, TestResolveMethodTypes) {
ASSERT_FALSE(method2->IsDirect());
const DexFile::MethodId& method2_id = dex_file.GetMethodId(method2->GetDexMethodIndex());
Handle<mirror::MethodType> method2_type = hs.NewHandle(
- class_linker_->ResolveMethodType(soa.Self(),
- dex_file,
- method2_id.proto_idx_,
- dex_cache,
- class_loader));
+ class_linker_->ResolveMethodType(soa.Self(), method2_id.proto_idx_, dex_cache, class_loader));
ASSERT_TRUE(method1_type.Get() != method2_type.Get());
}
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 54e75588b9..3ec5335a80 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -21,8 +21,8 @@
#include "base/stl_util.h"
#include "class_linker.h"
#include "class_loader_utils.h"
-#include "dex_file.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_loader.h"
#include "handle_scope-inl.h"
#include "jni_internal.h"
#include "oat_file_assistant.h"
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index fc3446c3f9..bc726354a8 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -23,7 +23,7 @@
#include "base/stl_util.h"
#include "class_linker.h"
#include "common_runtime_test.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "handle_scope-inl.h"
#include "mirror/class.h"
#include "mirror/class_loader.h"
diff --git a/runtime/class_reference.h b/runtime/class_reference.h
index 2ef9ab8959..e8e668e169 100644
--- a/runtime/class_reference.h
+++ b/runtime/class_reference.h
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <utility>
-#include "dex_file_reference.h"
+#include "dex/dex_file_reference.h"
namespace art {
diff --git a/runtime/class_status.h b/runtime/class_status.h
index 7f2ef6a09d..ada286338b 100644
--- a/runtime/class_status.h
+++ b/runtime/class_status.h
@@ -24,70 +24,70 @@ namespace art {
// Class Status
//
-// kStatusRetired: Class that's temporarily used till class linking time
+// kRetired: Class that's temporarily used till class linking time
// has its (vtable) size figured out and has been cloned to one with the
// right size which will be the one used later. The old one is retired and
// will be gc'ed once all refs to the class point to the newly
// cloned version.
//
-// kStatusErrorUnresolved, kStatusErrorResolved: Class is erroneous. We need
+// kErrorUnresolved, kErrorResolved: Class is erroneous. We need
// to distinguish between classes that have been resolved and classes that
// have not. This is important because the const-class instruction needs to
// return a previously resolved class even if its subsequent initialization
// failed. We also need this to decide whether to wrap a previous
// initialization failure in ClassDefNotFound error or not.
//
-// kStatusNotReady: If a Class cannot be found in the class table by
+// kNotReady: If a Class cannot be found in the class table by
// FindClass, it allocates an new one with AllocClass in the
-// kStatusNotReady and calls LoadClass. Note if it does find a
-// class, it may not be kStatusResolved and it will try to push it
-// forward toward kStatusResolved.
+// kNotReady and calls LoadClass. Note if it does find a
+// class, it may not be kResolved and it will try to push it
+// forward toward kResolved.
//
-// kStatusIdx: LoadClass populates with Class with information from
-// the DexFile, moving the status to kStatusIdx, indicating that the
+// kIdx: LoadClass populates with Class with information from
+// the DexFile, moving the status to kIdx, indicating that the
// Class value in super_class_ has not been populated. The new Class
// can then be inserted into the classes table.
//
-// kStatusLoaded: After taking a lock on Class, the ClassLinker will
-// attempt to move a kStatusIdx class forward to kStatusLoaded by
+// kLoaded: After taking a lock on Class, the ClassLinker will
+// attempt to move a kIdx class forward to kLoaded by
// using ResolveClass to initialize the super_class_ and ensuring the
// interfaces are resolved.
//
-// kStatusResolving: Class is just cloned with the right size from
+// kResolving: Class is just cloned with the right size from
// temporary class that's acting as a placeholder for linking. The old
// class will be retired. New class is set to this status first before
// moving on to being resolved.
//
-// kStatusResolved: Still holding the lock on Class, the ClassLinker
+// kResolved: Still holding the lock on Class, the ClassLinker
// shows linking is complete and fields of the Class populated by making
-// it kStatusResolved. Java allows circularities of the form where a super
+// it kResolved. Java allows circularities of the form where a super
// class has a field that is of the type of the sub class. We need to be able
// to fully resolve super classes while resolving types for fields.
//
-// kStatusRetryVerificationAtRuntime: The verifier sets a class to
+// kRetryVerificationAtRuntime: The verifier sets a class to
// this state if it encounters a soft failure at compile time. This
// often happens when there are unresolved classes in other dex
// files, and this status marks a class as needing to be verified
// again at runtime.
//
// TODO: Explain the other states
-enum ClassStatus : int8_t {
- kStatusRetired = -3, // Retired, should not be used. Use the newly cloned one instead.
- kStatusErrorResolved = -2,
- kStatusErrorUnresolved = -1,
- kStatusNotReady = 0,
- kStatusIdx = 1, // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_.
- kStatusLoaded = 2, // DEX idx values resolved.
- kStatusResolving = 3, // Just cloned from temporary class object.
- kStatusResolved = 4, // Part of linking.
- kStatusVerifying = 5, // In the process of being verified.
- kStatusRetryVerificationAtRuntime = 6, // Compile time verification failed, retry at runtime.
- kStatusVerifyingAtRuntime = 7, // Retrying verification at runtime.
- kStatusVerified = 8, // Logically part of linking; done pre-init.
- kStatusSuperclassValidated = 9, // Superclass validation part of init done.
- kStatusInitializing = 10, // Class init in progress.
- kStatusInitialized = 11, // Ready to go.
- kStatusMax = 12,
+enum class ClassStatus : uint8_t {
+ kNotReady = 0, // Zero-initialized Class object starts in this state.
+ kRetired = 1, // Retired, should not be used. Use the newly cloned one instead.
+ kErrorResolved = 2,
+ kErrorUnresolved = 3,
+ kIdx = 4, // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_.
+ kLoaded = 5, // DEX idx values resolved.
+ kResolving = 6, // Just cloned from temporary class object.
+ kResolved = 7, // Part of linking.
+ kVerifying = 8, // In the process of being verified.
+ kRetryVerificationAtRuntime = 9, // Compile time verification failed, retry at runtime.
+ kVerifyingAtRuntime = 10, // Retrying verification at runtime.
+ kVerified = 11, // Logically part of linking; done pre-init.
+ kSuperclassValidated = 12, // Superclass validation part of init done.
+ kInitializing = 13, // Class init in progress.
+ kInitialized = 14, // Ready to go.
+ kLast = kInitialized
};
std::ostream& operator<<(std::ostream& os, const ClassStatus& rhs);
diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h
index 1280466a91..718e93a97d 100644
--- a/runtime/class_table-inl.h
+++ b/runtime/class_table-inl.h
@@ -95,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_.CompareExchangeStrongRelease(before, Encode(after_ptr, MaskHash(before)));
+ data_.CompareAndSetStrongRelease(before, Encode(after_ptr, MaskHash(before)));
}
return after_ptr.Ptr();
}
@@ -110,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_.CompareExchangeStrongRelease(before, Encode(after_ptr, MaskHash(before)));
+ data_.CompareAndSetStrongRelease(before, Encode(after_ptr, MaskHash(before)));
}
}
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index c45bbe5334..e313ec5dd7 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -79,7 +79,7 @@ mirror::Class* ClassTable::UpdateClass(const char* descriptor, mirror::Class* kl
mirror::Class* const existing = existing_it->Read();
CHECK_NE(existing, klass) << descriptor;
CHECK(!existing->IsResolved()) << descriptor;
- CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusResolving) << descriptor;
+ CHECK_EQ(klass->GetStatus(), ClassStatus::kResolving) << descriptor;
CHECK(!klass->IsTemp()) << descriptor;
VerifyObject(klass);
// Update the element in the hash set with the new class. This is safe to do since the descriptor
diff --git a/runtime/class_table_test.cc b/runtime/class_table_test.cc
index 18c2b827fe..fdf6ad1fea 100644
--- a/runtime/class_table_test.cc
+++ b/runtime/class_table_test.cc
@@ -20,7 +20,7 @@
#include "art_method-inl.h"
#include "class_linker-inl.h"
#include "common_runtime_test.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/heap.h"
#include "handle_scope-inl.h"
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h
index 267735fe95..1db25c49f6 100644
--- a/runtime/common_dex_operations.h
+++ b/runtime/common_dex_operations.h
@@ -23,6 +23,7 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "class_linker.h"
+#include "dex/code_item_accessors.h"
#include "handle_scope-inl.h"
#include "instrumentation.h"
#include "interpreter/shadow_frame.h"
@@ -52,7 +53,7 @@ namespace interpreter {
} // namespace interpreter
inline void PerformCall(Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
ArtMethod* caller_method,
const size_t first_dest_reg,
ShadowFrame* callee_frame,
@@ -61,13 +62,13 @@ inline void PerformCall(Thread* self,
REQUIRES_SHARED(Locks::mutator_lock_) {
if (LIKELY(Runtime::Current()->IsStarted())) {
if (use_interpreter_entrypoint) {
- interpreter::ArtInterpreterToInterpreterBridge(self, code_item, callee_frame, result);
+ interpreter::ArtInterpreterToInterpreterBridge(self, accessor, callee_frame, result);
} else {
interpreter::ArtInterpreterToCompiledCodeBridge(
self, caller_method, callee_frame, first_dest_reg, result);
}
} else {
- interpreter::UnstartedRuntime::Invoke(self, code_item, callee_frame, result, first_dest_reg);
+ interpreter::UnstartedRuntime::Invoke(self, accessor, callee_frame, result, first_dest_reg);
}
}
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index ef1647caf3..96d660fd64 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -30,12 +30,13 @@
#include "base/file_utils.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/runtime_debug.h"
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
#include "compiler_callbacks.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_loader.h"
#include "gc/heap.h"
#include "gc_root-inl.h"
#include "gtest/gtest.h"
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 5be8d5b55c..1c73240eea 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -22,8 +22,11 @@
#include <string>
+#include <android-base/logging.h>
+
#include "arch/instruction_set.h"
#include "base/mutex.h"
+#include "dex/compact_dex_level.h"
#include "globals.h"
// TODO: Add inl file and avoid including inl.
#include "obj_ptr-inl.h"
@@ -32,6 +35,9 @@
namespace art {
+using LogSeverity = android::base::LogSeverity;
+using ScopedLogSeverity = android::base::ScopedLogSeverity;
+
// OBJ pointer helpers to avoid needing .Decode everywhere.
#define EXPECT_OBJ_PTR_EQ(a, b) EXPECT_EQ(MakeObjPtr(a).Ptr(), MakeObjPtr(b).Ptr());
#define ASSERT_OBJ_PTR_EQ(a, b) ASSERT_EQ(MakeObjPtr(a).Ptr(), MakeObjPtr(b).Ptr());
@@ -300,6 +306,11 @@ class CheckJniAbortCatcher {
return; \
}
+#define TEST_DISABLED_FOR_COMPACT_DEX() \
+ if (kDefaultCompactDexLevel != CompactDexLevel::kCompactDexLevelNone) { \
+ printf("WARNING: TEST DISABLED FOR COMPACT DEX\n"); \
+ return; \
+ }
} // namespace art
#endif // ART_RUNTIME_COMMON_RUNTIME_TEST_H_
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index cd52bb6551..92d86519dc 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -18,14 +18,14 @@
#include <sstream>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "art_field-inl.h"
#include "art_method-inl.h"
-#include "base/logging.h"
#include "class_linker-inl.h"
-#include "dex_file-inl.h"
-#include "dex_instruction-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_instruction-inl.h"
#include "invoke_type.h"
#include "mirror/class-inl.h"
#include "mirror/method_type.h"
@@ -441,7 +441,7 @@ static bool IsValidReadBarrierImplicitCheck(uintptr_t addr) {
return addr == monitor_offset;
}
-static bool IsValidImplicitCheck(uintptr_t addr, ArtMethod* method, const Instruction& instr)
+static bool IsValidImplicitCheck(uintptr_t addr, const Instruction& instr)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (!CanDoImplicitNullCheckOn(addr)) {
return false;
@@ -483,9 +483,10 @@ static bool IsValidImplicitCheck(uintptr_t addr, ArtMethod* method, const Instru
case Instruction::IPUT_BYTE:
case Instruction::IPUT_CHAR:
case Instruction::IPUT_SHORT: {
- ArtField* field =
- Runtime::Current()->GetClassLinker()->ResolveField(instr.VRegC_22c(), method, false);
- return (addr == 0) || (addr == field->GetOffset().Uint32Value());
+ // We might be doing an implicit null check with an offset that doesn't correspond
+ // to the instruction, for example with two field accesses and the first one being
+ // eliminated or re-ordered.
+ return true;
}
case Instruction::IGET_OBJECT_QUICK:
@@ -506,7 +507,10 @@ static bool IsValidImplicitCheck(uintptr_t addr, ArtMethod* method, const Instru
case Instruction::IPUT_SHORT_QUICK:
case Instruction::IPUT_WIDE_QUICK:
case Instruction::IPUT_OBJECT_QUICK: {
- return (addr == 0u) || (addr == instr.VRegC_22c());
+ // We might be doing an implicit null check with an offset that doesn't correspond
+ // to the instruction, for example with two field accesses and the first one being
+ // eliminated or re-ordered.
+ return true;
}
case Instruction::AGET_OBJECT:
@@ -547,43 +551,43 @@ static bool IsValidImplicitCheck(uintptr_t addr, ArtMethod* method, const Instru
void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) {
uint32_t throw_dex_pc;
ArtMethod* method = Thread::Current()->GetCurrentMethod(&throw_dex_pc);
- const DexFile::CodeItem* code = method->GetCodeItem();
- CHECK_LT(throw_dex_pc, code->insns_size_in_code_units_);
- const Instruction* instr = Instruction::At(&code->insns_[throw_dex_pc]);
- if (check_address && !IsValidImplicitCheck(addr, method, *instr)) {
+ CodeItemInstructionAccessor accessor(method);
+ CHECK_LT(throw_dex_pc, accessor.InsnsSizeInCodeUnits());
+ const Instruction& instr = accessor.InstructionAt(throw_dex_pc);
+ if (check_address && !IsValidImplicitCheck(addr, instr)) {
const DexFile* dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
LOG(FATAL) << "Invalid address for an implicit NullPointerException check: "
<< "0x" << std::hex << addr << std::dec
<< ", at "
- << instr->DumpString(dex_file)
+ << instr.DumpString(dex_file)
<< " in "
<< method->PrettyMethod();
}
- switch (instr->Opcode()) {
+ switch (instr.Opcode()) {
case Instruction::INVOKE_DIRECT:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kDirect);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kDirect);
break;
case Instruction::INVOKE_DIRECT_RANGE:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kDirect);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kDirect);
break;
case Instruction::INVOKE_VIRTUAL:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kVirtual);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kVirtual);
break;
case Instruction::INVOKE_VIRTUAL_RANGE:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kVirtual);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kVirtual);
break;
case Instruction::INVOKE_INTERFACE:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kInterface);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kInterface);
break;
case Instruction::INVOKE_INTERFACE_RANGE:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kInterface);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kInterface);
break;
case Instruction::INVOKE_POLYMORPHIC:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_45cc(), kVirtual);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_45cc(), kVirtual);
break;
case Instruction::INVOKE_POLYMORPHIC_RANGE:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_4rcc(), kVirtual);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_4rcc(), kVirtual);
break;
case Instruction::INVOKE_VIRTUAL_QUICK:
case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
@@ -608,7 +612,7 @@ void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) {
case Instruction::IGET_CHAR:
case Instruction::IGET_SHORT: {
ArtField* field =
- Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(), method, false);
+ Runtime::Current()->GetClassLinker()->ResolveField(instr.VRegC_22c(), method, false);
ThrowNullPointerExceptionForFieldAccess(field, true /* read */);
break;
}
@@ -640,7 +644,7 @@ void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) {
case Instruction::IPUT_CHAR:
case Instruction::IPUT_SHORT: {
ArtField* field =
- Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(), method, false);
+ Runtime::Current()->GetClassLinker()->ResolveField(instr.VRegC_22c(), method, false);
ThrowNullPointerExceptionForFieldAccess(field, false /* write */);
break;
}
@@ -703,7 +707,7 @@ void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) {
const DexFile* dex_file =
method->GetDeclaringClass()->GetDexCache()->GetDexFile();
LOG(FATAL) << "NullPointerException at an unexpected instruction: "
- << instr->DumpString(dex_file)
+ << instr.DumpString(dex_file)
<< " in "
<< method->PrettyMethod();
break;
diff --git a/runtime/compiler_callbacks.h b/runtime/compiler_callbacks.h
index 9041df94b9..4560bca922 100644
--- a/runtime/compiler_callbacks.h
+++ b/runtime/compiler_callbacks.h
@@ -55,7 +55,7 @@ class CompilerCallbacks {
// Return the class status of a previous stage of the compilation. This can be used, for example,
// when class unloading is enabled during multidex compilation.
virtual ClassStatus GetPreviousClassState(ClassReference ref ATTRIBUTE_UNUSED) {
- return ClassStatus::kStatusNotReady;
+ return ClassStatus::kNotReady;
}
virtual void SetDoesClassUnloading(bool does_class_unloading ATTRIBUTE_UNUSED,
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 1dcd935eea..842cd7330c 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -33,13 +33,14 @@
#include "base/time_utils.h"
#include "class_linker-inl.h"
#include "class_linker.h"
-#include "dex_file-inl.h"
-#include "dex_file_annotations.h"
-#include "dex_file_types.h"
-#include "dex_instruction.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_annotations.h"
+#include "dex/dex_file_types.h"
+#include "dex/dex_instruction.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/allocation_record.h"
+#include "gc/gc_cause.h"
#include "gc/scoped_gc_critical_section.h"
#include "gc/space/bump_pointer_space-walk-inl.h"
#include "gc/space/large_object_space.h"
@@ -278,11 +279,8 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati
}
private:
- static bool IsReturn(ArtMethod* method, uint32_t dex_pc)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile::CodeItem* code_item = method->GetCodeItem();
- const Instruction* instruction = Instruction::At(&code_item->insns_[dex_pc]);
- return instruction->IsReturn();
+ static bool IsReturn(ArtMethod* method, uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return method->DexInstructions().InstructionAt(dex_pc).IsReturn();
}
static bool IsListeningToDexPcMoved() REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -328,6 +326,7 @@ bool Dbg::gDisposed = false;
ObjectRegistry* Dbg::gRegistry = nullptr;
DebuggerActiveMethodInspectionCallback Dbg::gDebugActiveCallback;
DebuggerDdmCallback Dbg::gDebugDdmCallback;
+InternalDebuggerControlCallback Dbg::gDebuggerControlCallback;
// Deoptimization support.
std::vector<DeoptimizationRequest> Dbg::deoptimization_requests_;
@@ -364,6 +363,20 @@ bool DebuggerActiveMethodInspectionCallback::IsMethodSafeToJit(ArtMethod* m) {
return !Dbg::MethodHasAnyBreakpoints(m);
}
+void InternalDebuggerControlCallback::StartDebugger() {
+ // Release the mutator lock.
+ ScopedThreadStateChange stsc(art::Thread::Current(), kNative);
+ Dbg::StartJdwp();
+}
+
+void InternalDebuggerControlCallback::StopDebugger() {
+ Dbg::StopJdwp();
+}
+
+bool InternalDebuggerControlCallback::IsDebuggerConfigured() {
+ return Dbg::IsJdwpConfigured();
+}
+
// Breakpoints.
static std::vector<Breakpoint> gBreakpoints GUARDED_BY(Locks::breakpoint_lock_);
@@ -736,6 +749,7 @@ void Dbg::ConfigureJdwp(const JDWP::JdwpOptions& jdwp_options) {
CHECK_NE(jdwp_options.transport, JDWP::kJdwpTransportUnknown);
gJdwpOptions = jdwp_options;
gJdwpConfigured = true;
+ Runtime::Current()->GetRuntimeCallbacks()->AddDebuggerControlCallback(&gDebuggerControlCallback);
}
bool Dbg::IsJdwpConfigured() {
@@ -934,7 +948,7 @@ JDWP::JdwpError Dbg::GetContendedMonitor(JDWP::ObjectId thread_id,
JDWP::JdwpError Dbg::GetInstanceCounts(const std::vector<JDWP::RefTypeId>& class_ids,
std::vector<uint64_t>* counts) {
gc::Heap* heap = Runtime::Current()->GetHeap();
- heap->CollectGarbage(false);
+ heap->CollectGarbage(false, gc::GcCause::kGcCauseDebugger);
VariableSizedHandleScope hs(Thread::Current());
std::vector<Handle<mirror::Class>> classes;
counts->clear();
@@ -955,7 +969,7 @@ JDWP::JdwpError Dbg::GetInstances(JDWP::RefTypeId class_id, int32_t max_count,
std::vector<JDWP::ObjectId>* instances) {
gc::Heap* heap = Runtime::Current()->GetHeap();
// We only want reachable instances, so do a GC.
- heap->CollectGarbage(false);
+ heap->CollectGarbage(false, gc::GcCause::kGcCauseDebugger);
JDWP::JdwpError error;
ObjPtr<mirror::Class> c = DecodeClass(class_id, &error);
if (c == nullptr) {
@@ -963,7 +977,11 @@ JDWP::JdwpError Dbg::GetInstances(JDWP::RefTypeId class_id, int32_t max_count,
}
VariableSizedHandleScope hs(Thread::Current());
std::vector<Handle<mirror::Object>> raw_instances;
- Runtime::Current()->GetHeap()->GetInstances(hs, hs.NewHandle(c), max_count, raw_instances);
+ Runtime::Current()->GetHeap()->GetInstances(hs,
+ hs.NewHandle(c),
+ /* use_is_assignable_from */ false,
+ max_count,
+ raw_instances);
for (size_t i = 0; i < raw_instances.size(); ++i) {
instances->push_back(gRegistry->Add(raw_instances[i].Get()));
}
@@ -973,7 +991,7 @@ JDWP::JdwpError Dbg::GetInstances(JDWP::RefTypeId class_id, int32_t max_count,
JDWP::JdwpError Dbg::GetReferringObjects(JDWP::ObjectId object_id, int32_t max_count,
std::vector<JDWP::ObjectId>* referring_objects) {
gc::Heap* heap = Runtime::Current()->GetHeap();
- heap->CollectGarbage(false);
+ heap->CollectGarbage(false, gc::GcCause::kGcCauseDebugger);
JDWP::JdwpError error;
ObjPtr<mirror::Object> o = gRegistry->Get<mirror::Object*>(object_id, &error);
if (o == nullptr) {
@@ -1515,15 +1533,15 @@ static uint32_t MangleAccessFlags(uint32_t accessFlags) {
*/
static uint16_t MangleSlot(uint16_t slot, ArtMethod* m)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(m);
+ if (!accessor.HasCodeItem()) {
// We should not get here for a method without code (native, proxy or abstract). Log it and
// return the slot as is since all registers are arguments.
LOG(WARNING) << "Trying to mangle slot for method without code " << m->PrettyMethod();
return slot;
}
- uint16_t ins_size = code_item->ins_size_;
- uint16_t locals_size = code_item->registers_size_ - ins_size;
+ uint16_t ins_size = accessor.InsSize();
+ uint16_t locals_size = accessor.RegistersSize() - ins_size;
if (slot >= locals_size) {
return slot - locals_size;
} else {
@@ -1546,8 +1564,8 @@ static size_t GetMethodNumArgRegistersIncludingThis(ArtMethod* method)
*/
static uint16_t DemangleSlot(uint16_t slot, ArtMethod* m, JDWP::JdwpError* error)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(m);
+ if (!accessor.HasCodeItem()) {
// We should not get here for a method without code (native, proxy or abstract). Log it and
// return the slot as is since all registers are arguments.
LOG(WARNING) << "Trying to demangle slot for method without code "
@@ -1558,9 +1576,9 @@ static uint16_t DemangleSlot(uint16_t slot, ArtMethod* m, JDWP::JdwpError* error
return slot;
}
} else {
- if (slot < code_item->registers_size_) {
- uint16_t ins_size = code_item->ins_size_;
- uint16_t locals_size = code_item->registers_size_ - ins_size;
+ if (slot < accessor.RegistersSize()) {
+ uint16_t ins_size = accessor.InsSize();
+ uint16_t locals_size = accessor.RegistersSize() - ins_size;
*error = JDWP::ERR_NONE;
return (slot < ins_size) ? slot + locals_size : slot - ins_size;
}
@@ -1657,16 +1675,16 @@ void Dbg::OutputLineTable(JDWP::RefTypeId, JDWP::MethodId method_id, JDWP::Expan
}
};
ArtMethod* m = FromMethodId(method_id);
- const DexFile::CodeItem* code_item = m->GetCodeItem();
+ CodeItemDebugInfoAccessor accessor(m);
uint64_t start, end;
- if (code_item == nullptr) {
+ if (!accessor.HasCodeItem()) {
DCHECK(m->IsNative() || m->IsProxyMethod());
start = -1;
end = -1;
} else {
start = 0;
// Return the index of the last instruction
- end = code_item->insns_size_in_code_units_ - 1;
+ end = accessor.InsnsSizeInCodeUnits() - 1;
}
expandBufAdd8BE(pReply, start);
@@ -1680,10 +1698,10 @@ void Dbg::OutputLineTable(JDWP::RefTypeId, JDWP::MethodId method_id, JDWP::Expan
context.numItems = 0;
context.pReply = pReply;
- if (code_item != nullptr) {
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*(m->GetDexFile()), code_item);
- m->GetDexFile()->DecodeDebugPositionInfo(
- code_item, debug_info_offset, DebugCallbackContext::Callback, &context);
+ if (accessor.HasCodeItem()) {
+ m->GetDexFile()->DecodeDebugPositionInfo(accessor.DebugInfoOffset(),
+ DebugCallbackContext::Callback,
+ &context);
}
JDWP::Set4BE(expandBufGetBuffer(pReply) + numLinesOffset, context.numItems);
@@ -1723,6 +1741,7 @@ void Dbg::OutputVariableTable(JDWP::RefTypeId, JDWP::MethodId method_id, bool wi
}
};
ArtMethod* m = FromMethodId(method_id);
+ CodeItemDebugInfoAccessor accessor(m);
// arg_count considers doubles and longs to take 2 units.
// variable_count considers everything to take 1 unit.
@@ -1738,12 +1757,15 @@ void Dbg::OutputVariableTable(JDWP::RefTypeId, JDWP::MethodId method_id, bool wi
context.variable_count = 0;
context.with_generic = with_generic;
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item != nullptr) {
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*(m->GetDexFile()), code_item);
- m->GetDexFile()->DecodeDebugLocalInfo(
- code_item, debug_info_offset, m->IsStatic(), m->GetDexMethodIndex(),
- DebugCallbackContext::Callback, &context);
+ if (accessor.HasCodeItem()) {
+ m->GetDexFile()->DecodeDebugLocalInfo(accessor.RegistersSize(),
+ accessor.InsSize(),
+ accessor.InsnsSizeInCodeUnits(),
+ accessor.DebugInfoOffset(),
+ m->IsStatic(),
+ m->GetDexMethodIndex(),
+ DebugCallbackContext::Callback,
+ &context);
}
JDWP::Set4BE(expandBufGetBuffer(pReply) + variable_count_offset, context.variable_count);
@@ -1769,9 +1791,9 @@ JDWP::JdwpError Dbg::GetBytecodes(JDWP::RefTypeId, JDWP::MethodId method_id,
if (m == nullptr) {
return JDWP::ERR_INVALID_METHODID;
}
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- size_t byte_count = code_item->insns_size_in_code_units_ * 2;
- const uint8_t* begin = reinterpret_cast<const uint8_t*>(code_item->insns_);
+ CodeItemDataAccessor accessor(m);
+ size_t byte_count = accessor.InsnsSizeInCodeUnits() * 2;
+ const uint8_t* begin = reinterpret_cast<const uint8_t*>(accessor.Insns());
const uint8_t* end = begin + byte_count;
for (const uint8_t* p = begin; p != end; ++p) {
bytecodes->push_back(*p);
@@ -2954,9 +2976,8 @@ void Dbg::PostLocationEvent(ArtMethod* m, int dex_pc, mirror::Object* this_objec
Handle<mirror::Throwable> pending_exception(hs.NewHandle(self->GetException()));
self->ClearException();
if (kIsDebugBuild && pending_exception != nullptr) {
- const DexFile::CodeItem* code_item = location.method->GetCodeItem();
- const Instruction* instr = Instruction::At(&code_item->insns_[location.dex_pc]);
- CHECK_EQ(Instruction::MOVE_EXCEPTION, instr->Opcode());
+ const Instruction& instr = location.method->DexInstructions().InstructionAt(location.dex_pc);
+ CHECK_EQ(Instruction::MOVE_EXCEPTION, instr.Opcode());
}
gJdwpState->PostLocationEvent(&location, this_object, event_flags, return_value);
@@ -3832,9 +3853,9 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize
// Find the dex_pc values that correspond to the current line, for line-based single-stepping.
struct DebugCallbackContext {
DebugCallbackContext(SingleStepControl* single_step_control_cb,
- int32_t line_number_cb, const DexFile::CodeItem* code_item)
+ int32_t line_number_cb, uint32_t num_insns_in_code_units)
: single_step_control_(single_step_control_cb), line_number_(line_number_cb),
- code_item_(code_item), last_pc_valid(false), last_pc(0) {
+ num_insns_in_code_units_(num_insns_in_code_units), last_pc_valid(false), last_pc(0) {
}
static bool Callback(void* raw_context, const DexFile::PositionInfo& entry) {
@@ -3860,8 +3881,7 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize
~DebugCallbackContext() {
// If the line number was the last in the position table...
if (last_pc_valid) {
- size_t end = code_item_->insns_size_in_code_units_;
- for (uint32_t dex_pc = last_pc; dex_pc < end; ++dex_pc) {
+ for (uint32_t dex_pc = last_pc; dex_pc < num_insns_in_code_units_; ++dex_pc) {
single_step_control_->AddDexPc(dex_pc);
}
}
@@ -3869,7 +3889,7 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize
SingleStepControl* const single_step_control_;
const int32_t line_number_;
- const DexFile::CodeItem* const code_item_;
+ const uint32_t num_insns_in_code_units_;
bool last_pc_valid;
uint32_t last_pc;
};
@@ -3888,11 +3908,11 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize
// Note: if the thread is not running Java code (pure native thread), there is no "current"
// method on the stack (and no line number either).
if (m != nullptr && !m->IsNative()) {
- const DexFile::CodeItem* const code_item = m->GetCodeItem();
- DebugCallbackContext context(single_step_control, line_number, code_item);
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*(m->GetDexFile()), code_item);
- m->GetDexFile()->DecodeDebugPositionInfo(
- code_item, debug_info_offset, DebugCallbackContext::Callback, &context);
+ CodeItemDebugInfoAccessor accessor(m);
+ DebugCallbackContext context(single_step_control, line_number, accessor.InsnsSizeInCodeUnits());
+ m->GetDexFile()->DecodeDebugPositionInfo(accessor.DebugInfoOffset(),
+ DebugCallbackContext::Callback,
+ &context);
}
// Activate single-step in the thread.
@@ -4372,15 +4392,20 @@ bool Dbg::DdmHandleChunk(JNIEnv* env,
replyData.get(),
offset,
length);
- if (length == 0 || replyData.get() == nullptr) {
- return false;
- }
-
out_data->resize(length);
env->GetByteArrayRegion(replyData.get(),
offset,
length,
reinterpret_cast<jbyte*>(out_data->data()));
+
+ if (env->ExceptionCheck()) {
+ LOG(INFO) << StringPrintf("Exception thrown when reading response data from dispatcher 0x%08x",
+ type);
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ return false;
+ }
+
return true;
}
@@ -4414,7 +4439,7 @@ bool Dbg::DdmHandlePacket(JDWP::Request* request, uint8_t** pReplyBuf, int* pRep
std::vector<uint8_t> out_data;
uint32_t out_type = 0;
request->Skip(request_length);
- if (!DdmHandleChunk(env, type, data, &out_type, &out_data)) {
+ if (!DdmHandleChunk(env, type, data, &out_type, &out_data) || out_data.empty()) {
return false;
}
const uint32_t kDdmHeaderSize = 8;
diff --git a/runtime/debugger.h b/runtime/debugger.h
index d5bad8dc67..74018137a0 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -53,18 +53,22 @@ class ScopedObjectAccessUnchecked;
class StackVisitor;
class Thread;
+struct DebuggerActiveMethodInspectionCallback : public MethodInspectionCallback {
+ bool IsMethodBeingInspected(ArtMethod* method) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
+ bool IsMethodSafeToJit(ArtMethod* method) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
+};
+
struct DebuggerDdmCallback : public DdmCallback {
void DdmPublishChunk(uint32_t type, const ArrayRef<const uint8_t>& data)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
};
-struct DebuggerActiveMethodInspectionCallback : public MethodInspectionCallback {
- bool IsMethodBeingInspected(ArtMethod* m ATTRIBUTE_UNUSED)
- OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
- bool IsMethodSafeToJit(ArtMethod* m) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
+struct InternalDebuggerControlCallback : public DebuggerControlCallback {
+ void StartDebugger() OVERRIDE;
+ void StopDebugger() OVERRIDE;
+ bool IsDebuggerConfigured() OVERRIDE;
};
-
/*
* Invoke-during-breakpoint support.
*/
@@ -251,7 +255,8 @@ class Dbg {
}
// Configures JDWP with parsed command-line options.
- static void ConfigureJdwp(const JDWP::JdwpOptions& jdwp_options);
+ static void ConfigureJdwp(const JDWP::JdwpOptions& jdwp_options)
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Returns true if we had -Xrunjdwp or -agentlib:jdwp= on the command line.
static bool IsJdwpConfigured();
@@ -789,6 +794,7 @@ class Dbg {
static DebuggerActiveMethodInspectionCallback gDebugActiveCallback;
static DebuggerDdmCallback gDebugDdmCallback;
+ static InternalDebuggerControlCallback gDebuggerControlCallback;
// Indicates whether we should drop the JDWP connection because the runtime stops or the
// debugger called VirtualMachine.Dispose.
diff --git a/runtime/dex/code_item_accessors-inl.h b/runtime/dex/code_item_accessors-inl.h
new file mode 100644
index 0000000000..2fdf262b7d
--- /dev/null
+++ b/runtime/dex/code_item_accessors-inl.h
@@ -0,0 +1,49 @@
+/*
+ * 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_CODE_ITEM_ACCESSORS_INL_H_
+#define ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_INL_H_
+
+#include "code_item_accessors-no_art-inl.h"
+
+#include "art_method-inl.h"
+#include "compact_dex_file.h"
+#include "dex_file-inl.h"
+#include "oat_file.h"
+#include "standard_dex_file.h"
+
+namespace art {
+
+inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(ArtMethod* method)
+ : CodeItemInstructionAccessor(method->GetDexFile(), method->GetCodeItem()) {}
+
+inline CodeItemDataAccessor::CodeItemDataAccessor(ArtMethod* method)
+ : CodeItemDataAccessor(method->GetDexFile(), method->GetCodeItem()) {}
+
+inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(ArtMethod* method)
+ : CodeItemDebugInfoAccessor(method->GetDexFile(), method->GetCodeItem()) {}
+
+inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(const DexFile* dex_file,
+ const DexFile::CodeItem* code_item) {
+ if (code_item == nullptr) {
+ return;
+ }
+ Init(dex_file, code_item, OatFile::GetDebugInfoOffset(*dex_file, code_item->debug_info_off_));
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_INL_H_
diff --git a/runtime/code_item_accessors-inl.h b/runtime/dex/code_item_accessors-no_art-inl.h
index d04849d09a..016923d035 100644
--- a/runtime/code_item_accessors-inl.h
+++ b/runtime/dex/code_item_accessors-no_art-inl.h
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_
-#define ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_
+#ifndef ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_
+#define ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_
#include "code_item_accessors.h"
-#include "art_method-inl.h"
-#include "cdex/compact_dex_file.h"
+#include "compact_dex_file.h"
#include "dex_file-inl.h"
#include "standard_dex_file.h"
+// The no ART version is used by binaries that don't include the whole runtime.
namespace art {
inline void CodeItemInstructionAccessor::Init(const CompactDexFile::CodeItem& code_item) {
@@ -37,14 +37,16 @@ inline void CodeItemInstructionAccessor::Init(const StandardDexFile::CodeItem& c
}
inline void CodeItemInstructionAccessor::Init(const DexFile* dex_file,
- const DexFile::CodeItem* code_item) {
- DCHECK(dex_file != nullptr);
- DCHECK(code_item != nullptr);
- if (dex_file->IsCompactDexFile()) {
- Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
- } else {
- DCHECK(dex_file->IsStandardDexFile());
- Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ const DexFile::CodeItem* code_item) {
+ if (code_item != nullptr) {
+ DCHECK(dex_file->HasAddress(code_item));
+ DCHECK(dex_file != nullptr);
+ if (dex_file->IsCompactDexFile()) {
+ Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+ } else {
+ DCHECK(dex_file->IsStandardDexFile());
+ Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ }
}
}
@@ -54,9 +56,6 @@ inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(
Init(dex_file, code_item);
}
-inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(ArtMethod* method)
- : CodeItemInstructionAccessor(method->GetDexFile(), method->GetCodeItem()) {}
-
inline DexInstructionIterator CodeItemInstructionAccessor::begin() const {
return DexInstructionIterator(insns_, 0u);
}
@@ -65,17 +64,12 @@ inline DexInstructionIterator CodeItemInstructionAccessor::end() const {
return DexInstructionIterator(insns_, insns_size_in_code_units_);
}
-inline CodeItemInstructionAccessor CodeItemInstructionAccessor::CreateNullable(
- ArtMethod* method) {
- DCHECK(method != nullptr);
- CodeItemInstructionAccessor ret;
- const DexFile::CodeItem* code_item = method->GetCodeItem();
- if (code_item != nullptr) {
- ret.Init(method->GetDexFile(), code_item);
- } else {
- DCHECK(!ret.HasCodeItem()) << "Should be null initialized";
- }
- return ret;
+inline IterationRange<DexInstructionIterator> CodeItemInstructionAccessor::InstructionsFrom(
+ uint32_t start_dex_pc) const {
+ DCHECK_LT(start_dex_pc, InsnsSizeInCodeUnits());
+ return {
+ DexInstructionIterator(insns_, start_dex_pc),
+ DexInstructionIterator(insns_, insns_size_in_code_units_) };
}
inline void CodeItemDataAccessor::Init(const CompactDexFile::CodeItem& code_item) {
@@ -96,13 +90,14 @@ inline void CodeItemDataAccessor::Init(const StandardDexFile::CodeItem& code_ite
inline void CodeItemDataAccessor::Init(const DexFile* dex_file,
const DexFile::CodeItem* code_item) {
- DCHECK(dex_file != nullptr);
- DCHECK(code_item != nullptr);
- if (dex_file->IsCompactDexFile()) {
- CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
- } else {
- DCHECK(dex_file->IsStandardDexFile());
- CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ if (code_item != nullptr) {
+ DCHECK(dex_file != nullptr);
+ if (dex_file->IsCompactDexFile()) {
+ CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+ } else {
+ DCHECK(dex_file->IsStandardDexFile());
+ CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ }
}
}
@@ -111,26 +106,6 @@ inline CodeItemDataAccessor::CodeItemDataAccessor(const DexFile* dex_file,
Init(dex_file, code_item);
}
-inline CodeItemDataAccessor::CodeItemDataAccessor(ArtMethod* method)
- : CodeItemDataAccessor(method->GetDexFile(), method->GetCodeItem()) {}
-
-inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(
- const DexFile* dex_file,
- const DexFile::CodeItem* code_item) {
- CodeItemDataAccessor ret;
- if (code_item != nullptr) {
- ret.Init(dex_file, code_item);
- } else {
- DCHECK(!ret.HasCodeItem()) << "Should be null initialized";
- }
- return ret;
-}
-
-inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(ArtMethod* method) {
- DCHECK(method != nullptr);
- return CreateNullable(method->GetDexFile(), method->GetCodeItem());
-}
-
inline IterationRange<const DexFile::TryItem*> CodeItemDataAccessor::TryItems() const {
const DexFile::TryItem* try_items = DexFile::GetTryItems(end(), 0u);
return {
@@ -150,6 +125,42 @@ inline const DexFile::TryItem* CodeItemDataAccessor::FindTryItem(uint32_t try_de
return index != -1 ? &try_items.begin()[index] : nullptr;
}
+inline void CodeItemDebugInfoAccessor::Init(const DexFile* dex_file,
+ const DexFile::CodeItem* code_item,
+ uint32_t debug_info_offset) {
+ dex_file_ = dex_file;
+ debug_info_offset_ = debug_info_offset;
+ if (dex_file->IsCompactDexFile()) {
+ Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+ } else {
+ DCHECK(dex_file->IsStandardDexFile());
+ Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ }
+}
+
+inline void CodeItemDebugInfoAccessor::Init(const CompactDexFile::CodeItem& code_item) {
+ CodeItemDataAccessor::Init(code_item);
+}
+
+inline void CodeItemDebugInfoAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+ CodeItemDataAccessor::Init(code_item);
+}
+
+template<typename NewLocalCallback>
+inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo(bool is_static,
+ uint32_t method_idx,
+ NewLocalCallback new_local,
+ void* context) const {
+ return dex_file_->DecodeDebugLocalInfo(RegistersSize(),
+ InsSize(),
+ InsnsSizeInCodeUnits(),
+ DebugInfoOffset(),
+ is_static,
+ method_idx,
+ new_local,
+ context);
+}
+
} // namespace art
-#endif // ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_
+#endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_
diff --git a/runtime/code_item_accessors.h b/runtime/dex/code_item_accessors.h
index aa1305acad..65cc0bf996 100644
--- a/runtime/code_item_accessors.h
+++ b/runtime/dex/code_item_accessors.h
@@ -16,11 +16,11 @@
// TODO: Dex helpers have ART specific APIs, we may want to refactor these for use in dexdump.
-#ifndef ART_RUNTIME_CODE_ITEM_ACCESSORS_H_
-#define ART_RUNTIME_CODE_ITEM_ACCESSORS_H_
+#ifndef ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_H_
+#define ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_H_
#include "base/mutex.h"
-#include "cdex/compact_dex_file.h"
+#include "compact_dex_file.h"
#include "dex_file.h"
#include "dex_instruction_iterator.h"
#include "standard_dex_file.h"
@@ -42,6 +42,8 @@ class CodeItemInstructionAccessor {
ALWAYS_INLINE DexInstructionIterator end() const;
+ IterationRange<DexInstructionIterator> InstructionsFrom(uint32_t start_dex_pc) const;
+
uint32_t InsnsSizeInCodeUnits() const {
return insns_size_in_code_units_;
}
@@ -52,6 +54,7 @@ class CodeItemInstructionAccessor {
// Return the instruction for a dex pc.
const Instruction& InstructionAt(uint32_t dex_pc) const {
+ DCHECK_LT(dex_pc, InsnsSizeInCodeUnits());
return *Instruction::At(insns_ + dex_pc);
}
@@ -60,10 +63,6 @@ class CodeItemInstructionAccessor {
return Insns() != nullptr;
}
- // CreateNullable allows ArtMethods that have a null code item.
- ALWAYS_INLINE static CodeItemInstructionAccessor CreateNullable(ArtMethod* method)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
protected:
CodeItemInstructionAccessor() = default;
@@ -109,14 +108,6 @@ class CodeItemDataAccessor : public CodeItemInstructionAccessor {
const DexFile::TryItem* FindTryItem(uint32_t try_dex_pc) const;
- // CreateNullable allows ArtMethods that have a null code item.
- ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(ArtMethod* method)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(
- const DexFile* dex_file,
- const DexFile::CodeItem* code_item);
-
protected:
CodeItemDataAccessor() = default;
@@ -132,6 +123,48 @@ class CodeItemDataAccessor : public CodeItemInstructionAccessor {
uint16_t tries_size_;
};
+// Abstract accesses to code item data including debug info offset. More heavy weight than the other
+// helpers.
+class CodeItemDebugInfoAccessor : public CodeItemDataAccessor {
+ public:
+ CodeItemDebugInfoAccessor() = default;
+
+ // Handles null code items, but not null dex files.
+ ALWAYS_INLINE CodeItemDebugInfoAccessor(const DexFile* dex_file,
+ const DexFile::CodeItem* code_item);
+
+ // Initialize with an existing offset.
+ ALWAYS_INLINE CodeItemDebugInfoAccessor(const DexFile* dex_file,
+ const DexFile::CodeItem* code_item,
+ uint32_t debug_info_offset) {
+ Init(dex_file, code_item, debug_info_offset);
+ }
+
+ ALWAYS_INLINE void Init(const DexFile* dex_file,
+ const DexFile::CodeItem* code_item,
+ uint32_t debug_info_offset);
+
+ ALWAYS_INLINE explicit CodeItemDebugInfoAccessor(ArtMethod* method);
+
+ uint32_t DebugInfoOffset() const {
+ return debug_info_offset_;
+ }
+
+ template<typename NewLocalCallback>
+ bool DecodeDebugLocalInfo(bool is_static,
+ uint32_t method_idx,
+ NewLocalCallback new_local,
+ void* context) const;
+
+ protected:
+ ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
+ ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
+
+ private:
+ const DexFile* dex_file_ = nullptr;
+ uint32_t debug_info_offset_ = 0u;
+};
+
} // namespace art
-#endif // ART_RUNTIME_CODE_ITEM_ACCESSORS_H_
+#endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_H_
diff --git a/runtime/code_item_accessors_test.cc b/runtime/dex/code_item_accessors_test.cc
index ef5d246a54..57a5573d8d 100644
--- a/runtime/code_item_accessors_test.cc
+++ b/runtime/dex/code_item_accessors_test.cc
@@ -86,17 +86,17 @@ TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor) {
EXPECT_EQ(data_accessor.TriesSize(), kTriesSize);
};
- uint8_t buffer1[sizeof(CompactDexFile::CodeItem) + kInsnsSizeInCodeUnits * sizeof(uint16_t)] = {};
- CompactDexFile::CodeItem* dex_code_item = reinterpret_cast<CompactDexFile::CodeItem*>(buffer1);
+ StandardDexFile::CodeItem* dex_code_item =
+ reinterpret_cast<StandardDexFile::CodeItem*>(const_cast<uint8_t*>(standard_dex->Begin()));
dex_code_item->registers_size_ = kRegisterSize;
dex_code_item->ins_size_ = kInsSize;
dex_code_item->outs_size_ = kOutsSize;
dex_code_item->tries_size_ = kTriesSize;
dex_code_item->insns_size_in_code_units_ = kInsnsSizeInCodeUnits;
- verify_code_item(compact_dex.get(), dex_code_item, dex_code_item->insns_);
+ verify_code_item(standard_dex.get(), dex_code_item, dex_code_item->insns_);
- uint8_t buffer2[sizeof(CompactDexFile::CodeItem) + kInsnsSizeInCodeUnits * sizeof(uint16_t)] = {};
- CompactDexFile::CodeItem* cdex_code_item = reinterpret_cast<CompactDexFile::CodeItem*>(buffer2);
+ CompactDexFile::CodeItem* cdex_code_item =
+ reinterpret_cast<CompactDexFile::CodeItem*>(const_cast<uint8_t*>(compact_dex->Begin()));
cdex_code_item->registers_size_ = kRegisterSize;
cdex_code_item->ins_size_ = kInsSize;
cdex_code_item->outs_size_ = kOutsSize;
diff --git a/runtime/dex/compact_dex_file.cc b/runtime/dex/compact_dex_file.cc
new file mode 100644
index 0000000000..8f90e098bb
--- /dev/null
+++ b/runtime/dex/compact_dex_file.cc
@@ -0,0 +1,90 @@
+/*
+ * 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 "compact_dex_file.h"
+
+#include "dex_file-inl.h"
+#include "leb128.h"
+
+namespace art {
+
+constexpr uint8_t CompactDexFile::kDexMagic[kDexMagicSize];
+constexpr uint8_t CompactDexFile::kDexMagicVersion[];
+
+void CompactDexFile::WriteMagic(uint8_t* magic) {
+ std::copy_n(kDexMagic, kDexMagicSize, magic);
+}
+
+void CompactDexFile::WriteCurrentVersion(uint8_t* magic) {
+ std::copy_n(kDexMagicVersion, kDexVersionLen, magic + kDexMagicSize);
+}
+
+bool CompactDexFile::IsMagicValid(const uint8_t* magic) {
+ return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0);
+}
+
+bool CompactDexFile::IsVersionValid(const uint8_t* magic) {
+ const uint8_t* version = &magic[sizeof(kDexMagic)];
+ return memcmp(version, kDexMagicVersion, kDexVersionLen) == 0;
+}
+
+bool CompactDexFile::IsMagicValid() const {
+ return IsMagicValid(header_->magic_);
+}
+
+bool CompactDexFile::IsVersionValid() const {
+ return IsVersionValid(header_->magic_);
+}
+
+bool CompactDexFile::SupportsDefaultMethods() const {
+ return (GetHeader().GetFeatureFlags() &
+ static_cast<uint32_t>(FeatureFlags::kDefaultMethods)) != 0;
+}
+
+uint32_t CompactDexFile::GetCodeItemSize(const DexFile::CodeItem& item) const {
+ // TODO: Clean up this temporary code duplication with StandardDexFile. Eventually the
+ // implementations will differ.
+ DCHECK(HasAddress(&item));
+ const CodeItem& code_item = down_cast<const CodeItem&>(item);
+ uintptr_t code_item_start = reinterpret_cast<uintptr_t>(&code_item);
+ uint32_t insns_size = code_item.insns_size_in_code_units_;
+ uint32_t tries_size = code_item.tries_size_;
+ const uint8_t* handler_data = GetCatchHandlerData(
+ DexInstructionIterator(code_item.insns_, code_item.insns_size_in_code_units_),
+ code_item.tries_size_,
+ 0);
+
+ if (tries_size == 0 || handler_data == nullptr) {
+ uintptr_t insns_end = reinterpret_cast<uintptr_t>(&code_item.insns_[insns_size]);
+ return insns_end - code_item_start;
+ } else {
+ // Get the start of the handler data.
+ uint32_t handlers_size = DecodeUnsignedLeb128(&handler_data);
+ // Manually read each handler.
+ for (uint32_t i = 0; i < handlers_size; ++i) {
+ int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2;
+ if (uleb128_count <= 0) {
+ uleb128_count = -uleb128_count + 1;
+ }
+ for (int32_t j = 0; j < uleb128_count; ++j) {
+ DecodeUnsignedLeb128(&handler_data);
+ }
+ }
+ return reinterpret_cast<uintptr_t>(handler_data) - code_item_start;
+ }
+}
+
+} // namespace art
diff --git a/runtime/cdex/compact_dex_file.h b/runtime/dex/compact_dex_file.h
index f17f8cf68a..280c6f70cc 100644
--- a/runtime/cdex/compact_dex_file.h
+++ b/runtime/dex/compact_dex_file.h
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_CDEX_COMPACT_DEX_FILE_H_
-#define ART_RUNTIME_CDEX_COMPACT_DEX_FILE_H_
+#ifndef ART_RUNTIME_DEX_COMPACT_DEX_FILE_H_
+#define ART_RUNTIME_DEX_COMPACT_DEX_FILE_H_
+#include "base/casts.h"
#include "dex_file.h"
namespace art {
@@ -27,13 +28,26 @@ class CompactDexFile : public DexFile {
static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' };
static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'};
+ enum class FeatureFlags : uint32_t {
+ kDefaultMethods = 0x1,
+ };
+
class Header : public DexFile::Header {
- // Same for now.
+ public:
+ uint32_t GetFeatureFlags() const {
+ return feature_flags_;
+ }
+
+ private:
+ uint32_t feature_flags_ = 0u;
+
+ friend class CompactDexWriter;
};
struct CodeItem : public DexFile::CodeItem {
private:
// TODO: Insert compact dex specific fields here.
+ friend class CompactDexFile;
DISALLOW_COPY_AND_ASSIGN(CodeItem);
};
@@ -51,6 +65,14 @@ class CompactDexFile : public DexFile {
static bool IsVersionValid(const uint8_t* magic);
virtual bool IsVersionValid() const OVERRIDE;
+ const Header& GetHeader() const {
+ return down_cast<const Header&>(DexFile::GetHeader());
+ }
+
+ virtual bool SupportsDefaultMethods() const OVERRIDE;
+
+ uint32_t GetCodeItemSize(const DexFile::CodeItem& item) const OVERRIDE;
+
private:
// Not supported yet.
CompactDexFile(const uint8_t* base,
@@ -75,4 +97,4 @@ class CompactDexFile : public DexFile {
} // namespace art
-#endif // ART_RUNTIME_CDEX_COMPACT_DEX_FILE_H_
+#endif // ART_RUNTIME_DEX_COMPACT_DEX_FILE_H_
diff --git a/runtime/cdex/compact_dex_file_test.cc b/runtime/dex/compact_dex_file_test.cc
index b43b35d69a..d665dc994b 100644
--- a/runtime/cdex/compact_dex_file_test.cc
+++ b/runtime/dex/compact_dex_file_test.cc
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#include "cdex/compact_dex_file.h"
-#include "dex_file_loader.h"
#include "common_runtime_test.h"
+#include "compact_dex_file.h"
+#include "dex_file_loader.h"
namespace art {
diff --git a/runtime/dex/compact_dex_level.h b/runtime/dex/compact_dex_level.h
new file mode 100644
index 0000000000..de9ca3c783
--- /dev/null
+++ b/runtime/dex/compact_dex_level.h
@@ -0,0 +1,50 @@
+/*
+ * 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_COMPACT_DEX_LEVEL_H_
+#define ART_RUNTIME_DEX_COMPACT_DEX_LEVEL_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "dex_file.h"
+
+namespace art {
+
+// Optimization level for compact dex generation.
+enum class CompactDexLevel {
+ // Level none means not generated.
+ kCompactDexLevelNone,
+ // Level fast means optimizations that don't take many resources to perform.
+ kCompactDexLevelFast,
+};
+
+#ifndef ART_DEFAULT_COMPACT_DEX_LEVEL
+#error ART_DEFAULT_COMPACT_DEX_LEVEL not specified.
+#else
+#define ART_DEFAULT_COMPACT_DEX_LEVEL_VALUE_fast CompactDexLevel::kCompactDexLevelFast
+#define ART_DEFAULT_COMPACT_DEX_LEVEL_VALUE_none CompactDexLevel::kCompactDexLevelNone
+
+#define ART_DEFAULT_COMPACT_DEX_LEVEL_DEFAULT APPEND_TOKENS_AFTER_EVAL( \
+ ART_DEFAULT_COMPACT_DEX_LEVEL_VALUE_, \
+ ART_DEFAULT_COMPACT_DEX_LEVEL)
+
+static constexpr CompactDexLevel kDefaultCompactDexLevel = ART_DEFAULT_COMPACT_DEX_LEVEL_DEFAULT;
+#endif
+
+} // namespace art
+
+#endif // ART_RUNTIME_DEX_COMPACT_DEX_LEVEL_H_
diff --git a/runtime/dex_file-inl.h b/runtime/dex/dex_file-inl.h
index 18809683cc..9b56328a71 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex/dex_file-inl.h
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_FILE_INL_H_
-#define ART_RUNTIME_DEX_FILE_INL_H_
+#ifndef ART_RUNTIME_DEX_DEX_FILE_INL_H_
+#define ART_RUNTIME_DEX_DEX_FILE_INL_H_
#include "base/bit_utils.h"
#include "base/casts.h"
-#include "base/logging.h"
#include "base/stringpiece.h"
-#include "cdex/compact_dex_file.h"
+#include "compact_dex_file.h"
#include "dex_file.h"
#include "invoke_type.h"
#include "leb128.h"
@@ -134,10 +133,6 @@ inline const char* DexFile::GetShorty(uint32_t proto_idx) const {
return StringDataByIdx(proto_id.shorty_idx_);
}
-inline const DexFile::TryItem* DexFile::GetTryItems(const CodeItem& code_item, uint32_t offset) {
- return GetTryItems(code_item.Instructions().end(), offset);
-}
-
inline const DexFile::TryItem* DexFile::GetTryItems(const DexInstructionIterator& code_item_end,
uint32_t offset) {
return reinterpret_cast<const TryItem*>
@@ -385,13 +380,16 @@ bool DexFile::DecodeDebugLocalInfo(const uint8_t* stream,
}
template<typename NewLocalCallback>
-bool DexFile::DecodeDebugLocalInfo(const CodeItem* code_item,
+bool DexFile::DecodeDebugLocalInfo(uint32_t registers_size,
+ uint32_t ins_size,
+ uint32_t insns_size_in_code_units,
uint32_t debug_info_offset,
bool is_static,
uint32_t method_idx,
NewLocalCallback new_local_callback,
void* context) const {
- if (code_item == nullptr) {
+ const uint8_t* const stream = GetDebugInfoStream(debug_info_offset);
+ if (stream == nullptr) {
return false;
}
std::vector<const char*> arg_descriptors;
@@ -399,15 +397,15 @@ bool DexFile::DecodeDebugLocalInfo(const CodeItem* code_item,
for (; it.HasNext(); it.Next()) {
arg_descriptors.push_back(it.GetDescriptor());
}
- return DecodeDebugLocalInfo(GetDebugInfoStream(debug_info_offset),
+ return DecodeDebugLocalInfo(stream,
GetLocation(),
GetMethodDeclaringClassDescriptor(GetMethodId(method_idx)),
arg_descriptors,
this->PrettyMethod(method_idx),
is_static,
- code_item->registers_size_,
- code_item->ins_size_,
- code_item->insns_size_in_code_units_,
+ registers_size,
+ ins_size,
+ insns_size_in_code_units,
[this](uint32_t idx) {
return StringDataByIdx(dex::StringIndex(idx));
},
@@ -488,13 +486,9 @@ bool DexFile::DecodeDebugPositionInfo(const uint8_t* stream,
}
template<typename DexDebugNewPosition>
-bool DexFile::DecodeDebugPositionInfo(const CodeItem* code_item,
- uint32_t debug_info_offset,
+bool DexFile::DecodeDebugPositionInfo(uint32_t debug_info_offset,
DexDebugNewPosition position_functor,
void* context) const {
- if (code_item == nullptr) {
- return false;
- }
return DecodeDebugPositionInfo(GetDebugInfoStream(debug_info_offset),
[this](uint32_t idx) {
return StringDataByIdx(dex::StringIndex(idx));
@@ -513,6 +507,15 @@ inline const StandardDexFile* DexFile::AsStandardDexFile() const {
return down_cast<const StandardDexFile*>(this);
}
+// Get the base of the encoded data for the given DexCode.
+inline const uint8_t* DexFile::GetCatchHandlerData(const DexInstructionIterator& code_item_end,
+ uint32_t tries_size,
+ uint32_t offset) {
+ const uint8_t* handler_data =
+ reinterpret_cast<const uint8_t*>(GetTryItems(code_item_end, tries_size));
+ return handler_data + offset;
+}
+
} // namespace art
-#endif // ART_RUNTIME_DEX_FILE_INL_H_
+#endif // ART_RUNTIME_DEX_DEX_FILE_INL_H_
diff --git a/runtime/dex_file.cc b/runtime/dex/dex_file.cc
index af79207834..16325b83f6 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex/dex_file.cc
@@ -29,7 +29,6 @@
#include "android-base/stringprintf.h"
#include "base/enums.h"
-#include "base/logging.h"
#include "base/stl_util.h"
#include "dex_file-inl.h"
#include "leb128.h"
@@ -47,9 +46,13 @@ static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wro
static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
uint32_t DexFile::CalculateChecksum() const {
+ return CalculateChecksum(Begin(), Size());
+}
+
+uint32_t DexFile::CalculateChecksum(const uint8_t* begin, size_t size) {
const uint32_t non_sum = OFFSETOF_MEMBER(DexFile::Header, signature_);
- const uint8_t* non_sum_ptr = Begin() + non_sum;
- return adler32(adler32(0L, Z_NULL, 0), non_sum_ptr, Size() - non_sum);
+ const uint8_t* non_sum_ptr = begin + non_sum;
+ return adler32(adler32(0L, Z_NULL, 0), non_sum_ptr, size - non_sum);
}
int DexFile::GetPermissions() const {
@@ -214,32 +217,6 @@ uint32_t DexFile::FindCodeItemOffset(const DexFile::ClassDef& class_def,
UNREACHABLE();
}
-uint32_t DexFile::GetCodeItemSize(const DexFile::CodeItem& code_item) {
- uintptr_t code_item_start = reinterpret_cast<uintptr_t>(&code_item);
- uint32_t insns_size = code_item.insns_size_in_code_units_;
- uint32_t tries_size = code_item.tries_size_;
- const uint8_t* handler_data = GetCatchHandlerData(code_item, 0);
-
- if (tries_size == 0 || handler_data == nullptr) {
- uintptr_t insns_end = reinterpret_cast<uintptr_t>(&code_item.insns_[insns_size]);
- return insns_end - code_item_start;
- } else {
- // Get the start of the handler data.
- uint32_t handlers_size = DecodeUnsignedLeb128(&handler_data);
- // Manually read each handler.
- for (uint32_t i = 0; i < handlers_size; ++i) {
- int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2;
- if (uleb128_count <= 0) {
- uleb128_count = -uleb128_count + 1;
- }
- for (int32_t j = 0; j < uleb128_count; ++j) {
- DecodeUnsignedLeb128(&handler_data);
- }
- }
- return reinterpret_cast<uintptr_t>(handler_data) - code_item_start;
- }
-}
-
const DexFile::FieldId* DexFile::FindFieldId(const DexFile::TypeId& declaring_klass,
const DexFile::StringId& name,
const DexFile::TypeId& type) const {
@@ -508,11 +485,6 @@ int32_t DexFile::FindTryItem(const TryItem* try_items, uint32_t tries_size, uint
return -1;
}
-int32_t DexFile::FindCatchHandlerOffset(const CodeItem &code_item, uint32_t address) {
- int32_t try_item = FindTryItem(GetTryItems(code_item, 0), code_item.tries_size_, address);
- return (try_item == -1) ? -1 : DexFile::GetTryItems(code_item, try_item)->handler_off_;
-}
-
bool DexFile::LineNumForPcCb(void* raw_context, const PositionInfo& entry) {
LineNumFromPcContext* context = reinterpret_cast<LineNumFromPcContext*>(raw_context);
@@ -799,85 +771,6 @@ void EncodedArrayValueIterator::Next() {
ptr_ += width;
}
-CatchHandlerIterator::CatchHandlerIterator(const DexFile::CodeItem& code_item, uint32_t address) {
- handler_.address_ = -1;
- int32_t offset = -1;
-
- // Short-circuit the overwhelmingly common cases.
- switch (code_item.tries_size_) {
- case 0:
- break;
- case 1: {
- const DexFile::TryItem* tries = DexFile::GetTryItems(code_item, 0);
- uint32_t start = tries->start_addr_;
- if (address >= start) {
- uint32_t end = start + tries->insn_count_;
- if (address < end) {
- offset = tries->handler_off_;
- }
- }
- break;
- }
- default:
- offset = DexFile::FindCatchHandlerOffset(code_item, address);
- }
- Init(code_item, offset);
-}
-
-CatchHandlerIterator::CatchHandlerIterator(const DexFile::CodeItem& code_item,
- const DexFile::TryItem& try_item) {
- handler_.address_ = -1;
- Init(code_item, try_item.handler_off_);
-}
-
-void CatchHandlerIterator::Init(const DexFile::CodeItem& code_item,
- int32_t offset) {
- if (offset >= 0) {
- Init(DexFile::GetCatchHandlerData(code_item, offset));
- } else {
- // Not found, initialize as empty
- current_data_ = nullptr;
- remaining_count_ = -1;
- catch_all_ = false;
- DCHECK(!HasNext());
- }
-}
-
-void CatchHandlerIterator::Init(const uint8_t* handler_data) {
- current_data_ = handler_data;
- remaining_count_ = DecodeSignedLeb128(&current_data_);
-
- // If remaining_count_ is non-positive, then it is the negative of
- // the number of catch types, and the catches are followed by a
- // catch-all handler.
- if (remaining_count_ <= 0) {
- catch_all_ = true;
- remaining_count_ = -remaining_count_;
- } else {
- catch_all_ = false;
- }
- Next();
-}
-
-void CatchHandlerIterator::Next() {
- if (remaining_count_ > 0) {
- handler_.type_idx_ = dex::TypeIndex(DecodeUnsignedLeb128(&current_data_));
- handler_.address_ = DecodeUnsignedLeb128(&current_data_);
- remaining_count_--;
- return;
- }
-
- if (catch_all_) {
- handler_.type_idx_ = dex::TypeIndex(DexFile::kDexNoIndex16);
- handler_.address_ = DecodeUnsignedLeb128(&current_data_);
- catch_all_ = false;
- return;
- }
-
- // no more handler
- remaining_count_ = -1;
-}
-
namespace dex {
std::ostream& operator<<(std::ostream& os, const StringIndex& index) {
diff --git a/runtime/dex_file.h b/runtime/dex/dex_file.h
index 944a30849f..c2a36ce01a 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex/dex_file.h
@@ -14,15 +14,17 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_FILE_H_
-#define ART_RUNTIME_DEX_FILE_H_
+#ifndef ART_RUNTIME_DEX_DEX_FILE_H_
+#define ART_RUNTIME_DEX_DEX_FILE_H_
#include <memory>
#include <string>
#include <vector>
+#include <android-base/logging.h>
+
#include "base/iteration_range.h"
-#include "base/logging.h"
+#include "base/macros.h"
#include "base/value_object.h"
#include "dex_file_types.h"
#include "dex_instruction_iterator.h"
@@ -67,8 +69,6 @@ class DexFile {
static constexpr size_t kDexMagicSize = 4;
static constexpr size_t kDexVersionLen = 4;
- // First Dex format version supporting default methods.
- static const uint32_t kDefaultMethodsVersion = 37;
// First Dex format version enforcing class definition ordering rules.
static const uint32_t kClassDefinitionOrderEnforcedVersion = 37;
@@ -303,21 +303,16 @@ class DexFile {
// Raw code_item.
struct CodeItem {
- IterationRange<DexInstructionIterator> Instructions(uint32_t start_dex_pc = 0u) const {
- DCHECK_LE(start_dex_pc, insns_size_in_code_units_);
- return { DexInstructionIterator(insns_, start_dex_pc),
- DexInstructionIterator(insns_, insns_size_in_code_units_) };
- }
-
- const Instruction& InstructionAt(uint32_t dex_pc) const {
- return *Instruction::At(insns_ + dex_pc);
- }
-
// Used when quickening / unquickening.
void SetDebugInfoOffset(uint32_t new_offset) {
debug_info_off_ = new_offset;
}
+ uint32_t GetDebugInfoOffset() const {
+ return debug_info_off_;
+ }
+
+ protected:
uint16_t registers_size_; // the number of registers used by this code
// (locals + parameters)
uint16_t ins_size_; // the number of words of incoming arguments to the method
@@ -338,6 +333,11 @@ class DexFile {
uint16_t insns_[1]; // actual array of bytecode.
private:
+ ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
+ friend class CodeItemDataAccessor;
+ friend class CodeItemDebugInfoAccessor;
+ friend class CodeItemInstructionAccessor;
+ friend class VdexFile; // TODO: Remove this one when it's cleaned up.
DISALLOW_COPY_AND_ASSIGN(CodeItem);
};
@@ -472,7 +472,7 @@ class DexFile {
}
// Decode the dex magic version
- uint32_t GetVersion() const {
+ uint32_t GetDexVersion() const {
return GetHeader().GetVersion();
}
@@ -482,6 +482,9 @@ class DexFile {
// Returns true if the byte string after the magic is the correct value.
virtual bool IsVersionValid() const = 0;
+ // Returns true if the dex file supports default methods.
+ virtual bool SupportsDefaultMethods() const = 0;
+
// Returns the number of string identifiers in the .dex file.
size_t NumStringIds() const {
DCHECK(header_ != nullptr) << GetLocation();
@@ -583,7 +586,7 @@ class DexFile {
uint32_t FindCodeItemOffset(const DexFile::ClassDef& class_def,
uint32_t dex_method_idx) const;
- static uint32_t GetCodeItemSize(const DexFile::CodeItem& disk_code_item);
+ virtual uint32_t GetCodeItemSize(const DexFile::CodeItem& disk_code_item) const = 0;
// Returns the declaring class descriptor string of a field id.
const char* GetFieldDeclaringClassDescriptor(const FieldId& field_id) const {
@@ -715,7 +718,7 @@ class DexFile {
}
CHECK(oat_dex_file_ == nullptr)
<< "Should only use GetDebugInfoOffset in a non runtime setup";
- return code_item->debug_info_off_;
+ return code_item->GetDebugInfoOffset();
}
const char* GetReturnTypeDescriptor(const ProtoId& proto_id) const;
@@ -774,26 +777,15 @@ class DexFile {
}
static const TryItem* GetTryItems(const DexInstructionIterator& code_item_end, uint32_t offset);
- static const TryItem* GetTryItems(const CodeItem& code_item, uint32_t offset);
// Get the base of the encoded data for the given DexCode.
static const uint8_t* GetCatchHandlerData(const DexInstructionIterator& code_item_end,
uint32_t tries_size,
- uint32_t offset) {
- const uint8_t* handler_data =
- reinterpret_cast<const uint8_t*>(GetTryItems(code_item_end, tries_size));
- return handler_data + offset;
- }
- static const uint8_t* GetCatchHandlerData(const CodeItem& code_item, uint32_t offset) {
- return GetCatchHandlerData(code_item.Instructions().end(), code_item.tries_size_, offset);
- }
+ uint32_t offset);
// Find which try region is associated with the given address (ie dex pc). Returns -1 if none.
static int32_t FindTryItem(const TryItem* try_items, uint32_t tries_size, uint32_t address);
- // Find the handler offset associated with the given address (ie dex pc). Returns -1 if none.
- static int32_t FindCatchHandlerOffset(const CodeItem &code_item, uint32_t address);
-
// Get the pointer to the start of the debugging data
const uint8_t* GetDebugInfoStream(uint32_t debug_info_off) const {
// Check that the offset is in bounds.
@@ -954,7 +946,9 @@ class DexFile {
NewLocalCallback new_local,
void* context);
template<typename NewLocalCallback>
- bool DecodeDebugLocalInfo(const CodeItem* code_item,
+ bool DecodeDebugLocalInfo(uint32_t registers_size,
+ uint32_t ins_size,
+ uint32_t insns_size_in_code_units,
uint32_t debug_info_offset,
bool is_static,
uint32_t method_idx,
@@ -968,8 +962,7 @@ class DexFile {
DexDebugNewPosition position_functor,
void* context);
template<typename DexDebugNewPosition>
- bool DecodeDebugPositionInfo(const CodeItem* code_item,
- uint32_t debug_info_offset,
+ bool DecodeDebugPositionInfo(uint32_t debug_info_offset,
DexDebugNewPosition position_functor,
void* context) const;
@@ -1014,6 +1007,7 @@ class DexFile {
// Recalculates the checksum of the dex file. Does not use the current value in the header.
uint32_t CalculateChecksum() const;
+ static uint32_t CalculateChecksum(const uint8_t* begin, size_t size);
// Returns a human-readable form of the method at an index.
std::string PrettyMethod(uint32_t method_idx, bool with_signature = true) const;
@@ -1032,7 +1026,14 @@ class DexFile {
ALWAYS_INLINE const StandardDexFile* AsStandardDexFile() const;
ALWAYS_INLINE const CompactDexFile* AsCompactDexFile() const;
+ bool HasAddress(const void* addr) const {
+ return Begin() <= addr && addr < Begin() + Size();
+ }
+
protected:
+ // First Dex format version supporting default methods.
+ static const uint32_t kDefaultMethodsVersion = 37;
+
DexFile(const uint8_t* base,
size_t size,
const std::string& location,
@@ -1453,47 +1454,6 @@ class CallSiteArrayValueIterator : public EncodedArrayValueIterator {
};
std::ostream& operator<<(std::ostream& os, const CallSiteArrayValueIterator::ValueType& code);
-class CatchHandlerIterator {
- public:
- CatchHandlerIterator(const DexFile::CodeItem& code_item, uint32_t address);
-
- CatchHandlerIterator(const DexFile::CodeItem& code_item,
- const DexFile::TryItem& try_item);
-
- explicit CatchHandlerIterator(const uint8_t* handler_data) {
- Init(handler_data);
- }
-
- dex::TypeIndex GetHandlerTypeIndex() const {
- return handler_.type_idx_;
- }
- uint32_t GetHandlerAddress() const {
- return handler_.address_;
- }
- void Next();
- bool HasNext() const {
- return remaining_count_ != -1 || catch_all_;
- }
- // End of this set of catch blocks, convenience method to locate next set of catch blocks
- const uint8_t* EndDataPointer() const {
- CHECK(!HasNext());
- return current_data_;
- }
-
- private:
- void Init(const DexFile::CodeItem& code_item, int32_t offset);
- void Init(const uint8_t* handler_data);
-
- struct CatchHandlerItem {
- dex::TypeIndex type_idx_; // type index of the caught exception type
- uint32_t address_; // handler address
- } handler_;
- const uint8_t* current_data_; // the current handler in dex file.
- int32_t remaining_count_; // number of handlers not read.
- bool catch_all_; // is there a handler that will catch all exceptions in case
- // that all typed handler does not match.
-};
-
} // namespace art
-#endif // ART_RUNTIME_DEX_FILE_H_
+#endif // ART_RUNTIME_DEX_DEX_FILE_H_
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index b44bd51643..72b18fb420 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -343,8 +343,7 @@ mirror::Object* ProcessEncodedAnnotation(const ClassData& klass, const uint8_t**
StackHandleScope<4> hs(self);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Handle<mirror::Class> annotation_class(hs.NewHandle(
- class_linker->ResolveType(klass.GetDexFile(),
- dex::TypeIndex(type_index),
+ class_linker->ResolveType(dex::TypeIndex(type_index),
hs.NewHandle(klass.GetDexCache()),
hs.NewHandle(klass.GetClassLoader()))));
if (annotation_class == nullptr) {
@@ -458,7 +457,7 @@ bool ProcessAnnotationValue(const ClassData& klass,
} else {
StackHandleScope<1> hs(self);
element_object = Runtime::Current()->GetClassLinker()->ResolveString(
- klass.GetDexFile(), dex::StringIndex(index), hs.NewHandle(klass.GetDexCache()));
+ dex::StringIndex(index), hs.NewHandle(klass.GetDexCache()));
set_object = true;
if (element_object == nullptr) {
return false;
@@ -474,7 +473,6 @@ bool ProcessAnnotationValue(const ClassData& klass,
dex::TypeIndex type_index(index);
StackHandleScope<2> hs(self);
element_object = Runtime::Current()->GetClassLinker()->ResolveType(
- klass.GetDexFile(),
type_index,
hs.NewHandle(klass.GetDexCache()),
hs.NewHandle(klass.GetClassLoader()));
@@ -501,7 +499,6 @@ bool ProcessAnnotationValue(const ClassData& klass,
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<2> hs(self);
ArtMethod* method = class_linker->ResolveMethodWithoutInvokeType(
- klass.GetDexFile(),
index,
hs.NewHandle(klass.GetDexCache()),
hs.NewHandle(klass.GetClassLoader()));
@@ -540,7 +537,6 @@ bool ProcessAnnotationValue(const ClassData& klass,
} else {
StackHandleScope<2> hs(self);
ArtField* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(
- klass.GetDexFile(),
index,
hs.NewHandle(klass.GetDexCache()),
hs.NewHandle(klass.GetClassLoader()));
@@ -569,7 +565,6 @@ bool ProcessAnnotationValue(const ClassData& klass,
} else {
StackHandleScope<3> hs(self);
ArtField* enum_field = Runtime::Current()->GetClassLinker()->ResolveField(
- klass.GetDexFile(),
index,
hs.NewHandle(klass.GetDexCache()),
hs.NewHandle(klass.GetClassLoader()),
@@ -783,10 +778,8 @@ const DexFile::AnnotationItem* GetAnnotationItemFromAnnotationSet(
uint32_t type_index = DecodeUnsignedLeb128(&annotation);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Thread* self = Thread::Current();
- mirror::Class* resolved_class;
StackHandleScope<2> hs(self);
- resolved_class = class_linker->ResolveType(
- klass.GetDexFile(),
+ ObjPtr<mirror::Class> resolved_class = class_linker->ResolveType(
dex::TypeIndex(type_index),
hs.NewHandle(klass.GetDexCache()),
hs.NewHandle(klass.GetClassLoader()));
@@ -1401,7 +1394,6 @@ mirror::Class* GetEnclosingClass(Handle<mirror::Class> klass) {
}
StackHandleScope<2> hs(Thread::Current());
ArtMethod* method = Runtime::Current()->GetClassLinker()->ResolveMethodWithoutInvokeType(
- data.GetDexFile(),
annotation_value.value_.GetI(),
hs.NewHandle(data.GetDexCache()),
hs.NewHandle(data.GetClassLoader()));
@@ -1567,21 +1559,18 @@ int32_t GetLineNumFromPC(const DexFile* dex_file, ArtMethod* method, uint32_t re
return -2;
}
- const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
- DCHECK(code_item != nullptr) << method->PrettyMethod() << " " << dex_file->GetLocation();
+ CodeItemDebugInfoAccessor accessor(method);
+ DCHECK(accessor.HasCodeItem()) << method->PrettyMethod() << " " << dex_file->GetLocation();
// A method with no line number info should return -1
DexFile::LineNumFromPcContext context(rel_pc, -1);
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex_file, code_item);
- dex_file->DecodeDebugPositionInfo(
- code_item, debug_info_offset, DexFile::LineNumForPcCb, &context);
+ dex_file->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), DexFile::LineNumForPcCb, &context);
return context.line_num_;
}
template<bool kTransactionActive>
void RuntimeEncodedStaticFieldValueIterator::ReadValueToField(ArtField* field) const {
DCHECK(dex_cache_ != nullptr);
- DCHECK(class_loader_ != nullptr);
switch (type_) {
case kBoolean: field->SetBoolean<kTransactionActive>(field->GetDeclaringClass(), jval_.z);
break;
@@ -1594,17 +1583,15 @@ void RuntimeEncodedStaticFieldValueIterator::ReadValueToField(ArtField* field) c
case kDouble: field->SetDouble<kTransactionActive>(field->GetDeclaringClass(), jval_.d); break;
case kNull: field->SetObject<kTransactionActive>(field->GetDeclaringClass(), nullptr); break;
case kString: {
- mirror::String* resolved = linker_->ResolveString(dex_file_,
- dex::StringIndex(jval_.i),
- *dex_cache_);
+ ObjPtr<mirror::String> resolved = linker_->ResolveString(dex::StringIndex(jval_.i),
+ dex_cache_);
field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
break;
}
case kType: {
- mirror::Class* resolved = linker_->ResolveType(dex_file_,
- dex::TypeIndex(jval_.i),
- *dex_cache_,
- *class_loader_);
+ ObjPtr<mirror::Class> resolved = linker_->ResolveType(dex::TypeIndex(jval_.i),
+ dex_cache_,
+ class_loader_);
field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
break;
}
diff --git a/runtime/dex_file_annotations.h b/runtime/dex/dex_file_annotations.h
index a934a4f99c..26773729c2 100644
--- a/runtime/dex_file_annotations.h
+++ b/runtime/dex/dex_file_annotations.h
@@ -14,23 +14,23 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_FILE_ANNOTATIONS_H_
-#define ART_RUNTIME_DEX_FILE_ANNOTATIONS_H_
+#ifndef ART_RUNTIME_DEX_DEX_FILE_ANNOTATIONS_H_
+#define ART_RUNTIME_DEX_DEX_FILE_ANNOTATIONS_H_
#include "dex_file.h"
+#include "handle.h"
+#include "mirror/dex_cache.h"
#include "mirror/object_array.h"
namespace art {
namespace mirror {
class ClassLoader;
-class DexCache;
} // namespace mirror
class ArtField;
class ArtMethod;
class ClassLinker;
-template<class T> class MutableHandle;
namespace annotations {
@@ -116,13 +116,12 @@ int32_t GetLineNumFromPC(const DexFile* dex_file, ArtMethod* method, uint32_t re
class RuntimeEncodedStaticFieldValueIterator : public EncodedStaticFieldValueIterator {
public:
// A constructor meant to be called from runtime code.
- RuntimeEncodedStaticFieldValueIterator(const DexFile& dex_file,
- Handle<mirror::DexCache>* dex_cache,
- Handle<mirror::ClassLoader>* class_loader,
+ RuntimeEncodedStaticFieldValueIterator(Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
ClassLinker* linker,
const DexFile::ClassDef& class_def)
REQUIRES_SHARED(Locks::mutator_lock_)
- : EncodedStaticFieldValueIterator(dex_file, class_def),
+ : EncodedStaticFieldValueIterator(*dex_cache->GetDexFile(), class_def),
dex_cache_(dex_cache),
class_loader_(class_loader),
linker_(linker) {
@@ -132,9 +131,9 @@ class RuntimeEncodedStaticFieldValueIterator : public EncodedStaticFieldValueIte
void ReadValueToField(ArtField* field) const REQUIRES_SHARED(Locks::mutator_lock_);
private:
- Handle<mirror::DexCache>* const dex_cache_; // Dex cache to resolve literal objects.
- Handle<mirror::ClassLoader>* const class_loader_; // ClassLoader to resolve types.
- ClassLinker* linker_; // Linker to resolve literal objects.
+ const Handle<mirror::DexCache> dex_cache_; // Dex cache to resolve literal objects.
+ const Handle<mirror::ClassLoader> class_loader_; // ClassLoader to resolve types.
+ ClassLinker* const linker_; // Linker to resolve literal objects.
DISALLOW_IMPLICIT_CONSTRUCTORS(RuntimeEncodedStaticFieldValueIterator);
};
@@ -142,4 +141,4 @@ class RuntimeEncodedStaticFieldValueIterator : public EncodedStaticFieldValueIte
} // namespace art
-#endif // ART_RUNTIME_DEX_FILE_ANNOTATIONS_H_
+#endif // ART_RUNTIME_DEX_DEX_FILE_ANNOTATIONS_H_
diff --git a/runtime/dex/dex_file_exception_helpers.cc b/runtime/dex/dex_file_exception_helpers.cc
new file mode 100644
index 0000000000..ad56eb0a0b
--- /dev/null
+++ b/runtime/dex/dex_file_exception_helpers.cc
@@ -0,0 +1,104 @@
+/*
+ * 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_exception_helpers.h"
+
+#include "code_item_accessors-no_art-inl.h"
+
+namespace art {
+
+CatchHandlerIterator::CatchHandlerIterator(const CodeItemDataAccessor& accessor, uint32_t address) {
+ handler_.address_ = -1;
+ int32_t offset = -1;
+
+ // Short-circuit the overwhelmingly common cases.
+ switch (accessor.TriesSize()) {
+ case 0:
+ break;
+ case 1: {
+ const DexFile::TryItem* tries = accessor.TryItems().begin();
+ uint32_t start = tries->start_addr_;
+ if (address >= start) {
+ uint32_t end = start + tries->insn_count_;
+ if (address < end) {
+ offset = tries->handler_off_;
+ }
+ }
+ break;
+ }
+ default: {
+ const DexFile::TryItem* try_item = accessor.FindTryItem(address);
+ offset = try_item != nullptr ? try_item->handler_off_ : -1;
+ break;
+ }
+ }
+ Init(accessor, offset);
+}
+
+CatchHandlerIterator::CatchHandlerIterator(const CodeItemDataAccessor& accessor,
+ const DexFile::TryItem& try_item) {
+ handler_.address_ = -1;
+ Init(accessor, try_item.handler_off_);
+}
+
+void CatchHandlerIterator::Init(const CodeItemDataAccessor& accessor, int32_t offset) {
+ if (offset >= 0) {
+ Init(accessor.GetCatchHandlerData(offset));
+ } else {
+ // Not found, initialize as empty
+ current_data_ = nullptr;
+ remaining_count_ = -1;
+ catch_all_ = false;
+ DCHECK(!HasNext());
+ }
+}
+
+void CatchHandlerIterator::Init(const uint8_t* handler_data) {
+ current_data_ = handler_data;
+ remaining_count_ = DecodeSignedLeb128(&current_data_);
+
+ // If remaining_count_ is non-positive, then it is the negative of
+ // the number of catch types, and the catches are followed by a
+ // catch-all handler.
+ if (remaining_count_ <= 0) {
+ catch_all_ = true;
+ remaining_count_ = -remaining_count_;
+ } else {
+ catch_all_ = false;
+ }
+ Next();
+}
+
+void CatchHandlerIterator::Next() {
+ if (remaining_count_ > 0) {
+ handler_.type_idx_ = dex::TypeIndex(DecodeUnsignedLeb128(&current_data_));
+ handler_.address_ = DecodeUnsignedLeb128(&current_data_);
+ remaining_count_--;
+ return;
+ }
+
+ if (catch_all_) {
+ handler_.type_idx_ = dex::TypeIndex(DexFile::kDexNoIndex16);
+ handler_.address_ = DecodeUnsignedLeb128(&current_data_);
+ catch_all_ = false;
+ return;
+ }
+
+ // no more handler
+ remaining_count_ = -1;
+}
+
+} // namespace art
diff --git a/runtime/dex/dex_file_exception_helpers.h b/runtime/dex/dex_file_exception_helpers.h
new file mode 100644
index 0000000000..bd6cb7e747
--- /dev/null
+++ b/runtime/dex/dex_file_exception_helpers.h
@@ -0,0 +1,68 @@
+/*
+ * 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_DEX_FILE_EXCEPTION_HELPERS_H_
+#define ART_RUNTIME_DEX_DEX_FILE_EXCEPTION_HELPERS_H_
+
+#include "dex_file.h"
+
+namespace art {
+
+class CodeItemDataAccessor;
+
+class CatchHandlerIterator {
+ public:
+ CatchHandlerIterator(const CodeItemDataAccessor& accessor, uint32_t address);
+
+ CatchHandlerIterator(const CodeItemDataAccessor& accessor, const DexFile::TryItem& try_item);
+
+ explicit CatchHandlerIterator(const uint8_t* handler_data) {
+ Init(handler_data);
+ }
+
+ dex::TypeIndex GetHandlerTypeIndex() const {
+ return handler_.type_idx_;
+ }
+ uint32_t GetHandlerAddress() const {
+ return handler_.address_;
+ }
+ void Next();
+ bool HasNext() const {
+ return remaining_count_ != -1 || catch_all_;
+ }
+ // End of this set of catch blocks, convenience method to locate next set of catch blocks
+ const uint8_t* EndDataPointer() const {
+ CHECK(!HasNext());
+ return current_data_;
+ }
+
+ private:
+ void Init(const CodeItemDataAccessor& accessor, int32_t offset);
+ void Init(const uint8_t* handler_data);
+
+ struct CatchHandlerItem {
+ dex::TypeIndex type_idx_; // type index of the caught exception type
+ uint32_t address_; // handler address
+ } handler_;
+ const uint8_t* current_data_; // the current handler in dex file.
+ int32_t remaining_count_; // number of handlers not read.
+ bool catch_all_; // is there a handler that will catch all exceptions in case
+ // that all typed handler does not match.
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_DEX_DEX_FILE_EXCEPTION_HELPERS_H_
diff --git a/runtime/dex_file_layout.cc b/runtime/dex/dex_file_layout.cc
index 1973440d55..1973440d55 100644
--- a/runtime/dex_file_layout.cc
+++ b/runtime/dex/dex_file_layout.cc
diff --git a/runtime/dex_file_layout.h b/runtime/dex/dex_file_layout.h
index 4c960c3ff5..a7b9051f24 100644
--- a/runtime/dex_file_layout.h
+++ b/runtime/dex/dex_file_layout.h
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_FILE_LAYOUT_H_
-#define ART_RUNTIME_DEX_FILE_LAYOUT_H_
+#ifndef ART_RUNTIME_DEX_DEX_FILE_LAYOUT_H_
+#define ART_RUNTIME_DEX_DEX_FILE_LAYOUT_H_
#include <algorithm>
#include <cstdint>
#include <iosfwd>
-#include "base/logging.h"
+#include <android-base/logging.h>
namespace art {
@@ -121,4 +121,4 @@ std::ostream& operator<<(std::ostream& os, const DexLayoutSections& sections);
} // namespace art
-#endif // ART_RUNTIME_DEX_FILE_LAYOUT_H_
+#endif // ART_RUNTIME_DEX_DEX_FILE_LAYOUT_H_
diff --git a/runtime/dex_file_loader.cc b/runtime/dex/dex_file_loader.cc
index bc9276985b..fafd69889d 100644
--- a/runtime/dex_file_loader.cc
+++ b/runtime/dex/dex_file_loader.cc
@@ -25,7 +25,7 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/unix_file/fd_file.h"
-#include "cdex/compact_dex_file.h"
+#include "compact_dex_file.h"
#include "dex_file.h"
#include "dex_file_verifier.h"
#include "standard_dex_file.h"
diff --git a/runtime/dex_file_loader.h b/runtime/dex/dex_file_loader.h
index 17631234b3..7db8d8e08e 100644
--- a/runtime/dex_file_loader.h
+++ b/runtime/dex/dex_file_loader.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_FILE_LOADER_H_
-#define ART_RUNTIME_DEX_FILE_LOADER_H_
+#ifndef ART_RUNTIME_DEX_DEX_FILE_LOADER_H_
+#define ART_RUNTIME_DEX_DEX_FILE_LOADER_H_
#include <cstdint>
#include <memory>
@@ -202,4 +202,4 @@ class DexFileLoader {
} // namespace art
-#endif // ART_RUNTIME_DEX_FILE_LOADER_H_
+#endif // ART_RUNTIME_DEX_DEX_FILE_LOADER_H_
diff --git a/runtime/dex_file_reference.h b/runtime/dex/dex_file_reference.h
index 01a64257a8..6f882900c6 100644
--- a/runtime/dex_file_reference.h
+++ b/runtime/dex/dex_file_reference.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_FILE_REFERENCE_H_
-#define ART_RUNTIME_DEX_FILE_REFERENCE_H_
+#ifndef ART_RUNTIME_DEX_DEX_FILE_REFERENCE_H_
+#define ART_RUNTIME_DEX_DEX_FILE_REFERENCE_H_
#include <cstdint>
@@ -49,4 +49,4 @@ inline bool operator==(const DexFileReference& a, const DexFileReference& b) {
} // namespace art
-#endif // ART_RUNTIME_DEX_FILE_REFERENCE_H_
+#endif // ART_RUNTIME_DEX_DEX_FILE_REFERENCE_H_
diff --git a/runtime/dex_file_test.cc b/runtime/dex/dex_file_test.cc
index 14c36b4538..87eec571f1 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex/dex_file_test.cc
@@ -22,6 +22,7 @@
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
+#include "code_item_accessors-inl.h"
#include "common_runtime_test.h"
#include "dex_file-inl.h"
#include "dex_file_loader.h"
@@ -730,8 +731,8 @@ TEST_F(DexFileTest, OpenDexDebugInfoLocalNullType) {
kRawDexDebugInfoLocalNullType, tmp.GetFilename().c_str(), 0xf25f2b38U, true);
const DexFile::ClassDef& class_def = raw->GetClassDef(0);
const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def, 1));
- uint32_t debug_info_offset = raw->GetDebugInfoOffset(code_item);
- ASSERT_TRUE(raw->DecodeDebugLocalInfo(code_item, debug_info_offset, true, 1, Callback, nullptr));
+ CodeItemDebugInfoAccessor accessor(raw.get(), code_item);
+ ASSERT_TRUE(accessor.DecodeDebugLocalInfo(true, 1, Callback, nullptr));
}
} // namespace art
diff --git a/runtime/dex_file_tracking_registrar.cc b/runtime/dex/dex_file_tracking_registrar.cc
index 874d8ea905..bffca5599a 100644
--- a/runtime/dex_file_tracking_registrar.cc
+++ b/runtime/dex/dex_file_tracking_registrar.cc
@@ -19,6 +19,8 @@
#include <deque>
#include <tuple>
+#include <android-base/logging.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
@@ -28,7 +30,7 @@
#endif
#include "base/memory_tool.h"
-#include "base/logging.h"
+#include "code_item_accessors-inl.h"
#include "dex_file-inl.h"
namespace art {
@@ -162,7 +164,7 @@ void DexFileTrackingRegistrar::SetAllCodeItemRegistration(bool should_poison) {
const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
if (code_item != nullptr) {
const void* code_item_begin = reinterpret_cast<const void*>(code_item);
- size_t code_item_size = DexFile::GetCodeItemSize(*code_item);
+ size_t code_item_size = dex_file_->GetCodeItemSize(*code_item);
range_values_.push_back(std::make_tuple(code_item_begin, code_item_size, should_poison));
}
cdit.Next();
@@ -183,9 +185,12 @@ void DexFileTrackingRegistrar::SetAllCodeItemStartRegistration(bool should_poiso
if (code_item != nullptr) {
const void* code_item_begin = reinterpret_cast<const void*>(code_item);
size_t code_item_start = reinterpret_cast<size_t>(code_item);
- size_t code_item_start_end = reinterpret_cast<size_t>(&code_item->insns_[1]);
+ CodeItemInstructionAccessor accessor(dex_file_, code_item);
+ size_t code_item_start_end = reinterpret_cast<size_t>(accessor.Insns());
size_t code_item_start_size = code_item_start_end - code_item_start;
- range_values_.push_back(std::make_tuple(code_item_begin, code_item_start_size, should_poison));
+ range_values_.push_back(std::make_tuple(code_item_begin,
+ code_item_start_size,
+ should_poison));
}
cdit.Next();
}
@@ -203,9 +208,10 @@ void DexFileTrackingRegistrar::SetAllInsnsRegistration(bool should_poison) {
while (cdit.HasNextMethod()) {
const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
if (code_item != nullptr) {
- const void* insns_begin = reinterpret_cast<const void*>(&code_item->insns_);
+ CodeItemInstructionAccessor accessor(dex_file_, code_item);
+ const void* insns_begin = reinterpret_cast<const void*>(accessor.Insns());
// Member insns_size_in_code_units_ is in 2-byte units
- size_t insns_size = code_item->insns_size_in_code_units_ * 2;
+ size_t insns_size = accessor.InsnsSizeInCodeUnits() * 2;
range_values_.push_back(std::make_tuple(insns_begin, insns_size, should_poison));
}
cdit.Next();
@@ -227,7 +233,7 @@ void DexFileTrackingRegistrar::SetCodeItemRegistration(const char* class_name, b
const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
if (code_item != nullptr && strcmp(methodid_name, class_name) == 0) {
const void* code_item_begin = reinterpret_cast<const void*>(code_item);
- size_t code_item_size = DexFile::GetCodeItemSize(*code_item);
+ size_t code_item_size = dex_file_->GetCodeItemSize(*code_item);
range_values_.push_back(std::make_tuple(code_item_begin, code_item_size, should_poison));
}
cdit.Next();
diff --git a/runtime/dex_file_tracking_registrar.h b/runtime/dex/dex_file_tracking_registrar.h
index 5c0e0f50ab..71b8ed7bde 100644
--- a/runtime/dex_file_tracking_registrar.h
+++ b/runtime/dex/dex_file_tracking_registrar.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_FILE_TRACKING_REGISTRAR_H_
-#define ART_RUNTIME_DEX_FILE_TRACKING_REGISTRAR_H_
+#ifndef ART_RUNTIME_DEX_DEX_FILE_TRACKING_REGISTRAR_H_
+#define ART_RUNTIME_DEX_DEX_FILE_TRACKING_REGISTRAR_H_
#include <deque>
#include <tuple>
@@ -78,4 +78,4 @@ void RegisterDexFile(const DexFile* dex_file);
} // namespace dex
} // namespace art
-#endif // ART_RUNTIME_DEX_FILE_TRACKING_REGISTRAR_H_
+#endif // ART_RUNTIME_DEX_DEX_FILE_TRACKING_REGISTRAR_H_
diff --git a/runtime/dex_file_types.h b/runtime/dex/dex_file_types.h
index acca7c055b..2c508f9c99 100644
--- a/runtime/dex_file_types.h
+++ b/runtime/dex/dex_file_types.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_FILE_TYPES_H_
-#define ART_RUNTIME_DEX_FILE_TYPES_H_
+#ifndef ART_RUNTIME_DEX_DEX_FILE_TYPES_H_
+#define ART_RUNTIME_DEX_DEX_FILE_TYPES_H_
#include <limits>
#include <ostream>
@@ -114,4 +114,4 @@ template<> struct hash<art::dex::TypeIndex> {
} // namespace std
-#endif // ART_RUNTIME_DEX_FILE_TYPES_H_
+#endif // ART_RUNTIME_DEX_DEX_FILE_TYPES_H_
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex/dex_file_verifier.cc
index edf5650df1..d6f685a595 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex/dex_file_verifier.cc
@@ -23,6 +23,7 @@
#include "android-base/stringprintf.h"
+#include "code_item_accessors-no_art-inl.h"
#include "dex_file-inl.h"
#include "experimental_flags.h"
#include "leb128.h"
@@ -385,7 +386,14 @@ bool DexFileVerifier::CheckHeader() {
return false;
}
- if (header_->header_size_ != sizeof(DexFile::Header)) {
+ bool size_matches = false;
+ if (dex_file_->IsCompactDexFile()) {
+ size_matches = header_->header_size_ == sizeof(CompactDexFile::Header);
+ } else {
+ size_matches = header_->header_size_ == sizeof(StandardDexFile::Header);
+ }
+
+ if (!size_matches) {
ErrorStringPrintf("Bad header size: %ud", header_->header_size_);
return false;
}
@@ -572,7 +580,8 @@ uint32_t DexFileVerifier::ReadUnsignedLittleEndian(uint32_t size) {
bool DexFileVerifier::CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_item,
uint32_t* handler_offsets, uint32_t handlers_size) {
- const uint8_t* handlers_base = DexFile::GetCatchHandlerData(*code_item, 0);
+ CodeItemDataAccessor accessor(dex_file_, code_item);
+ const uint8_t* handlers_base = accessor.GetCatchHandlerData();
for (uint32_t i = 0; i < handlers_size; i++) {
bool catch_all;
@@ -600,7 +609,7 @@ bool DexFileVerifier::CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_it
}
DECODE_UNSIGNED_CHECKED_FROM(ptr_, addr);
- if (UNLIKELY(addr >= code_item->insns_size_in_code_units_)) {
+ if (UNLIKELY(addr >= accessor.InsnsSizeInCodeUnits())) {
ErrorStringPrintf("Invalid handler addr: %x", addr);
return false;
}
@@ -608,7 +617,7 @@ bool DexFileVerifier::CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_it
if (catch_all) {
DECODE_UNSIGNED_CHECKED_FROM(ptr_, addr);
- if (UNLIKELY(addr >= code_item->insns_size_in_code_units_)) {
+ if (UNLIKELY(addr >= accessor.InsnsSizeInCodeUnits())) {
ErrorStringPrintf("Invalid handler catch_all_addr: %x", addr);
return false;
}
@@ -1224,14 +1233,14 @@ bool DexFileVerifier::CheckIntraCodeItem() {
return false;
}
- if (UNLIKELY(code_item->ins_size_ > code_item->registers_size_)) {
+ CodeItemDataAccessor accessor(dex_file_, code_item);
+ if (UNLIKELY(accessor.InsSize() > accessor.RegistersSize())) {
ErrorStringPrintf("ins_size (%ud) > registers_size (%ud)",
- code_item->ins_size_, code_item->registers_size_);
+ accessor.InsSize(), accessor.RegistersSize());
return false;
}
- if (UNLIKELY((code_item->outs_size_ > 5) &&
- (code_item->outs_size_ > code_item->registers_size_))) {
+ if (UNLIKELY(accessor.OutsSize() > 5 && accessor.OutsSize() > accessor.RegistersSize())) {
/*
* outs_size can be up to 5, even if registers_size is smaller, since the
* short forms of method invocation allow repetitions of a register multiple
@@ -1239,18 +1248,18 @@ bool DexFileVerifier::CheckIntraCodeItem() {
* need to be represented in-order in the register file.
*/
ErrorStringPrintf("outs_size (%ud) > registers_size (%ud)",
- code_item->outs_size_, code_item->registers_size_);
+ accessor.OutsSize(), accessor.RegistersSize());
return false;
}
- const uint16_t* insns = code_item->insns_;
- uint32_t insns_size = code_item->insns_size_in_code_units_;
+ const uint16_t* insns = accessor.Insns();
+ uint32_t insns_size = accessor.InsnsSizeInCodeUnits();
if (!CheckListSize(insns, insns_size, sizeof(uint16_t), "insns size")) {
return false;
}
// Grab the end of the insns if there are no try_items.
- uint32_t try_items_size = code_item->tries_size_;
+ uint32_t try_items_size = accessor.TriesSize();
if (try_items_size == 0) {
ptr_ = reinterpret_cast<const uint8_t*>(&insns[insns_size]);
return true;
@@ -1262,12 +1271,12 @@ bool DexFileVerifier::CheckIntraCodeItem() {
return false;
}
- const DexFile::TryItem* try_items = DexFile::GetTryItems(*code_item, 0);
+ const DexFile::TryItem* try_items = accessor.TryItems().begin();
if (!CheckListSize(try_items, try_items_size, sizeof(DexFile::TryItem), "try_items size")) {
return false;
}
- ptr_ = DexFile::GetCatchHandlerData(*code_item, 0);
+ ptr_ = accessor.GetCatchHandlerData();
DECODE_UNSIGNED_CHECKED_FROM(ptr_, handlers_size);
if (UNLIKELY((handlers_size == 0) || (handlers_size >= 65536))) {
@@ -3002,7 +3011,7 @@ bool DexFileVerifier::CheckFieldAccessFlags(uint32_t idx,
GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
field_access_flags,
PrettyJavaAccessFlags(field_access_flags).c_str());
- if (header_->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+ if (dex_file_->SupportsDefaultMethods()) {
return false;
} else {
// Allow in older versions, but warn.
@@ -3017,7 +3026,7 @@ bool DexFileVerifier::CheckFieldAccessFlags(uint32_t idx,
GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
field_access_flags,
PrettyJavaAccessFlags(field_access_flags).c_str());
- if (header_->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+ if (dex_file_->SupportsDefaultMethods()) {
return false;
} else {
// Allow in older versions, but warn.
@@ -3100,7 +3109,7 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
*error_msg = StringPrintf("Constructor %" PRIu32 "(%s) is not flagged correctly wrt/ static.",
method_index,
GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- if (header_->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+ if (dex_file_->SupportsDefaultMethods()) {
return false;
} else {
// Allow in older versions, but warn.
@@ -3129,14 +3138,14 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
if ((class_access_flags & kAccInterface) != 0) {
// Non-static interface methods must be public or private.
uint32_t desired_flags = (kAccPublic | kAccStatic);
- if (dex_file_->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+ if (dex_file_->SupportsDefaultMethods()) {
desired_flags |= kAccPrivate;
}
if ((method_access_flags & desired_flags) == 0) {
*error_msg = StringPrintf("Interface virtual method %" PRIu32 "(%s) is not public",
method_index,
GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- if (header_->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+ if (dex_file_->SupportsDefaultMethods()) {
return false;
} else {
// Allow in older versions, but warn.
@@ -3161,7 +3170,7 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
*error_msg = StringPrintf("Constructor %u(%s) must not be abstract or native",
method_index,
GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- if (header_->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+ if (dex_file_->SupportsDefaultMethods()) {
return false;
} else {
// Allow in older versions, but warn.
@@ -3195,7 +3204,7 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
*error_msg = StringPrintf("Interface method %" PRIu32 "(%s) is not public and abstract",
method_index,
GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- if (header_->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+ if (dex_file_->SupportsDefaultMethods()) {
return false;
} else {
// Allow in older versions, but warn.
diff --git a/runtime/dex_file_verifier.h b/runtime/dex/dex_file_verifier.h
index 23089fa215..6cb5d4c629 100644
--- a/runtime/dex_file_verifier.h
+++ b/runtime/dex/dex_file_verifier.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_FILE_VERIFIER_H_
-#define ART_RUNTIME_DEX_FILE_VERIFIER_H_
+#ifndef ART_RUNTIME_DEX_DEX_FILE_VERIFIER_H_
+#define ART_RUNTIME_DEX_DEX_FILE_VERIFIER_H_
#include <unordered_set>
@@ -254,4 +254,4 @@ class DexFileVerifier {
} // namespace art
-#endif // ART_RUNTIME_DEX_FILE_VERIFIER_H_
+#endif // ART_RUNTIME_DEX_DEX_FILE_VERIFIER_H_
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex/dex_file_verifier_test.cc
index d4d912cbfb..d4d912cbfb 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex/dex_file_verifier_test.cc
diff --git a/runtime/dex_instruction-inl.h b/runtime/dex/dex_instruction-inl.h
index f6ed1f03b7..a6b8414e62 100644
--- a/runtime/dex_instruction-inl.h
+++ b/runtime/dex/dex_instruction-inl.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_INSTRUCTION_INL_H_
-#define ART_RUNTIME_DEX_INSTRUCTION_INL_H_
+#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_INL_H_
+#define ART_RUNTIME_DEX_DEX_INSTRUCTION_INL_H_
#include "dex_instruction.h"
@@ -555,4 +555,4 @@ inline void Instruction::GetVarArgs(uint32_t arg[kMaxVarArgRegs], uint16_t inst_
} // namespace art
-#endif // ART_RUNTIME_DEX_INSTRUCTION_INL_H_
+#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_INL_H_
diff --git a/runtime/dex_instruction.cc b/runtime/dex/dex_instruction.cc
index 6ebe2286e8..6ebe2286e8 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex/dex_instruction.cc
diff --git a/runtime/dex_instruction.h b/runtime/dex/dex_instruction.h
index 4041820616..8b1a5ce670 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex/dex_instruction.h
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_INSTRUCTION_H_
-#define ART_RUNTIME_DEX_INSTRUCTION_H_
+#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_H_
+#define ART_RUNTIME_DEX_DEX_INSTRUCTION_H_
+
+#include <android-base/logging.h>
-#include "base/logging.h"
#include "base/macros.h"
#include "globals.h"
@@ -738,4 +739,4 @@ class VarArgsInstructionOperands FINAL : public InstructionOperands {
} // namespace art
-#endif // ART_RUNTIME_DEX_INSTRUCTION_H_
+#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_H_
diff --git a/runtime/dex_instruction_iterator.h b/runtime/dex/dex_instruction_iterator.h
index be583a2533..c1b3118f85 100644
--- a/runtime/dex_instruction_iterator.h
+++ b/runtime/dex/dex_instruction_iterator.h
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_
-#define ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_
+#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_ITERATOR_H_
+#define ART_RUNTIME_DEX_DEX_INSTRUCTION_ITERATOR_H_
#include <iterator>
+#include <android-base/logging.h>
+
+#include "base/macros.h"
#include "dex_instruction.h"
-#include "base/logging.h"
namespace art {
@@ -232,4 +234,4 @@ class SafeDexInstructionIterator : public DexInstructionIteratorBase {
} // namespace art
-#endif // ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_
+#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_ITERATOR_H_
diff --git a/runtime/dex_instruction_list.h b/runtime/dex/dex_instruction_list.h
index ef83bdc216..aa63fadb66 100644
--- a/runtime/dex_instruction_list.h
+++ b/runtime/dex/dex_instruction_list.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_INSTRUCTION_LIST_H_
-#define ART_RUNTIME_DEX_INSTRUCTION_LIST_H_
+#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_
+#define ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_
// V(opcode, instruction_code, name, format, index, flags, extended_flags, verifier_flags);
#define DEX_INSTRUCTION_LIST(V) \
@@ -304,5 +304,5 @@
V(k4rcc) \
V(k51l)
-#endif // ART_RUNTIME_DEX_INSTRUCTION_LIST_H_
-#undef ART_RUNTIME_DEX_INSTRUCTION_LIST_H_ // the guard in this file is just for cpplint
+#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_
+#undef ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_ // the guard in this file is just for cpplint
diff --git a/runtime/dex_instruction_test.cc b/runtime/dex/dex_instruction_test.cc
index c944085b9e..c944085b9e 100644
--- a/runtime/dex_instruction_test.cc
+++ b/runtime/dex/dex_instruction_test.cc
diff --git a/runtime/dex_instruction_utils.h b/runtime/dex/dex_instruction_utils.h
index 72d82442b5..27501927e7 100644
--- a/runtime/dex_instruction_utils.h
+++ b/runtime/dex/dex_instruction_utils.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_INSTRUCTION_UTILS_H_
-#define ART_RUNTIME_DEX_INSTRUCTION_UTILS_H_
+#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_UTILS_H_
+#define ART_RUNTIME_DEX_DEX_INSTRUCTION_UTILS_H_
#include "dex_instruction.h"
@@ -216,4 +216,4 @@ constexpr DexMemAccessType AGetOrAPutMemAccessType(Instruction::Code code) {
} // namespace art
-#endif // ART_RUNTIME_DEX_INSTRUCTION_UTILS_H_
+#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_UTILS_H_
diff --git a/runtime/standard_dex_file.cc b/runtime/dex/standard_dex_file.cc
index 4c1d3081d8..843508d831 100644
--- a/runtime/standard_dex_file.cc
+++ b/runtime/dex/standard_dex_file.cc
@@ -16,6 +16,10 @@
#include "standard_dex_file.h"
+#include "base/casts.h"
+#include "dex_file-inl.h"
+#include "leb128.h"
+
namespace art {
const uint8_t StandardDexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' };
@@ -63,4 +67,39 @@ bool StandardDexFile::IsVersionValid() const {
return IsVersionValid(header_->magic_);
}
+bool StandardDexFile::SupportsDefaultMethods() const {
+ return GetDexVersion() >= DexFile::kDefaultMethodsVersion;
+}
+
+uint32_t StandardDexFile::GetCodeItemSize(const DexFile::CodeItem& item) const {
+ DCHECK(HasAddress(&item));
+ const CodeItem& code_item = down_cast<const CodeItem&>(item);
+ uintptr_t code_item_start = reinterpret_cast<uintptr_t>(&code_item);
+ uint32_t insns_size = code_item.insns_size_in_code_units_;
+ uint32_t tries_size = code_item.tries_size_;
+ const uint8_t* handler_data = GetCatchHandlerData(
+ DexInstructionIterator(code_item.insns_, code_item.insns_size_in_code_units_),
+ code_item.tries_size_,
+ 0);
+
+ if (tries_size == 0 || handler_data == nullptr) {
+ uintptr_t insns_end = reinterpret_cast<uintptr_t>(&code_item.insns_[insns_size]);
+ return insns_end - code_item_start;
+ } else {
+ // Get the start of the handler data.
+ uint32_t handlers_size = DecodeUnsignedLeb128(&handler_data);
+ // Manually read each handler.
+ for (uint32_t i = 0; i < handlers_size; ++i) {
+ int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2;
+ if (uleb128_count <= 0) {
+ uleb128_count = -uleb128_count + 1;
+ }
+ for (int32_t j = 0; j < uleb128_count; ++j) {
+ DecodeUnsignedLeb128(&handler_data);
+ }
+ }
+ return reinterpret_cast<uintptr_t>(handler_data) - code_item_start;
+ }
+}
+
} // namespace art
diff --git a/runtime/standard_dex_file.h b/runtime/dex/standard_dex_file.h
index 5d5359776d..fb2f720920 100644
--- a/runtime/standard_dex_file.h
+++ b/runtime/dex/standard_dex_file.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_STANDARD_DEX_FILE_H_
-#define ART_RUNTIME_STANDARD_DEX_FILE_H_
+#ifndef ART_RUNTIME_DEX_STANDARD_DEX_FILE_H_
+#define ART_RUNTIME_DEX_STANDARD_DEX_FILE_H_
#include <iosfwd>
@@ -35,6 +35,7 @@ class StandardDexFile : public DexFile {
struct CodeItem : public DexFile::CodeItem {
private:
// TODO: Insert standard dex specific fields here.
+ friend class StandardDexFile;
DISALLOW_COPY_AND_ASSIGN(CodeItem);
};
@@ -56,6 +57,10 @@ class StandardDexFile : public DexFile {
static bool IsVersionValid(const uint8_t* magic);
virtual bool IsVersionValid() const OVERRIDE;
+ virtual bool SupportsDefaultMethods() const OVERRIDE;
+
+ uint32_t GetCodeItemSize(const DexFile::CodeItem& item) const OVERRIDE;
+
private:
StandardDexFile(const uint8_t* base,
size_t size,
@@ -81,4 +86,4 @@ class StandardDexFile : public DexFile {
} // namespace art
-#endif // ART_RUNTIME_STANDARD_DEX_FILE_H_
+#endif // ART_RUNTIME_DEX_STANDARD_DEX_FILE_H_
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index 5f9b3cf6c4..e459f09e95 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -27,7 +27,7 @@
#include "base/stl_util.h"
#include "common_runtime_test.h"
#include "compiler_callbacks.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file_loader.h"
#include "exec_utils.h"
#include "gc/heap.h"
#include "gc/space/image_space.h"
diff --git a/runtime/dex_cache_resolved_classes.h b/runtime/dex_cache_resolved_classes.h
index 2278b052ed..ca6afc5b92 100644
--- a/runtime/dex_cache_resolved_classes.h
+++ b/runtime/dex_cache_resolved_classes.h
@@ -21,7 +21,7 @@
#include <unordered_set>
#include <vector>
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
namespace art {
diff --git a/runtime/dex_to_dex_decompiler.cc b/runtime/dex_to_dex_decompiler.cc
index a5ebaded5f..f3f2d52cb4 100644
--- a/runtime/dex_to_dex_decompiler.cc
+++ b/runtime/dex_to_dex_decompiler.cc
@@ -16,11 +16,14 @@
#include "dex_to_dex_decompiler.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/macros.h"
#include "base/mutex.h"
#include "bytecode_utils.h"
-#include "dex_file-inl.h"
-#include "dex_instruction-inl.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_instruction-inl.h"
#include "quicken_info.h"
namespace art {
@@ -28,10 +31,11 @@ namespace optimizer {
class DexDecompiler {
public:
- DexDecompiler(const DexFile::CodeItem& code_item,
+ DexDecompiler(const DexFile& dex_file,
+ const DexFile::CodeItem& code_item,
const ArrayRef<const uint8_t>& quickened_info,
bool decompile_return_instruction)
- : code_item_(code_item),
+ : code_item_accessor_(&dex_file, &code_item),
quicken_info_(quickened_info.data()),
quicken_info_number_of_indices_(QuickenInfoTable::NumberOfIndices(quickened_info.size())),
decompile_return_instruction_(decompile_return_instruction) {}
@@ -74,7 +78,7 @@ class DexDecompiler {
return ret;
}
- const DexFile::CodeItem& code_item_;
+ const CodeItemInstructionAccessor code_item_accessor_;
const QuickenInfoTable quicken_info_;
const size_t quicken_info_number_of_indices_;
const bool decompile_return_instruction_;
@@ -89,7 +93,7 @@ bool DexDecompiler::Decompile() {
// because the RETURN_VOID quickening is not encoded in the quickening data. Because
// unquickening is a rare need and not performance sensitive, it is not worth the
// added storage to also add the RETURN_VOID quickening in the quickened data.
- for (const DexInstructionPcPair& pair : code_item_.Instructions()) {
+ for (const DexInstructionPcPair& pair : code_item_accessor_) {
Instruction* inst = const_cast<Instruction*>(&pair.Inst());
switch (inst->Opcode()) {
@@ -192,13 +196,14 @@ bool DexDecompiler::Decompile() {
return true;
}
-bool ArtDecompileDEX(const DexFile::CodeItem& code_item,
+bool ArtDecompileDEX(const DexFile& dex_file,
+ const DexFile::CodeItem& code_item,
const ArrayRef<const uint8_t>& quickened_info,
bool decompile_return_instruction) {
if (quickened_info.size() == 0 && !decompile_return_instruction) {
return true;
}
- DexDecompiler decompiler(code_item, quickened_info, decompile_return_instruction);
+ DexDecompiler decompiler(dex_file, code_item, quickened_info, decompile_return_instruction);
return decompiler.Decompile();
}
diff --git a/runtime/dex_to_dex_decompiler.h b/runtime/dex_to_dex_decompiler.h
index d7cb1641e1..93711d17db 100644
--- a/runtime/dex_to_dex_decompiler.h
+++ b/runtime/dex_to_dex_decompiler.h
@@ -18,7 +18,7 @@
#define ART_RUNTIME_DEX_TO_DEX_DECOMPILER_H_
#include "base/array_ref.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
namespace art {
namespace optimizer {
@@ -29,7 +29,8 @@ namespace optimizer {
// to non-const has too many repercussions on the code base. We make it
// consistent with DexToDexCompiler, but we should really change it to
// DexFile::CodeItem*.
-bool ArtDecompileDEX(const DexFile::CodeItem& code_item,
+bool ArtDecompileDEX(const DexFile& dex_file,
+ const DexFile::CodeItem& code_item,
const ArrayRef<const uint8_t>& quickened_data,
bool decompile_return_instruction);
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc
index 3c8243a6c5..d93d76793f 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -218,10 +218,11 @@ void DexoptTest::ReserveImageSpace() {
std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true));
ASSERT_TRUE(map.get() != nullptr) << "Failed to build process map";
- for (BacktraceMap::const_iterator it = map->begin();
+ for (BacktraceMap::iterator it = map->begin();
reservation_start < reservation_end && it != map->end(); ++it) {
- ReserveImageSpaceChunk(reservation_start, std::min(it->start, reservation_end));
- reservation_start = std::max(reservation_start, it->end);
+ const backtrace_map_t* entry = *it;
+ ReserveImageSpaceChunk(reservation_start, std::min(entry->start, reservation_end));
+ reservation_start = std::max(reservation_start, entry->end);
}
ReserveImageSpaceChunk(reservation_start, reservation_end);
}
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index afe4eeb059..d057ff3b1a 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -25,7 +25,6 @@
#include "android-base/strings.h"
#include "arch/instruction_set.h"
-#include "base/logging.h"
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
#include "elf_file_impl.h"
diff --git a/runtime/elf_utils.h b/runtime/elf_utils.h
index 418d937b12..0cac8e8d02 100644
--- a/runtime/elf_utils.h
+++ b/runtime/elf_utils.h
@@ -19,11 +19,11 @@
#include <sys/cdefs.h>
+#include <android-base/logging.h>
+
// Explicitly include our own elf.h to avoid Linux and other dependencies.
#include "./elf.h"
-#include "base/logging.h"
-
namespace art {
// Architecture dependent flags for the ELF header.
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 8253739427..3048f45f30 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -24,7 +24,7 @@
#include "base/enums.h"
#include "class_linker-inl.h"
#include "common_throws.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "entrypoints/quick/callee_save_frame.h"
#include "handle_scope-inl.h"
#include "imt_conflict_table.h"
@@ -245,7 +245,7 @@ inline mirror::Class* CheckArrayAlloc(dex::TypeIndex type_idx,
*slow_path = true;
return nullptr; // Failure
}
- mirror::Class* klass = method->GetDexCache()->GetResolvedType(type_idx);
+ ObjPtr<mirror::Class> klass = method->GetDexCache()->GetResolvedType(type_idx);
if (UNLIKELY(klass == nullptr)) { // Not in dex cache so try to resolve
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
klass = class_linker->ResolveType(type_idx, method);
@@ -264,7 +264,7 @@ inline mirror::Class* CheckArrayAlloc(dex::TypeIndex type_idx,
return nullptr; // Failure
}
}
- return klass;
+ return klass.Ptr();
}
// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
@@ -349,8 +349,7 @@ inline ArtField* FindFieldFromCode(uint32_t field_idx,
Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(method->GetDexCache()));
Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(method->GetClassLoader()));
- resolved_field = class_linker->ResolveFieldJLS(*method->GetDexFile(),
- field_idx,
+ resolved_field = class_linker->ResolveFieldJLS(field_idx,
h_dex_cache,
h_class_loader);
} else {
@@ -500,7 +499,8 @@ inline ArtMethod* FindMethodFromCode(uint32_t method_idx,
Handle<mirror::Class> h_referring_class(hs2.NewHandle(referrer->GetDeclaringClass()));
const dex::TypeIndex method_type_idx =
referrer->GetDexFile()->GetMethodId(method_idx).class_idx_;
- mirror::Class* method_reference_class = class_linker->ResolveType(method_type_idx, referrer);
+ ObjPtr<mirror::Class> method_reference_class =
+ class_linker->ResolveType(method_type_idx, referrer);
if (UNLIKELY(method_reference_class == nullptr)) {
// Bad type idx.
CHECK(self->IsExceptionPending());
@@ -682,7 +682,7 @@ inline ArtMethod* FindMethodFast(uint32_t method_idx,
} else if (type == kSuper) {
// TODO This lookup is rather slow.
dex::TypeIndex method_type_idx = dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
- ObjPtr<mirror::Class> method_reference_class = ClassLinker::LookupResolvedType(
+ ObjPtr<mirror::Class> method_reference_class = linker->LookupResolvedType(
method_type_idx, dex_cache, referrer->GetClassLoader());
if (method_reference_class == nullptr) {
// Need to do full type resolution...
@@ -711,13 +711,13 @@ inline ArtMethod* FindMethodFast(uint32_t method_idx,
}
}
-inline mirror::Class* ResolveVerifyAndClinit(dex::TypeIndex type_idx,
- ArtMethod* referrer,
- Thread* self,
- bool can_run_clinit,
- bool verify_access) {
+inline ObjPtr<mirror::Class> ResolveVerifyAndClinit(dex::TypeIndex type_idx,
+ ArtMethod* referrer,
+ Thread* self,
+ bool can_run_clinit,
+ bool verify_access) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- mirror::Class* klass = class_linker->ResolveType(type_idx, referrer);
+ ObjPtr<mirror::Class> klass = class_linker->ResolveType(type_idx, referrer);
if (UNLIKELY(klass == nullptr)) {
CHECK(self->IsExceptionPending());
return nullptr; // Failure - Indicate to caller to deliver exception
@@ -748,32 +748,31 @@ inline mirror::Class* ResolveVerifyAndClinit(dex::TypeIndex type_idx,
return h_class.Get();
}
-static inline mirror::String* ResolveString(ClassLinker* class_linker,
- dex::StringIndex string_idx,
- ArtMethod* referrer)
+static inline ObjPtr<mirror::String> ResolveString(ClassLinker* class_linker,
+ dex::StringIndex string_idx,
+ ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_) {
Thread::PoisonObjectPointersIfDebug();
ObjPtr<mirror::String> string = referrer->GetDexCache()->GetResolvedString(string_idx);
if (UNLIKELY(string == nullptr)) {
StackHandleScope<1> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
- const DexFile& dex_file = *dex_cache->GetDexFile();
- string = class_linker->ResolveString(dex_file, string_idx, dex_cache);
+ string = class_linker->ResolveString(string_idx, dex_cache);
}
- return string.Ptr();
+ return string;
}
-inline mirror::String* ResolveStringFromCode(ArtMethod* referrer, dex::StringIndex string_idx) {
+inline ObjPtr<mirror::String> ResolveStringFromCode(ArtMethod* referrer,
+ dex::StringIndex string_idx) {
Thread::PoisonObjectPointersIfDebug();
ObjPtr<mirror::String> string = referrer->GetDexCache()->GetResolvedString(string_idx);
if (UNLIKELY(string == nullptr)) {
StackHandleScope<1> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
- const DexFile& dex_file = *dex_cache->GetDexFile();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- string = class_linker->ResolveString(dex_file, string_idx, dex_cache);
+ string = class_linker->ResolveString(string_idx, dex_cache);
}
- return string.Ptr();
+ return string;
}
inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) {
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index f3450da306..ffa138d5b1 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -21,7 +21,7 @@
#include "base/enums.h"
#include "base/mutex.h"
#include "class_linker-inl.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "entrypoints/quick/callee_save_frame.h"
#include "entrypoints/runtime_asm_entrypoints.h"
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index cda70ea265..eb32153b16 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -23,8 +23,8 @@
#include "base/callee_save_type.h"
#include "base/macros.h"
#include "base/mutex.h"
-#include "dex_file_types.h"
-#include "dex_instruction.h"
+#include "dex/dex_file_types.h"
+#include "dex/dex_instruction.h"
#include "gc/allocator_type.h"
#include "handle.h"
#include "jvalue.h"
@@ -143,15 +143,16 @@ inline ArtMethod* FindMethodFast(uint32_t method_idx,
ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_);
-inline mirror::Class* ResolveVerifyAndClinit(dex::TypeIndex type_idx,
- ArtMethod* referrer,
- Thread* self,
- bool can_run_clinit,
- bool verify_access)
+inline ObjPtr<mirror::Class> ResolveVerifyAndClinit(dex::TypeIndex type_idx,
+ ArtMethod* referrer,
+ Thread* self,
+ bool can_run_clinit,
+ bool verify_access)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
-inline mirror::String* ResolveStringFromCode(ArtMethod* referrer, dex::StringIndex string_idx)
+inline ObjPtr<mirror::String> ResolveStringFromCode(ArtMethod* referrer,
+ dex::StringIndex string_idx)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index 7ec360a93c..780e221129 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -14,8 +14,9 @@
* limitations under the License.
*/
+#include <android-base/logging.h>
+
#include "art_method-inl.h"
-#include "base/logging.h"
#include "entrypoints/entrypoint_utils.h"
#include "java_vm_ext.h"
#include "mirror/object-inl.h"
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index b8d96af3fb..1ab67ec2b9 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -19,7 +19,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "callee_save_frame.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
diff --git a/runtime/entrypoints/quick/quick_default_init_entrypoints.h b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
index 8acaa90053..8c90800463 100644
--- a/runtime/entrypoints/quick/quick_default_init_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
@@ -17,7 +17,7 @@
#ifndef ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_DEFAULT_INIT_ENTRYPOINTS_H_
#define ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_DEFAULT_INIT_ENTRYPOINTS_H_
-#include "base/logging.h"
+#include "base/logging.h" // FOR VLOG_IS_ON.
#include "entrypoints/jni/jni_entrypoints.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "quick_alloc_entrypoints.h"
diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
index 5f40711753..c782c9c949 100644
--- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG_IS_ON.
#include "base/mutex.h"
#include "base/systrace.h"
#include "callee_save_frame.h"
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index f756312983..cfb427f1ac 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -19,8 +19,8 @@
#include "callee_save_frame.h"
#include "class_linker-inl.h"
#include "class_table-inl.h"
-#include "dex_file-inl.h"
-#include "dex_file_types.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_types.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "gc/heap.h"
#include "mirror/class-inl.h"
@@ -41,6 +41,12 @@ static void StoreObjectInBss(ArtMethod* outer_method,
static_assert(sizeof(GcRoot<mirror::String>) == sizeof(GcRoot<mirror::Object>), "Size check.");
DCHECK_NE(bss_offset, IndexBssMappingLookup::npos);
DCHECK_ALIGNED(bss_offset, sizeof(GcRoot<mirror::Object>));
+ if (UNLIKELY(!oat_file->IsExecutable())) {
+ // There are situations where we execute bytecode tied to an oat file opened
+ // as non-executable (i.e. the AOT-compiled code cannot be executed) and we
+ // can JIT that bytecode and get here without the .bss being mmapped.
+ return;
+ }
GcRoot<mirror::Object>* slot = reinterpret_cast<GcRoot<mirror::Object>*>(
const_cast<uint8_t*>(oat_file->BssBegin() + bss_offset));
DCHECK_GE(slot, oat_file->GetBssGcRoots().data());
@@ -132,15 +138,15 @@ extern "C" mirror::Class* artInitializeStaticStorageFromCode(uint32_t type_idx,
auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(
self, CalleeSaveType::kSaveEverythingForClinit);
ArtMethod* caller = caller_and_outer.caller;
- mirror::Class* result = ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
- caller,
- self,
- /* can_run_clinit */ true,
- /* verify_access */ false);
+ ObjPtr<mirror::Class> result = ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
+ caller,
+ self,
+ /* can_run_clinit */ true,
+ /* verify_access */ false);
if (LIKELY(result != nullptr) && CanReferenceBss(caller_and_outer.outer_method, caller)) {
StoreTypeInBss(caller_and_outer.outer_method, dex::TypeIndex(type_idx), result);
}
- return result;
+ return result.Ptr();
}
extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx, Thread* self)
@@ -150,15 +156,15 @@ extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx, Thread* s
auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(
self, CalleeSaveType::kSaveEverythingForClinit);
ArtMethod* caller = caller_and_outer.caller;
- mirror::Class* result = ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
- caller,
- self,
- /* can_run_clinit */ false,
- /* verify_access */ false);
+ ObjPtr<mirror::Class> result = ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
+ caller,
+ self,
+ /* can_run_clinit */ false,
+ /* verify_access */ false);
if (LIKELY(result != nullptr) && CanReferenceBss(caller_and_outer.outer_method, caller)) {
StoreTypeInBss(caller_and_outer.outer_method, dex::TypeIndex(type_idx), result);
}
- return result;
+ return result.Ptr();
}
extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Thread* self)
@@ -168,13 +174,13 @@ extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type
auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(self,
CalleeSaveType::kSaveEverything);
ArtMethod* caller = caller_and_outer.caller;
- mirror::Class* result = ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
- caller,
- self,
- /* can_run_clinit */ false,
- /* verify_access */ true);
+ ObjPtr<mirror::Class> result = ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
+ caller,
+ self,
+ /* can_run_clinit */ false,
+ /* verify_access */ true);
// Do not StoreTypeInBss(); access check entrypoint is never used together with .bss.
- return result;
+ return result.Ptr();
}
extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* self)
@@ -183,11 +189,11 @@ extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread*
auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(self,
CalleeSaveType::kSaveEverything);
ArtMethod* caller = caller_and_outer.caller;
- mirror::String* result = ResolveStringFromCode(caller, dex::StringIndex(string_idx));
+ ObjPtr<mirror::String> result = ResolveStringFromCode(caller, dex::StringIndex(string_idx));
if (LIKELY(result != nullptr) && CanReferenceBss(caller_and_outer.outer_method, caller)) {
StoreStringInBss(caller_and_outer.outer_method, dex::StringIndex(string_idx), result);
}
- return result;
+ return result.Ptr();
}
} // namespace art
diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc
index b13103df03..62cc9dee27 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -20,7 +20,7 @@
#include "art_method-inl.h"
#include "base/callee_save_type.h"
#include "callee_save_frame.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "gc_root-inl.h"
#include "mirror/class-inl.h"
@@ -68,6 +68,11 @@ static ArtMethod* GetReferrer(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_
return GetCalleeSaveMethodCallerAndOuterMethod(self, CalleeSaveType::kSaveRefsOnly).caller;
}
+// Macro used to define this set of functions:
+//
+// art{Get,Set}<Kind>{Static,Instance}FromCode
+// art{Get,Set}<Kind>{Static,Instance}FromCompiledCode
+//
#define ART_GET_FIELD_FROM_CODE(Kind, PrimitiveType, RetType, SetType, \
PrimitiveOrObject, IsObject, Ptr) \
extern "C" RetType artGet ## Kind ## StaticFromCode(uint32_t field_idx, \
@@ -216,15 +221,100 @@ static ArtMethod* GetReferrer(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_
field_idx, obj, new_value, GetReferrer(self), self); \
}
+// Define these functions:
+//
+// artGetByteStaticFromCode
+// artGetByteInstanceFromCode
+// artSetByteStaticFromCode
+// artSetByteInstanceFromCode
+// artGetByteStaticFromCompiledCode
+// artGetByteInstanceFromCompiledCode
+// artSetByteStaticFromCompiledCode
+// artSetByteInstanceFromCompiledCode
+//
ART_GET_FIELD_FROM_CODE(Byte, int8_t, ssize_t, uint32_t, Primitive, false, )
+
+// Define these functions:
+//
+// artGetBooleanStaticFromCode
+// artGetBooleanInstanceFromCode
+// artSetBooleanStaticFromCode
+// artSetBooleanInstanceFromCode
+// artGetBooleanStaticFromCompiledCode
+// artGetBooleanInstanceFromCompiledCode
+// artSetBooleanStaticFromCompiledCode
+// artSetBooleanInstanceFromCompiledCode
+//
ART_GET_FIELD_FROM_CODE(Boolean, int8_t, size_t, uint32_t, Primitive, false, )
+
+// Define these functions:
+//
+// artGetShortStaticFromCode
+// artGetShortInstanceFromCode
+// artSetShortStaticFromCode
+// artSetShortInstanceFromCode
+// artGetShortStaticFromCompiledCode
+// artGetShortInstanceFromCompiledCode
+// artSetShortStaticFromCompiledCode
+// artSetShortInstanceFromCompiledCode
+//
ART_GET_FIELD_FROM_CODE(Short, int16_t, ssize_t, uint16_t, Primitive, false, )
+
+// Define these functions:
+//
+// artGetCharStaticFromCode
+// artGetCharInstanceFromCode
+// artSetCharStaticFromCode
+// artSetCharInstanceFromCode
+// artGetCharStaticFromCompiledCode
+// artGetCharInstanceFromCompiledCode
+// artSetCharStaticFromCompiledCode
+// artSetCharInstanceFromCompiledCode
+//
ART_GET_FIELD_FROM_CODE(Char, int16_t, size_t, uint16_t, Primitive, false, )
+
+// Define these functions:
+//
+// artGet32StaticFromCode
+// artGet32InstanceFromCode
+// artSet32StaticFromCode
+// artSet32InstanceFromCode
+// artGet32StaticFromCompiledCode
+// artGet32InstanceFromCompiledCode
+// artSet32StaticFromCompiledCode
+// artSet32InstanceFromCompiledCode
+//
ART_GET_FIELD_FROM_CODE(32, int32_t, size_t, uint32_t, Primitive, false, )
+
+// Define these functions:
+//
+// artGet64StaticFromCode
+// artGet64InstanceFromCode
+// artSet64StaticFromCode
+// artSet64InstanceFromCode
+// artGet64StaticFromCompiledCode
+// artGet64InstanceFromCompiledCode
+// artSet64StaticFromCompiledCode
+// artSet64InstanceFromCompiledCode
+//
ART_GET_FIELD_FROM_CODE(64, int64_t, uint64_t, uint64_t, Primitive, false, )
+
+// Define these functions:
+//
+// artGetObjStaticFromCode
+// artGetObjInstanceFromCode
+// artSetObjStaticFromCode
+// artSetObjInstanceFromCode
+// artGetObjStaticFromCompiledCode
+// artGetObjInstanceFromCompiledCode
+// artSetObjStaticFromCompiledCode
+// artSetObjInstanceFromCompiledCode
+//
ART_GET_FIELD_FROM_CODE(Obj, mirror::HeapReference<mirror::Object>, mirror::Object*,
mirror::Object*, Object, true, .Ptr())
+#undef ART_GET_FIELD_FROM_CODE
+
// To cut on the number of entrypoints, we have shared entries for
// byte/boolean and char/short for setting an instance or static field. We just
diff --git a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
index d4bc1c76b1..d22f180c7a 100644
--- a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
@@ -28,7 +28,7 @@ extern "C" int artHandleFillArrayDataFromCode(uint32_t payload_offset, mirror::A
ArtMethod* method, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
ScopedQuickEntrypointChecks sqec(self);
- const uint16_t* const insns = method->GetCodeItem()->insns_;
+ const uint16_t* const insns = method->DexInstructions().Insns();
const Instruction::ArrayDataPayload* payload =
reinterpret_cast<const Instruction::ArrayDataPayload*>(insns + payload_offset);
bool success = FillArrayData(array, payload);
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 29a62c86ee..3c41a8c3b5 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -14,9 +14,10 @@
* limitations under the License.
*/
+#include <android-base/logging.h>
+
#include "art_method-inl.h"
#include "base/casts.h"
-#include "base/logging.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "indirect_reference_table.h"
#include "mirror/object-inl.h"
@@ -50,8 +51,8 @@ extern void ReadBarrierJni(mirror::CompressedReference<mirror::Object>* handle_o
extern uint32_t JniMethodFastStart(Thread* self) {
JNIEnvExt* env = self->GetJniEnv();
DCHECK(env != nullptr);
- uint32_t saved_local_ref_cookie = bit_cast<uint32_t>(env->local_ref_cookie);
- env->local_ref_cookie = env->locals.GetSegmentState();
+ uint32_t saved_local_ref_cookie = bit_cast<uint32_t>(env->GetLocalRefCookie());
+ env->SetLocalRefCookie(env->GetLocalsSegmentState());
if (kIsDebugBuild) {
ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
@@ -65,8 +66,8 @@ extern uint32_t JniMethodFastStart(Thread* self) {
extern uint32_t JniMethodStart(Thread* self) {
JNIEnvExt* env = self->GetJniEnv();
DCHECK(env != nullptr);
- uint32_t saved_local_ref_cookie = bit_cast<uint32_t>(env->local_ref_cookie);
- env->local_ref_cookie = env->locals.GetSegmentState();
+ uint32_t saved_local_ref_cookie = bit_cast<uint32_t>(env->GetLocalRefCookie());
+ env->SetLocalRefCookie(env->GetLocalsSegmentState());
ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
// TODO: Introduce special entrypoint for synchronized @FastNative methods?
// Or ban synchronized @FastNative outright to avoid the extra check here?
@@ -114,11 +115,11 @@ ALWAYS_INLINE static inline void GoToRunnableFast(Thread* self) {
static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
JNIEnvExt* env = self->GetJniEnv();
- if (UNLIKELY(env->check_jni)) {
+ if (UNLIKELY(env->IsCheckJniEnabled())) {
env->CheckNoHeldMonitors();
}
- env->locals.SetSegmentState(env->local_ref_cookie);
- env->local_ref_cookie = bit_cast<IRTSegmentState>(saved_local_ref_cookie);
+ env->SetLocalSegmentState(env->GetLocalRefCookie());
+ env->SetLocalRefCookie(bit_cast<IRTSegmentState>(saved_local_ref_cookie));
self->PopHandleScope();
}
@@ -155,7 +156,7 @@ static mirror::Object* JniMethodEndWithReferenceHandleResult(jobject result,
}
PopLocalReferences(saved_local_ref_cookie, self);
// Process result.
- if (UNLIKELY(self->GetJniEnv()->check_jni)) {
+ if (UNLIKELY(self->GetJniEnv()->IsCheckJniEnabled())) {
// CheckReferenceResult can resolve types.
StackHandleScope<1> hs(self);
HandleWrapperObjPtr<mirror::Object> h_obj(hs.NewHandleWrapper(&o));
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 0a76cddf5e..f727690c11 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -20,9 +20,9 @@
#include "callee_save_frame.h"
#include "common_throws.h"
#include "debugger.h"
-#include "dex_file-inl.h"
-#include "dex_file_types.h"
-#include "dex_instruction-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_types.h"
+#include "dex/dex_instruction-inl.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
@@ -784,8 +784,8 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self,
DCHECK(!method->IsNative()) << method->PrettyMethod();
uint32_t shorty_len = 0;
ArtMethod* non_proxy_method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
- const DexFile::CodeItem* code_item = non_proxy_method->GetCodeItem();
- DCHECK(code_item != nullptr) << method->PrettyMethod();
+ DCHECK(non_proxy_method->GetCodeItem() != nullptr) << method->PrettyMethod();
+ CodeItemDataAccessor accessor(non_proxy_method);
const char* shorty = non_proxy_method->GetShorty(&shorty_len);
JValue result;
@@ -795,12 +795,12 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self,
} else {
const char* old_cause = self->StartAssertNoThreadSuspension(
"Building interpreter shadow frame");
- uint16_t num_regs = code_item->registers_size_;
+ uint16_t num_regs = accessor.RegistersSize();
// No last shadow coming from quick.
ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
CREATE_SHADOW_FRAME(num_regs, /* link */ nullptr, method, /* dex pc */ 0);
ShadowFrame* shadow_frame = shadow_frame_unique_ptr.get();
- size_t first_arg_reg = code_item->registers_size_ - code_item->ins_size_;
+ size_t first_arg_reg = accessor.RegistersSize() - accessor.InsSize();
BuildQuickShadowFrameVisitor shadow_frame_builder(sp, method->IsStatic(), shorty, shorty_len,
shadow_frame, first_arg_reg);
shadow_frame_builder.VisitArguments();
@@ -823,7 +823,7 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self,
}
}
- result = interpreter::EnterInterpreterFromEntryPoint(self, code_item, shadow_frame);
+ result = interpreter::EnterInterpreterFromEntryPoint(self, accessor, shadow_frame);
}
// Pop transition.
@@ -1121,10 +1121,9 @@ extern "C" const void* artQuickResolutionTrampoline(
// code.
if (!found_stack_map || kIsDebugBuild) {
uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
- const DexFile::CodeItem* code;
- code = caller->GetCodeItem();
- CHECK_LT(dex_pc, code->insns_size_in_code_units_);
- const Instruction& instr = code->InstructionAt(dex_pc);
+ CodeItemInstructionAccessor accessor(caller);
+ CHECK_LT(dex_pc, accessor.InsnsSizeInCodeUnits());
+ const Instruction& instr = accessor.InstructionAt(dex_pc);
Instruction::Code instr_code = instr.Opcode();
bool is_range;
switch (instr_code) {
@@ -1250,17 +1249,8 @@ extern "C" const void* artQuickResolutionTrampoline(
} else {
DCHECK_EQ(invoke_type, kSuper);
CHECK(caller != nullptr) << invoke_type;
- StackHandleScope<2> hs(self);
- Handle<mirror::DexCache> dex_cache(
- hs.NewHandle(caller->GetDeclaringClass()->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(caller->GetDeclaringClass()->GetClassLoader()));
- // TODO Maybe put this into a mirror::Class function.
ObjPtr<mirror::Class> ref_class = linker->LookupResolvedType(
- *dex_cache->GetDexFile(),
- dex_cache->GetDexFile()->GetMethodId(called_method.index).class_idx_,
- dex_cache.Get(),
- class_loader.Get());
+ caller->GetDexFile()->GetMethodId(called_method.index).class_idx_, caller);
if (ref_class->IsInterface()) {
called = ref_class->FindVirtualMethodForInterfaceSuper(called, kRuntimePointerSize);
} else {
@@ -2459,9 +2449,7 @@ extern "C" TwoWordReturn artInvokeInterfaceTrampoline(ArtMethod* interface_metho
// Fetch the dex_method_idx of the target interface method from the caller.
uint32_t dex_method_idx;
uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
- const DexFile::CodeItem* code_item = caller_method->GetCodeItem();
- DCHECK_LT(dex_pc, code_item->insns_size_in_code_units_);
- const Instruction& instr = code_item->InstructionAt(dex_pc);
+ const Instruction& instr = caller_method->DexInstructions().InstructionAt(dex_pc);
Instruction::Code instr_code = instr.Opcode();
DCHECK(instr_code == Instruction::INVOKE_INTERFACE ||
instr_code == Instruction::INVOKE_INTERFACE_RANGE)
@@ -2576,13 +2564,11 @@ extern "C" uintptr_t artInvokePolymorphic(
// From the instruction, get the |callsite_shorty| and expose arguments on the stack to the GC.
ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
- const DexFile::CodeItem* code = caller_method->GetCodeItem();
- const Instruction& inst = code->InstructionAt(dex_pc);
+ const Instruction& inst = caller_method->DexInstructions().InstructionAt(dex_pc);
DCHECK(inst.Opcode() == Instruction::INVOKE_POLYMORPHIC ||
inst.Opcode() == Instruction::INVOKE_POLYMORPHIC_RANGE);
- const DexFile* dex_file = caller_method->GetDexFile();
const uint32_t proto_idx = inst.VRegH();
- const char* shorty = dex_file->GetShorty(proto_idx);
+ const char* shorty = caller_method->GetDexFile()->GetShorty(proto_idx);
const size_t shorty_length = strlen(shorty);
static const bool kMethodIsStatic = false; // invoke() and invokeExact() are not static.
RememberForGcArgumentVisitor gc_visitor(sp, kMethodIsStatic, shorty, shorty_length, &soa);
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 6a4e5b5f01..49c2a15e86 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -21,9 +21,10 @@
#include <sys/ucontext.h>
#include "art_method-inl.h"
+#include "base/logging.h" // For VLOG
#include "base/safe_copy.h"
#include "base/stl_util.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "mirror/class.h"
#include "mirror/object_reference.h"
#include "oat_quick_method_header.h"
diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h
index 3d0e8172b6..72eb8274c8 100644
--- a/runtime/gc/accounting/atomic_stack.h
+++ b/runtime/gc/accounting/atomic_stack.h
@@ -23,8 +23,9 @@
#include <memory>
#include <string>
+#include <android-base/logging.h>
+
#include "atomic.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "mem_map.h"
#include "stack_reference.h"
@@ -108,7 +109,7 @@ class AtomicStack {
// Stack overflow.
return false;
}
- } while (!back_index_.CompareExchangeWeakRelaxed(index, new_index));
+ } while (!back_index_.CompareAndSetWeakRelaxed(index, new_index));
*start_address = begin_ + index;
*end_address = begin_ + new_index;
if (kIsDebugBuild) {
@@ -240,7 +241,7 @@ class AtomicStack {
// Stack overflow.
return false;
}
- } while (!back_index_.CompareExchangeWeakRelaxed(index, index + 1));
+ } while (!back_index_.CompareAndSetWeakRelaxed(index, index + 1));
begin_[index].Assign(value);
return true;
}
diff --git a/runtime/gc/accounting/bitmap-inl.h b/runtime/gc/accounting/bitmap-inl.h
index cd3923abbe..bf153f56d8 100644
--- a/runtime/gc/accounting/bitmap-inl.h
+++ b/runtime/gc/accounting/bitmap-inl.h
@@ -21,9 +21,10 @@
#include <memory>
+#include <android-base/logging.h>
+
#include "atomic.h"
#include "base/bit_utils.h"
-#include "base/logging.h"
namespace art {
namespace gc {
@@ -42,8 +43,7 @@ inline bool Bitmap::AtomicTestAndSetBit(uintptr_t bit_index) {
DCHECK(TestBit(bit_index));
return true;
}
- } while (!atomic_entry->CompareExchangeWeakSequentiallyConsistent(old_word,
- old_word | word_mask));
+ } while (!atomic_entry->CompareAndSetWeakSequentiallyConsistent(old_word, old_word | word_mask));
DCHECK(TestBit(bit_index));
return false;
}
diff --git a/runtime/gc/accounting/card_table-inl.h b/runtime/gc/accounting/card_table-inl.h
index 6ff53597e4..adca5c835e 100644
--- a/runtime/gc/accounting/card_table-inl.h
+++ b/runtime/gc/accounting/card_table-inl.h
@@ -17,10 +17,12 @@
#ifndef ART_RUNTIME_GC_ACCOUNTING_CARD_TABLE_INL_H_
#define ART_RUNTIME_GC_ACCOUNTING_CARD_TABLE_INL_H_
+#include "card_table.h"
+
+#include <android-base/logging.h>
+
#include "atomic.h"
#include "base/bit_utils.h"
-#include "base/logging.h"
-#include "card_table.h"
#include "mem_map.h"
#include "space_bitmap.h"
@@ -31,7 +33,7 @@ namespace accounting {
static inline bool byte_cas(uint8_t old_value, uint8_t new_value, uint8_t* address) {
#if defined(__i386__) || defined(__x86_64__)
Atomic<uint8_t>* byte_atomic = reinterpret_cast<Atomic<uint8_t>*>(address);
- return byte_atomic->CompareExchangeWeakRelaxed(old_value, new_value);
+ return byte_atomic->CompareAndSetWeakRelaxed(old_value, new_value);
#else
// Little endian means most significant byte is on the left.
const size_t shift_in_bytes = reinterpret_cast<uintptr_t>(address) % sizeof(uintptr_t);
@@ -45,7 +47,7 @@ static inline bool byte_cas(uint8_t old_value, uint8_t new_value, uint8_t* addre
~(static_cast<uintptr_t>(0xFF) << shift_in_bits);
const uintptr_t old_word = cur_word | (static_cast<uintptr_t>(old_value) << shift_in_bits);
const uintptr_t new_word = cur_word | (static_cast<uintptr_t>(new_value) << shift_in_bits);
- return word_atomic->CompareExchangeWeakRelaxed(old_word, new_word);
+ return word_atomic->CompareAndSetWeakRelaxed(old_word, new_word);
#endif
}
@@ -193,7 +195,7 @@ inline void CardTable::ModifyCardsAtomic(uint8_t* scan_begin,
new_bytes[i] = visitor(expected_bytes[i]);
}
Atomic<uintptr_t>* atomic_word = reinterpret_cast<Atomic<uintptr_t>*>(word_cur);
- if (LIKELY(atomic_word->CompareExchangeWeakRelaxed(expected_word, new_word))) {
+ if (LIKELY(atomic_word->CompareAndSetWeakRelaxed(expected_word, new_word))) {
for (size_t i = 0; i < sizeof(uintptr_t); ++i) {
const uint8_t expected_byte = expected_bytes[i];
const uint8_t new_byte = new_bytes[i];
diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc
index 01b5896650..934e57a61b 100644
--- a/runtime/gc/accounting/card_table.cc
+++ b/runtime/gc/accounting/card_table.cc
@@ -18,7 +18,6 @@
#include <sys/mman.h>
-#include "base/logging.h"
#include "base/systrace.h"
#include "card_table-inl.h"
#include "gc/heap.h"
diff --git a/runtime/gc/accounting/heap_bitmap.h b/runtime/gc/accounting/heap_bitmap.h
index 4237e7ee3f..c997f8dbfc 100644
--- a/runtime/gc/accounting/heap_bitmap.h
+++ b/runtime/gc/accounting/heap_bitmap.h
@@ -17,8 +17,11 @@
#ifndef ART_RUNTIME_GC_ACCOUNTING_HEAP_BITMAP_H_
#define ART_RUNTIME_GC_ACCOUNTING_HEAP_BITMAP_H_
+#include <android-base/logging.h>
+
#include "base/allocator.h"
-#include "base/logging.h"
+#include "base/macros.h"
+#include "base/mutex.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 1b3d0dadae..0dd05cd6f0 100644
--- a/runtime/gc/accounting/mod_union_table.cc
+++ b/runtime/gc/accounting/mod_union_table.cc
@@ -18,6 +18,7 @@
#include <memory>
+#include "base/logging.h" // For VLOG
#include "base/stl_util.h"
#include "bitmap-inl.h"
#include "card_table-inl.h"
diff --git a/runtime/gc/accounting/space_bitmap-inl.h b/runtime/gc/accounting/space_bitmap-inl.h
index b37dd965fc..df9ee8c219 100644
--- a/runtime/gc/accounting/space_bitmap-inl.h
+++ b/runtime/gc/accounting/space_bitmap-inl.h
@@ -21,9 +21,10 @@
#include <memory>
+#include <android-base/logging.h>
+
#include "atomic.h"
#include "base/bit_utils.h"
-#include "base/logging.h"
namespace art {
namespace gc {
@@ -46,7 +47,7 @@ inline bool SpaceBitmap<kAlignment>::AtomicTestAndSet(const mirror::Object* obj)
DCHECK(Test(obj));
return true;
}
- } while (!atomic_entry->CompareExchangeWeakRelaxed(old_word, old_word | mask));
+ } while (!atomic_entry->CompareAndSetWeakRelaxed(old_word, old_word | mask));
DCHECK(Test(obj));
return false;
}
diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc
index 280c0b1d69..237ee80ba0 100644
--- a/runtime/gc/accounting/space_bitmap.cc
+++ b/runtime/gc/accounting/space_bitmap.cc
@@ -19,7 +19,7 @@
#include "android-base/stringprintf.h"
#include "art_field-inl.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "mem_map.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
diff --git a/runtime/gc/allocation_record.cc b/runtime/gc/allocation_record.cc
index 2257b81e09..2ee4239e8a 100644
--- a/runtime/gc/allocation_record.cc
+++ b/runtime/gc/allocation_record.cc
@@ -18,6 +18,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
+#include "base/logging.h" // For VLOG
#include "base/stl_util.h"
#include "obj_ptr-inl.h"
#include "object_callbacks.h"
diff --git a/runtime/gc/allocator/dlmalloc.cc b/runtime/gc/allocator/dlmalloc.cc
index ef916f8745..65062208d6 100644
--- a/runtime/gc/allocator/dlmalloc.cc
+++ b/runtime/gc/allocator/dlmalloc.cc
@@ -16,8 +16,9 @@
#include "dlmalloc.h"
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
// ART specific morecore implementation defined in space.cc.
static void* art_heap_morecore(void* m, intptr_t increment);
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index b742ac4a7c..928abe873e 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -23,6 +23,7 @@
#include "android-base/stringprintf.h"
+#include "base/logging.h" // For VLOG
#include "base/memory_tool.h"
#include "base/mutex-inl.h"
#include "gc/space/memory_tool_settings.h"
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 2c90773b8f..6e5cf0ede8 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -26,9 +26,10 @@
#include <unordered_set>
#include <vector>
+#include <android-base/logging.h>
+
#include "base/allocator.h"
#include "base/bit_utils.h"
-#include "base/logging.h"
#include "base/mutex.h"
#include "globals.h"
#include "thread.h"
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 7beff960cc..cf837161e0 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -88,6 +88,7 @@ ConcurrentCopying::ConcurrentCopying(Heap* heap,
from_space_num_bytes_at_first_pause_(0),
mark_stack_mode_(kMarkStackModeOff),
weak_ref_access_enabled_(true),
+ max_peak_num_non_free_regions_(0),
skipped_blocks_lock_("concurrent copying bytes blocks lock", kMarkSweepMarkStackLock),
measure_read_barrier_slow_path_(measure_read_barrier_slow_path),
mark_from_read_barrier_measurements_(false),
@@ -760,7 +761,8 @@ class ConcurrentCopying::ImmuneSpaceScanObjVisitor {
// Done scanning the object, go back to white.
bool success = obj->AtomicSetReadBarrierState(ReadBarrier::GrayState(),
ReadBarrier::WhiteState());
- CHECK(success);
+ CHECK(success)
+ << Runtime::Current()->GetHeap()->GetVerification()->DumpObjectInfo(obj, "failed CAS");
}
} else {
collector_->ScanImmuneObject(obj);
@@ -1753,6 +1755,8 @@ void ConcurrentCopying::ReclaimPhase() {
cumulative_bytes_moved_.FetchAndAddRelaxed(to_bytes);
uint64_t to_objects = objects_moved_.LoadSequentiallyConsistent();
cumulative_objects_moved_.FetchAndAddRelaxed(to_objects);
+ max_peak_num_non_free_regions_ = std::max(max_peak_num_non_free_regions_,
+ region_space_->GetNumNonFreeRegions());
if (kEnableFromSpaceAccountingCheck) {
CHECK_EQ(from_space_num_objects_at_first_pause_, from_objects + unevac_from_objects);
CHECK_EQ(from_space_num_bytes_at_first_pause_, from_bytes + unevac_from_bytes);
@@ -2078,7 +2082,7 @@ inline void ConcurrentCopying::VisitRoots(
// It was updated by the mutator.
break;
}
- } while (!addr->CompareExchangeWeakRelaxed(expected_ref, new_ref));
+ } while (!addr->CompareAndSetWeakRelaxed(expected_ref, new_ref));
}
}
@@ -2097,7 +2101,7 @@ inline void ConcurrentCopying::MarkRoot(mirror::CompressedReference<mirror::Obje
// It was updated by the mutator.
break;
}
- } while (!addr->CompareExchangeWeakRelaxed(expected_ref, new_ref));
+ } while (!addr->CompareAndSetWeakRelaxed(expected_ref, new_ref));
}
}
@@ -2690,6 +2694,13 @@ void ConcurrentCopying::DumpPerformanceInfo(std::ostream& os) {
}
os << "Cumulative bytes moved " << cumulative_bytes_moved_.LoadRelaxed() << "\n";
os << "Cumulative objects moved " << cumulative_objects_moved_.LoadRelaxed() << "\n";
+
+ os << "Peak regions allocated "
+ << max_peak_num_non_free_regions_ << " ("
+ << PrettySize(max_peak_num_non_free_regions_ * space::RegionSpace::kRegionSize)
+ << ") / " << region_space_->GetNumRegions() << " ("
+ << PrettySize(region_space_->GetNumRegions() * space::RegionSpace::kRegionSize)
+ << ")\n";
}
} // namespace collector
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index 8b4b58e7b1..939e7fc8a4 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -308,6 +308,11 @@ class ConcurrentCopying : public GarbageCollector {
Atomic<uint64_t> cumulative_bytes_moved_;
Atomic<uint64_t> cumulative_objects_moved_;
+ // Maintain the maximum of number of non-free regions collected just before
+ // reclaim in each GC cycle. At this moment in cycle, highest number of
+ // regions are in non-free.
+ size_t max_peak_num_non_free_regions_;
+
// The skipped blocks are memory blocks/chucks that were copies of
// objects that were unused due to lost races (cas failures) at
// object copy/forward pointer install. They are reused.
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index c5a341fc80..fa34270d95 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -22,7 +22,7 @@
#include "base/dumpable.h"
#include "base/histogram-inl.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG_IS_ON.
#include "base/mutex-inl.h"
#include "base/systrace.h"
#include "base/time_utils.h"
diff --git a/runtime/gc/collector/immune_spaces.cc b/runtime/gc/collector/immune_spaces.cc
index 1024050409..3b5961899f 100644
--- a/runtime/gc/collector/immune_spaces.cc
+++ b/runtime/gc/collector/immune_spaces.cc
@@ -19,6 +19,7 @@
#include <tuple>
#include <vector>
+#include "base/logging.h" // For VLOG.
#include "gc/space/space-inl.h"
#include "mirror/object.h"
#include "oat_file.h"
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index aef98dee58..34cc129ce8 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -16,7 +16,9 @@
#include "mark_compact.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/macros.h"
#include "base/mutex-inl.h"
#include "base/timing_logger.h"
#include "gc/accounting/heap_bitmap-inl.h"
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index c6caf4b08e..fdfe949265 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -25,7 +25,7 @@
#include "base/bounded_fifo.h"
#include "base/enums.h"
#include "base/file_utils.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "base/mutex-inl.h"
#include "base/systrace.h"
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index 9fb37b6138..3150781a5a 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -22,7 +22,7 @@
#include <sstream>
#include <vector>
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "base/mutex-inl.h"
#include "base/timing_logger.h"
diff --git a/runtime/gc/gc_cause.cc b/runtime/gc/gc_cause.cc
index 871208037a..d88fcdcc95 100644
--- a/runtime/gc/gc_cause.cc
+++ b/runtime/gc/gc_cause.cc
@@ -15,7 +15,10 @@
*/
#include "gc_cause.h"
-#include "base/logging.h"
+
+#include <android-base/logging.h>
+
+#include "base/macros.h"
#include "globals.h"
#include <ostream>
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 2047646413..52dd104ac8 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -401,8 +401,7 @@ inline bool Heap::IsOutOfMemoryOnAllocation(AllocatorType allocator_type,
return true;
}
// TODO: Grow for allocation is racy, fix it.
- VLOG(heap) << "Growing heap from " << PrettySize(max_allowed_footprint_) << " to "
- << PrettySize(new_footprint) << " for a " << PrettySize(alloc_size) << " allocation";
+ VlogHeapGrowth(max_allowed_footprint_, new_footprint, alloc_size);
max_allowed_footprint_ = new_footprint;
}
}
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 9f6266612a..9edba96ddd 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -30,6 +30,7 @@
#include "base/dumpable.h"
#include "base/file_utils.h"
#include "base/histogram-inl.h"
+#include "base/logging.h" // For VLOG.
#include "base/memory_tool.h"
#include "base/stl_util.h"
#include "base/systrace.h"
@@ -37,7 +38,7 @@
#include "common_throws.h"
#include "cutils/sched_policy.h"
#include "debugger.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "entrypoints/quick/quick_alloc_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/accounting/heap_bitmap-inl.h"
@@ -799,12 +800,11 @@ void Heap::IncrementDisableThreadFlip(Thread* self) {
bool has_waited = false;
uint64_t wait_start = NanoTime();
if (thread_flip_running_) {
- ATRACE_BEGIN("IncrementDisableThreadFlip");
+ ScopedTrace trace("IncrementDisableThreadFlip");
while (thread_flip_running_) {
has_waited = true;
thread_flip_cond_->Wait(self);
}
- ATRACE_END();
}
++disable_thread_flip_count_;
if (has_waited) {
@@ -1127,7 +1127,7 @@ static inline AllocationListener* GetAndOverwriteAllocationListener(
AllocationListener* old;
do {
old = storage->LoadSequentiallyConsistent();
- } while (!storage->CompareExchangeStrongSequentiallyConsistent(old, new_value));
+ } while (!storage->CompareAndSetStrongSequentiallyConsistent(old, new_value));
return old;
}
@@ -1299,7 +1299,7 @@ class TrimIndirectReferenceTableClosure : public Closure {
explicit TrimIndirectReferenceTableClosure(Barrier* barrier) : barrier_(barrier) {
}
virtual void Run(Thread* thread) OVERRIDE NO_THREAD_SAFETY_ANALYSIS {
- thread->GetJniEnv()->locals.Trim();
+ thread->GetJniEnv()->TrimLocals();
// If thread is a running mutator, then act on behalf of the trim thread.
// See the code in ThreadList::RunCheckpoint.
barrier_->Pass(Thread::Current());
@@ -1796,19 +1796,25 @@ uint64_t Heap::GetBytesAllocatedEver() const {
return GetBytesFreedEver() + GetBytesAllocated();
}
+// Check whether the given object is an instance of the given class.
+static bool MatchesClass(mirror::Object* obj,
+ Handle<mirror::Class> h_class,
+ bool use_is_assignable_from) REQUIRES_SHARED(Locks::mutator_lock_) {
+ mirror::Class* instance_class = obj->GetClass();
+ CHECK(instance_class != nullptr);
+ ObjPtr<mirror::Class> klass = h_class.Get();
+ if (use_is_assignable_from) {
+ return klass != nullptr && klass->IsAssignableFrom(instance_class);
+ }
+ return instance_class == klass;
+}
+
void Heap::CountInstances(const std::vector<Handle<mirror::Class>>& classes,
bool use_is_assignable_from,
uint64_t* counts) {
auto instance_counter = [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Class* instance_class = obj->GetClass();
- CHECK(instance_class != nullptr);
for (size_t i = 0; i < classes.size(); ++i) {
- ObjPtr<mirror::Class> klass = classes[i].Get();
- if (use_is_assignable_from) {
- if (klass != nullptr && klass->IsAssignableFrom(instance_class)) {
- ++counts[i];
- }
- } else if (instance_class == klass) {
+ if (MatchesClass(obj, classes[i], use_is_assignable_from)) {
++counts[i];
}
}
@@ -1818,11 +1824,12 @@ void Heap::CountInstances(const std::vector<Handle<mirror::Class>>& classes,
void Heap::GetInstances(VariableSizedHandleScope& scope,
Handle<mirror::Class> h_class,
+ bool use_is_assignable_from,
int32_t max_count,
std::vector<Handle<mirror::Object>>& instances) {
DCHECK_GE(max_count, 0);
auto instance_collector = [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
- if (obj->GetClass() == h_class.Get()) {
+ if (MatchesClass(obj, h_class, use_is_assignable_from)) {
if (max_count == 0 || instances.size() < static_cast<size_t>(max_count)) {
instances.push_back(scope.NewHandle(obj));
}
@@ -1876,10 +1883,10 @@ void Heap::GetReferringObjects(VariableSizedHandleScope& scope,
VisitObjects(referring_objects_finder);
}
-void Heap::CollectGarbage(bool clear_soft_references) {
+void Heap::CollectGarbage(bool clear_soft_references, GcCause cause) {
// Even if we waited for a GC we still need to do another GC since weaks allocated during the
// last GC will not have necessarily been cleared.
- CollectGarbageInternal(gc_plan_.back(), kGcCauseExplicit, clear_soft_references);
+ CollectGarbageInternal(gc_plan_.back(), cause, clear_soft_references);
}
bool Heap::SupportHomogeneousSpaceCompactAndCollectorTransitions() const {
@@ -3594,7 +3601,7 @@ void Heap::ClearConcurrentGCRequest() {
void Heap::RequestConcurrentGC(Thread* self, GcCause cause, bool force_full) {
if (CanAddHeapTask(self) &&
- concurrent_gc_pending_.CompareExchangeStrongSequentiallyConsistent(false, true)) {
+ concurrent_gc_pending_.CompareAndSetStrongSequentiallyConsistent(false, true)) {
task_processor_->AddTask(self, new ConcurrentGCTask(NanoTime(), // Start straight away.
cause,
force_full));
@@ -3839,7 +3846,7 @@ void Heap::RegisterNativeFree(JNIEnv*, size_t bytes) {
do {
allocated = new_native_bytes_allocated_.LoadRelaxed();
new_freed_bytes = std::min(allocated, bytes);
- } while (!new_native_bytes_allocated_.CompareExchangeWeakRelaxed(allocated,
+ } while (!new_native_bytes_allocated_.CompareAndSetWeakRelaxed(allocated,
allocated - new_freed_bytes));
if (new_freed_bytes < bytes) {
old_native_bytes_allocated_.FetchAndSubRelaxed(bytes - new_freed_bytes);
@@ -4149,5 +4156,10 @@ const Verification* Heap::GetVerification() const {
return verification_.get();
}
+void Heap::VlogHeapGrowth(size_t max_allowed_footprint, size_t new_footprint, size_t alloc_size) {
+ VLOG(heap) << "Growing heap from " << PrettySize(max_allowed_footprint) << " to "
+ << PrettySize(new_footprint) << " for a " << PrettySize(alloc_size) << " allocation";
+}
+
} // namespace gc
} // namespace art
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 4d7424c7ef..7dcf82f415 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -22,11 +22,14 @@
#include <unordered_set>
#include <vector>
+#include <android-base/logging.h>
+
#include "allocator_type.h"
#include "arch/instruction_set.h"
#include "atomic.h"
-#include "base/logging.h"
+#include "base/macros.h"
#include "base/mutex.h"
+#include "base/runtime_debug.h"
#include "base/time_utils.h"
#include "gc/collector/gc_type.h"
#include "gc/collector/iteration.h"
@@ -330,7 +333,7 @@ class Heap {
REQUIRES_SHARED(Locks::mutator_lock_);
// Initiates an explicit garbage collection.
- void CollectGarbage(bool clear_soft_references)
+ void CollectGarbage(bool clear_soft_references, GcCause cause = kGcCauseExplicit)
REQUIRES(!*gc_complete_lock_, !*pending_task_lock_);
// Does a concurrent GC, should only be called by the GC daemon thread
@@ -346,9 +349,10 @@ class Heap {
REQUIRES(!Locks::heap_bitmap_lock_, !*gc_complete_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Implements JDWP RT_Instances.
+ // Implements VMDebug.getInstancesOfClasses and JDWP RT_Instances.
void GetInstances(VariableSizedHandleScope& scope,
Handle<mirror::Class> c,
+ bool use_is_assignable_from,
int32_t max_count,
std::vector<Handle<mirror::Object>>& instances)
REQUIRES(!Locks::heap_bitmap_lock_, !*gc_complete_lock_)
@@ -1095,6 +1099,9 @@ class Heap {
void TraceHeapSize(size_t heap_size);
+ // Remove a vlog code from heap-inl.h which is transitively included in half the world.
+ static void VlogHeapGrowth(size_t max_allowed_footprint, size_t new_footprint, size_t alloc_size);
+
// All-known continuous spaces, where objects lie within fixed bounds.
std::vector<space::ContinuousSpace*> continuous_spaces_ GUARDED_BY(Locks::mutator_lock_);
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index d58d09c794..c59642fe4e 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -273,7 +273,7 @@ void ReferenceProcessor::EnqueueClearedReferences(Thread* self) {
jobject cleared_references;
{
ReaderMutexLock mu(self, *Locks::mutator_lock_);
- cleared_references = self->GetJniEnv()->vm->AddGlobalRef(
+ cleared_references = self->GetJniEnv()->GetVm()->AddGlobalRef(
self, cleared_references_.GetList());
}
if (kAsyncReferenceQueueAdd) {
diff --git a/runtime/gc/space/bump_pointer_space-inl.h b/runtime/gc/space/bump_pointer_space-inl.h
index 1509bb027d..9ebb131ad1 100644
--- a/runtime/gc/space/bump_pointer_space-inl.h
+++ b/runtime/gc/space/bump_pointer_space-inl.h
@@ -74,7 +74,7 @@ inline mirror::Object* BumpPointerSpace::AllocNonvirtualWithoutAccounting(size_t
if (UNLIKELY(new_end > growth_end_)) {
return nullptr;
}
- } while (!end_.CompareExchangeWeakSequentiallyConsistent(old_end, new_end));
+ } while (!end_.CompareAndSetWeakSequentiallyConsistent(old_end, new_end));
return reinterpret_cast<mirror::Object*>(old_end);
}
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index 576a35c52d..a3eef90e3a 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -16,6 +16,7 @@
#include "dlmalloc_space-inl.h"
+#include "base/logging.h" // For VLOG.
#include "base/time_utils.h"
#include "gc/accounting/card_table.h"
#include "gc/accounting/space_bitmap-inl.h"
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 74813b4dd1..251d94ca25 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -36,7 +36,7 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file_loader.h"
#include "exec_utils.h"
#include "gc/accounting/space_bitmap-inl.h"
#include "image-inl.h"
@@ -1587,7 +1587,9 @@ std::unique_ptr<ImageSpace> ImageSpace::CreateBootImage(const char* image_locati
if (!Runtime::Current()->IsImageDex2OatEnabled()) {
local_error_msg = "Patching disabled.";
} else if (secondary_image) {
- local_error_msg = "Cannot patch a secondary image.";
+ // We really want a working image. Prune and restart.
+ PruneDalvikCache(image_isa);
+ _exit(1);
} else if (ImageCreationAllowed(is_global_cache, image_isa, &local_error_msg)) {
bool patch_success =
RelocateImage(image_location, cache_filename.c_str(), image_isa, &local_error_msg);
diff --git a/runtime/gc/space/image_space_fs.h b/runtime/gc/space/image_space_fs.h
index a0ecb95ac7..6ce81e9209 100644
--- a/runtime/gc/space/image_space_fs.h
+++ b/runtime/gc/space/image_space_fs.h
@@ -23,7 +23,7 @@
#include "android-base/stringprintf.h"
#include "base/file_utils.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "base/unix_file/fd_file.h"
#include "globals.h"
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index 45f4f82448..d2efb102e9 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -20,7 +20,9 @@
#include <memory>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/macros.h"
#include "base/memory_tool.h"
#include "base/mutex-inl.h"
#include "base/stl_util.h"
diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc
index dcb783782f..17274b508d 100644
--- a/runtime/gc/space/malloc_space.cc
+++ b/runtime/gc/space/malloc_space.cc
@@ -18,6 +18,7 @@
#include "android-base/stringprintf.h"
+#include "base/logging.h" // For VLOG
#include "gc/accounting/card_table-inl.h"
#include "gc/accounting/space_bitmap-inl.h"
#include "gc/heap.h"
diff --git a/runtime/gc/space/region_space-inl.h b/runtime/gc/space/region_space-inl.h
index a3b53b4cad..ea2168fe9c 100644
--- a/runtime/gc/space/region_space-inl.h
+++ b/runtime/gc/space/region_space-inl.h
@@ -101,7 +101,7 @@ inline mirror::Object* RegionSpace::Region::Alloc(size_t num_bytes, size_t* byte
if (UNLIKELY(new_top > end_)) {
return nullptr;
}
- } while (!top_.CompareExchangeWeakRelaxed(old_top, new_top));
+ } while (!top_.CompareAndSetWeakRelaxed(old_top, new_top));
objects_allocated_.FetchAndAddRelaxed(1);
DCHECK_LE(Top(), end_);
DCHECK_LT(old_top, end_);
diff --git a/runtime/gc/space/region_space.h b/runtime/gc/space/region_space.h
index 77d76fb93b..c9c9136c27 100644
--- a/runtime/gc/space/region_space.h
+++ b/runtime/gc/space/region_space.h
@@ -138,6 +138,13 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace {
uint64_t GetObjectsAllocatedInUnevacFromSpace() REQUIRES(!region_lock_) {
return GetObjectsAllocatedInternal<RegionType::kRegionTypeUnevacFromSpace>();
}
+ // It is OK to do a racy read here as it's only for performance dump.
+ size_t GetNumNonFreeRegions() const {
+ return num_non_free_regions_;
+ }
+ size_t GetNumRegions() const {
+ return num_regions_;
+ }
bool CanMoveObjects() const OVERRIDE {
return true;
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index 5d1f191e4d..3a685cb82d 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -17,6 +17,7 @@
#include "rosalloc_space-inl.h"
+#include "base/logging.h" // For VLOG.
#include "base/time_utils.h"
#include "gc/accounting/card_table.h"
#include "gc/accounting/space_bitmap-inl.h"
diff --git a/runtime/gc/space/space.cc b/runtime/gc/space/space.cc
index 74ce273abf..2c6afa7eb8 100644
--- a/runtime/gc/space/space.cc
+++ b/runtime/gc/space/space.cc
@@ -16,7 +16,9 @@
#include "space.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/macros.h"
#include "gc/accounting/heap_bitmap.h"
#include "gc/accounting/space_bitmap-inl.h"
#include "gc/heap.h"
diff --git a/runtime/gc/verification.cc b/runtime/gc/verification.cc
index 3cd04a61e9..d99b37762f 100644
--- a/runtime/gc/verification.cc
+++ b/runtime/gc/verification.cc
@@ -86,7 +86,7 @@ void Verification::LogHeapCorruption(ObjPtr<mirror::Object> holder,
mirror::Object* ref,
bool fatal) const {
// Lowest priority logging first:
- PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT);
+ PrintFileToLog("/proc/self/maps", android::base::LogSeverity::FATAL_WITHOUT_ABORT);
MemMap::DumpMaps(LOG_STREAM(FATAL_WITHOUT_ABORT), true);
// Buffer the output in the string stream since it is more important than the stack traces
// and we want it to have log priority. The stack traces are printed from Runtime::Abort
diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h
index e1582120dc..46630dbeef 100644
--- a/runtime/generated/asm_support_gen.h
+++ b/runtime/generated/asm_support_gen.h
@@ -54,8 +54,6 @@ DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_DEX_CACHE_RESOLVED_METHODS_OFFSET),
DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_OBJECT_CLASS_OFFSET), (static_cast<int32_t>(art::mirror::Object::ClassOffset().Int32Value())))
#define MIRROR_OBJECT_LOCK_WORD_OFFSET 4
DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_OBJECT_LOCK_WORD_OFFSET), (static_cast<int32_t>(art::mirror::Object::MonitorOffset().Int32Value())))
-#define MIRROR_CLASS_STATUS_INITIALIZED 0xb
-DEFINE_CHECK_EQ(static_cast<uint32_t>(MIRROR_CLASS_STATUS_INITIALIZED), (static_cast<uint32_t>((art::mirror::Class::kStatusInitialized))))
#define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000
DEFINE_CHECK_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE), (static_cast<uint32_t>((art::kAccClassIsFinalizable))))
#define ACCESS_FLAGS_CLASS_IS_INTERFACE 0x200
diff --git a/runtime/handle.h b/runtime/handle.h
index ccff575495..18e503d1de 100644
--- a/runtime/handle.h
+++ b/runtime/handle.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_HANDLE_H_
#define ART_RUNTIME_HANDLE_H_
+#include <android-base/logging.h>
+
#include "base/casts.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "base/value_object.h"
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index f248a118e9..28a230291d 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -19,8 +19,9 @@
#include <stack>
+#include <android-base/logging.h>
+
#include "base/enums.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "handle.h"
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index 6a1a8c7271..ea8a68405f 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -36,17 +36,19 @@
#include <set>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "art_field-inl.h"
#include "art_method-inl.h"
-#include "base/logging.h"
+#include "base/macros.h"
+#include "base/mutex.h"
#include "base/time_utils.h"
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
#include "common_throws.h"
#include "debugger.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "gc/accounting/heap_bitmap.h"
#include "gc/allocation_record.h"
#include "gc/heap-visit-objects-inl.h"
diff --git a/runtime/image.cc b/runtime/image.cc
index 8f35d8474c..b9d955c08c 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
namespace art {
const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '1', '\0' }; // @FastNative access flags.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '2', '\0' }; // 4-bit ClassStatus.
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
diff --git a/runtime/image.h b/runtime/image.h
index 3844186a9b..159a308fb3 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -179,6 +179,10 @@ class PACKED(4) ImageHeader {
return patch_delta_;
}
+ void SetPatchDelta(off_t patch_delta) {
+ patch_delta_ = patch_delta;
+ }
+
static std::string GetOatLocationFromImageLocation(const std::string& image) {
return GetLocationFromImageLocation(image, "oat");
}
diff --git a/runtime/imtable-inl.h b/runtime/imtable-inl.h
index cb85fa6e56..6237cca9e4 100644
--- a/runtime/imtable-inl.h
+++ b/runtime/imtable-inl.h
@@ -20,7 +20,7 @@
#include "imtable.h"
#include "art_method-inl.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "utf.h"
namespace art {
diff --git a/runtime/indenter.h b/runtime/indenter.h
index 69b973252d..6361dd2092 100644
--- a/runtime/indenter.h
+++ b/runtime/indenter.h
@@ -20,7 +20,8 @@
#include <ostream>
#include <streambuf>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/macros.h"
namespace art {
diff --git a/runtime/index_bss_mapping.h b/runtime/index_bss_mapping.h
index d9f4e663a7..dcbc05c195 100644
--- a/runtime/index_bss_mapping.h
+++ b/runtime/index_bss_mapping.h
@@ -17,8 +17,9 @@
#ifndef ART_RUNTIME_INDEX_BSS_MAPPING_H_
#define ART_RUNTIME_INDEX_BSS_MAPPING_H_
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
namespace art {
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 2c8ec47492..51878312d9 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -357,7 +357,7 @@ bool IndirectReferenceTable::Remove(IRTSegmentState previous_state, IndirectRef
if (self->HandleScopeContains(reinterpret_cast<jobject>(iref))) {
auto* env = self->GetJniEnv();
DCHECK(env != nullptr);
- if (env->check_jni) {
+ if (env->IsCheckJniEnabled()) {
ScopedObjectAccess soa(self);
LOG(WARNING) << "Attempt to remove non-JNI local reference, dumping thread";
if (kDumpStackOnNonLocalReference) {
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index 6675099523..00184e2ed0 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -23,8 +23,10 @@
#include <limits>
#include <string>
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
+#include "base/macros.h"
#include "base/mutex.h"
#include "gc_root.h"
#include "obj_ptr.h"
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 49f202182d..4524448916 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -25,9 +25,9 @@
#include "base/callee_save_type.h"
#include "class_linker.h"
#include "debugger.h"
-#include "dex_file-inl.h"
-#include "dex_file_types.h"
-#include "dex_instruction-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_types.h"
+#include "dex/dex_instruction-inl.h"
#include "entrypoints/quick/quick_alloc_entrypoints.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "entrypoints/runtime_asm_entrypoints.h"
@@ -1246,18 +1246,17 @@ struct RuntimeMethodShortyVisitor : public StackVisitor {
shorty = m->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty()[0];
return false;
}
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- const Instruction* instr = Instruction::At(&code_item->insns_[GetDexPc()]);
- if (instr->IsInvoke()) {
+ const Instruction& instr = m->DexInstructions().InstructionAt(GetDexPc());
+ if (instr.IsInvoke()) {
const DexFile* dex_file = m->GetDexFile();
- if (interpreter::IsStringInit(dex_file, instr->VRegB())) {
+ if (interpreter::IsStringInit(dex_file, instr.VRegB())) {
// Invoking string init constructor is turned into invoking
// StringFactory.newStringFromChars() which returns a string.
shorty = 'L';
return false;
}
// A regular invoke, use callee's shorty.
- uint32_t method_idx = instr->VRegB();
+ uint32_t method_idx = instr.VRegB();
shorty = dex_file->GetMethodShorty(method_idx)[0];
}
// Stop stack walking since we've seen a Java frame.
diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc
index 89baa3504f..836bbe711f 100644
--- a/runtime/instrumentation_test.cc
+++ b/runtime/instrumentation_test.cc
@@ -21,7 +21,7 @@
#include "class_linker-inl.h"
#include "common_runtime_test.h"
#include "common_throws.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "gc/scoped_gc_critical_section.h"
#include "handle_scope-inl.h"
#include "jni_internal.h"
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 01b7d4e457..54db87297d 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -20,7 +20,7 @@
#include "common_dex_operations.h"
#include "common_throws.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "interpreter_common.h"
#include "interpreter_mterp_impl.h"
#include "interpreter_switch_impl.h"
@@ -240,7 +240,7 @@ static constexpr InterpreterImplKind kInterpreterImplKind = kMterpImplKind;
static inline JValue Execute(
Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame,
JValue result_register,
bool stay_in_interpreter = false) REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -254,11 +254,13 @@ static inline JValue Execute(
ArtMethod *method = shadow_frame.GetMethod();
if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
- instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
- method, 0);
+ instrumentation->MethodEnterEvent(self,
+ shadow_frame.GetThisObject(accessor.InsSize()),
+ method,
+ 0);
if (UNLIKELY(self->IsExceptionPending())) {
instrumentation->MethodUnwindEvent(self,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
method,
0);
return JValue();
@@ -277,7 +279,7 @@ static inline JValue Execute(
// Calculate the offset of the first input reg. The input registers are in the high regs.
// It's ok to access the code item here since JIT code will have been touched by the
// interpreter and compiler already.
- uint16_t arg_offset = code_item->registers_size_ - code_item->ins_size_;
+ uint16_t arg_offset = accessor.RegistersSize() - accessor.InsSize();
ArtInterpreterToCompiledCodeBridge(self, nullptr, &shadow_frame, arg_offset, &result);
// Push the shadow frame back as the caller will expect it.
self->PushShadowFrame(&shadow_frame);
@@ -302,27 +304,27 @@ static inline JValue Execute(
if (kInterpreterImplKind == kMterpImplKind) {
if (transaction_active) {
// No Mterp variant - just use the switch interpreter.
- return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<false, true>(self, accessor, shadow_frame, result_register,
false);
} else if (UNLIKELY(!Runtime::Current()->IsStarted())) {
- return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register,
false);
} else {
while (true) {
// Mterp does not support all instrumentation/debugging.
if (MterpShouldSwitchInterpreters() != 0) {
- return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register,
false);
}
bool returned = ExecuteMterpImpl(self,
- code_item->insns_,
+ accessor.Insns(),
&shadow_frame,
&result_register);
if (returned) {
return result_register;
} else {
// Mterp didn't like that instruction. Single-step it with the reference interpreter.
- result_register = ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame,
+ result_register = ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame,
result_register, true);
if (shadow_frame.GetDexPC() == dex::kDexNoIndex) {
// Single-stepped a return or an exception not handled locally. Return to caller.
@@ -334,10 +336,10 @@ static inline JValue Execute(
} else {
DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
if (transaction_active) {
- return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<false, true>(self, accessor, shadow_frame, result_register,
false);
} else {
- return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register,
false);
}
}
@@ -346,19 +348,19 @@ static inline JValue Execute(
if (kInterpreterImplKind == kMterpImplKind) {
// No access check variants for Mterp. Just use the switch version.
if (transaction_active) {
- return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<true, true>(self, accessor, shadow_frame, result_register,
false);
} else {
- return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<true, false>(self, accessor, shadow_frame, result_register,
false);
}
} else {
DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
if (transaction_active) {
- return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<true, true>(self, accessor, shadow_frame, result_register,
false);
} else {
- return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<true, false>(self, accessor, shadow_frame, result_register,
false);
}
}
@@ -387,12 +389,12 @@ void EnterInterpreterFromInvoke(Thread* self,
}
const char* old_cause = self->StartAssertNoThreadSuspension("EnterInterpreterFromInvoke");
- const DexFile::CodeItem* code_item = method->GetCodeItem();
+ CodeItemDataAccessor accessor(method);
uint16_t num_regs;
uint16_t num_ins;
- if (code_item != nullptr) {
- num_regs = code_item->registers_size_;
- num_ins = code_item->ins_size_;
+ if (accessor.HasCodeItem()) {
+ num_regs = accessor.RegistersSize();
+ num_ins = accessor.InsSize();
} else if (!method->IsInvokable()) {
self->EndAssertNoThreadSuspension(old_cause);
method->ThrowInvocationTimeError();
@@ -454,7 +456,7 @@ void EnterInterpreterFromInvoke(Thread* self,
}
}
if (LIKELY(!method->IsNative())) {
- JValue r = Execute(self, code_item, *shadow_frame, JValue(), stay_in_interpreter);
+ JValue r = Execute(self, accessor, *shadow_frame, JValue(), stay_in_interpreter);
if (result != nullptr) {
*result = r;
}
@@ -497,7 +499,7 @@ void EnterInterpreterFromDeoptimize(Thread* self,
DCHECK(!shadow_frame->GetMethod()->MustCountLocks());
self->SetTopOfShadowStack(shadow_frame);
- const DexFile::CodeItem* code_item = shadow_frame->GetMethod()->GetCodeItem();
+ CodeItemDataAccessor accessor(shadow_frame->GetMethod());
const uint32_t dex_pc = shadow_frame->GetDexPC();
uint32_t new_dex_pc = dex_pc;
if (UNLIKELY(self->IsExceptionPending())) {
@@ -510,7 +512,7 @@ void EnterInterpreterFromDeoptimize(Thread* self,
self, *shadow_frame, instrumentation) ? shadow_frame->GetDexPC() : dex::kDexNoIndex;
} else if (!from_code) {
// Deoptimization is not called from code directly.
- const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]);
+ const Instruction* instr = &accessor.InstructionAt(dex_pc);
if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc) {
DCHECK(first);
// Need to re-execute the dex instruction.
@@ -566,7 +568,7 @@ void EnterInterpreterFromDeoptimize(Thread* self,
}
if (new_dex_pc != dex::kDexNoIndex) {
shadow_frame->SetDexPC(new_dex_pc);
- value = Execute(self, code_item, *shadow_frame, value);
+ value = Execute(self, accessor, *shadow_frame, value);
}
ShadowFrame* old_frame = shadow_frame;
shadow_frame = shadow_frame->GetLink();
@@ -580,7 +582,7 @@ void EnterInterpreterFromDeoptimize(Thread* self,
ret_val->SetJ(value.GetJ());
}
-JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item,
+JValue EnterInterpreterFromEntryPoint(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame* shadow_frame) {
DCHECK_EQ(self, Thread::Current());
bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
@@ -593,11 +595,11 @@ JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* cod
if (jit != nullptr) {
jit->NotifyCompiledCodeToInterpreterTransition(self, shadow_frame->GetMethod());
}
- return Execute(self, code_item, *shadow_frame, JValue());
+ return Execute(self, accessor, *shadow_frame, JValue());
}
void ArtInterpreterToInterpreterBridge(Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
ShadowFrame* shadow_frame,
JValue* result) {
bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
@@ -626,7 +628,7 @@ void ArtInterpreterToInterpreterBridge(Thread* self,
}
if (LIKELY(!shadow_frame->GetMethod()->IsNative())) {
- result->SetJ(Execute(self, code_item, *shadow_frame, JValue()).GetJ());
+ result->SetJ(Execute(self, accessor, *shadow_frame, JValue()).GetJ());
} else {
// We don't expect to be asked to interpret native code (which is entered via a JNI compiler
// generated stub) except during testing and image writing.
diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h
index df8568edcd..0d43b9090a 100644
--- a/runtime/interpreter/interpreter.h
+++ b/runtime/interpreter/interpreter.h
@@ -18,7 +18,7 @@
#define ART_RUNTIME_INTERPRETER_INTERPRETER_H_
#include "base/mutex.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "obj_ptr.h"
namespace art {
@@ -27,6 +27,7 @@ class Object;
} // namespace mirror
class ArtMethod;
+class CodeItemDataAccessor;
union JValue;
class ShadowFrame;
class Thread;
@@ -52,12 +53,15 @@ extern void EnterInterpreterFromDeoptimize(Thread* self,
DeoptimizationMethodType method_type)
REQUIRES_SHARED(Locks::mutator_lock_);
-extern JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item,
+extern JValue EnterInterpreterFromEntryPoint(Thread* self,
+ const CodeItemDataAccessor& accessor,
ShadowFrame* shadow_frame)
REQUIRES_SHARED(Locks::mutator_lock_);
-void ArtInterpreterToInterpreterBridge(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result)
+void ArtInterpreterToInterpreterBridge(Thread* self,
+ const CodeItemDataAccessor& accessor,
+ ShadowFrame* shadow_frame,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
// One-time sanity check.
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index d2d017e118..475f93803d 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -20,7 +20,7 @@
#include "base/enums.h"
#include "debugger.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "intrinsics_enum.h"
#include "jit/jit.h"
@@ -1062,7 +1062,7 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self,
// The second parameter is the name to lookup.
{
dex::StringIndex name_idx(static_cast<uint32_t>(it.GetJavaValue().i));
- ObjPtr<mirror::String> name = class_linker->ResolveString(*dex_file, name_idx, dex_cache);
+ ObjPtr<mirror::String> name = class_linker->ResolveString(name_idx, dex_cache);
if (name.IsNull()) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -1073,12 +1073,8 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self,
// The third parameter is the method type associated with the name.
uint32_t method_type_idx = static_cast<uint32_t>(it.GetJavaValue().i);
- Handle<mirror::MethodType>
- method_type(hs.NewHandle(class_linker->ResolveMethodType(self,
- *dex_file,
- method_type_idx,
- dex_cache,
- class_loader)));
+ Handle<mirror::MethodType> method_type(hs.NewHandle(
+ class_linker->ResolveMethodType(self, method_type_idx, dex_cache, class_loader)));
if (method_type.IsNull()) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -1113,7 +1109,7 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self,
case EncodedArrayValueIterator::ValueType::kMethodType: {
uint32_t idx = static_cast<uint32_t>(jvalue.i);
ObjPtr<mirror::MethodType> ref =
- class_linker->ResolveMethodType(self, *dex_file, idx, dex_cache, class_loader);
+ class_linker->ResolveMethodType(self, idx, dex_cache, class_loader);
if (ref.IsNull()) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -1136,7 +1132,7 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self,
}
case EncodedArrayValueIterator::ValueType::kString: {
dex::StringIndex idx(static_cast<uint32_t>(jvalue.i));
- ObjPtr<mirror::String> ref = class_linker->ResolveString(*dex_file, idx, dex_cache);
+ ObjPtr<mirror::String> ref = class_linker->ResolveString(idx, dex_cache);
if (ref.IsNull()) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -1147,8 +1143,7 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self,
}
case EncodedArrayValueIterator::ValueType::kType: {
dex::TypeIndex idx(static_cast<uint32_t>(jvalue.i));
- ObjPtr<mirror::Class> ref =
- class_linker->ResolveType(*dex_file, idx, dex_cache, class_loader);
+ ObjPtr<mirror::Class> ref = class_linker->ResolveType(idx, dex_cache, class_loader);
if (ref.IsNull()) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -1325,7 +1320,7 @@ static inline bool DoCallCommon(ArtMethod* called_method,
}
// Compute method information.
- const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+ CodeItemDataAccessor accessor(called_method);
// Number of registers for the callee's call frame.
uint16_t num_regs;
// Test whether to use the interpreter or compiler entrypoint, and save that result to pass to
@@ -1339,7 +1334,7 @@ static inline bool DoCallCommon(ArtMethod* called_method,
ClassLinker::ShouldUseInterpreterEntrypoint(
called_method,
called_method->GetEntryPointFromQuickCompiledCode());
- if (LIKELY(code_item != nullptr)) {
+ if (LIKELY(accessor.HasCodeItem())) {
// When transitioning to compiled code, space only needs to be reserved for the input registers.
// The rest of the frame gets discarded. This also prevents accessing the called method's code
// item, saving memory by keeping code items of compiled code untouched.
@@ -1347,8 +1342,8 @@ static inline bool DoCallCommon(ArtMethod* called_method,
DCHECK(!Runtime::Current()->IsAotCompiler()) << "Compiler should use interpreter entrypoint";
num_regs = number_of_inputs;
} else {
- num_regs = code_item->registers_size_;
- DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, code_item->ins_size_);
+ num_regs = accessor.RegistersSize();
+ DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, accessor.InsSize());
}
} else {
DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
@@ -1372,7 +1367,7 @@ static inline bool DoCallCommon(ArtMethod* called_method,
DCHECK_GT(num_regs, 0u); // As the method is an instance method, there should be at least 1.
// The new StringFactory call is static and has one fewer argument.
- if (code_item == nullptr) {
+ if (!accessor.HasCodeItem()) {
DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
num_regs--;
} // else ... don't need to change num_regs since it comes up from the string_init's code item
@@ -1504,7 +1499,7 @@ static inline bool DoCallCommon(ArtMethod* called_method,
}
PerformCall(self,
- code_item,
+ accessor,
shadow_frame.GetMethod(),
first_dest_reg,
new_shadow_frame,
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index f097bc71b9..8180222e22 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -26,18 +26,19 @@
#include <iostream>
#include <sstream>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/enums.h"
-#include "base/logging.h"
#include "base/macros.h"
+#include "base/mutex.h"
#include "class_linker-inl.h"
#include "common_dex_operations.h"
#include "common_throws.h"
-#include "dex_file-inl.h"
-#include "dex_instruction-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_instruction-inl.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "handle_scope-inl.h"
#include "jit/jit.h"
@@ -206,17 +207,17 @@ static inline bool DoInvoke(Thread* self,
}
}
-static inline mirror::MethodHandle* ResolveMethodHandle(Thread* self,
- uint32_t method_handle_index,
- ArtMethod* referrer)
+static inline ObjPtr<mirror::MethodHandle> ResolveMethodHandle(Thread* self,
+ uint32_t method_handle_index,
+ ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
return class_linker->ResolveMethodHandle(self, method_handle_index, referrer);
}
-static inline mirror::MethodType* ResolveMethodType(Thread* self,
- uint32_t method_type_index,
- ArtMethod* referrer)
+static inline ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self,
+ uint32_t method_type_index,
+ ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
return class_linker->ResolveMethodType(self, method_type_index, referrer);
@@ -348,9 +349,7 @@ static inline ObjPtr<mirror::String> ResolveString(Thread* self,
if (UNLIKELY(string_ptr == nullptr)) {
StackHandleScope<1> hs(self);
Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
- string_ptr = Runtime::Current()->GetClassLinker()->ResolveString(*dex_cache->GetDexFile(),
- string_idx,
- dex_cache);
+ string_ptr = Runtime::Current()->GetClassLinker()->ResolveString(string_idx, dex_cache);
}
return string_ptr;
}
diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc
index 37593bc728..99a4f763c9 100644
--- a/runtime/interpreter/interpreter_intrinsics.cc
+++ b/runtime/interpreter/interpreter_intrinsics.cc
@@ -16,7 +16,7 @@
#include "interpreter/interpreter_intrinsics.h"
-#include "dex_instruction.h"
+#include "dex/dex_instruction.h"
#include "intrinsics_enum.h"
#include "interpreter/interpreter_common.h"
diff --git a/runtime/interpreter/interpreter_mterp_impl.h b/runtime/interpreter/interpreter_mterp_impl.h
index 7aa5a34bd4..d8a764f855 100644
--- a/runtime/interpreter/interpreter_mterp_impl.h
+++ b/runtime/interpreter/interpreter_mterp_impl.h
@@ -19,7 +19,7 @@
#include "base/macros.h"
#include "base/mutex.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "jvalue.h"
#include "obj_ptr.h"
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 094f08664e..6f9cad848d 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -17,7 +17,7 @@
#include "interpreter_switch_impl.h"
#include "base/enums.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "experimental_flags.h"
#include "interpreter_common.h"
#include "jit/jit.h"
@@ -67,7 +67,7 @@ namespace interpreter {
{ \
if (UNLIKELY(instrumentation->HasDexPcListeners()) && \
UNLIKELY(!DoDexPcMoveEvent(self, \
- code_item, \
+ accessor, \
shadow_frame, \
dex_pc, \
instrumentation, \
@@ -125,7 +125,7 @@ namespace interpreter {
// jvmti-agents while handling breakpoint or single step events. We had to move this into its own
// function because it was making ExecuteSwitchImpl have too large a stack.
NO_INLINE static bool DoDexPcMoveEvent(Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
const ShadowFrame& shadow_frame,
uint32_t dex_pc,
const instrumentation::Instrumentation* instrumentation,
@@ -139,7 +139,7 @@ NO_INLINE static bool DoDexPcMoveEvent(Thread* self,
hs.NewHandleWrapper(LIKELY(save_ref == nullptr) ? &null_obj : save_ref->GetGCRoot()));
self->ClearException();
instrumentation->DexPcMovedEvent(self,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
dex_pc);
if (UNLIKELY(self->IsExceptionPending())) {
@@ -188,7 +188,7 @@ NO_INLINE static bool SendMethodExitEvents(Thread* self,
}
template<bool do_access_check, bool transaction_active>
-JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction) {
constexpr bool do_assignability_check = do_access_check;
@@ -200,10 +200,10 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
uint32_t dex_pc = shadow_frame.GetDexPC();
const auto* const instrumentation = Runtime::Current()->GetInstrumentation();
- const uint16_t* const insns = code_item->insns_;
+ ArtMethod* method = shadow_frame.GetMethod();
+ const uint16_t* const insns = accessor.Insns();
const Instruction* inst = Instruction::At(insns + dex_pc);
uint16_t inst_data;
- ArtMethod* method = shadow_frame.GetMethod();
jit::Jit* jit = Runtime::Current()->GetJit();
do {
@@ -303,7 +303,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
!SendMethodExitEvents(self,
instrumentation,
shadow_frame,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
inst->GetDexPc(insns),
result))) {
@@ -325,7 +325,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
!SendMethodExitEvents(self,
instrumentation,
shadow_frame,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
inst->GetDexPc(insns),
result))) {
@@ -348,7 +348,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
!SendMethodExitEvents(self,
instrumentation,
shadow_frame,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
inst->GetDexPc(insns),
result))) {
@@ -370,7 +370,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
!SendMethodExitEvents(self,
instrumentation,
shadow_frame,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
inst->GetDexPc(insns),
result))) {
@@ -412,7 +412,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
!SendMethodExitEvents(self,
instrumentation,
shadow_frame,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
inst->GetDexPc(insns),
result))) {
@@ -2484,19 +2484,19 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
// Explicit definitions of ExecuteSwitchImpl.
template HOT_ATTR
-JValue ExecuteSwitchImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<true, false>(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction);
template HOT_ATTR
-JValue ExecuteSwitchImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<false, false>(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction);
template
-JValue ExecuteSwitchImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<true, true>(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction);
template
-JValue ExecuteSwitchImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<false, true>(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction);
diff --git a/runtime/interpreter/interpreter_switch_impl.h b/runtime/interpreter/interpreter_switch_impl.h
index 267df2e219..50db337f03 100644
--- a/runtime/interpreter/interpreter_switch_impl.h
+++ b/runtime/interpreter/interpreter_switch_impl.h
@@ -19,12 +19,13 @@
#include "base/macros.h"
#include "base/mutex.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "jvalue.h"
#include "obj_ptr.h"
namespace art {
+class CodeItemDataAccessor;
class ShadowFrame;
class Thread;
@@ -32,7 +33,7 @@ namespace interpreter {
template<bool do_access_check, bool transaction_active>
JValue ExecuteSwitchImpl(Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame,
JValue result_register,
bool interpret_one_instruction) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/interpreter/mterp/mips/entry.S b/runtime/interpreter/mterp/mips/entry.S
index 3908cb506e..41b5d5650d 100644
--- a/runtime/interpreter/mterp/mips/entry.S
+++ b/runtime/interpreter/mterp/mips/entry.S
@@ -32,6 +32,7 @@
*/
ExecuteMterpImpl:
+ .cfi_startproc
.set noreorder
.cpload t9
.set reorder
diff --git a/runtime/interpreter/mterp/mips/footer.S b/runtime/interpreter/mterp/mips/footer.S
index 6e1ba1c882..1c784ef188 100644
--- a/runtime/interpreter/mterp/mips/footer.S
+++ b/runtime/interpreter/mterp/mips/footer.S
@@ -284,4 +284,5 @@ MterpProfileActive:
STACK_LOAD_FULL()
jalr zero, ra
+ .cfi_endproc
.end ExecuteMterpImpl
diff --git a/runtime/interpreter/mterp/mips/header.S b/runtime/interpreter/mterp/mips/header.S
index 1ccaa6443f..0f7a6f1116 100644
--- a/runtime/interpreter/mterp/mips/header.S
+++ b/runtime/interpreter/mterp/mips/header.S
@@ -32,7 +32,7 @@
*/
#include "asm_support.h"
-#include "interpreter/mterp/cfi_asm_support.S"
+#include "interpreter/mterp/cfi_asm_support.h"
#if (__mips==32) && (__mips_isa_rev>=2)
#define MIPS32REVGE2 /* mips32r2 and greater */
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 92dd19ed2f..9c7645af9e 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -151,8 +151,14 @@ extern "C" size_t MterpShouldSwitchInterpreters()
Dbg::IsDebuggerActive() ||
// An async exception has been thrown. We need to go to the switch interpreter. MTerp doesn't
// know how to deal with these so we could end up never dealing with it if we are in an
- // infinite loop.
- UNLIKELY(Thread::Current()->IsAsyncExceptionPending());
+ // infinite loop. Since this can be called in a tight loop and getting the current thread
+ // requires a TLS read we instead first check a short-circuit runtime flag that will only be
+ // set if something tries to set an async exception. This will make this function faster in
+ // the common case where no async exception has ever been sent. We don't need to worry about
+ // synchronization on the runtime flag since it is only set in a checkpoint which will either
+ // take place on the current thread or act as a synchronization point.
+ (UNLIKELY(runtime->AreAsyncExceptionsThrown()) &&
+ Thread::Current()->IsAsyncExceptionPending());
}
@@ -370,15 +376,15 @@ extern "C" size_t MterpConstClass(uint32_t index,
ShadowFrame* shadow_frame,
Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(index),
- shadow_frame->GetMethod(),
- self,
- false,
- false);
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(index),
+ shadow_frame->GetMethod(),
+ self,
+ /* can_run_clinit */ false,
+ /* verify_access */ false);
if (UNLIKELY(c == nullptr)) {
return true;
}
- shadow_frame->SetVRegReference(tgt_vreg, c);
+ shadow_frame->SetVRegReference(tgt_vreg, c.Ptr());
return false;
}
@@ -457,17 +463,17 @@ extern "C" size_t MterpNewInstance(ShadowFrame* shadow_frame, Thread* self, uint
REQUIRES_SHARED(Locks::mutator_lock_) {
const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
mirror::Object* obj = nullptr;
- mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
- shadow_frame->GetMethod(),
- self,
- false,
- false);
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
+ shadow_frame->GetMethod(),
+ self,
+ /* can_run_clinit */ false,
+ /* verify_access */ false);
if (LIKELY(c != nullptr)) {
if (UNLIKELY(c->IsStringClass())) {
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
} else {
- obj = AllocObjectFromCode<true>(c,
+ obj = AllocObjectFromCode<true>(c.Ptr(),
self,
Runtime::Current()->GetHeap()->GetCurrentAllocator());
}
diff --git a/runtime/interpreter/mterp/out/mterp_mips.S b/runtime/interpreter/mterp/out/mterp_mips.S
index 9535e254e7..1687afa58a 100644
--- a/runtime/interpreter/mterp/out/mterp_mips.S
+++ b/runtime/interpreter/mterp/out/mterp_mips.S
@@ -39,7 +39,7 @@
*/
#include "asm_support.h"
-#include "interpreter/mterp/cfi_asm_support.S"
+#include "interpreter/mterp/cfi_asm_support.h"
#if (__mips==32) && (__mips_isa_rev>=2)
#define MIPS32REVGE2 /* mips32r2 and greater */
@@ -766,6 +766,7 @@
*/
ExecuteMterpImpl:
+ .cfi_startproc
.set noreorder
.cpload t9
.set reorder
@@ -12844,5 +12845,6 @@ MterpProfileActive:
STACK_LOAD_FULL()
jalr zero, ra
+ .cfi_endproc
.end ExecuteMterpImpl
diff --git a/runtime/interpreter/shadow_frame.cc b/runtime/interpreter/shadow_frame.cc
index ab154cf767..fe7e3e0a9b 100644
--- a/runtime/interpreter/shadow_frame.cc
+++ b/runtime/interpreter/shadow_frame.cc
@@ -27,9 +27,9 @@ mirror::Object* ShadowFrame::GetThisObject() const {
} else if (m->IsNative()) {
return GetVRegReference(0);
} else {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- CHECK(code_item != nullptr) << ArtMethod::PrettyMethod(m);
- uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
+ CHECK(m->GetCodeItem() != nullptr) << ArtMethod::PrettyMethod(m);
+ CodeItemDataAccessor accessor(m);
+ uint16_t reg = accessor.RegistersSize() - accessor.InsSize();
return GetVRegReference(reg);
}
}
diff --git a/runtime/interpreter/shadow_frame.h b/runtime/interpreter/shadow_frame.h
index be2c943427..d5451ffded 100644
--- a/runtime/interpreter/shadow_frame.h
+++ b/runtime/interpreter/shadow_frame.h
@@ -23,7 +23,7 @@
#include "base/macros.h"
#include "base/mutex.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "lock_count_data.h"
#include "read_barrier.h"
#include "stack_reference.h"
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 31e7986770..d1436fa9cf 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -26,12 +26,12 @@
#include <locale>
#include <unordered_map>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "art_method-inl.h"
#include "base/casts.h"
#include "base/enums.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "class_linker.h"
#include "common_throws.h"
@@ -1910,7 +1910,7 @@ void UnstartedRuntime::Initialize() {
tables_initialized_ = true;
}
-void UnstartedRuntime::Invoke(Thread* self, const DexFile::CodeItem* code_item,
+void UnstartedRuntime::Invoke(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
// In a runtime that's not started we intercept certain methods to avoid complicated dependency
// problems in core libraries.
@@ -1930,7 +1930,7 @@ void UnstartedRuntime::Invoke(Thread* self, const DexFile::CodeItem* code_item,
self->PopShadowFrame();
} else {
// Not special, continue with regular interpreter execution.
- ArtInterpreterToInterpreterBridge(self, code_item, shadow_frame, result);
+ ArtInterpreterToInterpreterBridge(self, accessor, shadow_frame, result);
}
}
diff --git a/runtime/interpreter/unstarted_runtime.h b/runtime/interpreter/unstarted_runtime.h
index bc9ead8360..b38c685d9b 100644
--- a/runtime/interpreter/unstarted_runtime.h
+++ b/runtime/interpreter/unstarted_runtime.h
@@ -19,12 +19,13 @@
#include "interpreter.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "jvalue.h"
namespace art {
class ArtMethod;
+class CodeItemDataAccessor;
class Thread;
class ShadowFrame;
@@ -48,7 +49,7 @@ class UnstartedRuntime {
static void Initialize();
static void Invoke(Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
ShadowFrame* shadow_frame,
JValue* result,
size_t arg_offset)
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 9db5f88dab..0986005e4b 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -24,7 +24,7 @@
#include "base/memory_tool.h"
#include "class_linker.h"
#include "common_runtime_test.h"
-#include "dex_instruction.h"
+#include "dex/dex_instruction.h"
#include "handle.h"
#include "handle_scope-inl.h"
#include "interpreter/interpreter_common.h"
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index f8b82ed313..da4c4b2fa4 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -26,7 +26,7 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "check_jni.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "fault_handler.h"
#include "gc/allocation_record.h"
#include "gc/heap.h"
@@ -48,6 +48,7 @@
#include "thread-inl.h"
#include "thread_list.h"
#include "ti/agent.h"
+#include "well_known_classes.h"
namespace art {
@@ -337,7 +338,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(self->GetJniEnv()->vm, nullptr);
+ jni_on_unload(self->GetJniEnv()->GetVm(), nullptr);
}
delete library;
}
@@ -853,7 +854,6 @@ void JavaVMExt::UnloadNativeLibraries() {
bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
const std::string& path,
jobject class_loader,
- jstring library_path,
std::string* error_msg) {
error_msg->clear();
@@ -950,6 +950,9 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
// class unloading. Libraries will only be unloaded when the reference count (incremented by
// dlopen) becomes zero from dlclose.
+ // Retrieve the library path from the classloader, if necessary.
+ ScopedLocalRef<jstring> library_path(env, GetLibrarySearchPath(env, class_loader));
+
Locks::mutator_lock_->AssertNotHeld(self);
const char* path_str = path.empty() ? nullptr : path.c_str();
bool needs_native_bridge = false;
@@ -957,7 +960,7 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
runtime_->GetTargetSdkVersion(),
path_str,
class_loader,
- library_path,
+ library_path.get(),
&needs_native_bridge,
error_msg);
@@ -1052,17 +1055,17 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
static void* FindCodeForNativeMethodInAgents(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) {
std::string jni_short_name(m->JniShortName());
std::string jni_long_name(m->JniLongName());
- for (const ti::Agent& agent : Runtime::Current()->GetAgents()) {
- void* fn = agent.FindSymbol(jni_short_name);
+ for (const std::unique_ptr<ti::Agent>& agent : Runtime::Current()->GetAgents()) {
+ void* fn = agent->FindSymbol(jni_short_name);
if (fn != nullptr) {
VLOG(jni) << "Found implementation for " << m->PrettyMethod()
- << " (symbol: " << jni_short_name << ") in " << agent;
+ << " (symbol: " << jni_short_name << ") in " << *agent;
return fn;
}
- fn = agent.FindSymbol(jni_long_name);
+ fn = agent->FindSymbol(jni_long_name);
if (fn != nullptr) {
VLOG(jni) << "Found implementation for " << m->PrettyMethod()
- << " (symbol: " << jni_long_name << ") in " << agent;
+ << " (symbol: " << jni_long_name << ") in " << *agent;
return fn;
}
}
@@ -1119,6 +1122,18 @@ void JavaVMExt::VisitRoots(RootVisitor* visitor) {
// The weak_globals table is visited by the GC itself (because it mutates the table).
}
+jstring JavaVMExt::GetLibrarySearchPath(JNIEnv* env, jobject class_loader) {
+ if (class_loader == nullptr) {
+ return nullptr;
+ }
+ if (!env->IsInstanceOf(class_loader, WellKnownClasses::dalvik_system_BaseDexClassLoader)) {
+ return nullptr;
+ }
+ return reinterpret_cast<jstring>(env->CallObjectMethod(
+ class_loader,
+ WellKnownClasses::dalvik_system_BaseDexClassLoader_getLdLibraryPath));
+}
+
// JNI Invocation interface.
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index 7c2755fc58..8c81c2565d 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -101,7 +101,6 @@ class JavaVMExt : public JavaVM {
bool LoadNativeLibrary(JNIEnv* env,
const std::string& path,
jobject class_loader,
- jstring library_path,
std::string* error_msg);
// Unload native libraries with cleared class loaders.
@@ -200,6 +199,11 @@ class JavaVMExt : public JavaVM {
static bool IsBadJniVersion(int version);
+ // Return the library search path for the given classloader, if the classloader is of a
+ // well-known type. The jobject will be a local reference and is expected to be managed by the
+ // caller.
+ static jstring GetLibrarySearchPath(JNIEnv* env, jobject class_loader);
+
private:
// The constructor should not be called directly. It may leave the object in
// an erroneous state, and the result needs to be checked.
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index aeeda1e791..b491c3ee5c 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_JDWP_JDWP_H_
#include "atomic.h"
+#include "base/logging.h" // For VLOG.
#include "base/mutex.h"
#include "jdwp/jdwp_bits.h"
#include "jdwp/jdwp_constants.h"
@@ -97,14 +98,15 @@ bool operator!=(const JdwpLocation& lhs, const JdwpLocation& rhs);
* How we talk to the debugger.
*/
enum JdwpTransportType {
- kJdwpTransportUnknown = 0,
+ kJdwpTransportNone = 0,
+ kJdwpTransportUnknown, // Unknown tranpsort
kJdwpTransportSocket, // transport=dt_socket
kJdwpTransportAndroidAdb, // transport=dt_android_adb
};
std::ostream& operator<<(std::ostream& os, const JdwpTransportType& rhs);
struct JdwpOptions {
- JdwpTransportType transport = kJdwpTransportUnknown;
+ JdwpTransportType transport = kJdwpTransportNone;
bool server = false;
bool suspend = false;
std::string host = "";
@@ -113,6 +115,8 @@ struct JdwpOptions {
bool operator==(const JdwpOptions& lhs, const JdwpOptions& rhs);
+bool ParseJdwpOptions(const std::string& options, JdwpOptions* jdwp_options);
+
struct JdwpEvent;
class JdwpNetStateBase;
struct ModBasket;
diff --git a/runtime/jdwp/jdwp_adb.cc b/runtime/jdwp/jdwp_adb.cc
index ede4f9edb7..d68430f3ac 100644
--- a/runtime/jdwp/jdwp_adb.cc
+++ b/runtime/jdwp/jdwp_adb.cc
@@ -22,7 +22,7 @@
#include "android-base/stringprintf.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "jdwp/jdwp_priv.h"
#include "thread-current-inl.h"
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index 41cb64276c..9409b7661f 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -25,7 +25,7 @@
#include "art_field-inl.h"
#include "art_method-inl.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "debugger.h"
#include "jdwp/jdwp_constants.h"
#include "jdwp/jdwp_expand_buf.h"
diff --git a/runtime/jdwp/jdwp_expand_buf.cc b/runtime/jdwp/jdwp_expand_buf.cc
index f0b8c918dc..4b4ca0e4a3 100644
--- a/runtime/jdwp/jdwp_expand_buf.cc
+++ b/runtime/jdwp/jdwp_expand_buf.cc
@@ -23,7 +23,8 @@
#include <stdlib.h>
#include <string.h>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "jdwp/jdwp.h"
#include "jdwp/jdwp_bits.h"
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index 618332b7ef..89eef88b88 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -24,7 +24,7 @@
#include "atomic.h"
#include "base/hex_dump.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "debugger.h"
#include "jdwp/jdwp_constants.h"
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index e6c60685cc..63f5dc8b69 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -23,7 +23,7 @@
#include "android-base/stringprintf.h"
#include "atomic.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/time_utils.h"
#include "debugger.h"
#include "jdwp/jdwp_priv.h"
@@ -37,6 +37,119 @@ using android::base::StringPrintf;
static void* StartJdwpThread(void* arg);
+
+static bool ParseJdwpOption(const std::string& name,
+ const std::string& value,
+ JdwpOptions* jdwp_options) {
+ if (name == "transport") {
+ if (value == "dt_socket") {
+ jdwp_options->transport = JDWP::kJdwpTransportSocket;
+ } else if (value == "dt_android_adb") {
+ jdwp_options->transport = JDWP::kJdwpTransportAndroidAdb;
+ } else {
+ jdwp_options->transport = JDWP::kJdwpTransportUnknown;
+ LOG(ERROR) << "JDWP transport not supported: " << value;
+ return false;
+ }
+ } else if (name == "server") {
+ if (value == "n") {
+ jdwp_options->server = false;
+ } else if (value == "y") {
+ jdwp_options->server = true;
+ } else {
+ LOG(ERROR) << "JDWP option 'server' must be 'y' or 'n'";
+ return false;
+ }
+ } else if (name == "suspend") {
+ if (value == "n") {
+ jdwp_options->suspend = false;
+ } else if (value == "y") {
+ jdwp_options->suspend = true;
+ } else {
+ LOG(ERROR) << "JDWP option 'suspend' must be 'y' or 'n'";
+ return false;
+ }
+ } else if (name == "address") {
+ /* this is either <port> or <host>:<port> */
+ std::string port_string;
+ jdwp_options->host.clear();
+ std::string::size_type colon = value.find(':');
+ if (colon != std::string::npos) {
+ jdwp_options->host = value.substr(0, colon);
+ port_string = value.substr(colon + 1);
+ } else {
+ port_string = value;
+ }
+ if (port_string.empty()) {
+ LOG(ERROR) << "JDWP address missing port: " << value;
+ return false;
+ }
+ char* end;
+ uint64_t port = strtoul(port_string.c_str(), &end, 10);
+ if (*end != '\0' || port > 0xffff) {
+ LOG(ERROR) << "JDWP address has junk in port field: " << value;
+ return false;
+ }
+ jdwp_options->port = port;
+ } else if (name == "launch" || name == "onthrow" || name == "oncaught" || name == "timeout") {
+ /* valid but unsupported */
+ LOG(INFO) << "Ignoring JDWP option '" << name << "'='" << value << "'";
+ } else {
+ LOG(INFO) << "Ignoring unrecognized JDWP option '" << name << "'='" << value << "'";
+ }
+
+ return true;
+}
+
+bool ParseJdwpOptions(const std::string& options, JdwpOptions* jdwp_options) {
+ VLOG(jdwp) << "ParseJdwpOptions: " << options;
+
+ if (options == "help") {
+ LOG(ERROR) << "Example: -XjdwpOptions:transport=dt_socket,address=8000,server=y\n"
+ << "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n"
+ << "Example: -Xrunjdwp:transport=dt_socket,address=localhost:6500,server=n\n";
+ return false;
+ }
+
+ const std::string s;
+
+ std::vector<std::string> pairs;
+ Split(options, ',', &pairs);
+
+ for (const std::string& jdwp_option : pairs) {
+ std::string::size_type equals_pos = jdwp_option.find('=');
+ if (equals_pos == std::string::npos) {
+ LOG(ERROR) << s << "Can't parse JDWP option '" << jdwp_option << "' in '" << options << "'";
+ return false;
+ }
+
+ bool parse_attempt = ParseJdwpOption(jdwp_option.substr(0, equals_pos),
+ jdwp_option.substr(equals_pos + 1),
+ jdwp_options);
+ if (!parse_attempt) {
+ // We fail to parse this JDWP option.
+ return parse_attempt;
+ }
+ }
+
+ if (jdwp_options->transport == JDWP::kJdwpTransportUnknown) {
+ LOG(ERROR) << s << "Must specify JDWP transport: " << options;
+ return false;
+ }
+#if ART_TARGET_ANDROID
+ if (jdwp_options->transport == JDWP::kJdwpTransportNone) {
+ jdwp_options->transport = JDWP::kJdwpTransportAndroidAdb;
+ LOG(WARNING) << "no JDWP transport specified. Defaulting to dt_android_adb";
+ }
+#endif
+ if (!jdwp_options->server && (jdwp_options->host.empty() || jdwp_options->port == 0)) {
+ LOG(ERROR) << s << "Must specify JDWP host and port when server=n: " << options;
+ return false;
+ }
+
+ return true;
+}
+
/*
* JdwpNetStateBase class implementation
*/
diff --git a/runtime/jdwp/jdwp_options_test.cc b/runtime/jdwp/jdwp_options_test.cc
new file mode 100644
index 0000000000..10c52e8cf8
--- /dev/null
+++ b/runtime/jdwp/jdwp_options_test.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jdwp.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+namespace JDWP {
+
+TEST(JdwpOptionsTest, Options) {
+ {
+ /*
+ * "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n"
+ */
+ JDWP::JdwpOptions opt = JDWP::JdwpOptions();
+ const char *opt_args = "transport=dt_socket,address=8000,server=y";
+
+ EXPECT_TRUE(ParseJdwpOptions(opt_args, &opt));
+ EXPECT_EQ(opt.transport, JdwpTransportType::kJdwpTransportSocket);
+ EXPECT_EQ(opt.port, 8000u);
+ EXPECT_EQ(opt.server, true);
+ EXPECT_EQ(opt.suspend, false);
+ }
+
+ {
+ /*
+ * Example: transport=dt_socket,address=localhost:6500,server=n
+ */
+ JDWP::JdwpOptions opt = JDWP::JdwpOptions();
+ const char *opt_args = "transport=dt_socket,address=localhost:6500,server=y";
+
+ EXPECT_TRUE(ParseJdwpOptions(opt_args, &opt));
+ EXPECT_EQ(opt.transport, JdwpTransportType::kJdwpTransportSocket);
+ EXPECT_EQ(opt.port, 6500u);
+ EXPECT_EQ(opt.host, "localhost");
+ EXPECT_EQ(opt.server, true);
+ EXPECT_EQ(opt.suspend, false);
+ }
+
+ {
+ /*
+ * Example: transport=dt_android_adb,server=n,suspend=y;
+ */
+ JDWP::JdwpOptions opt = JDWP::JdwpOptions();
+ const char *opt_args = "transport=dt_android_adb,server=y";
+
+ EXPECT_TRUE(ParseJdwpOptions(opt_args, &opt));
+ EXPECT_EQ(opt.transport, JdwpTransportType::kJdwpTransportAndroidAdb);
+ EXPECT_EQ(opt.port, 0xFFFF);
+ EXPECT_EQ(opt.host, "");
+ EXPECT_EQ(opt.server, true);
+ EXPECT_EQ(opt.suspend, false);
+ }
+
+ /*
+ * Test failures
+ */
+ JDWP::JdwpOptions opt = JDWP::JdwpOptions();
+ EXPECT_FALSE(ParseJdwpOptions("help", &opt));
+ EXPECT_FALSE(ParseJdwpOptions("blabla", &opt));
+ EXPECT_FALSE(ParseJdwpOptions("transport=dt_android_adb,server=n", &opt));
+}
+
+} // namespace JDWP
+} // namespace art
diff --git a/runtime/jdwp/jdwp_socket.cc b/runtime/jdwp/jdwp_socket.cc
index 97662f0727..673a942517 100644
--- a/runtime/jdwp/jdwp_socket.cc
+++ b/runtime/jdwp/jdwp_socket.cc
@@ -28,7 +28,7 @@
#include "android-base/stringprintf.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "jdwp/jdwp_priv.h"
namespace art {
diff --git a/runtime/base/type_static_if.h b/runtime/jdwp_provider.h
index a74d79a665..b62e10b4f8 100644
--- a/runtime/base/type_static_if.h
+++ b/runtime/jdwp_provider.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 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.
@@ -14,19 +14,23 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_BASE_TYPE_STATIC_IF_H_
-#define ART_RUNTIME_BASE_TYPE_STATIC_IF_H_
+#ifndef ART_RUNTIME_JDWP_PROVIDER_H_
+#define ART_RUNTIME_JDWP_PROVIDER_H_
-// A static if which determines whether to return type A or B based on the condition boolean.
-template <bool condition, typename A, typename B>
-struct TypeStaticIf {
- typedef A type;
-};
+#include <ios>
+
+#include "base/macros.h"
+#include "base/logging.h"
-// Specialization to handle the false case.
-template <typename A, typename B>
-struct TypeStaticIf<false, A, B> {
- typedef B type;
+namespace art {
+
+enum class JdwpProvider {
+ kNone,
+ kInternal,
+ kAdbConnection,
};
-#endif // ART_RUNTIME_BASE_TYPE_STATIC_IF_H_
+std::ostream& operator<<(std::ostream& os, const JdwpProvider& rhs);
+
+} // namespace art
+#endif // ART_RUNTIME_JDWP_PROVIDER_H_
diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc
index 135d9b1f51..4d1c85a1c2 100644
--- a/runtime/jit/debugger_interface.cc
+++ b/runtime/jit/debugger_interface.cc
@@ -16,7 +16,8 @@
#include "debugger_interface.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/mutex.h"
#include "thread-current-inl.h"
#include "thread.h"
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 0d95bc6e64..12bf79d7ca 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -20,8 +20,9 @@
#include "art_method-inl.h"
#include "base/enums.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/memory_tool.h"
+#include "base/runtime_debug.h"
#include "debugger.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "interpreter/interpreter.h"
@@ -466,7 +467,8 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread,
// Fetch some data before looking up for an OSR method. We don't want thread
// suspension once we hold an OSR method, as the JIT code cache could delete the OSR
// method while we are being suspended.
- const size_t number_of_vregs = method->GetCodeItem()->registers_size_;
+ CodeItemDataAccessor accessor(method);
+ const size_t number_of_vregs = accessor.RegistersSize();
const char* shorty = method->GetShorty();
std::string method_name(VLOG_IS_ON(jit) ? method->PrettyMethod() : "");
void** memory = nullptr;
@@ -647,6 +649,10 @@ void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count, bool with_
// We do not want to compile such methods.
return;
}
+ if (hot_method_threshold_ == 0) {
+ // Tests might request JIT on first use (compiled synchronously in the interpreter).
+ return;
+ }
DCHECK(thread_pool_ != nullptr);
DCHECK_GT(warm_method_threshold_, 0);
DCHECK_GT(hot_method_threshold_, warm_method_threshold_);
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index a5c167eee8..659c55a289 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -21,12 +21,13 @@
#include "arch/context.h"
#include "art_method-inl.h"
#include "base/enums.h"
+#include "base/logging.h" // For VLOG.
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
#include "cha.h"
#include "debugger_interface.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file_loader.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/bitmap-inl.h"
#include "gc/scoped_gc_critical_section.h"
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index bb8e5e5c15..74bf237c31 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -35,13 +35,14 @@
#include "base/arena_allocator.h"
#include "base/dumpable.h"
#include "base/file_utils.h"
+#include "base/logging.h" // For VLOG.
#include "base/mutex.h"
#include "base/scoped_flock.h"
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
#include "base/unix_file/fd_file.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file_loader.h"
#include "jit/profiling_info.h"
#include "os.h"
#include "safe_map.h"
@@ -1582,7 +1583,11 @@ std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>*
for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
MethodHotness hotness_info(dex_data->GetHotnessInfo(method_idx));
if (startup ? hotness_info.IsStartup() : hotness_info.IsPostStartup()) {
- os << method_idx << ", ";
+ if (dex_file != nullptr) {
+ os << "\n\t\t" << dex_file->PrettyMethod(method_idx, true);
+ } else {
+ os << method_idx << ", ";
+ }
}
}
if (startup == false) {
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
index 8dbb43fb53..7c30dee0c0 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -25,8 +25,8 @@
#include "base/arena_object.h"
#include "bit_memory_region.h"
#include "dex_cache_resolved_classes.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
#include "method_reference.h"
#include "safe_map.h"
#include "type_reference.h"
diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc
index f155d7e163..08042cc890 100644
--- a/runtime/jit/profile_compilation_info_test.cc
+++ b/runtime/jit/profile_compilation_info_test.cc
@@ -20,7 +20,7 @@
#include "base/unix_file/fd_file.h"
#include "class_linker-inl.h"
#include "common_runtime_test.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "handle_scope-inl.h"
#include "jit/profile_compilation_info.h"
#include "linear_alloc.h"
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index acbc6e63a4..8f0ac33594 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -25,13 +25,14 @@
#include "art_method-inl.h"
#include "base/enums.h"
+#include "base/logging.h" // For VLOG.
#include "base/scoped_arena_containers.h"
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
#include "class_table-inl.h"
#include "compiler_filter.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file_loader.h"
#include "dex_reference_collection.h"
#include "gc/collector_type.h"
#include "gc/gc_cause.h"
diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc
index e54a0179e1..9126bea7d0 100644
--- a/runtime/jit/profiling_info.cc
+++ b/runtime/jit/profiling_info.cc
@@ -17,7 +17,7 @@
#include "profiling_info.h"
#include "art_method-inl.h"
-#include "dex_instruction.h"
+#include "dex/dex_instruction.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
#include "scoped_thread_state_change-inl.h"
@@ -94,8 +94,8 @@ void ProfilingInfo::AddInvokeInfo(uint32_t dex_pc, mirror::Class* cls) {
// *after* this thread hits a suspend point.
GcRoot<mirror::Class> expected_root(existing);
GcRoot<mirror::Class> desired_root(cls);
- if (!reinterpret_cast<Atomic<GcRoot<mirror::Class>>*>(&cache->classes_[i])->
- CompareExchangeStrongSequentiallyConsistent(expected_root, desired_root)) {
+ auto atomic_root = reinterpret_cast<Atomic<GcRoot<mirror::Class>>*>(&cache->classes_[i]);
+ if (!atomic_root->CompareAndSetStrongSequentiallyConsistent(expected_root, desired_root)) {
// Some other thread put a class in the cache, continue iteration starting at this
// entry in case the entry contains `cls`.
--i;
diff --git a/runtime/jni_env_ext-inl.h b/runtime/jni_env_ext-inl.h
index d66df081c6..14f708b18d 100644
--- a/runtime/jni_env_ext-inl.h
+++ b/runtime/jni_env_ext-inl.h
@@ -26,7 +26,7 @@ namespace art {
template<typename T>
inline T JNIEnvExt::AddLocalReference(ObjPtr<mirror::Object> obj) {
std::string error_msg;
- IndirectRef ref = locals.Add(local_ref_cookie, obj, &error_msg);
+ IndirectRef ref = locals_.Add(local_ref_cookie_, obj, &error_msg);
if (UNLIKELY(ref == nullptr)) {
// This is really unexpected if we allow resizing local IRTs...
LOG(FATAL) << error_msg;
@@ -35,10 +35,10 @@ inline T JNIEnvExt::AddLocalReference(ObjPtr<mirror::Object> obj) {
// TODO: fix this to understand PushLocalFrame, so we can turn it on.
if (false) {
- if (check_jni) {
- size_t entry_count = locals.Capacity();
+ if (check_jni_) {
+ size_t entry_count = locals_.Capacity();
if (entry_count > 16) {
- locals.Dump(LOG_STREAM(WARNING) << "Warning: more than 16 JNI local references: "
+ locals_.Dump(LOG_STREAM(WARNING) << "Warning: more than 16 JNI local references: "
<< entry_count << " (most recent was a "
<< mirror::Object::PrettyTypeOf(obj) << ")\n");
// TODO: LOG(FATAL) in a later release?
diff --git a/runtime/jni_env_ext.cc b/runtime/jni_env_ext.cc
index 8352657f28..efe43ee0e9 100644
--- a/runtime/jni_env_ext.cc
+++ b/runtime/jni_env_ext.cc
@@ -21,6 +21,7 @@
#include "android-base/stringprintf.h"
+#include "base/to_str.h"
#include "check_jni.h"
#include "indirect_reference_table.h"
#include "java_vm_ext.h"
@@ -28,6 +29,7 @@
#include "lock_word.h"
#include "mirror/object-inl.h"
#include "nth_caller_visitor.h"
+#include "scoped_thread_state_change.h"
#include "thread-current-inl.h"
#include "thread_list.h"
@@ -40,14 +42,11 @@ static constexpr size_t kMonitorsMax = 4096; // Arbitrary sanity check.
const JNINativeInterface* JNIEnvExt::table_override_ = nullptr;
-// Checking "locals" requires the mutator lock, but at creation time we're really only interested
-// in validity, which isn't changing. To avoid grabbing the mutator lock, factored out and tagged
-// with NO_THREAD_SAFETY_ANALYSIS.
-static bool CheckLocalsValid(JNIEnvExt* in) NO_THREAD_SAFETY_ANALYSIS {
+bool JNIEnvExt::CheckLocalsValid(JNIEnvExt* in) NO_THREAD_SAFETY_ANALYSIS {
if (in == nullptr) {
return false;
}
- return in->locals.IsValid();
+ return in->locals_.IsValid();
}
jint JNIEnvExt::GetEnvHandler(JavaVMExt* vm, /*out*/void** env, jint version) {
@@ -73,23 +72,23 @@ JNIEnvExt* JNIEnvExt::Create(Thread* self_in, JavaVMExt* vm_in, std::string* err
}
JNIEnvExt::JNIEnvExt(Thread* self_in, JavaVMExt* vm_in, std::string* error_msg)
- : self(self_in),
- vm(vm_in),
- local_ref_cookie(kIRTFirstSegment),
- locals(kLocalsInitial, kLocal, IndirectReferenceTable::ResizableCapacity::kYes, error_msg),
- check_jni(false),
- runtime_deleted(false),
- critical(0),
- monitors("monitors", kMonitorsInitial, kMonitorsMax) {
+ : self_(self_in),
+ vm_(vm_in),
+ local_ref_cookie_(kIRTFirstSegment),
+ locals_(kLocalsInitial, kLocal, IndirectReferenceTable::ResizableCapacity::kYes, error_msg),
+ monitors_("monitors", kMonitorsInitial, kMonitorsMax),
+ critical_(0),
+ check_jni_(false),
+ runtime_deleted_(false) {
MutexLock mu(Thread::Current(), *Locks::jni_function_table_lock_);
- check_jni = vm->IsCheckJniEnabled();
- functions = GetFunctionTable(check_jni);
- unchecked_functions = GetJniNativeInterface();
+ check_jni_ = vm_in->IsCheckJniEnabled();
+ functions = GetFunctionTable(check_jni_);
+ unchecked_functions_ = GetJniNativeInterface();
}
void JNIEnvExt::SetFunctionsToRuntimeShutdownFunctions() {
functions = GetRuntimeShutdownNativeInterface();
- runtime_deleted = true;
+ runtime_deleted_ = true;
}
JNIEnvExt::~JNIEnvExt() {
@@ -100,7 +99,7 @@ jobject JNIEnvExt::NewLocalRef(mirror::Object* obj) {
return nullptr;
}
std::string error_msg;
- jobject ref = reinterpret_cast<jobject>(locals.Add(local_ref_cookie, obj, &error_msg));
+ jobject ref = reinterpret_cast<jobject>(locals_.Add(local_ref_cookie_, obj, &error_msg));
if (UNLIKELY(ref == nullptr)) {
// This is really unexpected if we allow resizing local IRTs...
LOG(FATAL) << error_msg;
@@ -111,12 +110,12 @@ jobject JNIEnvExt::NewLocalRef(mirror::Object* obj) {
void JNIEnvExt::DeleteLocalRef(jobject obj) {
if (obj != nullptr) {
- locals.Remove(local_ref_cookie, reinterpret_cast<IndirectRef>(obj));
+ locals_.Remove(local_ref_cookie_, reinterpret_cast<IndirectRef>(obj));
}
}
void JNIEnvExt::SetCheckJniEnabled(bool enabled) {
- check_jni = enabled;
+ check_jni_ = enabled;
MutexLock mu(Thread::Current(), *Locks::jni_function_table_lock_);
functions = GetFunctionTable(enabled);
// Check whether this is a no-op because of override.
@@ -126,20 +125,20 @@ void JNIEnvExt::SetCheckJniEnabled(bool enabled) {
}
void JNIEnvExt::DumpReferenceTables(std::ostream& os) {
- locals.Dump(os);
- monitors.Dump(os);
+ locals_.Dump(os);
+ monitors_.Dump(os);
}
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();
+ DCHECK_GE(locals_.FreeCapacity(), static_cast<size_t>(capacity));
+ stacked_local_ref_cookies_.push_back(local_ref_cookie_);
+ local_ref_cookie_ = locals_.GetSegmentState();
}
void JNIEnvExt::PopFrame() {
- locals.SetSegmentState(local_ref_cookie);
- local_ref_cookie = stacked_local_ref_cookies.back();
- stacked_local_ref_cookies.pop_back();
+ locals_.SetSegmentState(local_ref_cookie_);
+ local_ref_cookie_ = stacked_local_ref_cookies_.back();
+ stacked_local_ref_cookies_.pop_back();
}
// Note: the offset code is brittle, as we can't use OFFSETOF_MEMBER or offsetof easily. Thus, there
@@ -188,7 +187,7 @@ static uintptr_t GetJavaCallFrame(Thread* self) REQUIRES_SHARED(Locks::mutator_l
}
void JNIEnvExt::RecordMonitorEnter(jobject obj) {
- locked_objects_.push_back(std::make_pair(GetJavaCallFrame(self), obj));
+ locked_objects_.push_back(std::make_pair(GetJavaCallFrame(self_), obj));
}
static std::string ComputeMonitorDescription(Thread* self,
@@ -230,7 +229,7 @@ static void RemoveMonitors(Thread* self,
}
void JNIEnvExt::CheckMonitorRelease(jobject obj) {
- uintptr_t current_frame = GetJavaCallFrame(self);
+ uintptr_t current_frame = GetJavaCallFrame(self_);
std::pair<uintptr_t, jobject> exact_pair = std::make_pair(current_frame, obj);
auto it = std::find(locked_objects_.begin(), locked_objects_.end(), exact_pair);
bool will_abort = false;
@@ -238,11 +237,11 @@ void JNIEnvExt::CheckMonitorRelease(jobject obj) {
locked_objects_.erase(it);
} else {
// Check whether this monitor was locked in another JNI "session."
- ObjPtr<mirror::Object> mirror_obj = self->DecodeJObject(obj);
+ ObjPtr<mirror::Object> mirror_obj = self_->DecodeJObject(obj);
for (std::pair<uintptr_t, jobject>& pair : locked_objects_) {
- if (self->DecodeJObject(pair.second) == mirror_obj) {
- std::string monitor_descr = ComputeMonitorDescription(self, pair.second);
- vm->JniAbortF("<JNI MonitorExit>",
+ if (self_->DecodeJObject(pair.second) == mirror_obj) {
+ std::string monitor_descr = ComputeMonitorDescription(self_, pair.second);
+ vm_->JniAbortF("<JNI MonitorExit>",
"Unlocking monitor that wasn't locked here: %s",
monitor_descr.c_str());
will_abort = true;
@@ -255,26 +254,26 @@ void JNIEnvExt::CheckMonitorRelease(jobject obj) {
// the monitors table, otherwise we may visit local objects in GC during abort (which won't be
// valid anymore).
if (will_abort) {
- RemoveMonitors(self, current_frame, &monitors, &locked_objects_);
+ RemoveMonitors(self_, current_frame, &monitors_, &locked_objects_);
}
}
void JNIEnvExt::CheckNoHeldMonitors() {
- uintptr_t current_frame = GetJavaCallFrame(self);
// The locked_objects_ are grouped by their stack frame component, as this enforces structured
// locking, and the groups form a stack. So the current frame entries are at the end. Check
// whether the vector is empty, and when there are elements, whether the last element belongs
// to this call - this signals that there are unlocked monitors.
if (!locked_objects_.empty()) {
+ uintptr_t current_frame = GetJavaCallFrame(self_);
std::pair<uintptr_t, jobject>& pair = locked_objects_[locked_objects_.size() - 1];
if (pair.first == current_frame) {
- std::string monitor_descr = ComputeMonitorDescription(self, pair.second);
- vm->JniAbortF("<JNI End>",
+ std::string monitor_descr = ComputeMonitorDescription(self_, pair.second);
+ vm_->JniAbortF("<JNI End>",
"Still holding a locked object on JNI end: %s",
monitor_descr.c_str());
// When we abort, also make sure that any locks from the current "session" are removed from
// the monitors table, otherwise we may visit local objects in GC during abort.
- RemoveMonitors(self, current_frame, &monitors, &locked_objects_);
+ RemoveMonitors(self_, current_frame, &monitors_, &locked_objects_);
} else if (kIsDebugBuild) {
// Make sure there are really no other entries and our checking worked as expected.
for (std::pair<uintptr_t, jobject>& check_pair : locked_objects_) {
@@ -282,12 +281,18 @@ void JNIEnvExt::CheckNoHeldMonitors() {
}
}
}
+ // Ensure critical locks aren't held when returning to Java.
+ if (critical_ > 0) {
+ vm_->JniAbortF("<JNI End>",
+ "Critical lock held when returning to Java on thread %s",
+ ToStr<Thread>(*self_).c_str());
+ }
}
static void ThreadResetFunctionTable(Thread* thread, void* arg ATTRIBUTE_UNUSED)
REQUIRES(Locks::jni_function_table_lock_) {
JNIEnvExt* env = thread->GetJniEnv();
- bool check_jni = env->check_jni;
+ bool check_jni = env->IsCheckJniEnabled();
env->functions = JNIEnvExt::GetFunctionTable(check_jni);
}
diff --git a/runtime/jni_env_ext.h b/runtime/jni_env_ext.h
index 2f6c5dc92a..0e8fd03057 100644
--- a/runtime/jni_env_ext.h
+++ b/runtime/jni_env_ext.h
@@ -37,10 +37,15 @@ class Object;
// low enough that it forces sanity checks.
static constexpr size_t kLocalsInitial = 512;
-struct JNIEnvExt : public JNIEnv {
+class JNIEnvExt : public JNIEnv {
+ public:
// Creates a new JNIEnvExt. Returns null on error, in which case error_msg
// will contain a description of the error.
static JNIEnvExt* Create(Thread* self, JavaVMExt* vm, std::string* error_msg);
+ static Offset SegmentStateOffset(size_t pointer_size);
+ static Offset LocalRefCookieOffset(size_t pointer_size);
+ static Offset SelfOffset(size_t pointer_size);
+ static jint GetEnvHandler(JavaVMExt* vm, /*out*/void** out, jint version);
~JNIEnvExt();
@@ -58,43 +63,44 @@ struct JNIEnvExt : public JNIEnv {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::alloc_tracker_lock_);
- static Offset SegmentStateOffset(size_t pointer_size);
- static Offset LocalRefCookieOffset(size_t pointer_size);
- static Offset SelfOffset(size_t pointer_size);
-
- static jint GetEnvHandler(JavaVMExt* vm, /*out*/void** out, jint version);
+ void UpdateLocal(IndirectRef iref, ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_) {
+ locals_.Update(iref, obj);
+ }
jobject NewLocalRef(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_);
void DeleteLocalRef(jobject obj) REQUIRES_SHARED(Locks::mutator_lock_);
- Thread* const self;
- JavaVMExt* const vm;
-
- // Cookie used when using the local indirect reference table.
- IRTSegmentState local_ref_cookie;
+ void TrimLocals() REQUIRES_SHARED(Locks::mutator_lock_) {
+ locals_.Trim();
+ }
+ void AssertLocalsEmpty() REQUIRES_SHARED(Locks::mutator_lock_) {
+ locals_.AssertEmpty();
+ }
+ size_t GetLocalsCapacity() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return locals_.Capacity();
+ }
- // JNI local references.
- IndirectReferenceTable locals GUARDED_BY(Locks::mutator_lock_);
+ IRTSegmentState GetLocalRefCookie() const { return local_ref_cookie_; }
+ void SetLocalRefCookie(IRTSegmentState new_cookie) { local_ref_cookie_ = new_cookie; }
- // Stack of cookies corresponding to PushLocalFrame/PopLocalFrame calls.
- // TODO: to avoid leaks (and bugs), we need to clear this vector on entry (or return)
- // to a native method.
- std::vector<IRTSegmentState> stacked_local_ref_cookies;
+ IRTSegmentState GetLocalsSegmentState() const REQUIRES_SHARED(Locks::mutator_lock_) {
+ return locals_.GetSegmentState();
+ }
+ void SetLocalSegmentState(IRTSegmentState new_state) REQUIRES_SHARED(Locks::mutator_lock_) {
+ locals_.SetSegmentState(new_state);
+ }
- // Frequently-accessed fields cached from JavaVM.
- bool check_jni;
+ void VisitJniLocalRoots(RootVisitor* visitor, const RootInfo& root_info)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ locals_.VisitRoots(visitor, root_info);
+ }
- // If we are a JNI env for a daemon thread with a deleted runtime.
- bool runtime_deleted;
+ Thread* GetSelf() const { return self_; }
+ JavaVMExt* GetVm() const { return vm_; }
- // How many nested "critical" JNI calls are we in?
- int critical;
+ bool IsRuntimeDeleted() const { return runtime_deleted_; }
+ bool IsCheckJniEnabled() const { return check_jni_; }
- // Entered JNI monitors, for bulk exit on thread detach.
- ReferenceTable monitors;
-
- // Used by -Xcheck:jni.
- const JNINativeInterface* unchecked_functions;
// Functions to keep track of monitor lock and unlock operations. Used to ensure proper locking
// rules in CheckJNI mode.
@@ -108,6 +114,11 @@ struct JNIEnvExt : public JNIEnv {
// Check that no monitors are held that have been acquired in this JNI "segment."
void CheckNoHeldMonitors() REQUIRES_SHARED(Locks::mutator_lock_);
+ void VisitMonitorRoots(RootVisitor* visitor, const RootInfo& root_info)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ monitors_.VisitRoots(visitor, root_info);
+ }
+
// Set the functions to the runtime shutdown functions.
void SetFunctionsToRuntimeShutdownFunctions();
@@ -124,6 +135,11 @@ struct JNIEnvExt : public JNIEnv {
REQUIRES(Locks::jni_function_table_lock_);
private:
+ // Checking "locals" requires the mutator lock, but at creation time we're
+ // really only interested in validity, which isn't changing. To avoid grabbing
+ // the mutator lock, factored out and tagged with NO_THREAD_SAFETY_ANALYSIS.
+ static bool CheckLocalsValid(JNIEnvExt* in) NO_THREAD_SAFETY_ANALYSIS;
+
// Override of function tables. This applies to both default as well as instrumented (CheckJNI)
// function tables.
static const JNINativeInterface* table_override_ GUARDED_BY(Locks::jni_function_table_lock_);
@@ -133,29 +149,73 @@ struct JNIEnvExt : public JNIEnv {
JNIEnvExt(Thread* self, JavaVMExt* vm, std::string* error_msg)
REQUIRES(!Locks::jni_function_table_lock_);
+ // Link to Thread::Current().
+ Thread* const self_;
+
+ // The invocation interface JavaVM.
+ JavaVMExt* const vm_;
+
+ // Cookie used when using the local indirect reference table.
+ IRTSegmentState local_ref_cookie_;
+
+ // JNI local references.
+ IndirectReferenceTable locals_ GUARDED_BY(Locks::mutator_lock_);
+
+ // Stack of cookies corresponding to PushLocalFrame/PopLocalFrame calls.
+ // TODO: to avoid leaks (and bugs), we need to clear this vector on entry (or return)
+ // to a native method.
+ std::vector<IRTSegmentState> stacked_local_ref_cookies_;
+
+ // Entered JNI monitors, for bulk exit on thread detach.
+ ReferenceTable monitors_;
+
+ // Used by -Xcheck:jni.
+ const JNINativeInterface* unchecked_functions_;
+
// All locked objects, with the (Java caller) stack frame that locked them. Used in CheckJNI
// to ensure that only monitors locked in this native frame are being unlocked, and that at
// the end all are unlocked.
std::vector<std::pair<uintptr_t, jobject>> locked_objects_;
+
+ // Start time of "critical" JNI calls to ensure that their use doesn't
+ // excessively block the VM with CheckJNI.
+ uint64_t critical_start_us_;
+
+ // How many nested "critical" JNI calls are we in? Used by CheckJNI to ensure that criticals are
+ uint32_t critical_;
+
+ // Frequently-accessed fields cached from JavaVM.
+ bool check_jni_;
+
+ // If we are a JNI env for a daemon thread with a deleted runtime.
+ bool runtime_deleted_;
+
+ friend class CheckJNI;
+ friend class JNI;
+ friend class ScopedCheck;
+ friend class ScopedJniEnvLocalRefState;
+ friend class Thread;
+ ART_FRIEND_TEST(JniInternalTest, JNIEnvExtOffsets);
};
// Used to save and restore the JNIEnvExt state when not going through code created by the JNI
// compiler.
class ScopedJniEnvLocalRefState {
public:
- explicit ScopedJniEnvLocalRefState(JNIEnvExt* env) : env_(env) {
- saved_local_ref_cookie_ = env->local_ref_cookie;
- env->local_ref_cookie = env->locals.GetSegmentState();
+ explicit ScopedJniEnvLocalRefState(JNIEnvExt* env) :
+ env_(env),
+ saved_local_ref_cookie_(env->local_ref_cookie_) {
+ env->local_ref_cookie_ = env->locals_.GetSegmentState();
}
~ScopedJniEnvLocalRefState() {
- env_->locals.SetSegmentState(env_->local_ref_cookie);
- env_->local_ref_cookie = saved_local_ref_cookie_;
+ env_->locals_.SetSegmentState(env_->local_ref_cookie_);
+ env_->local_ref_cookie_ = saved_local_ref_cookie_;
}
private:
JNIEnvExt* const env_;
- IRTSegmentState saved_local_ref_cookie_;
+ const IRTSegmentState saved_local_ref_cookie_;
DISALLOW_COPY_AND_ASSIGN(ScopedJniEnvLocalRefState);
};
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 1e55158a34..b8e6ebe8d8 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -28,11 +28,11 @@
#include "atomic.h"
#include "base/allocator.h"
#include "base/enums.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/mutex.h"
#include "base/stl_util.h"
#include "class_linker-inl.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "fault_handler.h"
#include "gc/accounting/card_table-inl.h"
#include "gc_root.h"
@@ -383,7 +383,7 @@ int ThrowNewException(JNIEnv* env, jclass exception_class, const char* msg, jobj
}
static JavaVMExt* JavaVmExtFromEnv(JNIEnv* env) {
- return reinterpret_cast<JNIEnvExt*>(env)->vm;
+ return reinterpret_cast<JNIEnvExt*>(env)->GetVm();
}
#define CHECK_NON_NULL_ARGUMENT(value) \
@@ -545,7 +545,7 @@ class JNI {
}
static jboolean ExceptionCheck(JNIEnv* env) {
- return static_cast<JNIEnvExt*>(env)->self->IsExceptionPending() ? JNI_TRUE : JNI_FALSE;
+ return static_cast<JNIEnvExt*>(env)->self_->IsExceptionPending() ? JNI_TRUE : JNI_FALSE;
}
static void ExceptionClear(JNIEnv* env) {
@@ -623,8 +623,8 @@ class JNI {
}
static void DeleteGlobalRef(JNIEnv* env, jobject obj) {
- JavaVMExt* vm = down_cast<JNIEnvExt*>(env)->vm;
- Thread* self = down_cast<JNIEnvExt*>(env)->self;
+ JavaVMExt* vm = down_cast<JNIEnvExt*>(env)->GetVm();
+ Thread* self = down_cast<JNIEnvExt*>(env)->self_;
vm->DeleteGlobalRef(self, obj);
}
@@ -635,8 +635,8 @@ class JNI {
}
static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj) {
- JavaVMExt* vm = down_cast<JNIEnvExt*>(env)->vm;
- Thread* self = down_cast<JNIEnvExt*>(env)->self;
+ JavaVMExt* vm = down_cast<JNIEnvExt*>(env)->GetVm();
+ Thread* self = down_cast<JNIEnvExt*>(env)->self_;
vm->DeleteWeakGlobalRef(self, obj);
}
@@ -659,7 +659,7 @@ class JNI {
// it. b/22119403
ScopedObjectAccess soa(env);
auto* ext_env = down_cast<JNIEnvExt*>(env);
- if (!ext_env->locals.Remove(ext_env->local_ref_cookie, obj)) {
+ if (!ext_env->locals_.Remove(ext_env->local_ref_cookie_, obj)) {
// Attempting to delete a local reference that is not in the
// topmost local reference frame is a no-op. DeleteLocalRef returns
// void and doesn't throw any exceptions, but we should probably
@@ -2310,7 +2310,7 @@ class JNI {
// first, either as a direct or a virtual method. Then move to
// the parent.
ArtMethod* m = nullptr;
- bool warn_on_going_to_parent = down_cast<JNIEnvExt*>(env)->vm->IsCheckJniEnabled();
+ bool warn_on_going_to_parent = down_cast<JNIEnvExt*>(env)->GetVm()->IsCheckJniEnabled();
for (ObjPtr<mirror::Class> current_class = c.Get();
current_class != nullptr;
current_class = current_class->GetSuperClass()) {
@@ -2399,7 +2399,7 @@ class JNI {
ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
o = o->MonitorEnter(soa.Self());
if (soa.Self()->HoldsLock(o)) {
- soa.Env()->monitors.Add(o);
+ soa.Env()->monitors_.Add(o);
}
if (soa.Self()->IsExceptionPending()) {
return JNI_ERR;
@@ -2414,7 +2414,7 @@ class JNI {
bool remove_mon = soa.Self()->HoldsLock(o);
o->MonitorExit(soa.Self());
if (remove_mon) {
- soa.Env()->monitors.Remove(o);
+ soa.Env()->monitors_.Remove(o);
}
if (soa.Self()->IsExceptionPending()) {
return JNI_ERR;
@@ -2458,7 +2458,7 @@ class JNI {
jobject result = env->NewObject(WellKnownClasses::java_nio_DirectByteBuffer,
WellKnownClasses::java_nio_DirectByteBuffer_init,
address_arg, capacity_arg);
- return static_cast<JNIEnvExt*>(env)->self->IsExceptionPending() ? nullptr : result;
+ return static_cast<JNIEnvExt*>(env)->self_->IsExceptionPending() ? nullptr : result;
}
static void* GetDirectBufferAddress(JNIEnv* env, jobject java_buffer) {
@@ -2504,7 +2504,7 @@ class JNI {
}
std::string error_msg;
- if (!soa.Env()->locals.EnsureFreeCapacity(static_cast<size_t>(desired_capacity), &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;
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 1ecfe7cb76..ad24c94ae9 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -867,7 +867,7 @@ TEST_F(JniInternalTest, GetStaticMethodID) {
static size_t GetLocalsCapacity(JNIEnv* env) {
ScopedObjectAccess soa(Thread::Current());
- return reinterpret_cast<JNIEnvExt*>(env)->locals.Capacity();
+ return reinterpret_cast<JNIEnvExt*>(env)->GetLocalsCapacity();
}
TEST_F(JniInternalTest, FromReflectedField_ToReflectedField) {
@@ -1783,66 +1783,115 @@ TEST_F(JniInternalTest, GetObjectArrayElement_SetObjectArrayElement) {
EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni)); \
} while (false)
+#define TEST_PRIMITIVE_FIELD_FOR_CLASS(cname) \
+ do { \
+ Thread::Current()->TransitionFromSuspendedToRunnable(); \
+ LoadDex("AllFields"); \
+ bool started = runtime_->Start(); \
+ ASSERT_TRUE(started); \
+ jclass c = env_->FindClass(cname); \
+ ASSERT_NE(c, nullptr); \
+ jobject o = env_->AllocObject(c); \
+ ASSERT_NE(o, nullptr); \
+ \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Boolean, "sZ", "Z", JNI_TRUE, JNI_FALSE); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Byte, "sB", "B", 1, 2); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Char, "sC", "C", 'a', 'b'); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, Double, "sD", "D", 1.0, 2.0); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, Float, "sF", "F", 1.0, 2.0); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Int, "sI", "I", 1, 2); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Long, "sJ", "J", 1, 2); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Short, "sS", "S", 1, 2); \
+ \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Boolean, "iZ", "Z", JNI_TRUE, JNI_FALSE); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Byte, "iB", "B", 1, 2); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Char, "iC", "C", 'a', 'b'); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, o, Double, "iD", "D", 1.0, 2.0); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, o, Float, "iF", "F", 1.0, 2.0); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Int, "iI", "I", 1, 2); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Long, "iJ", "J", 1, 2); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Short, "iS", "S", 1, 2); \
+ } while (false)
TEST_F(JniInternalTest, GetPrimitiveField_SetPrimitiveField) {
- Thread::Current()->TransitionFromSuspendedToRunnable();
- LoadDex("AllFields");
- bool started = runtime_->Start();
- ASSERT_TRUE(started);
-
- jclass c = env_->FindClass("AllFields");
- ASSERT_NE(c, nullptr);
- jobject o = env_->AllocObject(c);
- ASSERT_NE(o, nullptr);
+ TEST_PRIMITIVE_FIELD_FOR_CLASS("AllFields");
+}
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Boolean, "sZ", "Z", JNI_TRUE, JNI_FALSE);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Byte, "sB", "B", 1, 2);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Char, "sC", "C", 'a', 'b');
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, Double, "sD", "D", 1.0, 2.0);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, Float, "sF", "F", 1.0, 2.0);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Int, "sI", "I", 1, 2);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Long, "sJ", "J", 1, 2);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Short, "sS", "S", 1, 2);
-
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Boolean, "iZ", "Z", JNI_TRUE, JNI_FALSE);
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Byte, "iB", "B", 1, 2);
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Char, "iC", "C", 'a', 'b');
- EXPECT_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, o, Double, "iD", "D", 1.0, 2.0);
- EXPECT_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, o, Float, "iF", "F", 1.0, 2.0);
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Int, "iI", "I", 1, 2);
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Long, "iJ", "J", 1, 2);
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Short, "iS", "S", 1, 2);
+TEST_F(JniInternalTest, GetPrimitiveField_SetPrimitiveField_Subclass) {
+ TEST_PRIMITIVE_FIELD_FOR_CLASS("AllFieldsSub");
}
-TEST_F(JniInternalTest, GetObjectField_SetObjectField) {
+#define EXPECT_UNRELATED_FIELD_FAILURE(type, field_name, sig, value1) \
+ do { \
+ jfieldID fid = env_->GetStaticFieldID(c, field_name, sig); \
+ EXPECT_NE(fid, nullptr); \
+ CheckJniAbortCatcher jni_abort_catcher; \
+ env_->Get ## type ## Field(uc, fid); \
+ jni_abort_catcher.Check("not valid for an object of class"); \
+ env_->Set ## type ## Field(uc, fid, value1); \
+ jni_abort_catcher.Check("not valid for an object of class"); \
+ } while (false)
+
+TEST_F(JniInternalTest, GetField_SetField_unrelated) {
Thread::Current()->TransitionFromSuspendedToRunnable();
LoadDex("AllFields");
- runtime_->Start();
-
+ bool started = runtime_->Start();
+ ASSERT_TRUE(started);
jclass c = env_->FindClass("AllFields");
ASSERT_NE(c, nullptr);
- jobject o = env_->AllocObject(c);
- ASSERT_NE(o, nullptr);
-
- jstring s1 = env_->NewStringUTF("hello");
- ASSERT_NE(s1, nullptr);
- jstring s2 = env_->NewStringUTF("world");
- ASSERT_NE(s2, nullptr);
+ jclass uc = env_->FindClass("AllFieldsUnrelated");
+ ASSERT_NE(uc, nullptr);
+ bool old_check_jni = vm_->SetCheckJniEnabled(true);
+ EXPECT_UNRELATED_FIELD_FAILURE(Boolean, "sZ", "Z", JNI_TRUE);
+ EXPECT_UNRELATED_FIELD_FAILURE(Byte, "sB", "B", 1);
+ EXPECT_UNRELATED_FIELD_FAILURE(Char, "sC", "C", 'a');
+ EXPECT_UNRELATED_FIELD_FAILURE(Double, "sD", "D", 1.0);
+ EXPECT_UNRELATED_FIELD_FAILURE(Float, "sF", "F", 1.0);
+ EXPECT_UNRELATED_FIELD_FAILURE(Int, "sI", "I", 1);
+ EXPECT_UNRELATED_FIELD_FAILURE(Long, "sJ", "J", 1);
+ EXPECT_UNRELATED_FIELD_FAILURE(Short, "sS", "S", 1);
+ EXPECT_UNRELATED_FIELD_FAILURE(Object, "sObject", "Ljava/lang/Object;", c);
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
+}
- jfieldID s_fid = env_->GetStaticFieldID(c, "sObject", "Ljava/lang/Object;");
- ASSERT_NE(s_fid, nullptr);
- jfieldID i_fid = env_->GetFieldID(c, "iObject", "Ljava/lang/Object;");
- ASSERT_NE(i_fid, nullptr);
+#define TEST_OBJECT_FIELD_FOR_CLASS(cname) \
+ do { \
+ Thread::Current()->TransitionFromSuspendedToRunnable(); \
+ LoadDex("AllFields"); \
+ runtime_->Start(); \
+ \
+ jclass c = env_->FindClass(cname); \
+ ASSERT_NE(c, nullptr); \
+ jobject o = env_->AllocObject(c); \
+ ASSERT_NE(o, nullptr); \
+ \
+ jstring s1 = env_->NewStringUTF("hello"); \
+ ASSERT_NE(s1, nullptr); \
+ jstring s2 = env_->NewStringUTF("world"); \
+ ASSERT_NE(s2, nullptr); \
+ \
+ jfieldID s_fid = env_->GetStaticFieldID(c, "sObject", "Ljava/lang/Object;"); \
+ ASSERT_NE(s_fid, nullptr); \
+ jfieldID i_fid = env_->GetFieldID(c, "iObject", "Ljava/lang/Object;"); \
+ ASSERT_NE(i_fid, nullptr); \
+ \
+ env_->SetStaticObjectField(c, s_fid, s1); \
+ ASSERT_TRUE(env_->IsSameObject(s1, env_->GetStaticObjectField(c, s_fid))); \
+ env_->SetStaticObjectField(c, s_fid, s2); \
+ ASSERT_TRUE(env_->IsSameObject(s2, env_->GetStaticObjectField(c, s_fid))); \
+ \
+ env_->SetObjectField(o, i_fid, s1); \
+ ASSERT_TRUE(env_->IsSameObject(s1, env_->GetObjectField(o, i_fid))); \
+ env_->SetObjectField(o, i_fid, s2); \
+ ASSERT_TRUE(env_->IsSameObject(s2, env_->GetObjectField(o, i_fid))); \
+ } while (false)
- env_->SetStaticObjectField(c, s_fid, s1);
- ASSERT_TRUE(env_->IsSameObject(s1, env_->GetStaticObjectField(c, s_fid)));
- env_->SetStaticObjectField(c, s_fid, s2);
- ASSERT_TRUE(env_->IsSameObject(s2, env_->GetStaticObjectField(c, s_fid)));
+TEST_F(JniInternalTest, GetObjectField_SetObjectField) {
+ TEST_OBJECT_FIELD_FOR_CLASS("AllFields");
+}
- env_->SetObjectField(o, i_fid, s1);
- ASSERT_TRUE(env_->IsSameObject(s1, env_->GetObjectField(o, i_fid)));
- env_->SetObjectField(o, i_fid, s2);
- ASSERT_TRUE(env_->IsSameObject(s2, env_->GetObjectField(o, i_fid)));
+TEST_F(JniInternalTest, GetObjectField_SetObjectField_subclass) {
+ TEST_OBJECT_FIELD_FOR_CLASS("AllFieldsSub");
}
TEST_F(JniInternalTest, NewLocalRef_nullptr) {
@@ -2351,15 +2400,15 @@ TEST_F(JniInternalTest, IndirectReferenceTableOffsets) {
// Test the offset computation of JNIEnvExt offsets. b/26071368.
TEST_F(JniInternalTest, JNIEnvExtOffsets) {
- EXPECT_EQ(OFFSETOF_MEMBER(JNIEnvExt, local_ref_cookie),
+ EXPECT_EQ(OFFSETOF_MEMBER(JNIEnvExt, local_ref_cookie_),
JNIEnvExt::LocalRefCookieOffset(sizeof(void*)).Uint32Value());
- EXPECT_EQ(OFFSETOF_MEMBER(JNIEnvExt, self), JNIEnvExt::SelfOffset(sizeof(void*)).Uint32Value());
+ EXPECT_EQ(OFFSETOF_MEMBER(JNIEnvExt, self_), JNIEnvExt::SelfOffset(sizeof(void*)).Uint32Value());
// segment_state_ is private in the IndirectReferenceTable. So this test isn't as good as we'd
// hope it to be.
uint32_t segment_state_now =
- OFFSETOF_MEMBER(JNIEnvExt, locals) +
+ OFFSETOF_MEMBER(JNIEnvExt, locals_) +
IndirectReferenceTable::SegmentStateOffset(sizeof(void*)).Uint32Value();
uint32_t segment_state_computed = JNIEnvExt::SegmentStateOffset(sizeof(void*)).Uint32Value();
EXPECT_EQ(segment_state_now, segment_state_computed);
diff --git a/runtime/leb128.h b/runtime/leb128.h
index 31459af3a0..2bfed7f539 100644
--- a/runtime/leb128.h
+++ b/runtime/leb128.h
@@ -19,8 +19,10 @@
#include <vector>
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
+#include "base/macros.h"
#include "globals.h"
namespace art {
diff --git a/runtime/lock_word.h b/runtime/lock_word.h
index b9aa0b793b..fac1a7597d 100644
--- a/runtime/lock_word.h
+++ b/runtime/lock_word.h
@@ -20,8 +20,9 @@
#include <cstdint>
#include <iosfwd>
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
#include "read_barrier.h"
namespace art {
diff --git a/runtime/managed_stack.h b/runtime/managed_stack.h
index 07078ecb13..d1c230fd8f 100644
--- a/runtime/managed_stack.h
+++ b/runtime/managed_stack.h
@@ -21,7 +21,8 @@
#include <cstring>
#include <string>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/macros.h"
#include "base/mutex.h"
#include "base/bit_utils.h"
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 7f68d2faa0..8abf8a6003 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -35,6 +35,7 @@
#include "base/allocator.h"
#include "base/bit_utils.h"
#include "base/file_utils.h"
+#include "base/logging.h" // For VLOG_IS_ON.
#include "base/memory_tool.h"
#include "globals.h"
#include "utils.h"
@@ -59,14 +60,15 @@ static Maps* gMaps GUARDED_BY(MemMap::GetMemMapsLock()) = nullptr;
static std::ostream& operator<<(
std::ostream& os,
- std::pair<BacktraceMap::const_iterator, BacktraceMap::const_iterator> iters) {
- for (BacktraceMap::const_iterator it = iters.first; it != iters.second; ++it) {
+ std::pair<BacktraceMap::iterator, BacktraceMap::iterator> iters) {
+ for (BacktraceMap::iterator it = iters.first; it != iters.second; ++it) {
+ const backtrace_map_t* entry = *it;
os << StringPrintf("0x%08x-0x%08x %c%c%c %s\n",
- static_cast<uint32_t>(it->start),
- static_cast<uint32_t>(it->end),
- (it->flags & PROT_READ) ? 'r' : '-',
- (it->flags & PROT_WRITE) ? 'w' : '-',
- (it->flags & PROT_EXEC) ? 'x' : '-', it->name.c_str());
+ static_cast<uint32_t>(entry->start),
+ static_cast<uint32_t>(entry->end),
+ (entry->flags & PROT_READ) ? 'r' : '-',
+ (entry->flags & PROT_WRITE) ? 'w' : '-',
+ (entry->flags & PROT_EXEC) ? 'x' : '-', entry->name.c_str());
}
return os;
}
@@ -170,9 +172,10 @@ bool MemMap::ContainedWithinExistingMap(uint8_t* ptr, size_t size, std::string*
}
ScopedBacktraceMapIteratorLock lock(map.get());
- for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
- if ((begin >= it->start && begin < it->end) // start of new within old
- && (end > it->start && end <= it->end)) { // end of new within old
+ for (BacktraceMap::iterator it = map->begin(); it != map->end(); ++it) {
+ const backtrace_map_t* entry = *it;
+ if ((begin >= entry->start && begin < entry->end) // start of new within old
+ && (end > entry->start && end <= entry->end)) { // end of new within old
return true;
}
}
@@ -194,17 +197,18 @@ static bool CheckNonOverlapping(uintptr_t begin,
return false;
}
ScopedBacktraceMapIteratorLock lock(map.get());
- for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
- if ((begin >= it->start && begin < it->end) // start of new within old
- || (end > it->start && end < it->end) // end of new within old
- || (begin <= it->start && end > it->end)) { // start/end of new includes all of old
+ for (BacktraceMap::iterator it = map->begin(); it != map->end(); ++it) {
+ const backtrace_map_t* entry = *it;
+ if ((begin >= entry->start && begin < entry->end) // start of new within old
+ || (end > entry->start && end < entry->end) // end of new within old
+ || (begin <= entry->start && end > entry->end)) { // start/end of new includes all of old
std::ostringstream map_info;
map_info << std::make_pair(it, map->end());
*error_msg = StringPrintf("Requested region 0x%08" PRIxPTR "-0x%08" PRIxPTR " overlaps with "
"existing map 0x%08" PRIxPTR "-0x%08" PRIxPTR " (%s)\n%s",
begin, end,
- static_cast<uintptr_t>(it->start), static_cast<uintptr_t>(it->end),
- it->name.c_str(),
+ static_cast<uintptr_t>(entry->start), static_cast<uintptr_t>(entry->end),
+ entry->name.c_str(),
map_info.str().c_str());
return false;
}
diff --git a/runtime/memory_region.cc b/runtime/memory_region.cc
index 13cc5c99bc..862ff73639 100644
--- a/runtime/memory_region.cc
+++ b/runtime/memory_region.cc
@@ -19,9 +19,6 @@
#include <stdint.h>
#include <string.h>
-#include "base/logging.h"
-#include "globals.h"
-
namespace art {
void MemoryRegion::CopyFrom(size_t offset, const MemoryRegion& from) const {
diff --git a/runtime/memory_region.h b/runtime/memory_region.h
index 7cf5d49d70..23e0aecbda 100644
--- a/runtime/memory_region.h
+++ b/runtime/memory_region.h
@@ -20,10 +20,11 @@
#include <stdint.h>
#include <type_traits>
+#include <android-base/logging.h>
+
#include "arch/instruction_set.h"
#include "base/bit_utils.h"
#include "base/casts.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/value_object.h"
#include "globals.h"
diff --git a/runtime/method_handles-inl.h b/runtime/method_handles-inl.h
index 08b8ad937a..2bc71f4b5e 100644
--- a/runtime/method_handles-inl.h
+++ b/runtime/method_handles-inl.h
@@ -20,7 +20,7 @@
#include "method_handles.h"
#include "common_throws.h"
-#include "dex_instruction.h"
+#include "dex/dex_instruction.h"
#include "interpreter/interpreter_common.h"
#include "jvalue.h"
#include "mirror/class.h"
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 8eb31c1ef8..88f30a8900 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -408,7 +408,7 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
const InstructionOperands* const operands,
JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
// Compute method information.
- const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+ CodeItemDataAccessor accessor(called_method);
// Number of registers for the callee's call frame. Note that for non-exact
// invokes, we always derive this information from the callee method. We
@@ -419,10 +419,10 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
uint16_t num_regs;
size_t num_input_regs;
size_t first_dest_reg;
- if (LIKELY(code_item != nullptr)) {
- num_regs = code_item->registers_size_;
- first_dest_reg = num_regs - code_item->ins_size_;
- num_input_regs = code_item->ins_size_;
+ if (LIKELY(accessor.HasCodeItem())) {
+ num_regs = accessor.RegistersSize();
+ first_dest_reg = num_regs - accessor.InsSize();
+ num_input_regs = accessor.InsSize();
// Parameter registers go at the end of the shadow frame.
DCHECK_NE(first_dest_reg, (size_t)-1);
} else {
@@ -496,7 +496,7 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
called_method, called_method->GetEntryPointFromQuickCompiledCode());
PerformCall(self,
- code_item,
+ accessor,
shadow_frame.GetMethod(),
first_dest_reg,
new_shadow_frame,
@@ -550,10 +550,9 @@ static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
// - One for the only method argument (an EmulatedStackFrame).
static constexpr size_t kNumRegsForTransform = 2;
- const DexFile::CodeItem* code_item = called_method->GetCodeItem();
- DCHECK(code_item != nullptr);
- DCHECK_EQ(kNumRegsForTransform, code_item->registers_size_);
- DCHECK_EQ(kNumRegsForTransform, code_item->ins_size_);
+ CodeItemDataAccessor accessor(called_method);
+ DCHECK_EQ(kNumRegsForTransform, accessor.RegistersSize());
+ DCHECK_EQ(kNumRegsForTransform, accessor.InsSize());
ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
CREATE_SHADOW_FRAME(kNumRegsForTransform, &shadow_frame, called_method, /* dex pc */ 0);
@@ -589,7 +588,7 @@ static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
called_method, called_method->GetEntryPointFromQuickCompiledCode());
PerformCall(self,
- code_item,
+ accessor,
shadow_frame.GetMethod(),
0 /* first destination register */,
new_shadow_frame,
@@ -1035,14 +1034,14 @@ static inline bool MethodHandleInvokeExactInternal(
}
// Compute method information.
- const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+ CodeItemDataAccessor accessor(called_method);
uint16_t num_regs;
size_t num_input_regs;
size_t first_dest_reg;
- if (LIKELY(code_item != nullptr)) {
- num_regs = code_item->registers_size_;
- first_dest_reg = num_regs - code_item->ins_size_;
- num_input_regs = code_item->ins_size_;
+ if (LIKELY(accessor.HasCodeItem())) {
+ num_regs = accessor.RegistersSize();
+ first_dest_reg = num_regs - accessor.InsSize();
+ num_input_regs = accessor.InsSize();
// Parameter registers go at the end of the shadow frame.
DCHECK_NE(first_dest_reg, (size_t)-1);
} else {
@@ -1066,7 +1065,7 @@ static inline bool MethodHandleInvokeExactInternal(
bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
called_method, called_method->GetEntryPointFromQuickCompiledCode());
PerformCall(self,
- code_item,
+ accessor,
shadow_frame.GetMethod(),
first_dest_reg,
new_shadow_frame,
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index bc74bf23d2..6ffd1a81fc 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -19,7 +19,7 @@
#include <ostream>
-#include "dex_instruction.h"
+#include "dex/dex_instruction.h"
#include "handle.h"
#include "interpreter/shadow_frame.h"
#include "jvalue.h"
diff --git a/runtime/method_info.h b/runtime/method_info.h
index 5a72125be4..6485af992d 100644
--- a/runtime/method_info.h
+++ b/runtime/method_info.h
@@ -17,7 +17,9 @@
#ifndef ART_RUNTIME_METHOD_INFO_H_
#define ART_RUNTIME_METHOD_INFO_H_
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/macros.h"
#include "leb128.h"
#include "memory_region.h"
diff --git a/runtime/method_reference.h b/runtime/method_reference.h
index 31f3b8e84e..50b6d6eb68 100644
--- a/runtime/method_reference.h
+++ b/runtime/method_reference.h
@@ -19,8 +19,8 @@
#include <stdint.h>
#include <string>
-#include "dex_file.h"
-#include "dex_file_reference.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_reference.h"
namespace art {
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 22812454d1..636c84c759 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -19,11 +19,11 @@
#include "array.h"
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "base/bit_utils.h"
#include "base/casts.h"
-#include "base/logging.h"
#include "class.h"
#include "gc/heap-inl.h"
#include "obj_ptr-inl.h"
diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc
index 6218dd9c9c..25283bc310 100644
--- a/runtime/mirror/array.cc
+++ b/runtime/mirror/array.cc
@@ -20,7 +20,7 @@
#include "class.h"
#include "class_linker-inl.h"
#include "common_throws.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "handle_scope-inl.h"
#include "object-inl.h"
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index eb54f7fb1f..302a5e622e 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -27,7 +27,7 @@
#include "class_loader.h"
#include "common_throws.h"
#include "dex_cache.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "gc/heap-inl.h"
#include "iftable.h"
#include "invoke_type.h"
@@ -440,7 +440,6 @@ inline bool Class::ResolvedFieldAccessTest(ObjPtr<Class> access_to,
// cache. Use LookupResolveType here to search the class table if it is not in the dex cache.
// should be no thread suspension due to the class being resolved.
ObjPtr<Class> dex_access_to = Runtime::Current()->GetClassLinker()->LookupResolvedType(
- *dex_cache->GetDexFile(),
class_idx,
dex_cache,
access_to->GetClassLoader());
@@ -477,7 +476,6 @@ inline bool Class::ResolvedMethodAccessTest(ObjPtr<Class> access_to,
// The referenced class has already been resolved with the method, but may not be in the dex
// cache.
ObjPtr<Class> dex_access_to = Runtime::Current()->GetClassLinker()->LookupResolvedType(
- *dex_cache->GetDexFile(),
class_idx,
dex_cache,
access_to->GetClassLoader());
diff --git a/runtime/mirror/class-refvisitor-inl.h b/runtime/mirror/class-refvisitor-inl.h
index 3d52ead0f4..263b7746db 100644
--- a/runtime/mirror/class-refvisitor-inl.h
+++ b/runtime/mirror/class-refvisitor-inl.h
@@ -32,12 +32,12 @@ template <bool kVisitNativeRoots,
inline void Class::VisitReferences(ObjPtr<Class> klass, const Visitor& visitor) {
VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass.Ptr(), visitor);
// Right after a class is allocated, but not yet loaded
- // (kStatusNotReady, see ClassLinker::LoadClass()), GC may find it
+ // (ClassStatus::kNotReady, see ClassLinker::LoadClass()), GC may find it
// and scan it. IsTemp() may call Class::GetAccessFlags() but may
// fail in the DCHECK in Class::GetAccessFlags() because the class
- // status is kStatusNotReady. To avoid it, rely on IsResolved()
+ // status is ClassStatus::kNotReady. To avoid it, rely on IsResolved()
// only. This is fine because a temp class never goes into the
- // kStatusResolved state.
+ // ClassStatus::kResolved state.
if (IsResolved<kVerifyFlags>()) {
// Temp classes don't ever populate imt/vtable or static fields and they are not even
// allocated with the right size for those. Also, unresolved classes don't have fields
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 892c03912a..8a7defd362 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -20,13 +20,14 @@
#include "art_field-inl.h"
#include "art_method-inl.h"
+#include "base/logging.h" // For VLOG.
#include "class-inl.h"
#include "class_ext.h"
#include "class_linker-inl.h"
#include "class_loader.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_annotations.h"
#include "dex_cache.h"
-#include "dex_file-inl.h"
-#include "dex_file_annotations.h"
#include "gc/accounting/card_table-inl.h"
#include "handle_scope-inl.h"
#include "subtype_check.h"
@@ -53,23 +54,6 @@ using android::base::StringPrintf;
GcRoot<Class> Class::java_lang_Class_;
-constexpr Class::Status Class::kStatusRetired;
-constexpr Class::Status Class::kStatusErrorResolved;
-constexpr Class::Status Class::kStatusErrorUnresolved;
-constexpr Class::Status Class::kStatusNotReady;
-constexpr Class::Status Class::kStatusIdx;
-constexpr Class::Status Class::kStatusLoaded;
-constexpr Class::Status Class::kStatusResolving;
-constexpr Class::Status Class::kStatusResolved;
-constexpr Class::Status Class::kStatusVerifying;
-constexpr Class::Status Class::kStatusRetryVerificationAtRuntime;
-constexpr Class::Status Class::kStatusVerifyingAtRuntime;
-constexpr Class::Status Class::kStatusVerified;
-constexpr Class::Status Class::kStatusSuperclassValidated;
-constexpr Class::Status Class::kStatusInitializing;
-constexpr Class::Status Class::kStatusInitialized;
-constexpr Class::Status Class::kStatusMax;
-
void Class::SetClassClass(ObjPtr<Class> java_lang_Class) {
CHECK(java_lang_Class_.IsNull())
<< java_lang_Class_.Read()
@@ -130,19 +114,19 @@ ClassExt* Class::EnsureExtDataPresent(Thread* self) {
}
}
-void Class::SetStatus(Handle<Class> h_this, Status new_status, Thread* self) {
- Status old_status = h_this->GetStatus();
+void Class::SetStatus(Handle<Class> h_this, ClassStatus new_status, Thread* self) {
+ ClassStatus old_status = h_this->GetStatus();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
bool class_linker_initialized = class_linker != nullptr && class_linker->IsInitialized();
if (LIKELY(class_linker_initialized)) {
if (UNLIKELY(new_status <= old_status &&
- new_status != kStatusErrorUnresolved &&
- new_status != kStatusErrorResolved &&
- new_status != kStatusRetired)) {
+ new_status != ClassStatus::kErrorUnresolved &&
+ new_status != ClassStatus::kErrorResolved &&
+ new_status != ClassStatus::kRetired)) {
LOG(FATAL) << "Unexpected change back of class status for " << h_this->PrettyClass()
<< " " << old_status << " -> " << new_status;
}
- if (new_status >= kStatusResolved || old_status >= kStatusResolved) {
+ if (new_status >= ClassStatus::kResolved || old_status >= ClassStatus::kResolved) {
// When classes are being resolved the resolution code should hold the lock.
CHECK_EQ(h_this->GetLockOwnerThreadId(), self->GetThreadId())
<< "Attempt to change status of class while not holding its lock: "
@@ -154,7 +138,7 @@ void Class::SetStatus(Handle<Class> h_this, Status new_status, Thread* self) {
<< "Attempt to set as erroneous an already erroneous class "
<< h_this->PrettyClass()
<< " old_status: " << old_status << " new_status: " << new_status;
- CHECK_EQ(new_status == kStatusErrorResolved, old_status >= kStatusResolved);
+ CHECK_EQ(new_status == ClassStatus::kErrorResolved, old_status >= ClassStatus::kResolved);
if (VLOG_IS_ON(class_linker)) {
LOG(ERROR) << "Setting " << h_this->PrettyDescriptor() << " to erroneous.";
if (self->IsExceptionPending()) {
@@ -180,7 +164,7 @@ void Class::SetStatus(Handle<Class> h_this, Status new_status, Thread* self) {
// Setting the object size alloc fast path needs to be after the status write so that if the
// alloc path sees a valid object size, we would know that it's initialized as long as it has a
// load-acquire/fake dependency.
- if (new_status == kStatusInitialized && !h_this->IsVariableSize()) {
+ if (new_status == ClassStatus::kInitialized && !h_this->IsVariableSize()) {
DCHECK_EQ(h_this->GetObjectSizeAllocFastPath(), std::numeric_limits<uint32_t>::max());
// Finalizable objects must always go slow path.
if (!h_this->IsFinalizable()) {
@@ -198,13 +182,13 @@ void Class::SetStatus(Handle<Class> h_this, Status new_status, Thread* self) {
if (h_this->IsTemp()) {
// Class is a temporary one, ensure that waiters for resolution get notified of retirement
// so that they can grab the new version of the class from the class linker's table.
- CHECK_LT(new_status, kStatusResolved) << h_this->PrettyDescriptor();
- if (new_status == kStatusRetired || new_status == kStatusErrorUnresolved) {
+ CHECK_LT(new_status, ClassStatus::kResolved) << h_this->PrettyDescriptor();
+ if (new_status == ClassStatus::kRetired || new_status == ClassStatus::kErrorUnresolved) {
h_this->NotifyAll(self);
}
} else {
- CHECK_NE(new_status, kStatusRetired);
- if (old_status >= kStatusResolved || new_status >= kStatusResolved) {
+ CHECK_NE(new_status, ClassStatus::kRetired);
+ if (old_status >= ClassStatus::kResolved || new_status >= ClassStatus::kResolved) {
h_this->NotifyAll(self);
}
}
@@ -1034,7 +1018,7 @@ ObjPtr<Class> Class::GetDirectInterface(Thread* self, ObjPtr<Class> klass, uint3
return interfaces->Get(idx);
} else {
dex::TypeIndex type_idx = klass->GetDirectInterfaceTypeIdx(idx);
- ObjPtr<Class> interface = ClassLinker::LookupResolvedType(
+ ObjPtr<Class> interface = Runtime::Current()->GetClassLinker()->LookupResolvedType(
type_idx, klass->GetDexCache(), klass->GetClassLoader());
return interface;
}
@@ -1046,9 +1030,7 @@ ObjPtr<Class> Class::ResolveDirectInterface(Thread* self, Handle<Class> klass, u
DCHECK(!klass->IsArrayClass());
DCHECK(!klass->IsProxyClass());
dex::TypeIndex type_idx = klass->GetDirectInterfaceTypeIdx(idx);
- interface = Runtime::Current()->GetClassLinker()->ResolveType(klass->GetDexFile(),
- type_idx,
- klass.Get());
+ interface = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, klass.Get());
CHECK(interface != nullptr || self->IsExceptionPending());
}
return interface;
@@ -1130,7 +1112,7 @@ class ReadBarrierOnNativeRootsVisitor {
// Update the field atomically. This may fail if mutator updates before us, but it's ok.
auto* atomic_root =
reinterpret_cast<Atomic<CompressedReference<Object>>*>(root);
- atomic_root->CompareExchangeStrongSequentiallyConsistent(
+ atomic_root->CompareAndSetStrongSequentiallyConsistent(
CompressedReference<Object>::FromMirrorPtr(old_ref.Ptr()),
CompressedReference<Object>::FromMirrorPtr(new_ref.Ptr()));
}
@@ -1155,7 +1137,7 @@ class CopyClassVisitor {
StackHandleScope<1> hs(self_);
Handle<mirror::Class> h_new_class_obj(hs.NewHandle(obj->AsClass()));
Object::CopyObject(h_new_class_obj.Get(), orig_->Get(), copy_bytes_);
- Class::SetStatus(h_new_class_obj, Class::kStatusResolving, self_);
+ Class::SetStatus(h_new_class_obj, ClassStatus::kResolving, self_);
h_new_class_obj->PopulateEmbeddedVTable(pointer_size_);
h_new_class_obj->SetImt(imt_, pointer_size_);
h_new_class_obj->SetClassSize(new_length_);
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index c545a9b7d5..55c588930e 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -18,12 +18,13 @@
#define ART_RUNTIME_MIRROR_CLASS_H_
#include "base/bit_utils.h"
+#include "base/casts.h"
#include "base/enums.h"
#include "base/iteration_range.h"
#include "class_flags.h"
#include "class_status.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
#include "gc/allocator_type.h"
#include "gc_root.h"
#include "imtable.h"
@@ -77,38 +78,16 @@ class MANAGED Class FINAL : public Object {
static constexpr uint32_t kPrimitiveTypeSizeShiftShift = 16;
static constexpr uint32_t kPrimitiveTypeMask = (1u << kPrimitiveTypeSizeShiftShift) - 1;
- // Make ClassStatus available as Class::Status.
- using Status = ClassStatus;
-
- // Required for a minimal change. Fix up and remove in a future change.
- static constexpr Status kStatusRetired = Status::kStatusRetired;
- static constexpr Status kStatusErrorResolved = Status::kStatusErrorResolved;
- static constexpr Status kStatusErrorUnresolved = Status::kStatusErrorUnresolved;
- static constexpr Status kStatusNotReady = Status::kStatusNotReady;
- static constexpr Status kStatusIdx = Status::kStatusIdx;
- static constexpr Status kStatusLoaded = Status::kStatusLoaded;
- static constexpr Status kStatusResolving = Status::kStatusResolving;
- static constexpr Status kStatusResolved = Status::kStatusResolved;
- static constexpr Status kStatusVerifying = Status::kStatusVerifying;
- static constexpr Status kStatusRetryVerificationAtRuntime =
- Status::kStatusRetryVerificationAtRuntime;
- static constexpr Status kStatusVerifyingAtRuntime = Status::kStatusVerifyingAtRuntime;
- static constexpr Status kStatusVerified = Status::kStatusVerified;
- static constexpr Status kStatusSuperclassValidated = Status::kStatusSuperclassValidated;
- static constexpr Status kStatusInitializing = Status::kStatusInitializing;
- static constexpr Status kStatusInitialized = Status::kStatusInitialized;
- static constexpr Status kStatusMax = Status::kStatusMax;
-
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- Status GetStatus() REQUIRES_SHARED(Locks::mutator_lock_) {
+ ClassStatus GetStatus() REQUIRES_SHARED(Locks::mutator_lock_) {
// Avoid including "subtype_check_bits_and_status.h" to get the field.
// The ClassStatus is always in the least-significant bits of status_.
- return static_cast<Status>(static_cast<uint8_t>(
- static_cast<uint32_t>(GetField32Volatile<kVerifyFlags>(StatusOffset())) & 0xff));
+ return enum_cast<ClassStatus>(
+ static_cast<uint32_t>(GetField32Volatile<kVerifyFlags>(StatusOffset())) & 0xff);
}
// This is static because 'this' may be moved by GC.
- static void SetStatus(Handle<Class> h_this, Status new_status, Thread* self)
+ static void SetStatus(Handle<Class> h_this, ClassStatus new_status, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
static MemberOffset StatusOffset() {
@@ -118,24 +97,24 @@ class MANAGED Class FINAL : public Object {
// Returns true if the class has been retired.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsRetired() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() == kStatusRetired;
+ return GetStatus<kVerifyFlags>() == ClassStatus::kRetired;
}
// Returns true if the class has failed to link.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsErroneousUnresolved() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() == kStatusErrorUnresolved;
+ return GetStatus<kVerifyFlags>() == ClassStatus::kErrorUnresolved;
}
// Returns true if the class has failed to initialize.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsErroneousResolved() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() == kStatusErrorResolved;
+ return GetStatus<kVerifyFlags>() == ClassStatus::kErrorResolved;
}
// Returns true if the class status indicets that the class has failed to link or initialize.
- static bool IsErroneous(Status status) {
- return status == kStatusErrorUnresolved || status == kStatusErrorResolved;
+ static bool IsErroneous(ClassStatus status) {
+ return status == ClassStatus::kErrorUnresolved || status == ClassStatus::kErrorResolved;
}
// Returns true if the class has failed to link or initialize.
@@ -147,44 +126,44 @@ class MANAGED Class FINAL : public Object {
// Returns true if the class has been loaded.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsIdxLoaded() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() >= kStatusIdx;
+ return GetStatus<kVerifyFlags>() >= ClassStatus::kIdx;
}
// Returns true if the class has been loaded.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsLoaded() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() >= kStatusLoaded;
+ return GetStatus<kVerifyFlags>() >= ClassStatus::kLoaded;
}
// Returns true if the class has been linked.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsResolved() REQUIRES_SHARED(Locks::mutator_lock_) {
- Status status = GetStatus<kVerifyFlags>();
- return status >= kStatusResolved || status == kStatusErrorResolved;
+ ClassStatus status = GetStatus<kVerifyFlags>();
+ return status >= ClassStatus::kResolved || status == ClassStatus::kErrorResolved;
}
// Returns true if the class should be verified at runtime.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool ShouldVerifyAtRuntime() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() == kStatusRetryVerificationAtRuntime;
+ return GetStatus<kVerifyFlags>() == ClassStatus::kRetryVerificationAtRuntime;
}
// Returns true if the class has been verified.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsVerified() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() >= kStatusVerified;
+ return GetStatus<kVerifyFlags>() >= ClassStatus::kVerified;
}
// Returns true if the class is initializing.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsInitializing() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() >= kStatusInitializing;
+ return GetStatus<kVerifyFlags>() >= ClassStatus::kInitializing;
}
// Returns true if the class is initialized.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsInitialized() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetStatus<kVerifyFlags>() == kStatusInitialized;
+ return GetStatus<kVerifyFlags>() == ClassStatus::kInitialized;
}
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -333,8 +312,10 @@ class MANAGED Class FINAL : public Object {
// Returns true if this class is the placeholder and should retire and
// be replaced with a class with the right size for embedded imt/vtable.
bool IsTemp() REQUIRES_SHARED(Locks::mutator_lock_) {
- Status s = GetStatus();
- return s < Status::kStatusResolving && s != kStatusErrorResolved && ShouldHaveEmbeddedVTable();
+ ClassStatus s = GetStatus();
+ return s < ClassStatus::kResolving &&
+ s != ClassStatus::kErrorResolved &&
+ ShouldHaveEmbeddedVTable();
}
String* GetName() REQUIRES_SHARED(Locks::mutator_lock_); // Returns the cached name.
diff --git a/runtime/mirror/class_ext.cc b/runtime/mirror/class_ext.cc
index 32d49bbc10..c18b219f19 100644
--- a/runtime/mirror/class_ext.cc
+++ b/runtime/mirror/class_ext.cc
@@ -20,7 +20,7 @@
#include "base/casts.h"
#include "base/enums.h"
#include "class-inl.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "object-inl.h"
#include "object_array.h"
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 8b11c1290d..573244ef17 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -19,13 +19,14 @@
#include "dex_cache.h"
+#include <android-base/logging.h>
+
#include "art_field.h"
#include "art_method.h"
#include "base/casts.h"
#include "base/enums.h"
-#include "base/logging.h"
#include "class_linker.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "gc/heap-inl.h"
#include "gc_root.h"
#include "mirror/call_site.h"
@@ -167,7 +168,7 @@ inline CallSite* DexCache::SetResolvedCallSite(uint32_t call_site_idx, CallSite*
// The first assignment for a given call site wins.
Atomic<GcRoot<mirror::CallSite>>& ref =
reinterpret_cast<Atomic<GcRoot<mirror::CallSite>>&>(target);
- if (ref.CompareExchangeStrongSequentiallyConsistent(null_call_site, candidate)) {
+ if (ref.CompareAndSetStrongSequentiallyConsistent(null_call_site, candidate)) {
// TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this);
return call_site;
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index 2f63dff3be..eb4db00ccd 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -17,7 +17,6 @@
#include "dex_cache-inl.h"
#include "art_method-inl.h"
-#include "base/logging.h"
#include "class_linker.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/heap.h"
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index f75786b521..b46d80cf15 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -19,7 +19,8 @@
#include "array.h"
#include "base/bit_utils.h"
-#include "dex_file_types.h"
+#include "base/mutex.h"
+#include "dex/dex_file_types.h"
#include "object.h"
#include "object_array.h"
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index 8198636b3d..d2bff2c19a 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -150,13 +150,11 @@ TEST_F(DexCacheMethodHandlesTest, TestResolvedMethodTypes) {
const DexFile::MethodId& method2_id = dex_file.GetMethodId(method2->GetDexMethodIndex());
Handle<mirror::MethodType> method1_type = hs.NewHandle(
class_linker_->ResolveMethodType(soa.Self(),
- dex_file,
method1_id.proto_idx_,
dex_cache,
class_loader));
Handle<mirror::MethodType> method2_type = hs.NewHandle(
class_linker_->ResolveMethodType(soa.Self(),
- dex_file,
method2_id.proto_idx_,
dex_cache,
class_loader));
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index b6aa949ec3..9bfa4d6098 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -17,7 +17,7 @@
#ifndef ART_RUNTIME_MIRROR_EMULATED_STACK_FRAME_H_
#define ART_RUNTIME_MIRROR_EMULATED_STACK_FRAME_H_
-#include "dex_instruction.h"
+#include "dex/dex_instruction.h"
#include "method_type.h"
#include "object.h"
#include "stack.h"
diff --git a/runtime/mirror/method_handle_impl.cc b/runtime/mirror/method_handle_impl.cc
index 42b8473ef0..0b4dde1aa8 100644
--- a/runtime/mirror/method_handle_impl.cc
+++ b/runtime/mirror/method_handle_impl.cc
@@ -22,6 +22,14 @@
namespace art {
namespace mirror {
+const char* MethodHandle::GetReturnTypeDescriptor(const char* invoke_method_name) {
+ if (strcmp(invoke_method_name, "invoke") == 0 || strcmp(invoke_method_name, "invokeExact") == 0) {
+ return "Ljava/lang/Object;";
+ } else {
+ return nullptr;
+ }
+}
+
mirror::Class* MethodHandle::StaticClass() {
mirror::Class* klass = MethodHandleImpl::StaticClass()->GetSuperClass();
DCHECK(klass->DescriptorEquals("Ljava/lang/invoke/MethodHandle;"));
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index f362d43b01..a1bc976a25 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -81,6 +81,10 @@ class MANAGED MethodHandle : public Object {
ALWAYS_INLINE ObjPtr<mirror::Class> GetTargetClass() REQUIRES_SHARED(Locks::mutator_lock_);
+ // Gets the return type for a named invoke method, or nullptr if the invoke method is not
+ // supported.
+ static const char* GetReturnTypeDescriptor(const char* invoke_method_name);
+
static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_);
protected:
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index f1a86e5353..6e2a07c9e0 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -579,7 +579,7 @@ inline bool Object::CasFieldWeakSequentiallyConsistent32(MemberOffset field_offs
uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
- return atomic_addr->CompareExchangeWeakSequentiallyConsistent(old_value, new_value);
+ return atomic_addr->CompareAndSetWeakSequentiallyConsistent(old_value, new_value);
}
template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
@@ -597,7 +597,7 @@ inline bool Object::CasFieldWeakAcquire32(MemberOffset field_offset,
uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
- return atomic_addr->CompareExchangeWeakAcquire(old_value, new_value);
+ return atomic_addr->CompareAndSetWeakAcquire(old_value, new_value);
}
template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
@@ -615,7 +615,7 @@ inline bool Object::CasFieldWeakRelease32(MemberOffset field_offset,
uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
- return atomic_addr->CompareExchangeWeakRelease(old_value, new_value);
+ return atomic_addr->CompareAndSetWeakRelease(old_value, new_value);
}
template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
@@ -633,7 +633,7 @@ inline bool Object::CasFieldStrongSequentiallyConsistent32(MemberOffset field_of
uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
- return atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_value, new_value);
+ return atomic_addr->CompareAndSetStrongSequentiallyConsistent(old_value, new_value);
}
template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags,
@@ -689,7 +689,7 @@ inline bool Object::CasFieldWeakSequentiallyConsistent64(MemberOffset field_offs
}
uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
Atomic<int64_t>* atomic_addr = reinterpret_cast<Atomic<int64_t>*>(raw_addr);
- return atomic_addr->CompareExchangeWeakSequentiallyConsistent(old_value, new_value);
+ return atomic_addr->CompareAndSetWeakSequentiallyConsistent(old_value, new_value);
}
template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
@@ -706,7 +706,7 @@ inline bool Object::CasFieldStrongSequentiallyConsistent64(MemberOffset field_of
}
uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
Atomic<int64_t>* atomic_addr = reinterpret_cast<Atomic<int64_t>*>(raw_addr);
- return atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_value, new_value);
+ return atomic_addr->CompareAndSetStrongSequentiallyConsistent(old_value, new_value);
}
template<class T, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption,
@@ -832,7 +832,7 @@ inline bool Object::CasFieldWeakSequentiallyConsistentObjectWithoutWriteBarrier(
uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr);
- bool success = atomic_addr->CompareExchangeWeakSequentiallyConsistent(old_ref, new_ref);
+ bool success = atomic_addr->CompareAndSetWeakSequentiallyConsistent(old_ref, new_ref);
return success;
}
@@ -873,7 +873,7 @@ inline bool Object::CasFieldStrongSequentiallyConsistentObjectWithoutWriteBarrie
uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr);
- bool success = atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_ref, new_ref);
+ bool success = atomic_addr->CompareAndSetStrongSequentiallyConsistent(old_ref, new_ref);
return success;
}
@@ -902,7 +902,7 @@ inline bool Object::CasFieldWeakRelaxedObjectWithoutWriteBarrier(
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->CompareExchangeWeakRelaxed(old_ref, new_ref);
+ bool success = atomic_addr->CompareAndSetWeakRelaxed(old_ref, new_ref);
return success;
}
@@ -931,7 +931,7 @@ inline bool Object::CasFieldWeakReleaseObjectWithoutWriteBarrier(
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, new_ref);
+ bool success = atomic_addr->CompareAndSetWeakRelease(old_ref, new_ref);
return success;
}
diff --git a/runtime/mirror/object-readbarrier-inl.h b/runtime/mirror/object-readbarrier-inl.h
index 0a956633d4..d81fff0a22 100644
--- a/runtime/mirror/object-readbarrier-inl.h
+++ b/runtime/mirror/object-readbarrier-inl.h
@@ -52,7 +52,7 @@ inline bool Object::CasFieldWeakRelaxed32(MemberOffset field_offset,
uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
- return atomic_addr->CompareExchangeWeakRelaxed(old_value, new_value);
+ return atomic_addr->CompareAndSetWeakRelaxed(old_value, new_value);
}
inline bool Object::CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val) {
@@ -217,7 +217,7 @@ inline bool Object::CasFieldStrongRelaxedObjectWithoutWriteBarrier(
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->CompareExchangeStrongRelaxed(old_ref, new_ref);
+ bool success = atomic_addr->CompareAndSetStrongRelaxed(old_ref, new_ref);
return success;
}
@@ -246,7 +246,7 @@ inline bool Object::CasFieldStrongReleaseObjectWithoutWriteBarrier(
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, new_ref);
+ bool success = atomic_addr->CompareAndSetStrongRelease(old_ref, new_ref);
return success;
}
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 87cc620309..3765d0af59 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -24,7 +24,7 @@
#include "class-inl.h"
#include "class.h"
#include "class_linker-inl.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/heap.h"
#include "handle_scope-inl.h"
@@ -174,7 +174,7 @@ uint32_t Object::GenerateIdentityHashCode() {
do {
expected_value = hash_code_seed.LoadRelaxed();
new_value = expected_value * 1103515245 + 12345;
- } while (!hash_code_seed.CompareExchangeWeakRelaxed(expected_value, new_value) ||
+ } while (!hash_code_seed.CompareAndSetWeakRelaxed(expected_value, new_value) ||
(expected_value & LockWord::kHashMask) == 0);
return expected_value & LockWord::kHashMask;
}
@@ -240,7 +240,7 @@ void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, ObjPtr<Object>
CHECK_NE(field.GetTypeAsPrimitiveType(), Primitive::kPrimNot);
// TODO: resolve the field type for moving GC.
ObjPtr<mirror::Class> field_type =
- kMovingCollector ? field.LookupType() : field.ResolveType();
+ kMovingCollector ? field.LookupResolvedType() : field.ResolveType();
if (field_type != nullptr) {
CHECK(field_type->IsAssignableFrom(new_value->GetClass()));
}
@@ -258,7 +258,7 @@ void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, ObjPtr<Object>
CHECK_NE(field.GetTypeAsPrimitiveType(), Primitive::kPrimNot);
// TODO: resolve the field type for moving GC.
ObjPtr<mirror::Class> field_type =
- kMovingCollector ? field.LookupType() : field.ResolveType();
+ kMovingCollector ? field.LookupResolvedType() : field.ResolveType();
if (field_type != nullptr) {
CHECK(field_type->IsAssignableFrom(new_value->GetClass()));
}
diff --git a/runtime/mirror/object_reference-inl.h b/runtime/mirror/object_reference-inl.h
index 60f3ce153f..295b460a01 100644
--- a/runtime/mirror/object_reference-inl.h
+++ b/runtime/mirror/object_reference-inl.h
@@ -31,9 +31,8 @@ void ObjectReference<kPoisonReferences, MirrorType>::Assign(ObjPtr<MirrorType> p
template<class MirrorType>
bool HeapReference<MirrorType>::CasWeakRelaxed(MirrorType* expected_ptr, MirrorType* new_ptr) {
- return reference_.CompareExchangeWeakRelaxed(
- Compression::Compress(expected_ptr),
- Compression::Compress(new_ptr));
+ return reference_.CompareAndSetWeakRelaxed(Compression::Compress(expected_ptr),
+ Compression::Compress(new_ptr));
}
} // namespace mirror
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 1a0fc76190..32a99eb753 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -29,7 +29,7 @@
#include "class_linker-inl.h"
#include "class_linker.h"
#include "common_runtime_test.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/heap.h"
diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h
index 84587c871c..24c75ec0d8 100644
--- a/runtime/mirror/string-inl.h
+++ b/runtime/mirror/string-inl.h
@@ -35,7 +35,16 @@ namespace art {
namespace mirror {
inline uint32_t String::ClassSize(PointerSize pointer_size) {
+#ifdef USE_D8_DESUGAR
+ // Two lambdas in CharSequence:
+ // lambda$chars$0$CharSequence
+ // lambda$codePoints$1$CharSequence
+ // which were virtual functions in standalone desugar, becomes
+ // direct functions with D8 desugaring.
+ uint32_t vtable_entries = Object::kVTableLength + 54;
+#else
uint32_t vtable_entries = Object::kVTableLength + 56;
+#endif
return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0, 1, 2, pointer_size);
}
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index 077ad50dcc..a7a6d087e1 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -21,7 +21,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "class-inl.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "object-inl.h"
#include "object_array-inl.h"
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index e7eac1a5ab..3f4a28ce9d 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -26,6 +26,59 @@ namespace mirror {
namespace {
+struct VarHandleAccessorToAccessModeEntry {
+ const char* method_name;
+ VarHandle::AccessMode access_mode;
+
+ // Binary predicate function for finding access_mode by
+ // method_name. The access_mode field is ignored.
+ static bool CompareName(const VarHandleAccessorToAccessModeEntry& lhs,
+ const VarHandleAccessorToAccessModeEntry& rhs) {
+ return strcmp(lhs.method_name, rhs.method_name) < 0;
+ }
+};
+
+// Map of VarHandle accessor method names to access mode values. The list is alpha-sorted to support
+// binary search. For the usage scenario - lookups in the verifier - a linear scan would likely
+// suffice since we expect VarHandles to be a lesser encountered class. We could use a std::hashmap
+// here and this would be easier to maintain if new values are added here. However, this entails
+// CPU cycles initializing the structure on every execution and uses O(N) more memory for
+// intermediate nodes and makes that memory dirty. Compile-time magic using constexpr is possible
+// here, but that's a tax when this code is recompiled.
+const VarHandleAccessorToAccessModeEntry kAccessorToAccessMode[VarHandle::kNumberOfAccessModes] = {
+ { "compareAndExchange", VarHandle::AccessMode::kCompareAndExchange },
+ { "compareAndExchangeAcquire", VarHandle::AccessMode::kCompareAndExchangeAcquire },
+ { "compareAndExchangeRelease", VarHandle::AccessMode::kCompareAndExchangeRelease },
+ { "compareAndSet", VarHandle::AccessMode::kCompareAndSet },
+ { "get", VarHandle::AccessMode::kGet },
+ { "getAcquire", VarHandle::AccessMode::kGetAcquire },
+ { "getAndAdd", VarHandle::AccessMode::kGetAndAdd },
+ { "getAndAddAcquire", VarHandle::AccessMode::kGetAndAddAcquire },
+ { "getAndAddRelease", VarHandle::AccessMode::kGetAndAddRelease },
+ { "getAndBitwiseAnd", VarHandle::AccessMode::kGetAndBitwiseAnd },
+ { "getAndBitwiseAndAcquire", VarHandle::AccessMode::kGetAndBitwiseAndAcquire },
+ { "getAndBitwiseAndRelease", VarHandle::AccessMode::kGetAndBitwiseAndRelease },
+ { "getAndBitwiseOr", VarHandle::AccessMode::kGetAndBitwiseOr },
+ { "getAndBitwiseOrAcquire", VarHandle::AccessMode::kGetAndBitwiseOrAcquire },
+ { "getAndBitwiseOrRelease", VarHandle::AccessMode::kGetAndBitwiseOrRelease },
+ { "getAndBitwiseXor", VarHandle::AccessMode::kGetAndBitwiseXor },
+ { "getAndBitwiseXorAcquire", VarHandle::AccessMode::kGetAndBitwiseXorAcquire },
+ { "getAndBitwiseXorRelease", VarHandle::AccessMode::kGetAndBitwiseXorRelease },
+ { "getAndSet", VarHandle::AccessMode::kGetAndSet },
+ { "getAndSetAcquire", VarHandle::AccessMode::kGetAndSetAcquire },
+ { "getAndSetRelease", VarHandle::AccessMode::kGetAndSetRelease },
+ { "getOpaque", VarHandle::AccessMode::kGetOpaque },
+ { "getVolatile", VarHandle::AccessMode::kGetVolatile },
+ { "set", VarHandle::AccessMode::kSet },
+ { "setOpaque", VarHandle::AccessMode::kSetOpaque },
+ { "setRelease", VarHandle::AccessMode::kSetRelease },
+ { "setVolatile", VarHandle::AccessMode::kSetVolatile },
+ { "weakCompareAndSet", VarHandle::AccessMode::kWeakCompareAndSet },
+ { "weakCompareAndSetAcquire", VarHandle::AccessMode::kWeakCompareAndSetAcquire },
+ { "weakCompareAndSetPlain", VarHandle::AccessMode::kWeakCompareAndSetPlain },
+ { "weakCompareAndSetRelease", VarHandle::AccessMode::kWeakCompareAndSetRelease },
+};
+
// Enumeration for describing the parameter and return types of an AccessMode.
enum class AccessModeTemplate : uint32_t {
kGet, // T Op(C0..CN)
@@ -281,6 +334,41 @@ MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode acces
return GetMethodTypeForAccessMode(self, this, access_mode);
}
+const char* VarHandle::GetReturnTypeDescriptor(const char* accessor_name) {
+ AccessMode access_mode;
+ if (!GetAccessModeByMethodName(accessor_name, &access_mode)) {
+ return nullptr;
+ }
+ AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
+ switch (access_mode_template) {
+ case AccessModeTemplate::kGet:
+ case AccessModeTemplate::kCompareAndExchange:
+ case AccessModeTemplate::kGetAndUpdate:
+ return "Ljava/lang/Object;";
+ case AccessModeTemplate::kCompareAndSet:
+ return "Z";
+ case AccessModeTemplate::kSet:
+ return "V";
+ }
+}
+
+bool VarHandle::GetAccessModeByMethodName(const char* method_name, AccessMode* access_mode) {
+ if (method_name == nullptr) {
+ return false;
+ }
+ VarHandleAccessorToAccessModeEntry target = { method_name, /*dummy*/VarHandle::AccessMode::kGet };
+ auto last = std::cend(kAccessorToAccessMode);
+ auto it = std::lower_bound(std::cbegin(kAccessorToAccessMode),
+ last,
+ target,
+ VarHandleAccessorToAccessModeEntry::CompareName);
+ if (it == last || strcmp(it->method_name, method_name) != 0) {
+ return false;
+ }
+ *access_mode = it->access_mode;
+ return true;
+}
+
void VarHandle::SetClass(Class* klass) {
CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
CHECK(klass != nullptr);
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index a2a5d8c9ff..7b48669bba 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -26,6 +26,7 @@ namespace art {
template<class T> class Handle;
struct VarHandleOffsets;
struct FieldVarHandleOffsets;
+struct ArrayElementVarHandleOffsets;
struct ByteArrayViewVarHandleOffsets;
struct ByteBufferViewVarHandleOffsets;
@@ -77,7 +78,9 @@ class MANAGED VarHandle : public Object {
kGetAndBitwiseXor,
kGetAndBitwiseXorRelease,
kGetAndBitwiseXorAcquire,
+ kLast = kGetAndBitwiseXorAcquire,
};
+ constexpr static size_t kNumberOfAccessModes = static_cast<size_t>(AccessMode::kLast) + 1u;
// Returns true if the AccessMode specified is a supported operation.
bool IsAccessModeSupported(AccessMode accessMode) REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -104,6 +107,14 @@ class MANAGED VarHandle : public Object {
return static_class_.Read();
}
+ // Gets the return type descriptor for a named accessor method,
+ // nullptr if accessor_method is not supported.
+ static const char* GetReturnTypeDescriptor(const char* accessor_method);
+
+ // Returns true and sets access_mode if method_name corresponds to a
+ // VarHandle access method, such as "setOpaque". Returns false otherwise.
+ static bool GetAccessModeByMethodName(const char* method_name, AccessMode* access_mode);
+
static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/var_handle_test.cc b/runtime/mirror/var_handle_test.cc
index 159f80c4fd..e844fd4436 100644
--- a/runtime/mirror/var_handle_test.cc
+++ b/runtime/mirror/var_handle_test.cc
@@ -987,5 +987,79 @@ TEST_F(VarHandleTest, ByteBufferViewVarHandle) {
}
}
+TEST_F(VarHandleTest, GetMethodTypeForAccessMode) {
+ VarHandle::AccessMode access_mode;
+
+ // Invalid access mode names
+ EXPECT_FALSE(VarHandle::GetAccessModeByMethodName(nullptr, &access_mode));
+ EXPECT_FALSE(VarHandle::GetAccessModeByMethodName("", &access_mode));
+ EXPECT_FALSE(VarHandle::GetAccessModeByMethodName("CompareAndExchange", &access_mode));
+ EXPECT_FALSE(VarHandle::GetAccessModeByMethodName("compareAndExchangX", &access_mode));
+
+ // Valid access mode names
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("compareAndExchange", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kCompareAndExchange, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("compareAndExchangeAcquire", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kCompareAndExchangeAcquire, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("compareAndExchangeRelease", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kCompareAndExchangeRelease, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("compareAndSet", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kCompareAndSet, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("get", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGet, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAcquire", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAcquire, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndAdd", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndAdd, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndAddAcquire", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndAddAcquire, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndAddRelease", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndAddRelease, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndBitwiseAnd", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndBitwiseAnd, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndBitwiseAndAcquire", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndBitwiseAndAcquire, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndBitwiseAndRelease", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndBitwiseAndRelease, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndBitwiseOr", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndBitwiseOr, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndBitwiseOrAcquire", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndBitwiseOrAcquire, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndBitwiseOrRelease", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndBitwiseOrRelease, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndBitwiseXor", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndBitwiseXor, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndBitwiseXorAcquire", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndBitwiseXorAcquire, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndBitwiseXorRelease", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndBitwiseXorRelease, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndSet", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndSet, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndSetAcquire", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndSetAcquire, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getAndSetRelease", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetAndSetRelease, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getOpaque", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetOpaque, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("getVolatile", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kGetVolatile, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("set", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kSet, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("setOpaque", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kSetOpaque, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("setRelease", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kSetRelease, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("setVolatile", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kSetVolatile, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("weakCompareAndSet", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kWeakCompareAndSet, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("weakCompareAndSetAcquire", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kWeakCompareAndSetAcquire, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("weakCompareAndSetPlain", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kWeakCompareAndSetPlain, access_mode);
+ EXPECT_TRUE(VarHandle::GetAccessModeByMethodName("weakCompareAndSetRelease", &access_mode));
+ EXPECT_EQ(VarHandle::AccessMode::kWeakCompareAndSetRelease, access_mode);
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index d5520d9aca..325591fb53 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -21,14 +21,15 @@
#include "android-base/stringprintf.h"
#include "art_method-inl.h"
+#include "base/logging.h" // For VLOG.
#include "base/mutex.h"
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
#include "class_linker.h"
-#include "dex_file-inl.h"
-#include "dex_file_types.h"
-#include "dex_instruction-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_types.h"
+#include "dex/dex_instruction-inl.h"
#include "lock_word-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
@@ -133,7 +134,7 @@ Monitor::Monitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_
int32_t Monitor::GetHashCode() {
while (!HasHashCode()) {
- if (hash_code_.CompareExchangeWeakRelaxed(0, mirror::Object::GenerateIdentityHashCode())) {
+ if (hash_code_.CompareAndSetWeakRelaxed(0, mirror::Object::GenerateIdentityHashCode())) {
break;
}
}
@@ -1288,62 +1289,54 @@ uint32_t Monitor::GetLockOwnerThreadId(mirror::Object* obj) {
}
}
-void Monitor::DescribeWait(std::ostream& os, const Thread* thread) {
- // Determine the wait message and object we're waiting or blocked upon.
- mirror::Object* pretty_object = nullptr;
- const char* wait_message = nullptr;
- uint32_t lock_owner = ThreadList::kInvalidThreadId;
+ThreadState Monitor::FetchState(const Thread* thread,
+ /* out */ mirror::Object** monitor_object,
+ /* out */ uint32_t* lock_owner_tid) {
+ DCHECK(monitor_object != nullptr);
+ DCHECK(lock_owner_tid != nullptr);
+
+ *monitor_object = nullptr;
+ *lock_owner_tid = ThreadList::kInvalidThreadId;
+
ThreadState state = thread->GetState();
- if (state == kWaiting || state == kTimedWaiting || state == kSleeping) {
- wait_message = (state == kSleeping) ? " - sleeping on " : " - waiting on ";
- Thread* self = Thread::Current();
- MutexLock mu(self, *thread->GetWaitMutex());
- Monitor* monitor = thread->GetWaitMonitor();
- if (monitor != nullptr) {
- pretty_object = monitor->GetObject();
- }
- } else if (state == kBlocked || state == kWaitingForLockInflation) {
- wait_message = (state == kBlocked) ? " - waiting to lock "
- : " - waiting for lock inflation of ";
- pretty_object = thread->GetMonitorEnterObject();
- if (pretty_object != nullptr) {
- if (kUseReadBarrier && Thread::Current()->GetIsGcMarking()) {
- // We may call Thread::Dump() in the middle of the CC thread flip and this thread's stack
- // may have not been flipped yet and "pretty_object" may be a from-space (stale) ref, in
- // which case the GetLockOwnerThreadId() call below will crash. So explicitly mark/forward
- // it here.
- pretty_object = ReadBarrier::Mark(pretty_object);
+
+ switch (state) {
+ case kWaiting:
+ case kTimedWaiting:
+ case kSleeping:
+ {
+ Thread* self = Thread::Current();
+ MutexLock mu(self, *thread->GetWaitMutex());
+ Monitor* monitor = thread->GetWaitMonitor();
+ if (monitor != nullptr) {
+ *monitor_object = monitor->GetObject();
}
- lock_owner = pretty_object->GetLockOwnerThreadId();
}
- }
+ break;
- if (wait_message != nullptr) {
- if (pretty_object == nullptr) {
- os << wait_message << "an unknown object";
- } else {
- if ((pretty_object->GetLockWord(true).GetState() == LockWord::kThinLocked) &&
- Locks::mutator_lock_->IsExclusiveHeld(Thread::Current())) {
- // Getting the identity hashcode here would result in lock inflation and suspension of the
- // current thread, which isn't safe if this is the only runnable thread.
- os << wait_message << StringPrintf("<@addr=0x%" PRIxPTR "> (a %s)",
- reinterpret_cast<intptr_t>(pretty_object),
- pretty_object->PrettyTypeOf().c_str());
- } else {
- // - waiting on <0x6008c468> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
- // Call PrettyTypeOf before IdentityHashCode since IdentityHashCode can cause thread
- // suspension and move pretty_object.
- const std::string pretty_type(pretty_object->PrettyTypeOf());
- os << wait_message << StringPrintf("<0x%08x> (a %s)", pretty_object->IdentityHashCode(),
- pretty_type.c_str());
+ case kBlocked:
+ case kWaitingForLockInflation:
+ {
+ mirror::Object* lock_object = thread->GetMonitorEnterObject();
+ if (lock_object != nullptr) {
+ if (kUseReadBarrier && Thread::Current()->GetIsGcMarking()) {
+ // We may call Thread::Dump() in the middle of the CC thread flip and this thread's stack
+ // may have not been flipped yet and "pretty_object" may be a from-space (stale) ref, in
+ // which case the GetLockOwnerThreadId() call below will crash. So explicitly mark/forward
+ // it here.
+ lock_object = ReadBarrier::Mark(lock_object);
+ }
+ *monitor_object = lock_object;
+ *lock_owner_tid = lock_object->GetLockOwnerThreadId();
}
}
- // - waiting to lock <0x613f83d8> (a java.lang.Object) held by thread 5
- if (lock_owner != ThreadList::kInvalidThreadId) {
- os << " held by thread " << lock_owner;
- }
- os << "\n";
+ break;
+
+ default:
+ break;
}
+
+ return state;
}
mirror::Object* Monitor::GetContendedMonitor(Thread* thread) {
@@ -1384,9 +1377,9 @@ void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(mirror::O
}
// Is there any reason to believe there's any synchronization in this method?
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- CHECK(code_item != nullptr) << m->PrettyMethod();
- if (code_item->tries_size_ == 0) {
+ CHECK(m->GetCodeItem() != nullptr) << m->PrettyMethod();
+ CodeItemDataAccessor accessor(m);
+ if (accessor.TriesSize() == 0) {
return; // No "tries" implies no synchronization, so no held locks to report.
}
@@ -1406,11 +1399,10 @@ void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(mirror::O
for (verifier::MethodVerifier::DexLockInfo& dex_lock_info : monitor_enter_dex_pcs) {
// As a debug check, check that dex PC corresponds to a monitor-enter.
if (kIsDebugBuild) {
- const Instruction* monitor_enter_instruction =
- Instruction::At(&code_item->insns_[dex_lock_info.dex_pc]);
- CHECK_EQ(monitor_enter_instruction->Opcode(), Instruction::MONITOR_ENTER)
+ const Instruction& monitor_enter_instruction = accessor.InstructionAt(dex_lock_info.dex_pc);
+ CHECK_EQ(monitor_enter_instruction.Opcode(), Instruction::MONITOR_ENTER)
<< "expected monitor-enter @" << dex_lock_info.dex_pc << "; was "
- << reinterpret_cast<const void*>(monitor_enter_instruction);
+ << reinterpret_cast<const void*>(&monitor_enter_instruction);
}
// Iterate through the set of dex registers, as the compiler may not have held all of them
diff --git a/runtime/monitor.h b/runtime/monitor.h
index b4c0e6f471..f150a8c091 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -94,7 +94,9 @@ class Monitor {
bool interruptShouldThrow, ThreadState why)
REQUIRES_SHARED(Locks::mutator_lock_) NO_THREAD_SAFETY_ANALYSIS;
- static void DescribeWait(std::ostream& os, const Thread* thread)
+ static ThreadState FetchState(const Thread* thread,
+ /* out */ mirror::Object** monitor_object,
+ /* out */ uint32_t* lock_owner_tid)
REQUIRES(!Locks::thread_suspend_count_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/monitor_objects_stack_visitor.h b/runtime/monitor_objects_stack_visitor.h
new file mode 100644
index 0000000000..5c962c3b26
--- /dev/null
+++ b/runtime/monitor_objects_stack_visitor.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_MONITOR_OBJECTS_STACK_VISITOR_H_
+#define ART_RUNTIME_MONITOR_OBJECTS_STACK_VISITOR_H_
+
+#include <android-base/logging.h>
+
+#include "art_method.h"
+#include "base/mutex.h"
+#include "monitor.h"
+#include "stack.h"
+#include "thread.h"
+#include "thread_state.h"
+
+namespace art {
+
+namespace mirror {
+class Object;
+}
+
+class Context;
+
+class MonitorObjectsStackVisitor : public StackVisitor {
+ public:
+ MonitorObjectsStackVisitor(Thread* thread_in,
+ Context* context,
+ bool check_suspended = true,
+ bool dump_locks_in = true)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ : StackVisitor(thread_in,
+ context,
+ StackVisitor::StackWalkKind::kIncludeInlinedFrames,
+ check_suspended),
+ frame_count(0u),
+ dump_locks(dump_locks_in) {}
+
+ enum class VisitMethodResult {
+ kContinueMethod,
+ kSkipMethod,
+ kEndStackWalk,
+ };
+
+ bool VisitFrame() FINAL REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = GetMethod();
+ if (m->IsRuntimeMethod()) {
+ return true;
+ }
+
+ VisitMethodResult vmrEntry = StartMethod(m, frame_count);
+ switch (vmrEntry) {
+ case VisitMethodResult::kContinueMethod:
+ break;
+ case VisitMethodResult::kSkipMethod:
+ return true;
+ case VisitMethodResult::kEndStackWalk:
+ return false;
+ }
+
+ if (frame_count == 0) {
+ // Top frame, check for blocked state.
+
+ mirror::Object* monitor_object;
+ uint32_t lock_owner_tid;
+ ThreadState state = Monitor::FetchState(GetThread(),
+ &monitor_object,
+ &lock_owner_tid);
+ switch (state) {
+ case kWaiting:
+ case kTimedWaiting:
+ VisitWaitingObject(monitor_object, state);
+ break;
+ case kSleeping:
+ VisitSleepingObject(monitor_object);
+ break;
+
+ case kBlocked:
+ case kWaitingForLockInflation:
+ VisitBlockedOnObject(monitor_object, state, lock_owner_tid);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (dump_locks) {
+ // Visit locks, but do not abort on errors. This could trigger a nested abort.
+ // Skip visiting locks if dump_locks is false as it would cause a bad_mutexes_held in
+ // RegTypeCache::RegTypeCache due to thread_list_lock.
+ Monitor::VisitLocks(this, VisitLockedObject, this, false);
+ }
+
+ ++frame_count;
+
+ VisitMethodResult vmrExit = EndMethod(m);
+ switch (vmrExit) {
+ case VisitMethodResult::kContinueMethod:
+ case VisitMethodResult::kSkipMethod:
+ return true;
+
+ case VisitMethodResult::kEndStackWalk:
+ return false;
+ }
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+ }
+
+ protected:
+ virtual VisitMethodResult StartMethod(ArtMethod* m, size_t frame_nr)
+ REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+ virtual VisitMethodResult EndMethod(ArtMethod* m)
+ REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+
+ virtual void VisitWaitingObject(mirror::Object* obj, ThreadState state)
+ REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+ virtual void VisitSleepingObject(mirror::Object* obj)
+ REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+ virtual void VisitBlockedOnObject(mirror::Object* obj, ThreadState state, uint32_t owner_tid)
+ REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+ virtual void VisitLockedObject(mirror::Object* obj)
+ REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+
+ size_t frame_count;
+
+ private:
+ static void VisitLockedObject(mirror::Object* o, void* context)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ MonitorObjectsStackVisitor* self = reinterpret_cast<MonitorObjectsStackVisitor*>(context);
+ if (o != nullptr) {
+ if (kUseReadBarrier && Thread::Current()->GetIsGcMarking()) {
+ // We may call Thread::Dump() in the middle of the CC thread flip and this thread's stack
+ // may have not been flipped yet and "o" may be a from-space (stale) ref, in which case the
+ // IdentityHashCode call below will crash. So explicitly mark/forward it here.
+ o = ReadBarrier::Mark(o);
+ }
+ }
+ self->VisitLockedObject(o);
+ }
+
+ const bool dump_locks;
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_MONITOR_OBJECTS_STACK_VISITOR_H_
diff --git a/runtime/monitor_pool.cc b/runtime/monitor_pool.cc
index d00f979379..cf5934b6a0 100644
--- a/runtime/monitor_pool.cc
+++ b/runtime/monitor_pool.cc
@@ -16,7 +16,7 @@
#include "monitor_pool.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/mutex-inl.h"
#include "monitor.h"
#include "thread-current-inl.h"
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index c0de374904..a992b5cb5b 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -27,8 +27,8 @@
#include <class_loader_context.h>
#include "common_throws.h"
#include "compiler_filter.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_loader.h"
#include "jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index 2663bea344..6da34bcc60 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -157,8 +157,9 @@ static jboolean VMDebug_isDebuggerConnected(JNIEnv*, jclass) {
return Dbg::IsDebuggerActive();
}
-static jboolean VMDebug_isDebuggingEnabled(JNIEnv*, jclass) {
- return Dbg::IsJdwpConfigured();
+static jboolean VMDebug_isDebuggingEnabled(JNIEnv* env, jclass) {
+ ScopedObjectAccess soa(env);
+ return Runtime::Current()->GetRuntimeCallbacks()->IsDebuggerConfigured();
}
static jlong VMDebug_lastDebuggerActivity(JNIEnv*, jclass) {
@@ -319,6 +320,53 @@ static jlongArray VMDebug_countInstancesOfClasses(JNIEnv* env,
return soa.AddLocalReference<jlongArray>(long_counts);
}
+static jobjectArray VMDebug_getInstancesOfClasses(JNIEnv* env,
+ jclass,
+ jobjectArray javaClasses,
+ jboolean includeAssignable) {
+ ScopedObjectAccess soa(env);
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::ObjectArray<mirror::Class>> classes = hs.NewHandle(
+ soa.Decode<mirror::ObjectArray<mirror::Class>>(javaClasses));
+ if (classes == nullptr) {
+ return nullptr;
+ }
+
+ jclass object_array_class = env->FindClass("[Ljava/lang/Object;");
+ if (env->ExceptionCheck() == JNI_TRUE) {
+ return nullptr;
+ }
+ CHECK(object_array_class != nullptr);
+
+ size_t num_classes = classes->GetLength();
+ jobjectArray result = env->NewObjectArray(num_classes, object_array_class, nullptr);
+ if (env->ExceptionCheck() == JNI_TRUE) {
+ return nullptr;
+ }
+
+ gc::Heap* const heap = Runtime::Current()->GetHeap();
+ MutableHandle<mirror::Class> h_class(hs.NewHandle<mirror::Class>(nullptr));
+ for (size_t i = 0; i < num_classes; ++i) {
+ h_class.Assign(classes->Get(i));
+
+ VariableSizedHandleScope hs2(soa.Self());
+ std::vector<Handle<mirror::Object>> raw_instances;
+ heap->GetInstances(hs2, h_class, includeAssignable, /* max_count */ 0, raw_instances);
+ jobjectArray array = env->NewObjectArray(raw_instances.size(),
+ WellKnownClasses::java_lang_Object,
+ nullptr);
+ if (env->ExceptionCheck() == JNI_TRUE) {
+ return nullptr;
+ }
+
+ for (size_t j = 0; j < raw_instances.size(); ++j) {
+ env->SetObjectArrayElement(array, j, raw_instances[j].ToJObject());
+ }
+ env->SetObjectArrayElement(result, i, array);
+ }
+ return result;
+}
+
// We export the VM internal per-heap-space size/alloc/free metrics
// for the zygote space, alloc space (application heap), and the large
// object space for dumpsys meminfo. The other memory region data such
@@ -500,7 +548,7 @@ static jobjectArray VMDebug_getRuntimeStatsInternal(JNIEnv* env, jclass) {
return result;
}
-static void VMDebug_attachAgent(JNIEnv* env, jclass, jstring agent) {
+static void VMDebug_nativeAttachAgent(JNIEnv* env, jclass, jstring agent, jobject classloader) {
if (agent == nullptr) {
ScopedObjectAccess soa(env);
ThrowNullPointerException("agent is null");
@@ -522,7 +570,7 @@ static void VMDebug_attachAgent(JNIEnv* env, jclass, jstring agent) {
filename = chars.c_str();
}
- Runtime::Current()->AttachAgent(filename);
+ Runtime::Current()->AttachAgent(env, filename, classloader);
}
static JNINativeMethod gMethods[] = {
@@ -534,6 +582,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMDebug, dumpReferenceTables, "()V"),
NATIVE_METHOD(VMDebug, getAllocCount, "(I)I"),
NATIVE_METHOD(VMDebug, getHeapSpaceStats, "([J)V"),
+ NATIVE_METHOD(VMDebug, getInstancesOfClasses, "([Ljava/lang/Class;Z)[[Ljava/lang/Object;"),
NATIVE_METHOD(VMDebug, getInstructionCount, "([I)V"),
FAST_NATIVE_METHOD(VMDebug, getLoadedClassCount, "()I"),
NATIVE_METHOD(VMDebug, getVmFeatureList, "()[Ljava/lang/String;"),
@@ -558,7 +607,7 @@ static JNINativeMethod gMethods[] = {
FAST_NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "()J"),
NATIVE_METHOD(VMDebug, getRuntimeStatInternal, "(I)Ljava/lang/String;"),
NATIVE_METHOD(VMDebug, getRuntimeStatsInternal, "()[Ljava/lang/String;"),
- NATIVE_METHOD(VMDebug, attachAgent, "(Ljava/lang/String;)V"),
+ NATIVE_METHOD(VMDebug, nativeAttachAgent, "(Ljava/lang/String;Ljava/lang/ClassLoader;)V"),
};
void register_dalvik_system_VMDebug(JNIEnv* env) {
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 2d1f886896..400518df20 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -32,8 +32,8 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version);
#include "class_linker-inl.h"
#include "common_throws.h"
#include "debugger.h"
-#include "dex_file-inl.h"
-#include "dex_file_types.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_types.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/allocator/dlmalloc.h"
#include "gc/heap.h"
@@ -223,7 +223,7 @@ static jboolean VMRuntime_is64Bit(JNIEnv*, jobject) {
}
static jboolean VMRuntime_isCheckJniEnabled(JNIEnv* env, jobject) {
- return down_cast<JNIEnvExt*>(env)->vm->IsCheckJniEnabled() ? JNI_TRUE : JNI_FALSE;
+ return down_cast<JNIEnvExt*>(env)->GetVm()->IsCheckJniEnabled() ? JNI_TRUE : JNI_FALSE;
}
static void VMRuntime_setTargetSdkVersionNative(JNIEnv*, jobject, jint target_sdk_version) {
@@ -375,8 +375,8 @@ static void PreloadDexCachesResolveField(ObjPtr<mirror::DexCache> dex_cache,
}
const DexFile* dex_file = dex_cache->GetDexFile();
const DexFile::FieldId& field_id = dex_file->GetFieldId(field_idx);
- ObjPtr<mirror::Class> klass =
- ClassLinker::LookupResolvedType(field_id.class_idx_, dex_cache, nullptr);
+ ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->LookupResolvedType(
+ field_id.class_idx_, dex_cache, /* class_loader */ nullptr);
if (klass == nullptr) {
return;
}
@@ -401,8 +401,8 @@ static void PreloadDexCachesResolveMethod(ObjPtr<mirror::DexCache> dex_cache, ui
}
const DexFile* dex_file = dex_cache->GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx);
- ObjPtr<mirror::Class> klass =
- ClassLinker::LookupResolvedType(method_id.class_idx_, dex_cache, nullptr);
+ ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->LookupResolvedType(
+ method_id.class_idx_, dex_cache, /* class_loader */ nullptr);
if (klass == nullptr) {
return;
}
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index a88563da1f..3e8040bfa5 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -16,6 +16,8 @@
#include "dalvik_system_VMStack.h"
+#include <type_traits>
+
#include "nativehelper/jni_macros.h"
#include "art_method-inl.h"
@@ -32,12 +34,17 @@
namespace art {
-static jobject GetThreadStack(const ScopedFastNativeObjectAccess& soa, jobject peer)
+template <typename T,
+ typename ResultT =
+ typename std::result_of<T(Thread*, const ScopedFastNativeObjectAccess&)>::type>
+static ResultT GetThreadStack(const ScopedFastNativeObjectAccess& soa,
+ jobject peer,
+ T fn)
REQUIRES_SHARED(Locks::mutator_lock_) {
- jobject trace = nullptr;
+ ResultT trace = nullptr;
ObjPtr<mirror::Object> decoded_peer = soa.Decode<mirror::Object>(peer);
if (decoded_peer == soa.Self()->GetPeer()) {
- trace = soa.Self()->CreateInternalStackTrace<false>(soa);
+ trace = fn(soa.Self(), soa);
} else {
// Never allow suspending the heap task thread since it may deadlock if allocations are
// required for the stack trace.
@@ -59,7 +66,7 @@ static jobject GetThreadStack(const ScopedFastNativeObjectAccess& soa, jobject p
// Must be runnable to create returned array.
{
ScopedObjectAccess soa2(soa.Self());
- trace = thread->CreateInternalStackTrace<false>(soa);
+ trace = fn(thread, soa);
}
// Restart suspended thread.
bool resumed = thread_list->Resume(thread, SuspendReason::kInternal);
@@ -75,7 +82,11 @@ static jobject GetThreadStack(const ScopedFastNativeObjectAccess& soa, jobject p
static jint VMStack_fillStackTraceElements(JNIEnv* env, jclass, jobject javaThread,
jobjectArray javaSteArray) {
ScopedFastNativeObjectAccess soa(env);
- jobject trace = GetThreadStack(soa, javaThread);
+ auto fn = [](Thread* thread, const ScopedFastNativeObjectAccess& soaa)
+ REQUIRES_SHARED(Locks::mutator_lock_) -> jobject {
+ return thread->CreateInternalStackTrace<false>(soaa);
+ };
+ jobject trace = GetThreadStack(soa, javaThread, fn);
if (trace == nullptr) {
return 0;
}
@@ -138,7 +149,11 @@ static jclass VMStack_getStackClass2(JNIEnv* env, jclass) {
static jobjectArray VMStack_getThreadStackTrace(JNIEnv* env, jclass, jobject javaThread) {
ScopedFastNativeObjectAccess soa(env);
- jobject trace = GetThreadStack(soa, javaThread);
+ auto fn = [](Thread* thread, const ScopedFastNativeObjectAccess& soaa)
+ REQUIRES_SHARED(Locks::mutator_lock_) -> jobject {
+ return thread->CreateInternalStackTrace<false>(soaa);
+ };
+ jobject trace = GetThreadStack(soa, javaThread, fn);
if (trace == nullptr) {
return nullptr;
}
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index a7bee39a81..fd80aaeaf7 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -18,11 +18,14 @@
#include <stdlib.h>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "arch/instruction_set.h"
#include "art_method-inl.h"
-#include "base/logging.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "base/runtime_debug.h"
#include "debugger.h"
#include "java_vm_ext.h"
#include "jit/jit.h"
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 9359ffc7fd..7b999c04af 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -23,8 +23,8 @@
#include "base/enums.h"
#include "class_linker-inl.h"
#include "common_throws.h"
-#include "dex_file-inl.h"
-#include "dex_file_annotations.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_annotations.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
@@ -146,11 +146,11 @@ static jobjectArray Class_getInterfacesInternal(JNIEnv* env, jobject javaThis) {
// with kActiveTransaction == false.
DCHECK(!Runtime::Current()->IsActiveTransaction());
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
MutableHandle<mirror::Class> interface(hs.NewHandle<mirror::Class>(nullptr));
for (uint32_t i = 0; i < num_ifaces; ++i) {
const dex::TypeIndex type_idx = iface_list->GetTypeItem(i).type_idx_;
- interface.Assign(ClassLinker::LookupResolvedType(
- type_idx, klass->GetDexCache(), klass->GetClassLoader()));
+ interface.Assign(linker->LookupResolvedType(type_idx, klass.Get()));
ifaces->SetWithoutChecks<false>(i, interface.Get());
}
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index a717264bcb..9a52f7002b 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -37,7 +37,7 @@ static jobject Thread_currentThread(JNIEnv* env, jclass) {
}
static jboolean Thread_interrupted(JNIEnv* env, jclass) {
- return static_cast<JNIEnvExt*>(env)->self->Interrupted() ? JNI_TRUE : JNI_FALSE;
+ return static_cast<JNIEnvExt*>(env)->GetSelf()->Interrupted() ? JNI_TRUE : JNI_FALSE;
}
static jboolean Thread_isInterrupted(JNIEnv* env, jobject java_thread) {
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 5130ad50e4..6eebff4aca 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -17,7 +17,7 @@
#include "java_lang_VMClassLoader.h"
#include "class_linker.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file_loader.h"
#include "jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
index 5be317147b..12d400895c 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -20,7 +20,7 @@
#include "class_linker-inl.h"
#include "common_throws.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "handle_scope-inl.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index abbb347be6..86124388bc 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -22,7 +22,7 @@
#include "base/enums.h"
#include "class_linker-inl.h"
#include "class_linker.h"
-#include "dex_file_annotations.h"
+#include "dex/dex_file_annotations.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/method.h"
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index f209f1d73a..e37c14b41c 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -20,7 +20,7 @@
#include "nativehelper/jni_macros.h"
#include "art_method-inl.h"
-#include "dex_file_annotations.h"
+#include "dex/dex_file_annotations.h"
#include "handle.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 2e4dd8a599..f990c0421d 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -23,8 +23,8 @@
#include "class_linker-inl.h"
#include "class_linker.h"
#include "common_throws.h"
-#include "dex_file-inl.h"
-#include "dex_file_annotations.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_annotations.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/field-inl.h"
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index 18ff9c39bf..b604dc0fa1 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -22,7 +22,7 @@
#include "base/enums.h"
#include "class_linker-inl.h"
#include "class_linker.h"
-#include "dex_file_annotations.h"
+#include "dex/dex_file_annotations.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc
index c4ab5d69fc..0b3015bda8 100644
--- a/runtime/native/java_lang_reflect_Parameter.cc
+++ b/runtime/native/java_lang_reflect_Parameter.cc
@@ -21,8 +21,8 @@
#include "art_method-inl.h"
#include "common_throws.h"
-#include "dex_file-inl.h"
-#include "dex_file_annotations.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_annotations.h"
#include "jni_internal.h"
#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
index c79f51b51e..8f8fd71727 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
@@ -16,8 +16,9 @@
#include "org_apache_harmony_dalvik_ddmc_DdmServer.h"
+#include <android-base/logging.h>
+
#include "base/array_ref.h"
-#include "base/logging.h"
#include "debugger.h"
#include "jni_internal.h"
#include "native_util.h"
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index f5057b013a..836637f4f0 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -16,8 +16,9 @@
#include "org_apache_harmony_dalvik_ddmc_DdmVmInternal.h"
+#include <android-base/logging.h>
+
#include "base/file_utils.h"
-#include "base/logging.h"
#include "base/mutex.h"
#include "debugger.h"
#include "gc/heap.h"
@@ -31,6 +32,10 @@
namespace art {
+static Thread* GetSelf(JNIEnv* env) {
+ return static_cast<JNIEnvExt*>(env)->GetSelf();
+}
+
static void DdmVmInternal_enableRecentAllocations(JNIEnv*, jclass, jboolean enable) {
Dbg::SetAllocTrackingEnabled(enable);
}
@@ -50,7 +55,7 @@ static jboolean DdmVmInternal_getRecentAllocationStatus(JNIEnv*, jclass) {
*/
static jobjectArray DdmVmInternal_getStackTraceById(JNIEnv* env, jclass, jint thin_lock_id) {
jobjectArray trace = nullptr;
- Thread* const self = Thread::Current();
+ Thread* const self = GetSelf(env);
if (static_cast<uint32_t>(thin_lock_id) == self->GetThreadId()) {
// No need to suspend ourself to build stacktrace.
ScopedObjectAccess soa(env);
@@ -135,7 +140,7 @@ static void ThreadStatsGetterCallback(Thread* t, void* context) {
static jbyteArray DdmVmInternal_getThreadStats(JNIEnv* env, jclass) {
std::vector<uint8_t> bytes;
- Thread* self = static_cast<JNIEnvExt*>(env)->self;
+ Thread* self = GetSelf(env);
{
MutexLock mu(self, *Locks::thread_list_lock_);
ThreadList* thread_list = Runtime::Current()->GetThreadList();
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
index cd8315cdf9..7d72805dc6 100644
--- a/runtime/native_bridge_art_interface.cc
+++ b/runtime/native_bridge_art_interface.cc
@@ -22,9 +22,9 @@
#include "art_method-inl.h"
#include "base/enums.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/macros.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc
index f166714b79..ec9455289f 100644
--- a/runtime/native_stack_dump.cc
+++ b/runtime/native_stack_dump.cc
@@ -40,6 +40,7 @@
#include "android-base/stringprintf.h"
#include "arch/instruction_set.h"
+#include "base/aborting.h"
#include "base/file_utils.h"
#include "base/memory_tool.h"
#include "base/mutex.h"
diff --git a/runtime/non_debuggable_classes.cc b/runtime/non_debuggable_classes.cc
index 7db199cd06..8484e2cde7 100644
--- a/runtime/non_debuggable_classes.cc
+++ b/runtime/non_debuggable_classes.cc
@@ -16,7 +16,6 @@
#include "non_debuggable_classes.h"
-#include "base/logging.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "nativehelper/scoped_local_ref.h"
diff --git a/runtime/oat.h b/runtime/oat.h
index 9d2118064d..6d4f18bdb1 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -22,7 +22,7 @@
#include "arch/instruction_set.h"
#include "base/macros.h"
#include "compiler_filter.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "safe_map.h"
namespace art {
@@ -32,8 +32,8 @@ class InstructionSetFeatures;
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- // Last oat version changed reason: .bss index mapping change.
- static constexpr uint8_t kOatVersion[] = { '1', '3', '5', '\0' };
+ // Last oat version changed reason: 4-bit ClassStatus.
+ static constexpr uint8_t kOatVersion[] = { '1', '3', '6', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index c82df7119f..df07a191bc 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -39,11 +39,13 @@
#include "base/bit_vector.h"
#include "base/enums.h"
#include "base/file_utils.h"
+#include "base/logging.h" // For VLOG_IS_ON.
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/unix_file/fd_file.h"
-#include "dex_file_types.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file_loader.h"
+#include "dex/dex_file_types.h"
+#include "dex/standard_dex_file.h"
#include "elf_file.h"
#include "elf_utils.h"
#include "gc_root.h"
@@ -56,7 +58,6 @@
#include "oat_file_manager.h"
#include "os.h"
#include "runtime.h"
-#include "standard_dex_file.h"
#include "type_lookup_table.h"
#include "utf-inl.h"
#include "utils.h"
@@ -314,7 +315,7 @@ bool OatFileBase::ComputeFields(uint8_t* requested_base,
if (requested_base != nullptr && begin_ != requested_base) {
// Host can fail this check. Do not dump there to avoid polluting the output.
if (kIsTargetBuild && (kIsDebugBuild || VLOG_IS_ON(oat))) {
- PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
+ PrintFileToLog("/proc/self/maps", android::base::LogSeverity::WARNING);
}
*error_msg = StringPrintf("Failed to find oatdata symbol at expected address: "
"oatdata=%p != expected=%p. See process maps in the log.",
@@ -1068,7 +1069,7 @@ void DlOpenOatFile::PreSetup(const std::string& elf_filename) {
dl_iterate_context context0 = { Begin(), &dlopen_mmaps_, 0, 0};
if (dl_iterate_phdr(dl_iterate_context::callback, &context0) == 0) {
// OK, give up and print an error.
- PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
+ PrintFileToLog("/proc/self/maps", android::base::LogSeverity::WARNING);
LOG(ERROR) << "File " << elf_filename << " loaded with dlopen but cannot find its mmaps.";
}
}
@@ -1499,14 +1500,10 @@ ArrayRef<GcRoot<mirror::Object>> OatFile::GetBssGcRoots() const {
}
}
-uint32_t OatFile::GetDebugInfoOffset(const DexFile& dex_file,
- const DexFile::CodeItem* code_item) {
- if (code_item == nullptr) {
- return 0;
- }
- const uint32_t debug_info_off = code_item->debug_info_off_;
+uint32_t OatFile::GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off) {
// Note that although the specification says that 0 should be used if there
// is no debug information, some applications incorrectly use 0xFFFFFFFF.
+ // The following check also handles debug_info_off == 0.
if (debug_info_off < dex_file.Size() || debug_info_off == 0xFFFFFFFF) {
return debug_info_off;
}
@@ -1657,9 +1654,8 @@ OatFile::OatClass OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) con
const uint8_t* status_pointer = oat_class_pointer;
CHECK_LT(status_pointer, oat_file_->End()) << oat_file_->GetLocation();
- mirror::Class::Status status =
- static_cast<mirror::Class::Status>(*reinterpret_cast<const int16_t*>(status_pointer));
- CHECK_LT(status, mirror::Class::kStatusMax);
+ ClassStatus status = enum_cast<ClassStatus>(*reinterpret_cast<const int16_t*>(status_pointer));
+ CHECK_LE(status, ClassStatus::kLast);
const uint8_t* type_pointer = status_pointer + sizeof(uint16_t);
CHECK_LT(type_pointer, oat_file_->End()) << oat_file_->GetLocation();
@@ -1740,7 +1736,7 @@ void OatDexFile::MadviseDexFile(const DexFile& dex_file, MadviseState state) {
}
OatFile::OatClass::OatClass(const OatFile* oat_file,
- mirror::Class::Status status,
+ ClassStatus status,
OatClassType type,
uint32_t bitmap_size,
const uint32_t* bitmap_pointer,
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 36a4d7b8fc..02318b68b7 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -24,11 +24,12 @@
#include "base/array_ref.h"
#include "base/mutex.h"
#include "base/stringpiece.h"
+#include "class_status.h"
#include "compiler_filter.h"
-#include "dex_file.h"
-#include "dex_file_layout.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_layout.h"
#include "index_bss_mapping.h"
-#include "mirror/class.h"
+#include "mirror/object.h"
#include "oat.h"
#include "os.h"
#include "type_lookup_table.h"
@@ -114,9 +115,9 @@ class OatFile {
const char* abs_dex_location,
std::string* error_msg);
- // Return the debug info offset of the code item `item` located in `dex_file`.
- static uint32_t GetDebugInfoOffset(const DexFile& dex_file,
- const DexFile::CodeItem* item);
+ // Return the actual debug info offset for an offset that might be actually pointing to
+ // dequickening info. The returned debug info offset is the one originally in the the dex file.
+ static uint32_t GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off);
virtual ~OatFile();
@@ -196,7 +197,7 @@ class OatFile {
class OatClass FINAL {
public:
- mirror::Class::Status GetStatus() const {
+ ClassStatus GetStatus() const {
return status_;
}
@@ -224,7 +225,7 @@ class OatFile {
// See FindOatClass().
static OatClass Invalid() {
return OatClass(/* oat_file */ nullptr,
- mirror::Class::kStatusErrorUnresolved,
+ ClassStatus::kErrorUnresolved,
kOatClassNoneCompiled,
/* bitmap_size */ 0,
/* bitmap_pointer */ nullptr,
@@ -233,7 +234,7 @@ class OatFile {
private:
OatClass(const OatFile* oat_file,
- mirror::Class::Status status,
+ ClassStatus status,
OatClassType type,
uint32_t bitmap_size,
const uint32_t* bitmap_pointer,
@@ -241,7 +242,7 @@ class OatFile {
const OatFile* const oat_file_;
- const mirror::Class::Status status_;
+ const ClassStatus status_;
const OatClassType type_;
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index cd18ce102e..240030cf5b 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -24,11 +24,11 @@
#include "android-base/strings.h"
#include "base/file_utils.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/stl_util.h"
#include "class_linker.h"
#include "compiler_filter.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file_loader.h"
#include "exec_utils.h"
#include "gc/heap.h"
#include "gc/space/image_space.h"
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index b86f479eed..29b9bfcf7f 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -26,14 +26,14 @@
#include "art_field-inl.h"
#include "base/bit_vector-inl.h"
#include "base/file_utils.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/stl_util.h"
#include "base/systrace.h"
#include "class_linker.h"
#include "class_loader_context.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
-#include "dex_file_tracking_registrar.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_loader.h"
+#include "dex/dex_file_tracking_registrar.h"
#include "gc/scoped_gc_critical_section.h"
#include "gc/space/image_space.h"
#include "handle_scope-inl.h"
diff --git a/runtime/oat_quick_method_header.cc b/runtime/oat_quick_method_header.cc
index aa28fd8c9b..98238e5600 100644
--- a/runtime/oat_quick_method_header.cc
+++ b/runtime/oat_quick_method_header.cc
@@ -17,7 +17,7 @@
#include "oat_quick_method_header.h"
#include "art_method.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "scoped_thread_state_change-inl.h"
#include "thread.h"
diff --git a/runtime/os_linux.cc b/runtime/os_linux.cc
index a463f700d8..1b3e0000da 100644
--- a/runtime/os_linux.cc
+++ b/runtime/os_linux.cc
@@ -23,7 +23,8 @@
#include <cstddef>
#include <memory>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/unix_file/fd_file.h"
namespace art {
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 85af560ce3..3ac3d03e90 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -18,8 +18,10 @@
#include <sstream>
+#include <android-base/logging.h>
+
#include "base/file_utils.h"
-#include "base/logging.h"
+#include "base/macros.h"
#include "base/stringpiece.h"
#include "debugger.h"
#include "gc/heap.h"
@@ -90,15 +92,18 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize
.IntoKey(M::CheckJni)
.Define("-Xjniopts:forcecopy")
.IntoKey(M::JniOptsForceCopy)
- .Define({"-Xrunjdwp:_", "-agentlib:jdwp=_"})
- .WithType<JDWP::JdwpOptions>()
+ .Define("-XjdwpProvider:_")
+ .WithType<JdwpProvider>()
+ .IntoKey(M::JdwpProvider)
+ .Define({"-Xrunjdwp:_", "-agentlib:jdwp=_", "-XjdwpOptions:_"})
+ .WithType<std::string>()
.IntoKey(M::JdwpOptions)
// TODO Re-enable -agentlib: once I have a good way to transform the values.
// .Define("-agentlib:_")
// .WithType<std::vector<ti::Agent>>().AppendValues()
// .IntoKey(M::AgentLib)
.Define("-agentpath:_")
- .WithType<std::list<ti::Agent>>().AppendValues()
+ .WithType<std::list<ti::AgentSpec>>().AppendValues()
.IntoKey(M::AgentPath)
.Define("-Xms_")
.WithType<MemoryKiB>()
diff --git a/runtime/plugin.cc b/runtime/plugin.cc
index 6aa078771b..7d86f1d5dc 100644
--- a/runtime/plugin.cc
+++ b/runtime/plugin.cc
@@ -20,8 +20,6 @@
#include "android-base/stringprintf.h"
-#include "base/logging.h"
-
namespace art {
using android::base::StringPrintf;
diff --git a/runtime/plugin.h b/runtime/plugin.h
index f077aaf3fb..909c710a96 100644
--- a/runtime/plugin.h
+++ b/runtime/plugin.h
@@ -18,7 +18,8 @@
#define ART_RUNTIME_PLUGIN_H_
#include <string>
-#include "base/logging.h"
+
+#include <android-base/logging.h>
namespace art {
diff --git a/runtime/primitive.h b/runtime/primitive.h
index a429914d5c..5b163d8cbe 100644
--- a/runtime/primitive.h
+++ b/runtime/primitive.h
@@ -19,7 +19,8 @@
#include <sys/types.h>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/macros.h"
namespace art {
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index f94923e065..3a7640fa8b 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -19,8 +19,9 @@
#include "arch/context.h"
#include "art_method-inl.h"
#include "base/enums.h"
-#include "dex_file_types.h"
-#include "dex_instruction.h"
+#include "base/logging.h" // For VLOG_IS_ON.
+#include "dex/dex_file_types.h"
+#include "dex/dex_instruction.h"
#include "entrypoints/entrypoint_utils.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "entrypoints/runtime_asm_entrypoints.h"
@@ -221,7 +222,8 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor*
self_->DumpStack(LOG_STREAM(INFO) << "Setting catch phis: ");
}
- const size_t number_of_vregs = handler_method_->GetCodeItem()->registers_size_;
+ CodeItemDataAccessor accessor(handler_method_);
+ const size_t number_of_vregs = accessor.RegistersSize();
CodeInfo code_info = handler_method_header_->GetOptimizedCodeInfo();
CodeInfoEncoding encoding = code_info.ExtractEncoding();
@@ -358,7 +360,8 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor {
const size_t frame_id = GetFrameId();
ShadowFrame* new_frame = GetThread()->FindDebuggerShadowFrame(frame_id);
const bool* updated_vregs;
- const size_t num_regs = method->GetCodeItem()->registers_size_;
+ CodeItemDataAccessor accessor(method);
+ const size_t num_regs = accessor.RegistersSize();
if (new_frame == nullptr) {
new_frame = ShadowFrame::CreateDeoptimizedFrame(num_regs, nullptr, method, GetDexPc());
updated_vregs = nullptr;
@@ -405,7 +408,8 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor {
uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc());
CodeInfoEncoding encoding = code_info.ExtractEncoding();
StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
- const size_t number_of_vregs = m->GetCodeItem()->registers_size_;
+ CodeItemDataAccessor accessor(m);
+ const size_t number_of_vregs = accessor.RegistersSize();
uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, stack_map);
BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map);
DexRegisterMap vreg_map = IsInInlinedFrame()
diff --git a/runtime/quick_exception_handler.h b/runtime/quick_exception_handler.h
index 12b63c933d..1103dab52c 100644
--- a/runtime/quick_exception_handler.h
+++ b/runtime/quick_exception_handler.h
@@ -17,7 +17,8 @@
#ifndef ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
#define ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/macros.h"
#include "base/mutex.h"
#include "deoptimization_kind.h"
diff --git a/runtime/quicken_info.h b/runtime/quicken_info.h
index 5b72468fcd..ce11f3c19b 100644
--- a/runtime/quicken_info.h
+++ b/runtime/quicken_info.h
@@ -17,7 +17,7 @@
#ifndef ART_RUNTIME_QUICKEN_INFO_H_
#define ART_RUNTIME_QUICKEN_INFO_H_
-#include "dex_instruction.h"
+#include "dex/dex_instruction.h"
namespace art {
diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h
index 642459924e..a77d100b92 100644
--- a/runtime/read_barrier-inl.h
+++ b/runtime/read_barrier-inl.h
@@ -131,7 +131,7 @@ inline MirrorType* ReadBarrier::BarrierForRoot(MirrorType** root,
// Update the field atomically. This may fail if mutator updates before us, but it's ok.
if (ref != old_ref) {
Atomic<mirror::Object*>* atomic_root = reinterpret_cast<Atomic<mirror::Object*>*>(root);
- atomic_root->CompareExchangeStrongRelaxed(old_ref, ref);
+ atomic_root->CompareAndSetStrongRelaxed(old_ref, ref);
}
}
AssertToSpaceInvariant(gc_root_source, ref);
@@ -174,7 +174,7 @@ inline MirrorType* ReadBarrier::BarrierForRoot(mirror::CompressedReference<Mirro
if (new_ref.AsMirrorPtr() != old_ref.AsMirrorPtr()) {
auto* atomic_root =
reinterpret_cast<Atomic<mirror::CompressedReference<MirrorType>>*>(root);
- atomic_root->CompareExchangeStrongRelaxed(old_ref, new_ref);
+ atomic_root->CompareAndSetStrongRelaxed(old_ref, new_ref);
}
}
AssertToSpaceInvariant(gc_root_source, ref);
diff --git a/runtime/read_barrier.h b/runtime/read_barrier.h
index d4b9f4311f..e8df2ad4ce 100644
--- a/runtime/read_barrier.h
+++ b/runtime/read_barrier.h
@@ -17,9 +17,11 @@
#ifndef ART_RUNTIME_READ_BARRIER_H_
#define ART_RUNTIME_READ_BARRIER_H_
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/macros.h"
#include "base/mutex.h"
+#include "base/runtime_debug.h"
#include "gc_root.h"
#include "jni.h"
#include "mirror/object_reference.h"
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 9683cedd4d..635a03afe0 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -21,7 +21,7 @@
#include "base/enums.h"
#include "class_linker.h"
#include "common_throws.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "indirect_reference_table-inl.h"
#include "java_vm_ext.h"
#include "jni_internal.h"
@@ -447,7 +447,7 @@ static void InvokeWithArgArray(const ScopedObjectAccessAlreadyRunnable& soa,
const char* shorty)
REQUIRES_SHARED(Locks::mutator_lock_) {
uint32_t* args = arg_array->GetArray();
- if (UNLIKELY(soa.Env()->check_jni)) {
+ if (UNLIKELY(soa.Env()->IsCheckJniEnabled())) {
CheckMethodArguments(soa.Vm(), method->GetInterfaceMethodIfProxy(kRuntimePointerSize), args);
}
method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, shorty);
@@ -927,14 +927,14 @@ void UpdateReference(Thread* self, jobject obj, ObjPtr<mirror::Object> result) {
IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
IndirectRefKind kind = IndirectReferenceTable::GetIndirectRefKind(ref);
if (kind == kLocal) {
- self->GetJniEnv()->locals.Update(obj, result);
+ self->GetJniEnv()->UpdateLocal(obj, result);
} else if (kind == kHandleScopeOrInvalid) {
LOG(FATAL) << "Unsupported UpdateReference for kind kHandleScopeOrInvalid";
} else if (kind == kGlobal) {
- self->GetJniEnv()->vm->UpdateGlobal(self, ref, result);
+ self->GetJniEnv()->GetVm()->UpdateGlobal(self, ref, result);
} else {
DCHECK_EQ(kind, kWeakGlobal);
- self->GetJniEnv()->vm->UpdateWeakGlobal(self, ref, result);
+ self->GetJniEnv()->GetVm()->UpdateWeakGlobal(self, ref, result);
}
}
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index f09b6c9825..2f45b100d7 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -57,6 +57,7 @@
#include "asm_support.h"
#include "asm_support_check.h"
#include "atomic.h"
+#include "base/aborting.h"
#include "base/arena_allocator.h"
#include "base/dumpable.h"
#include "base/enums.h"
@@ -68,7 +69,7 @@
#include "class_linker-inl.h"
#include "compiler_callbacks.h"
#include "debugger.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file_loader.h"
#include "elf_file.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "experimental_flags.h"
@@ -256,6 +257,7 @@ Runtime::Runtime()
force_native_bridge_(false),
is_native_bridge_loaded_(false),
is_native_debuggable_(false),
+ async_exceptions_thrown_(false),
is_java_debuggable_(false),
zygote_max_failed_boots_(0),
experimental_flags_(ExperimentalFlags::kNone),
@@ -288,13 +290,19 @@ Runtime::~Runtime() {
Thread* self = Thread::Current();
const bool attach_shutdown_thread = self == nullptr;
if (attach_shutdown_thread) {
- CHECK(AttachCurrentThread("Shutdown thread", false, nullptr, false));
+ // We can only create a peer if the runtime is actually started. This is only not true during
+ // some tests.
+ CHECK(AttachCurrentThread("Shutdown thread",
+ false,
+ GetSystemThreadGroup(),
+ /* Create peer */IsStarted()));
self = Thread::Current();
} else {
LOG(WARNING) << "Current thread not detached in Runtime shutdown";
}
if (dump_gc_performance_on_shutdown_) {
+ ScopedLogSeverity sls(LogSeverity::INFO);
// This can't be called from the Heap destructor below because it
// could call RosAlloc::InspectAll() which needs the thread_list
// to be still alive.
@@ -352,7 +360,7 @@ Runtime::~Runtime() {
}
// Make sure our internal threads are dead before we start tearing down things they're using.
- Dbg::StopJdwp();
+ GetRuntimeCallbacks()->StopDebugger();
delete signal_catcher_;
// Make sure all other non-daemon threads have terminated, and all daemon threads are suspended.
@@ -363,7 +371,7 @@ Runtime::~Runtime() {
// TODO Maybe do some locking.
for (auto& agent : agents_) {
- agent.Unload();
+ agent->Unload();
}
// TODO Maybe do some locking
@@ -804,7 +812,7 @@ bool Runtime::Start() {
{
ScopedObjectAccess soa(self);
- self->GetJniEnv()->locals.AssertEmpty();
+ self->GetJniEnv()->AssertLocalsEmpty();
}
VLOG(startup) << "Runtime::Start exiting";
@@ -868,8 +876,10 @@ void Runtime::InitNonZygoteOrPostFork(
StartSignalCatcher();
// Start the JDWP thread. If the command-line debugger flags specified "suspend=y",
- // this will pause the runtime, so we probably want this to come last.
- Dbg::StartJdwp();
+ // this will pause the runtime (in the internal debugger implementation), so we probably want
+ // this to come last.
+ ScopedObjectAccess soa(Thread::Current());
+ GetRuntimeCallbacks()->StartDebugger();
}
void Runtime::StartSignalCatcher() {
@@ -1161,7 +1171,7 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
madvise_random_access_ = runtime_options.GetOrDefault(Opt::MadviseRandomAccess);
plugins_ = runtime_options.ReleaseOrDefault(Opt::Plugins);
- agents_ = runtime_options.ReleaseOrDefault(Opt::AgentPath);
+ agent_specs_ = runtime_options.ReleaseOrDefault(Opt::AgentPath);
// TODO Add back in -agentlib
// for (auto lib : runtime_options.ReleaseOrDefault(Opt::AgentLib)) {
// agents_.push_back(lib);
@@ -1218,8 +1228,29 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
dump_gc_performance_on_shutdown_ = runtime_options.Exists(Opt::DumpGCPerformanceOnShutdown);
- if (runtime_options.Exists(Opt::JdwpOptions)) {
- Dbg::ConfigureJdwp(runtime_options.GetOrDefault(Opt::JdwpOptions));
+ jdwp_options_ = runtime_options.GetOrDefault(Opt::JdwpOptions);
+ jdwp_provider_ = runtime_options.GetOrDefault(Opt::JdwpProvider);
+ switch (jdwp_provider_) {
+ case JdwpProvider::kNone: {
+ LOG(WARNING) << "Disabling all JDWP support.";
+ break;
+ }
+ case JdwpProvider::kInternal: {
+ if (runtime_options.Exists(Opt::JdwpOptions)) {
+ JDWP::JdwpOptions ops;
+ if (!JDWP::ParseJdwpOptions(runtime_options.GetOrDefault(Opt::JdwpOptions), &ops)) {
+ LOG(ERROR) << "failed to parse jdwp options!";
+ return false;
+ }
+ Dbg::ConfigureJdwp(ops);
+ }
+ break;
+ }
+ case JdwpProvider::kAdbConnection: {
+ constexpr const char* plugin_name = kIsDebugBuild ? "libadbconnectiond.so"
+ : "libadbconnection.so";
+ plugins_.push_back(Plugin::Create(plugin_name));
+ }
}
callbacks_->AddThreadLifecycleCallback(Dbg::GetThreadLifecycleCallback());
callbacks_->AddClassLoadCallback(Dbg::GetClassLoadCallback());
@@ -1472,16 +1503,32 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
// Startup agents
// TODO Maybe we should start a new thread to run these on. Investigate RI behavior more.
- for (auto& agent : agents_) {
+ for (auto& agent_spec : agent_specs_) {
// TODO Check err
int res = 0;
std::string err = "";
- ti::Agent::LoadError result = agent.Load(&res, &err);
- if (result == ti::Agent::kInitializationError) {
- LOG(FATAL) << "Unable to initialize agent!";
- } else if (result != ti::Agent::kNoError) {
- LOG(ERROR) << "Unable to load an agent: " << err;
+ ti::LoadError error;
+ std::unique_ptr<ti::Agent> agent = agent_spec.Load(&res, &error, &err);
+
+ if (agent != nullptr) {
+ agents_.push_back(std::move(agent));
+ continue;
+ }
+
+ switch (error) {
+ case ti::LoadError::kInitializationError:
+ LOG(FATAL) << "Unable to initialize agent!";
+ UNREACHABLE();
+
+ case ti::LoadError::kLoadingError:
+ LOG(ERROR) << "Unable to load an agent: " << err;
+ continue;
+
+ case ti::LoadError::kNoError:
+ break;
}
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
}
{
ScopedObjectAccess soa(self);
@@ -1506,6 +1553,7 @@ static bool EnsureJvmtiPlugin(Runtime* runtime,
}
// Is the process debuggable? Otherwise, do not attempt to load the plugin.
+ // TODO Support a crimped jvmti for non-debuggable runtimes.
if (!runtime->IsJavaDebuggable()) {
*error_msg = "Process is not debuggable.";
return false;
@@ -1527,7 +1575,7 @@ static bool EnsureJvmtiPlugin(Runtime* runtime,
// revisit this and make sure we're doing this on the right thread
// (and we synchronize access to any shared data structures like "agents_")
//
-void Runtime::AttachAgent(const std::string& agent_arg) {
+void Runtime::AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader) {
std::string error_msg;
if (!EnsureJvmtiPlugin(this, &plugins_, &error_msg)) {
LOG(WARNING) << "Could not load plugin: " << error_msg;
@@ -1536,15 +1584,16 @@ void Runtime::AttachAgent(const std::string& agent_arg) {
return;
}
- ti::Agent agent(agent_arg);
+ ti::AgentSpec agent_spec(agent_arg);
int res = 0;
- ti::Agent::LoadError result = agent.Attach(&res, &error_msg);
+ ti::LoadError error;
+ std::unique_ptr<ti::Agent> agent = agent_spec.Attach(env, class_loader, &res, &error, &error_msg);
- if (result == ti::Agent::kNoError) {
+ if (agent != nullptr) {
agents_.push_back(std::move(agent));
} else {
- LOG(WARNING) << "Agent attach failed (result=" << result << ") : " << error_msg;
+ LOG(WARNING) << "Agent attach failed (result=" << error << ") : " << error_msg;
ScopedObjectAccess soa(Thread::Current());
ThrowIOException("%s", error_msg.c_str());
}
@@ -1570,7 +1619,7 @@ void Runtime::InitNativeMethods() {
// libcore can't because it's the library that implements System.loadLibrary!
{
std::string error_msg;
- if (!java_vm_->LoadNativeLibrary(env, "libjavacore.so", nullptr, nullptr, &error_msg)) {
+ if (!java_vm_->LoadNativeLibrary(env, "libjavacore.so", nullptr, &error_msg)) {
LOG(FATAL) << "LoadNativeLibrary failed for \"libjavacore.so\": " << error_msg;
}
}
@@ -1579,7 +1628,7 @@ void Runtime::InitNativeMethods() {
? "libopenjdkd.so"
: "libopenjdk.so";
std::string error_msg;
- if (!java_vm_->LoadNativeLibrary(env, kOpenJdkLibrary, nullptr, nullptr, &error_msg)) {
+ if (!java_vm_->LoadNativeLibrary(env, kOpenJdkLibrary, nullptr, &error_msg)) {
LOG(FATAL) << "LoadNativeLibrary failed for \"" << kOpenJdkLibrary << "\": " << error_msg;
}
}
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 6b01cc220f..c8edabce09 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -31,10 +31,11 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "deoptimization_kind.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "experimental_flags.h"
#include "gc_root.h"
#include "instrumentation.h"
+#include "jdwp_provider.h"
#include "obj_ptr.h"
#include "offsets.h"
#include "process_state.h"
@@ -65,6 +66,7 @@ class Throwable;
} // namespace mirror
namespace ti {
class Agent;
+class AgentSpec;
} // namespace ti
namespace verifier {
class MethodVerifier;
@@ -586,6 +588,14 @@ class Runtime {
is_native_debuggable_ = value;
}
+ bool AreAsyncExceptionsThrown() const {
+ return async_exceptions_thrown_;
+ }
+
+ void SetAsyncExceptionsThrown() {
+ async_exceptions_thrown_ = true;
+ }
+
// Returns the build fingerprint, if set. Otherwise an empty string is returned.
std::string GetFingerprint() {
return fingerprint_;
@@ -651,9 +661,9 @@ class Runtime {
void AddSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
void RemoveSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
- void AttachAgent(const std::string& agent_arg);
+ void AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader);
- const std::list<ti::Agent>& GetAgents() const {
+ const std::list<std::unique_ptr<ti::Agent>>& GetAgents() const {
return agents_;
}
@@ -688,6 +698,14 @@ class Runtime {
return madvise_random_access_;
}
+ const std::string& GetJdwpOptions() {
+ return jdwp_options_;
+ }
+
+ JdwpProvider GetJdwpProvider() const {
+ return jdwp_provider_;
+ }
+
private:
static void InitPlatformSignalHandlers();
@@ -762,7 +780,8 @@ class Runtime {
std::string class_path_string_;
std::vector<std::string> properties_;
- std::list<ti::Agent> agents_;
+ std::list<ti::AgentSpec> agent_specs_;
+ std::list<std::unique_ptr<ti::Agent>> agents_;
std::vector<Plugin> plugins_;
// The default stack size for managed threads created by the runtime.
@@ -899,6 +918,10 @@ class Runtime {
// Whether we are running under native debugger.
bool is_native_debuggable_;
+ // whether or not any async exceptions have ever been thrown. This is used to speed up the
+ // MterpShouldSwitchInterpreters function.
+ bool async_exceptions_thrown_;
+
// Whether Java code needs to be debuggable.
bool is_java_debuggable_;
@@ -941,6 +964,12 @@ class Runtime {
// Whether zygote code is in a section that should not start threads.
bool zygote_no_threads_;
+ // The string containing requested jdwp options
+ std::string jdwp_options_;
+
+ // The jdwp provider we were configured with.
+ JdwpProvider jdwp_provider_;
+
// Saved environment.
class EnvSnapshot {
public:
diff --git a/runtime/runtime_callbacks.cc b/runtime/runtime_callbacks.cc
index 40d7889565..cd3c0b7c88 100644
--- a/runtime/runtime_callbacks.cc
+++ b/runtime/runtime_callbacks.cc
@@ -49,6 +49,35 @@ void RuntimeCallbacks::DdmPublishChunk(uint32_t type, const ArrayRef<const uint8
}
}
+void RuntimeCallbacks::AddDebuggerControlCallback(DebuggerControlCallback* cb) {
+ debugger_control_callbacks_.push_back(cb);
+}
+
+void RuntimeCallbacks::RemoveDebuggerControlCallback(DebuggerControlCallback* cb) {
+ Remove(cb, &debugger_control_callbacks_);
+}
+
+bool RuntimeCallbacks::IsDebuggerConfigured() {
+ for (DebuggerControlCallback* cb : debugger_control_callbacks_) {
+ if (cb->IsDebuggerConfigured()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void RuntimeCallbacks::StartDebugger() {
+ for (DebuggerControlCallback* cb : debugger_control_callbacks_) {
+ cb->StartDebugger();
+ }
+}
+
+void RuntimeCallbacks::StopDebugger() {
+ for (DebuggerControlCallback* cb : debugger_control_callbacks_) {
+ cb->StopDebugger();
+ }
+}
+
void RuntimeCallbacks::AddMethodInspectionCallback(MethodInspectionCallback* cb) {
method_inspection_callbacks_.push_back(cb);
}
diff --git a/runtime/runtime_callbacks.h b/runtime/runtime_callbacks.h
index baf941a8e1..24386ba14a 100644
--- a/runtime/runtime_callbacks.h
+++ b/runtime/runtime_callbacks.h
@@ -22,7 +22,7 @@
#include "base/array_ref.h"
#include "base/macros.h"
#include "base/mutex.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "handle.h"
namespace art {
@@ -62,6 +62,19 @@ class DdmCallback {
REQUIRES_SHARED(Locks::mutator_lock_) = 0;
};
+class DebuggerControlCallback {
+ public:
+ virtual ~DebuggerControlCallback() {}
+
+ // Begin running the debugger.
+ virtual void StartDebugger() = 0;
+ // The debugger should begin shutting down since the runtime is ending. This is just advisory
+ virtual void StopDebugger() = 0;
+
+ // This allows the debugger to tell the runtime if it is configured.
+ virtual bool IsDebuggerConfigured() = 0;
+};
+
class RuntimeSigQuitCallback {
public:
virtual ~RuntimeSigQuitCallback() {}
@@ -197,6 +210,17 @@ class RuntimeCallbacks {
void AddDdmCallback(DdmCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_);
void RemoveDdmCallback(DdmCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_);
+ void StartDebugger() REQUIRES_SHARED(Locks::mutator_lock_);
+ // NO_THREAD_SAFETY_ANALYSIS since this is only called when we are in the middle of shutting down
+ // and the mutator_lock_ is no longer acquirable.
+ void StopDebugger() NO_THREAD_SAFETY_ANALYSIS;
+ bool IsDebuggerConfigured() REQUIRES_SHARED(Locks::mutator_lock_);
+
+ void AddDebuggerControlCallback(DebuggerControlCallback* cb)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ void RemoveDebuggerControlCallback(DebuggerControlCallback* cb)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
std::vector<ThreadLifecycleCallback*> thread_callbacks_
GUARDED_BY(Locks::mutator_lock_);
@@ -214,6 +238,8 @@ class RuntimeCallbacks {
GUARDED_BY(Locks::mutator_lock_);
std::vector<DdmCallback*> ddm_callbacks_
GUARDED_BY(Locks::mutator_lock_);
+ std::vector<DebuggerControlCallback*> debugger_control_callbacks_
+ GUARDED_BY(Locks::mutator_lock_);
};
} // namespace art
diff --git a/runtime/runtime_common.cc b/runtime/runtime_common.cc
index eb69d91dad..59af9187f9 100644
--- a/runtime/runtime_common.cc
+++ b/runtime/runtime_common.cc
@@ -23,10 +23,12 @@
#include <sstream>
#include <string>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include "base/aborting.h"
#include "base/file_utils.h"
-#include "base/logging.h"
+#include "base/logging.h" // For LogHelper, GetCmdLine.
#include "base/macros.h"
#include "base/mutex.h"
#include "native_stack_dump.h"
@@ -430,7 +432,7 @@ void HandleUnexpectedSignalCommon(int signal_number,
logger(LOG_STREAM(FATAL_WITHOUT_ABORT));
}
if (kIsDebugBuild && signal_number == SIGSEGV) {
- PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT);
+ PrintFileToLog("/proc/self/maps", android::base::LogSeverity::FATAL_WITHOUT_ABORT);
}
Runtime* runtime = Runtime::Current();
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 2e03562505..1dd3de5039 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -43,7 +43,8 @@ RUNTIME_OPTIONS_KEY (std::string, ClassPath)
RUNTIME_OPTIONS_KEY (std::string, Image)
RUNTIME_OPTIONS_KEY (Unit, CheckJni)
RUNTIME_OPTIONS_KEY (Unit, JniOptsForceCopy)
-RUNTIME_OPTIONS_KEY (JDWP::JdwpOptions, JdwpOptions)
+RUNTIME_OPTIONS_KEY (std::string, JdwpOptions, "")
+RUNTIME_OPTIONS_KEY (JdwpProvider, JdwpProvider, JdwpProvider::kInternal)
RUNTIME_OPTIONS_KEY (MemoryKiB, MemoryMaximumSize, gc::Heap::kDefaultMaximumSize) // -Xmx
RUNTIME_OPTIONS_KEY (MemoryKiB, MemoryInitialSize, gc::Heap::kDefaultInitialSize) // -Xms
RUNTIME_OPTIONS_KEY (MemoryKiB, HeapGrowthLimit) // Default is 0 for unlimited
@@ -123,8 +124,8 @@ RUNTIME_OPTIONS_KEY (Unit, NoDexFileFallback)
RUNTIME_OPTIONS_KEY (std::string, CpuAbiList)
RUNTIME_OPTIONS_KEY (std::string, Fingerprint)
RUNTIME_OPTIONS_KEY (ExperimentalFlags, Experimental, ExperimentalFlags::kNone) // -Xexperimental:{...}
-RUNTIME_OPTIONS_KEY (std::list<ti::Agent>, AgentLib) // -agentlib:<libname>=<options>
-RUNTIME_OPTIONS_KEY (std::list<ti::Agent>, AgentPath) // -agentpath:<libname>=<options>
+RUNTIME_OPTIONS_KEY (std::list<ti::AgentSpec>, AgentLib) // -agentlib:<libname>=<options>
+RUNTIME_OPTIONS_KEY (std::list<ti::AgentSpec>, AgentPath) // -agentpath:<libname>=<options>
RUNTIME_OPTIONS_KEY (std::vector<Plugin>, Plugins) // -Xplugin:<library>
// Not parse-able from command line, but can be provided explicitly.
diff --git a/runtime/safe_map.h b/runtime/safe_map.h
index f29869172e..33e45bdbd8 100644
--- a/runtime/safe_map.h
+++ b/runtime/safe_map.h
@@ -21,8 +21,9 @@
#include <memory>
#include <type_traits>
+#include <android-base/logging.h>
+
#include "base/allocator.h"
-#include "base/logging.h"
namespace art {
diff --git a/runtime/scoped_thread_state_change-inl.h b/runtime/scoped_thread_state_change-inl.h
index aa96871145..f95593209b 100644
--- a/runtime/scoped_thread_state_change-inl.h
+++ b/runtime/scoped_thread_state_change-inl.h
@@ -19,6 +19,8 @@
#include "scoped_thread_state_change.h"
+#include <android-base/logging.h>
+
#include "base/casts.h"
#include "jni_env_ext-inl.h"
#include "obj_ptr-inl.h"
@@ -95,12 +97,12 @@ inline bool ScopedObjectAccessAlreadyRunnable::IsRunnable() const {
}
inline ScopedObjectAccessAlreadyRunnable::ScopedObjectAccessAlreadyRunnable(JNIEnv* env)
- : self_(ThreadForEnv(env)), env_(down_cast<JNIEnvExt*>(env)), vm_(env_->vm) {}
+ : self_(ThreadForEnv(env)), env_(down_cast<JNIEnvExt*>(env)), vm_(env_->GetVm()) {}
inline ScopedObjectAccessAlreadyRunnable::ScopedObjectAccessAlreadyRunnable(Thread* self)
: self_(self),
env_(down_cast<JNIEnvExt*>(self->GetJniEnv())),
- vm_(env_ != nullptr ? env_->vm : nullptr) {}
+ vm_(env_ != nullptr ? env_->GetVm() : nullptr) {}
inline ScopedObjectAccessUnchecked::ScopedObjectAccessUnchecked(JNIEnv* env)
: ScopedObjectAccessAlreadyRunnable(env), tsc_(Self(), kRunnable) {
diff --git a/runtime/scoped_thread_state_change.cc b/runtime/scoped_thread_state_change.cc
index 94354fc586..6a86cc6411 100644
--- a/runtime/scoped_thread_state_change.cc
+++ b/runtime/scoped_thread_state_change.cc
@@ -19,7 +19,6 @@
#include <type_traits>
#include "base/casts.h"
-#include "base/logging.h"
#include "java_vm_ext.h"
#include "obj_ptr-inl.h"
#include "runtime-inl.h"
diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h
index 02b6124118..0c42c5ae8d 100644
--- a/runtime/scoped_thread_state_change.h
+++ b/runtime/scoped_thread_state_change.h
@@ -27,7 +27,7 @@
namespace art {
class JavaVMExt;
-struct JNIEnvExt;
+class JNIEnvExt;
template<class MirrorType> class ObjPtr;
class Thread;
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index bf5d718113..d9c4da9b96 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -35,6 +35,7 @@
#include "arch/instruction_set.h"
#include "base/file_utils.h"
+#include "base/logging.h" // For GetCmdLine.
#include "base/time_utils.h"
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
diff --git a/runtime/signal_set.h b/runtime/signal_set.h
index 6f888525cb..53613236fa 100644
--- a/runtime/signal_set.h
+++ b/runtime/signal_set.h
@@ -19,7 +19,7 @@
#include <signal.h>
-#include "base/logging.h"
+#include <android-base/logging.h>
namespace art {
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 5ad1f7c9c5..dfdea28ae8 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -23,7 +23,7 @@
#include "base/callee_save_type.h"
#include "base/enums.h"
#include "base/hex_dump.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/space/image_space.h"
@@ -154,13 +154,13 @@ mirror::Object* StackVisitor::GetThisObject() const {
return cur_shadow_frame_->GetVRegReference(0);
}
} else {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(m);
+ if (!accessor.HasCodeItem()) {
UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method: "
<< ArtMethod::PrettyMethod(m);
return nullptr;
} else {
- uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
+ uint16_t reg = accessor.RegistersSize() - accessor.InsSize();
uint32_t value = 0;
bool success = GetVReg(m, reg, kReferenceVReg, &value);
// We currently always guarantee the `this` object is live throughout the method.
@@ -223,11 +223,11 @@ bool StackVisitor::GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t*
bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind,
uint32_t* val) const {
DCHECK_EQ(m, GetMethod());
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- DCHECK(code_item != nullptr) << m->PrettyMethod(); // Can't be null or how would we compile
- // its instructions?
- uint16_t number_of_dex_registers = code_item->registers_size_;
- DCHECK_LT(vreg, code_item->registers_size_);
+ // Can't be null or how would we compile its instructions?
+ DCHECK(m->GetCodeItem() != nullptr) << m->PrettyMethod();
+ CodeItemDataAccessor accessor(m);
+ uint16_t number_of_dex_registers = accessor.RegistersSize();
+ DCHECK_LT(vreg, number_of_dex_registers);
const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
CodeInfo code_info = method_header->GetOptimizedCodeInfo();
CodeInfoEncoding encoding = code_info.ExtractEncoding();
@@ -395,8 +395,8 @@ bool StackVisitor::SetVReg(ArtMethod* m,
uint16_t vreg,
uint32_t new_value,
VRegKind kind) {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(m);
+ if (!accessor.HasCodeItem()) {
return false;
}
ShadowFrame* shadow_frame = GetCurrentShadowFrame();
@@ -404,7 +404,7 @@ bool StackVisitor::SetVReg(ArtMethod* m,
// This is a compiled frame: we must prepare and update a shadow frame that will
// be executed by the interpreter after deoptimization of the stack.
const size_t frame_id = GetFrameId();
- const uint16_t num_regs = code_item->registers_size_;
+ const uint16_t num_regs = accessor.RegistersSize();
shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc());
CHECK(shadow_frame != nullptr);
// Remember the vreg has been set for debugging and must not be overwritten by the
@@ -432,15 +432,15 @@ bool StackVisitor::SetVRegPair(ArtMethod* m,
LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi;
UNREACHABLE();
}
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(m);
+ if (!accessor.HasCodeItem()) {
return false;
}
ShadowFrame* shadow_frame = GetCurrentShadowFrame();
if (shadow_frame == nullptr) {
// This is a compiled frame: we must prepare for deoptimization (see SetVRegFromDebugger).
const size_t frame_id = GetFrameId();
- const uint16_t num_regs = code_item->registers_size_;
+ const uint16_t num_regs = accessor.RegistersSize();
shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc());
CHECK(shadow_frame != nullptr);
// Remember the vreg pair has been set for debugging and must not be overwritten by the
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 85c734ee4c..62fb54fb56 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -23,8 +23,8 @@
#include "base/bit_utils.h"
#include "base/bit_vector.h"
#include "bit_memory_region.h"
+#include "dex/dex_file_types.h"
#include "leb128.h"
-#include "dex_file_types.h"
#include "memory_region.h"
#include "method_info.h"
diff --git a/runtime/stride_iterator.h b/runtime/stride_iterator.h
index 0560c33eee..511c2c66f2 100644
--- a/runtime/stride_iterator.h
+++ b/runtime/stride_iterator.h
@@ -19,7 +19,7 @@
#include <iterator>
-#include "base/logging.h"
+#include <android-base/logging.h>
namespace art {
diff --git a/runtime/string_reference.h b/runtime/string_reference.h
index d0ab4e40d0..97661c6019 100644
--- a/runtime/string_reference.h
+++ b/runtime/string_reference.h
@@ -19,10 +19,11 @@
#include <stdint.h>
-#include "base/logging.h"
-#include "dex_file-inl.h"
-#include "dex_file_reference.h"
-#include "dex_file_types.h"
+#include <android-base/logging.h>
+
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_reference.h"
+#include "dex/dex_file_types.h"
#include "utf-inl.h"
namespace art {
diff --git a/runtime/subtype_check.h b/runtime/subtype_check.h
index 1556abe67f..54d2f00106 100644
--- a/runtime/subtype_check.h
+++ b/runtime/subtype_check.h
@@ -216,12 +216,13 @@
* All node targets (in `src <: target`) get Assigned, and any parent of an Initialized
* node also gets Assigned.
*/
-struct MockSubtypeCheck; // Forward declaration for testing.
namespace art {
-// This is class is using a template parameter to enable testability without losing performance.
-// KlassT is almost always `mirror::Class*` or `ObjPtr<mirror::Class>`.
-template <typename KlassT /* Pointer-like type to Class */>
+struct MockSubtypeCheck; // Forward declaration for testing.
+
+// This class is using a template parameter to enable testability without losing performance.
+// ClassPtr is almost always `mirror::Class*` or `ObjPtr<mirror::Class>`.
+template <typename ClassPtr /* Pointer-like type to Class */>
struct SubtypeCheck {
// Force this class's SubtypeCheckInfo state into at least Initialized.
// As a side-effect, all parent classes also become Assigned|Overflowed.
@@ -230,7 +231,7 @@ struct SubtypeCheck {
//
// Post-condition: State is >= Initialized.
// Returns: The precise SubtypeCheckInfo::State.
- static SubtypeCheckInfo::State EnsureInitialized(KlassT& klass)
+ static SubtypeCheckInfo::State EnsureInitialized(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
return InitializeOrAssign(klass, /*assign*/false).GetState();
@@ -243,7 +244,7 @@ struct SubtypeCheck {
//
// Post-condition: State is Assigned|Overflowed.
// Returns: The precise SubtypeCheckInfo::State.
- static SubtypeCheckInfo::State EnsureAssigned(KlassT& klass)
+ static SubtypeCheckInfo::State EnsureAssigned(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
return InitializeOrAssign(klass, /*assign*/true).GetState();
@@ -258,7 +259,7 @@ struct SubtypeCheck {
// Cost: O(1).
//
// Returns: A state that is always Uninitialized.
- static SubtypeCheckInfo::State ForceUninitialize(KlassT& klass)
+ static SubtypeCheckInfo::State ForceUninitialize(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Trying to do this in a real runtime will break thread safety invariants
@@ -288,7 +289,7 @@ struct SubtypeCheck {
// Cost: O(Depth(Class)).
//
// Returns the encoded_src value. Must be >= Initialized (EnsureInitialized).
- static BitString::StorageType GetEncodedPathToRootForSource(const KlassT& klass)
+ static BitString::StorageType GetEncodedPathToRootForSource(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_NE(SubtypeCheckInfo::kUninitialized, GetSubtypeCheckInfo(klass).GetState());
@@ -301,7 +302,7 @@ struct SubtypeCheck {
// Cost: O(Depth(Class)).
//
// Returns the encoded_target value. Must be Assigned (EnsureAssigned).
- static BitString::StorageType GetEncodedPathToRootForTarget(const KlassT& klass)
+ static BitString::StorageType GetEncodedPathToRootForTarget(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_EQ(SubtypeCheckInfo::kAssigned, GetSubtypeCheckInfo(klass).GetState());
@@ -314,7 +315,7 @@ struct SubtypeCheck {
// Cost: O(Depth(Class)).
//
// Returns the mask_target value. Must be Assigned (EnsureAssigned).
- static BitString::StorageType GetEncodedPathToRootMask(const KlassT& klass)
+ static BitString::StorageType GetEncodedPathToRootMask(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_EQ(SubtypeCheckInfo::kAssigned, GetSubtypeCheckInfo(klass).GetState());
@@ -333,7 +334,7 @@ struct SubtypeCheck {
// Runtime cost: O(Depth(Class)), but would be O(1) if depth was known.
//
// If the result is known, return kSubtypeOf or kNotSubtypeOf.
- static SubtypeCheckInfo::Result IsSubtypeOf(const KlassT& source, const KlassT& target)
+ static SubtypeCheckInfo::Result IsSubtypeOf(ClassPtr source, ClassPtr target)
REQUIRES_SHARED(Locks::mutator_lock_) {
SubtypeCheckInfo sci = GetSubtypeCheckInfo(source);
SubtypeCheckInfo target_sci = GetSubtypeCheckInfo(target);
@@ -342,24 +343,24 @@ struct SubtypeCheck {
}
// Print SubtypeCheck bitstring and overflow to a stream (e.g. for oatdump).
- static std::ostream& Dump(const KlassT& klass, std::ostream& os)
+ static std::ostream& Dump(ClassPtr klass, std::ostream& os)
REQUIRES_SHARED(Locks::mutator_lock_) {
return os << GetSubtypeCheckInfo(klass);
}
- static void WriteStatus(const KlassT& klass, ClassStatus status)
+ static void WriteStatus(ClassPtr klass, ClassStatus status)
REQUIRES_SHARED(Locks::mutator_lock_) {
WriteStatusImpl(klass, status);
}
private:
- static KlassT GetParentClass(const KlassT& klass)
+ static ClassPtr GetParentClass(ClassPtr klass)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(klass->HasSuperClass());
- return KlassT(klass->GetSuperClass());
+ return ClassPtr(klass->GetSuperClass());
}
- static SubtypeCheckInfo InitializeOrAssign(KlassT& klass, bool assign)
+ static SubtypeCheckInfo InitializeOrAssign(ClassPtr klass, bool assign)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (UNLIKELY(!klass->HasSuperClass())) {
@@ -380,8 +381,8 @@ struct SubtypeCheck {
}
// Force all ancestors to Assigned | Overflowed.
- KlassT parent_klass = GetParentClass(klass);
- EnsureAssigned(parent_klass);
+ ClassPtr parent_klass = GetParentClass(klass);
+ size_t parent_depth = InitializeOrAssign(parent_klass, /*assign*/true).GetDepth();
if (kIsDebugBuild) {
SubtypeCheckInfo::State parent_state = GetSubtypeCheckInfo(parent_klass).GetState();
DCHECK(parent_state == SubtypeCheckInfo::kAssigned ||
@@ -390,8 +391,8 @@ struct SubtypeCheck {
}
// Read.
- SubtypeCheckInfo sci = GetSubtypeCheckInfo(klass);
- SubtypeCheckInfo parent_sci = GetSubtypeCheckInfo(parent_klass);
+ SubtypeCheckInfo sci = GetSubtypeCheckInfo(klass, parent_depth + 1u);
+ SubtypeCheckInfo parent_sci = GetSubtypeCheckInfo(parent_klass, parent_depth);
// Modify.
const SubtypeCheckInfo::State sci_state = sci.GetState();
@@ -426,7 +427,7 @@ struct SubtypeCheck {
return sci;
}
- static SubtypeCheckBitsAndStatus ReadField(const KlassT& klass)
+ static SubtypeCheckBitsAndStatus ReadField(ClassPtr klass)
REQUIRES_SHARED(Locks::mutator_lock_) {
SubtypeCheckBitsAndStatus current_bits_and_status;
@@ -441,7 +442,7 @@ struct SubtypeCheck {
return current_bits_and_status;
}
- static void WriteSubtypeCheckBits(const KlassT& klass, const SubtypeCheckBits& new_bits)
+ static void WriteSubtypeCheckBits(ClassPtr klass, const SubtypeCheckBits& new_bits)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Use a "CAS" to write the SubtypeCheckBits in the class.
@@ -490,7 +491,7 @@ struct SubtypeCheck {
}
}
- static void WriteStatusImpl(const KlassT& klass, ClassStatus status)
+ static void WriteStatusImpl(ClassPtr klass, ClassStatus status)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Despite not having a lock annotation, this is done with mutual exclusion.
// See Class::SetStatus for more details.
@@ -519,7 +520,7 @@ struct SubtypeCheck {
}
}
- static bool CasFieldWeakSequentiallyConsistent32(const KlassT& klass,
+ static bool CasFieldWeakSequentiallyConsistent32(ClassPtr klass,
MemberOffset offset,
int32_t old_value,
int32_t new_value)
@@ -541,18 +542,23 @@ struct SubtypeCheck {
// it also requires calling klass->Depth.
//
// Anything calling this function will also be O(Depth(Class)).
- static SubtypeCheckInfo GetSubtypeCheckInfo(const KlassT& klass)
+ static SubtypeCheckInfo GetSubtypeCheckInfo(ClassPtr klass)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetSubtypeCheckInfo(klass, klass->Depth());
+ }
+
+ // Get the SubtypeCheckInfo for a klass with known depth.
+ static SubtypeCheckInfo GetSubtypeCheckInfo(ClassPtr klass, size_t depth)
REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK_EQ(depth, klass->Depth());
SubtypeCheckBitsAndStatus current_bits_and_status = ReadField(klass);
- size_t depth = klass->Depth();
const SubtypeCheckInfo current =
SubtypeCheckInfo::Create(current_bits_and_status.subtype_check_info_, depth);
return current;
}
- static void SetSubtypeCheckInfo(KlassT& klass,
- const SubtypeCheckInfo& new_sci)
+ static void SetSubtypeCheckInfo(ClassPtr klass, const SubtypeCheckInfo& new_sci)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
SubtypeCheckBits new_bits = new_sci.GetSubtypeCheckBits();
@@ -565,7 +571,7 @@ struct SubtypeCheck {
SubtypeCheck(SubtypeCheck&& other) = default;
~SubtypeCheck() = default;
- friend struct ::MockSubtypeCheck;
+ friend struct MockSubtypeCheck;
};
} // namespace art
diff --git a/runtime/subtype_check_info.h b/runtime/subtype_check_info.h
index cd579c3a5c..61d590bd59 100644
--- a/runtime/subtype_check_info.h
+++ b/runtime/subtype_check_info.h
@@ -90,10 +90,13 @@ namespace art {
*
* Uninitialized <=> StrLen(PathToRoot) == 0
* Next == 0
+ * OF == False
* Initialized <=> StrLen(PathToRoot) < Depth
- * Next == 0
+ * Next == 1
+ * OF == False
* Assigned <=> StrLen(PathToRoot) == Depth
- * Next > 1
+ * Next >= 1
+ * OF == False
* Overflowed <=> OF == True
*
* Tree Invariants:
@@ -135,6 +138,11 @@ struct SubtypeCheckInfo {
kSubtypeOf // Enough data. src is a subchild of the target.
};
+ // Get the raw depth.
+ size_t GetDepth() const {
+ return depth_;
+ }
+
// Chop off the depth, returning only the bitstring+of state.
// (Used to store into memory, since storing the depth would be redundant.)
SubtypeCheckBits GetSubtypeCheckBits() const {
@@ -219,7 +227,7 @@ struct SubtypeCheckInfo {
// Next must be non-0 to disambiguate it from Uninitialized.
child.MaybeInitNext();
- // Always clear the inherited Parent's next Value on the child.
+ // Always clear the inherited Parent's next Value, i.e. the child's last path entry.
OverwriteNextValueFromParent(/*inout*/&child, BitStringChar{});
// The state is now Initialized | Overflowed.
@@ -235,7 +243,6 @@ struct SubtypeCheckInfo {
// Assign attempt.
if (HasNext() && !bitstring_and_of_.overflow_) {
- // Do not bother assigning if parent had overflowed.
BitStringChar next = GetNext();
if (next != next.MaximumValue()) {
// The parent's "next" value is now the child's latest path element.
@@ -260,17 +267,16 @@ struct SubtypeCheckInfo {
// Get the current state (Uninitialized, Initialized, Assigned, or Overflowed).
// See the "SubtypeCheckInfo" documentation above which explains how a state is determined.
State GetState() const {
- if (GetBitString().IsEmpty()) {
- // Empty bitstring (all 0s) -> uninitialized.
- DCHECK(!bitstring_and_of_.overflow_);
- return kUninitialized;
- }
-
if (bitstring_and_of_.overflow_) {
// Overflowed if and only if the OF bit was set.
return kOverflowed;
}
+ if (GetBitString().IsEmpty()) {
+ // Empty bitstring (all 0s) -> uninitialized.
+ return kUninitialized;
+ }
+
// Either Assigned or Initialized.
BitString path_to_root = GetPathToRoot();
@@ -387,6 +393,7 @@ struct SubtypeCheckInfo {
SetBitStringUnchecked(bs);
}
+ // If there is a next field, set it to 1.
void MaybeInitNext() {
if (HasNext()) {
// Clearing out the "Next" value like this
diff --git a/runtime/subtype_check_test.cc b/runtime/subtype_check_test.cc
index dd51c18eff..e297d0beb4 100644
--- a/runtime/subtype_check_test.cc
+++ b/runtime/subtype_check_test.cc
@@ -24,10 +24,6 @@ namespace art {
constexpr size_t BitString::kBitSizeAtPosition[BitString::kCapacity];
constexpr size_t BitString::kCapacity;
-}; // namespace art
-
-using namespace art; // NOLINT
-
struct MockClass {
explicit MockClass(MockClass* parent, size_t x = 0, size_t y = 0) {
parent_ = parent;
@@ -1061,3 +1057,5 @@ TEST_F(SubtypeCheckTest, EnsureInitialized_TooWide_TooDeep) {
}
// TODO: add dcheck for child-parent invariants (e.g. child < parent.next) and death tests
+
+} // namespace art
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index b5a962691b..2f6f50e31e 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -19,6 +19,7 @@
#include "thread.h"
+#include "base/aborting.h"
#include "base/casts.h"
#include "base/mutex-inl.h"
#include "base/time_utils.h"
@@ -33,7 +34,7 @@ namespace art {
// Quickly access the current thread from a JNIEnv.
static inline Thread* ThreadForEnv(JNIEnv* env) {
JNIEnvExt* full_env(down_cast<JNIEnvExt*>(env));
- return full_env->self;
+ return full_env->GetSelf();
}
inline void Thread::AllowThreadSuspension() {
@@ -200,7 +201,7 @@ inline void Thread::TransitionToSuspendedAndRunCheckpoints(ThreadState new_state
// CAS the value with a memory ordering.
bool done =
- tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakRelease(old_state_and_flags.as_int,
+ tls32_.state_and_flags.as_atomic_int.CompareAndSetWeakRelease(old_state_and_flags.as_int,
new_state_and_flags.as_int);
if (LIKELY(done)) {
break;
@@ -251,7 +252,7 @@ inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
new_state_and_flags.as_int = old_state_and_flags.as_int;
new_state_and_flags.as_struct.state = kRunnable;
// CAS the value with a memory barrier.
- if (LIKELY(tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakAcquire(
+ if (LIKELY(tls32_.state_and_flags.as_atomic_int.CompareAndSetWeakAcquire(
old_state_and_flags.as_int,
new_state_and_flags.as_int))) {
// Mark the acquisition of a share of the mutator_lock_.
diff --git a/runtime/thread.cc b/runtime/thread.cc
index bec1c908ad..9f4e5441a5 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -47,9 +47,9 @@
#include "base/to_str.h"
#include "class_linker-inl.h"
#include "debugger.h"
-#include "dex_file-inl.h"
-#include "dex_file_annotations.h"
-#include "dex_file_types.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_annotations.h"
+#include "dex/dex_file_types.h"
#include "entrypoints/entrypoint_utils.h"
#include "entrypoints/quick/quick_alloc_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
@@ -70,6 +70,7 @@
#include "mirror/object_array-inl.h"
#include "mirror/stack_trace_element.h"
#include "monitor.h"
+#include "monitor_objects_stack_visitor.h"
#include "native_stack_dump.h"
#include "nativehelper/scoped_local_ref.h"
#include "nativehelper/scoped_utf_chars.h"
@@ -620,7 +621,7 @@ void Thread::InstallImplicitProtection() {
void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) {
CHECK(java_peer != nullptr);
- Thread* self = static_cast<JNIEnvExt*>(env)->self;
+ Thread* self = static_cast<JNIEnvExt*>(env)->GetSelf();
if (VLOG_IS_ON(threads)) {
ScopedObjectAccess soa(env);
@@ -753,8 +754,8 @@ bool Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm, JNIEnvExt* jni_en
tls32_.thin_lock_thread_id = thread_list->AllocThreadId(this);
if (jni_env_ext != nullptr) {
- DCHECK_EQ(jni_env_ext->vm, java_vm);
- DCHECK_EQ(jni_env_ext->self, this);
+ DCHECK_EQ(jni_env_ext->GetVm(), java_vm);
+ DCHECK_EQ(jni_env_ext->GetSelf(), this);
tlsPtr_.jni_env = jni_env_ext;
} else {
std::string error_msg;
@@ -773,14 +774,16 @@ template <typename PeerAction>
Thread* Thread::Attach(const char* thread_name, bool as_daemon, PeerAction peer_action) {
Runtime* runtime = Runtime::Current();
if (runtime == nullptr) {
- LOG(ERROR) << "Thread attaching to non-existent runtime: " << thread_name;
+ LOG(ERROR) << "Thread attaching to non-existent runtime: " <<
+ ((thread_name != nullptr) ? thread_name : "(Unnamed)");
return nullptr;
}
Thread* self;
{
MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
if (runtime->IsShuttingDownLocked()) {
- LOG(WARNING) << "Thread attaching while runtime is shutting down: " << thread_name;
+ LOG(WARNING) << "Thread attaching while runtime is shutting down: " <<
+ ((thread_name != nullptr) ? thread_name : "(Unnamed)");
return nullptr;
} else {
Runtime::Current()->StartThreadBirth();
@@ -850,7 +853,7 @@ Thread* Thread::Attach(const char* thread_name,
if (thread_name != nullptr) {
self->tlsPtr_.name->assign(thread_name);
::art::SetThreadName(thread_name);
- } else if (self->GetJniEnv()->check_jni) {
+ } else if (self->GetJniEnv()->IsCheckJniEnabled()) {
LOG(WARNING) << *Thread::Current() << " attached without supplying a name";
}
}
@@ -1275,7 +1278,7 @@ bool Thread::ModifySuspendCountInternal(Thread* self,
AtomicClearFlag(kSuspendRequest);
} else {
// Two bits might be set simultaneously.
- tls32_.state_and_flags.as_atomic_int.FetchAndOrSequentiallyConsistent(flags);
+ tls32_.state_and_flags.as_atomic_int.FetchAndBitwiseOrSequentiallyConsistent(flags);
TriggerSuspend();
}
return true;
@@ -1316,7 +1319,7 @@ bool Thread::PassActiveSuspendBarriers(Thread* self) {
int32_t cur_val = pending_threads->LoadRelaxed();
CHECK_GT(cur_val, 0) << "Unexpected value for PassActiveSuspendBarriers(): " << cur_val;
// Reduce value by 1.
- done = pending_threads->CompareExchangeWeakRelaxed(cur_val, cur_val - 1);
+ done = pending_threads->CompareAndSetWeakRelaxed(cur_val, cur_val - 1);
#if ART_USE_FUTEXES
if (done && (cur_val - 1) == 0) { // Weak CAS may fail spuriously.
futex(pending_threads->Address(), FUTEX_WAKE, -1, nullptr, nullptr, 0);
@@ -1387,7 +1390,7 @@ bool Thread::RequestCheckpoint(Closure* function) {
union StateAndFlags new_state_and_flags;
new_state_and_flags.as_int = old_state_and_flags.as_int;
new_state_and_flags.as_struct.flags |= kCheckpointRequest;
- bool success = tls32_.state_and_flags.as_atomic_int.CompareExchangeStrongSequentiallyConsistent(
+ bool success = tls32_.state_and_flags.as_atomic_int.CompareAndSetStrongSequentiallyConsistent(
old_state_and_flags.as_int, new_state_and_flags.as_int);
if (success) {
// Succeeded setting checkpoint flag, now insert the actual checkpoint.
@@ -1416,7 +1419,7 @@ bool Thread::RequestEmptyCheckpoint() {
union StateAndFlags new_state_and_flags;
new_state_and_flags.as_int = old_state_and_flags.as_int;
new_state_and_flags.as_struct.flags |= kEmptyCheckpointRequest;
- bool success = tls32_.state_and_flags.as_atomic_int.CompareExchangeStrongSequentiallyConsistent(
+ bool success = tls32_.state_and_flags.as_atomic_int.CompareAndSetStrongSequentiallyConsistent(
old_state_and_flags.as_int, new_state_and_flags.as_int);
if (success) {
TriggerSuspend();
@@ -1557,7 +1560,7 @@ Closure* Thread::GetFlipFunction() {
if (func == nullptr) {
return nullptr;
}
- } while (!atomic_func->CompareExchangeWeakSequentiallyConsistent(func, nullptr));
+ } while (!atomic_func->CompareAndSetWeakSequentiallyConsistent(func, nullptr));
DCHECK(func != nullptr);
return func;
}
@@ -1756,25 +1759,22 @@ void Thread::DumpState(std::ostream& os) const {
Thread::DumpState(os, this, GetTid());
}
-struct StackDumpVisitor : public StackVisitor {
+struct StackDumpVisitor : public MonitorObjectsStackVisitor {
StackDumpVisitor(std::ostream& os_in,
Thread* thread_in,
Context* context,
- bool can_allocate_in,
+ bool can_allocate,
bool check_suspended = true,
- bool dump_locks_in = true)
+ bool dump_locks = true)
REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread_in,
- context,
- StackVisitor::StackWalkKind::kIncludeInlinedFrames,
- check_suspended),
+ : MonitorObjectsStackVisitor(thread_in,
+ context,
+ check_suspended,
+ can_allocate && dump_locks),
os(os_in),
- can_allocate(can_allocate_in),
last_method(nullptr),
last_line_number(0),
- repetition_count(0),
- frame_count(0),
- dump_locks(dump_locks_in) {}
+ repetition_count(0) {}
virtual ~StackDumpVisitor() {
if (frame_count == 0) {
@@ -1782,13 +1782,12 @@ struct StackDumpVisitor : public StackVisitor {
}
}
- bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* m = GetMethod();
- if (m->IsRuntimeMethod()) {
- return true;
- }
+ static constexpr size_t kMaxRepetition = 3u;
+
+ VisitMethodResult StartMethod(ArtMethod* m, size_t frame_nr ATTRIBUTE_UNUSED)
+ OVERRIDE
+ REQUIRES_SHARED(Locks::mutator_lock_) {
m = m->GetInterfaceMethodIfProxy(kRuntimePointerSize);
- const int kMaxRepetition = 3;
ObjPtr<mirror::Class> c = m->GetDeclaringClass();
ObjPtr<mirror::DexCache> dex_cache = c->GetDexCache();
int line_number = -1;
@@ -1806,67 +1805,97 @@ struct StackDumpVisitor : public StackVisitor {
last_line_number = line_number;
last_method = m;
}
- if (repetition_count < kMaxRepetition) {
- os << " at " << m->PrettyMethod(false);
- if (m->IsNative()) {
- os << "(Native method)";
- } else {
- const char* source_file(m->GetDeclaringClassSourceFile());
- os << "(" << (source_file != nullptr ? source_file : "unavailable")
- << ":" << line_number << ")";
- }
- os << "\n";
- if (frame_count == 0) {
- Monitor::DescribeWait(os, GetThread());
- }
- if (can_allocate && dump_locks) {
- // Visit locks, but do not abort on errors. This would trigger a nested abort.
- // Skip visiting locks if dump_locks is false as it would cause a bad_mutexes_held in
- // RegTypeCache::RegTypeCache due to thread_list_lock.
- Monitor::VisitLocks(this, DumpLockedObject, &os, false);
- }
+
+ if (repetition_count >= kMaxRepetition) {
+ // Skip visiting=printing anything.
+ return VisitMethodResult::kSkipMethod;
}
- ++frame_count;
- return true;
+ os << " at " << m->PrettyMethod(false);
+ if (m->IsNative()) {
+ os << "(Native method)";
+ } else {
+ const char* source_file(m->GetDeclaringClassSourceFile());
+ os << "(" << (source_file != nullptr ? source_file : "unavailable")
+ << ":" << line_number << ")";
+ }
+ os << "\n";
+ // Go and visit locks.
+ return VisitMethodResult::kContinueMethod;
+ }
+
+ VisitMethodResult EndMethod(ArtMethod* m ATTRIBUTE_UNUSED) OVERRIDE {
+ return VisitMethodResult::kContinueMethod;
}
- static void DumpLockedObject(mirror::Object* o, void* context)
+ void VisitWaitingObject(mirror::Object* obj, ThreadState state ATTRIBUTE_UNUSED)
+ OVERRIDE
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ PrintObject(obj, " - waiting on ", ThreadList::kInvalidThreadId);
+ }
+ void VisitSleepingObject(mirror::Object* obj)
+ OVERRIDE
REQUIRES_SHARED(Locks::mutator_lock_) {
- std::ostream& os = *reinterpret_cast<std::ostream*>(context);
- os << " - locked ";
- if (o == nullptr) {
- os << "an unknown object";
+ PrintObject(obj, " - sleeping on ", ThreadList::kInvalidThreadId);
+ }
+ void VisitBlockedOnObject(mirror::Object* obj,
+ ThreadState state,
+ uint32_t owner_tid)
+ OVERRIDE
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ const char* msg;
+ switch (state) {
+ case kBlocked:
+ msg = " - waiting to lock ";
+ break;
+
+ case kWaitingForLockInflation:
+ msg = " - waiting for lock inflation of ";
+ break;
+
+ default:
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+ }
+ PrintObject(obj, msg, owner_tid);
+ }
+ void VisitLockedObject(mirror::Object* obj)
+ OVERRIDE
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ PrintObject(obj, " - locked ", ThreadList::kInvalidThreadId);
+ }
+
+ void PrintObject(mirror::Object* obj,
+ const char* msg,
+ uint32_t owner_tid) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (obj == nullptr) {
+ os << msg << "an unknown object";
} else {
- if (kUseReadBarrier && Thread::Current()->GetIsGcMarking()) {
- // We may call Thread::Dump() in the middle of the CC thread flip and this thread's stack
- // may have not been flipped yet and "o" may be a from-space (stale) ref, in which case the
- // IdentityHashCode call below will crash. So explicitly mark/forward it here.
- o = ReadBarrier::Mark(o);
- }
- if ((o->GetLockWord(false).GetState() == LockWord::kThinLocked) &&
+ if ((obj->GetLockWord(true).GetState() == LockWord::kThinLocked) &&
Locks::mutator_lock_->IsExclusiveHeld(Thread::Current())) {
// Getting the identity hashcode here would result in lock inflation and suspension of the
// current thread, which isn't safe if this is the only runnable thread.
- os << StringPrintf("<@addr=0x%" PRIxPTR "> (a %s)", reinterpret_cast<intptr_t>(o),
- o->PrettyTypeOf().c_str());
+ os << msg << StringPrintf("<@addr=0x%" PRIxPTR "> (a %s)",
+ reinterpret_cast<intptr_t>(obj),
+ obj->PrettyTypeOf().c_str());
} else {
- // IdentityHashCode can cause thread suspension, which would invalidate o if it moved. So
- // we get the pretty type beofre we call IdentityHashCode.
- const std::string pretty_type(o->PrettyTypeOf());
- os << StringPrintf("<0x%08x> (a %s)", o->IdentityHashCode(), pretty_type.c_str());
+ // - waiting on <0x6008c468> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
+ // Call PrettyTypeOf before IdentityHashCode since IdentityHashCode can cause thread
+ // suspension and move pretty_object.
+ const std::string pretty_type(obj->PrettyTypeOf());
+ os << msg << StringPrintf("<0x%08x> (a %s)", obj->IdentityHashCode(), pretty_type.c_str());
}
}
+ if (owner_tid != ThreadList::kInvalidThreadId) {
+ os << " held by thread " << owner_tid;
+ }
os << "\n";
}
std::ostream& os;
- const bool can_allocate;
ArtMethod* last_method;
int last_line_number;
- int repetition_count;
- int frame_count;
- const bool dump_locks;
+ size_t repetition_count;
};
static bool ShouldShowNativeStack(const Thread* thread)
@@ -2141,7 +2170,7 @@ void Thread::Destroy() {
ScopedObjectAccess soa(self);
MonitorExitVisitor visitor(self);
// On thread detach, all monitors entered with JNI MonitorEnter are automatically exited.
- tlsPtr_.jni_env->monitors.VisitRoots(&visitor, RootInfo(kRootVMInternal));
+ tlsPtr_.jni_env->monitors_.VisitRoots(&visitor, RootInfo(kRootVMInternal));
}
// Release locally held global references which releasing may require the mutator lock.
if (tlsPtr_.jpeer != nullptr) {
@@ -2310,7 +2339,7 @@ ObjPtr<mirror::Object> Thread::DecodeJObject(jobject obj) const {
bool expect_null = false;
// The "kinds" below are sorted by the frequency we expect to encounter them.
if (kind == kLocal) {
- IndirectReferenceTable& locals = tlsPtr_.jni_env->locals;
+ IndirectReferenceTable& locals = tlsPtr_.jni_env->locals_;
// Local references do not need a read barrier.
result = locals.Get<kWithoutReadBarrier>(ref);
} else if (kind == kHandleScopeOrInvalid) {
@@ -2321,15 +2350,15 @@ ObjPtr<mirror::Object> Thread::DecodeJObject(jobject obj) const {
result = reinterpret_cast<StackReference<mirror::Object>*>(obj)->AsMirrorPtr();
VerifyObject(result);
} else {
- tlsPtr_.jni_env->vm->JniAbortF(nullptr, "use of invalid jobject %p", obj);
+ tlsPtr_.jni_env->vm_->JniAbortF(nullptr, "use of invalid jobject %p", obj);
expect_null = true;
result = nullptr;
}
} else if (kind == kGlobal) {
- result = tlsPtr_.jni_env->vm->DecodeGlobal(ref);
+ result = tlsPtr_.jni_env->vm_->DecodeGlobal(ref);
} else {
DCHECK_EQ(kind, kWeakGlobal);
- result = tlsPtr_.jni_env->vm->DecodeWeakGlobal(const_cast<Thread*>(this), ref);
+ result = tlsPtr_.jni_env->vm_->DecodeWeakGlobal(const_cast<Thread*>(this), ref);
if (Runtime::Current()->IsClearedJniWeakGlobal(result)) {
// This is a special case where it's okay to return null.
expect_null = true;
@@ -2338,7 +2367,7 @@ ObjPtr<mirror::Object> Thread::DecodeJObject(jobject obj) const {
}
if (UNLIKELY(!expect_null && result == nullptr)) {
- tlsPtr_.jni_env->vm->JniAbortF(nullptr, "use of deleted %s %p",
+ tlsPtr_.jni_env->vm_->JniAbortF(nullptr, "use of deleted %s %p",
ToStr<IndirectRefKind>(kind).c_str(), obj);
}
return result;
@@ -2349,7 +2378,7 @@ bool Thread::IsJWeakCleared(jweak obj) const {
IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
IndirectRefKind kind = IndirectReferenceTable::GetIndirectRefKind(ref);
CHECK_EQ(kind, kWeakGlobal);
- return tlsPtr_.jni_env->vm->IsWeakGlobalCleared(const_cast<Thread*>(this), ref);
+ return tlsPtr_.jni_env->vm_->IsWeakGlobalCleared(const_cast<Thread*>(this), ref);
}
// Implements java.lang.Thread.interrupted.
@@ -2603,6 +2632,61 @@ bool Thread::IsExceptionThrownByCurrentMethod(ObjPtr<mirror::Throwable> exceptio
return count_visitor.GetDepth() == static_cast<uint32_t>(exception->GetStackDepth());
}
+static ObjPtr<mirror::StackTraceElement> CreateStackTraceElement(
+ const ScopedObjectAccessAlreadyRunnable& soa,
+ ArtMethod* method,
+ uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) {
+ int32_t line_number;
+ StackHandleScope<3> hs(soa.Self());
+ auto class_name_object(hs.NewHandle<mirror::String>(nullptr));
+ auto source_name_object(hs.NewHandle<mirror::String>(nullptr));
+ if (method->IsProxyMethod()) {
+ line_number = -1;
+ class_name_object.Assign(method->GetDeclaringClass()->GetName());
+ // source_name_object intentionally left null for proxy methods
+ } else {
+ line_number = method->GetLineNumFromDexPC(dex_pc);
+ // Allocate element, potentially triggering GC
+ // TODO: reuse class_name_object via Class::name_?
+ const char* descriptor = method->GetDeclaringClassDescriptor();
+ CHECK(descriptor != nullptr);
+ std::string class_name(PrettyDescriptor(descriptor));
+ class_name_object.Assign(
+ mirror::String::AllocFromModifiedUtf8(soa.Self(), class_name.c_str()));
+ if (class_name_object == nullptr) {
+ soa.Self()->AssertPendingOOMException();
+ return nullptr;
+ }
+ const char* source_file = method->GetDeclaringClassSourceFile();
+ if (line_number == -1) {
+ // Make the line_number field of StackTraceElement hold the dex pc.
+ // source_name_object is intentionally left null if we failed to map the dex pc to
+ // a line number (most probably because there is no debug info). See b/30183883.
+ line_number = dex_pc;
+ } else {
+ if (source_file != nullptr) {
+ source_name_object.Assign(mirror::String::AllocFromModifiedUtf8(soa.Self(), source_file));
+ if (source_name_object == nullptr) {
+ soa.Self()->AssertPendingOOMException();
+ return nullptr;
+ }
+ }
+ }
+ }
+ const char* method_name = method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetName();
+ CHECK(method_name != nullptr);
+ Handle<mirror::String> method_name_object(
+ hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), method_name)));
+ if (method_name_object == nullptr) {
+ return nullptr;
+ }
+ return mirror::StackTraceElement::Alloc(soa.Self(),
+ class_name_object,
+ method_name_object,
+ source_name_object,
+ line_number);
+}
+
jobjectArray Thread::InternalStackTraceToStackTraceElementArray(
const ScopedObjectAccessAlreadyRunnable& soa,
jobject internal,
@@ -2649,55 +2733,7 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray(
ArtMethod* method = method_trace->GetElementPtrSize<ArtMethod*>(i, kRuntimePointerSize);
uint32_t dex_pc = method_trace->GetElementPtrSize<uint32_t>(
i + method_trace->GetLength() / 2, kRuntimePointerSize);
- int32_t line_number;
- StackHandleScope<3> hs(soa.Self());
- auto class_name_object(hs.NewHandle<mirror::String>(nullptr));
- auto source_name_object(hs.NewHandle<mirror::String>(nullptr));
- if (method->IsProxyMethod()) {
- line_number = -1;
- class_name_object.Assign(method->GetDeclaringClass()->GetName());
- // source_name_object intentionally left null for proxy methods
- } else {
- line_number = method->GetLineNumFromDexPC(dex_pc);
- // Allocate element, potentially triggering GC
- // TODO: reuse class_name_object via Class::name_?
- const char* descriptor = method->GetDeclaringClassDescriptor();
- CHECK(descriptor != nullptr);
- std::string class_name(PrettyDescriptor(descriptor));
- class_name_object.Assign(
- mirror::String::AllocFromModifiedUtf8(soa.Self(), class_name.c_str()));
- if (class_name_object == nullptr) {
- soa.Self()->AssertPendingOOMException();
- return nullptr;
- }
- const char* source_file = method->GetDeclaringClassSourceFile();
- if (line_number == -1) {
- // Make the line_number field of StackTraceElement hold the dex pc.
- // source_name_object is intentionally left null if we failed to map the dex pc to
- // a line number (most probably because there is no debug info). See b/30183883.
- line_number = dex_pc;
- } else {
- if (source_file != nullptr) {
- source_name_object.Assign(mirror::String::AllocFromModifiedUtf8(soa.Self(), source_file));
- if (source_name_object == nullptr) {
- soa.Self()->AssertPendingOOMException();
- return nullptr;
- }
- }
- }
- }
- const char* method_name = method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetName();
- CHECK(method_name != nullptr);
- Handle<mirror::String> method_name_object(
- hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), method_name)));
- if (method_name_object == nullptr) {
- return nullptr;
- }
- ObjPtr<mirror::StackTraceElement> obj = mirror::StackTraceElement::Alloc(soa.Self(),
- class_name_object,
- method_name_object,
- source_name_object,
- line_number);
+ ObjPtr<mirror::StackTraceElement> obj = CreateStackTraceElement(soa, method, dex_pc);
if (obj == nullptr) {
return nullptr;
}
@@ -3389,7 +3425,7 @@ class ReferenceMapVisitor : public StackVisitor {
const CodeInfoEncoding& _encoding,
const StackMap& map,
RootVisitor& _visitor)
- : number_of_dex_registers(method->GetCodeItem()->registers_size_),
+ : number_of_dex_registers(CodeItemDataAccessor(method).RegistersSize()),
code_info(_code_info),
encoding(_encoding),
dex_register_map(code_info.GetDexRegisterMapOf(map,
@@ -3480,8 +3516,8 @@ void Thread::VisitRoots(RootVisitor* visitor) {
RootInfo(kRootNativeStack, thread_id));
}
visitor->VisitRootIfNonNull(&tlsPtr_.monitor_enter_object, RootInfo(kRootNativeStack, thread_id));
- tlsPtr_.jni_env->locals.VisitRoots(visitor, RootInfo(kRootJNILocal, thread_id));
- tlsPtr_.jni_env->monitors.VisitRoots(visitor, RootInfo(kRootJNIMonitor, thread_id));
+ tlsPtr_.jni_env->VisitJniLocalRoots(visitor, RootInfo(kRootJNILocal, thread_id));
+ tlsPtr_.jni_env->VisitMonitorRoots(visitor, RootInfo(kRootJNIMonitor, thread_id));
HandleScopeVisitRoots(visitor, thread_id);
if (tlsPtr_.debug_invoke_req != nullptr) {
tlsPtr_.debug_invoke_req->VisitRoots(visitor, RootInfo(kRootDebugger, thread_id));
@@ -3700,6 +3736,7 @@ void Thread::DeoptimizeWithDeoptimizationException(JValue* result) {
void Thread::SetAsyncException(ObjPtr<mirror::Throwable> new_exception) {
CHECK(new_exception != nullptr);
+ Runtime::Current()->SetAsyncExceptionsThrown();
if (kIsDebugBuild) {
// Make sure we are in a checkpoint.
MutexLock mu(Thread::Current(), *Locks::thread_suspend_count_lock_);
diff --git a/runtime/thread.h b/runtime/thread.h
index 0803975d26..1e89887c3e 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -86,7 +86,7 @@ class DeoptimizationContextRecord;
class DexFile;
class FrameIdToShadowFrame;
class JavaVMExt;
-struct JNIEnvExt;
+class JNIEnvExt;
class Monitor;
class RootVisitor;
class ScopedObjectAccessAlreadyRunnable;
@@ -1086,11 +1086,11 @@ class Thread {
}
void AtomicSetFlag(ThreadFlag flag) {
- tls32_.state_and_flags.as_atomic_int.FetchAndOrSequentiallyConsistent(flag);
+ tls32_.state_and_flags.as_atomic_int.FetchAndBitwiseOrSequentiallyConsistent(flag);
}
void AtomicClearFlag(ThreadFlag flag) {
- tls32_.state_and_flags.as_atomic_int.FetchAndAndSequentiallyConsistent(-1 ^ flag);
+ tls32_.state_and_flags.as_atomic_int.FetchAndBitwiseAndSequentiallyConsistent(-1 ^ flag);
}
void ResetQuickAllocEntryPointsForThread(bool is_marking);
diff --git a/runtime/thread_linux.cc b/runtime/thread_linux.cc
index b922d94617..9673eee795 100644
--- a/runtime/thread_linux.cc
+++ b/runtime/thread_linux.cc
@@ -14,9 +14,11 @@
* limitations under the License.
*/
+#include "thread.h"
+
#include <signal.h>
-#include "thread.h"
+#include "base/logging.h" // For VLOG.
#include "utils.h"
namespace art {
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 9f553147c4..8095ef57c7 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -28,6 +28,7 @@
#include "nativehelper/scoped_local_ref.h"
#include "nativehelper/scoped_utf_chars.h"
+#include "base/aborting.h"
#include "base/histogram-inl.h"
#include "base/mutex-inl.h"
#include "base/systrace.h"
@@ -68,8 +69,7 @@ static constexpr useconds_t kThreadSuspendMaxSleepUs = 5000;
// Whether we should try to dump the native stack of unattached threads. See commit ed8b723 for
// some history.
-// Turned off again. b/29248079
-static constexpr bool kDumpUnattachedThreadNativeStackForSigQuit = false;
+static constexpr bool kDumpUnattachedThreadNativeStackForSigQuit = true;
ThreadList::ThreadList(uint64_t thread_suspend_timeout_ns)
: suspend_all_count_(0),
@@ -364,11 +364,11 @@ size_t ThreadList::RunCheckpoint(Closure* checkpoint_function, Closure* callback
// Run the checkpoint on the suspended threads.
for (const auto& thread : suspended_count_modified_threads) {
if (!thread->IsSuspended()) {
- if (ATRACE_ENABLED()) {
+ ScopedTrace trace([&]() {
std::ostringstream oss;
thread->ShortDump(oss);
- ATRACE_BEGIN((std::string("Waiting for suspension of thread ") + oss.str()).c_str());
- }
+ return std::string("Waiting for suspension of thread ") + oss.str();
+ });
// Busy wait until the thread is suspended.
const uint64_t start_time = NanoTime();
do {
@@ -377,7 +377,6 @@ size_t ThreadList::RunCheckpoint(Closure* checkpoint_function, Closure* callback
const uint64_t total_delay = NanoTime() - start_time;
// Shouldn't need to wait for longer than 1000 microseconds.
constexpr uint64_t kLongWaitThreshold = MsToNs(1);
- ATRACE_END();
if (UNLIKELY(total_delay > kLongWaitThreshold)) {
LOG(WARNING) << "Long wait of " << PrettyDuration(total_delay) << " for "
<< *thread << " suspension!";
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index cffaffc045..386cdf006a 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -22,11 +22,11 @@
#include <pthread.h>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "base/bit_utils.h"
#include "base/casts.h"
-#include "base/logging.h"
#include "base/stl_util.h"
#include "base/time_utils.h"
#include "runtime.h"
diff --git a/runtime/ti/agent.cc b/runtime/ti/agent.cc
index 548752e980..62bdde6790 100644
--- a/runtime/ti/agent.cc
+++ b/runtime/ti/agent.cc
@@ -17,6 +17,8 @@
#include "agent.h"
#include "android-base/stringprintf.h"
+#include "nativehelper/scoped_local_ref.h"
+#include "nativeloader/native_loader.h"
#include "base/strlcpy.h"
#include "java_vm_ext.h"
@@ -33,31 +35,58 @@ const char* AGENT_ON_LOAD_FUNCTION_NAME = "Agent_OnLoad";
const char* AGENT_ON_ATTACH_FUNCTION_NAME = "Agent_OnAttach";
const char* AGENT_ON_UNLOAD_FUNCTION_NAME = "Agent_OnUnload";
+AgentSpec::AgentSpec(const std::string& arg) {
+ size_t eq = arg.find_first_of('=');
+ if (eq == std::string::npos) {
+ name_ = arg;
+ } else {
+ name_ = arg.substr(0, eq);
+ args_ = arg.substr(eq + 1, arg.length());
+ }
+}
+
+std::unique_ptr<Agent> AgentSpec::Load(/*out*/jint* call_res,
+ /*out*/LoadError* error,
+ /*out*/std::string* error_msg) {
+ VLOG(agents) << "Loading agent: " << name_ << " " << args_;
+ return DoLoadHelper(nullptr, false, nullptr, call_res, error, error_msg);
+}
+
+// Tries to attach the agent using its OnAttach method. Returns true on success.
+std::unique_ptr<Agent> AgentSpec::Attach(JNIEnv* env,
+ jobject class_loader,
+ /*out*/jint* call_res,
+ /*out*/LoadError* error,
+ /*out*/std::string* error_msg) {
+ VLOG(agents) << "Attaching agent: " << name_ << " " << args_;
+ return DoLoadHelper(env, true, class_loader, call_res, error, error_msg);
+}
+
+
// TODO We need to acquire some locks probably.
-Agent::LoadError Agent::DoLoadHelper(bool attaching,
- /*out*/jint* call_res,
- /*out*/std::string* error_msg) {
+std::unique_ptr<Agent> AgentSpec::DoLoadHelper(JNIEnv* env,
+ bool attaching,
+ jobject class_loader,
+ /*out*/jint* call_res,
+ /*out*/LoadError* error,
+ /*out*/std::string* error_msg) {
ScopedThreadStateChange stsc(Thread::Current(), ThreadState::kNative);
DCHECK(call_res != nullptr);
DCHECK(error_msg != nullptr);
- if (IsStarted()) {
- *error_msg = StringPrintf("the agent at %s has already been started!", name_.c_str());
- VLOG(agents) << "err: " << *error_msg;
- return kAlreadyStarted;
- }
- LoadError err = DoDlOpen(error_msg);
- if (err != kNoError) {
+ std::unique_ptr<Agent> agent = DoDlOpen(env, class_loader, error, error_msg);
+ if (agent == nullptr) {
VLOG(agents) << "err: " << *error_msg;
- return err;
+ return nullptr;
}
- AgentOnLoadFunction callback = attaching ? onattach_ : onload_;
+ AgentOnLoadFunction callback = attaching ? agent->onattach_ : agent->onload_;
if (callback == nullptr) {
*error_msg = StringPrintf("Unable to start agent %s: No %s callback found",
(attaching ? "attach" : "load"),
name_.c_str());
VLOG(agents) << "err: " << *error_msg;
- return kLoadingError;
+ *error = kLoadingError;
+ return nullptr;
}
// Need to let the function fiddle with the array.
std::unique_ptr<char[]> copied_args(new char[args_.size() + 1]);
@@ -70,44 +99,58 @@ Agent::LoadError Agent::DoLoadHelper(bool attaching,
*error_msg = StringPrintf("Initialization of %s returned non-zero value of %d",
name_.c_str(), *call_res);
VLOG(agents) << "err: " << *error_msg;
- return kInitializationError;
- } else {
- return kNoError;
+ *error = kInitializationError;
+ return nullptr;
}
+ return agent;
}
-void* Agent::FindSymbol(const std::string& name) const {
- CHECK(IsStarted()) << "Cannot find symbols in an unloaded agent library " << this;
- return dlsym(dlopen_handle_, name.c_str());
-}
-
-Agent::LoadError Agent::DoDlOpen(/*out*/std::string* error_msg) {
+std::unique_ptr<Agent> AgentSpec::DoDlOpen(JNIEnv* env,
+ jobject class_loader,
+ /*out*/LoadError* error,
+ /*out*/std::string* error_msg) {
DCHECK(error_msg != nullptr);
- DCHECK(dlopen_handle_ == nullptr);
- DCHECK(onload_ == nullptr);
- DCHECK(onattach_ == nullptr);
- DCHECK(onunload_ == nullptr);
-
- dlopen_handle_ = dlopen(name_.c_str(), RTLD_LAZY);
- if (dlopen_handle_ == nullptr) {
+ ScopedLocalRef<jstring> library_path(env,
+ class_loader == nullptr
+ ? nullptr
+ : JavaVMExt::GetLibrarySearchPath(env, class_loader));
+
+ bool needs_native_bridge = false;
+ void* dlopen_handle = android::OpenNativeLibrary(env,
+ Runtime::Current()->GetTargetSdkVersion(),
+ name_.c_str(),
+ class_loader,
+ library_path.get(),
+ &needs_native_bridge,
+ error_msg);
+ if (dlopen_handle == nullptr) {
*error_msg = StringPrintf("Unable to dlopen %s: %s", name_.c_str(), dlerror());
- return kLoadingError;
- }
-
- onload_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_LOAD_FUNCTION_NAME));
- if (onload_ == nullptr) {
- VLOG(agents) << "Unable to find 'Agent_OnLoad' symbol in " << this;
- }
- onattach_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_ATTACH_FUNCTION_NAME));
- if (onattach_ == nullptr) {
- VLOG(agents) << "Unable to find 'Agent_OnAttach' symbol in " << this;
+ *error = kLoadingError;
+ return nullptr;
}
- onunload_ = reinterpret_cast<AgentOnUnloadFunction>(FindSymbol(AGENT_ON_UNLOAD_FUNCTION_NAME));
- if (onunload_ == nullptr) {
- VLOG(agents) << "Unable to find 'Agent_OnUnload' symbol in " << this;
+ if (needs_native_bridge) {
+ // TODO: Consider support?
+ android::CloseNativeLibrary(dlopen_handle, needs_native_bridge);
+ *error_msg = StringPrintf("Native-bridge agents unsupported: %s", name_.c_str());
+ *error = kLoadingError;
+ return nullptr;
}
- return kNoError;
+
+ std::unique_ptr<Agent> agent(new Agent(name_, dlopen_handle));
+ agent->PopulateFunctions();
+ *error = kNoError;
+ return agent;
+}
+
+std::ostream& operator<<(std::ostream &os, AgentSpec const& m) {
+ return os << "AgentSpec { name=\"" << m.name_ << "\", args=\"" << m.args_ << "\" }";
+}
+
+
+void* Agent::FindSymbol(const std::string& name) const {
+ CHECK(dlopen_handle_ != nullptr) << "Cannot find symbols in an unloaded agent library " << this;
+ return dlsym(dlopen_handle_, name.c_str());
}
// TODO Lock some stuff probably.
@@ -116,8 +159,9 @@ void Agent::Unload() {
if (onunload_ != nullptr) {
onunload_(Runtime::Current()->GetJavaVM());
}
- // Don't actually dlclose since some agents assume they will never get unloaded. Since this only
- // happens when the runtime is shutting down anyway this isn't a big deal.
+ // Don't actually android::CloseNativeLibrary since some agents assume they will never get
+ // unloaded. Since this only happens when the runtime is shutting down anyway this isn't a big
+ // deal.
dlopen_handle_ = nullptr;
onload_ = nullptr;
onattach_ = nullptr;
@@ -127,58 +171,6 @@ void Agent::Unload() {
}
}
-Agent::Agent(const std::string& arg)
- : dlopen_handle_(nullptr),
- onload_(nullptr),
- onattach_(nullptr),
- onunload_(nullptr) {
- size_t eq = arg.find_first_of('=');
- if (eq == std::string::npos) {
- name_ = arg;
- } else {
- name_ = arg.substr(0, eq);
- args_ = arg.substr(eq + 1, arg.length());
- }
-}
-
-Agent::Agent(const Agent& other)
- : dlopen_handle_(nullptr),
- onload_(nullptr),
- onattach_(nullptr),
- onunload_(nullptr) {
- *this = other;
-}
-
-// Attempting to copy to/from loaded/started agents is a fatal error
-Agent& Agent::operator=(const Agent& other) {
- if (this != &other) {
- if (other.dlopen_handle_ != nullptr) {
- LOG(FATAL) << "Attempting to copy a loaded agent!";
- }
-
- if (dlopen_handle_ != nullptr) {
- LOG(FATAL) << "Attempting to assign into a loaded agent!";
- }
-
- DCHECK(other.onload_ == nullptr);
- DCHECK(other.onattach_ == nullptr);
- DCHECK(other.onunload_ == nullptr);
-
- DCHECK(onload_ == nullptr);
- DCHECK(onattach_ == nullptr);
- DCHECK(onunload_ == nullptr);
-
- name_ = other.name_;
- args_ = other.args_;
-
- dlopen_handle_ = nullptr;
- onload_ = nullptr;
- onattach_ = nullptr;
- onunload_ = nullptr;
- }
- return *this;
-}
-
Agent::Agent(Agent&& other)
: dlopen_handle_(nullptr),
onload_(nullptr),
@@ -190,10 +182,9 @@ Agent::Agent(Agent&& other)
Agent& Agent::operator=(Agent&& other) {
if (this != &other) {
if (dlopen_handle_ != nullptr) {
- dlclose(dlopen_handle_);
+ Unload();
}
name_ = std::move(other.name_);
- args_ = std::move(other.args_);
dlopen_handle_ = other.dlopen_handle_;
onload_ = other.onload_;
onattach_ = other.onattach_;
@@ -206,9 +197,24 @@ Agent& Agent::operator=(Agent&& other) {
return *this;
}
+void Agent::PopulateFunctions() {
+ onload_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_LOAD_FUNCTION_NAME));
+ if (onload_ == nullptr) {
+ VLOG(agents) << "Unable to find 'Agent_OnLoad' symbol in " << this;
+ }
+ onattach_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_ATTACH_FUNCTION_NAME));
+ if (onattach_ == nullptr) {
+ VLOG(agents) << "Unable to find 'Agent_OnAttach' symbol in " << this;
+ }
+ onunload_ = reinterpret_cast<AgentOnUnloadFunction>(FindSymbol(AGENT_ON_UNLOAD_FUNCTION_NAME));
+ if (onunload_ == nullptr) {
+ VLOG(agents) << "Unable to find 'Agent_OnUnload' symbol in " << this;
+ }
+}
+
Agent::~Agent() {
if (dlopen_handle_ != nullptr) {
- dlclose(dlopen_handle_);
+ Unload();
}
}
@@ -217,8 +223,7 @@ std::ostream& operator<<(std::ostream &os, const Agent* m) {
}
std::ostream& operator<<(std::ostream &os, Agent const& m) {
- return os << "Agent { name=\"" << m.name_ << "\", args=\"" << m.args_ << "\", handle="
- << m.dlopen_handle_ << " }";
+ return os << "Agent { name=\"" << m.name_ << "\", handle=" << m.dlopen_handle_ << " }";
}
} // namespace ti
diff --git a/runtime/ti/agent.h b/runtime/ti/agent.h
index d6f1f2ef06..24a6f1ce6a 100644
--- a/runtime/ti/agent.h
+++ b/runtime/ti/agent.h
@@ -20,34 +20,24 @@
#include <dlfcn.h>
#include <jni.h> // for jint, JavaVM* etc declarations
+#include <memory>
+
#include "base/logging.h"
namespace art {
namespace ti {
-using AgentOnLoadFunction = jint (*)(JavaVM*, const char*, void*);
-using AgentOnUnloadFunction = void (*)(JavaVM*);
+class Agent;
-// Agents are native libraries that will be loaded by the runtime for the purpose of
-// instrumentation. They will be entered by Agent_OnLoad or Agent_OnAttach depending on whether the
-// agent is being attached during runtime startup or later.
-//
-// The agent's Agent_OnUnload function will be called during runtime shutdown.
-//
-// TODO: consider splitting ti::Agent into command line, agent and shared library handler classes
-// TODO Support native-bridge. Currently agents can only be the actual runtime ISA of the device.
-class Agent {
+enum LoadError {
+ kNoError, // No error occurred..
+ kLoadingError, // dlopen or dlsym returned an error.
+ kInitializationError, // The entrypoint did not return 0. This might require an abort.
+};
+
+class AgentSpec {
public:
- enum LoadError {
- kNoError, // No error occurred..
- kAlreadyStarted, // The agent has already been loaded.
- kLoadingError, // dlopen or dlsym returned an error.
- kInitializationError, // The entrypoint did not return 0. This might require an abort.
- };
-
- bool IsStarted() const {
- return dlopen_handle_ != nullptr;
- }
+ explicit AgentSpec(const std::string& arg);
const std::string& GetName() const {
return name_;
@@ -61,26 +51,59 @@ class Agent {
return !GetArgs().empty();
}
- void* FindSymbol(const std::string& name) const;
+ std::unique_ptr<Agent> Load(/*out*/jint* call_res,
+ /*out*/LoadError* error,
+ /*out*/std::string* error_msg);
- LoadError Load(/*out*/jint* call_res, /*out*/std::string* error_msg) {
- VLOG(agents) << "Loading agent: " << name_ << " " << args_;
- return DoLoadHelper(false, call_res, error_msg);
- }
+ // Tries to attach the agent using its OnAttach method. Returns true on success.
+ std::unique_ptr<Agent> Attach(JNIEnv* env,
+ jobject class_loader,
+ /*out*/jint* call_res,
+ /*out*/LoadError* error,
+ /*out*/std::string* error_msg);
- // TODO We need to acquire some locks probably.
- void Unload();
+ private:
+ std::unique_ptr<Agent> DoDlOpen(JNIEnv* env,
+ jobject class_loader,
+ /*out*/LoadError* error,
+ /*out*/std::string* error_msg);
+
+ std::unique_ptr<Agent> DoLoadHelper(JNIEnv* env,
+ bool attaching,
+ jobject class_loader,
+ /*out*/jint* call_res,
+ /*out*/LoadError* error,
+ /*out*/std::string* error_msg);
- // Tries to attach the agent using its OnAttach method. Returns true on success.
- LoadError Attach(/*out*/jint* call_res, /*out*/std::string* error_msg) {
- VLOG(agents) << "Attaching agent: " << name_ << " " << args_;
- return DoLoadHelper(true, call_res, error_msg);
+ std::string name_;
+ std::string args_;
+
+ friend std::ostream& operator<<(std::ostream &os, AgentSpec const& m);
+};
+
+std::ostream& operator<<(std::ostream &os, AgentSpec const& m);
+
+using AgentOnLoadFunction = jint (*)(JavaVM*, const char*, void*);
+using AgentOnUnloadFunction = void (*)(JavaVM*);
+
+// Agents are native libraries that will be loaded by the runtime for the purpose of
+// instrumentation. They will be entered by Agent_OnLoad or Agent_OnAttach depending on whether the
+// agent is being attached during runtime startup or later.
+//
+// The agent's Agent_OnUnload function will be called during runtime shutdown.
+//
+// TODO: consider splitting ti::Agent into command line, agent and shared library handler classes
+// TODO Support native-bridge. Currently agents can only be the actual runtime ISA of the device.
+class Agent {
+ public:
+ const std::string& GetName() const {
+ return name_;
}
- explicit Agent(const std::string& arg);
+ void* FindSymbol(const std::string& name) const;
- Agent(const Agent& other);
- Agent& operator=(const Agent& other);
+ // TODO We need to acquire some locks probably.
+ void Unload();
Agent(Agent&& other);
Agent& operator=(Agent&& other);
@@ -88,14 +111,17 @@ class Agent {
~Agent();
private:
- LoadError DoDlOpen(/*out*/std::string* error_msg);
+ Agent(const std::string& name, void* dlopen_handle) : name_(name),
+ dlopen_handle_(dlopen_handle),
+ onload_(nullptr),
+ onattach_(nullptr),
+ onunload_(nullptr) {
+ DCHECK(dlopen_handle != nullptr);
+ }
- LoadError DoLoadHelper(bool attaching,
- /*out*/jint* call_res,
- /*out*/std::string* error_msg);
+ void PopulateFunctions();
std::string name_;
- std::string args_;
void* dlopen_handle_;
// The entrypoints.
@@ -103,7 +129,10 @@ class Agent {
AgentOnLoadFunction onattach_;
AgentOnUnloadFunction onunload_;
+ friend class AgentSpec;
friend std::ostream& operator<<(std::ostream &os, Agent const& m);
+
+ DISALLOW_COPY_AND_ASSIGN(Agent);
};
std::ostream& operator<<(std::ostream &os, Agent const& m);
diff --git a/runtime/trace.cc b/runtime/trace.cc
index a113ab5cc8..f9d22df543 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -31,7 +31,7 @@
#include "class_linker.h"
#include "common_throws.h"
#include "debugger.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "gc/scoped_gc_critical_section.h"
#include "instrumentation.h"
@@ -937,7 +937,7 @@ void Trace::LogMethodTraceEvent(Thread* thread, ArtMethod* method,
overflow_ = true;
return;
}
- } while (!cur_offset_.CompareExchangeWeakSequentiallyConsistent(old_offset, new_offset));
+ } while (!cur_offset_.CompareAndSetWeakSequentiallyConsistent(old_offset, new_offset));
}
TraceAction action = kTraceMethodEnter;
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
index e923aff439..c9766bc9ca 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -16,7 +16,8 @@
#include "transaction.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/stl_util.h"
#include "gc/accounting/card_table-inl.h"
#include "gc_root-inl.h"
diff --git a/runtime/transaction.h b/runtime/transaction.h
index 4e9cde521f..8539ebc1d6 100644
--- a/runtime/transaction.h
+++ b/runtime/transaction.h
@@ -20,7 +20,7 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "base/value_object.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "gc_root.h"
#include "offsets.h"
#include "primitive.h"
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index e52dd08540..02e61d76a1 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -20,7 +20,7 @@
#include "art_method-inl.h"
#include "class_linker-inl.h"
#include "common_runtime_test.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "mirror/array-inl.h"
#include "scoped_thread_state_change-inl.h"
@@ -66,7 +66,7 @@ class TransactionTest : public CommonRuntimeTest {
class_linker_->VerifyClass(soa.Self(), h_klass);
ASSERT_TRUE(h_klass->IsVerified());
- mirror::Class::Status old_status = h_klass->GetStatus();
+ ClassStatus old_status = h_klass->GetStatus();
LockWord old_lock_word = h_klass->GetLockWord(false);
Runtime::Current()->EnterTransactionMode();
@@ -493,7 +493,7 @@ TEST_F(TransactionTest, ResolveString) {
dex::StringIndex string_idx = dex_file->GetIndexForStringId(*string_id);
ASSERT_TRUE(string_idx.IsValid());
// String should only get resolved by the initializer.
- EXPECT_TRUE(class_linker_->LookupString(*dex_file, string_idx, h_dex_cache.Get()) == nullptr);
+ EXPECT_TRUE(class_linker_->LookupString(string_idx, h_dex_cache.Get()) == nullptr);
EXPECT_TRUE(h_dex_cache->GetResolvedString(string_idx) == nullptr);
// Do the transaction, then roll back.
Runtime::Current()->EnterTransactionMode();
@@ -502,14 +502,15 @@ TEST_F(TransactionTest, ResolveString) {
ASSERT_TRUE(h_klass->IsInitialized());
// Make sure the string got resolved by the transaction.
{
- mirror::String* s = class_linker_->LookupString(*dex_file, string_idx, h_dex_cache.Get());
+ ObjPtr<mirror::String> s =
+ class_linker_->LookupString(string_idx, h_dex_cache.Get());
ASSERT_TRUE(s != nullptr);
EXPECT_STREQ(s->ToModifiedUtf8().c_str(), kResolvedString);
- EXPECT_EQ(s, h_dex_cache->GetResolvedString(string_idx));
+ EXPECT_EQ(s.Ptr(), h_dex_cache->GetResolvedString(string_idx));
}
Runtime::Current()->RollbackAndExitTransactionMode();
// Check that the string did not stay resolved.
- EXPECT_TRUE(class_linker_->LookupString(*dex_file, string_idx, h_dex_cache.Get()) == nullptr);
+ EXPECT_TRUE(class_linker_->LookupString(string_idx, h_dex_cache.Get()) == nullptr);
EXPECT_TRUE(h_dex_cache->GetResolvedString(string_idx) == nullptr);
ASSERT_FALSE(h_klass->IsInitialized());
ASSERT_FALSE(soa.Self()->IsExceptionPending());
diff --git a/runtime/type_lookup_table.cc b/runtime/type_lookup_table.cc
index 4fab39cd73..6eb3d83631 100644
--- a/runtime/type_lookup_table.cc
+++ b/runtime/type_lookup_table.cc
@@ -20,7 +20,7 @@
#include <memory>
#include "base/bit_utils.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "utf-inl.h"
#include "utils.h"
diff --git a/runtime/type_lookup_table.h b/runtime/type_lookup_table.h
index 780b3804e0..6a6f47fba2 100644
--- a/runtime/type_lookup_table.h
+++ b/runtime/type_lookup_table.h
@@ -17,7 +17,7 @@
#ifndef ART_RUNTIME_TYPE_LOOKUP_TABLE_H_
#define ART_RUNTIME_TYPE_LOOKUP_TABLE_H_
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "leb128.h"
#include "utf.h"
diff --git a/runtime/type_lookup_table_test.cc b/runtime/type_lookup_table_test.cc
index 0f8f2880fe..d04652a8e7 100644
--- a/runtime/type_lookup_table_test.cc
+++ b/runtime/type_lookup_table_test.cc
@@ -19,7 +19,7 @@
#include <memory>
#include "common_runtime_test.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "scoped_thread_state_change-inl.h"
#include "utf-inl.h"
diff --git a/runtime/type_reference.h b/runtime/type_reference.h
index f7daa2bd58..2b0b99f75e 100644
--- a/runtime/type_reference.h
+++ b/runtime/type_reference.h
@@ -19,8 +19,9 @@
#include <stdint.h>
-#include "base/logging.h"
-#include "dex_file_types.h"
+#include <android-base/logging.h>
+
+#include "dex/dex_file_types.h"
#include "string_reference.h"
namespace art {
diff --git a/runtime/utf.cc b/runtime/utf.cc
index 7e06482635..93fcb32136 100644
--- a/runtime/utf.cc
+++ b/runtime/utf.cc
@@ -16,7 +16,8 @@
#include "utf.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "mirror/array.h"
#include "mirror/object-inl.h"
#include "utf-inl.h"
diff --git a/runtime/utils.cc b/runtime/utils.cc
index f6533a7130..bd4175f5fd 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -30,7 +30,7 @@
#include "android-base/strings.h"
#include "base/file_utils.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "os.h"
#include "utf-inl.h"
diff --git a/runtime/utils.h b/runtime/utils.h
index ede32dc57a..789498ce09 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -23,9 +23,10 @@
#include <random>
#include <string>
+#include <android-base/logging.h>
+
#include "arch/instruction_set.h"
#include "base/casts.h"
-#include "base/logging.h"
#include "base/stringpiece.h"
#include "globals.h"
#include "primitive.h"
diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h
index 9d4e9fb96c..855b856187 100644
--- a/runtime/utils/dex_cache_arrays_layout-inl.h
+++ b/runtime/utils/dex_cache_arrays_layout-inl.h
@@ -19,8 +19,9 @@
#include "dex_cache_arrays_layout.h"
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
#include "gc_root.h"
#include "globals.h"
#include "mirror/dex_cache.h"
diff --git a/runtime/utils/dex_cache_arrays_layout.h b/runtime/utils/dex_cache_arrays_layout.h
index fc0415957d..6f689f334a 100644
--- a/runtime/utils/dex_cache_arrays_layout.h
+++ b/runtime/utils/dex_cache_arrays_layout.h
@@ -17,8 +17,8 @@
#ifndef ART_RUNTIME_UTILS_DEX_CACHE_ARRAYS_LAYOUT_H_
#define ART_RUNTIME_UTILS_DEX_CACHE_ARRAYS_LAYOUT_H_
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
namespace art {
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index fb9d24f9bc..a53556ffcc 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -20,12 +20,13 @@
#include <memory>
+#include <android-base/logging.h>
+
#include "base/bit_utils.h"
-#include "base/logging.h"
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
-#include "dex_file.h"
-#include "dex_file_loader.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_loader.h"
#include "dex_to_dex_decompiler.h"
namespace art {
@@ -253,6 +254,7 @@ void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
quickening_info));
}
optimizer::ArtDecompileDEX(
+ target_dex_file,
*code_item,
GetQuickeningInfoAt(quickening_info, quickening_offset),
decompile_return_instruction);
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 3e0882693a..2d9fcab59c 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -68,6 +68,18 @@ class VdexFile {
uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; }
+ size_t GetComputedFileSize() const {
+ return sizeof(Header) +
+ GetSizeOfChecksumsSection() +
+ GetDexSize() +
+ GetVerifierDepsSize() +
+ GetQuickeningInfoSize();
+ }
+
+ size_t GetSizeOfChecksumsSection() const {
+ return sizeof(VdexChecksum) * GetNumberOfDexFiles();
+ }
+
static constexpr uint8_t kVdexInvalidMagic[] = { 'w', 'd', 'e', 'x' };
private:
@@ -172,17 +184,13 @@ class VdexFile {
}
const uint8_t* DexBegin() const {
- return Begin() + sizeof(Header) + GetSizeOfChecksumsSection();
+ return Begin() + sizeof(Header) + GetHeader().GetSizeOfChecksumsSection();
}
const uint8_t* DexEnd() const {
return DexBegin() + GetHeader().GetDexSize();
}
- size_t GetSizeOfChecksumsSection() const {
- return sizeof(VdexChecksum) * GetHeader().GetNumberOfDexFiles();
- }
-
uint32_t GetDexFileIndex(const DexFile& dex_file) const;
std::unique_ptr<MemMap> mmap_;
diff --git a/runtime/verifier/method_verifier-inl.h b/runtime/verifier/method_verifier-inl.h
index a7fa9f34d1..445a6ff7de 100644
--- a/runtime/verifier/method_verifier-inl.h
+++ b/runtime/verifier/method_verifier-inl.h
@@ -19,7 +19,8 @@
#include "method_verifier.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "handle_scope-inl.h"
#include "mirror/class_loader.h"
#include "mirror/dex_cache.h"
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index c6ba2f7e43..2183b60b1e 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -22,17 +22,19 @@
#include "art_field-inl.h"
#include "art_method-inl.h"
+#include "base/aborting.h"
#include "base/enums.h"
-#include "base/logging.h"
+#include "base/logging.h" // For VLOG.
#include "base/mutex-inl.h"
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
#include "class_linker.h"
#include "compiler_callbacks.h"
-#include "dex_file-inl.h"
-#include "dex_instruction-inl.h"
-#include "dex_instruction_utils.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_exception_helpers.h"
+#include "dex/dex_instruction-inl.h"
+#include "dex/dex_instruction_utils.h"
#include "experimental_flags.h"
#include "gc/accounting/card_table-inl.h"
#include "handle_scope-inl.h"
@@ -46,6 +48,7 @@
#include "mirror/method_type.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "mirror/var_handle.h"
#include "reg_type-inl.h"
#include "register_line-inl.h"
#include "runtime.h"
@@ -61,8 +64,6 @@ namespace verifier {
using android::base::StringPrintf;
static constexpr bool kTimeVerifyMethod = !kIsDebugBuild;
-static constexpr bool kDebugVerify = false;
-// TODO: Add a constant to method_verifier to turn on verbose logging?
// On VLOG(verifier), should we dump the whole state when we run into a hard failure?
static constexpr bool kDumpRegLinesOnHardFailureIfVLOG = true;
@@ -231,7 +232,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethods(Thread* self,
previous_method_idx = method_idx;
InvokeType type = it->GetMethodInvokeType(class_def);
ArtMethod* method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- *dex_file, method_idx, dex_cache, class_loader, nullptr, type);
+ method_idx, dex_cache, class_loader, /* referrer */ nullptr, type);
if (method == nullptr) {
DCHECK(self->IsExceptionPending());
// We couldn't resolve the method, but continue regardless.
@@ -284,7 +285,7 @@ FailureKind MethodVerifier::VerifyClass(Thread* self,
bool allow_soft_failures,
HardFailLogMode log_level,
std::string* error) {
- ScopedTrace trace(__FUNCTION__);
+ SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
// A class must not be abstract and final.
if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) {
@@ -351,13 +352,13 @@ FailureKind MethodVerifier::VerifyClass(Thread* self,
}
}
-static bool IsLargeMethod(const DexFile::CodeItem* const code_item) {
- if (code_item == nullptr) {
+static bool IsLargeMethod(const CodeItemDataAccessor& accessor) {
+ if (!accessor.HasCodeItem()) {
return false;
}
- uint16_t registers_size = code_item->registers_size_;
- uint32_t insns_size = code_item->insns_size_in_code_units_;
+ uint16_t registers_size = accessor.RegistersSize();
+ uint32_t insns_size = accessor.InsnsSizeInCodeUnits();
return registers_size * insns_size > 4*1024*1024;
}
@@ -408,6 +409,10 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
verifier.DumpFailures(VLOG_STREAM(verifier) << "Soft verification failures in "
<< dex_file->PrettyMethod(method_idx) << "\n");
}
+ if (VLOG_IS_ON(verifier_debug)) {
+ std::cout << "\n" << verifier.info_messages_.str();
+ verifier.Dump(std::cout);
+ }
result.kind = FailureKind::kSoftFailure;
if (method != nullptr &&
!CanCompilerHandleVerificationFailure(verifier.encountered_failure_types_)) {
@@ -481,7 +486,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
callbacks->ClassRejected(ref);
}
}
- if (VLOG_IS_ON(verifier)) {
+ if (VLOG_IS_ON(verifier) || VLOG_IS_ON(verifier_debug)) {
std::cout << "\n" << verifier.info_messages_.str();
verifier.Dump(std::cout);
}
@@ -491,7 +496,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
if (duration_ns > MsToNs(100)) {
LOG(WARNING) << "Verification of " << dex_file->PrettyMethod(method_idx)
<< " took " << PrettyDuration(duration_ns)
- << (IsLargeMethod(code_item) ? " (large method)" : "");
+ << (IsLargeMethod(verifier.CodeItem()) ? " (large method)" : "");
}
}
result.types = verifier.encountered_failure_types_;
@@ -564,7 +569,7 @@ MethodVerifier::MethodVerifier(Thread* self,
dex_cache_(dex_cache),
class_loader_(class_loader),
class_def_(class_def),
- code_item_accessor_(CodeItemDataAccessor::CreateNullable(dex_file, code_item)),
+ code_item_accessor_(dex_file, code_item),
declaring_class_(nullptr),
interesting_dex_pc_(-1),
monitor_enter_dex_pcs_(nullptr),
@@ -832,7 +837,7 @@ bool MethodVerifier::Verify() {
return false;
} else {
uint32_t access_flag_options = kAccPublic;
- if (dex_file_->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+ if (dex_file_->SupportsDefaultMethods()) {
access_flag_options |= kAccPrivate;
}
if (!(method_access_flags_ & access_flag_options)) {
@@ -1074,9 +1079,8 @@ bool MethodVerifier::ScanTryCatchBlocks() {
// Ensure exception types are resolved so that they don't need resolution to be delivered,
// unresolved exception types will be ignored by exception delivery
if (iterator.GetHandlerTypeIndex().IsValid()) {
- mirror::Class* exception_type = linker->ResolveType(*dex_file_,
- iterator.GetHandlerTypeIndex(),
- dex_cache_, class_loader_);
+ ObjPtr<mirror::Class> exception_type =
+ linker->ResolveType(iterator.GetHandlerTypeIndex(), dex_cache_, class_loader_);
if (exception_type == nullptr) {
DCHECK(self_->IsExceptionPending());
self_->ClearException();
@@ -1935,7 +1939,7 @@ bool MethodVerifier::CodeFlowVerifyMethod() {
GetInstructionFlags(insn_idx).ClearChanged();
}
- if (kDebugVerify) {
+ if (UNLIKELY(VLOG_IS_ON(verifier_debug))) {
/*
* Scan for dead code. There's nothing "evil" about dead code
* (besides the wasted space), but it indicates a flaw somewhere
@@ -2079,7 +2083,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
int32_t branch_target = 0;
bool just_set_result = false;
- if (kDebugVerify) {
+ if (UNLIKELY(VLOG_IS_ON(verifier_debug))) {
// Generate processing back trace to debug verifier
LogVerifyInfo() << "Processing " << inst->DumpString(dex_file_) << "\n"
<< work_line_->Dump(this) << "\n";
@@ -2237,7 +2241,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-object not expected";
} else {
/* return_type is the *expected* return type, not register value */
- DCHECK(!return_type.IsZero());
+ DCHECK(!return_type.IsZeroOrNull());
DCHECK(!return_type.IsUninitializedReference());
const uint32_t vregA = inst->VRegA_11x();
const RegType& reg_type = work_line_->GetRegisterType(this, vregA);
@@ -2431,8 +2435,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
const RegType& res_type = ResolveClass<CheckAccess::kYes>(type_idx);
if (res_type.IsConflict()) {
// If this is a primitive type, fail HARD.
- ObjPtr<mirror::Class> klass =
- ClassLinker::LookupResolvedType(type_idx, dex_cache_.Get(), class_loader_.Get());
+ ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->LookupResolvedType(
+ type_idx, dex_cache_.Get(), class_loader_.Get());
if (klass != nullptr && klass->IsPrimitive()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "using primitive type "
<< dex_file_->StringByTypeIdx(type_idx) << " in instanceof in "
@@ -2485,7 +2489,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::ARRAY_LENGTH: {
const RegType& res_type = work_line_->GetRegisterType(this, inst->VRegB_12x());
if (res_type.IsReferenceTypes()) {
- if (!res_type.IsArrayTypes() && !res_type.IsZero()) { // ie not an array or null
+ if (!res_type.IsArrayTypes() && !res_type.IsZeroOrNull()) {
+ // ie not an array or null
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type;
} else {
work_line_->SetRegisterType<LockOp::kClear>(this,
@@ -2592,7 +2597,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
/* Similar to the verification done for APUT */
const RegType& array_type = work_line_->GetRegisterType(this, inst->VRegA_31t());
/* array_type can be null if the reg type is Zero */
- if (!array_type.IsZero()) {
+ if (!array_type.IsZeroOrNull()) {
if (!array_type.IsArrayTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with array type "
<< array_type;
@@ -2632,7 +2637,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
const RegType& reg_type1 = work_line_->GetRegisterType(this, inst->VRegA_22t());
const RegType& reg_type2 = work_line_->GetRegisterType(this, inst->VRegB_22t());
bool mismatch = false;
- if (reg_type1.IsZero()) { // zero then integral or reference expected
+ if (reg_type1.IsZeroOrNull()) { // zero then integral or reference expected
mismatch = !reg_type2.IsReferenceTypes() && !reg_type2.IsIntegralTypes();
} else if (reg_type1.IsReferenceTypes()) { // both references?
mismatch = !reg_type2.IsReferenceTypes();
@@ -2717,7 +2722,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
!cast_type.IsUnresolvedTypes() && !orig_type.IsUnresolvedTypes() &&
cast_type.HasClass() && // Could be conflict type, make sure it has a class.
!cast_type.GetClass()->IsInterface() &&
- (orig_type.IsZero() ||
+ (orig_type.IsZeroOrNull() ||
orig_type.IsStrictlyAssignableFrom(
cast_type.Merge(orig_type, &reg_types_, this), this))) {
RegisterLine* update_line = RegisterLine::Create(code_item_accessor_.RegistersSize(),
@@ -3005,7 +3010,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
break;
/* no null refs allowed (?) */
- if (this_type.IsZero()) {
+ if (this_type.IsZeroOrNull()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unable to initialize null ref";
break;
}
@@ -3082,7 +3087,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* interface or Object (see comments in RegType::JoinClass).
*/
const RegType& this_type = work_line_->GetInvocationThis(this, inst);
- if (this_type.IsZero()) {
+ if (this_type.IsZeroOrNull()) {
/* null pointer always passes (and always fails at runtime) */
} else {
if (this_type.IsUninitializedTypes()) {
@@ -3137,6 +3142,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
if (!CheckSignaturePolymorphicMethod(called_method) ||
!CheckSignaturePolymorphicReceiver(inst)) {
+ DCHECK(HasFailures());
break;
}
const uint32_t proto_idx = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc();
@@ -3627,7 +3633,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
bool has_catch_all_handler = false;
const DexFile::TryItem* try_item = code_item_accessor_.FindTryItem(work_insn_idx_);
CHECK(try_item != nullptr);
- CatchHandlerIterator iterator(code_item_accessor_.GetCatchHandlerData(try_item->handler_off_));
+ CatchHandlerIterator iterator(code_item_accessor_, *try_item);
// Need the linker to try and resolve the handled class to check if it's Throwable.
ClassLinker* linker = Runtime::Current()->GetClassLinker();
@@ -3638,8 +3644,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
has_catch_all_handler = true;
} else {
// It is also a catch-all if it is java.lang.Throwable.
- mirror::Class* klass = linker->ResolveType(*dex_file_, handler_type_idx, dex_cache_,
- class_loader_);
+ ObjPtr<mirror::Class> klass =
+ linker->ResolveType(handler_type_idx, dex_cache_, class_loader_);
if (klass != nullptr) {
if (klass == mirror::Throwable::GetJavaLangThrowable()) {
has_catch_all_handler = true;
@@ -3757,16 +3763,16 @@ void MethodVerifier::UninstantiableError(const char* descriptor) {
<< "non-instantiable klass " << descriptor;
}
-inline bool MethodVerifier::IsInstantiableOrPrimitive(mirror::Class* klass) {
+inline bool MethodVerifier::IsInstantiableOrPrimitive(ObjPtr<mirror::Class> klass) {
return klass->IsInstantiable() || klass->IsPrimitive();
}
template <MethodVerifier::CheckAccess C>
const RegType& MethodVerifier::ResolveClass(dex::TypeIndex class_idx) {
- mirror::Class* klass = can_load_classes_
- ? Runtime::Current()->GetClassLinker()->ResolveType(
- *dex_file_, class_idx, dex_cache_, class_loader_)
- : ClassLinker::LookupResolvedType(class_idx, dex_cache_.Get(), class_loader_.Get()).Ptr();
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ ObjPtr<mirror::Class> klass = can_load_classes_
+ ? linker->ResolveType(class_idx, dex_cache_, class_loader_)
+ : linker->LookupResolvedType(class_idx, dex_cache_.Get(), class_loader_.Get());
if (can_load_classes_ && klass == nullptr) {
DCHECK(self_->IsExceptionPending());
self_->ClearException();
@@ -3779,10 +3785,10 @@ const RegType& MethodVerifier::ResolveClass(dex::TypeIndex class_idx) {
UninstantiableError(descriptor);
precise = false;
}
- result = reg_types_.FindClass(klass, precise);
+ result = reg_types_.FindClass(klass.Ptr(), precise);
if (result == nullptr) {
const char* descriptor = dex_file_->StringByTypeIdx(class_idx);
- result = reg_types_.InsertClass(descriptor, klass, precise);
+ result = reg_types_.InsertClass(descriptor, klass.Ptr(), precise);
}
} else {
const char* descriptor = dex_file_->StringByTypeIdx(class_idx);
@@ -3797,7 +3803,7 @@ const RegType& MethodVerifier::ResolveClass(dex::TypeIndex class_idx) {
}
// Record result of class resolution attempt.
- VerifierDeps::MaybeRecordClassResolution(*dex_file_, class_idx, klass);
+ VerifierDeps::MaybeRecordClassResolution(*dex_file_, class_idx, klass.Ptr());
// If requested, check if access is allowed. Unresolved types are included in this check, as the
// interpreter only tests whether access is allowed when a class is not pre-verified and runs in
@@ -3961,10 +3967,10 @@ ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(
// while this check implies an IncompatibleClassChangeError.
if (klass->IsInterface()) {
// methods called on interfaces should be invoke-interface, invoke-super, invoke-direct (if
- // dex file version is 37 or greater), or invoke-static.
+ // default methods are supported for the dex file), or invoke-static.
if (method_type != METHOD_INTERFACE &&
method_type != METHOD_STATIC &&
- ((dex_file_->GetVersion() < DexFile::kDefaultMethodsVersion) ||
+ (!dex_file_->SupportsDefaultMethods() ||
method_type != METHOD_DIRECT) &&
method_type != METHOD_SUPER) {
Fail(VERIFY_ERROR_CLASS_CHANGE)
@@ -4081,7 +4087,7 @@ ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator(
const RegType& adjusted_type = is_init
? GetRegTypeCache()->FromUninitialized(actual_arg_type)
: actual_arg_type;
- if (method_type != METHOD_INTERFACE && !adjusted_type.IsZero()) {
+ if (method_type != METHOD_INTERFACE && !adjusted_type.IsZeroOrNull()) {
const RegType* res_method_class;
// Miranda methods have the declaring interface as their declaring class, not the abstract
// class. It would be wrong to use this for the type check (interface type checks are
@@ -4414,14 +4420,20 @@ ArtMethod* MethodVerifier::VerifyInvocationArgs(
bool MethodVerifier::CheckSignaturePolymorphicMethod(ArtMethod* method) {
mirror::Class* klass = method->GetDeclaringClass();
- if (klass != mirror::MethodHandle::StaticClass()) {
+ const char* method_name = method->GetName();
+
+ const char* expected_return_descriptor;
+ if (klass == mirror::MethodHandle::StaticClass()) {
+ expected_return_descriptor = mirror::MethodHandle::GetReturnTypeDescriptor(method_name);
+ } else if (klass == mirror::VarHandle::StaticClass()) {
+ expected_return_descriptor = mirror::VarHandle::GetReturnTypeDescriptor(method_name);
+ } else {
Fail(VERIFY_ERROR_BAD_CLASS_HARD)
- << "Signature polymorphic method must be declared in java.lang.invoke.MethodClass";
+ << "Signature polymorphic method in unsuppported class: " << klass->PrettyDescriptor();
return false;
}
- const char* method_name = method->GetName();
- if (strcmp(method_name, "invoke") != 0 && strcmp(method_name, "invokeExact") != 0) {
+ if (expected_return_descriptor == nullptr) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD)
<< "Signature polymorphic method name invalid: " << method_name;
return false;
@@ -4443,9 +4455,10 @@ bool MethodVerifier::CheckSignaturePolymorphicMethod(ArtMethod* method) {
}
const char* return_descriptor = method->GetReturnTypeDescriptor();
- if (strcmp(return_descriptor, "Ljava/lang/Object;") != 0) {
+ if (strcmp(return_descriptor, expected_return_descriptor) != 0) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD)
- << "Signature polymorphic method has unexpected return type: " << return_descriptor;
+ << "Signature polymorphic method has unexpected return type: " << return_descriptor
+ << " != " << expected_return_descriptor;
return false;
}
@@ -4454,7 +4467,7 @@ bool MethodVerifier::CheckSignaturePolymorphicMethod(ArtMethod* method) {
bool MethodVerifier::CheckSignaturePolymorphicReceiver(const Instruction* inst) {
const RegType& this_type = work_line_->GetInvocationThis(this, inst);
- if (this_type.IsZero()) {
+ if (this_type.IsZeroOrNull()) {
/* null pointer always passes (and always fails at run time) */
return true;
} else if (!this_type.IsNonZeroReferenceTypes()) {
@@ -4472,9 +4485,10 @@ bool MethodVerifier::CheckSignaturePolymorphicReceiver(const Instruction* inst)
<< "invoke-polymorphic receiver has no class: "
<< this_type;
return false;
- } else if (!this_type.GetClass()->IsSubClass(mirror::MethodHandle::StaticClass())) {
+ } else if (!this_type.GetClass()->IsSubClass(mirror::MethodHandle::StaticClass()) &&
+ !this_type.GetClass()->IsSubClass(mirror::VarHandle::StaticClass())) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD)
- << "invoke-polymorphic receiver is not a subclass of MethodHandle: "
+ << "invoke-polymorphic receiver is not a subclass of MethodHandle or VarHandle: "
<< this_type;
return false;
}
@@ -4573,7 +4587,7 @@ ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst,
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "'this' arg must be initialized";
return nullptr;
}
- if (!actual_arg_type.IsZero()) {
+ if (!actual_arg_type.IsZeroOrNull()) {
mirror::Class* klass = res_method->GetDeclaringClass();
std::string temp;
const RegType& res_method_class =
@@ -4689,13 +4703,20 @@ void MethodVerifier::VerifyAGet(const Instruction* inst,
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
} else {
const RegType& array_type = work_line_->GetRegisterType(this, inst->VRegB_23x());
- if (array_type.IsZero()) {
- have_pending_runtime_throw_failure_ = true;
+ if (array_type.IsZeroOrNull()) {
// Null array class; this code path will fail at runtime. Infer a merge-able type from the
- // instruction type. TODO: have a proper notion of bottom here.
- if (!is_primitive || insn_type.IsCategory1Types()) {
- // Reference or category 1
- work_line_->SetRegisterType<LockOp::kClear>(this, inst->VRegA_23x(), reg_types_.Zero());
+ // instruction type.
+ if (!is_primitive) {
+ work_line_->SetRegisterType<LockOp::kClear>(this, inst->VRegA_23x(), reg_types_.Null());
+ } else if (insn_type.IsInteger()) {
+ // Pick a non-zero constant (to distinguish with null) that can fit in any primitive.
+ // We cannot use 'insn_type' as it could be a float array or an int array.
+ work_line_->SetRegisterType<LockOp::kClear>(
+ this, inst->VRegA_23x(), DetermineCat1Constant(1, need_precise_constants_));
+ } else if (insn_type.IsCategory1Types()) {
+ // Category 1
+ // The 'insn_type' is exactly the type we need.
+ work_line_->SetRegisterType<LockOp::kClear>(this, inst->VRegA_23x(), insn_type);
} else {
// Category 2
work_line_->SetRegisterTypeWide(this, inst->VRegA_23x(),
@@ -4804,7 +4825,7 @@ void MethodVerifier::VerifyAPut(const Instruction* inst,
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
} else {
const RegType& array_type = work_line_->GetRegisterType(this, inst->VRegB_23x());
- if (array_type.IsZero()) {
+ if (array_type.IsZeroOrNull()) {
// Null array type; this code path will fail at runtime.
// Still check that the given value matches the instruction's type.
// Note: this is, as usual, complicated by the fact the the instruction isn't fully typed
@@ -4873,7 +4894,7 @@ ArtField* MethodVerifier::GetStaticField(int field_idx) {
return nullptr; // Can't resolve Class so no more to do here, will do checking at runtime.
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- ArtField* field = class_linker->ResolveFieldJLS(*dex_file_, field_idx, dex_cache_, class_loader_);
+ ArtField* field = class_linker->ResolveFieldJLS(field_idx, dex_cache_, class_loader_);
// Record result of the field resolution attempt.
VerifierDeps::MaybeRecordFieldResolution(*dex_file_, field_idx, field);
@@ -4914,7 +4935,7 @@ ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int field_id
return nullptr; // Can't resolve Class so no more to do here
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- ArtField* field = class_linker->ResolveFieldJLS(*dex_file_, field_idx, dex_cache_, class_loader_);
+ ArtField* field = class_linker->ResolveFieldJLS(field_idx, dex_cache_, class_loader_);
// Record result of the field resolution attempt.
VerifierDeps::MaybeRecordFieldResolution(*dex_file_, field_idx, field);
@@ -4926,7 +4947,7 @@ ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int field_id
DCHECK(self_->IsExceptionPending());
self_->ClearException();
return nullptr;
- } else if (obj_type.IsZero()) {
+ } else if (obj_type.IsZeroOrNull()) {
// Cannot infer and check type, however, access will cause null pointer exception.
// Fall through into a few last soft failure checks below.
} else if (!obj_type.IsReferenceTypes()) {
@@ -5038,7 +5059,7 @@ void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const RegType&
}
ObjPtr<mirror::Class> field_type_class =
- can_load_classes_ ? field->ResolveType() : field->LookupType();
+ can_load_classes_ ? field->ResolveType() : field->LookupResolvedType();
if (field_type_class != nullptr) {
field_type = &FromClass(field->GetTypeDescriptor(),
field_type_class.Ptr(),
@@ -5154,10 +5175,11 @@ ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst, RegisterL
}
uint32_t field_offset = static_cast<uint32_t>(inst->VRegC_22c());
ArtField* const f = ArtField::FindInstanceFieldWithOffset(object_type.GetClass(), field_offset);
- DCHECK_EQ(f->GetOffset().Uint32Value(), field_offset);
if (f == nullptr) {
VLOG(verifier) << "Failed to find instance field at offset '" << field_offset
<< "' from '" << mirror::Class::PrettyDescriptor(object_type.GetClass()) << "'";
+ } else {
+ DCHECK_EQ(f->GetOffset().Uint32Value(), field_offset);
}
return f;
}
@@ -5186,7 +5208,7 @@ void MethodVerifier::VerifyQuickFieldAccess(const Instruction* inst, const RegTy
const RegType* field_type;
{
ObjPtr<mirror::Class> field_type_class =
- can_load_classes_ ? field->ResolveType() : field->LookupType();
+ can_load_classes_ ? field->ResolveType() : field->LookupResolvedType();
if (field_type_class != nullptr) {
field_type = &FromClass(field->GetTypeDescriptor(),
@@ -5341,7 +5363,7 @@ bool MethodVerifier::UpdateRegisters(uint32_t next_insn, RegisterLine* merge_lin
}
} else {
RegisterLineArenaUniquePtr copy;
- if (kDebugVerify) {
+ if (UNLIKELY(VLOG_IS_ON(verifier_debug))) {
copy.reset(RegisterLine::Create(target_line->NumRegs(), this));
copy->CopyFromLine(target_line);
}
@@ -5349,7 +5371,7 @@ bool MethodVerifier::UpdateRegisters(uint32_t next_insn, RegisterLine* merge_lin
if (have_pending_hard_failure_) {
return false;
}
- if (kDebugVerify && changed) {
+ if (UNLIKELY(VLOG_IS_ON(verifier_debug)) && changed) {
LogVerifyInfo() << "Merging at [" << reinterpret_cast<void*>(work_insn_idx_) << "]"
<< " to [" << reinterpret_cast<void*>(next_insn) << "]: " << "\n"
<< copy->Dump(this) << " MERGE\n"
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index c885914633..cadf4eb0ba 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -25,9 +25,9 @@
#include "base/macros.h"
#include "base/scoped_arena_containers.h"
#include "base/value_object.h"
-#include "code_item_accessors.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/code_item_accessors.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
#include "handle.h"
#include "instruction_flags.h"
#include "method_reference.h"
@@ -127,10 +127,6 @@ class MethodVerifier {
return *dex_file_;
}
- uint32_t DexFileVersion() const {
- return dex_file_->GetVersion();
- }
-
RegTypeCache* GetRegTypeCache() {
return &reg_types_;
}
@@ -257,7 +253,8 @@ class MethodVerifier {
REQUIRES_SHARED(Locks::mutator_lock_);
void UninstantiableError(const char* descriptor);
- static bool IsInstantiableOrPrimitive(mirror::Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+ static bool IsInstantiableOrPrimitive(ObjPtr<mirror::Class> klass)
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Is the method being verified a constructor? See the comment on the field.
bool IsConstructor() const {
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index d9874677e8..97c1b62abe 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -23,7 +23,7 @@
#include "class_linker-inl.h"
#include "common_runtime_test.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "scoped_thread_state_change-inl.h"
#include "utils.h"
#include "verifier_enums.h"
diff --git a/runtime/verifier/reg_type-inl.h b/runtime/verifier/reg_type-inl.h
index 631c6bd7ef..f719782727 100644
--- a/runtime/verifier/reg_type-inl.h
+++ b/runtime/verifier/reg_type-inl.h
@@ -29,6 +29,8 @@ namespace art {
namespace verifier {
inline bool RegType::CanAccess(const RegType& other) const {
+ DCHECK(IsReferenceTypes());
+ DCHECK(!IsNull());
if (Equals(other)) {
return true; // Trivial accessibility.
} else {
@@ -45,9 +47,13 @@ inline bool RegType::CanAccess(const RegType& other) const {
}
inline bool RegType::CanAccessMember(ObjPtr<mirror::Class> klass, uint32_t access_flags) const {
+ DCHECK(IsReferenceTypes());
if ((access_flags & kAccPublic) != 0) {
return true;
}
+ if (IsNull()) {
+ return true;
+ }
if (!IsUnresolvedTypes()) {
return GetClass()->CanAccessMember(klass, access_flags);
} else {
@@ -92,7 +98,7 @@ inline bool RegType::AssignableFrom(const RegType& lhs,
LOG(WARNING) << "RegType::AssignableFrom lhs is Conflict!";
return false;
case AssignmentType::kReference:
- if (rhs.IsZero()) {
+ if (rhs.IsZeroOrNull()) {
return true; // All reference types can be assigned null.
} else if (!rhs.IsReferenceTypes()) {
return false; // Expect rhs to be a reference type.
@@ -119,6 +125,7 @@ inline bool RegType::AssignableFrom(const RegType& lhs,
return result;
} else {
// Unresolved types are only assignable for null and equality.
+ // Null cannot be the left-hand side.
return false;
}
case AssignmentType::kNotAssignable:
@@ -199,6 +206,11 @@ inline const UndefinedType* UndefinedType::GetInstance() {
return instance_;
}
+inline const NullType* NullType::GetInstance() {
+ DCHECK(instance_ != nullptr);
+ return instance_;
+}
+
inline void* RegType::operator new(size_t size, ScopedArenaAllocator* allocator) {
return allocator->Alloc(size, kArenaAllocMisc);
}
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 8df2e0f50b..7ebdd90fc0 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -22,7 +22,7 @@
#include "base/bit_vector-inl.h"
#include "base/casts.h"
#include "class_linker-inl.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "method_verifier.h"
#include "mirror/class-inl.h"
#include "mirror/class.h"
@@ -51,6 +51,7 @@ const LongHiType* LongHiType::instance_ = nullptr;
const DoubleLoType* DoubleLoType::instance_ = nullptr;
const DoubleHiType* DoubleHiType::instance_ = nullptr;
const IntegerType* IntegerType::instance_ = nullptr;
+const NullType* NullType::instance_ = nullptr;
PrimitiveType::PrimitiveType(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id)
: RegType(klass, descriptor, cache_id) {
@@ -581,6 +582,10 @@ static const RegType& SelectNonConstant(const RegType& a, const RegType& b) {
return a.IsConstantTypes() ? b : a;
}
+static const RegType& SelectNonConstant2(const RegType& a, const RegType& b) {
+ return a.IsConstantTypes() ? (b.IsZero() ? a : b) : a;
+}
+
const RegType& RegType::Merge(const RegType& incoming_type,
RegTypeCache* reg_types,
MethodVerifier* verifier) const {
@@ -695,8 +700,8 @@ const RegType& RegType::Merge(const RegType& incoming_type,
// special. They may only ever be merged with themselves (must be taken care of by the
// caller of Merge(), see the DCHECK on entry). So mark any other merge as conflicting here.
return conflict;
- } else if (IsZero() || incoming_type.IsZero()) {
- return SelectNonConstant(*this, incoming_type); // 0 MERGE ref => ref
+ } else if (IsZeroOrNull() || incoming_type.IsZeroOrNull()) {
+ return SelectNonConstant2(*this, incoming_type); // 0 MERGE ref => ref
} else if (IsJavaLangObject() || incoming_type.IsJavaLangObject()) {
return reg_types->JavaLangObject(false); // Object MERGE ref => Object
} else if (IsUnresolvedTypes() || incoming_type.IsUnresolvedTypes()) {
@@ -965,6 +970,21 @@ bool RegType::CanAssignArray(const RegType& src,
return cmp1.CanAssignArray(cmp2, reg_types, class_loader, verifier, soft_error);
}
+const NullType* NullType::CreateInstance(mirror::Class* klass,
+ const StringPiece& descriptor,
+ uint16_t cache_id) {
+ CHECK(instance_ == nullptr);
+ instance_ = new NullType(klass, descriptor, cache_id);
+ return instance_;
+}
+
+void NullType::Destroy() {
+ if (NullType::instance_ != nullptr) {
+ delete instance_;
+ instance_ = nullptr;
+ }
+}
+
} // namespace verifier
} // namespace art
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index a2085a3f09..9055849ca0 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -129,8 +129,12 @@ class RegType {
virtual bool IsConstantShort() const { return false; }
virtual bool IsOne() const { return false; }
virtual bool IsZero() const { return false; }
+ virtual bool IsNull() const { return false; }
bool IsReferenceTypes() const {
- return IsNonZeroReferenceTypes() || IsZero();
+ return IsNonZeroReferenceTypes() || IsZero() || IsNull();
+ }
+ bool IsZeroOrNull() const {
+ return IsZero() || IsNull();
}
virtual bool IsNonZeroReferenceTypes() const { return false; }
bool IsCategory1Types() const {
@@ -857,6 +861,46 @@ class ImpreciseConstHiType FINAL : public ConstantType {
}
};
+// Special "null" type that captures the semantics of null / bottom.
+class NullType FINAL : public RegType {
+ public:
+ bool IsNull() const OVERRIDE {
+ return true;
+ }
+
+ // Get the singleton Null instance.
+ static const NullType* GetInstance() PURE;
+
+ // Create the singleton instance.
+ static const NullType* CreateInstance(mirror::Class* klass,
+ const StringPiece& descriptor,
+ uint16_t cache_id)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static void Destroy();
+
+ std::string Dump() const OVERRIDE {
+ return "null";
+ }
+
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kReference;
+ }
+
+ bool IsConstantTypes() const OVERRIDE {
+ return true;
+ }
+
+ private:
+ NullType(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ : RegType(klass, descriptor, cache_id) {
+ CheckConstructorInvariants(this);
+ }
+
+ static const NullType* instance_;
+};
+
// Common parent of all uninitialized types. Uninitialized types are created by
// "new" dex
// instructions and must be passed to a constructor.
diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h
index 197c97671e..61f34afdac 100644
--- a/runtime/verifier/reg_type_cache-inl.h
+++ b/runtime/verifier/reg_type_cache-inl.h
@@ -81,6 +81,9 @@ inline const UndefinedType& RegTypeCache::Undefined() {
inline const ConflictType& RegTypeCache::Conflict() {
return *ConflictType::GetInstance();
}
+inline const NullType& RegTypeCache::Null() {
+ return *NullType::GetInstance();
+}
inline const ImpreciseConstType& RegTypeCache::ByteConstant() {
const ConstantType& result = FromCat1Const(std::numeric_limits<jbyte>::min(), false);
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 0029eb90a3..5564684c4f 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -16,13 +16,16 @@
#include "reg_type_cache-inl.h"
+#include <type_traits>
+
+#include "base/aborting.h"
#include "base/arena_bit_vector.h"
#include "base/bit_vector-inl.h"
#include "base/casts.h"
#include "base/scoped_arena_allocator.h"
#include "base/stl_util.h"
#include "class_linker-inl.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "reg_type-inl.h"
@@ -51,8 +54,10 @@ ALWAYS_INLINE static inline bool MatchingPrecisionForClass(const RegType* entry,
}
void RegTypeCache::FillPrimitiveAndSmallConstantTypes() {
+ // Note: this must have the same order as CreatePrimitiveAndSmallConstantTypes.
entries_.push_back(UndefinedType::GetInstance());
entries_.push_back(ConflictType::GetInstance());
+ entries_.push_back(NullType::GetInstance());
entries_.push_back(BooleanType::GetInstance());
entries_.push_back(ByteType::GetInstance());
entries_.push_back(ShortType::GetInstance());
@@ -304,6 +309,7 @@ void RegTypeCache::ShutDown() {
FloatType::Destroy();
DoubleLoType::Destroy();
DoubleHiType::Destroy();
+ NullType::Destroy();
for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) {
const PreciseConstType* type = small_precise_constants_[value - kMinSmallConstant];
delete type;
@@ -314,33 +320,55 @@ void RegTypeCache::ShutDown() {
}
}
-template <class Type>
-const Type* RegTypeCache::CreatePrimitiveTypeInstance(const std::string& descriptor) {
- mirror::Class* klass = nullptr;
- // Try loading the class from linker.
- if (!descriptor.empty()) {
- klass = art::Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(),
- descriptor.c_str());
- DCHECK(klass != nullptr);
- }
- const Type* entry = Type::CreateInstance(klass, descriptor, RegTypeCache::primitive_count_);
- RegTypeCache::primitive_count_++;
- return entry;
-}
+// Helper for create_primitive_type_instance lambda.
+namespace {
+template <typename T>
+struct TypeHelper {
+ using type = T;
+ static_assert(std::is_convertible<T*, RegType*>::value, "T must be a RegType");
+
+ const char* descriptor;
+
+ explicit TypeHelper(const char* d) : descriptor(d) {}
+};
+} // namespace
void RegTypeCache::CreatePrimitiveAndSmallConstantTypes() {
- CreatePrimitiveTypeInstance<UndefinedType>("");
- CreatePrimitiveTypeInstance<ConflictType>("");
- CreatePrimitiveTypeInstance<BooleanType>("Z");
- CreatePrimitiveTypeInstance<ByteType>("B");
- CreatePrimitiveTypeInstance<ShortType>("S");
- CreatePrimitiveTypeInstance<CharType>("C");
- CreatePrimitiveTypeInstance<IntegerType>("I");
- CreatePrimitiveTypeInstance<LongLoType>("J");
- CreatePrimitiveTypeInstance<LongHiType>("J");
- CreatePrimitiveTypeInstance<FloatType>("F");
- CreatePrimitiveTypeInstance<DoubleLoType>("D");
- CreatePrimitiveTypeInstance<DoubleHiType>("D");
+ // Note: this must have the same order as FillPrimitiveAndSmallConstantTypes.
+
+ // It is acceptable to pass on the const char* in type to CreateInstance, as all calls below are
+ // with compile-time constants that will have global lifetime. Use of the lambda ensures this
+ // code cannot leak to other users.
+ auto create_primitive_type_instance = [&](auto type) REQUIRES_SHARED(Locks::mutator_lock_) {
+ using Type = typename decltype(type)::type;
+ mirror::Class* klass = nullptr;
+ // Try loading the class from linker.
+ DCHECK(type.descriptor != nullptr);
+ if (strlen(type.descriptor) > 0) {
+ klass = art::Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(),
+ type.descriptor);
+ DCHECK(klass != nullptr);
+ }
+ const Type* entry = Type::CreateInstance(klass,
+ type.descriptor,
+ RegTypeCache::primitive_count_);
+ RegTypeCache::primitive_count_++;
+ return entry;
+ };
+ create_primitive_type_instance(TypeHelper<UndefinedType>(""));
+ create_primitive_type_instance(TypeHelper<ConflictType>(""));
+ create_primitive_type_instance(TypeHelper<NullType>(""));
+ create_primitive_type_instance(TypeHelper<BooleanType>("Z"));
+ create_primitive_type_instance(TypeHelper<ByteType>("B"));
+ create_primitive_type_instance(TypeHelper<ShortType>("S"));
+ create_primitive_type_instance(TypeHelper<CharType>("C"));
+ create_primitive_type_instance(TypeHelper<IntegerType>("I"));
+ create_primitive_type_instance(TypeHelper<LongLoType>("J"));
+ create_primitive_type_instance(TypeHelper<LongHiType>("J"));
+ create_primitive_type_instance(TypeHelper<FloatType>("F"));
+ create_primitive_type_instance(TypeHelper<DoubleLoType>("D"));
+ create_primitive_type_instance(TypeHelper<DoubleHiType>("D"));
+
for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) {
PreciseConstType* type = new PreciseConstType(value, primitive_count_);
small_precise_constants_[value - kMinSmallConstant] = type;
@@ -396,6 +424,9 @@ const RegType& RegTypeCache::FromUnresolvedMerge(const RegType& left,
if (resolved_parts_merged.IsConflict()) {
return Conflict();
}
+ if (resolved_parts_merged.IsJavaLangObject()) {
+ return resolved_parts_merged;
+ }
bool resolved_merged_is_array = resolved_parts_merged.IsArrayTypes();
if (left_unresolved_is_array || right_unresolved_is_array || resolved_merged_is_array) {
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index d0907564e2..52776766bc 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -49,6 +49,7 @@ class IntegerType;
class LongHiType;
class LongLoType;
class MethodVerifier;
+class NullType;
class PreciseConstType;
class PreciseReferenceType;
class RegType;
@@ -123,6 +124,7 @@ class RegTypeCache {
const DoubleHiType& DoubleHi() REQUIRES_SHARED(Locks::mutator_lock_);
const UndefinedType& Undefined() REQUIRES_SHARED(Locks::mutator_lock_);
const ConflictType& Conflict();
+ const NullType& Null();
const PreciseReferenceType& JavaLangClass() REQUIRES_SHARED(Locks::mutator_lock_);
const PreciseReferenceType& JavaLangString() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -171,9 +173,6 @@ class RegTypeCache {
// verifier.
StringPiece AddString(const StringPiece& string_piece);
- template <class Type>
- static const Type* CreatePrimitiveTypeInstance(const std::string& descriptor)
- REQUIRES_SHARED(Locks::mutator_lock_);
static void CreatePrimitiveAndSmallConstantTypes() REQUIRES_SHARED(Locks::mutator_lock_);
// A quick look up for popular small constants.
@@ -183,7 +182,7 @@ class RegTypeCache {
kMinSmallConstant + 1];
static constexpr size_t kNumPrimitivesAndSmallConstants =
- 12 + (kMaxSmallConstant - kMinSmallConstant + 1);
+ 13 + (kMaxSmallConstant - kMinSmallConstant + 1);
// Have the well known global primitives been created?
static bool primitive_initialized_;
diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc
index 1bc48ed71b..15a38f3fd7 100644
--- a/runtime/verifier/reg_type_test.cc
+++ b/runtime/verifier/reg_type_test.cc
@@ -664,6 +664,368 @@ TEST_F(RegTypeTest, MergingDouble) {
}
}
+TEST_F(RegTypeTest, MergeSemiLatticeRef) {
+ // (Incomplete) semilattice:
+ //
+ // Excluded for now: * category-2 types
+ // * interfaces
+ // * all of category-1 primitive types, including constants.
+ // This is to demonstrate/codify the reference side, mostly.
+ //
+ // Note: It is not a real semilattice because int = float makes this wonky. :-(
+ //
+ // Conflict
+ // |
+ // #---------#--------------------------#-----------------------------#
+ // | | |
+ // | | Object
+ // | | |
+ // int uninit types #---------------#--------#------------------#---------#
+ // | | | | | |
+ // | unresolved-merge-types | Object[] char[] byte[]
+ // | | | | | | | |
+ // | unresolved-types | #------Number #---------# | |
+ // | | | | | | | |
+ // | | #--------Integer Number[] Number[][] | |
+ // | | | | | | |
+ // | #---------------#--------#---------#--------#---------#
+ // | |
+ // | null
+ // | |
+ // #--------------------------#----------------------------#
+ // |
+ // 0
+
+ ArenaStack stack(Runtime::Current()->GetArenaPool());
+ ScopedArenaAllocator allocator(&stack);
+ ScopedObjectAccess soa(Thread::Current());
+
+ // We cannot allow moving GC. Otherwise we'd have to ensure the reg types are updated (reference
+ // reg types store a class pointer in a GCRoot, which is normally updated through active verifiers
+ // being registered with their thread), which is unnecessarily complex.
+ Runtime::Current()->GetHeap()->IncrementDisableMovingGC(soa.Self());
+
+ RegTypeCache cache(true, allocator);
+
+ const RegType& conflict = cache.Conflict();
+ const RegType& zero = cache.Zero();
+ const RegType& null = cache.Null();
+ const RegType& int_type = cache.Integer();
+
+ const RegType& obj = cache.JavaLangObject(false);
+ const RegType& obj_arr = cache.From(nullptr, "[Ljava/lang/Object;", false);
+ ASSERT_FALSE(obj_arr.IsUnresolvedReference());
+
+ const RegType& unresolved_a = cache.From(nullptr, "Ldoes/not/resolve/A;", false);
+ ASSERT_TRUE(unresolved_a.IsUnresolvedReference());
+ const RegType& unresolved_b = cache.From(nullptr, "Ldoes/not/resolve/B;", false);
+ ASSERT_TRUE(unresolved_b.IsUnresolvedReference());
+ const RegType& unresolved_ab = cache.FromUnresolvedMerge(unresolved_a, unresolved_b, nullptr);
+ ASSERT_TRUE(unresolved_ab.IsUnresolvedMergedReference());
+
+ const RegType& uninit_this = cache.UninitializedThisArgument(obj);
+ const RegType& uninit_obj_0 = cache.Uninitialized(obj, 0u);
+ const RegType& uninit_obj_1 = cache.Uninitialized(obj, 1u);
+
+ const RegType& uninit_unres_this = cache.UninitializedThisArgument(unresolved_a);
+ const RegType& uninit_unres_a_0 = cache.Uninitialized(unresolved_a, 0);
+ const RegType& uninit_unres_b_0 = cache.Uninitialized(unresolved_b, 0);
+
+ const RegType& number = cache.From(nullptr, "Ljava/lang/Number;", false);
+ ASSERT_FALSE(number.IsUnresolvedReference());
+ const RegType& integer = cache.From(nullptr, "Ljava/lang/Integer;", false);
+ ASSERT_FALSE(integer.IsUnresolvedReference());
+
+ const RegType& uninit_number_0 = cache.Uninitialized(number, 0u);
+ const RegType& uninit_integer_0 = cache.Uninitialized(integer, 0u);
+
+ const RegType& number_arr = cache.From(nullptr, "[Ljava/lang/Number;", false);
+ ASSERT_FALSE(number_arr.IsUnresolvedReference());
+ const RegType& integer_arr = cache.From(nullptr, "[Ljava/lang/Integer;", false);
+ ASSERT_FALSE(integer_arr.IsUnresolvedReference());
+
+ const RegType& number_arr_arr = cache.From(nullptr, "[[Ljava/lang/Number;", false);
+ ASSERT_FALSE(number_arr_arr.IsUnresolvedReference());
+
+ const RegType& char_arr = cache.From(nullptr, "[C", false);
+ ASSERT_FALSE(char_arr.IsUnresolvedReference());
+ const RegType& byte_arr = cache.From(nullptr, "[B", false);
+ ASSERT_FALSE(byte_arr.IsUnresolvedReference());
+
+ const RegType& unresolved_a_num = cache.FromUnresolvedMerge(unresolved_a, number, nullptr);
+ ASSERT_TRUE(unresolved_a_num.IsUnresolvedMergedReference());
+ const RegType& unresolved_b_num = cache.FromUnresolvedMerge(unresolved_b, number, nullptr);
+ ASSERT_TRUE(unresolved_b_num.IsUnresolvedMergedReference());
+ const RegType& unresolved_ab_num = cache.FromUnresolvedMerge(unresolved_ab, number, nullptr);
+ ASSERT_TRUE(unresolved_ab_num.IsUnresolvedMergedReference());
+
+ const RegType& unresolved_a_int = cache.FromUnresolvedMerge(unresolved_a, integer, nullptr);
+ ASSERT_TRUE(unresolved_a_int.IsUnresolvedMergedReference());
+ const RegType& unresolved_b_int = cache.FromUnresolvedMerge(unresolved_b, integer, nullptr);
+ ASSERT_TRUE(unresolved_b_int.IsUnresolvedMergedReference());
+ const RegType& unresolved_ab_int = cache.FromUnresolvedMerge(unresolved_ab, integer, nullptr);
+ ASSERT_TRUE(unresolved_ab_int.IsUnresolvedMergedReference());
+ std::vector<const RegType*> uninitialized_types = {
+ &uninit_this, &uninit_obj_0, &uninit_obj_1, &uninit_number_0, &uninit_integer_0
+ };
+ std::vector<const RegType*> unresolved_types = {
+ &unresolved_a,
+ &unresolved_b,
+ &unresolved_ab,
+ &unresolved_a_num,
+ &unresolved_b_num,
+ &unresolved_ab_num,
+ &unresolved_a_int,
+ &unresolved_b_int,
+ &unresolved_ab_int
+ };
+ std::vector<const RegType*> uninit_unresolved_types = {
+ &uninit_unres_this, &uninit_unres_a_0, &uninit_unres_b_0
+ };
+ std::vector<const RegType*> plain_nonobj_classes = { &number, &integer };
+ std::vector<const RegType*> plain_nonobj_arr_classes = {
+ &number_arr,
+ &number_arr_arr,
+ &integer_arr,
+ &char_arr,
+ };
+ // std::vector<const RegType*> others = { &conflict, &zero, &null, &obj, &int_type };
+
+ std::vector<const RegType*> all_minus_uninit_conflict;
+ all_minus_uninit_conflict.insert(all_minus_uninit_conflict.end(),
+ unresolved_types.begin(),
+ unresolved_types.end());
+ all_minus_uninit_conflict.insert(all_minus_uninit_conflict.end(),
+ plain_nonobj_classes.begin(),
+ plain_nonobj_classes.end());
+ all_minus_uninit_conflict.insert(all_minus_uninit_conflict.end(),
+ plain_nonobj_arr_classes.begin(),
+ plain_nonobj_arr_classes.end());
+ all_minus_uninit_conflict.push_back(&zero);
+ all_minus_uninit_conflict.push_back(&null);
+ all_minus_uninit_conflict.push_back(&obj);
+
+ std::vector<const RegType*> all_minus_uninit;
+ all_minus_uninit.insert(all_minus_uninit.end(),
+ all_minus_uninit_conflict.begin(),
+ all_minus_uninit_conflict.end());
+ all_minus_uninit.push_back(&conflict);
+
+
+ std::vector<const RegType*> all;
+ all.insert(all.end(), uninitialized_types.begin(), uninitialized_types.end());
+ all.insert(all.end(), uninit_unresolved_types.begin(), uninit_unresolved_types.end());
+ all.insert(all.end(), all_minus_uninit.begin(), all_minus_uninit.end());
+ all.push_back(&int_type);
+
+ auto check = [&](const RegType& in1, const RegType& in2, const RegType& expected_out)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ const RegType& merge_result = in1.SafeMerge(in2, &cache, nullptr);
+ EXPECT_EQ(&expected_out, &merge_result)
+ << in1.Dump() << " x " << in2.Dump() << " = " << merge_result.Dump()
+ << " != " << expected_out.Dump();
+ };
+
+ // Identity.
+ {
+ for (auto r : all) {
+ check(*r, *r, *r);
+ }
+ }
+
+ // Define a covering relation through a list of Edges. We'll then derive LUBs from this and
+ // create checks for every pair of types.
+
+ struct Edge {
+ const RegType& from;
+ const RegType& to;
+
+ Edge(const RegType& from_, const RegType& to_) : from(from_), to(to_) {}
+ };
+ std::vector<Edge> edges;
+#define ADD_EDGE(from, to) edges.emplace_back((from), (to))
+
+ // To Conflict.
+ {
+ for (auto r : uninitialized_types) {
+ ADD_EDGE(*r, conflict);
+ }
+ for (auto r : uninit_unresolved_types) {
+ ADD_EDGE(*r, conflict);
+ }
+ ADD_EDGE(obj, conflict);
+ ADD_EDGE(int_type, conflict);
+ }
+
+ ADD_EDGE(zero, null);
+
+ // Unresolved.
+ {
+ ADD_EDGE(null, unresolved_a);
+ ADD_EDGE(null, unresolved_b);
+ ADD_EDGE(unresolved_a, unresolved_ab);
+ ADD_EDGE(unresolved_b, unresolved_ab);
+
+ ADD_EDGE(number, unresolved_a_num);
+ ADD_EDGE(unresolved_a, unresolved_a_num);
+ ADD_EDGE(number, unresolved_b_num);
+ ADD_EDGE(unresolved_b, unresolved_b_num);
+ ADD_EDGE(number, unresolved_ab_num);
+ ADD_EDGE(unresolved_a_num, unresolved_ab_num);
+ ADD_EDGE(unresolved_b_num, unresolved_ab_num);
+ ADD_EDGE(unresolved_ab, unresolved_ab_num);
+
+ ADD_EDGE(integer, unresolved_a_int);
+ ADD_EDGE(unresolved_a, unresolved_a_int);
+ ADD_EDGE(integer, unresolved_b_int);
+ ADD_EDGE(unresolved_b, unresolved_b_int);
+ ADD_EDGE(integer, unresolved_ab_int);
+ ADD_EDGE(unresolved_a_int, unresolved_ab_int);
+ ADD_EDGE(unresolved_b_int, unresolved_ab_int);
+ ADD_EDGE(unresolved_ab, unresolved_ab_int);
+
+ ADD_EDGE(unresolved_a_int, unresolved_a_num);
+ ADD_EDGE(unresolved_b_int, unresolved_b_num);
+ ADD_EDGE(unresolved_ab_int, unresolved_ab_num);
+
+ ADD_EDGE(unresolved_ab_num, obj);
+ }
+
+ // Classes.
+ {
+ ADD_EDGE(null, integer);
+ ADD_EDGE(integer, number);
+ ADD_EDGE(number, obj);
+ }
+
+ // Arrays.
+ {
+ ADD_EDGE(integer_arr, number_arr);
+ ADD_EDGE(number_arr, obj_arr);
+ ADD_EDGE(obj_arr, obj);
+ ADD_EDGE(number_arr_arr, obj_arr);
+
+ ADD_EDGE(char_arr, obj);
+ ADD_EDGE(byte_arr, obj);
+
+ ADD_EDGE(null, integer_arr);
+ ADD_EDGE(null, number_arr_arr);
+ ADD_EDGE(null, char_arr);
+ ADD_EDGE(null, byte_arr);
+ }
+
+ // Primitive.
+ {
+ ADD_EDGE(zero, int_type);
+ }
+#undef ADD_EDGE
+
+ // Create merge triples by using the covering relation established by edges to derive the
+ // expected merge for any pair of types.
+
+ // Expect merge(in1, in2) == out.
+ struct MergeExpectation {
+ const RegType& in1;
+ const RegType& in2;
+ const RegType& out;
+
+ MergeExpectation(const RegType& in1_, const RegType& in2_, const RegType& out_)
+ : in1(in1_), in2(in2_), out(out_) {}
+ };
+ std::vector<MergeExpectation> expectations;
+
+ for (auto r1 : all) {
+ for (auto r2 : all) {
+ if (r1 == r2) {
+ continue;
+ }
+
+ // Very simple algorithm here that is usually used with adjacency lists. Our graph is
+ // small, it didn't make sense to have lists per node. Thus, the regular guarantees
+ // of O(n + |e|) don't apply, but that is acceptable.
+ //
+ // To compute r1 lub r2 = merge(r1, r2):
+ // 1) Generate the reachable set of r1, name it grey.
+ // 2) Mark all grey reachable nodes of r2 as black.
+ // 3) Find black nodes with no in-edges from other black nodes.
+ // 4) If |3)| == 1, that's the lub.
+
+ // Generic BFS of the graph induced by edges, starting at start. new_node will be called
+ // with any discovered node, in order.
+ auto bfs = [&](auto new_node, const RegType* start) {
+ std::unordered_set<const RegType*> seen;
+ std::queue<const RegType*> work_list;
+ work_list.push(start);
+ while (!work_list.empty()) {
+ const RegType* cur = work_list.front();
+ work_list.pop();
+ auto it = seen.find(cur);
+ if (it != seen.end()) {
+ continue;
+ }
+ seen.insert(cur);
+ new_node(cur);
+
+ for (const Edge& edge : edges) {
+ if (&edge.from == cur) {
+ work_list.push(&edge.to);
+ }
+ }
+ }
+ };
+
+ std::unordered_set<const RegType*> grey;
+ auto compute_grey = [&](const RegType* cur) {
+ grey.insert(cur); // Mark discovered node as grey.
+ };
+ bfs(compute_grey, r1);
+
+ std::set<const RegType*> black;
+ auto compute_black = [&](const RegType* cur) {
+ // Mark discovered grey node as black.
+ if (grey.find(cur) != grey.end()) {
+ black.insert(cur);
+ }
+ };
+ bfs(compute_black, r2);
+
+ std::set<const RegType*> no_in_edge(black); // Copy of black, remove nodes with in-edges.
+ for (auto r : black) {
+ for (Edge& e : edges) {
+ if (&e.from == r) {
+ no_in_edge.erase(&e.to); // It doesn't matter whether "to" is black or not, just
+ // attempt to remove it.
+ }
+ }
+ }
+
+ // Helper to print sets when something went wrong.
+ auto print_set = [](auto& container) REQUIRES_SHARED(Locks::mutator_lock_) {
+ std::string result;
+ for (auto r : container) {
+ result.append(" + ");
+ result.append(r->Dump());
+ }
+ return result;
+ };
+ ASSERT_EQ(no_in_edge.size(), 1u) << r1->Dump() << " u " << r2->Dump()
+ << " grey=" << print_set(grey)
+ << " black=" << print_set(black)
+ << " no-in-edge=" << print_set(no_in_edge);
+ expectations.emplace_back(*r1, *r2, **no_in_edge.begin());
+ }
+ }
+
+ // Evaluate merge expectations. The merge is expected to be commutative.
+
+ for (auto& triple : expectations) {
+ check(triple.in1, triple.in2, triple.out);
+ check(triple.in2, triple.in1, triple.out);
+ }
+
+ Runtime::Current()->GetHeap()->DecrementDisableMovingGC(soa.Self());
+}
+
TEST_F(RegTypeTest, ConstPrecision) {
// Tests creating primitive types types.
ArenaStack stack(Runtime::Current()->GetArenaPool());
diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h
index a9c9428581..39d73f54d8 100644
--- a/runtime/verifier/register_line-inl.h
+++ b/runtime/verifier/register_line-inl.h
@@ -19,6 +19,7 @@
#include "register_line.h"
+#include "base/logging.h" // For VLOG.
#include "method_verifier.h"
#include "reg_type_cache-inl.h"
@@ -192,6 +193,27 @@ inline RegisterLine::RegisterLine(size_t num_regs, MethodVerifier* verifier)
SetResultTypeToUnknown(verifier);
}
+inline void RegisterLine::ClearRegToLockDepth(size_t reg, size_t depth) {
+ CHECK_LT(depth, 32u);
+ DCHECK(IsSetLockDepth(reg, depth));
+ auto it = reg_to_lock_depths_.find(reg);
+ DCHECK(it != reg_to_lock_depths_.end());
+ uint32_t depths = it->second ^ (1 << depth);
+ if (depths != 0) {
+ it->second = depths;
+ } else {
+ reg_to_lock_depths_.erase(it);
+ }
+ // Need to unlock every register at the same lock depth. These are aliased locks.
+ uint32_t mask = 1 << depth;
+ for (auto& pair : reg_to_lock_depths_) {
+ if ((pair.second & mask) != 0) {
+ VLOG(verifier) << "Also unlocking " << pair.first;
+ pair.second ^= mask;
+ }
+ }
+}
+
inline void RegisterLineArenaDelete::operator()(RegisterLine* ptr) const {
if (ptr != nullptr) {
ptr->~RegisterLine();
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index 34c406e5b0..ea30e05487 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -18,7 +18,7 @@
#include "android-base/stringprintf.h"
-#include "dex_instruction-inl.h"
+#include "dex/dex_instruction-inl.h"
#include "method_verifier-inl.h"
#include "reg_type-inl.h"
#include "register_line-inl.h"
diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h
index 71eb4d6ac7..82f63b281a 100644
--- a/runtime/verifier/register_line.h
+++ b/runtime/verifier/register_line.h
@@ -20,6 +20,8 @@
#include <memory>
#include <vector>
+#include <android-base/logging.h>
+
#include "base/scoped_arena_containers.h"
#include "safe_map.h"
@@ -401,26 +403,7 @@ class RegisterLine {
return true;
}
- void ClearRegToLockDepth(size_t reg, size_t depth) {
- CHECK_LT(depth, 32u);
- DCHECK(IsSetLockDepth(reg, depth));
- auto it = reg_to_lock_depths_.find(reg);
- DCHECK(it != reg_to_lock_depths_.end());
- uint32_t depths = it->second ^ (1 << depth);
- if (depths != 0) {
- it->second = depths;
- } else {
- reg_to_lock_depths_.erase(it);
- }
- // Need to unlock every register at the same lock depth. These are aliased locks.
- uint32_t mask = 1 << depth;
- for (auto& pair : reg_to_lock_depths_) {
- if ((pair.second & mask) != 0) {
- VLOG(verifier) << "Also unlocking " << pair.first;
- pair.second ^= mask;
- }
- }
- }
+ void ClearRegToLockDepth(size_t reg, size_t depth);
void ClearAllRegToLockDepths(size_t reg) {
reg_to_lock_depths_.erase(reg);
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index 0481f24c45..7d8c5aae34 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -22,7 +22,7 @@
#include "art_method-inl.h"
#include "base/stl_util.h"
#include "compiler_callbacks.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "indenter.h"
#include "leb128.h"
#include "mirror/class-inl.h"
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index 4069a1188a..94441da7e2 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -23,7 +23,7 @@
#include "base/array_ref.h"
#include "base/mutex.h"
-#include "dex_file_types.h"
+#include "dex/dex_file_types.h"
#include "handle.h"
#include "obj_ptr.h"
#include "thread.h"
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 9722db9641..dc57f81a67 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -20,9 +20,9 @@
#include <sstream>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
-#include "base/logging.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "jni_internal.h"
#include "mirror/class.h"
@@ -81,6 +81,7 @@ jclass WellKnownClasses::libcore_util_EmptyArray;
jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk;
jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer;
+jmethodID WellKnownClasses::dalvik_system_BaseDexClassLoader_getLdLibraryPath;
jmethodID WellKnownClasses::dalvik_system_VMRuntime_runFinalization;
jmethodID WellKnownClasses::java_lang_Boolean_valueOf;
jmethodID WellKnownClasses::java_lang_Byte_valueOf;
@@ -269,7 +270,7 @@ uint32_t WellKnownClasses::StringInitToEntryPoint(ArtMethod* string_init) {
return kQuick ## entry_point_name; \
}
STRING_INIT_LIST(TO_ENTRY_POINT)
- #undef TO_STRING_FACTORY
+ #undef TO_ENTRY_POINT
LOG(FATAL) << "Could not find StringFactory method for String.<init>";
return 0;
}
@@ -325,6 +326,7 @@ void WellKnownClasses::Init(JNIEnv* env) {
org_apache_harmony_dalvik_ddmc_Chunk = CacheClass(env, "org/apache/harmony/dalvik/ddmc/Chunk");
org_apache_harmony_dalvik_ddmc_DdmServer = CacheClass(env, "org/apache/harmony/dalvik/ddmc/DdmServer");
+ dalvik_system_BaseDexClassLoader_getLdLibraryPath = CacheMethod(env, dalvik_system_BaseDexClassLoader, false, "getLdLibraryPath", "()Ljava/lang/String;");
dalvik_system_VMRuntime_runFinalization = CacheMethod(env, dalvik_system_VMRuntime, true, "runFinalization", "(J)V");
java_lang_ClassNotFoundException_init = CacheMethod(env, java_lang_ClassNotFoundException, false, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
java_lang_ClassLoader_loadClass = CacheMethod(env, java_lang_ClassLoader, false, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
@@ -406,7 +408,7 @@ void WellKnownClasses::LateInit(JNIEnv* env) {
// to make sure these JNI methods are available.
java_lang_Runtime_nativeLoad =
CacheMethod(env, java_lang_Runtime.get(), true, "nativeLoad",
- "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)"
+ "(Ljava/lang/String;Ljava/lang/ClassLoader;)"
"Ljava/lang/String;");
java_lang_reflect_Proxy_invoke =
CacheMethod(env, java_lang_reflect_Proxy, true, "invoke",
@@ -465,6 +467,7 @@ void WellKnownClasses::Clear() {
org_apache_harmony_dalvik_ddmc_Chunk = nullptr;
org_apache_harmony_dalvik_ddmc_DdmServer = nullptr;
+ dalvik_system_BaseDexClassLoader_getLdLibraryPath = nullptr;
dalvik_system_VMRuntime_runFinalization = nullptr;
java_lang_Boolean_valueOf = nullptr;
java_lang_Byte_valueOf = nullptr;
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 3ebcc33171..024971ae3d 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -92,6 +92,7 @@ struct WellKnownClasses {
static jclass org_apache_harmony_dalvik_ddmc_Chunk;
static jclass org_apache_harmony_dalvik_ddmc_DdmServer;
+ static jmethodID dalvik_system_BaseDexClassLoader_getLdLibraryPath;
static jmethodID dalvik_system_VMRuntime_runFinalization;
static jmethodID java_lang_Boolean_valueOf;
static jmethodID java_lang_Byte_valueOf;
diff --git a/runtime/zip_archive.h b/runtime/zip_archive.h
index 821cc5ceb1..75f8757f6c 100644
--- a/runtime/zip_archive.h
+++ b/runtime/zip_archive.h
@@ -21,7 +21,8 @@
#include <memory>
#include <string>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/unix_file/random_access_file.h"
#include "globals.h"
#include "mem_map.h"
diff --git a/simulator/code_simulator_arm64.cc b/simulator/code_simulator_arm64.cc
index 939d2e287f..a64bd0bc0b 100644
--- a/simulator/code_simulator_arm64.cc
+++ b/simulator/code_simulator_arm64.cc
@@ -16,7 +16,7 @@
#include "code_simulator_arm64.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
using namespace vixl::aarch64; // NOLINT(build/namespaces)
diff --git a/simulator/code_simulator_container.cc b/simulator/code_simulator_container.cc
index a5f05dc8fc..9f52b320f2 100644
--- a/simulator/code_simulator_container.cc
+++ b/simulator/code_simulator_container.cc
@@ -18,6 +18,7 @@
#include "code_simulator_container.h"
+#include "base/logging.h" // For VLOG.
#include "code_simulator.h"
#include "globals.h"
diff --git a/simulator/code_simulator_container.h b/simulator/code_simulator_container.h
index 31a915e4f1..a21971508a 100644
--- a/simulator/code_simulator_container.h
+++ b/simulator/code_simulator_container.h
@@ -17,8 +17,9 @@
#ifndef ART_SIMULATOR_CODE_SIMULATOR_CONTAINER_H_
#define ART_SIMULATOR_CODE_SIMULATOR_CONTAINER_H_
+#include <android-base/logging.h>
+
#include "arch/instruction_set.h"
-#include "base/logging.h"
namespace art {
diff --git a/test/004-JniTest/expected.txt b/test/004-JniTest/expected.txt
index 1d05160883..b09b9a22eb 100644
--- a/test/004-JniTest/expected.txt
+++ b/test/004-JniTest/expected.txt
@@ -1,4 +1,5 @@
JNI_OnLoad called
+ABC.XYZ = 12, GetStaticIntField(DEF.class, 'XYZ') = 12
Super.<init>
Super.<init>
Subclass.<init>
diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
index bc5a0a64e8..33a8f5bba2 100644
--- a/test/004-JniTest/jni_test.cc
+++ b/test/004-JniTest/jni_test.cc
@@ -20,8 +20,10 @@
#include <iostream>
#include <vector>
+#include <android-base/logging.h>
+
#include "art_method-inl.h"
-#include "base/logging.h"
+#include "base/runtime_debug.h"
#include "jni.h"
namespace art {
@@ -88,6 +90,14 @@ static void testFindClassOnAttachedNativeThread(JNIEnv* env) {
CHECK(!env->ExceptionCheck());
}
+extern "C" JNIEXPORT jint JNICALL Java_Main_getFieldSubclass(JNIEnv* env,
+ jclass,
+ jobject f_obj,
+ jclass sub) {
+ jfieldID f = env->FromReflectedField(f_obj);
+ return env->GetStaticIntField(sub, f);
+}
+
// http://b/10994325
extern "C" JNIEXPORT void JNICALL Java_Main_testFindClassOnAttachedNativeThread(JNIEnv*, jclass) {
PthreadHelper(&testFindClassOnAttachedNativeThread);
diff --git a/test/004-JniTest/src/Main.java b/test/004-JniTest/src/Main.java
index 871107c56b..f94dcf6c70 100644
--- a/test/004-JniTest/src/Main.java
+++ b/test/004-JniTest/src/Main.java
@@ -18,6 +18,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.regex.Pattern;
@@ -32,6 +33,7 @@ public class Main {
throw new RuntimeException("Slow-debug flags unexpectedly off.");
}
+ testFieldSubclass();
testFindClassOnAttachedNativeThread();
testFindFieldOnAttachedNativeThread();
testReflectFieldGetFromAttachedNativeThreadNative();
@@ -65,6 +67,19 @@ public class Main {
testDoubleLoad(args[0]);
}
+ static class ABC { public static int XYZ = 12; }
+ static class DEF extends ABC {}
+ public static void testFieldSubclass() {
+ try {
+ System.out.println("ABC.XYZ = " + ABC.XYZ + ", GetStaticIntField(DEF.class, 'XYZ') = " +
+ getFieldSubclass(ABC.class.getDeclaredField("XYZ"), DEF.class));
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to test get static field on a subclass", e);
+ }
+ }
+
+ public static native int getFieldSubclass(Field f, Class sub);
+
private static native boolean registerNativesJniTest();
private static native void testCallDefaultMethods();
diff --git a/test/004-ThreadStress/src/Main.java b/test/004-ThreadStress/src/Main.java
index a9e0faf500..6ad160c1a6 100644
--- a/test/004-ThreadStress/src/Main.java
+++ b/test/004-ThreadStress/src/Main.java
@@ -267,6 +267,15 @@ public class Main implements Runnable {
semaphore.acquire();
permitAcquired = true;
Thread.sleep(SLEEP_TIME);
+ } catch (OutOfMemoryError ignored) {
+ // The call to semaphore.acquire() above may trigger an OOME,
+ // despite the care taken doing some warm-up by forcing
+ // ahead-of-time initialization of classes used by the Semaphore
+ // class (see forceTransitiveClassInitialization below).
+ // For instance, one of the code paths executes
+ // AbstractQueuedSynchronizer.addWaiter, which allocates an
+ // AbstractQueuedSynchronizer$Node (see b/67730573).
+ // In that case, just ignore the OOME and continue.
} catch (InterruptedException ignored) {
} finally {
if (permitAcquired) {
diff --git a/test/008-exceptions/src/Main.java b/test/008-exceptions/src/Main.java
index 89fe016856..008576acc3 100644
--- a/test/008-exceptions/src/Main.java
+++ b/test/008-exceptions/src/Main.java
@@ -158,8 +158,8 @@ public class Main {
t.printStackTrace(System.out);
}
try {
- // Before splitting mirror::Class::kStatusError into
- // kStatusErrorUnresolved and kStatusErrorResolved,
+ // Before splitting ClassStatus::kError into
+ // ClassStatus::kErrorUnresolved and ClassStatus::kErrorResolved,
// this would trigger a
// CHECK(super_class->IsResolved())
// failure in
@@ -188,8 +188,8 @@ public class Main {
} catch (Throwable t) {
t.printStackTrace(System.out);
}
- // Before splitting mirror::Class::kStatusError into
- // kStatusErrorUnresolved and kStatusErrorResolved,
+ // Before splitting ClassStatus::kError into
+ // ClassStatus::kErrorUnresolved and ClassStatus::kErrorResolved,
// the exception from wrapper 1 would have been
// wrapped in NoClassDefFoundError but the exception
// from wrapper 2 would have been unwrapped.
diff --git a/test/031-class-attributes/jasmin/ClassAttrs$1.j b/test/031-class-attributes/jasmin/ClassAttrs$1.j
new file mode 100644
index 0000000000..ea767efdba
--- /dev/null
+++ b/test/031-class-attributes/jasmin/ClassAttrs$1.j
@@ -0,0 +1,49 @@
+; 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.
+
+; (new OtherClass() { int i = 5; }).getClass()
+
+; ClassAttrs$1.j
+
+; Generated by ClassFileAnalyzer (Can)
+; Analyzer and Disassembler for Java class files
+; (Jasmin syntax 2, http://jasmin.sourceforge.net)
+;
+; ClassFileAnalyzer, version 0.7.0
+
+.bytecode 52.0
+.source ClassAttrs.java
+.class final ClassAttrs$1
+.super OtherClass
+.enclosing method ClassAttrs/main()V
+; OpenJDK javac versions <= 8 consider anonymous classes declared side
+; static methods to be static (as is this one), whereas OpenJDK 9 javac
+; does not. See http://b/62290080
+.inner class static inner ClassAttrs$1 ; <anonymous> <not a member>
+
+.field i I
+
+.method <init>()V
+ .limit stack 2
+ .limit locals 1
+ .line 112
+ 0: aload_0
+ 1: invokespecial OtherClass/<init>()V
+ 4: aload_0
+ 5: iconst_5
+ 6: putfield ClassAttrs$1/i I
+ 9: return
+.end method
+
+
diff --git a/test/031-class-attributes/src/ClassAttrs.java b/test/031-class-attributes/src/ClassAttrs.java
index 8489a2c222..f55a34c5f2 100644
--- a/test/031-class-attributes/src/ClassAttrs.java
+++ b/test/031-class-attributes/src/ClassAttrs.java
@@ -107,9 +107,14 @@ public class ClassAttrs {
inner.showMe();
ClassAttrs attrs = new ClassAttrs();
-
- /* anonymous, not local, not member */
- printClassAttrs((new OtherClass() { int i = 5; }).getClass());
+ try {
+ /* anonymous, not local, not member */
+ printClassAttrs(Class.forName("ClassAttrs$1")); // ClassAttrs$1.j
+ } catch (ClassNotFoundException e) {
+ System.out.println("FAILED: " + e);
+ e.printStackTrace(System.out);
+ throw new AssertionError(e);
+ }
/* member, not anonymous, not local */
printClassAttrs(MemberClass.class);
diff --git a/test/044-proxy/native_proxy.cc b/test/044-proxy/native_proxy.cc
index f168719bf5..f3178f9c2a 100644
--- a/test/044-proxy/native_proxy.cc
+++ b/test/044-proxy/native_proxy.cc
@@ -16,7 +16,7 @@
#include "jni.h"
-#include "base/logging.h"
+#include <android-base/logging.h>
namespace art {
diff --git a/test/070-nio-buffer/src/Main.java b/test/070-nio-buffer/src/Main.java
index a3eeb3fda6..86eb553594 100644
--- a/test/070-nio-buffer/src/Main.java
+++ b/test/070-nio-buffer/src/Main.java
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import java.nio.Buffer;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -50,9 +51,9 @@ public class Main {
1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031
};
- shortBuf.position(0);
+ ((Buffer) shortBuf).position(0);
shortBuf.put(myShorts, 0, 32); // should work
- shortBuf.position(0);
+ ((Buffer) shortBuf).position(0);
shortBuf.put(myShorts, 16, 16); // should work
shortBuf.put(myShorts, 16, 16); // advance to end
@@ -64,7 +65,7 @@ public class Main {
}
try {
- shortBuf.position(0);
+ ((Buffer) shortBuf).position(0);
shortBuf.put(myShorts, 0, 33); // should fail
System.out.println("ERROR: out-of-bounds put succeeded\n");
} catch (IndexOutOfBoundsException ioobe) {
@@ -72,7 +73,7 @@ public class Main {
}
try {
- shortBuf.position(16);
+ ((Buffer) shortBuf).position(16);
shortBuf.put(myShorts, 0, 17); // should fail
System.out.println("ERROR: out-of-bounds put succeeded\n");
} catch (BufferOverflowException boe) {
@@ -93,13 +94,13 @@ public class Main {
int data[] = new int[25];
//FloatBuffer int1 = direct.asFloatBuffer();
//float data[] = new float[25];
- int1.clear ();
- int1.put (data);
- int1.position (0);
+ ((Buffer) int1).clear();
+ int1.put(data);
+ ((Buffer) int1).position(0);
- int1.clear ();
+ ((Buffer) int1).clear();
int1.put (data);
- int1.position (0);
+ ((Buffer) int1).position(0);
}
/*
@@ -119,7 +120,7 @@ public class Main {
}
static void storeValues(ByteBuffer directBuf) {
- directBuf.position(0);
+ ((Buffer) directBuf).position(0);
ShortBuffer shortBuf = directBuf.asShortBuffer();
CharBuffer charBuf = directBuf.asCharBuffer();
IntBuffer intBuf = directBuf.asIntBuffer();
@@ -157,7 +158,7 @@ public class Main {
throw new RuntimeException("double get/store failed");
}
- directBuf.position(0);
+ ((Buffer) directBuf).position(0);
char[] outBuf = new char[directBuf.limit() * 2];
for (int i = 0; i < directBuf.limit(); i++) {
byte b = directBuf.get();
diff --git a/test/085-old-style-inner-class/build b/test/085-old-style-inner-class/build
deleted file mode 100644
index 21dc66269d..0000000000
--- a/test/085-old-style-inner-class/build
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Stop if something fails.
-set -e
-
-# We compile for a 1.4 target to suppress the use of EnclosingMethod
-# attributes.
-mkdir classes
-${JAVAC} -source 1.4 -target 1.4 -d classes `find src -name '*.java'`
-
-if [ ${USE_JACK} = "true" ]; then
- jar cf classes.jill.jar -C classes .
- ${JACK} --import classes.jill.jar --output-dex .
-else
- # Suppress stderr to keep the inner class warnings out of the expected output.
- ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes 2>/dev/null
-fi
-
-zip $TEST_NAME.jar classes.dex
diff --git a/test/085-old-style-inner-class/jasmin/Main$1.j b/test/085-old-style-inner-class/jasmin/Main$1.j
new file mode 100644
index 0000000000..fde1ddea53
--- /dev/null
+++ b/test/085-old-style-inner-class/jasmin/Main$1.j
@@ -0,0 +1,39 @@
+; 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.
+
+.source Main.java
+.class final Main$1
+.super java/lang/Object
+.implements java/lang/Runnable
+
+; new Runnable() {
+; public void run() { }
+; };
+
+.method <init>()V
+ .limit stack 1
+ .limit locals 1
+ .line 23
+ aload_0
+ invokespecial java/lang/Object/<init>()V
+ return
+.end method
+
+.method public run()V
+ .limit stack 0
+ .limit locals 1
+ .line 24
+ return
+.end method
+
diff --git a/test/085-old-style-inner-class/jasmin/Main$2.j b/test/085-old-style-inner-class/jasmin/Main$2.j
new file mode 100644
index 0000000000..dedbe8682e
--- /dev/null
+++ b/test/085-old-style-inner-class/jasmin/Main$2.j
@@ -0,0 +1,39 @@
+; 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.
+
+.source Main.java
+.class final Main$2
+.super java/lang/Object
+.implements java/lang/Runnable
+
+; new Runnable() {
+; public void run() { }
+; };
+
+.method <init>()V
+ .limit stack 1
+ .limit locals 1
+ .line 28
+ aload_0
+ invokespecial java/lang/Object/<init>()V
+ return
+.end method
+
+.method public run()V
+ .limit stack 0
+ .limit locals 1
+ .line 29
+ return
+.end method
+
diff --git a/test/085-old-style-inner-class/src/Main.java b/test/085-old-style-inner-class/src/Main.java
index c9a5b72dbd..831364cae1 100644
--- a/test/085-old-style-inner-class/src/Main.java
+++ b/test/085-old-style-inner-class/src/Main.java
@@ -20,15 +20,19 @@ import java.lang.reflect.Method;
* Test reflection on old-style inner classes.
*/
public class Main {
+ /*
+ // Main$1.j
private static Runnable theRunnable = new Runnable() {
public void run() { }
};
+ // Main$1.2
private static Runnable create() {
return new Runnable() {
public void run() { }
};
}
+ */
private static String nameOf(Class clazz) {
return (clazz == null) ? "(null)" : clazz.getName();
@@ -48,8 +52,8 @@ public class Main {
nameOf(clazz.getEnclosingMethod()));
}
- public static void main(String args[]) {
- infoFor(theRunnable.getClass());
- infoFor(create().getClass());
+ public static void main(String args[]) throws ClassNotFoundException {
+ infoFor(Class.forName("Main$1"));
+ infoFor(Class.forName("Main$2"));
}
}
diff --git a/test/099-vmdebug/expected.txt b/test/099-vmdebug/expected.txt
index b8d72f66f8..f7801de62f 100644
--- a/test/099-vmdebug/expected.txt
+++ b/test/099-vmdebug/expected.txt
@@ -23,3 +23,9 @@ Instances of null 0
Instances of ClassA assignable 3
Array counts [2, 1, 0]
Array counts assignable [3, 1, 0]
+ClassD got 3, combined mask: 13
+ClassE got 2, combined mask: 18
+null got 0
+ClassD assignable got 5, combined mask: 31
+ClassE assignable got 2, combined mask: 18
+null assignable got 0
diff --git a/test/099-vmdebug/info.txt b/test/099-vmdebug/info.txt
index 7f88086986..873429e076 100644
--- a/test/099-vmdebug/info.txt
+++ b/test/099-vmdebug/info.txt
@@ -1 +1 @@
-Tests of private dalvik.system.VMDebug support for method tracing.
+Tests of dalvik.system.VMDebug APIs.
diff --git a/test/099-vmdebug/src/Main.java b/test/099-vmdebug/src/Main.java
index 90ad3155ca..e0d829a0d6 100644
--- a/test/099-vmdebug/src/Main.java
+++ b/test/099-vmdebug/src/Main.java
@@ -33,6 +33,7 @@ public class Main {
}
testMethodTracing();
testCountInstances();
+ testGetInstances();
testRuntimeStat();
testRuntimeStats();
}
@@ -249,6 +250,59 @@ public class Main {
System.out.println("Array counts assignable " + Arrays.toString(counts));
}
+ static class ClassD {
+ public int mask;
+
+ public ClassD(int mask) {
+ this.mask = mask;
+ }
+ }
+
+ static class ClassE extends ClassD {
+ public ClassE(int mask) {
+ super(mask);
+ }
+ }
+
+ private static void testGetInstances() throws Exception {
+ ArrayList<Object> l = new ArrayList<Object>();
+ l.add(new ClassD(0x01));
+ l.add(new ClassE(0x02));
+ l.add(new ClassD(0x04));
+ l.add(new ClassD(0x08));
+ l.add(new ClassE(0x10));
+ Runtime.getRuntime().gc();
+ Class<?>[] classes = new Class<?>[] {ClassD.class, ClassE.class, null};
+ Object[][] instances = VMDebug.getInstancesOfClasses(classes, false);
+
+ int mask = 0;
+ for (Object instance : instances[0]) {
+ mask |= ((ClassD)instance).mask;
+ }
+ System.out.println("ClassD got " + instances[0].length + ", combined mask: " + mask);
+
+ mask = 0;
+ for (Object instance : instances[1]) {
+ mask |= ((ClassD)instance).mask;
+ }
+ System.out.println("ClassE got " + instances[1].length + ", combined mask: " + mask);
+ System.out.println("null got " + instances[2].length);
+
+ instances = VMDebug.getInstancesOfClasses(classes, true);
+ mask = 0;
+ for (Object instance : instances[0]) {
+ mask |= ((ClassD)instance).mask;
+ }
+ System.out.println("ClassD assignable got " + instances[0].length + ", combined mask: " + mask);
+
+ mask = 0;
+ for (Object instance : instances[1]) {
+ mask |= ((ClassD)instance).mask;
+ }
+ System.out.println("ClassE assignable got " + instances[1].length + ", combined mask: " + mask);
+ System.out.println("null assignable got " + instances[2].length);
+ }
+
private static class VMDebug {
private static final Method startMethodTracingMethod;
private static final Method stopMethodTracingMethod;
@@ -257,6 +311,7 @@ public class Main {
private static final Method getRuntimeStatsMethod;
private static final Method countInstancesOfClassMethod;
private static final Method countInstancesOfClassesMethod;
+ private static final Method getInstancesOfClassesMethod;
static {
try {
Class<?> c = Class.forName("dalvik.system.VMDebug");
@@ -270,6 +325,8 @@ public class Main {
Class.class, Boolean.TYPE);
countInstancesOfClassesMethod = c.getDeclaredMethod("countInstancesOfClasses",
Class[].class, Boolean.TYPE);
+ getInstancesOfClassesMethod = c.getDeclaredMethod("getInstancesOfClasses",
+ Class[].class, Boolean.TYPE);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -300,5 +357,9 @@ public class Main {
return (long[]) countInstancesOfClassesMethod.invoke(
null, new Object[]{classes, assignable});
}
+ public static Object[][] getInstancesOfClasses(Class<?>[] classes, boolean assignable) throws Exception {
+ return (Object[][]) getInstancesOfClassesMethod.invoke(
+ null, new Object[]{classes, assignable});
+ }
}
}
diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc
index 2248fc4efd..7c382588a4 100644
--- a/test/117-nopatchoat/nopatchoat.cc
+++ b/test/117-nopatchoat/nopatchoat.cc
@@ -15,7 +15,7 @@
*/
#include "class_linker.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "gc/heap.h"
#include "gc/space/image_space.h"
#include "mirror/class-inl.h"
diff --git a/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
index 7d40f5773d..f01b82553d 100644
--- a/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
+++ b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
@@ -58,7 +58,7 @@ extern "C" JNIEXPORT void JNICALL Java_Main_destroyJavaVMAndExit(JNIEnv* env, jc
Thread* const self = Thread::Current();
self->SetTopOfStack(nullptr);
self->SetTopOfShadowStack(nullptr);
- JavaVM* vm = down_cast<JNIEnvExt*>(env)->vm;
+ JavaVM* vm = down_cast<JNIEnvExt*>(env)->GetVm();
vm->DetachCurrentThread();
// Open ourself again to make sure the native library does not get unloaded from
// underneath us due to DestroyJavaVM. b/28406866
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index 66270fd5c7..ef758e86e1 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -25,11 +25,11 @@
#include "jni.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <backtrace/Backtrace.h>
-#include "android-base/stringprintf.h"
#include "base/file_utils.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "gc/heap.h"
#include "gc/space/image_space.h"
diff --git a/test/137-cfi/run b/test/137-cfi/run
index ebc729bc74..adea71a07f 100755
--- a/test/137-cfi/run
+++ b/test/137-cfi/run
@@ -16,10 +16,15 @@
# Test with full DWARF debugging information.
# Check full signatures of methods.
+# The option jitthreshold:0 ensures that if we run the test in JIT mode,
+# there will be JITed frames on the callstack (it synchronously JITs on first use).
${RUN} "$@" -Xcompiler-option --generate-debug-info \
+ --runtime-option -Xjitthreshold:0 \
--args --full-signatures --args --test-local --args --test-remote
# Test with minimal compressed debugging information.
# Check only method names (parameters are omitted to save space).
# Check only remote unwinding since decompression is disabled in local unwinds (b/27391690).
-${RUN} "$@" -Xcompiler-option --generate-mini-debug-info --args --test-remote
+${RUN} "$@" -Xcompiler-option --generate-mini-debug-info \
+ --runtime-option -Xjitthreshold:0 \
+ --args --test-remote
diff --git a/test/150-loadlibrary/src/Main.java b/test/150-loadlibrary/src/Main.java
index 908693760f..ec96221d1e 100644
--- a/test/150-loadlibrary/src/Main.java
+++ b/test/150-loadlibrary/src/Main.java
@@ -47,7 +47,7 @@ public class Main {
// Then call an internal function that accepts the classloader. Do not use load(), as it
// is deprecated and only there for backwards compatibility, and prints a warning to the
// log that we'd have to strip (it contains the pid).
- Method m = Runtime.class.getDeclaredMethod("doLoad", String.class, ClassLoader.class);
+ Method m = Runtime.class.getDeclaredMethod("nativeLoad", String.class, ClassLoader.class);
m.setAccessible(true);
Object result = m.invoke(Runtime.getRuntime(), fileName, bootClassLoader);
if (result != null) {
diff --git a/test/151-OpenFileLimit/src/Main.java b/test/151-OpenFileLimit/src/Main.java
index 9fe47c8b16..de5890cbfa 100644
--- a/test/151-OpenFileLimit/src/Main.java
+++ b/test/151-OpenFileLimit/src/Main.java
@@ -55,8 +55,11 @@ public class Main {
System.out.println(e.getMessage());
}
- for (int i = 0; i < files.size(); i++) {
+ for (int i = 0; i < streams.size(); i++) {
streams.get(i).close();
+ }
+
+ for (int i = 0; i < files.size(); i++) {
files.get(i).delete();
}
System.out.println("done.");
diff --git a/test/1940-ddms-ext/check b/test/1940-ddms-ext/check
new file mode 100755
index 0000000000..d2c03841fc
--- /dev/null
+++ b/test/1940-ddms-ext/check
@@ -0,0 +1,21 @@
+#!/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.
+
+# Need to pull out the describeException ouput since that won't be there on
+# device.
+sed -e '/\t.*$/d' "$2" | sed -e '/java.lang.ArrayIndexOutOfBoundsException:.*$/d' > "$2.tmp"
+
+./default-check "$1" "$2.tmp"
diff --git a/test/1940-ddms-ext/expected.txt b/test/1940-ddms-ext/expected.txt
index 62d3b7bd4c..1a457a01a5 100644
--- a/test/1940-ddms-ext/expected.txt
+++ b/test/1940-ddms-ext/expected.txt
@@ -3,8 +3,19 @@ MyDdmHandler: Chunk received: Chunk(Type: 0xDEADBEEF, Len: 8, data: [1, 2, 3, 4,
MyDdmHandler: Putting value 0x800025
MyDdmHandler: Chunk returned: Chunk(Type: 0xFADE7357, Len: 8, data: [0, 0, 0, 0, 0, -128, 0, 37])
JVMTI returned chunk: Chunk(Type: 0xFADE7357, Len: 8, data: [0, 0, 0, 0, 0, -128, 0, 37])
+Sending empty data array
+MyDdmHandler: Chunk received: Chunk(Type: 0xDEADBEEF, Len: 0, data: [])
+MyDdmHandler: Putting value 0x1
+MyDdmHandler: Chunk returned: Chunk(Type: 0xFADE7357, Len: 8, data: [0, 0, 0, 0, 0, 0, 0, 1])
+JVMTI returned chunk: Chunk(Type: 0xFADE7357, Len: 8, data: [0, 0, 0, 0, 0, 0, 0, 1])
Sending chunk: Chunk(Type: 0xDEADBEEF, Len: 8, data: [9, 10, 11, 12, 13, 14, 15, 16])
Chunk published: Chunk(Type: 0xDEADBEEF, Len: 8, data: [9, 10, 11, 12, 13, 14, 15, 16])
+Sending data [1] to chunk handler -1412567295
+MyDdmHandler: Chunk received: Chunk(Type: 0xABCDEF01, Len: 1, data: [1])
+JVMTI returned chunk: Chunk(Type: 0xFADE7357, Len: 0, data: [])
+Sending data [1] to chunk handler 305419896
+MyDdmHandler: Chunk received: Chunk(Type: 0x12345678, Len: 1, data: [1])
+Got error: JVMTI_ERROR_INTERNAL
Saw expected thread events.
Expected chunk type published: 1213221190
Expected chunk type published: 1297109829
diff --git a/test/1940-ddms-ext/src-art/art/Test1940.java b/test/1940-ddms-ext/src-art/art/Test1940.java
index 9f79eaebba..226fe350bd 100644
--- a/test/1940-ddms-ext/src-art/art/Test1940.java
+++ b/test/1940-ddms-ext/src-art/art/Test1940.java
@@ -30,6 +30,8 @@ public class Test1940 {
public static final int DDMS_HEADER_LENGTH = 8;
public static final int MY_DDMS_TYPE = 0xDEADBEEF;
public static final int MY_DDMS_RESPONSE_TYPE = 0xFADE7357;
+ public static final int MY_EMPTY_DDMS_TYPE = 0xABCDEF01;
+ public static final int MY_INVALID_DDMS_TYPE = 0x12345678;
public static final boolean PRINT_ALL_CHUNKS = false;
@@ -58,19 +60,27 @@ public class Test1940 {
public void connected() {}
public void disconnected() {}
public Chunk handleChunk(Chunk req) {
- // For this test we will simply calculate the checksum
- checkEq(req.type, MY_DDMS_TYPE);
System.out.println("MyDdmHandler: Chunk received: " + printChunk(req));
- ByteBuffer b = ByteBuffer.wrap(new byte[8]);
- Adler32 a = new Adler32();
- a.update(req.data, req.offset, req.length);
- b.order(ByteOrder.BIG_ENDIAN);
- long val = a.getValue();
- b.putLong(val);
- System.out.printf("MyDdmHandler: Putting value 0x%X\n", val);
- Chunk ret = new Chunk(MY_DDMS_RESPONSE_TYPE, b.array(), 0, 8);
- System.out.println("MyDdmHandler: Chunk returned: " + printChunk(ret));
- return ret;
+ if (req.type == MY_DDMS_TYPE) {
+ // For this test we will simply calculate the checksum
+ ByteBuffer b = ByteBuffer.wrap(new byte[8]);
+ Adler32 a = new Adler32();
+ a.update(req.data, req.offset, req.length);
+ b.order(ByteOrder.BIG_ENDIAN);
+ long val = a.getValue();
+ b.putLong(val);
+ System.out.printf("MyDdmHandler: Putting value 0x%X\n", val);
+ Chunk ret = new Chunk(MY_DDMS_RESPONSE_TYPE, b.array(), 0, 8);
+ System.out.println("MyDdmHandler: Chunk returned: " + printChunk(ret));
+ return ret;
+ } else if (req.type == MY_EMPTY_DDMS_TYPE) {
+ return new Chunk(MY_DDMS_RESPONSE_TYPE, new byte[0], 0, 0);
+ } else if (req.type == MY_INVALID_DDMS_TYPE) {
+ // This is a very invalid chunk.
+ return new Chunk(MY_DDMS_RESPONSE_TYPE, new byte[] { 0 }, /*offset*/ 12, /*length*/ 55);
+ } else {
+ throw new TestError("Unknown ddm request type: " + req.type);
+ }
}
}
@@ -113,18 +123,42 @@ public class Test1940 {
Test1940.class.getDeclaredMethod("HandlePublish", Integer.TYPE, new byte[0].getClass()));
// Test sending chunk directly.
DdmServer.registerHandler(MY_DDMS_TYPE, SINGLE_HANDLER);
+ DdmServer.registerHandler(MY_EMPTY_DDMS_TYPE, SINGLE_HANDLER);
+ DdmServer.registerHandler(MY_INVALID_DDMS_TYPE, SINGLE_HANDLER);
DdmServer.registrationComplete();
byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
System.out.println("Sending data " + Arrays.toString(data));
Chunk res = processChunk(data);
System.out.println("JVMTI returned chunk: " + printChunk(res));
+ // Test sending an empty chunk.
+ System.out.println("Sending empty data array");
+ res = processChunk(new byte[0]);
+ System.out.println("JVMTI returned chunk: " + printChunk(res));
+
// Test sending chunk through DdmServer#sendChunk
Chunk c = new Chunk(
MY_DDMS_TYPE, new byte[] { 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }, 0, 8);
System.out.println("Sending chunk: " + printChunk(c));
DdmServer.sendChunk(c);
+ // Test getting back an empty chunk.
+ data = new byte[] { 0x1 };
+ System.out.println(
+ "Sending data " + Arrays.toString(data) + " to chunk handler " + MY_EMPTY_DDMS_TYPE);
+ res = processChunk(new Chunk(MY_EMPTY_DDMS_TYPE, data, 0, 1));
+ System.out.println("JVMTI returned chunk: " + printChunk(res));
+
+ // Test getting back an invalid chunk.
+ System.out.println(
+ "Sending data " + Arrays.toString(data) + " to chunk handler " + MY_INVALID_DDMS_TYPE);
+ try {
+ res = processChunk(new Chunk(MY_INVALID_DDMS_TYPE, data, 0, 1));
+ System.out.println("JVMTI returned chunk: " + printChunk(res));
+ } catch (RuntimeException e) {
+ System.out.println("Got error: " + e.getMessage());
+ }
+
// Test thread chunks are sent.
final boolean[] types_seen = new boolean[] { false, false, false };
CURRENT_HANDLER = (type, cdata) -> {
diff --git a/test/1941-dispose-stress/dispose_stress.cc b/test/1941-dispose-stress/dispose_stress.cc
index e8fcc775e9..f973abe28b 100644
--- a/test/1941-dispose-stress/dispose_stress.cc
+++ b/test/1941-dispose-stress/dispose_stress.cc
@@ -30,6 +30,17 @@
namespace art {
namespace Test1941DisposeStress {
+extern "C" JNIEXPORT void JNICALL Java_art_Test1941_setTracingOn(JNIEnv* env,
+ jclass,
+ jthread thr,
+ jboolean enable) {
+ JvmtiErrorToException(env,
+ jvmti_env,
+ jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE,
+ JVMTI_EVENT_SINGLE_STEP,
+ thr));
+}
+
extern "C" JNIEXPORT jlong JNICALL Java_art_Test1941_AllocEnv(JNIEnv* env, jclass) {
JavaVM* vm = nullptr;
if (env->GetJavaVM(&vm) != 0) {
diff --git a/test/1941-dispose-stress/src/art/Test1941.java b/test/1941-dispose-stress/src/art/Test1941.java
index d5a9de6cab..29cea6bdb8 100644
--- a/test/1941-dispose-stress/src/art/Test1941.java
+++ b/test/1941-dispose-stress/src/art/Test1941.java
@@ -19,6 +19,7 @@ package art;
import java.util.Arrays;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
+import java.util.concurrent.Semaphore;
public class Test1941 {
public static final boolean PRINT_CNT = false;
@@ -41,7 +42,8 @@ public class Test1941 {
// Don't bother actually doing anything.
}
- public static void LoopAllocFreeEnv() {
+ public static void LoopAllocFreeEnv(Semaphore sem) {
+ sem.release();
while (!Thread.interrupted()) {
CNT++;
long env = AllocEnv();
@@ -52,18 +54,25 @@ public class Test1941 {
public static native long AllocEnv();
public static native void FreeEnv(long env);
+ public static native void setTracingOn(Thread thr, boolean enable);
+
public static void run() throws Exception {
- Thread thr = new Thread(Test1941::LoopAllocFreeEnv, "LoopNative");
+ final Semaphore sem = new Semaphore(0);
+ Thread thr = new Thread(() -> { LoopAllocFreeEnv(sem); }, "LoopNative");
thr.start();
+ // Make sure the other thread is actually started.
+ sem.acquire();
Trace.enableSingleStepTracing(Test1941.class,
Test1941.class.getDeclaredMethod(
"notifySingleStep", Thread.class, Executable.class, Long.TYPE),
- null);
+ thr);
+ setTracingOn(Thread.currentThread(), true);
System.out.println("fib(20) is " + fib(20));
thr.interrupt();
thr.join();
+ setTracingOn(Thread.currentThread(), false);
Trace.disableTracing(null);
if (PRINT_CNT) {
System.out.println("Number of envs created/destroyed: " + CNT);
diff --git a/test/1942-suspend-raw-monitor-exit/expected.txt b/test/1942-suspend-raw-monitor-exit/expected.txt
new file mode 100644
index 0000000000..182e197c05
--- /dev/null
+++ b/test/1942-suspend-raw-monitor-exit/expected.txt
@@ -0,0 +1,11 @@
+Initial state.
+isLocked() = true
+isSuspended(target_thread) = false
+Suspend and sleep.
+isLocked() = true
+isSuspended(target_thread) = true
+Let other thread release the raw monitor.
+isLocked() = false
+isSuspended(target_thread) = true
+other thread doesn't hold lock!
+resumed test thread
diff --git a/test/1942-suspend-raw-monitor-exit/info.txt b/test/1942-suspend-raw-monitor-exit/info.txt
new file mode 100644
index 0000000000..f608e0685a
--- /dev/null
+++ b/test/1942-suspend-raw-monitor-exit/info.txt
@@ -0,0 +1,3 @@
+Tests jvmti suspending of a thread that is interacting with a raw monitor.
+
+Makes sure that the RawMonitorExit function does not act as a suspend point.
diff --git a/test/1942-suspend-raw-monitor-exit/native_suspend_monitor.cc b/test/1942-suspend-raw-monitor-exit/native_suspend_monitor.cc
new file mode 100644
index 0000000000..b182ad0ecb
--- /dev/null
+++ b/test/1942-suspend-raw-monitor-exit/native_suspend_monitor.cc
@@ -0,0 +1,80 @@
+/*
+ * 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 <atomic>
+
+#include "android-base/logging.h"
+#include "jni.h"
+#include "scoped_local_ref.h"
+#include "scoped_primitive_array.h"
+
+#include "jvmti.h"
+
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
+
+namespace art {
+namespace Test1942SuspendRawMonitorExit {
+
+jrawMonitorID mon;
+std::atomic<bool> should_pause(true);
+std::atomic<bool> paused(false);
+std::atomic<bool> done(false);
+std::atomic<bool> locked(false);
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test1942_nativeRun(JNIEnv* env, jclass) {
+ if (JvmtiErrorToException(
+ env, jvmti_env, jvmti_env->CreateRawMonitor("Test1942 monitor", &mon))) {
+ return;
+ }
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon))) {
+ return;
+ }
+ locked.store(true);
+ while (should_pause.load()) {
+ paused.store(true);
+ }
+ paused.store(false);
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon))) {
+ return;
+ }
+ locked.store(false);
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_art_Test1942_isLocked(JNIEnv*, jclass) {
+ return locked.load();
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test1942_waitForPause(JNIEnv*, jclass) {
+ while (!paused.load()) { }
+}
+extern "C" JNIEXPORT void JNICALL Java_art_Test1942_resume(JNIEnv*, jclass) {
+ should_pause.store(false);
+ while (paused.load()) { }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test1942_grabRawMonitor(JNIEnv* env, jclass) {
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon))) {
+ return;
+ }
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon))) {
+ return;
+ }
+}
+
+} // namespace Test1942SuspendRawMonitorExit
+} // namespace art
diff --git a/test/1942-suspend-raw-monitor-exit/run b/test/1942-suspend-raw-monitor-exit/run
new file mode 100755
index 0000000000..e92b873956
--- /dev/null
+++ b/test/1942-suspend-raw-monitor-exit/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 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.
+
+./default-run "$@" --jvmti
diff --git a/test/1942-suspend-raw-monitor-exit/src/Main.java b/test/1942-suspend-raw-monitor-exit/src/Main.java
new file mode 100644
index 0000000000..0f75bc62d4
--- /dev/null
+++ b/test/1942-suspend-raw-monitor-exit/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * 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 {
+ art.Test1942.run();
+ }
+}
diff --git a/runtime/cdex/compact_dex_level.h b/test/1942-suspend-raw-monitor-exit/src/art/Suspension.java
index b824462bf0..16e62ccac9 100644
--- a/runtime/cdex/compact_dex_level.h
+++ b/test/1942-suspend-raw-monitor-exit/src/art/Suspension.java
@@ -14,21 +14,17 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_CDEX_COMPACT_DEX_LEVEL_H_
-#define ART_RUNTIME_CDEX_COMPACT_DEX_LEVEL_H_
+package art;
-#include "dex_file.h"
+public class Suspension {
+ // Suspends a thread using jvmti.
+ public native static void suspend(Thread thr);
-namespace art {
+ // Resumes a thread using jvmti.
+ public native static void resume(Thread thr);
-// Optimization level for compact dex generation.
-enum class CompactDexLevel {
- // Level none means not generated.
- kCompactDexLevelNone,
- // Level fast means optimizations that don't take many resources to perform.
- kCompactDexLevelFast,
-};
+ public native static boolean isSuspended(Thread thr);
-} // namespace art
-
-#endif // ART_RUNTIME_CDEX_COMPACT_DEX_LEVEL_H_
+ public native static int[] suspendList(Thread... threads);
+ public native static int[] resumeList(Thread... threads);
+}
diff --git a/test/1942-suspend-raw-monitor-exit/src/art/Test1942.java b/test/1942-suspend-raw-monitor-exit/src/art/Test1942.java
new file mode 100644
index 0000000000..eaf756067b
--- /dev/null
+++ b/test/1942-suspend-raw-monitor-exit/src/art/Test1942.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+public class Test1942 {
+ public static void run() throws Exception {
+ final Thread target_thread = new Thread(() -> {
+ nativeRun();
+ }, "target_thread");
+
+ target_thread.start();
+
+ // wait for the other thread to spin holding lock.
+ waitForPause();
+
+ System.out.println("Initial state.");
+ System.out.println("isLocked() = " + isLocked());
+ System.out.println("isSuspended(target_thread) = " + Suspension.isSuspended(target_thread));
+
+ // Suspend it from java.
+ System.out.println("Suspend and sleep.");
+ Suspension.suspend(target_thread);
+ // Wait for the other thread to do something.
+ try { Thread.sleep(1000); } catch (Exception e) {}
+
+ System.out.println("isLocked() = " + isLocked());
+ System.out.println("isSuspended(target_thread) = " + Suspension.isSuspended(target_thread));
+
+ // Let it try to unlock the monitor.
+ System.out.println("Let other thread release the raw monitor.");
+ // Let the thread try to lock the monitor.
+ resume();
+
+ // Wait for the other thread to do something. It should exit by the time this is done if it
+ // has not hit a suspend point.
+ while (isLocked()) {
+ try { Thread.sleep(1000); } catch (Exception e) {}
+ }
+
+ System.out.println("isLocked() = " + isLocked());
+ System.out.println("isSuspended(target_thread) = " + Suspension.isSuspended(target_thread));
+
+ // Make sure the monitor is gone.
+ grabRawMonitor();
+ System.out.println("other thread doesn't hold lock!");
+
+ // Resume it from java
+ System.out.println("resumed test thread");
+ Suspension.resume(target_thread);
+ target_thread.join();
+ }
+
+ public static native void nativeRun();
+ public static native void waitForPause();
+ public static native void resume();
+ public static native boolean isLocked();
+ // Gets then releases raw monitor.
+ public static native void grabRawMonitor();
+}
diff --git a/test/1943-suspend-raw-monitor-wait/expected.txt b/test/1943-suspend-raw-monitor-wait/expected.txt
new file mode 100644
index 0000000000..9bb1ca37d0
--- /dev/null
+++ b/test/1943-suspend-raw-monitor-wait/expected.txt
@@ -0,0 +1,7 @@
+target_thread is sleeping in a wait.
+Suspend target_thread.
+Wake up the target_thread.
+target_thread is sleeping in suspend without lock.
+target_thread.isAlive() = true
+resumed target_thread
+target_thread doesn't hold lock!
diff --git a/test/1943-suspend-raw-monitor-wait/info.txt b/test/1943-suspend-raw-monitor-wait/info.txt
new file mode 100644
index 0000000000..1d716e11d1
--- /dev/null
+++ b/test/1943-suspend-raw-monitor-wait/info.txt
@@ -0,0 +1,4 @@
+Tests jvmti suspending of a thread that is interacting with a raw monitor.
+
+Makes sure that the RawMonitorWait function acts as a suspend point as the
+thread leaves the function.
diff --git a/test/1943-suspend-raw-monitor-wait/native_suspend_monitor.cc b/test/1943-suspend-raw-monitor-wait/native_suspend_monitor.cc
new file mode 100644
index 0000000000..fdfc3c63fc
--- /dev/null
+++ b/test/1943-suspend-raw-monitor-wait/native_suspend_monitor.cc
@@ -0,0 +1,82 @@
+/*
+ * 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 <atomic>
+
+#include "android-base/logging.h"
+#include "jni.h"
+#include "scoped_local_ref.h"
+#include "scoped_primitive_array.h"
+
+#include "jvmti.h"
+
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
+
+namespace art {
+namespace Test1943SuspendRawMonitorExit {
+
+jrawMonitorID mon;
+std::atomic<bool> locked(false);
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test1943_nativeRun(JNIEnv* env, jclass) {
+ if (JvmtiErrorToException(
+ env, jvmti_env, jvmti_env->CreateRawMonitor("Test1943 monitor", &mon))) {
+ return;
+ }
+ // Grab the monitor twice
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon))) {
+ return;
+ }
+ locked.store(true);
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorWait(mon, 0))) {
+ return;
+ }
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon))) {
+ return;
+ }
+ locked.store(false);
+}
+
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test1943_waitForPause(JNIEnv*, jclass) {
+ while (!locked.load()) { }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test1943_nativeNotify(JNIEnv* env, jclass) {
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon))) {
+ return;
+ }
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorNotifyAll(mon))) {
+ return;
+ }
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon))) {
+ return;
+ }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test1943_grabRawMonitor(JNIEnv* env, jclass) {
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon))) {
+ return;
+ }
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon))) {
+ return;
+ }
+}
+
+} // namespace Test1943SuspendRawMonitorExit
+} // namespace art
diff --git a/test/1943-suspend-raw-monitor-wait/run b/test/1943-suspend-raw-monitor-wait/run
new file mode 100755
index 0000000000..e92b873956
--- /dev/null
+++ b/test/1943-suspend-raw-monitor-wait/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 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.
+
+./default-run "$@" --jvmti
diff --git a/test/1943-suspend-raw-monitor-wait/src/Main.java b/test/1943-suspend-raw-monitor-wait/src/Main.java
new file mode 100644
index 0000000000..b95905339f
--- /dev/null
+++ b/test/1943-suspend-raw-monitor-wait/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * 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 {
+ art.Test1943.run();
+ }
+}
diff --git a/test/1943-suspend-raw-monitor-wait/src/art/Suspension.java b/test/1943-suspend-raw-monitor-wait/src/art/Suspension.java
new file mode 100644
index 0000000000..16e62ccac9
--- /dev/null
+++ b/test/1943-suspend-raw-monitor-wait/src/art/Suspension.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+public class Suspension {
+ // Suspends a thread using jvmti.
+ public native static void suspend(Thread thr);
+
+ // Resumes a thread using jvmti.
+ public native static void resume(Thread thr);
+
+ public native static boolean isSuspended(Thread thr);
+
+ public native static int[] suspendList(Thread... threads);
+ public native static int[] resumeList(Thread... threads);
+}
diff --git a/test/1943-suspend-raw-monitor-wait/src/art/Test1943.java b/test/1943-suspend-raw-monitor-wait/src/art/Test1943.java
new file mode 100644
index 0000000000..4be68f3d71
--- /dev/null
+++ b/test/1943-suspend-raw-monitor-wait/src/art/Test1943.java
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+public class Test1943 {
+ public static void run() throws Exception {
+ final Thread target_thread = new Thread(() -> {
+ nativeRun();
+ }, "target_thread");
+
+ target_thread.start();
+
+ // wait for the other thread to spin holding lock.
+ waitForPause();
+
+ // Ensure that the other thread is in a wait.
+ grabRawMonitor();
+ System.out.println("target_thread is sleeping in a wait.");
+
+ // Suspend it from java.
+ System.out.println("Suspend target_thread.");
+ Suspension.suspend(target_thread);
+
+ // Let it try to unlock the monitor.
+ System.out.println("Wake up the target_thread.");
+ // Let the thread try to lock the monitor.
+ nativeNotify();
+
+ // Ensure that the other thread is suspended without the monitor.
+ grabRawMonitor();
+ System.out.println("target_thread is sleeping in suspend without lock.");
+
+ // Check other thread is still alive
+ System.out.println("target_thread.isAlive() = " + target_thread.isAlive());
+
+ // Resume it from java
+ System.out.println("resumed target_thread");
+ Suspension.resume(target_thread);
+
+ // Make sure the monitor is gone.
+ grabRawMonitor();
+ System.out.println("target_thread doesn't hold lock!");
+
+ target_thread.join();
+ }
+
+ public static native void nativeRun();
+ public static native void waitForPause();
+ public static native void nativeNotify();
+ // Gets then releases raw monitor.
+ public static native void grabRawMonitor();
+}
diff --git a/test/445-checker-licm/src/Main.java b/test/445-checker-licm/src/Main.java
index 00ce3a9f8e..9635e70278 100644
--- a/test/445-checker-licm/src/Main.java
+++ b/test/445-checker-licm/src/Main.java
@@ -15,6 +15,11 @@
*/
public class Main {
+ static class Dummy {
+ static int getValue() {
+ return 1;
+ }
+ }
/// CHECK-START: int Main.div() licm (before)
/// CHECK-DAG: Div loop:{{B\d+}}
@@ -107,6 +112,28 @@ public class Main {
return result;
}
+ /// CHECK-START: int Main.clinitCheck() licm (before)
+ /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass loop:<<Loop:B\d+>>
+ /// CHECK-DAG: ClinitCheck [<<LoadClass>>] loop:<<Loop>>
+
+ /// CHECK-START: int Main.clinitCheck() licm (after)
+ /// CHECK-NOT: LoadClass loop:{{B\d+}}
+ /// CHECK-NOT: ClinitCheck loop:{{B\d+}}
+
+ /// CHECK-START: int Main.clinitCheck() licm (after)
+ /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass loop:none
+ /// CHECK-DAG: ClinitCheck [<<LoadClass>>] loop:none
+
+ public static int clinitCheck() {
+ int i = 0;
+ int sum = 0;
+ do {
+ sum += Dummy.getValue();
+ i++;
+ } while (i < 10);
+ return sum;
+ }
+
/// CHECK-START: int Main.divAndIntrinsic(int[]) licm (before)
/// CHECK-DAG: Div loop:{{B\d+}}
@@ -213,6 +240,7 @@ public class Main {
assertEquals(18900, innerMul());
assertEquals(105, divByA(2, 0));
assertEquals(12, arrayLength(new int[] { 4, 8 }));
+ assertEquals(10, clinitCheck());
assertEquals(21, divAndIntrinsic(new int[] { 4, -2, 8, -3 }));
assertEquals(45, invariantBoundIntrinsic(-10));
assertEquals(30, invariantBodyIntrinsic(2, 3));
diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc
index 6cea673b41..aeb9e44541 100644
--- a/test/466-get-live-vreg/get_live_vreg_jni.cc
+++ b/test/466-get-live-vreg/get_live_vreg_jni.cc
@@ -16,6 +16,7 @@
#include "arch/context.h"
#include "art_method-inl.h"
+#include "dex/code_item_accessors-inl.h"
#include "jni.h"
#include "oat_quick_method_header.h"
#include "scoped_thread_state_change-inl.h"
@@ -41,7 +42,7 @@ class TestVisitor : public StackVisitor {
CHECK(GetVReg(m, 0, kIntVReg, &value));
CHECK_EQ(value, 42u);
} else if (m_name.compare("$opt$noinline$testIntervalHole") == 0) {
- uint32_t number_of_dex_registers = m->GetCodeItem()->registers_size_;
+ uint32_t number_of_dex_registers = CodeItemDataAccessor(m).RegistersSize();
uint32_t dex_register_of_first_parameter = number_of_dex_registers - 2;
found_method_ = true;
uint32_t value = 0;
diff --git a/test/518-null-array-get/expected.txt b/test/518-null-array-get/expected.txt
index e69de29bb2..ae5318e53d 100644
--- a/test/518-null-array-get/expected.txt
+++ b/test/518-null-array-get/expected.txt
@@ -0,0 +1,6 @@
+NullArrayFailInt2Object
+NullArrayFailObject2Int
+NullArraySuccessInt
+NullArraySuccessInt2Float
+NullArraySuccessShort
+NullArraySuccessRef
diff --git a/test/518-null-array-get/info.txt b/test/518-null-array-get/info.txt
index 407f590b2b..71e0332e62 100644
--- a/test/518-null-array-get/info.txt
+++ b/test/518-null-array-get/info.txt
@@ -1,3 +1,9 @@
-Regression test for Quick and Optimizing that used
-to crash on an aget-object + int-to-byte sequence
-(accepted by the verifier in the case the array was null).
+Codifies that the verifier should reject type-unsafe
+instructions in dead code after aget on null, but pass
+type-safe dead code.
+
+Previously verification stopped after aget on null and
+punted the method to the interpreter in an effort to avoid
+compiler crashes. As broken code appears very uncommon,
+ensure verifier strictness and help the compilers see more
+code.
diff --git a/test/518-null-array-get/smali/NullArrayFailInt2Object.smali b/test/518-null-array-get/smali/NullArrayFailInt2Object.smali
new file mode 100644
index 0000000000..ca4ed10660
--- /dev/null
+++ b/test/518-null-array-get/smali/NullArrayFailInt2Object.smali
@@ -0,0 +1,28 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Check that the result of aget on null cannot be used as a reference.
+
+.class public LNullArrayFailInt2Object;
+
+.super Ljava/lang/Object;
+
+.method public static method()V
+ .registers 2
+ const/4 v0, 0
+ const/4 v1, 0
+ aget v0, v0, v1
+ invoke-virtual { v0 }, Ljava/lang/Object;->toString()Ljava/lang/String;
+ return-void
+.end method
diff --git a/test/518-null-array-get/smali/NullArray.smali b/test/518-null-array-get/smali/NullArrayFailObject2Int.smali
index 52abc38473..83823a24e5 100644
--- a/test/518-null-array-get/smali/NullArray.smali
+++ b/test/518-null-array-get/smali/NullArrayFailObject2Int.smali
@@ -12,7 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-.class public LNullArray;
+# Check that the result of aget-object on null cannot be used as an integral.
+
+.class public LNullArrayFailObject2Int;
.super Ljava/lang/Object;
diff --git a/test/518-null-array-get/smali/NullArraySuccessInt.smali b/test/518-null-array-get/smali/NullArraySuccessInt.smali
new file mode 100644
index 0000000000..01cf1c92ab
--- /dev/null
+++ b/test/518-null-array-get/smali/NullArraySuccessInt.smali
@@ -0,0 +1,33 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Check that the result of aget on null can be used as an int.
+
+.class public LNullArraySuccessInt;
+
+.super Ljava/lang/Object;
+
+.method public static intMethod(I)V
+ .registers 1
+ return-void
+.end method
+
+.method public static method()V
+ .registers 2
+ const/4 v0, 0
+ const/4 v1, 0
+ aget v0, v0, v1
+ invoke-static { v0 }, LNullArraySuccessInt;->intMethod(I)V
+ return-void
+.end method
diff --git a/test/518-null-array-get/smali/NullArraySuccessInt2Float.smali b/test/518-null-array-get/smali/NullArraySuccessInt2Float.smali
new file mode 100644
index 0000000000..bd59d5f68e
--- /dev/null
+++ b/test/518-null-array-get/smali/NullArraySuccessInt2Float.smali
@@ -0,0 +1,33 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Check that the result of aget on null can be used as a float.
+
+.class public LNullArraySuccessInt2Float;
+
+.super Ljava/lang/Object;
+
+.method public static floatMethod(F)V
+ .registers 1
+ return-void
+.end method
+
+.method public static method()V
+ .registers 2
+ const/4 v0, 0
+ const/4 v1, 0
+ aget v0, v0, v1
+ invoke-static { v0 }, LNullArraySuccessInt2Float;->floatMethod(F)V
+ return-void
+.end method
diff --git a/test/518-null-array-get/smali/NullArraySuccessRef.smali b/test/518-null-array-get/smali/NullArraySuccessRef.smali
new file mode 100644
index 0000000000..2f512d4089
--- /dev/null
+++ b/test/518-null-array-get/smali/NullArraySuccessRef.smali
@@ -0,0 +1,33 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Check that the result of aget-object on null can be used as a reference.
+
+.class public LNullArraySuccessRef;
+
+.super Ljava/lang/Object;
+
+.method public voidMethod()V
+ .registers 1
+ return-void
+.end method
+
+.method public static method()V
+ .registers 2
+ const/4 v0, 0
+ const/4 v1, 0
+ aget-object v0, v0, v1
+ invoke-virtual { v0 }, LNullArraySuccessRef;->voidMethod()V
+ return-void
+.end method
diff --git a/test/518-null-array-get/smali/NullArraySuccessShort.smali b/test/518-null-array-get/smali/NullArraySuccessShort.smali
new file mode 100644
index 0000000000..d332e51f52
--- /dev/null
+++ b/test/518-null-array-get/smali/NullArraySuccessShort.smali
@@ -0,0 +1,33 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Check that the result of aget-short on null can be used as a short.
+
+.class public LNullArraySuccessShort;
+
+.super Ljava/lang/Object;
+
+.method public static shortMethod(S)V
+ .registers 1
+ return-void
+.end method
+
+.method public static method()V
+ .registers 2
+ const/4 v0, 0
+ const/4 v1, 0
+ aget-short v0, v0, v1
+ invoke-static { v0 }, LNullArraySuccessShort;->shortMethod(S)V
+ return-void
+.end method
diff --git a/test/518-null-array-get/src/Main.java b/test/518-null-array-get/src/Main.java
index 66e50aacd7..678aef1f43 100644
--- a/test/518-null-array-get/src/Main.java
+++ b/test/518-null-array-get/src/Main.java
@@ -22,16 +22,36 @@ public class Main {
class InnerClass {}
public static void main(String[] args) throws Exception {
- Class<?> c = Class.forName("NullArray");
- Method m = c.getMethod("method");
- Object[] arguments = { };
+ checkLoad("NullArrayFailInt2Object", true);
+ checkLoad("NullArrayFailObject2Int", true);
+ checkLoad("NullArraySuccessInt", false);
+ checkLoad("NullArraySuccessInt2Float", false);
+ checkLoad("NullArraySuccessShort", false);
+ checkLoad("NullArraySuccessRef", false);
+ }
+
+ private static void checkLoad(String className, boolean expectError) throws Exception {
+ Class<?> c;
try {
- m.invoke(null, arguments);
- throw new Error("Expected an InvocationTargetException");
- } catch (InvocationTargetException e) {
- if (!(e.getCause() instanceof NullPointerException)) {
- throw new Error("Expected a NullPointerException");
+ c = Class.forName(className);
+ if (expectError) {
+ throw new RuntimeException("Expected error for " + className);
+ }
+ Method m = c.getMethod("method");
+ try {
+ m.invoke(null);
+ throw new RuntimeException("Expected an InvocationTargetException");
+ } catch (InvocationTargetException e) {
+ if (!(e.getCause() instanceof NullPointerException)) {
+ throw new RuntimeException("Expected a NullPointerException");
+ }
+ System.out.println(className);
+ }
+ } catch (VerifyError e) {
+ if (!expectError) {
+ throw new RuntimeException(e);
}
+ System.out.println(className);
}
}
}
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index c4cc3b0121..f6332b5503 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -999,6 +999,24 @@ public class Main {
return res;
}
+ /// CHECK-START: void Main.testStoreSameValue() load_store_elimination (before)
+ /// CHECK: NewArray
+ /// CHECK: ArrayGet
+ /// CHECK: ArraySet
+
+ /// CHECK-START: void Main.testStoreSameValue() load_store_elimination (after)
+ /// CHECK: NewArray
+ /// CHECK-NOT: ArrayGet
+ /// CHECK-NOT: ArraySet
+ private static void testStoreSameValue() {
+ Object[] array = new Object[2];
+ sArray = array;
+ Object obj = array[0];
+ array[1] = obj; // store the same value as the defaut value.
+ }
+
+ static Object[] sArray;
+
static void assertIntEquals(int result, int expected) {
if (expected != result) {
throw new Error("Expected: " + expected + ", found: " + result);
diff --git a/test/530-checker-lse3/expected.txt b/test/530-checker-lse3/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/530-checker-lse3/expected.txt
diff --git a/test/530-checker-lse3/info.txt b/test/530-checker-lse3/info.txt
new file mode 100644
index 0000000000..29b4cb82ab
--- /dev/null
+++ b/test/530-checker-lse3/info.txt
@@ -0,0 +1,4 @@
+Regression test for load store elimination not respecting the loaded type. When
+a wider value is stored in a narrower field and then loaded from that field,
+LSE needs to replace the value to be stored with a type conversion to the
+narrower type.
diff --git a/test/530-checker-lse3/smali/StoreLoad.smali b/test/530-checker-lse3/smali/StoreLoad.smali
new file mode 100644
index 0000000000..7fb582c8d1
--- /dev/null
+++ b/test/530-checker-lse3/smali/StoreLoad.smali
@@ -0,0 +1,62 @@
+# 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.
+
+.class public LStoreLoad;
+
+.super Ljava/lang/Object;
+
+## CHECK-START: int StoreLoad.test(int) load_store_elimination (before)
+## CHECK-DAG: <<Arg:i\d+>> ParameterValue
+## CHECK-DAG: StaticFieldSet [{{l\d+}},<<Arg>>] field_name:StoreLoad.byteField
+## CHECK-DAG: StaticFieldSet [{{l\d+}},<<Arg>>] field_name:StoreLoad.byteField2
+## CHECK-DAG: <<Val:b\d+>> StaticFieldGet [{{l\d+}}] field_name:StoreLoad.byteField
+## CHECK-DAG: <<Val2:b\d+>> StaticFieldGet [{{l\d+}}] field_name:StoreLoad.byteField2
+## CHECK-DAG: <<Val3:i\d+>> Add [<<Val>>,<<Val2>>]
+## CHECK-DAG: Return [<<Val3>>]
+
+## CHECK-START: int StoreLoad.test(int) load_store_elimination (after)
+## CHECK-NOT: StaticFieldGet
+
+## CHECK-START: int StoreLoad.test(int) load_store_elimination (after)
+## CHECK-DAG: <<Arg:i\d+>> ParameterValue
+## CHECK-DAG: StaticFieldSet [{{l\d+}},<<Arg>>] field_name:StoreLoad.byteField
+## CHECK-DAG: StaticFieldSet [{{l\d+}},<<Arg>>] field_name:StoreLoad.byteField2
+## CHECK-DAG: <<Conv:b\d+>> TypeConversion [<<Arg>>]
+## CHECK-DAG: <<Val3:i\d+>> Add [<<Conv>>,<<Conv>>]
+## CHECK-DAG: Return [<<Val3>>]
+.method public static test(I)I
+ .registers 2
+ sput-byte v1, LStoreLoad;->byteField:B
+ sput-byte v1, LStoreLoad;->byteField2:B
+ sget-byte v0, LStoreLoad;->byteField:B
+ sget-byte v1, LStoreLoad;->byteField2:B
+ add-int/2addr v0, v1
+ return v0
+.end method
+
+## CHECK-START: int StoreLoad.test2(int) load_store_elimination (before)
+## CHECK-DAG: <<Arg:i\d+>> ParameterValue
+## CHECK-DAG: StaticFieldSet [{{l\d+}},<<Arg>>] field_name:StoreLoad.byteField
+## CHECK-DAG: Return [<<Arg>>]
+
+## CHECK-START: int StoreLoad.test2(int) load_store_elimination (after)
+## CHECK-NOT: TypeConversion
+.method public static test2(I)I
+ .registers 1
+ sput-byte v0, LStoreLoad;->byteField:B
+ return v0
+.end method
+
+.field public static byteField:B
+.field public static byteField2:B
diff --git a/test/530-checker-lse3/src/Main.java b/test/530-checker-lse3/src/Main.java
new file mode 100644
index 0000000000..caef0b33cc
--- /dev/null
+++ b/test/530-checker-lse3/src/Main.java
@@ -0,0 +1,48 @@
+/*
+ * 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.Method;
+import java.lang.reflect.Field;
+
+public class Main {
+
+ // Workaround for b/18051191.
+ class InnerClass {}
+
+ public static void main(String[] args) throws Exception {
+ Class<?> c = Class.forName("StoreLoad");
+ Method m = c.getMethod("test", int.class);
+ int result = (Integer)m.invoke(null, 0x12345678);
+ if (result != (0x78 + 0x78)) {
+ throw new Error("Expected 240, got " + result);
+ }
+ m = c.getMethod("test2", int.class);
+ result = (Integer)m.invoke(null, 0xdeadbeef);
+ if (result != 0xdeadbeef) {
+ throw new Error("Expected 0xdeadbeef, got " + result);
+ }
+ Field f = c.getDeclaredField("byteField");
+ byte b = f.getByte(null);
+ if (b != (byte)0xef) {
+ throw new Error("Expected 0xef, got " + b);
+ }
+ f = c.getDeclaredField("byteField2");
+ b = f.getByte(null);
+ if (b != (byte)0x78) {
+ throw new Error("Expected 0xef, got " + b);
+ }
+ }
+}
diff --git a/test/532-checker-nonnull-arrayset/src/Main.java b/test/532-checker-nonnull-arrayset/src/Main.java
index 61c9e88e9e..f6f877c559 100644
--- a/test/532-checker-nonnull-arrayset/src/Main.java
+++ b/test/532-checker-nonnull-arrayset/src/Main.java
@@ -29,9 +29,7 @@ public class Main {
/// CHECK-NOT: test
/// CHECK: ReturnVoid
public static void test() {
- Object[] array = new Object[2];
- // Storing to static to avoid some lse optimization.
- sArray = array;
+ Object[] array = sArray;
Object nonNull = array[0];
nonNull.getClass(); // Ensure nonNull has an implicit null check.
array[1] = nonNull;
diff --git a/test/550-checker-multiply-accumulate/src/Main.java b/test/550-checker-multiply-accumulate/src/Main.java
index 9e6fd3d96a..b76efeac15 100644
--- a/test/550-checker-multiply-accumulate/src/Main.java
+++ b/test/550-checker-multiply-accumulate/src/Main.java
@@ -424,31 +424,19 @@ public class Main {
return - (left * right);
}
- /// CHECK-START-ARM64: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (before)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
- /// CHECK-START-ARM64: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (after)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecMultiplyAccumulate kind:Add loop:<<Loop>> outer_loop:none
- /// CHECK-START-ARM64: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (after)
/// CHECK-NOT: VecMul
/// CHECK-NOT: VecAdd
- /// CHECK-START-MIPS64: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (before)
- /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
-
- /// CHECK-START-MIPS64: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (after)
- /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecMultiplyAccumulate kind:Add loop:<<Loop>> outer_loop:none
-
- /// CHECK-START-MIPS64: void Main.SimdMulAdd(int[], int[]) instruction_simplifier$after_bce (after)
- /// CHECK-NOT: VecMul
- /// CHECK-NOT: VecAdd
public static void SimdMulAdd(int[] array1, int[] array2) {
for (int j = 0; j < 100; j++) {
array2[j] += 12345 * array1[j];
@@ -473,31 +461,19 @@ public class Main {
}
}
- /// CHECK-START-ARM64: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (before)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
- /// CHECK-START-ARM64: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (after)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecMultiplyAccumulate kind:Sub loop:<<Loop>> outer_loop:none
- /// CHECK-START-ARM64: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (after)
/// CHECK-NOT: VecMul
/// CHECK-NOT: VecSub
- /// CHECK-START-MIPS64: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (before)
- /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
-
- /// CHECK-START-MIPS64: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (after)
- /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecMultiplyAccumulate kind:Sub loop:<<Loop>> outer_loop:none
-
- /// CHECK-START-MIPS64: void Main.SimdMulSub(int[], int[]) instruction_simplifier$after_bce (after)
- /// CHECK-NOT: VecMul
- /// CHECK-NOT: VecSub
public static void SimdMulSub(int[] array1, int[] array2) {
for (int j = 0; j < 100; j++) {
array2[j] -= 12345 * array1[j];
@@ -522,21 +498,14 @@ public class Main {
}
}
- /// CHECK-START-ARM64: void Main.SimdMulMultipleUses(int[], int[]) instruction_simplifier$after_bce (before)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.SimdMulMultipleUses(int[], int[]) instruction_simplifier$after_bce (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
- /// CHECK-START-ARM64: void Main.SimdMulMultipleUses(int[], int[]) instruction_simplifier$after_bce (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.SimdMulMultipleUses(int[], int[]) instruction_simplifier$after_bce (after)
/// CHECK-NOT: VecMultiplyAccumulate
- /// CHECK-START-MIPS64: void Main.SimdMulMultipleUses(int[], int[]) instruction_simplifier$after_bce (before)
- /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
-
- /// CHECK-START-MIPS64: void Main.SimdMulMultipleUses(int[], int[]) instruction_simplifier$after_bce (after)
- /// CHECK-NOT: VecMultiplyAccumulate
public static void SimdMulMultipleUses(int[] array1, int[] array2) {
for (int j = 0; j < 100; j++) {
int temp = 12345 * array1[j];
diff --git a/test/552-checker-sharpening/src/Main.java b/test/552-checker-sharpening/src/Main.java
index 55873eabf0..3173afdfcd 100644
--- a/test/552-checker-sharpening/src/Main.java
+++ b/test/552-checker-sharpening/src/Main.java
@@ -44,24 +44,11 @@ public class Main {
/// CHECK-START: int Main.testSimple(int) sharpening (before)
/// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall
- /// CHECK-START-ARM: int Main.testSimple(int) sharpening (after)
+ /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: int Main.testSimple(int) sharpening (after)
/// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
- /// CHECK-START-ARM64: int Main.testSimple(int) sharpening (after)
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
-
- /// CHECK-START-MIPS: int Main.testSimple(int) sharpening (after)
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
-
- /// CHECK-START-MIPS64: int Main.testSimple(int) sharpening (after)
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
-
- /// CHECK-START-X86: int Main.testSimple(int) sharpening (after)
+ /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (before)
/// CHECK-NOT: X86ComputeBaseMethodAddress
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
-
- /// CHECK-START-X86_64: int Main.testSimple(int) sharpening (after)
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
/// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (after)
/// CHECK: X86ComputeBaseMethodAddress
@@ -74,31 +61,14 @@ public class Main {
/// CHECK-START: int Main.testDiamond(boolean, int) sharpening (before)
/// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall
+ /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall
- /// CHECK-START-ARM: int Main.testDiamond(boolean, int) sharpening (after)
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
-
- /// CHECK-START-ARM64: int Main.testDiamond(boolean, int) sharpening (after)
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
-
- /// CHECK-START-MIPS: int Main.testDiamond(boolean, int) sharpening (after)
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
-
- /// CHECK-START-MIPS64: int Main.testDiamond(boolean, int) sharpening (after)
+ /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: int Main.testDiamond(boolean, int) sharpening (after)
/// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
/// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
- /// CHECK-START-X86: int Main.testDiamond(boolean, int) sharpening (after)
+ /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (before)
/// CHECK-NOT: X86ComputeBaseMethodAddress
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
-
- /// CHECK-START-X86_64: int Main.testDiamond(boolean, int) sharpening (after)
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
- /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry
/// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after)
/// CHECK: X86ComputeBaseMethodAddress
@@ -169,30 +139,7 @@ public class Main {
return x;
}
- /// CHECK-START: java.lang.String Main.$noinline$getBootImageString() sharpening (before)
- /// CHECK: LoadString load_kind:RuntimeCall
-
- /// CHECK-START-X86: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
- // Note: load kind depends on PIC/non-PIC
- /// CHECK: LoadString load_kind:{{BootImageAddress|BootImageInternTable}}
-
- /// CHECK-START-X86_64: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
- // Note: load kind depends on PIC/non-PIC
- /// CHECK: LoadString load_kind:{{BootImageAddress|BootImageInternTable}}
-
- /// CHECK-START-ARM: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
- // Note: load kind depends on PIC/non-PIC
- /// CHECK: LoadString load_kind:{{BootImageAddress|BootImageInternTable}}
-
- /// CHECK-START-ARM64: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
- // Note: load kind depends on PIC/non-PIC
- /// CHECK: LoadString load_kind:{{BootImageAddress|BootImageInternTable}}
-
- /// CHECK-START-MIPS: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
- // Note: load kind depends on PIC/non-PIC
- /// CHECK: LoadString load_kind:{{BootImageAddress|BootImageInternTable}}
-
- /// CHECK-START-MIPS64: java.lang.String Main.$noinline$getBootImageString() sharpening (after)
+ /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$getBootImageString() builder (after)
// Note: load kind depends on PIC/non-PIC
/// CHECK: LoadString load_kind:{{BootImageAddress|BootImageInternTable}}
@@ -203,31 +150,16 @@ public class Main {
return "";
}
- /// CHECK-START: java.lang.String Main.$noinline$getNonBootImageString() sharpening (before)
- /// CHECK: LoadString load_kind:RuntimeCall
-
- /// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
+ /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$getNonBootImageString() builder (after)
/// CHECK: LoadString load_kind:BssEntry
+ /// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() pc_relative_fixups_x86 (before)
+ /// CHECK-NOT: X86ComputeBaseMethodAddress
+
/// CHECK-START-X86: java.lang.String Main.$noinline$getNonBootImageString() pc_relative_fixups_x86 (after)
/// CHECK-DAG: X86ComputeBaseMethodAddress
/// CHECK-DAG: LoadString load_kind:BssEntry
- /// CHECK-START-X86_64: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
- /// CHECK: LoadString load_kind:BssEntry
-
- /// CHECK-START-ARM: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
- /// CHECK: LoadString load_kind:BssEntry
-
- /// CHECK-START-ARM64: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
- /// CHECK: LoadString load_kind:BssEntry
-
- /// CHECK-START-MIPS: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
- /// CHECK: LoadString load_kind:BssEntry
-
- /// CHECK-START-MIPS64: java.lang.String Main.$noinline$getNonBootImageString() sharpening (after)
- /// CHECK: LoadString load_kind:BssEntry
-
public static String $noinline$getNonBootImageString() {
// Prevent inlining to avoid the string comparison being optimized away.
if (doThrow) { throw new Error(); }
@@ -235,27 +167,7 @@ public class Main {
return "non-boot-image-string";
}
- /// CHECK-START-X86: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
- // Note: load kind depends on PIC/non-PIC
- /// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String
-
- /// CHECK-START-X86_64: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
- // Note: load kind depends on PIC/non-PIC
- /// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String
-
- /// CHECK-START-ARM: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
- // Note: load kind depends on PIC/non-PIC
- /// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String
-
- /// CHECK-START-ARM64: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
- // Note: load kind depends on PIC/non-PIC
- /// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String
-
- /// CHECK-START-MIPS: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
- // Note: load kind depends on PIC/non-PIC
- /// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String
-
- /// CHECK-START-MIPS64: java.lang.Class Main.$noinline$getStringClass() sharpening (after)
+ /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.Class Main.$noinline$getStringClass() builder (after)
// Note: load kind depends on PIC/non-PIC
/// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String
@@ -266,28 +178,16 @@ public class Main {
return String.class;
}
- /// CHECK-START-X86: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
+ /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.Class Main.$noinline$getOtherClass() builder (after)
/// CHECK: LoadClass load_kind:BssEntry class_name:Other
+ /// CHECK-START-X86: java.lang.Class Main.$noinline$getOtherClass() pc_relative_fixups_x86 (before)
+ /// CHECK-NOT: X86ComputeBaseMethodAddress
+
/// CHECK-START-X86: java.lang.Class Main.$noinline$getOtherClass() pc_relative_fixups_x86 (after)
/// CHECK-DAG: X86ComputeBaseMethodAddress
/// CHECK-DAG: LoadClass load_kind:BssEntry class_name:Other
- /// CHECK-START-X86_64: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
- /// CHECK: LoadClass load_kind:BssEntry class_name:Other
-
- /// CHECK-START-ARM: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
- /// CHECK: LoadClass load_kind:BssEntry class_name:Other
-
- /// CHECK-START-ARM64: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
- /// CHECK: LoadClass load_kind:BssEntry class_name:Other
-
- /// CHECK-START-MIPS: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
- /// CHECK: LoadClass load_kind:BssEntry class_name:Other
-
- /// CHECK-START-MIPS64: java.lang.Class Main.$noinline$getOtherClass() sharpening (after)
- /// CHECK: LoadClass load_kind:BssEntry class_name:Other
-
public static Class<?> $noinline$getOtherClass() {
// Prevent inlining to avoid the string comparison being optimized away.
if (doThrow) { throw new Error(); }
diff --git a/test/595-profile-saving/profile-saving.cc b/test/595-profile-saving/profile-saving.cc
index 06e3fb48fc..b2af91e49f 100644
--- a/test/595-profile-saving/profile-saving.cc
+++ b/test/595-profile-saving/profile-saving.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "art_method-inl.h"
#include "jit/profile_compilation_info.h"
diff --git a/test/603-checker-instanceof/src/Main.java b/test/603-checker-instanceof/src/Main.java
index ddf4b92fba..1487969c03 100644
--- a/test/603-checker-instanceof/src/Main.java
+++ b/test/603-checker-instanceof/src/Main.java
@@ -22,12 +22,17 @@ class ChildClass extends SuperClass {
public class Main {
- /// CHECK-START: void Main.main(java.lang.String[]) builder (after)
+ public static void main(String[] args) {
+ test1();
+ test2();
+ }
+
+ /// CHECK-START: void Main.test1() builder (after)
/// CHECK: BoundType klass:SuperClass can_be_null:false exact:false
- /// CHECK-START: void Main.main(java.lang.String[]) builder (after)
+ /// CHECK-START: void Main.test1() builder (after)
/// CHECK-NOT: BoundType klass:SuperClass can_be_null:false exact:true
- public static void main(String[] args) {
+ public static void test1() {
Object obj = new ChildClass();
// We need a fixed point iteration to hit the bogus type update
@@ -45,4 +50,33 @@ public class Main {
}
}
}
+
+ /// CHECK-START-X86: boolean Main.$noinline$instanceOfString(java.lang.Object) disassembly (after)
+ /// CHECK: InstanceOf check_kind:exact_check
+ /// CHECK-NOT: {{.*fs:.*}}
+
+ /// CHECK-START-X86_64: boolean Main.$noinline$instanceOfString(java.lang.Object) disassembly (after)
+ /// CHECK: InstanceOf check_kind:exact_check
+ /// CHECK-NOT: {{.*gs:.*}}
+
+ /// CHECK-START-{ARM,ARM64}: boolean Main.$noinline$instanceOfString(java.lang.Object) disassembly (after)
+ /// CHECK: InstanceOf check_kind:exact_check
+ // For ARM and ARM64, the marking register (r8 and x20, respectively) can be used in
+ // non-CC configs for any other purpose, so we'd need a config-specific checker test.
+ // TODO: Add the checks when we support config-specific tests.
+ public static boolean $noinline$instanceOfString(Object o) {
+ // String is a final class, so `instanceof String` should use exact check.
+ // String is in the boot image, so we should avoid read barriers. The presence
+ // of the read barrier can be checked in the architecture-specific disassembly.
+ return o instanceof String;
+ }
+
+ public static void test2() {
+ if ($noinline$instanceOfString(new Object())) {
+ throw new Error();
+ }
+ if (!$noinline$instanceOfString(new String())) {
+ throw new Error();
+ }
+ }
}
diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java
index 3ef8fe64bb..29f3817afb 100644
--- a/test/623-checker-loop-regressions/src/Main.java
+++ b/test/623-checker-loop-regressions/src/Main.java
@@ -493,6 +493,95 @@ public class Main {
}
}
+ // Avoid bad scheduler-SIMD interaction.
+ static int doNotMoveSIMD() {
+ int sum = 0;
+ for (int j = 0; j <= 8; j++) {
+ int[] a = new int[17]; // a[i] = 0;
+ // ConstructorFence ?
+ for (int i = 0; i < a.length; i++) {
+ a[i] += 1; // a[i] = 1;
+ }
+ for (int i = 0; i < a.length; i++) {
+ sum += a[i]; // expect a[i] = 1;
+ }
+ }
+ return sum;
+ }
+
+ // Ensure spilling saves full SIMD values.
+ private static final int reduction32Values(int[] a, int[] b, int[] c, int[] d) {
+ int s0 = 0;
+ int s1 = 0;
+ int s2 = 0;
+ int s3 = 0;
+ int s4 = 0;
+ int s5 = 0;
+ int s6 = 0;
+ int s7 = 0;
+ int s8 = 0;
+ int s9 = 0;
+ int s10 = 0;
+ int s11 = 0;
+ int s12 = 0;
+ int s13 = 0;
+ int s14 = 0;
+ int s15 = 0;
+ int s16 = 0;
+ int s17 = 0;
+ int s18 = 0;
+ int s19 = 0;
+ int s20 = 0;
+ int s21 = 0;
+ int s22 = 0;
+ int s23 = 0;
+ int s24 = 0;
+ int s25 = 0;
+ int s26 = 0;
+ int s27 = 0;
+ int s28 = 0;
+ int s29 = 0;
+ int s30 = 0;
+ int s31 = 0;
+ for (int i = 1; i < 100; i++) {
+ s0 += a[i];
+ s1 += b[i];
+ s2 += c[i];
+ s3 += d[i];
+ s4 += a[i];
+ s5 += b[i];
+ s6 += c[i];
+ s7 += d[i];
+ s8 += a[i];
+ s9 += b[i];
+ s10 += c[i];
+ s11 += d[i];
+ s12 += a[i];
+ s13 += b[i];
+ s14 += c[i];
+ s15 += d[i];
+ s16 += a[i];
+ s17 += b[i];
+ s18 += c[i];
+ s19 += d[i];
+ s20 += a[i];
+ s21 += b[i];
+ s22 += c[i];
+ s23 += d[i];
+ s24 += a[i];
+ s25 += b[i];
+ s26 += c[i];
+ s27 += d[i];
+ s28 += a[i];
+ s29 += b[i];
+ s30 += c[i];
+ s31 += d[i];
+ }
+ return s0 + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15 +
+ s16 + s17 + s18 + s19 + s20 + s21 + s22 + s23 +
+ s24 + s25 + s26 + s27 + s28 + s29 + s30 + s31;
+ }
+
public static void main(String[] args) {
expectEquals(10, earlyExitFirst(-1));
for (int i = 0; i <= 10; i++) {
@@ -655,6 +744,22 @@ public class Main {
expectEquals((byte)((short) cx[i] + 1), b1[i]);
}
+ expectEquals(153, doNotMoveSIMD());
+
+ {
+ int[] a1 = new int[100];
+ int[] a2 = new int[100];
+ int[] a3 = new int[100];
+ int[] a4 = new int[100];
+ for (int i = 0; i < 100; i++) {
+ a1[i] = i;
+ a2[i] = 1;
+ a3[i] = 100 - i;
+ a4[i] = i % 16;
+ }
+ expectEquals(85800, reduction32Values(a1, a2, a3, a4));
+ }
+
System.out.println("passed");
}
diff --git a/test/626-const-class-linking/clear_dex_cache_types.cc b/test/626-const-class-linking/clear_dex_cache_types.cc
index e1af02edfd..96ef2665cb 100644
--- a/test/626-const-class-linking/clear_dex_cache_types.cc
+++ b/test/626-const-class-linking/clear_dex_cache_types.cc
@@ -36,10 +36,10 @@ extern "C" JNIEXPORT void JNICALL Java_Main_nativeSkipVerification(JNIEnv*, jcla
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> klass = hs.NewHandle(soa.Decode<mirror::Class>(cls));
- mirror::Class::Status status = klass->GetStatus();
- if (status == mirror::Class::kStatusResolved) {
+ ClassStatus status = klass->GetStatus();
+ if (status == ClassStatus::kResolved) {
ObjectLock<mirror::Class> lock(soa.Self(), klass);
- klass->SetStatus(klass, mirror::Class::kStatusVerified, soa.Self());
+ klass->SetStatus(klass, ClassStatus::kVerified, soa.Self());
} else {
LOG(ERROR) << klass->PrettyClass() << " has unexpected status: " << status;
}
diff --git a/test/706-jit-skip-compilation/expected.txt b/test/638-checker-inline-cache-intrinsic/expected.txt
index 6a5618ebc6..6a5618ebc6 100644
--- a/test/706-jit-skip-compilation/expected.txt
+++ b/test/638-checker-inline-cache-intrinsic/expected.txt
diff --git a/test/638-checker-inline-cache-intrinsic/info.txt b/test/638-checker-inline-cache-intrinsic/info.txt
new file mode 100644
index 0000000000..764577be54
--- /dev/null
+++ b/test/638-checker-inline-cache-intrinsic/info.txt
@@ -0,0 +1 @@
+Verify the devirtualization of a method that should be intrinsified.
diff --git a/test/706-jit-skip-compilation/run b/test/638-checker-inline-cache-intrinsic/run
index 6c5720a099..f43681dd56 100644
--- a/test/706-jit-skip-compilation/run
+++ b/test/638-checker-inline-cache-intrinsic/run
@@ -1,6 +1,6 @@
#!/bin/bash
#
-# Copyright (C) 2016 The Android Open Source Project
+# 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.
@@ -14,6 +14,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Run without the app image, otherwise the verification results will be cached
-# in the ArtMethod of the image and the test will be skewed.
-exec ${RUN} "${@}" --no-app-image
+exec ${RUN} --jit --runtime-option -Xjitthreshold:100 -Xcompiler-option --verbose-methods=inlineMonomorphic,knownReceiverType,stringEquals $@
diff --git a/test/638-checker-inline-cache-intrinsic/src/Main.java b/test/638-checker-inline-cache-intrinsic/src/Main.java
new file mode 100644
index 0000000000..472cbf68bc
--- /dev/null
+++ b/test/638-checker-inline-cache-intrinsic/src/Main.java
@@ -0,0 +1,95 @@
+/*
+ * 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 {
+
+ /// CHECK-START: char Main.$noinline$inlineMonomorphic(java.lang.CharSequence) inliner (before)
+ /// CHECK: InvokeInterface method_name:java.lang.CharSequence.charAt
+
+ /// CHECK-START: char Main.$noinline$inlineMonomorphic(java.lang.CharSequence) inliner (after)
+ /// CHECK: Deoptimize
+ /// CHECK: InvokeVirtual method_name:java.lang.String.charAt intrinsic:StringCharAt
+
+ /// CHECK-START: char Main.$noinline$inlineMonomorphic(java.lang.CharSequence) instruction_simplifier$after_inlining (after)
+ /// CHECK: Deoptimize
+ /// CHECK-NOT: InvokeInterface
+ /// CHECK-NOT: InvokeVirtual
+
+ public static char $noinline$inlineMonomorphic(CharSequence cs) {
+ return cs.charAt(0);
+ }
+
+ /// CHECK-START: char Main.$noinline$knownReceiverType() inliner (before)
+ /// CHECK: InvokeInterface method_name:java.lang.CharSequence.charAt
+
+ /// CHECK-START: char Main.$noinline$knownReceiverType() inliner (after)
+ /// CHECK: InvokeVirtual method_name:java.lang.String.charAt intrinsic:StringCharAt
+
+ /// CHECK-START: char Main.$noinline$knownReceiverType() instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: InvokeInterface
+ /// CHECK-NOT: InvokeVirtual
+
+ public static char $noinline$knownReceiverType() {
+ CharSequence cs = "abc";
+ return cs.charAt(1);
+ }
+
+ /// CHECK-START: boolean Main.$noinline$stringEquals(java.lang.Object) inliner (before)
+ /// CHECK: InvokeVirtual method_name:java.lang.Object.equals intrinsic:None
+
+ /// CHECK-START: boolean Main.$noinline$stringEquals(java.lang.Object) inliner (after)
+ /// CHECK: Deoptimize
+ /// CHECK: InvokeVirtual method_name:java.lang.Object.equals intrinsic:StringEquals
+
+ /// CHECK-START: boolean Main.$noinline$stringEquals(java.lang.Object) instruction_simplifier$after_inlining (after)
+ /// CHECK: Deoptimize
+ /// CHECK: InvokeVirtual method_name:java.lang.Object.equals intrinsic:StringEquals
+
+ public static boolean $noinline$stringEquals(Object obj) {
+ return obj.equals("def");
+ }
+
+ public static void test() {
+ // Warm up inline cache.
+ for (int i = 0; i < 45; i++) {
+ $noinline$inlineMonomorphic(str);
+ }
+ for (int i = 0; i < 60; i++) {
+ $noinline$stringEquals(str);
+ }
+ ensureJitCompiled(Main.class, "$noinline$stringEquals");
+ ensureJitCompiled(Main.class, "$noinline$inlineMonomorphic");
+ ensureJitCompiled(Main.class, "$noinline$knownReceiverType");
+ if ($noinline$inlineMonomorphic(str) != 'x') {
+ throw new Error("Expected x");
+ }
+ if ($noinline$knownReceiverType() != 'b') {
+ throw new Error("Expected b");
+ }
+ if ($noinline$stringEquals("abc")) {
+ throw new Error("Expected false");
+ }
+ }
+
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+ test();
+ }
+
+ static String str = "xyz";
+
+ private static native void ensureJitCompiled(Class<?> itf, String method_name);
+}
diff --git a/test/640-checker-boolean-simd/src/Main.java b/test/640-checker-boolean-simd/src/Main.java
index 347f916c8d..7d98e68a5a 100644
--- a/test/640-checker-boolean-simd/src/Main.java
+++ b/test/640-checker-boolean-simd/src/Main.java
@@ -29,17 +29,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.and(boolean) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAnd loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.and(boolean) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.and(boolean) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecAnd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -52,17 +42,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.or(boolean) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecOr loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.or(boolean) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.or(boolean) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecOr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -75,17 +55,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.xor(boolean) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecXor loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.xor(boolean) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.xor(boolean) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecXor loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -98,17 +68,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.not() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.not() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.not() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
diff --git a/test/640-checker-byte-simd/src/Main.java b/test/640-checker-byte-simd/src/Main.java
index 5c13fc3926..6b691277b0 100644
--- a/test/640-checker-byte-simd/src/Main.java
+++ b/test/640-checker-byte-simd/src/Main.java
@@ -29,17 +29,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.add(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.add(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.add(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -52,17 +42,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.sub(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.sub(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.sub(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -75,17 +55,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.mul(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.mul(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.mul(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -111,17 +81,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.neg() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.neg() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -134,17 +94,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.not() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.not() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.not() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -157,17 +107,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.shl4() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.shl4() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.shl4() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -180,17 +120,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.sar2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.sar2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.sar2() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
diff --git a/test/640-checker-char-simd/src/Main.java b/test/640-checker-char-simd/src/Main.java
index b3dff1411b..317a666980 100644
--- a/test/640-checker-char-simd/src/Main.java
+++ b/test/640-checker-char-simd/src/Main.java
@@ -29,17 +29,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.add(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.add(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.add(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -52,17 +42,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.sub(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.sub(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.sub(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -75,17 +55,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.mul(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.mul(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.mul(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -99,6 +69,7 @@ public class Main {
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START: void Main.div(int) loop_optimization (after)
+ /// CHECK-NOT: VecDiv
//
// Not supported on any architecture.
//
@@ -111,17 +82,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.neg() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.neg() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -134,17 +95,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.not() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.not() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.not() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -157,17 +108,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.shl4() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.shl4() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.shl4() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -192,17 +133,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.shr2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecUShr loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.shr2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.shr2() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecUShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
diff --git a/test/640-checker-double-simd/src/Main.java b/test/640-checker-double-simd/src/Main.java
index 5d0899864a..0f04f734cc 100644
--- a/test/640-checker-double-simd/src/Main.java
+++ b/test/640-checker-double-simd/src/Main.java
@@ -30,12 +30,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.add(double) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.add(double) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -48,12 +43,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.sub(double) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.sub(double) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -66,12 +56,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.mul(double) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.mul(double) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -84,12 +69,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.div(double) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.div(double) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecDiv loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -102,12 +82,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.neg() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -120,12 +95,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.abs() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.abs() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -138,11 +108,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.conv(long[]) loop_optimization (after)
- /// CHECK-NOT: VecLoad
- /// CHECK-NOT: VecStore
- //
- /// CHECK-START-MIPS64: void Main.conv(long[]) loop_optimization (after)
+ /// CHECK-START: void Main.conv(long[]) loop_optimization (after)
/// CHECK-NOT: VecLoad
/// CHECK-NOT: VecStore
//
diff --git a/test/640-checker-float-simd/src/Main.java b/test/640-checker-float-simd/src/Main.java
index c7883f37a3..d4eef9f763 100644
--- a/test/640-checker-float-simd/src/Main.java
+++ b/test/640-checker-float-simd/src/Main.java
@@ -30,12 +30,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.add(float) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.add(float) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -48,12 +43,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.sub(float) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.sub(float) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -66,12 +56,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.mul(float) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.mul(float) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -84,12 +69,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.div(float) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.div(float) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecDiv loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -102,12 +82,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.neg() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -120,12 +95,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-MIPS64: void Main.abs() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.abs() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -138,12 +108,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.conv(int[]) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.conv(int[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecCnv loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
diff --git a/test/640-checker-int-simd/src/Main.java b/test/640-checker-int-simd/src/Main.java
index aa230bfcaf..85d8b1b70b 100644
--- a/test/640-checker-int-simd/src/Main.java
+++ b/test/640-checker-int-simd/src/Main.java
@@ -29,17 +29,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.add(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.add(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.add(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -52,17 +42,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.sub(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.sub(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.sub(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -75,17 +55,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.mul(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.mul(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.mul(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -112,17 +82,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.neg() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.neg() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -135,17 +95,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.not() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.not() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.not() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -158,17 +108,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.shl4() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.shl4() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.shl4() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -181,17 +121,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.sar2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.sar2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.sar2() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -204,17 +134,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.shr2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecUShr loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.shr2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.shr2() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecUShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -242,15 +162,7 @@ public class Main {
/// CHECK-DAG: <<Get:i\d+>> ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Get>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.shr32() loop_optimization (after)
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Get>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.shr32() loop_optimization (after)
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Get>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.shr32() loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.shr32() loop_optimization (after)
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Get>>] loop:<<Loop>> outer_loop:none
static void shr32() {
@@ -271,19 +183,7 @@ public class Main {
/// CHECK-DAG: <<UShr:i\d+>> UShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.shr33() loop_optimization (after)
- /// CHECK-DAG: <<Dist:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.shr33() loop_optimization (after)
- /// CHECK-DAG: <<Dist:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.shr33() loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.shr33() loop_optimization (after)
/// CHECK-DAG: <<Dist:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
@@ -305,19 +205,7 @@ public class Main {
/// CHECK-DAG: <<UShr:i\d+>> UShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.shrMinus254() loop_optimization (after)
- /// CHECK-DAG: <<Dist:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.shrMinus254() loop_optimization (after)
- /// CHECK-DAG: <<Dist:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.shrMinus254() loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.shrMinus254() loop_optimization (after)
/// CHECK-DAG: <<Dist:i\d+>> IntConstant 2 loop:none
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
diff --git a/test/640-checker-long-simd/src/Main.java b/test/640-checker-long-simd/src/Main.java
index c754f2a309..bb4d0cbd67 100644
--- a/test/640-checker-long-simd/src/Main.java
+++ b/test/640-checker-long-simd/src/Main.java
@@ -29,12 +29,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.add(long) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.add(long) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -47,12 +42,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.sub(long) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.sub(long) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -65,14 +55,15 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
+ // Not directly supported for longs.
+ //
+ /// CHECK-START-ARM64: void Main.mul(long) loop_optimization (after)
+ /// CHECK-NOT: VecMul
+ //
/// CHECK-START-MIPS64: void Main.mul(long) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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
static void mul(long x) {
for (int i = 0; i < 128; i++)
a[i] *= x;
@@ -96,12 +87,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.neg() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -114,12 +100,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.not() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.not() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -132,12 +113,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.shl4() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.shl4() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -150,12 +126,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.sar2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.sar2() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -168,12 +139,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.shr2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM64,MIPS64}: void Main.shr2() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecUShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -201,11 +167,7 @@ public class Main {
/// CHECK-DAG: <<Get:j\d+>> ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Get>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.shr64() loop_optimization (after)
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Get>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.shr64() loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.shr64() loop_optimization (after)
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Get>>] loop:<<Loop>> outer_loop:none
static void shr64() {
@@ -226,13 +188,7 @@ public class Main {
/// CHECK-DAG: <<UShr:j\d+>> UShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.shr65() loop_optimization (after)
- /// CHECK-DAG: <<Dist:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.shr65() loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.shr65() loop_optimization (after)
/// CHECK-DAG: <<Dist:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
@@ -254,13 +210,7 @@ public class Main {
/// CHECK-DAG: <<UShr:j\d+>> UShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.shrMinus254() loop_optimization (after)
- /// CHECK-DAG: <<Dist:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.shrMinus254() loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.shrMinus254() loop_optimization (after)
/// CHECK-DAG: <<Dist:i\d+>> IntConstant 2 loop:none
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>] loop:<<Loop>> outer_loop:none
diff --git a/test/640-checker-short-simd/src/Main.java b/test/640-checker-short-simd/src/Main.java
index e187397853..2b4ba87b71 100644
--- a/test/640-checker-short-simd/src/Main.java
+++ b/test/640-checker-short-simd/src/Main.java
@@ -29,17 +29,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.add(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.add(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.add(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecAdd loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -52,17 +42,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.sub(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.sub(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.sub(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecSub loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -75,17 +55,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.mul(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.mul(int) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.mul(int) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecMul loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -99,6 +69,7 @@ public class Main {
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
/// CHECK-START: void Main.div(int) loop_optimization (after)
+ /// CHECK-NOT: VecDiv
//
// Not supported on any architecture.
//
@@ -111,17 +82,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.neg() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.neg() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNeg loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -134,17 +95,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.not() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.not() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.not() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecNot loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -157,17 +108,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.shl4() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.shl4() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.shl4() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecShl loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
@@ -180,17 +121,7 @@ public class Main {
/// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.sar2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.sar2() loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> 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-START-{ARM,ARM64,MIPS64}: void Main.sar2() loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecShr loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none
diff --git a/test/642-fp-callees/fp_callees.cc b/test/642-fp-callees/fp_callees.cc
index 600f9690eb..17bb55b70d 100644
--- a/test/642-fp-callees/fp_callees.cc
+++ b/test/642-fp-callees/fp_callees.cc
@@ -14,8 +14,9 @@
* limitations under the License.
*/
+#include <android-base/logging.h>
+
#include "base/casts.h"
-#include "base/logging.h"
#include "jni.h"
namespace art {
diff --git a/test/645-checker-abs-simd/src/Main.java b/test/645-checker-abs-simd/src/Main.java
index 823908c20e..d498bda052 100644
--- a/test/645-checker-abs-simd/src/Main.java
+++ b/test/645-checker-abs-simd/src/Main.java
@@ -28,7 +28,7 @@ public class Main {
/// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitByte(byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitByte(byte[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
@@ -38,25 +38,6 @@ public class Main {
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
- /// CHECK-START-ARM64: void Main.doitByte(byte[]) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> 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>>"
- //
- /// CHECK-START-MIPS64: void Main.doitByte(byte[]) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> 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]);
@@ -84,17 +65,7 @@ public class Main {
/// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitShort(short[]) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> 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>>"
- //
- /// CHECK-START-ARM64: void Main.doitShort(short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitShort(short[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
@@ -104,15 +75,6 @@ public class Main {
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
- /// CHECK-START-MIPS64: void Main.doitShort(short[]) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> 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]);
@@ -147,7 +109,7 @@ public class Main {
/// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitInt(int[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitInt(int[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
@@ -157,25 +119,6 @@ public class Main {
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
- /// CHECK-START-ARM64: void Main.doitInt(int[]) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> 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>>"
- //
- /// CHECK-START-MIPS64: void Main.doitInt(int[]) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> 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]);
@@ -188,7 +131,7 @@ public class Main {
/// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.doitLong(long[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.doitLong(long[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
@@ -198,15 +141,6 @@ public class Main {
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
- /// CHECK-START-MIPS64: void Main.doitLong(long[]) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> 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]);
@@ -219,7 +153,7 @@ public class Main {
/// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsFloat loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.doitFloat(float[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.doitFloat(float[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
@@ -229,15 +163,6 @@ public class Main {
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
- /// CHECK-START-MIPS64: void Main.doitFloat(float[]) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> 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]);
@@ -250,7 +175,7 @@ public class Main {
/// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsDouble loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.doitDouble(double[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.doitDouble(double[]) loop_optimization (after)
/// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
@@ -260,15 +185,6 @@ public class Main {
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
- /// CHECK-START-MIPS64: void Main.doitDouble(double[]) loop_optimization (after)
- /// CHECK-DAG: VecLoad loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: ArrayGet loop:<<Loop2:B\d+>> 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 41aa40cd6d..2ef340ab45 100644
--- a/test/646-checker-hadd-alt-byte/src/Main.java
+++ b/test/646-checker-hadd-alt-byte/src/Main.java
@@ -39,19 +39,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:false loop:<<Loop>> outer_loop:none
@@ -86,19 +74,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:false loop:<<Loop>> outer_loop:none
@@ -121,19 +97,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:true loop:<<Loop>> outer_loop:none
@@ -170,19 +134,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:true loop:<<Loop>> outer_loop:none
@@ -204,21 +156,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Int8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Int8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
@@ -252,21 +190,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
diff --git a/test/646-checker-hadd-alt-char/src/Main.java b/test/646-checker-hadd-alt-char/src/Main.java
index 8f879c77d0..2a1382dfde 100644
--- a/test/646-checker-hadd-alt-char/src/Main.java
+++ b/test/646-checker-hadd-alt-char/src/Main.java
@@ -39,19 +39,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
@@ -87,19 +75,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
@@ -125,19 +101,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
@@ -174,19 +138,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
@@ -211,21 +163,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_unsigned_constant(char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
@@ -259,21 +197,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_also_unsigned_constant(char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
diff --git a/test/646-checker-hadd-alt-short/src/Main.java b/test/646-checker-hadd-alt-short/src/Main.java
index b591081fba..4035b97209 100644
--- a/test/646-checker-hadd-alt-short/src/Main.java
+++ b/test/646-checker-hadd-alt-short/src/Main.java
@@ -39,19 +39,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
@@ -86,19 +74,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
@@ -121,19 +97,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
@@ -170,19 +134,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
@@ -204,21 +156,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
@@ -252,21 +190,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
diff --git a/test/646-checker-hadd-byte/src/Main.java b/test/646-checker-hadd-byte/src/Main.java
index 4d259c437b..ca22200a1a 100644
--- a/test/646-checker-hadd-byte/src/Main.java
+++ b/test/646-checker-hadd-byte/src/Main.java
@@ -36,19 +36,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:false loop:<<Loop>> outer_loop:none
@@ -83,19 +71,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:false loop:<<Loop>> outer_loop:none
@@ -118,19 +94,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int8 rounded:true loop:<<Loop>> outer_loop:none
@@ -167,19 +131,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint8 rounded:true loop:<<Loop>> outer_loop:none
@@ -201,21 +153,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Int8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Int8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
@@ -249,21 +187,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint8 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
diff --git a/test/646-checker-hadd-short/src/Main.java b/test/646-checker-hadd-short/src/Main.java
index 55bb958670..85c2fcaf22 100644
--- a/test/646-checker-hadd-short/src/Main.java
+++ b/test/646-checker-hadd-short/src/Main.java
@@ -36,19 +36,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
@@ -74,19 +62,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
@@ -122,19 +98,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
@@ -157,19 +121,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
@@ -192,19 +144,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
@@ -231,19 +171,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_signed_alt2(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_signed_alt2(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_signed_alt2(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_signed_alt2(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Int16 rounded:true loop:<<Loop>> outer_loop:none
@@ -281,19 +209,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
@@ -330,19 +246,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned_alt(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned_alt(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.rounding_halving_add_unsigned_alt(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.rounding_halving_add_unsigned_alt(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] packed_type:Uint16 rounded:true loop:<<Loop>> outer_loop:none
@@ -365,21 +269,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Int16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
@@ -413,21 +303,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: 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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] packed_type:Uint16 rounded:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<HAdd>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,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: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
diff --git a/test/651-checker-byte-simd-minmax/src/Main.java b/test/651-checker-byte-simd-minmax/src/Main.java
index 2188346aa9..45949ae90a 100644
--- a/test/651-checker-byte-simd-minmax/src/Main.java
+++ b/test/651-checker-byte-simd-minmax/src/Main.java
@@ -27,19 +27,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMin(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMin(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMin(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMin(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
@@ -70,19 +58,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMinUnsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Uint8 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMinUnsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Uint8 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMinUnsigned(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMinUnsigned(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Uint8 loop:<<Loop>> outer_loop:none
@@ -102,19 +78,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Max>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMax(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMax(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMax(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMax(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
@@ -145,19 +109,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Max>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMaxUnsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Uint8 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMaxUnsigned(byte[], byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Uint8 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMaxUnsigned(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMaxUnsigned(byte[], byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Uint8 loop:<<Loop>> outer_loop:none
@@ -177,14 +129,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.doitMin100(byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none
- /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>] loop:none
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Repl>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMin100(byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.doitMin100(byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>] loop:none
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
diff --git a/test/651-checker-char-simd-minmax/src/Main.java b/test/651-checker-char-simd-minmax/src/Main.java
index d92bdaf808..9b056094a3 100644
--- a/test/651-checker-char-simd-minmax/src/Main.java
+++ b/test/651-checker-char-simd-minmax/src/Main.java
@@ -27,19 +27,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMin(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMin(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMin(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMin(char[], char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
@@ -59,19 +47,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Max>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMax(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMax(char[], char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMax(char[], char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMax(char[], char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
@@ -91,14 +67,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.doitMin100(char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none
- /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>] loop:none
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Repl>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMin100(char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.doitMin100(char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>] loop:none
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
diff --git a/test/651-checker-int-simd-minmax/src/Main.java b/test/651-checker-int-simd-minmax/src/Main.java
index 598106e604..66343adaa8 100644
--- a/test/651-checker-int-simd-minmax/src/Main.java
+++ b/test/651-checker-int-simd-minmax/src/Main.java
@@ -26,19 +26,7 @@ public class Main {
/// CHECK-DAG: <<Min:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMin(int[], int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMin(int[], int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMin(int[], int[], int[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMin(int[], int[], int[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
@@ -57,19 +45,7 @@ public class Main {
/// CHECK-DAG: <<Max:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxIntInt loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMax(int[], int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMax(int[], int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMax(int[], int[], int[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMax(int[], int[], int[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
diff --git a/test/651-checker-short-simd-minmax/src/Main.java b/test/651-checker-short-simd-minmax/src/Main.java
index 91f2a2dbdb..5f10adab79 100644
--- a/test/651-checker-short-simd-minmax/src/Main.java
+++ b/test/651-checker-short-simd-minmax/src/Main.java
@@ -27,19 +27,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMin(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMin(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMin(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMin(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
@@ -70,19 +58,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMinUnsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMinUnsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMinUnsigned(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMinUnsigned(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
@@ -102,19 +78,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Max>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMax(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMax(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMax(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMax(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
@@ -145,19 +109,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Max>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: void Main.doitMaxUnsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: void Main.doitMaxUnsigned(short[], short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMaxUnsigned(short[], short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMaxUnsigned(short[], short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
@@ -177,14 +129,7 @@ public class Main {
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.doitMin100(short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none
- /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>] loop:none
- /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Repl>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.doitMin100(short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.doitMin100(short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>] loop:none
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
diff --git a/test/656-checker-simd-opt/src/Main.java b/test/656-checker-simd-opt/src/Main.java
index 31d28e851e..081e421422 100644
--- a/test/656-checker-simd-opt/src/Main.java
+++ b/test/656-checker-simd-opt/src/Main.java
@@ -102,20 +102,7 @@ public class Main {
/// CHECK-DAG: <<Add2>> Add [<<Phi2>>,<<Get>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add1>> Add [<<Phi1>>,<<L1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.longInductionReduction(long[]) loop_optimization (after)
- /// CHECK-DAG: <<L0:j\d+>> LongConstant 0 loop:none
- /// CHECK-DAG: <<L1:j\d+>> LongConstant 1 loop:none
- /// CHECK-DAG: <<L2:j\d+>> LongConstant 2 loop:none
- /// CHECK-DAG: <<I0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Get:j\d+>> ArrayGet [{{l\d+}},<<I0>>] loop:none
- /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Get>>] loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<L1>>] loop:none
- /// CHECK-DAG: <<Phi1:j\d+>> Phi [<<L0>>,{{j\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi2>>,<<Rep>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<L2>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.longInductionReduction(long[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.longInductionReduction(long[]) loop_optimization (after)
/// CHECK-DAG: <<L0:j\d+>> LongConstant 0 loop:none
/// CHECK-DAG: <<L1:j\d+>> LongConstant 1 loop:none
/// CHECK-DAG: <<L2:j\d+>> LongConstant 2 loop:none
@@ -144,18 +131,7 @@ public class Main {
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add>> Add [<<Phi>>,<<I1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.intVectorLongInvariant(int[], long[]) loop_optimization (after)
- /// CHECK-DAG: <<I0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<I4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<Get:j\d+>> ArrayGet [{{l\d+}},<<I0>>] loop:none
- /// CHECK-DAG: <<Cnv:i\d+>> TypeConversion [<<Get>>] loop:none
- /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Cnv>>] loop:none
- /// CHECK-DAG: <<Phi:i\d+>> Phi [<<I0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Rep>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi>>,<<I4>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.intVectorLongInvariant(int[], long[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.intVectorLongInvariant(int[], long[]) loop_optimization (after)
/// CHECK-DAG: <<I0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<I4:i\d+>> IntConstant 4 loop:none
@@ -183,19 +159,7 @@ public class Main {
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add>> Add [<<Phi>>,<<I1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.longCanBeDoneWithInt(int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<I0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<I4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<L1:j\d+>> LongConstant 1 loop:none
- /// CHECK-DAG: <<Cnv:i\d+>> TypeConversion [<<L1>>] loop:none
- /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Cnv>>] loop:none
- /// CHECK-DAG: <<Phi:i\d+>> Phi [<<I0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi>>,<<I4>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: void Main.longCanBeDoneWithInt(int[], int[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.longCanBeDoneWithInt(int[], int[]) loop_optimization (after)
/// CHECK-DAG: <<I0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<I4:i\d+>> IntConstant 4 loop:none
/// CHECK-DAG: <<L1:j\d+>> LongConstant 1 loop:none
diff --git a/test/660-checker-simd-sad-byte/src/Main.java b/test/660-checker-simd-sad-byte/src/Main.java
index 877d7189a2..594948b7f9 100644
--- a/test/660-checker-simd-sad-byte/src/Main.java
+++ b/test/660-checker-simd-sad-byte/src/Main.java
@@ -99,18 +99,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadByte2Int(byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadByte2Int(byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadByte2Int(byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
@@ -141,18 +130,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadByte2IntAlt(byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadByte2IntAlt(byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadByte2IntAlt(byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
@@ -185,18 +163,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadByte2IntAlt2(byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadByte2IntAlt2(byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadByte2IntAlt2(byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
@@ -234,19 +201,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadByte2Long(byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
- /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.sadByte2Long(byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.sadByte2Long(byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
/// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
@@ -283,19 +238,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadByte2LongAt1(byte[], byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
- /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.sadByte2LongAt1(byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.sadByte2LongAt1(byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
/// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
diff --git a/test/660-checker-simd-sad-int/src/Main.java b/test/660-checker-simd-sad-int/src/Main.java
index d7d5a959d7..aa8431c1f5 100644
--- a/test/660-checker-simd-sad-int/src/Main.java
+++ b/test/660-checker-simd-sad-int/src/Main.java
@@ -31,32 +31,14 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: int Main.sadInt2Int(int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
+ /// CHECK-START-{ARM,ARM64,MIPS64}: int Main.sadInt2Int(int[], int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons:i\d+>> IntConstant {{2|4}} loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
/// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Ld1:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Ld2:d\d+>> VecLoad [{{l\d+}},<<I>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: int Main.sadInt2Int(int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Ld1:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Ld2:d\d+>> VecLoad [{{l\d+}},<<I>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadInt2Int(int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Ld1:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Ld2:d\d+>> VecLoad [{{l\d+}},<<I>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<I>>,<<Cons>>] loop:<<Loop>> outer_loop:none
private static int sadInt2Int(int[] x, int[] y) {
int min_length = Math.min(x.length, y.length);
int sad = 0;
@@ -106,32 +88,14 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Ld1:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Ld2:d\d+>> VecLoad [{{l\d+}},<<I>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-ARM64: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Ld1:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Ld2:d\d+>> VecLoad [{{l\d+}},<<I>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-START-{ARM,ARM64,MIPS64}: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons:i\d+>> IntConstant {{2|4}} loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
/// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Ld1:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Ld2:d\d+>> VecLoad [{{l\d+}},<<I>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<I>>,<<Cons>>] loop:<<Loop>> outer_loop:none
private static int sadInt2IntAlt2(int[] x, int[] y) {
int min_length = Math.min(x.length, y.length);
int sad = 0;
@@ -160,19 +124,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadInt2Long(int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.sadInt2Long(int[], int[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.sadInt2Long(int[], int[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
/// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
@@ -209,19 +161,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadInt2LongAt1(int[], int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.sadInt2LongAt1(int[], int[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.sadInt2LongAt1(int[], int[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
/// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
diff --git a/test/660-checker-simd-sad-long/src/Main.java b/test/660-checker-simd-sad-long/src/Main.java
index d080e0cf3a..8281812b5b 100644
--- a/test/660-checker-simd-sad-long/src/Main.java
+++ b/test/660-checker-simd-sad-long/src/Main.java
@@ -32,19 +32,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadLong2Long(long[], long[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.sadLong2Long(long[], long[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.sadLong2Long(long[], long[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
/// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
@@ -106,19 +94,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadLong2LongAlt2(long[], long[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.sadLong2LongAlt2(long[], long[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.sadLong2LongAlt2(long[], long[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
/// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
@@ -155,19 +131,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadLong2LongAt1(long[], long[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.sadLong2LongAt1(long[], long[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.sadLong2LongAt1(long[], long[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
/// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
diff --git a/test/660-checker-simd-sad-short/src/Main.java b/test/660-checker-simd-sad-short/src/Main.java
index 4ab66827b6..16bcabac95 100644
--- a/test/660-checker-simd-sad-short/src/Main.java
+++ b/test/660-checker-simd-sad-short/src/Main.java
@@ -66,18 +66,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadShort2Int(short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadShort2Int(short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadShort2Int(short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
@@ -108,18 +97,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadShort2IntAlt(short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadShort2IntAlt(short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadShort2IntAlt(short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
@@ -152,18 +130,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadShort2IntAlt2(short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadShort2IntAlt2(short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadShort2IntAlt2(short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
@@ -201,19 +168,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadShort2Long(short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.sadShort2Long(short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.sadShort2Long(short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
@@ -250,19 +205,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadShort2LongAt1(short[], short[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.sadShort2LongAt1(short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.sadShort2LongAt1(short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
diff --git a/test/660-checker-simd-sad-short2/src/Main.java b/test/660-checker-simd-sad-short2/src/Main.java
index 331f5ce690..274892d001 100644
--- a/test/660-checker-simd-sad-short2/src/Main.java
+++ b/test/660-checker-simd-sad-short2/src/Main.java
@@ -84,18 +84,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadCastedChar2Int(char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadCastedChar2Int(char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadCastedChar2Int(char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
@@ -145,18 +134,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadCastedChar2IntAlt(char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadCastedChar2IntAlt(char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadCastedChar2IntAlt(char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
@@ -208,18 +186,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadCastedChar2IntAlt2(char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadCastedChar2IntAlt2(char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadCastedChar2IntAlt2(char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
@@ -276,19 +243,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadCastedChar2Long(char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.sadCastedChar2Long(char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.sadCastedChar2Long(char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
@@ -344,19 +299,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadCastedChar2LongAt1(char[], char[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: long Main.sadCastedChar2LongAt1(char[], char[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.sadCastedChar2LongAt1(char[], char[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
diff --git a/test/660-checker-simd-sad-short3/src/Main.java b/test/660-checker-simd-sad-short3/src/Main.java
index ecda8848c3..5016b658e5 100644
--- a/test/660-checker-simd-sad-short3/src/Main.java
+++ b/test/660-checker-simd-sad-short3/src/Main.java
@@ -33,19 +33,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadShort2IntParamRight(short[], short) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none
- /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Param>>] loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadShort2IntParamRight(short[], short) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadShort2IntParamRight(short[], short) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none
@@ -76,19 +64,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadShort2IntParamLeft(short[], short) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none
- /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Param>>] loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadShort2IntParamLeft(short[], short) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadShort2IntParamLeft(short[], short) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none
@@ -119,19 +95,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadShort2IntConstRight(short[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 32767 loop:none
- /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadShort2IntConstRight(short[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadShort2IntConstRight(short[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<ConsI:i\d+>> IntConstant 32767 loop:none
@@ -162,19 +126,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadShort2IntConstLeft(short[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 32767 loop:none
- /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadShort2IntConstLeft(short[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadShort2IntConstLeft(short[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<ConsI:i\d+>> IntConstant 32767 loop:none
@@ -205,19 +157,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadShort2IntInvariantRight(short[], int) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Conv>>] loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadShort2IntInvariantRight(short[], int) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadShort2IntInvariantRight(short[], int) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none
@@ -249,18 +189,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadShort2IntInvariantLeft(short[], int) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Conv>>] loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadShort2IntInvariantLeft(short[], int) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadShort2IntInvariantLeft(short[], int) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none
@@ -270,6 +199,7 @@ public class Main {
/// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntInvariantLeft(short[] s, int val) {
int sad = 0;
short x = (short) (val + 1);
@@ -293,19 +223,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadShort2IntCastedExprRight(short[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none
- /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Add>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadShort2IntCastedExprRight(short[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadShort2IntCastedExprRight(short[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none
@@ -316,6 +234,7 @@ public class Main {
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Add>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntCastedExprRight(short[] s) {
int sad = 0;
for (int i = 0; i < s.length; i++) {
@@ -339,19 +258,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadShort2IntCastedExprLeft(short[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
- /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none
- /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Add>>,<<Load>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-START-MIPS64: int Main.sadShort2IntCastedExprLeft(short[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: int Main.sadShort2IntCastedExprLeft(short[]) loop_optimization (after)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
/// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none
@@ -362,6 +269,7 @@ public class Main {
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Add>>,<<Load>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntCastedExprLeft(short[] s) {
int sad = 0;
for (int i = 0; i < s.length; i++) {
diff --git a/test/661-checker-simd-reduc/src/Main.java b/test/661-checker-simd-reduc/src/Main.java
index 1add0f1026..3a0a0495c4 100644
--- a/test/661-checker-simd-reduc/src/Main.java
+++ b/test/661-checker-simd-reduc/src/Main.java
@@ -62,33 +62,13 @@ public class Main {
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Return [<<Phi2>>] loop:none
//
- /// CHECK-START-ARM: int Main.reductionInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-ARM64: int Main.reductionInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-START-{ARM,ARM64,MIPS64}: int Main.reductionInt(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons:i\d+>> IntConstant {{2|4}} loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
/// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAdd [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-MIPS64: int Main.reductionInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<I>>,<<Cons>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
/// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
private static int reductionInt(int[] x) {
@@ -116,58 +96,19 @@ public class Main {
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
- /// CHECK-START-ARM: int Main.reductionIntChain() loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Set1:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi1:d\d+>> Phi [<<Set1>>,{{d\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<I1:i\d+>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi1>>,<<Load1>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: Add [<<I1>>,<<Cons2>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: <<Red1:d\d+>> VecReduce [<<Phi1>>] loop:none
- /// CHECK-DAG: <<Extr1:i\d+>> VecExtractScalar [<<Red1>>] loop:none
- /// CHECK-DAG: <<Set2:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set2>>,{{d\d+}}] loop:<<Loop2:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<I2:i\d+>>] loop:<<Loop2>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi2>>,<<Load2>>] loop:<<Loop2>> outer_loop:none
- /// CHECK-DAG: Add [<<I2>>,<<Cons2>>] loop:<<Loop2>> outer_loop:none
- /// CHECK-DAG: <<Red2:d\d+>> VecReduce [<<Phi2>>] loop:none
- /// CHECK-DAG: <<Extr2:i\d+>> VecExtractScalar [<<Red2>>] loop:none
- //
- /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
- //
- /// CHECK-START-ARM64: int Main.reductionIntChain() loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<Set1:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi1:d\d+>> Phi [<<Set1>>,{{d\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<I1:i\d+>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi1>>,<<Load1>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: Add [<<I1>>,<<Cons4>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: <<Red1:d\d+>> VecReduce [<<Phi1>>] loop:none
- /// CHECK-DAG: <<Extr1:i\d+>> VecExtractScalar [<<Red1>>] loop:none
- /// CHECK-DAG: <<Set2:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set2>>,{{d\d+}}] loop:<<Loop2:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<I2:i\d+>>] loop:<<Loop2>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi2>>,<<Load2>>] loop:<<Loop2>> outer_loop:none
- /// CHECK-DAG: Add [<<I2>>,<<Cons4>>] loop:<<Loop2>> outer_loop:none
- /// CHECK-DAG: <<Red2:d\d+>> VecReduce [<<Phi2>>] loop:none
- /// CHECK-DAG: <<Extr2:i\d+>> VecExtractScalar [<<Red2>>] loop:none
- //
- /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
- //
- /// CHECK-START-MIPS64: int Main.reductionIntChain() loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-START-{ARM,ARM64,MIPS64}: int Main.reductionIntChain() loop_optimization (after)
/// CHECK-DAG: <<Set1:d\d+>> VecSetScalars [{{i\d+}}] loop:none
/// CHECK-DAG: <<Phi1:d\d+>> Phi [<<Set1>>,{{d\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<I1:i\d+>>] loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecAdd [<<Phi1>>,<<Load1>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: Add [<<I1>>,<<Cons4>>] loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: Add [<<I1>>,{{i\d+}}] loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: <<Red1:d\d+>> VecReduce [<<Phi1>>] loop:none
/// CHECK-DAG: <<Extr1:i\d+>> VecExtractScalar [<<Red1>>] loop:none
/// CHECK-DAG: <<Set2:d\d+>> VecSetScalars [{{i\d+}}] loop:none
/// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set2>>,{{d\d+}}] loop:<<Loop2:B\d+>> outer_loop:none
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<I2:i\d+>>] loop:<<Loop2>> outer_loop:none
/// CHECK-DAG: VecAdd [<<Phi2>>,<<Load2>>] loop:<<Loop2>> outer_loop:none
- /// CHECK-DAG: Add [<<I2>>,<<Cons4>>] loop:<<Loop2>> outer_loop:none
+ /// CHECK-DAG: Add [<<I2>>,{{i\d+}}] loop:<<Loop2>> outer_loop:none
/// CHECK-DAG: <<Red2:d\d+>> VecReduce [<<Phi2>>] loop:none
/// CHECK-DAG: <<Extr2:i\d+>> VecExtractScalar [<<Red2>>] loop:none
//
@@ -199,38 +140,18 @@ public class Main {
//
/// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
//
- /// CHECK-START-ARM: int Main.reductionIntToLoop(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi>>,<<Load>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons2>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-ARM64: int Main.reductionIntToLoop(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi>>,<<Load>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-MIPS64: int Main.reductionIntToLoop(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-START-{ARM,ARM64,MIPS64}: int Main.reductionIntToLoop(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons:i\d+>> IntConstant {{2|4}} loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
/// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: VecAdd [<<Phi>>,<<Load>>] loop:<<Loop1>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: Add [<<I>>,<<Cons>>] loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
/// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
private static int reductionIntToLoop(int[] x) {
int r = 0;
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < 8; i++) {
r += x[i];
}
for (int i = r; i < 16; i++) {
@@ -250,17 +171,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Return [<<Phi2>>] loop:none
//
- /// CHECK-START-ARM64: long Main.reductionLong(long[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{j\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:j\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-MIPS64: long Main.reductionLong(long[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.reductionLong(long[]) loop_optimization (after)
/// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{j\d+}}] loop:none
/// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
@@ -312,33 +223,13 @@ public class Main {
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Return [<<Phi2>>] loop:none
//
- /// CHECK-START-ARM: int Main.reductionIntM1(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-ARM64: int Main.reductionIntM1(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-MIPS64: int Main.reductionIntM1(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-START-{ARM,ARM64,MIPS64}: int Main.reductionIntM1(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons:i\d+>> IntConstant {{2|4}} loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
/// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAdd [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<I>>,<<Cons>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
/// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
private static int reductionIntM1(int[] x) {
@@ -360,17 +251,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Return [<<Phi2>>] loop:none
//
- /// CHECK-START-ARM64: long Main.reductionLongM1(long[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{j\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecAdd [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:j\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-MIPS64: long Main.reductionLongM1(long[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.reductionLongM1(long[]) loop_optimization (after)
/// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{j\d+}}] loop:none
/// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
@@ -421,33 +302,13 @@ public class Main {
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Return [<<Phi2>>] loop:none
//
- /// CHECK-START-ARM: int Main.reductionMinusInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecSub [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-ARM64: int Main.reductionMinusInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-START-{ARM,ARM64,MIPS64}: int Main.reductionMinusInt(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons:i\d+>> IntConstant {{2|4}} loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
/// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecSub [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-MIPS64: int Main.reductionMinusInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecSub [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<I>>,<<Cons>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
/// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
private static int reductionMinusInt(int[] x) {
@@ -469,17 +330,7 @@ public class Main {
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Return [<<Phi2>>] loop:none
//
- /// CHECK-START-ARM64: long Main.reductionMinusLong(long[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{j\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecSub [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:j\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-MIPS64: long Main.reductionMinusLong(long[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: long Main.reductionMinusLong(long[]) loop_optimization (after)
/// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
/// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{j\d+}}] loop:none
/// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
@@ -531,33 +382,13 @@ public class Main {
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Return [<<Phi2>>] loop:none
//
- /// CHECK-START-ARM: int Main.reductionMinInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecReplicateScalar [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecMin [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-ARM64: int Main.reductionMinInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecReplicateScalar [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecMin [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-MIPS64: int Main.reductionMinInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-START-{ARM,ARM64,MIPS64}: int Main.reductionMinInt(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons:i\d+>> IntConstant {{2|4}} loop:none
/// CHECK-DAG: <<Set:d\d+>> VecReplicateScalar [{{i\d+}}] loop:none
/// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecMin [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<I>>,<<Cons>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
/// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
private static int reductionMinInt(int[] x) {
@@ -611,33 +442,13 @@ public class Main {
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Return [<<Phi2>>] loop:none
//
- /// CHECK-START-ARM: int Main.reductionMaxInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecReplicateScalar [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecMax [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-ARM64: int Main.reductionMaxInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
- /// CHECK-DAG: <<Set:d\d+>> VecReplicateScalar [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: VecMax [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
- /// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
- //
- /// CHECK-START-MIPS64: int Main.reductionMaxInt(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-START-{ARM,ARM64,MIPS64}: int Main.reductionMaxInt(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons:i\d+>> IntConstant {{2|4}} loop:none
/// CHECK-DAG: <<Set:d\d+>> VecReplicateScalar [{{i\d+}}] loop:none
/// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecMax [<<Phi>>,<<Load>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<I>>,<<Cons>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Red:d\d+>> VecReduce [<<Phi>>] loop:none
/// CHECK-DAG: <<Extr:i\d+>> VecExtractScalar [<<Red>>] loop:none
private static int reductionMaxInt(int[] x) {
@@ -743,9 +554,9 @@ public class Main {
}
// Test various reductions in loops.
- int[] x0 = { 0, 0, 0, 0 };
- int[] x1 = { 0, 0, 0, 1 };
- int[] x2 = { 1, 1, 1, 1 };
+ int[] x0 = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ int[] x1 = { 0, 0, 0, 1, 0, 0, 0, 0 };
+ int[] x2 = { 1, 1, 1, 1, 0, 0, 0, 0 };
expectEquals(-74, reductionByte(xb));
expectEquals(-27466, reductionShort(xs));
expectEquals(38070, reductionChar(xc));
@@ -754,7 +565,7 @@ public class Main {
expectEquals(120, reductionIntToLoop(x0));
expectEquals(121, reductionIntToLoop(x1));
expectEquals(118, reductionIntToLoop(x2));
- expectEquals(-1205, reductionIntToLoop(xi));
+ expectEquals(-1310, reductionIntToLoop(xi));
expectEquals(365750L, reductionLong(xl));
expectEquals(-75, reductionByteM1(xb));
expectEquals(-27467, reductionShortM1(xs));
diff --git a/test/664-aget-verifier/aget-verifier.cc b/test/664-aget-verifier/aget-verifier.cc
index 41372adf02..4a263fae7a 100644
--- a/test/664-aget-verifier/aget-verifier.cc
+++ b/test/664-aget-verifier/aget-verifier.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "art_method-inl.h"
#include "jni.h"
diff --git a/test/665-checker-simd-zero/src/Main.java b/test/665-checker-simd-zero/src/Main.java
index 6cd6d6465a..5c581c4fc7 100644
--- a/test/665-checker-simd-zero/src/Main.java
+++ b/test/665-checker-simd-zero/src/Main.java
@@ -24,13 +24,7 @@ public class Main {
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Zero>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.zeroz(boolean[]) loop_optimization (after)
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] 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-START-MIPS64: void Main.zeroz(boolean[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.zeroz(boolean[]) loop_optimization (after)
/// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] loop:none
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
@@ -46,13 +40,7 @@ public class Main {
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Zero>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.zerob(byte[]) loop_optimization (after)
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] 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-START-MIPS64: void Main.zerob(byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.zerob(byte[]) loop_optimization (after)
/// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] loop:none
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
@@ -68,13 +56,7 @@ public class Main {
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Zero>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.zeroc(char[]) loop_optimization (after)
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] 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-START-MIPS64: void Main.zeroc(char[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.zeroc(char[]) loop_optimization (after)
/// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] loop:none
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
@@ -90,13 +72,7 @@ public class Main {
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Zero>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.zeros(short[]) loop_optimization (after)
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] 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-START-MIPS64: void Main.zeros(short[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.zeros(short[]) loop_optimization (after)
/// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] loop:none
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
@@ -112,13 +88,7 @@ public class Main {
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Zero>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.zeroi(int[]) loop_optimization (after)
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
- /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] 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-START-MIPS64: void Main.zeroi(int[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.zeroi(int[]) loop_optimization (after)
/// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] loop:none
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
@@ -134,13 +104,7 @@ public class Main {
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Zero>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.zerol(long[]) loop_optimization (after)
- /// CHECK-DAG: <<Zero:j\d+>> LongConstant 0 loop:none
- /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] 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-START-MIPS64: void Main.zerol(long[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.zerol(long[]) loop_optimization (after)
/// CHECK-DAG: <<Zero:j\d+>> LongConstant 0 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] loop:none
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
@@ -156,13 +120,7 @@ public class Main {
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Zero>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.zerof(float[]) loop_optimization (after)
- /// CHECK-DAG: <<Zero:f\d+>> FloatConstant 0 loop:none
- /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] 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-START-MIPS64: void Main.zerof(float[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.zerof(float[]) loop_optimization (after)
/// CHECK-DAG: <<Zero:f\d+>> FloatConstant 0 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] loop:none
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
@@ -178,13 +136,7 @@ public class Main {
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Zero>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: void Main.zerod(double[]) loop_optimization (after)
- /// CHECK-DAG: <<Zero:d\d+>> DoubleConstant 0 loop:none
- /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] 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-START-MIPS64: void Main.zerod(double[]) loop_optimization (after)
+ /// CHECK-START-{ARM64,MIPS64}: void Main.zerod(double[]) loop_optimization (after)
/// CHECK-DAG: <<Zero:d\d+>> DoubleConstant 0 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<Zero>>] loop:none
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
diff --git a/test/667-jit-jni-stub/src/Main.java b/test/667-jit-jni-stub/src/Main.java
index b867970eab..794308d6e1 100644
--- a/test/667-jit-jni-stub/src/Main.java
+++ b/test/667-jit-jni-stub/src/Main.java
@@ -135,13 +135,16 @@ public class Main {
int count = 0;
while (!hasJitCompiledEntrypoint(Main.class, "callThrough")) {
// If `call` is true, also exercise the `callThrough()` method to increase hotness.
- int limit = call ? 1 << Math.min(count, 12) : 0;
+ // Ramp-up the number of calls we do up to 1 << 12.
+ final int rampUpCutOff = 12;
+ int limit = call ? 1 << Math.min(count, rampUpCutOff) : 0;
for (int i = 0; i < limit; ++i) {
callThrough(Main.class, "doNothing");
}
try {
- // Sleep to give a chance for the JIT to compile `hasJit` stub.
- Thread.sleep(100);
+ // Sleep to give a chance for the JIT to compile `callThrough` stub.
+ // After the ramp-up phase, give the JIT even more time to compile.
+ Thread.sleep(count >= rampUpCutOff ? 200 : 100);
} catch (Exception e) {
// Ignore
}
diff --git a/test/671-npe-field-opts/expected.txt b/test/671-npe-field-opts/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/671-npe-field-opts/expected.txt
diff --git a/test/671-npe-field-opts/info.txt b/test/671-npe-field-opts/info.txt
new file mode 100644
index 0000000000..f1e584633f
--- /dev/null
+++ b/test/671-npe-field-opts/info.txt
@@ -0,0 +1,3 @@
+Regression test for the compiler, which used to
+re-order or remove field access in a way that would confuse the runtime
+when validating a NPE.
diff --git a/test/671-npe-field-opts/src/Main.java b/test/671-npe-field-opts/src/Main.java
new file mode 100644
index 0000000000..a5e81ce672
--- /dev/null
+++ b/test/671-npe-field-opts/src/Main.java
@@ -0,0 +1,86 @@
+/*
+ * 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 {
+ static Main obj;
+ // Make 'doCheck' volatile to prevent optimizations
+ // in $noinline$bar like LICM that could hoist the null check
+ // out of the loop.
+ static volatile boolean doCheck = true;
+
+ float floatField;
+ int intField;
+
+ public static void main(String[] args) {
+ try {
+ $noinline$bar();
+ throw new Error("Expected NPE");
+ } catch (NullPointerException e) {
+ check(e, 29, 52, "$noinline$bar");
+ }
+
+ try {
+ $noinline$foo();
+ throw new Error("Expected NPE");
+ } catch (NullPointerException e) {
+ check(e, 36, 44, "$noinline$foo");
+ }
+ }
+
+ public static float $noinline$foo() {
+ int v1 = obj.intField;
+ float v2 = obj.floatField;
+ return v2;
+ }
+
+ public static float $noinline$bar() {
+ float a = 0;
+ while (doCheck) {
+ float f = obj.floatField;
+ int i = obj.intField;
+ a = (float)i + f;
+ }
+ return a;
+ }
+
+ static void check(NullPointerException npe, int mainLine, int methodLine, String methodName) {
+ StackTraceElement[] trace = npe.getStackTrace();
+ checkElement(trace[0], "Main", methodName, "Main.java", methodLine);
+ checkElement(trace[1], "Main", "main", "Main.java", mainLine);
+ }
+
+ static void checkElement(StackTraceElement element,
+ String declaringClass, String methodName,
+ String fileName, int lineNumber) {
+ assertEquals(declaringClass, element.getClassName());
+ assertEquals(methodName, element.getMethodName());
+ assertEquals(fileName, element.getFileName());
+ assertEquals(lineNumber, element.getLineNumber());
+ }
+
+ static void assertEquals(Object expected, Object actual) {
+ if (!expected.equals(actual)) {
+ String msg = "Expected \"" + expected + "\" but got \"" + actual + "\"";
+ throw new AssertionError(msg);
+ }
+ }
+
+ static void assertEquals(int expected, int actual) {
+ if (expected != actual) {
+ throw new AssertionError("Expected " + expected + " got " + actual);
+ }
+ }
+}
diff --git a/test/706-checker-scheduler/src/Main.java b/test/706-checker-scheduler/src/Main.java
index d21596d4bc..25e4fad714 100644
--- a/test/706-checker-scheduler/src/Main.java
+++ b/test/706-checker-scheduler/src/Main.java
@@ -523,7 +523,71 @@ public class Main {
return res;
}
+ private static void expectEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ private static final int ARRAY_SIZE = 32;
+
+ // Check that VecReplicateScalar is not reordered.
+ /// CHECK-START-ARM64: void Main.testVecReplicateScalar() scheduler (before)
+ /// CHECK: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK: NewArray loop:<<Loop>> outer_loop:none
+ /// CHECK: VecReplicateScalar loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START-ARM64: void Main.testVecReplicateScalar() scheduler (after)
+ /// CHECK: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK: NewArray loop:<<Loop>> outer_loop:none
+ /// CHECK: VecReplicateScalar loop:<<Loop>> outer_loop:none
+ private static void testVecReplicateScalar() {
+ for (int j = 0; j <= 8; j++) {
+ int[] a = new int[ARRAY_SIZE];
+ for (int i = 0; i < a.length; i++) {
+ a[i] += 1;
+ }
+ for (int i = 0; i < a.length; i++) {
+ expectEquals(1, a[i]);
+ }
+ }
+ }
+
+ // Check that VecSetScalars, VecReduce, VecExtractScalar are not reordered.
+ /// CHECK-START-ARM64: void Main.testVecSetScalars() scheduler (before)
+ /// CHECK: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK: NewArray loop:<<Loop>> outer_loop:none
+ /// CHECK: VecSetScalars loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK: VecReduce loop:<<Loop>> outer_loop:none
+ /// CHECK: VecExtractScalar loop:<<Loop>> outer_loop:none
+ /// CHECK: InvokeStaticOrDirect loop:<<Loop>> outer_loop:none
+ /// CHECK: InvokeStaticOrDirect loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START-ARM64: void Main.testVecSetScalars() scheduler (after)
+ /// CHECK: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK: NewArray loop:<<Loop>> outer_loop:none
+ /// CHECK: VecSetScalars loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK: VecReduce loop:<<Loop>> outer_loop:none
+ /// CHECK: VecExtractScalar loop:<<Loop>> outer_loop:none
+ /// CHECK: InvokeStaticOrDirect loop:<<Loop>> outer_loop:none
+ /// CHECK: InvokeStaticOrDirect loop:<<Loop>> outer_loop:none
+ private static void testVecSetScalars() {
+ for (int j = 0; j <= 8; j++) {
+ int[] a = new int[ARRAY_SIZE];
+ int s = 5;
+ for (int i = 0; i < ARRAY_SIZE; i++) {
+ s+=a[i];
+ }
+ expectEquals(a[0], 0);
+ expectEquals(s, 5);
+ }
+ }
+
public static void main(String[] args) {
+ testVecSetScalars();
+ testVecReplicateScalar();
if ((arrayAccess() + intDiv(10)) != -35) {
System.out.println("FAIL");
}
diff --git a/test/706-jit-skip-compilation/info.txt b/test/706-jit-skip-compilation/info.txt
deleted file mode 100644
index e9ef86bfb3..0000000000
--- a/test/706-jit-skip-compilation/info.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Regression test for the JIT crashing when compiling a method with invalid
-dead dex code. For not compilable methods we don't gather samples and we don't
-trigger JIT compilation. However kAccDontBotherCompile is not persisted in the
-oat file and so we may end up compiling a method which we shouldn't.
diff --git a/test/706-jit-skip-compilation/smali/errclass.smali b/test/706-jit-skip-compilation/smali/errclass.smali
deleted file mode 100644
index 410504cb2f..0000000000
--- a/test/706-jit-skip-compilation/smali/errclass.smali
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 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.
-
-
-.class public LErrClass;
-
-.super Ljava/lang/Object;
-
-.method public static errMethod()J
- .registers 8
- const/4 v0, 0x0
- const/4 v3, 0x0
- aget v1, v0, v3 # v0 is null, this will alays throw and the invalid code
- # below will not be verified.
- move v3, v4
- move-wide/from16 v6, v2 # should trigger a verification error if verified as
- # v3 is a single register but used as a pair here.
- return v6
-.end method
-
-# Add a field to work around demerger bug b/18051191.
-# Failure to verify dex file '...': Offset(552) should be zero when size is zero for field-ids.
-.field private a:I
diff --git a/test/706-jit-skip-compilation/src/Main.java b/test/706-jit-skip-compilation/src/Main.java
deleted file mode 100644
index aa847248d6..0000000000
--- a/test/706-jit-skip-compilation/src/Main.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-public class Main {
- public static void main(String[] args) throws Exception {
- System.loadLibrary(args[0]);
- Class<?> c = Class.forName("ErrClass");
- Method m = c.getMethod("errMethod");
-
- // Print the counter before invokes. The golden file expects this to be 0.
- int hotnessCounter = getHotnessCounter(c, "errMethod");
- if (hotnessCounter != 0) {
- throw new RuntimeException("Unexpected hotnessCounter: " + hotnessCounter);
- }
-
- // Loop enough to make sure the interpreter reports invocations count.
- long result = 0;
- for (int i = 0; i < 10000; i++) {
- try {
- result += (Long)m.invoke(null);
- hotnessCounter = getHotnessCounter(c, "errMethod");
- if (hotnessCounter != 0) {
- throw new RuntimeException(
- "Unexpected hotnessCounter: " + hotnessCounter);
- }
-
- } catch (InvocationTargetException e) {
- if (!(e.getCause() instanceof NullPointerException)) {
- throw e;
- }
- }
- }
-
- // Not compilable methods should not increase their hotness counter.
- if (hotnessCounter != 0) {
- throw new RuntimeException("Unexpected hotnessCounter: " + hotnessCounter);
- }
- }
-
- public static native int getHotnessCounter(Class cls, String method_name);
-}
diff --git a/test/711-checker-type-conversion/src/Main.java b/test/711-checker-type-conversion/src/Main.java
index 64ffcd2f1f..ae58200b1b 100644
--- a/test/711-checker-type-conversion/src/Main.java
+++ b/test/711-checker-type-conversion/src/Main.java
@@ -22,20 +22,41 @@ public class Main {
}
}
- /// CHECK-START: byte Main.getByte1() instruction_simplifier (before)
+ public static void assertShortEquals(short expected, short result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ public static void assertIntEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ public static void assertLongEquals(long expected, long result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ public static void assertCharEquals(char expected, char result) {
+ if (expected != result) {
+ // Values are cast to int to display numeric values instead of
+ // (UTF-16 encoded) characters.
+ throw new Error("Expected: " + (int)expected + ", found: " + (int)result);
+ }
+ }
+
+ /// CHECK-START: byte Main.getByte1() constant_folding (before)
/// CHECK: TypeConversion
/// CHECK: TypeConversion
/// CHECK: Add
/// CHECK: TypeConversion
- /// CHECK-START: byte Main.getByte1() instruction_simplifier (after)
+ /// CHECK-START: byte Main.getByte1() constant_folding (after)
/// CHECK-NOT: TypeConversion
- /// CHECK: Add
- /// CHECK: TypeConversion
-
- /// CHECK-START: byte Main.getByte1() instruction_simplifier$before_codegen (after)
/// CHECK-NOT: Add
- /// CHECK-NOT: TypeConversion
static byte getByte1() {
int i = -2;
@@ -43,20 +64,15 @@ public class Main {
return (byte)((byte)i + (byte)j);
}
- /// CHECK-START: byte Main.getByte2() instruction_simplifier (before)
+ /// CHECK-START: byte Main.getByte2() constant_folding (before)
/// CHECK: TypeConversion
/// CHECK: TypeConversion
/// CHECK: Add
/// CHECK: TypeConversion
- /// CHECK-START: byte Main.getByte2() instruction_simplifier (after)
+ /// CHECK-START: byte Main.getByte2() constant_folding (after)
/// CHECK-NOT: TypeConversion
- /// CHECK: Add
- /// CHECK: TypeConversion
-
- /// CHECK-START: byte Main.getByte2() instruction_simplifier$before_codegen (after)
/// CHECK-NOT: Add
- /// CHECK: TypeConversion
static byte getByte2() {
int i = -100;
@@ -64,8 +80,185 @@ public class Main {
return (byte)((byte)i + (byte)j);
}
+ /// CHECK-START: byte Main.getByte3() constant_folding (before)
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK: Add
+ /// CHECK: TypeConversion
+
+ /// CHECK-START: byte Main.getByte2() constant_folding (after)
+ /// CHECK-NOT: TypeConversion
+ /// CHECK-NOT: Add
+
+ static byte getByte3() {
+ long i = 0xabcdabcdabcdL;
+ return (byte)((byte)i + (byte)i);
+ }
+
+ static byte byteVal = -1;
+ static short shortVal = -1;
+ static char charVal = 0xffff;
+ static int intVal = -1;
+
+ static byte[] byteArr = { 0 };
+ static short[] shortArr = { 0 };
+ static char[] charArr = { 0 };
+ static int[] intArr = { 0 };
+
+ static byte $noinline$getByte() {
+ return byteVal;
+ }
+
+ static short $noinline$getShort() {
+ return shortVal;
+ }
+
+ static char $noinline$getChar() {
+ return charVal;
+ }
+
+ static int $noinline$getInt() {
+ return intVal;
+ }
+
+ static boolean sFlag = true;
+
+ /// CHECK-START: void Main.byteToShort() instruction_simplifier$before_codegen (after)
+ /// CHECK-NOT: TypeConversion
+ private static void byteToShort() {
+ shortArr[0] = 0;
+ if (sFlag) {
+ shortArr[0] = $noinline$getByte();
+ }
+ }
+
+ /// CHECK-START: void Main.byteToChar() instruction_simplifier$before_codegen (after)
+ /// CHECK: TypeConversion
+ private static void byteToChar() {
+ charArr[0] = 0;
+ if (sFlag) {
+ charArr[0] = (char)$noinline$getByte();
+ }
+ }
+
+ /// CHECK-START: void Main.byteToInt() instruction_simplifier$before_codegen (after)
+ /// CHECK-NOT: TypeConversion
+ private static void byteToInt() {
+ intArr[0] = 0;
+ if (sFlag) {
+ intArr[0] = $noinline$getByte();
+ }
+ }
+
+ /// CHECK-START: void Main.charToByte() instruction_simplifier$before_codegen (after)
+ /// CHECK-NOT: TypeConversion
+ private static void charToByte() {
+ byteArr[0] = 0;
+ if (sFlag) {
+ byteArr[0] = (byte)$noinline$getChar();
+ }
+ }
+
+ /// CHECK-START: void Main.charToShort() instruction_simplifier$before_codegen (after)
+ /// CHECK-NOT: TypeConversion
+ private static void charToShort() {
+ shortArr[0] = 0;
+ if (sFlag) {
+ shortArr[0] = (short)$noinline$getChar();
+ }
+ }
+
+ /// CHECK-START: void Main.charToInt() instruction_simplifier$before_codegen (after)
+ /// CHECK-NOT: TypeConversion
+ private static void charToInt() {
+ intArr[0] = 0;
+ if (sFlag) {
+ intArr[0] = $noinline$getChar();
+ }
+ }
+
+ /// CHECK-START: void Main.shortToByte() instruction_simplifier$before_codegen (after)
+ /// CHECK-NOT: TypeConversion
+ private static void shortToByte() {
+ byteArr[0] = 0;
+ if (sFlag) {
+ byteArr[0] = (byte)$noinline$getShort();
+ }
+ }
+
+ /// CHECK-START: void Main.shortToChar() instruction_simplifier$before_codegen (after)
+ /// CHECK-NOT: TypeConversion
+ private static void shortToChar() {
+ charArr[0] = 0;
+ if (sFlag) {
+ charArr[0] = (char)$noinline$getShort();
+ }
+ }
+
+ /// CHECK-START: void Main.shortToInt() instruction_simplifier$before_codegen (after)
+ /// CHECK-NOT: TypeConversion
+ private static void shortToInt() {
+ intArr[0] = 0;
+ if (sFlag) {
+ intArr[0] = $noinline$getShort();
+ }
+ }
+
+ /// CHECK-START: void Main.intToByte() instruction_simplifier$before_codegen (after)
+ /// CHECK-NOT: TypeConversion
+ private static void intToByte() {
+ byteArr[0] = 0;
+ if (sFlag) {
+ byteArr[0] = (byte)$noinline$getInt();
+ }
+ }
+
+ /// CHECK-START: void Main.intToShort() instruction_simplifier$before_codegen (after)
+ /// CHECK-NOT: TypeConversion
+ private static void intToShort() {
+ shortArr[0] = 0;
+ if (sFlag) {
+ shortArr[0] = (short)$noinline$getInt();
+ }
+ }
+
+ /// CHECK-START: void Main.intToChar() instruction_simplifier$before_codegen (after)
+ /// CHECK-NOT: TypeConversion
+ private static void intToChar() {
+ charArr[0] = 0;
+ if (sFlag) {
+ charArr[0] = (char)$noinline$getInt();
+ }
+ }
+
public static void main(String[] args) {
assertByteEquals(getByte1(), (byte)-5);
assertByteEquals(getByte2(), (byte)(-201));
+ assertByteEquals(getByte3(), (byte)(0xcd + 0xcd));
+
+ byteToShort();
+ assertShortEquals(shortArr[0], (short)-1);
+ byteToChar();
+ assertCharEquals(charArr[0], (char)-1);
+ byteToInt();
+ assertIntEquals(intArr[0], -1);
+ charToByte();
+ assertByteEquals(byteArr[0], (byte)-1);
+ charToShort();
+ assertShortEquals(shortArr[0], (short)-1);
+ charToInt();
+ assertIntEquals(intArr[0], 0xffff);
+ shortToByte();
+ assertByteEquals(byteArr[0], (byte)-1);
+ shortToChar();
+ assertCharEquals(charArr[0], (char)-1);
+ shortToInt();
+ assertIntEquals(intArr[0], -1);
+ intToByte();
+ assertByteEquals(byteArr[0], (byte)-1);
+ intToShort();
+ assertShortEquals(shortArr[0], (short)-1);
+ intToChar();
+ assertCharEquals(charArr[0], (char)-1);
}
}
diff --git a/test/900-hello-plugin/load_unload.cc b/test/900-hello-plugin/load_unload.cc
index 19312b4d71..cab0abf58b 100644
--- a/test/900-hello-plugin/load_unload.cc
+++ b/test/900-hello-plugin/load_unload.cc
@@ -17,9 +17,10 @@
#include <jni.h>
#include <stdio.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
#include "art_method-inl.h"
-#include "base/logging.h"
-#include "base/macros.h"
#include "java_vm_ext.h"
#include "runtime.h"
diff --git a/test/901-hello-ti-agent/basics.cc b/test/901-hello-ti-agent/basics.cc
index 472f2b768e..43a1d8319f 100644
--- a/test/901-hello-ti-agent/basics.cc
+++ b/test/901-hello-ti-agent/basics.cc
@@ -56,9 +56,13 @@ static void JNICALL VMInitCallback(jvmtiEnv *jvmti_env,
fsync(1);
}
-static void JNICALL VMDeatchCallback(jvmtiEnv *jenv, JNIEnv* jni_env ATTRIBUTE_UNUSED) {
+static void JNICALL VMDeathCallback(jvmtiEnv *jenv, JNIEnv* jni_env) {
printf("VMDeath (phase %d)\n", getPhase(jenv));
fsync(1);
+ jthread cur_thr;
+ CHECK_EQ(jenv->GetCurrentThread(&cur_thr), JVMTI_ERROR_NONE);
+ CHECK(cur_thr != nullptr);
+ jni_env->DeleteLocalRef(cur_thr);
}
@@ -67,7 +71,7 @@ static void InstallVMEvents(jvmtiEnv* env) {
memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
callbacks.VMStart = VMStartCallback;
callbacks.VMInit = VMInitCallback;
- callbacks.VMDeath = VMDeatchCallback;
+ callbacks.VMDeath = VMDeathCallback;
jvmtiError ret = env->SetEventCallbacks(&callbacks, sizeof(callbacks));
if (ret != JVMTI_ERROR_NONE) {
printf("Failed to install callbacks");
diff --git a/test/909-attach-agent/expected.txt b/test/909-attach-agent/expected.txt
index c0bccd6486..4d687f531e 100644
--- a/test/909-attach-agent/expected.txt
+++ b/test/909-attach-agent/expected.txt
@@ -1,11 +1,12 @@
Hello, world!
Attached Agent for test 909-attach-agent
+Attached Agent for test 909-attach-agent
Goodbye!
Hello, world!
Attached Agent for test 909-attach-agent
+Attached Agent for test 909-attach-agent
Goodbye!
Hello, world!
-java.io.IOException: Process is not debuggable.
- at dalvik.system.VMDebug.attachAgent(Native Method)
- at Main.main(Main.java:27)
+Process is not debuggable.
+Process is not debuggable.
Goodbye!
diff --git a/test/909-attach-agent/src-art/Main.java b/test/909-attach-agent/src-art/Main.java
index 25ebd57236..705e61eb99 100644
--- a/test/909-attach-agent/src-art/Main.java
+++ b/test/909-attach-agent/src-art/Main.java
@@ -14,7 +14,13 @@
* limitations under the License.
*/
+import dalvik.system.PathClassLoader;
import dalvik.system.VMDebug;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.File;
import java.io.IOException;
public class Main {
@@ -26,10 +32,76 @@ public class Main {
try {
VMDebug.attachAgent(agent);
} catch(IOException e) {
- e.printStackTrace(System.out);
+ System.out.println(e.getMessage());
}
}
}
+ attachWithClassLoader(args);
System.out.println("Goodbye!");
}
+
+ private static void attachWithClassLoader(String[] args) {
+ for(String a : args) {
+ if(a.startsWith("agent:")) {
+ String agentName = a.substring(6, a.indexOf('='));
+ File tmp = null;
+ try {
+ tmp = File.createTempFile("lib", ".so");
+ prepare(agentName, tmp);
+
+ String newAgentName = tmp.getName();
+ String agent = a.substring(6).replace(agentName, newAgentName);
+
+ ClassLoader cl = new PathClassLoader("", tmp.getParentFile().getAbsolutePath(),
+ Main.class.getClassLoader());
+ try {
+ VMDebug.attachAgent(agent, cl);
+ } catch(IOException e) {
+ System.out.println(e.getMessage());
+ }
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ } finally {
+ if (tmp != null) {
+ tmp.delete();
+ }
+ }
+ }
+ }
+ }
+
+ private static void prepare(String in, File tmp) throws Exception {
+ // Find the original.
+ File orig = find(in);
+ if (orig == null) {
+ throw new RuntimeException("Could not find " + in);
+ }
+ // Copy the original.
+ {
+ BufferedInputStream bis = new BufferedInputStream(new FileInputStream(orig));
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmp));
+ byte[] buf = new byte[16 * 1024];
+ for (;;) {
+ int r = bis.read(buf, 0, buf.length);
+ if (r < 0) {
+ break;
+ } else if (r > 0) {
+ bos.write(buf, 0, r);
+ }
+ }
+ bos.close();
+ bis.close();
+ }
+ }
+
+ private static File find(String in) {
+ String libraryPath = System.getProperty("java.library.path");
+ for (String path : libraryPath.split(":")) {
+ File f = new File(path + "/" + in);
+ if (f.exists()) {
+ return f;
+ }
+ }
+ return null;
+ }
}
diff --git a/test/936-search-onload/search_onload.cc b/test/936-search-onload/search_onload.cc
index 90d87e0e7b..23cea83be6 100644
--- a/test/936-search-onload/search_onload.cc
+++ b/test/936-search-onload/search_onload.cc
@@ -18,8 +18,9 @@
#include <inttypes.h>
-#include "android-base/stringprintf.h"
-#include "base/logging.h"
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+
#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
diff --git a/test/954-invoke-polymorphic-verifier/expected.txt b/test/954-invoke-polymorphic-verifier/expected.txt
index 5df393aede..d49af9648f 100644
--- a/test/954-invoke-polymorphic-verifier/expected.txt
+++ b/test/954-invoke-polymorphic-verifier/expected.txt
@@ -5,6 +5,12 @@ java.lang.VerifyError: Verifier rejected class TooFewArguments: void TooFewArgum
java.lang.VerifyError: Verifier rejected class TooManyArguments: void TooManyArguments.<init>() failed to verify: void TooManyArguments.<init>(): void TooManyArguments.<init>(): Rejecting invocation, expected 4 argument registers, method signature has 3
java.lang.VerifyError: Verifier rejected class BadThis: void BadThis.<init>() failed to verify: void BadThis.<init>(): void BadThis.<init>(): 'this' argument 'Precise Reference: java.lang.String' not instance of 'Reference: java.lang.invoke.MethodHandle'
java.lang.VerifyError: Verifier rejected class FakeSignaturePolymorphic: void FakeSignaturePolymorphic.<init>() failed to verify: void FakeSignaturePolymorphic.<init>(): void FakeSignaturePolymorphic.<init>(): invoke type (METHOD_POLYMORPHIC) does not match method type of java.lang.Object Main.invoke(java.lang.Object[])
-java.lang.VerifyError: Verifier rejected class BetterFakeSignaturePolymorphic: void BetterFakeSignaturePolymorphic.<init>() failed to verify: void BetterFakeSignaturePolymorphic.<init>(): Signature polymorphic method must be declared in java.lang.invoke.MethodClass
+java.lang.VerifyError: Verifier rejected class BetterFakeSignaturePolymorphic: void BetterFakeSignaturePolymorphic.<init>() failed to verify: void BetterFakeSignaturePolymorphic.<init>(): Signature polymorphic method in unsuppported class: Main
Passed Subclass test
java.lang.VerifyError: Verifier rejected class Unresolved: void Unresolved.<init>() failed to verify: void Unresolved.<init>(): invoke-polymorphic receiver has no class: Unresolved Reference: other.thing.Foo
+Passed VarHandleHappyAccessors test
+java.lang.VerifyError: Verifier rejected class VarHandleUnhappyAccessors: void VarHandleUnhappyAccessors.compareAndExchange(java.lang.invoke.VarHandle, java.lang.Object[]) failed to verify: void VarHandleUnhappyAccessors.compareAndExchange(java.lang.invoke.VarHandle, java.lang.Object[]): void VarHandleUnhappyAccessors.compareAndExchange(java.lang.invoke.VarHandle, java.lang.Object[]): couldn't find method java.lang.invoke.VarHandle.compareAndExchange ([Ljava/lang/Object;)Ljava/lang/Integer;
+ void VarHandleUnhappyAccessors.compareAndExchangeAcquire(java.lang.invoke.VarHandle) failed to verify: void VarHandleUnhappyAccessors.compareAndExchangeAcquire(java.lang.invoke.VarHandle): void VarHandleUnhappyAccessors.compareAndExchangeAcquire(java.lang.invoke.VarHandle): couldn't find method java.lang.invoke.VarHandle.compareAndExchangeAcquire (I)Ljava/lang/Object;
+ void VarHandleUnhappyAccessors.compareAndExchangeRelease(java.lang.invoke.VarHandle) failed to verify: void VarHandleUnhappyAccessors.compareAndExchangeRelease(java.lang.invoke.VarHandle): void VarHandleUnhappyAccessors.compareAndExchangeRelease(java.lang.invoke.VarHandle): couldn't find method java.lang.invoke.VarHandle.compareAndExchangeRelease ()V
+ void VarHandleUnhappyAccessors.compareAndSet(java.lang.invoke.VarHandle) failed to verify: void VarHandleUnhappyAccessors.compareAndSet(java.lang.invoke.VarHandle): void VarHandleUnhappyAccessors.compareAndSet(java.lang.invoke.VarHandle): couldn't find method java.lang.invoke.VarHandle.compareAndSet (I)Z
+java.lang.VerifyError: Verifier rejected class VarHandleUnknownAccessor: void VarHandleUnknownAccessor.<init>() failed to verify: void VarHandleUnknownAccessor.<init>(): void VarHandleUnknownAccessor.<init>(): couldn't find method java.lang.invoke.VarHandle.unknownAccessor ([Ljava/lang/Object;)Ljava/lang/Object;
diff --git a/test/954-invoke-polymorphic-verifier/smali/Main.smali b/test/954-invoke-polymorphic-verifier/smali/Main.smali
index 5b5e5557d7..e35aae7f4e 100644
--- a/test/954-invoke-polymorphic-verifier/smali/Main.smali
+++ b/test/954-invoke-polymorphic-verifier/smali/Main.smali
@@ -50,6 +50,12 @@
invoke-static {v0}, LMain;->test(Ljava/lang/String;)V
const-string v0, "Unresolved"
invoke-static {v0}, LMain;->test(Ljava/lang/String;)V
+ const-string v0, "VarHandleHappyAccessors"
+ invoke-static {v0}, LMain;->test(Ljava/lang/String;)V
+ const-string v0, "VarHandleUnhappyAccessors"
+ invoke-static {v0}, LMain;->test(Ljava/lang/String;)V
+const-string v0, "VarHandleUnknownAccessor"
+ invoke-static {v0}, LMain;->test(Ljava/lang/String;)V
return-void
.end method
diff --git a/test/954-invoke-polymorphic-verifier/smali/VarHandleHappyAccessors.smali b/test/954-invoke-polymorphic-verifier/smali/VarHandleHappyAccessors.smali
new file mode 100644
index 0000000000..ec6aa5bbce
--- /dev/null
+++ b/test/954-invoke-polymorphic-verifier/smali/VarHandleHappyAccessors.smali
@@ -0,0 +1,72 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.source "VarHandleHappyAccessors.smali"
+
+.class public LVarHandleHappyAccessors;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+.registers 4
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+ invoke-static {}, LVarHandleHappyAccessors;->getVarHandle()Ljava/lang/invoke/VarHandle;
+ move-result-object v0
+ if-eqz v0, :done
+ const/4 v1, 0
+ move-object v1, v1
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->compareAndExchange([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->compareAndExchangeAcquire([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->compareAndExchangeRelease([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->compareAndSet([Ljava/lang/Object;)Z, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->get([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAcquire([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndAdd([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndAddAcquire([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndAddRelease([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndBitwiseAnd([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndBitwiseAndAcquire([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndBitwiseAndRelease([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndBitwiseOr([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndBitwiseOrAcquire([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndBitwiseOrRelease([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndBitwiseXor([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndBitwiseXorAcquire([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndBitwiseXorRelease([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndSet([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndSetAcquire([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getAndSetRelease([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getOpaque([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->getVolatile([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->set([Ljava/lang/Object;)V, ([Ljava/lang/Object;)V
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->setOpaque([Ljava/lang/Object;)V, ([Ljava/lang/Object;)V
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->setRelease([Ljava/lang/Object;)V, ([Ljava/lang/Object;)V
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->setVolatile([Ljava/lang/Object;)V, ([Ljava/lang/Object;)V
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->weakCompareAndSet([Ljava/lang/Object;)Z, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->weakCompareAndSetAcquire([Ljava/lang/Object;)Z, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->weakCompareAndSetPlain([Ljava/lang/Object;)Z, ([Ljava/lang/Object;)Ljava/lang/Object;
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->weakCompareAndSetRelease([Ljava/lang/Object;)Z, ([Ljava/lang/Object;)Ljava/lang/Object;
+ return-void
+ :done
+ sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ const-string v1, "Passed VarHandleHappyAccessors test"
+ invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+.end method
+
+.method public static getVarHandle()Ljava/lang/invoke/VarHandle;
+.registers 1
+ const/4 v0, 0
+ return-object v0
+.end method
diff --git a/test/954-invoke-polymorphic-verifier/smali/VarHandleUnhappyAccessors.smali b/test/954-invoke-polymorphic-verifier/smali/VarHandleUnhappyAccessors.smali
new file mode 100644
index 0000000000..0832c04d38
--- /dev/null
+++ b/test/954-invoke-polymorphic-verifier/smali/VarHandleUnhappyAccessors.smali
@@ -0,0 +1,70 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.source "VarHandleUnhappyAccessors.smali"
+
+.class public LVarHandleUnhappyAccessors;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+.registers 4
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+ invoke-static {}, LVarHandleUnhappyAccessors;->getVarHandle()Ljava/lang/invoke/VarHandle;
+ move-result-object v0
+ invoke-static {}, LVarHandleUnhappyAccessors;->getObjectArray()[Ljava/lang/Object;
+ move-result-object v1
+ invoke-static {v0, v1}, LVarHandleUnhappyAccessors;->compareAndExchange(Ljava/lang/invoke/VarHandle;[Ljava/lang/Object;)V
+ invoke-static {v0}, LVarHandleUnhappyAccessors;->compareAndExchangeAcquire(Ljava/lang/invoke/VarHandle;)V
+ invoke-static {v0}, LVarHandleUnhappyAccessors;->compareAndExchangeRelease(Ljava/lang/invoke/VarHandle;)V
+ invoke-static {v0}, LVarHandleUnhappyAccessors;->compareAndSet(Ljava/lang/invoke/VarHandle;)V
+ return-void
+.end method
+
+# The following methods all invoke VarHandle accessors but the targetted
+# accessor methods have the wrong signature.
+
+.method public static compareAndExchange(Ljava/lang/invoke/VarHandle;[Ljava/lang/Object;)V
+.registers 2
+ invoke-polymorphic {p0, p1}, Ljava/lang/invoke/VarHandle;->compareAndExchange([Ljava/lang/Object;)Ljava/lang/Integer;, ([Ljava/lang/Object;)Ljava/lang/Object;
+.end method
+
+.method public static compareAndExchangeAcquire(Ljava/lang/invoke/VarHandle;)V
+.registers 2
+ const/4 v0, 1
+ invoke-polymorphic {p0, v0}, Ljava/lang/invoke/VarHandle;->compareAndExchangeAcquire(I)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+.end method
+
+.method public static compareAndExchangeRelease(Ljava/lang/invoke/VarHandle;)V
+.registers 1
+ invoke-polymorphic {p0}, Ljava/lang/invoke/VarHandle;->compareAndExchangeRelease()V, ([Ljava/lang/Object;)Ljava/lang/Object;
+.end method
+
+.method public static compareAndSet(Ljava/lang/invoke/VarHandle;)V
+.registers 2
+ const/4 v0, 1
+ invoke-polymorphic {p0, v0}, Ljava/lang/invoke/VarHandle;->compareAndSet(I)Z, ([Ljava/lang/Object;)Ljava/lang/Object;
+.end method
+
+.method public static getVarHandle()Ljava/lang/invoke/VarHandle;
+.registers 1
+ const/4 v0, 0
+ return-object v0
+.end method
+
+.method public static getObjectArray()[Ljava/lang/Object;
+.registers 1
+ const/4 v0, 0
+ return-object v0
+.end method
diff --git a/test/954-invoke-polymorphic-verifier/smali/VarHandleUnknownAccessor.smali b/test/954-invoke-polymorphic-verifier/smali/VarHandleUnknownAccessor.smali
new file mode 100644
index 0000000000..35084f5bca
--- /dev/null
+++ b/test/954-invoke-polymorphic-verifier/smali/VarHandleUnknownAccessor.smali
@@ -0,0 +1,37 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.source "VarHandleUnknownAccessor.smali"
+
+.class public LVarHandleUnknownAccessor;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+.registers 4
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+ invoke-static {}, LVarHandleUnknownAccessor;->getVarHandle()Ljava/lang/invoke/VarHandle;
+ move-result-object v0
+ const/4 v1, 0
+ move-object v1, v1
+ # Attempt invoke-polymorphic on VarHandle.unknownAccessor().
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/VarHandle;->unknownAccessor([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object;
+ return-void
+.end method
+
+.method public static getVarHandle()Ljava/lang/invoke/VarHandle;
+.registers 1
+ const/4 v0, 0
+ return-object v0
+.end method
diff --git a/test/980-redefine-object/expected.txt b/test/980-redefine-object/expected.txt
index 4c294bc870..0a80882de1 100644
--- a/test/980-redefine-object/expected.txt
+++ b/test/980-redefine-object/expected.txt
@@ -30,3 +30,7 @@ Object allocated of type 'java.util.LinkedList$Node'
Object allocated of type 'java.lang.Exception'
Exception caught.
Finishing test!
+Object allocated of type 'java.lang.Thread'
+Object allocated of type 'java.lang.Object'
+Object allocated of type 'java.lang.Object'
+Object allocated of type 'java.security.AccessControlContext'
diff --git a/test/983-source-transform-verify/source_transform.cc b/test/983-source-transform-verify/source_transform.cc
index ca3f88b347..55dc603c4f 100644
--- a/test/983-source-transform-verify/source_transform.cc
+++ b/test/983-source-transform-verify/source_transform.cc
@@ -25,12 +25,12 @@
#include "jni.h"
#include "jvmti.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "bytecode_utils.h"
-#include "dex_file.h"
-#include "dex_file_loader.h"
-#include "dex_instruction.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_loader.h"
+#include "dex/dex_instruction.h"
#include "jit/jit.h"
#include "native_stack_dump.h"
#include "runtime.h"
@@ -89,7 +89,8 @@ void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
if (!it.IsAtMethod() || it.GetMethodCodeItem() == nullptr) {
continue;
}
- for (const DexInstructionPcPair& pair : it.GetMethodCodeItem()->Instructions()) {
+ for (const DexInstructionPcPair& pair :
+ art::CodeItemInstructionAccessor(dex.get(), it.GetMethodCodeItem())) {
const Instruction& inst = pair.Inst();
int forbiden_flags = (Instruction::kVerifyError | Instruction::kVerifyRuntimeOnly);
if (inst.Opcode() == Instruction::RETURN_VOID_NO_BARRIER ||
diff --git a/test/AllFields/AllFields.java b/test/AllFields/AllFields.java
index d5eac8fa2e..24f8ba1a0b 100644
--- a/test/AllFields/AllFields.java
+++ b/test/AllFields/AllFields.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-class AllFields {
+public class AllFields {
static boolean sZ;
static byte sB;
static char sC;
diff --git a/test/AllFields/AllFieldsSub.java b/test/AllFields/AllFieldsSub.java
new file mode 100644
index 0000000000..d5f933f88d
--- /dev/null
+++ b/test/AllFields/AllFieldsSub.java
@@ -0,0 +1,17 @@
+/*
+ * 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 AllFieldsSub extends AllFields { }
diff --git a/test/AllFields/AllFieldsUnrelated.java b/test/AllFields/AllFieldsUnrelated.java
new file mode 100644
index 0000000000..4db66b1886
--- /dev/null
+++ b/test/AllFields/AllFieldsUnrelated.java
@@ -0,0 +1,17 @@
+/*
+ * 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 AllFieldsUnrelated { }
diff --git a/test/Android.bp b/test/Android.bp
index 01e424d5e3..f5ca2f0338 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -260,6 +260,8 @@ art_cc_defaults {
"1934-jvmti-signal-thread/signal_threads.cc",
"1939-proxy-frames/local_instance.cc",
"1941-dispose-stress/dispose_stress.cc",
+ "1942-suspend-raw-monitor-exit/native_suspend_monitor.cc",
+ "1943-suspend-raw-monitor-wait/native_suspend_monitor.cc",
],
shared_libs: [
"libbase",
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index fe4a327a1f..2cada76d90 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -22,7 +22,8 @@ TEST_ART_RUN_TEST_DEPENDENCIES := \
$(HOST_OUT_EXECUTABLES)/dx \
$(HOST_OUT_EXECUTABLES)/jasmin \
$(HOST_OUT_EXECUTABLES)/smali \
- $(HOST_OUT_EXECUTABLES)/dexmerger
+ $(HOST_OUT_EXECUTABLES)/dexmerger \
+ $(HOST_OUT_JAVA_LIBRARIES)/desugar.jar
# Add d8 dependency, if enabled.
ifeq ($(USE_D8),true)
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 34580800cc..22c51063fb 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -16,10 +16,12 @@
#include "jni.h"
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
#include "art_method-inl.h"
#include "base/enums.h"
-#include "base/logging.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "instrumentation.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc
index 80a278012d..fd6273769b 100644
--- a/test/common/stack_inspect.cc
+++ b/test/common/stack_inspect.cc
@@ -16,8 +16,10 @@
#include "jni.h"
-#include "base/logging.h"
-#include "dex_file-inl.h"
+#include <android-base/logging.h>
+
+#include "base/mutex.h"
+#include "dex/dex_file-inl.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "nth_caller_visitor.h"
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 31f43fc536..132099a45d 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -90,6 +90,9 @@ SYNC_BEFORE_RUN="n"
# When running a debug build, we want to run with all checks.
ANDROID_FLAGS="${ANDROID_FLAGS} -XX:SlowDebug=true"
+# The same for dex2oatd, both prebuild and runtime-driven.
+ANDROID_FLAGS="${ANDROID_FLAGS} -Xcompiler-option --runtime-arg -Xcompiler-option -XX:SlowDebug=true"
+COMPILER_FLAGS="${COMPILER_FLAGS} --runtime-arg -XX:SlowDebug=true"
while true; do
if [ "x$1" = "x--quiet" ]; then
@@ -184,6 +187,10 @@ while true; do
elif [ "x$1" = "x--prebuild" ]; then
PREBUILD="y"
shift
+ elif [ "x$1" = "x--compact-dex-level" ]; then
+ shift
+ COMPILE_FLAGS="${COMPILE_FLAGS} --compact-dex-level=$1"
+ shift
elif [ "x$1" = "x--jvmti-redefine-stress" ]; then
# APP_IMAGE doesn't really work with jvmti redefine stress
USE_JVMTI="y"
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 5b2ebf58a4..a12510c9dc 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -237,7 +237,8 @@
"tests": ["604-hot-static-interface",
"612-jit-dex-cache",
"613-inlining-dex-cache",
- "626-set-resolved-string"],
+ "626-set-resolved-string",
+ "638-checker-inline-cache-intrinsic"],
"variant": "trace | stream",
"description": ["These tests expect JIT compilation, which is",
"suppressed when tracing."]
@@ -649,4 +650,5 @@
"variant": "interp-ac | interpreter | jit | no-dex2oat | no-prebuild | no-image | trace",
"description": ["Test is designed to only check --compiler-filter=speed"]
}
+
]
diff --git a/test/run-test b/test/run-test
index fdb2ee47a7..75fe15c919 100755
--- a/test/run-test
+++ b/test/run-test
@@ -225,6 +225,11 @@ while true; do
run_args="${run_args} --prebuild"
prebuild_mode="yes"
shift;
+ elif [ "x$1" = "x--compact-dex-level" ]; then
+ option="$1"
+ shift
+ run_args="${run_args} $option $1"
+ shift;
elif [ "x$1" = "x--strip-dex" ]; then
run_args="${run_args} --strip-dex"
shift;
@@ -660,6 +665,7 @@ if [ "$usage" = "yes" ]; then
echo " -Xcompiler-option Pass an option to the compiler."
echo " --build-option Pass an option to the build script."
echo " --runtime-option Pass an option to the runtime."
+ echo " --compact-dex-level Specify a compact dex level to the compiler."
echo " --debug Wait for the default debugger to attach."
echo " --debug-agent <agent-path>"
echo " Wait for the given debugger agent to attach. Currently"
diff --git a/test/testrunner/target_config.py b/test/testrunner/target_config.py
index 6d21442045..297ce08bee 100644
--- a/test/testrunner/target_config.py
+++ b/test/testrunner/target_config.py
@@ -229,10 +229,13 @@ target_config = {
},
'art-heap-poisoning' : {
'run-test' : ['--interpreter',
- '--optimizing'],
+ '--optimizing',
+ '--cdex-fast'],
'env' : {
'ART_USE_READ_BARRIER' : 'false',
- 'ART_HEAP_POISONING' : 'true'
+ 'ART_HEAP_POISONING' : 'true',
+ # Get some extra automated testing coverage for compact dex.
+ 'ART_DEFAULT_COMPACT_DEX_LEVEL' : 'fast'
}
},
'art-preopt' : {
@@ -276,7 +279,9 @@ target_config = {
'make' : 'test-art-host-gtest',
'env': {
'ART_DEFAULT_GC_TYPE' : 'SS',
- 'ART_USE_READ_BARRIER' : 'false'
+ 'ART_USE_READ_BARRIER' : 'false',
+ # Get some extra automated testing coverage for compact dex.
+ 'ART_DEFAULT_COMPACT_DEX_LEVEL' : 'fast'
}
},
'art-gtest-gss-gc': {
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index 554b8a5429..93998579f3 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -141,6 +141,7 @@ def gather_test_info():
VARIANT_TYPE_DICT['debuggable'] = {'ndebuggable', 'debuggable'}
VARIANT_TYPE_DICT['gc'] = {'gcstress', 'gcverify', 'cms'}
VARIANT_TYPE_DICT['prebuild'] = {'no-prebuild', 'no-dex2oat', 'prebuild'}
+ VARIANT_TYPE_DICT['cdex_level'] = {'cdex-none', 'cdex-fast'}
VARIANT_TYPE_DICT['relocate'] = {'relocate-npatchoat', 'relocate', 'no-relocate'}
VARIANT_TYPE_DICT['jni'] = {'jni', 'forcecopy', 'checkjni'}
VARIANT_TYPE_DICT['address_sizes'] = {'64', '32'}
@@ -183,6 +184,9 @@ def setup_test_env():
if not _user_input_variants['prebuild']: # Default
_user_input_variants['prebuild'].add('prebuild')
+ if not _user_input_variants['cdex_level']: # Default
+ _user_input_variants['cdex_level'].add('cdex-none')
+
# By default only run without jvmti
if not _user_input_variants['jvmti']:
_user_input_variants['jvmti'].add('no-jvmti')
@@ -339,10 +343,11 @@ def run_tests(tests):
_user_input_variants['relocate'], _user_input_variants['trace'],
_user_input_variants['gc'], _user_input_variants['jni'],
_user_input_variants['image'], _user_input_variants['pictest'],
- _user_input_variants['debuggable'], _user_input_variants['jvmti'])
+ _user_input_variants['debuggable'], _user_input_variants['jvmti'],
+ _user_input_variants['cdex_level'])
for test, target, run, prebuild, compiler, relocate, trace, gc, \
- jni, image, pictest, debuggable, jvmti in config:
+ jni, image, pictest, debuggable, jvmti, cdex_level in config:
for address_size in _user_input_variants['address_sizes_target'][target]:
if stop_testrunner:
# When ART_TEST_KEEP_GOING is set to false, then as soon as a test
@@ -356,6 +361,7 @@ def run_tests(tests):
test_name += target + '-run-test-'
test_name += run + '-'
test_name += prebuild + '-'
+ test_name += cdex_level + '-'
test_name += compiler + '-'
test_name += relocate + '-'
test_name += trace + '-'
@@ -369,7 +375,7 @@ def run_tests(tests):
test_name += address_size
variant_set = {target, run, prebuild, compiler, relocate, trace, gc, jni,
- image, pictest, debuggable, jvmti, address_size}
+ image, pictest, debuggable, jvmti, cdex_level, address_size}
options_test = options_all
@@ -386,6 +392,9 @@ def run_tests(tests):
elif prebuild == 'no-dex2oat':
options_test += ' --no-prebuild --no-dex2oat'
+ # Add option and remove the cdex- prefix.
+ options_test += ' --compact-dex-level ' + cdex_level.replace('cdex-','')
+
if compiler == 'optimizing':
options_test += ' --optimizing'
elif compiler == 'regalloc_gc':
@@ -806,6 +815,7 @@ def parse_test_name(test_name):
regex += '(' + '|'.join(VARIANT_TYPE_DICT['pictest']) + ')-'
regex += '(' + '|'.join(VARIANT_TYPE_DICT['debuggable']) + ')-'
regex += '(' + '|'.join(VARIANT_TYPE_DICT['jvmti']) + ')-'
+ regex += '(' + '|'.join(VARIANT_TYPE_DICT['cdex_level']) + ')-'
regex += '(' + '|'.join(RUN_TEST_SET) + ')'
regex += '(' + '|'.join(VARIANT_TYPE_DICT['address_sizes']) + ')$'
match = re.match(regex, test_name)
@@ -822,8 +832,9 @@ def parse_test_name(test_name):
_user_input_variants['pictest'].add(match.group(10))
_user_input_variants['debuggable'].add(match.group(11))
_user_input_variants['jvmti'].add(match.group(12))
- _user_input_variants['address_sizes'].add(match.group(14))
- return {match.group(13)}
+ _user_input_variants['cdex_level'].add(match.group(13))
+ _user_input_variants['address_sizes'].add(match.group(15))
+ return {match.group(14)}
raise ValueError(test_name + " is not a valid test")
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index d85f33a05d..9a7352e479 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -17,7 +17,8 @@
#include <jni.h>
#include <stdio.h>
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "base/macros.h"
#include "jni_binder.h"
diff --git a/test/ti-agent/trace_helper.cc b/test/ti-agent/trace_helper.cc
index 8b74c7c089..b590175d77 100644
--- a/test/ti-agent/trace_helper.cc
+++ b/test/ti-agent/trace_helper.cc
@@ -27,6 +27,49 @@ namespace art {
namespace common_trace {
+static bool IsInCallback(JNIEnv* env, jvmtiEnv *jvmti, jthread thr) {
+ void* data;
+ ScopedLocalRef<jthrowable> exc(env, env->ExceptionOccurred());
+ env->ExceptionClear();
+ jvmti->GetThreadLocalStorage(thr, &data);
+ if (exc.get() != nullptr) {
+ env->Throw(exc.get());
+ }
+ if (data == nullptr) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+static void SetInCallback(JNIEnv* env, jvmtiEnv *jvmti, jthread thr, bool val) {
+ ScopedLocalRef<jthrowable> exc(env, env->ExceptionOccurred());
+ env->ExceptionClear();
+ jvmti->SetThreadLocalStorage(thr, (val ? reinterpret_cast<void*>(0x1)
+ : reinterpret_cast<void*>(0x0)));
+ if (exc.get() != nullptr) {
+ env->Throw(exc.get());
+ }
+}
+
+class ScopedCallbackState {
+ public:
+ ScopedCallbackState(JNIEnv* jnienv, jvmtiEnv* env, jthread thr)
+ : jnienv_(jnienv), env_(env), thr_(thr) {
+ CHECK(!IsInCallback(jnienv_, env_, thr_));
+ SetInCallback(jnienv_, env_, thr_, true);
+ }
+ ~ScopedCallbackState() {
+ CHECK(IsInCallback(jnienv_, env_, thr_));
+ SetInCallback(jnienv_, env_, thr_, false);
+ }
+
+ private:
+ JNIEnv* jnienv_;
+ jvmtiEnv* env_;
+ jthread thr_;
+};
+
struct TraceData {
jclass test_klass;
jmethodID enter_method;
@@ -36,9 +79,20 @@ struct TraceData {
jmethodID single_step;
jmethodID thread_start;
jmethodID thread_end;
- bool in_callback;
bool access_watch_on_load;
bool modify_watch_on_load;
+ jrawMonitorID trace_mon;
+
+ jclass GetTestClass(jvmtiEnv* jvmti, JNIEnv* env) {
+ if (JvmtiErrorToException(env, jvmti, jvmti->RawMonitorEnter(trace_mon))) {
+ return nullptr;
+ }
+ jclass out = reinterpret_cast<jclass>(env->NewLocalRef(test_klass));
+ if (JvmtiErrorToException(env, jvmti, jvmti->RawMonitorExit(trace_mon))) {
+ return nullptr;
+ }
+ return out;
+ }
};
static void threadStartCB(jvmtiEnv* jvmti,
@@ -49,8 +103,12 @@ static void threadStartCB(jvmtiEnv* jvmti,
jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
return;
}
+ ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
+ if (klass.get() == nullptr) {
+ return;
+ }
CHECK(data->thread_start != nullptr);
- jnienv->CallStaticVoidMethod(data->test_klass, data->thread_start, thread);
+ jnienv->CallStaticVoidMethod(klass.get(), data->thread_start, thread);
}
static void threadEndCB(jvmtiEnv* jvmti,
JNIEnv* jnienv,
@@ -60,8 +118,12 @@ static void threadEndCB(jvmtiEnv* jvmti,
jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
return;
}
+ ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
+ if (klass.get() == nullptr) {
+ return;
+ }
CHECK(data->thread_end != nullptr);
- jnienv->CallStaticVoidMethod(data->test_klass, data->thread_end, thread);
+ jnienv->CallStaticVoidMethod(klass.get(), data->thread_end, thread);
}
static void singleStepCB(jvmtiEnv* jvmti,
@@ -74,24 +136,27 @@ static void singleStepCB(jvmtiEnv* jvmti,
jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
return;
}
- if (data->in_callback) {
+ if (IsInCallback(jnienv, jvmti, thread)) {
+ return;
+ }
+ ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
+ if (klass.get() == nullptr) {
return;
}
CHECK(data->single_step != nullptr);
- data->in_callback = true;
+ ScopedCallbackState st(jnienv, jvmti, thread);
jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
- jnienv->CallStaticVoidMethod(data->test_klass,
+ jnienv->CallStaticVoidMethod(klass.get(),
data->single_step,
thread,
method_arg,
static_cast<jlong>(location));
jnienv->DeleteLocalRef(method_arg);
- data->in_callback = false;
}
static void fieldAccessCB(jvmtiEnv* jvmti,
JNIEnv* jnienv,
- jthread thr ATTRIBUTE_UNUSED,
+ jthread thr,
jmethodID method,
jlocation location,
jclass field_klass,
@@ -102,15 +167,19 @@ static void fieldAccessCB(jvmtiEnv* jvmti,
jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
return;
}
- if (data->in_callback) {
+ if (IsInCallback(jnienv, jvmti, thr)) {
// Don't do callback for either of these to prevent an infinite loop.
return;
}
+ ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
+ if (klass.get() == nullptr) {
+ return;
+ }
CHECK(data->field_access != nullptr);
- data->in_callback = true;
+ ScopedCallbackState st(jnienv, jvmti, thr);
jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
jobject field_arg = GetJavaField(jvmti, jnienv, field_klass, field);
- jnienv->CallStaticVoidMethod(data->test_klass,
+ jnienv->CallStaticVoidMethod(klass.get(),
data->field_access,
method_arg,
static_cast<jlong>(location),
@@ -119,12 +188,11 @@ static void fieldAccessCB(jvmtiEnv* jvmti,
field_arg);
jnienv->DeleteLocalRef(method_arg);
jnienv->DeleteLocalRef(field_arg);
- data->in_callback = false;
}
static void fieldModificationCB(jvmtiEnv* jvmti,
JNIEnv* jnienv,
- jthread thr ATTRIBUTE_UNUSED,
+ jthread thr,
jmethodID method,
jlocation location,
jclass field_klass,
@@ -137,22 +205,25 @@ static void fieldModificationCB(jvmtiEnv* jvmti,
jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
return;
}
- if (data->in_callback) {
+ if (IsInCallback(jnienv, jvmti, thr)) {
// Don't do callback recursively to prevent an infinite loop.
return;
}
+ ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
+ if (klass.get() == nullptr) {
+ return;
+ }
CHECK(data->field_modify != nullptr);
- data->in_callback = true;
+ ScopedCallbackState st(jnienv, jvmti, thr);
jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
jobject field_arg = GetJavaField(jvmti, jnienv, field_klass, field);
jobject value = GetJavaValueByType(jnienv, type_char, new_value);
if (jnienv->ExceptionCheck()) {
- data->in_callback = false;
jnienv->DeleteLocalRef(method_arg);
jnienv->DeleteLocalRef(field_arg);
return;
}
- jnienv->CallStaticVoidMethod(data->test_klass,
+ jnienv->CallStaticVoidMethod(klass.get(),
data->field_modify,
method_arg,
static_cast<jlong>(location),
@@ -162,12 +233,11 @@ static void fieldModificationCB(jvmtiEnv* jvmti,
value);
jnienv->DeleteLocalRef(method_arg);
jnienv->DeleteLocalRef(field_arg);
- data->in_callback = false;
}
static void methodExitCB(jvmtiEnv* jvmti,
JNIEnv* jnienv,
- jthread thr ATTRIBUTE_UNUSED,
+ jthread thr,
jmethodID method,
jboolean was_popped_by_exception,
jvalue return_value) {
@@ -176,31 +246,35 @@ static void methodExitCB(jvmtiEnv* jvmti,
jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
return;
}
- if (method == data->exit_method || method == data->enter_method || data->in_callback) {
+ if (method == data->exit_method ||
+ method == data->enter_method ||
+ IsInCallback(jnienv, jvmti, thr)) {
// Don't do callback for either of these to prevent an infinite loop.
return;
}
+ ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
+ if (klass.get() == nullptr) {
+ return;
+ }
CHECK(data->exit_method != nullptr);
- data->in_callback = true;
+ ScopedCallbackState st(jnienv, jvmti, thr);
jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
jobject result =
was_popped_by_exception ? nullptr : GetJavaValue(jvmti, jnienv, method, return_value);
if (jnienv->ExceptionCheck()) {
- data->in_callback = false;
return;
}
- jnienv->CallStaticVoidMethod(data->test_klass,
+ jnienv->CallStaticVoidMethod(klass.get(),
data->exit_method,
method_arg,
was_popped_by_exception,
result);
jnienv->DeleteLocalRef(method_arg);
- data->in_callback = false;
}
static void methodEntryCB(jvmtiEnv* jvmti,
JNIEnv* jnienv,
- jthread thr ATTRIBUTE_UNUSED,
+ jthread thr,
jmethodID method) {
TraceData* data = nullptr;
if (JvmtiErrorToException(jnienv, jvmti,
@@ -208,18 +282,23 @@ static void methodEntryCB(jvmtiEnv* jvmti,
return;
}
CHECK(data->enter_method != nullptr);
- if (method == data->exit_method || method == data->enter_method || data->in_callback) {
+ if (method == data->exit_method ||
+ method == data->enter_method ||
+ IsInCallback(jnienv, jvmti, thr)) {
// Don't do callback for either of these to prevent an infinite loop.
return;
}
- data->in_callback = true;
+ ScopedLocalRef<jclass> klass(jnienv, data->GetTestClass(jvmti, jnienv));
+ if (klass.get() == nullptr) {
+ return;
+ }
+ ScopedCallbackState st(jnienv, jvmti, thr);
jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
if (jnienv->ExceptionCheck()) {
return;
}
- jnienv->CallStaticVoidMethod(data->test_klass, data->enter_method, method_arg);
+ jnienv->CallStaticVoidMethod(klass.get(), data->enter_method, method_arg);
jnienv->DeleteLocalRef(method_arg);
- data->in_callback = false;
}
static void classPrepareCB(jvmtiEnv* jvmti,
@@ -407,6 +486,10 @@ extern "C" JNIEXPORT void JNICALL Java_art_Trace_enableTracing2(
return;
}
memset(data, 0, sizeof(TraceData));
+ if (JvmtiErrorToException(env, jvmti_env,
+ jvmti_env->CreateRawMonitor("Trace monitor", &data->trace_mon))) {
+ return;
+ }
data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(klass));
data->enter_method = enter != nullptr ? env->FromReflectedMethod(enter) : nullptr;
data->exit_method = exit != nullptr ? env->FromReflectedMethod(exit) : nullptr;
@@ -415,7 +498,6 @@ extern "C" JNIEXPORT void JNICALL Java_art_Trace_enableTracing2(
data->single_step = single_step != nullptr ? env->FromReflectedMethod(single_step) : nullptr;
data->thread_start = thread_start != nullptr ? env->FromReflectedMethod(thread_start) : nullptr;
data->thread_end = thread_end != nullptr ? env->FromReflectedMethod(thread_end) : nullptr;
- data->in_callback = false;
TraceData* old_data = nullptr;
if (JvmtiErrorToException(env, jvmti_env,
@@ -537,42 +619,63 @@ extern "C" JNIEXPORT void JNICALL Java_art_Trace_disableTracing(
if (data == nullptr || data->test_klass == nullptr) {
return;
}
- env->DeleteGlobalRef(data->test_klass);
- if (env->ExceptionCheck()) {
- return;
- }
- // Clear test_klass so we know this isn't being used
- data->test_klass = nullptr;
+ ScopedLocalRef<jthrowable> err(env, nullptr);
+ // First disable all the events.
if (JvmtiErrorToException(env, jvmti_env,
jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
JVMTI_EVENT_FIELD_ACCESS,
thr))) {
- return;
+ env->ExceptionDescribe();
+ err.reset(env->ExceptionOccurred());
+ env->ExceptionClear();
}
if (JvmtiErrorToException(env, jvmti_env,
jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
JVMTI_EVENT_FIELD_MODIFICATION,
thr))) {
- return;
+ env->ExceptionDescribe();
+ err.reset(env->ExceptionOccurred());
+ env->ExceptionClear();
}
if (JvmtiErrorToException(env, jvmti_env,
jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
JVMTI_EVENT_METHOD_ENTRY,
thr))) {
- return;
+ env->ExceptionDescribe();
+ err.reset(env->ExceptionOccurred());
+ env->ExceptionClear();
}
if (JvmtiErrorToException(env, jvmti_env,
jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
JVMTI_EVENT_METHOD_EXIT,
thr))) {
- return;
+ env->ExceptionDescribe();
+ err.reset(env->ExceptionOccurred());
+ env->ExceptionClear();
}
if (JvmtiErrorToException(env, jvmti_env,
jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
JVMTI_EVENT_SINGLE_STEP,
thr))) {
+ env->ExceptionDescribe();
+ err.reset(env->ExceptionOccurred());
+ env->ExceptionClear();
+ }
+ if (JvmtiErrorToException(env, jvmti_env,
+ jvmti_env->RawMonitorEnter(data->trace_mon))) {
return;
}
+ // Clear test_klass so we know this isn't being used
+ env->DeleteGlobalRef(data->test_klass);
+ data->test_klass = nullptr;
+ if (JvmtiErrorToException(env,
+ jvmti_env,
+ jvmti_env->RawMonitorExit(data->trace_mon))) {
+ return;
+ }
+ if (err.get() != nullptr) {
+ env->Throw(err.get());
+ }
}
} // namespace common_trace
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index a9a0492fe9..34e6a9cd42 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -23,6 +23,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src/main)
LOCAL_JAR_MANIFEST := etc/ahat.mf
LOCAL_JAVA_RESOURCE_FILES := $(LOCAL_PATH)/etc/style.css
+LOCAL_JAVACFLAGS := -Xdoclint:all/protected
LOCAL_IS_HOST_MODULE := true
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := ahat
diff --git a/tools/ahat/README.txt b/tools/ahat/README.txt
index a765b17951..cdfeba45cb 100644
--- a/tools/ahat/README.txt
+++ b/tools/ahat/README.txt
@@ -30,7 +30,6 @@ TODO:
* Show somewhere where to send bugs.
* Include a link to /objects in the overview and menu?
* Turn on LOCAL_JAVACFLAGS := -Xlint:unchecked -Werror
- * Use hex for object ids in URLs?
* [low priority] by site allocations won't line up if the stack has been
truncated. Is there any way to manually line them up in that case?
@@ -54,7 +53,15 @@ Reported Issues:
* Request to be able to sort tables by size.
Release History:
- 1.5 Pending
+ 1.6 Pending
+
+ 1.5 December 05, 2017
+ Distinguish between weakly reachable and unreachable instances.
+ Allow hex ids to be used for objects in query parameters.
+ Restore old presentation of sample paths from gc roots.
+ Fix bug in selection of sample paths from gc root.
+ Fix bug in proguard deobfuscation of stack frames.
+ Tighten up and document ahat public API.
1.4 October 03, 2017
Give better error messages on failure to launch ahat.
diff --git a/tools/ahat/etc/ahat.mf b/tools/ahat/etc/ahat.mf
index 1753406e6e..df964838bd 100644
--- a/tools/ahat/etc/ahat.mf
+++ b/tools/ahat/etc/ahat.mf
@@ -1,4 +1,4 @@
Name: ahat/
Implementation-Title: ahat
-Implementation-Version: 1.4
+Implementation-Version: 1.5
Main-Class: com.android.ahat.Main
diff --git a/tools/ahat/etc/ahat_api.txt b/tools/ahat/etc/ahat_api.txt
index 7920adae55..93fe46bf8b 100644
--- a/tools/ahat/etc/ahat_api.txt
+++ b/tools/ahat/etc/ahat_api.txt
@@ -9,7 +9,6 @@ package com.android.ahat {
package com.android.ahat.dominators {
public class DominatorsComputation {
- ctor public DominatorsComputation();
method public static void computeDominators(com.android.ahat.dominators.DominatorsComputation.Node);
}
@@ -109,7 +108,6 @@ package com.android.ahat.heapdump {
}
public class Diff {
- ctor public Diff();
method public static void snapshots(com.android.ahat.heapdump.AhatSnapshot, com.android.ahat.heapdump.AhatSnapshot);
}
@@ -159,7 +157,6 @@ package com.android.ahat.heapdump {
}
public class Parser {
- ctor public Parser();
method public static com.android.ahat.heapdump.AhatSnapshot parseHeapDump(java.io.File, com.android.ahat.proguard.ProguardMap) throws com.android.ahat.heapdump.HprofFormatException, java.io.IOException;
method public static com.android.ahat.heapdump.AhatSnapshot parseHeapDump(java.nio.ByteBuffer, com.android.ahat.proguard.ProguardMap) throws com.android.ahat.heapdump.HprofFormatException, java.io.IOException;
}
@@ -210,11 +207,9 @@ package com.android.ahat.heapdump {
}
public static class Site.ObjectsInfo implements com.android.ahat.heapdump.Diffable {
- ctor public Site.ObjectsInfo(com.android.ahat.heapdump.AhatHeap, com.android.ahat.heapdump.AhatClassObj);
method public com.android.ahat.heapdump.Site.ObjectsInfo getBaseline();
method public java.lang.String getClassName();
method public boolean isPlaceHolder();
- method public void setBaseline(com.android.ahat.heapdump.Site.ObjectsInfo);
field public com.android.ahat.heapdump.AhatClassObj classObj;
field public com.android.ahat.heapdump.AhatHeap heap;
field public com.android.ahat.heapdump.Size numBytes;
@@ -236,6 +231,7 @@ package com.android.ahat.heapdump {
ctor public Sort();
method public static java.util.Comparator<com.android.ahat.heapdump.AhatInstance> defaultInstanceCompare(com.android.ahat.heapdump.AhatSnapshot);
method public static java.util.Comparator<com.android.ahat.heapdump.Site> defaultSiteCompare(com.android.ahat.heapdump.AhatSnapshot);
+ method public static <T> java.util.Comparator<T> withPriority(java.util.Comparator<T>...);
field public static final java.util.Comparator<com.android.ahat.heapdump.FieldValue> FIELD_VALUE_BY_NAME;
field public static final java.util.Comparator<com.android.ahat.heapdump.FieldValue> FIELD_VALUE_BY_TYPE;
field public static final java.util.Comparator<com.android.ahat.heapdump.AhatInstance> INSTANCE_BY_TOTAL_RETAINED_SIZE;
@@ -246,22 +242,6 @@ package com.android.ahat.heapdump {
field public static final java.util.Comparator<com.android.ahat.heapdump.Size> SIZE_BY_SIZE;
}
- public static class Sort.InstanceByHeapRetainedSize implements java.util.Comparator {
- ctor public Sort.InstanceByHeapRetainedSize(com.android.ahat.heapdump.AhatHeap);
- method public int compare(com.android.ahat.heapdump.AhatInstance, com.android.ahat.heapdump.AhatInstance);
- }
-
- public static class Sort.SiteByHeapSize implements java.util.Comparator {
- ctor public Sort.SiteByHeapSize(com.android.ahat.heapdump.AhatHeap);
- method public int compare(com.android.ahat.heapdump.Site, com.android.ahat.heapdump.Site);
- }
-
- public static class Sort.WithPriority<T> implements java.util.Comparator {
- ctor public Sort.WithPriority(java.util.Comparator<T>...);
- ctor public Sort.WithPriority(java.util.List<java.util.Comparator<T>>);
- method public int compare(T, T);
- }
-
public final class Type extends java.lang.Enum {
method public static com.android.ahat.heapdump.Type valueOf(java.lang.String);
method public static final com.android.ahat.heapdump.Type[] values();
@@ -285,7 +265,6 @@ package com.android.ahat.heapdump {
method public java.lang.Integer asInteger();
method public java.lang.Long asLong();
method public abstract boolean equals(java.lang.Object);
- method public com.android.ahat.heapdump.Value getBaseline();
method public static com.android.ahat.heapdump.Value getBaseline(com.android.ahat.heapdump.Value);
method public static com.android.ahat.heapdump.Type getType(com.android.ahat.heapdump.Value);
method public boolean isAhatInstance();
diff --git a/tools/ahat/src/main/com/android/ahat/Main.java b/tools/ahat/src/main/com/android/ahat/Main.java
index 048573e915..04a6012a61 100644
--- a/tools/ahat/src/main/com/android/ahat/Main.java
+++ b/tools/ahat/src/main/com/android/ahat/Main.java
@@ -30,6 +30,9 @@ import java.net.InetSocketAddress;
import java.text.ParseException;
import java.util.concurrent.Executors;
+/**
+ * Contains the main entry point for the ahat heap dump viewer.
+ */
public class Main {
private Main() {
}
@@ -70,6 +73,14 @@ public class Main {
throw new AssertionError("Unreachable");
}
+ /**
+ * Main entry for ahat heap dump viewer.
+ * Launches an http server on localhost for viewing a given heap dump.
+ * See the ahat README or pass "--help" as one of the arguments to see a
+ * description of what arguments and options are expected.
+ *
+ * @param args the command line arguments
+ */
public static void main(String[] args) {
int port = 7100;
for (String arg : args) {
diff --git a/tools/ahat/src/main/com/android/ahat/SiteHandler.java b/tools/ahat/src/main/com/android/ahat/SiteHandler.java
index 543eaa376a..5093f0d43e 100644
--- a/tools/ahat/src/main/com/android/ahat/SiteHandler.java
+++ b/tools/ahat/src/main/com/android/ahat/SiteHandler.java
@@ -88,7 +88,7 @@ class SiteHandler implements AhatHandler {
new Column("Class"));
List<Site.ObjectsInfo> infos = site.getObjectsInfos();
- Comparator<Site.ObjectsInfo> compare = new Sort.WithPriority<Site.ObjectsInfo>(
+ Comparator<Site.ObjectsInfo> compare = Sort.withPriority(
Sort.OBJECTS_INFO_BY_HEAP_NAME,
Sort.OBJECTS_INFO_BY_SIZE,
Sort.OBJECTS_INFO_BY_CLASS_NAME);
diff --git a/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java b/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java
index 58b7b59f9a..d3fea4869a 100644
--- a/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java
+++ b/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java
@@ -23,38 +23,72 @@ import java.util.List;
import java.util.Queue;
/**
- * Generic DominatorsComputation.
- *
- * To use the dominators computation, have your graph nodes implement the
- * DominatorsComputation.Node interface, then call
- * DominatorsComputation.computeDominators on the single root node.
+ * Provides a static method for computing the immediate dominators of a
+ * directed graph. It can be used with any directed graph data structure
+ * that implements the {@link DominatorsComputation.Node} interface and has
+ * some root node with no incoming edges.
*/
public class DominatorsComputation {
+ private DominatorsComputation() {
+ }
+
/**
- * Interface for a directed graph to perform the dominators computation on.
+ * Interface for a directed graph to perform immediate dominators
+ * computation on.
+ * The dominators computation can be used with directed graph data
+ * structures that implement this <code>Node</code> interface. To use the
+ * dominators computation on your graph, you must make the following
+ * functionality available to the dominators computation:
+ * <ul>
+ * <li>Efficiently mapping from node to associated internal dominators
+ * computation state using the
+ * {@link #setDominatorsComputationState setDominatorsComputationState} and
+ * {@link #getDominatorsComputationState getDominatorsComputationState} methods.
+ * <li>Iterating over all outgoing edges of an node using the
+ * {@link #getReferencesForDominators getReferencesForDominators} method.
+ * <li>Setting the computed dominator for a node using the
+ * {@link #setDominator setDominator} method.
+ * </ul>
*/
public interface Node {
/**
- * Associate the given dominator state with this node.
+ * Associates the given dominator state with this node. Subsequent calls to
+ * {@link #getDominatorsComputationState getDominatorsComputationState} on
+ * this node should return the state given here. At the conclusion of the
+ * dominators computation, this method will be called for
+ * each node with <code>state</code> set to null.
+ *
+ * @param state the dominator state to associate with this node
*/
void setDominatorsComputationState(Object state);
/**
- * Get the most recent dominator state associated with this node using
- * setDominatorsComputationState. If setDominatorsComputationState has not
- * yet been called, this should return null.
+ * Returns the dominator state most recently associated with this node
+ * by a call to {@link #setDominatorsComputationState setDominatorsComputationState}.
+ * If <code>setDominatorsComputationState</code> has not yet been called
+ * on this node for this dominators computation, this method should return
+ * null.
+ *
+ * @return the associated dominator state
*/
Object getDominatorsComputationState();
/**
- * Return a collection of nodes referenced from this node, for the
- * purposes of computing dominators.
+ * Returns a collection of nodes referenced from this node, for the
+ * purposes of computing dominators. This method will be called at most
+ * once for each node reachable from the root node of the dominators
+ * computation.
+ *
+ * @return an iterable collection of the nodes with an incoming edge from
+ * this node.
*/
Iterable<? extends Node> getReferencesForDominators();
/**
- * Update this node's dominator based on the results of the dominators
+ * Sets the dominator for this node based on the results of the dominators
* computation.
+ *
+ * @param dominator the computed immediate dominator of this node
*/
void setDominator(Node dominator);
}
@@ -112,8 +146,14 @@ public class DominatorsComputation {
}
/**
- * Compute the dominator tree rooted at the given node.
- * There must not be any incoming references to the root node.
+ * Computes the immediate dominators of all nodes reachable from the <code>root</code> node.
+ * There must not be any incoming references to the <code>root</code> node.
+ * <p>
+ * The result of this function is to call the {@link Node#setDominator}
+ * function on every node reachable from the root node.
+ *
+ * @param root the root node of the dominators computation
+ * @see Node
*/
public static void computeDominators(Node root) {
long id = 0;
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java
index ccdd6e4df7..9c80802673 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java
@@ -21,6 +21,12 @@ import java.util.AbstractList;
import java.util.Collections;
import java.util.List;
+/**
+ * An array instance from a parsed heap dump.
+ * It is used for both object and primitive arrays. The class provides methods
+ * for accessing the length and elements of the array in addition to those
+ * methods inherited from {@link AhatInstance}.
+ */
public class AhatArrayInstance extends AhatInstance {
// To save space, we store arrays as primitive arrays or AhatInstance arrays
// and provide a wrapper over the arrays to expose a list of Values.
@@ -186,21 +192,30 @@ public class AhatArrayInstance extends AhatInstance {
}
/**
- * Returns the length of the array.
+ * Returns the number of elements in the array.
+ *
+ * @return number of elements in the array.
*/
public int getLength() {
return mValues.size();
}
/**
- * Returns the array's values.
+ * Returns a list of all of the array's elements in order.
+ * The returned list does not support modification.
+ *
+ * @return list of the array's elements.
*/
public List<Value> getValues() {
return mValues;
}
/**
- * Returns the object at the given index of this array.
+ * Returns the value at the given index of this array.
+ *
+ * @param index the index of the value to retrieve
+ * @return the value at the given index
+ * @throws IndexOutOfBoundsException if the index is out of range
*/
public Value getValue(int index) {
return mValues.get(index);
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
index cb9d959508..c82ef20e9b 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
@@ -20,6 +20,15 @@ import java.awt.image.BufferedImage;
import java.util.Iterator;
import java.util.NoSuchElementException;
+/**
+ * A typical Java object from a parsed heap dump.
+ * Note that this is used for Java objects that are instances of classes (as
+ * opposed to arrays), not for class objects themselves.
+ * See {@link AhatClassObj } for the representation of class objects.
+ * <p>
+ * This class provides a method for iterating over the instance fields of the
+ * object in addition to those methods inherited from {@link AhatInstance}.
+ */
public class AhatClassInstance extends AhatInstance {
// Instance fields of the object. These are stored in order of the instance
// field descriptors from the class object, starting with this class first,
@@ -84,6 +93,10 @@ public class AhatClassInstance extends AhatInstance {
/**
* Returns the list of class instance fields for this instance.
+ * Includes values of field inherited from the superclass of this instance.
+ * The fields are returned in no particular order.
+ *
+ * @return Iterable over the instance field values.
*/
public Iterable<FieldValue> getInstanceFields() {
return new InstanceFieldIterator(mFields, getClassObj());
@@ -220,7 +233,7 @@ public class AhatClassInstance extends AhatInstance {
}
- public BufferedImage asBitmap() {
+ @Override public BufferedImage asBitmap() {
BitmapInfo info = getBitmapInfo();
if (info == null) {
return null;
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java
index 3babf76842..36ada2857c 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java
@@ -20,6 +20,13 @@ import java.util.AbstractList;
import java.util.Arrays;
import java.util.List;
+/**
+ * A class from a parsed heap dump.
+ * In addition to those methods inherited from {@link AhatInstance}, the class
+ * provides methods for accessing information about the class object, such as
+ * the class loader, superclass, static field values and instance field
+ * descriptors.
+ */
public class AhatClassObj extends AhatInstance {
private String mClassName;
private AhatClassObj mSuperClassObj;
@@ -56,6 +63,9 @@ public class AhatClassObj extends AhatInstance {
/**
* Returns the name of the class this is a class object for.
+ * For example, "java.lang.String".
+ *
+ * @return the name of the class
*/
public String getName() {
return mClassName;
@@ -63,6 +73,8 @@ public class AhatClassObj extends AhatInstance {
/**
* Returns the superclass of this class object.
+ *
+ * @return the superclass object
*/
public AhatClassObj getSuperClassObj() {
return mSuperClassObj;
@@ -70,14 +82,18 @@ public class AhatClassObj extends AhatInstance {
/**
* Returns the class loader of this class object.
+ *
+ * @return the class loader object
*/
public AhatInstance getClassLoader() {
return mClassLoader;
}
/**
- * Returns the size of instances of this object, as reported in the heap
- * dump.
+ * Returns the size of instances of this object.
+ * The size returned is as reported in the heap dump.
+ *
+ * @return the class instance size
*/
public long getInstanceSize() {
return mInstanceSize;
@@ -85,6 +101,8 @@ public class AhatClassObj extends AhatInstance {
/**
* Returns the static field values for this class object.
+ *
+ * @return the static field values
*/
public List<FieldValue> getStaticFieldValues() {
return Arrays.asList(mStaticFieldValues);
@@ -92,6 +110,9 @@ public class AhatClassObj extends AhatInstance {
/**
* Returns the fields of instances of this class.
+ * Does not include fields from the super class of this class.
+ *
+ * @return the instance fields
*/
public Field[] getInstanceFields() {
return mInstanceFields;
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatHeap.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatHeap.java
index b8897a182c..60c9a0d086 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatHeap.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatHeap.java
@@ -16,6 +16,13 @@
package com.android.ahat.heapdump;
+/**
+ * Used to identify and access basic information about a particular
+ * heap from the heap dump. Standard Java heap dumps have a single heap,
+ * called the "default" heap. Android heap dumps distinguish among "zygote",
+ * "image", and "app" heaps. There will be a single instance of AhatHeap for
+ * each different heap in the heap dump.
+ */
public class AhatHeap implements Diffable<AhatHeap> {
private String mName;
private Size mSize = Size.ZERO;
@@ -61,6 +68,9 @@ public class AhatHeap implements Diffable<AhatHeap> {
/**
* Returns the name of this heap.
+ * For example, "default", "app", "image", or "zygote".
+ *
+ * @return The name of the heap.
*/
public String getName() {
return mName;
@@ -68,6 +78,8 @@ public class AhatHeap implements Diffable<AhatHeap> {
/**
* Returns the total number of bytes allocated on this heap.
+ *
+ * @return the total number of bytes allocated on this heap.
*/
public Size getSize() {
return mSize;
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
index a9f819f710..67253bf0e7 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
@@ -26,6 +26,11 @@ import java.util.Deque;
import java.util.List;
import java.util.Queue;
+/**
+ * A Java instance from a parsed heap dump. It is the base class used for all
+ * kinds of Java instances, including normal Java objects, class objects, and
+ * arrays.
+ */
public abstract class AhatInstance implements Diffable<AhatInstance>,
DominatorsComputation.Node {
// The id of this instance from the heap dump.
@@ -80,14 +85,20 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Returns a unique identifier for the instance.
+ * Returns a unique identifier for this instance.
+ *
+ * @return id of the instance
*/
public long getId() {
return mId;
}
/**
- * Returns the shallow number of bytes this object takes up.
+ * Returns the number of bytes used for this object in the heap.
+ * The returned size is a shallow size for the object that does not include
+ * sizes of other objects dominated by this object.
+ *
+ * @return the shallow size of the object
*/
public Size getSize() {
return new Size(mClassObj.getInstanceSize() + getExtraJavaSize(), mRegisteredNativeSize);
@@ -104,8 +115,13 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
abstract long getExtraJavaSize();
/**
- * Returns the number of bytes belonging to the given heap that this instance
- * retains.
+ * Returns the number of bytes retained by this object in the given heap.
+ * The returned size includes the shallow size of this object and the size
+ * of all objects directly or indirectly retained by this object. Only those
+ * objects allocated on the given heap are included in the reported size.
+ *
+ * @param heap the heap to get the retained size for
+ * @return the retained size of the object
*/
public Size getRetainedSize(AhatHeap heap) {
int index = heap.getIndex();
@@ -116,7 +132,11 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Returns the total number of bytes this instance retains.
+ * Returns the total number of bytes retained by this object. The returned
+ * size includes the shallow size of this object and the size of all objects
+ * directly or indirectly retained by this object.
+ *
+ * @return the total retained size of the object
*/
public Size getTotalRetainedSize() {
Size size = Size.ZERO;
@@ -136,7 +156,11 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Returns true if this object is strongly-reachable.
+ * Returns true if this object is strongly reachable. An object is strongly
+ * reachable if there exists a path of (strong) references from some root
+ * object to this object.
+ *
+ * @return true if the object is strongly reachable
*/
public boolean isStronglyReachable() {
return mImmediateDominator != null;
@@ -144,14 +168,28 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
/**
* Returns true if this object is reachable only through a
- * soft/weak/phantom/finalizer reference.
+ * soft/weak/phantom/finalizer reference. An object is weakly reachable if
+ * it is not strongly reachable but there still exists a path of references
+ * from some root object to this object. Because the object is not strongly
+ * reachable, any such path must contain a SoftReference, WeakReference,
+ * PhantomReference, or FinalizerReference somewhere along it.
+ * <p>
+ * Unlike a strongly reachable object, a weakly reachable object is allowed
+ * to be garbage collected.
+ *
+ * @return true if the object is weakly reachable
*/
public boolean isWeaklyReachable() {
return !isStronglyReachable() && mNextInstanceToGcRoot != null;
}
/**
- * Returns true if this object is completely unreachable.
+ * Returns true if this object is completely unreachable. An object is
+ * completely unreachable if there is no path to the object from some root
+ * object, neither through strong nor soft/weak/phantom/finalizer
+ * references.
+ *
+ * @return true if the object is completely unreachable
*/
public boolean isUnreachable() {
return !isStronglyReachable() && !isWeaklyReachable();
@@ -159,6 +197,8 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
/**
* Returns the heap that this instance is allocated on.
+ *
+ * @return heap the instance is allocated on
*/
public AhatHeap getHeap() {
return mHeap;
@@ -171,7 +211,10 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
abstract Iterable<Reference> getReferences();
/**
- * Returns true if this instance is marked as a root instance.
+ * Returns true if this instance is a GC root.
+ *
+ * @return true if this instance is a GC root.
+ * @see getRootTypes
*/
public boolean isRoot() {
return mRootTypes != 0;
@@ -187,6 +230,8 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
/**
* Returns a list of the root types of this object.
* Returns null if this object is not a root.
+ *
+ * @return list of the objects root types
*/
public Collection<RootType> getRootTypes() {
if (!isRoot()) {
@@ -205,14 +250,17 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
/**
* Returns the immediate dominator of this instance.
* Returns null if this is a root instance.
+ *
+ * @return the immediate dominator of this instance
*/
public AhatInstance getImmediateDominator() {
return mImmediateDominator;
}
/**
- * Returns a list of those objects immediately dominated by the given
- * instance.
+ * Returns a list of objects immediately dominated by this instance.
+ *
+ * @return list of immediately dominated objects
*/
public List<AhatInstance> getDominated() {
return mDominated;
@@ -220,13 +268,17 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
/**
* Returns the site where this instance was allocated.
+ *
+ * @return the object's allocation site
*/
public Site getSite() {
return mSite;
}
/**
- * Returns true if the given instance is a class object
+ * Returns true if this instance is a class object
+ *
+ * @return true if this instance is a class object
*/
public boolean isClassObj() {
// Overridden by AhatClassObj.
@@ -236,6 +288,8 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
/**
* Returns this as an AhatClassObj if this is an AhatClassObj.
* Returns null if this is not an AhatClassObj.
+ *
+ * @return this instance as a class object
*/
public AhatClassObj asClassObj() {
// Overridden by AhatClassObj.
@@ -243,7 +297,11 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Returns the class object instance for the class of this object.
+ * Returns the class object for this instance.
+ * For example, if this object is an instance of java.lang.String, this
+ * method returns the AhatClassObj for java.lang.String.
+ *
+ * @return the instance's class object
*/
public AhatClassObj getClassObj() {
return mClassObj;
@@ -251,6 +309,10 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
/**
* Returns the name of the class this object belongs to.
+ * For example, if this object is an instance of java.lang.String, returns
+ * "java.lang.String".
+ *
+ * @return the name of this instance's class
*/
public String getClassName() {
AhatClassObj classObj = getClassObj();
@@ -258,7 +320,9 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Returns true if the given instance is an array instance
+ * Returns true if the given instance is an array instance.
+ *
+ * @return true if the given instance is an array instance
*/
public boolean isArrayInstance() {
// Overridden by AhatArrayInstance.
@@ -268,6 +332,8 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
/**
* Returns this as an AhatArrayInstance if this is an AhatArrayInstance.
* Returns null if this is not an AhatArrayInstance.
+ *
+ * @return this instance as an array instance
*/
public AhatArrayInstance asArrayInstance() {
// Overridden by AhatArrayInstance.
@@ -275,7 +341,9 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Returns true if the given instance is a class instance
+ * Returns true if this instance is a class instance.
+ *
+ * @return true if this instance is a class instance
*/
public boolean isClassInstance() {
return false;
@@ -284,15 +352,20 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
/**
* Returns this as an AhatClassInstance if this is an AhatClassInstance.
* Returns null if this is not an AhatClassInstance.
+ *
+ * @return this instance as a class instance
*/
public AhatClassInstance asClassInstance() {
return null;
}
/**
- * Return the referent associated with this instance.
- * This is relevent for instances of java.lang.ref.Reference.
- * Returns null if the instance has no referent associated with it.
+ * Returns the <code>referent</code> associated with this instance.
+ * This is only relevant for instances of java.lang.ref.Reference or its
+ * subclasses. Returns null if the instance has no referent associated with
+ * it.
+ *
+ * @return the referent associated with this instance
*/
public AhatInstance getReferent() {
// Overridden by AhatClassInstance.
@@ -300,7 +373,9 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Returns a list of objects with hard references to this object.
+ * Returns a list of objects with (strong) references to this object.
+ *
+ * @return the objects referencing this object
*/
public List<AhatInstance> getHardReverseReferences() {
if (mHardReverseReferences != null) {
@@ -310,7 +385,10 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Returns a list of objects with soft references to this object.
+ * Returns a list of objects with soft/weak/phantom/finalizer references to
+ * this object.
+ *
+ * @return the objects weakly referencing this object
*/
public List<AhatInstance> getSoftReverseReferences() {
if (mSoftReverseReferences != null) {
@@ -320,9 +398,12 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Returns the value of a field of an instance.
- * Returns null if the field value is null, the field couldn't be read, or
- * there are multiple fields with the same name.
+ * Returns the value of a field of this instance. Returns null if the field
+ * value is null, the field couldn't be read, or there are multiple fields
+ * with the same name.
+ *
+ * @param fieldName the name of the field to get the value of
+ * @return the field value
*/
public Value getField(String fieldName) {
// Overridden by AhatClassInstance.
@@ -330,8 +411,13 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Reads a reference field of this instance.
- * Returns null if the field value is null, or if the field couldn't be read.
+ * Reads a reference field of this instance. Returns null if the field value
+ * is null, of primitive type, or if the field couldn't be read. There is no
+ * way using this method to distinguish between a reference field with value
+ * <code>null</code> and an invalid field.
+ *
+ * @param fieldName the name of the reference field to get the value of
+ * @return the reference field value
*/
public AhatInstance getRefField(String fieldName) {
// Overridden by AhatClassInstance.
@@ -339,30 +425,41 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Assuming inst represents a DexCache object, return the dex location for
- * that dex cache. Returns null if the given instance doesn't represent a
- * DexCache object or the location could not be found.
+ * Returns the dex location associated with this object. Only applies to
+ * instances of dalvik.system.DexCache. If this is an instance of DexCache,
+ * returns the dex location for that dex cache. Otherwise returns null.
* If maxChars is non-negative, the returned location is truncated to
* maxChars in length.
+ *
+ * @param maxChars the maximum length of the returned string
+ * @return the dex location associated with this object
*/
public String getDexCacheLocation(int maxChars) {
return null;
}
/**
- * Return the bitmap instance associated with this object, or null if there
- * is none. This works for android.graphics.Bitmap instances and their
- * underlying Byte[] instances.
+ * Returns the android.graphics.Bitmap instance associated with this object.
+ * Instances of android.graphics.Bitmap return themselves. If this is a
+ * byte[] array containing pixel data for an instance of
+ * android.graphics.Bitmap, that instance of android.graphics.Bitmap is
+ * returned. Otherwise null is returned.
+ *
+ * @return the bitmap instance associated with this object
*/
public AhatInstance getAssociatedBitmapInstance() {
return null;
}
/**
- * Read the string value from this instance.
- * Returns null if this object can't be interpreted as a string.
- * The returned string is truncated to maxChars characters.
- * If maxChars is negative, the returned string is not truncated.
+ * Returns the (bounded-length) string associated with this instance.
+ * Applies to instances of java.lang.String, char[], and in some cases
+ * byte[]. Returns null if this object cannot be interpreted as a string.
+ * If maxChars is non-negative, the returned string is truncated to maxChars
+ * characters in length.
+ *
+ * @param maxChars the maximum length of the returned string
+ * @return the string associated with this instance
*/
public String asString(int maxChars) {
// By default instances can't be interpreted as a string. This method is
@@ -372,17 +469,23 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Reads the string value from an hprof Instance.
- * Returns null if the object can't be interpreted as a string.
+ * Returns the string associated with this instance. Applies to instances of
+ * java.lang.String, char[], and in some cases byte[]. Returns null if this
+ * object cannot be interpreted as a string.
+ *
+ * @return the string associated with this instance
*/
public String asString() {
return asString(-1);
}
/**
- * Return the bitmap associated with the given instance, if any.
+ * Returns the bitmap pixel data associated with this instance.
* This is relevant for instances of android.graphics.Bitmap and byte[].
- * Returns null if there is no bitmap associated with the given instance.
+ * Returns null if there is no bitmap pixel data associated with the given
+ * instance.
+ *
+ * @return the bitmap pixel data associated with this image
*/
public BufferedImage asBitmap() {
return null;
@@ -402,11 +505,23 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
}
/**
- * Returns a sample path from a GC root to this instance.
- * This instance is included as the last element of the path with an empty
- * field description.
+ * Returns a sample path from a GC root to this instance. The first element
+ * of the returned path is a GC root object. This instance is included as
+ * the last element of the path with an empty field description.
+ * <p>
+ * If the instance is strongly reachable, a path of string references will
+ * be returned. If the instance is weakly reachable, the returned path will
+ * include a soft/weak/phantom/finalizer reference somewhere along it.
+ * Returns null if this instance is not reachable.
+ *
+ * @return sample path from a GC root to this instance
+ * @see PathElement
*/
public List<PathElement> getPathFromGcRoot() {
+ if (isUnreachable()) {
+ return null;
+ }
+
List<PathElement> path = new ArrayList<PathElement>();
AhatInstance dom = this;
@@ -434,12 +549,15 @@ public abstract class AhatInstance implements Diffable<AhatInstance>,
return new PathElement(inst.mNextInstanceToGcRoot, inst.mNextInstanceToGcRootField);
}
- /** Returns a human-readable identifier for this object.
+ /**
+ * Returns a human-readable identifier for this object.
* For class objects, the string is the class name.
* For class instances, the string is the class name followed by '@' and the
* hex id of the instance.
* For array instances, the string is the array type followed by the size in
* square brackets, followed by '@' and the hex id of the instance.
+ *
+ * @return human-readable identifier for this object
*/
@Override public abstract String toString();
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java
index 59ce5d1c6c..535db082c1 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java
@@ -19,6 +19,11 @@ package com.android.ahat.heapdump;
import com.android.ahat.dominators.DominatorsComputation;
import java.util.List;
+/**
+ * A parsed heap dump.
+ * It contains methods to access the heaps, allocation sites, roots, classes,
+ * and instances from the parsed heap dump.
+ */
public class AhatSnapshot implements Diffable<AhatSnapshot> {
private final Site mRootSite;
@@ -60,16 +65,24 @@ public class AhatSnapshot implements Diffable<AhatSnapshot> {
}
/**
- * Returns the instance with given id in this snapshot.
+ * Returns the instance with the given id in this snapshot.
+ * Where the id of an instance x is x.getId().
* Returns null if no instance with the given id is found.
+ *
+ * @param id the id of the instance to find
+ * @return the instance with the given id
*/
public AhatInstance findInstance(long id) {
return mInstances.get(id);
}
/**
- * Returns the AhatClassObj with given id in this snapshot.
+ * Returns the AhatClassObj with the given id in this snapshot.
+ * Where the id of a class object x is x.getId().
* Returns null if no class object with the given id is found.
+ *
+ * @param id the id of the class object to find
+ * @return the class object with the given id
*/
public AhatClassObj findClassObj(long id) {
AhatInstance inst = findInstance(id);
@@ -77,8 +90,12 @@ public class AhatSnapshot implements Diffable<AhatSnapshot> {
}
/**
- * Returns the heap with the given name, if any.
+ * Returns the heap with the given name.
+ * Where the name of a heap x is x.getName().
* Returns null if no heap with the given name could be found.
+ *
+ * @param name the name of the heap to get
+ * @return the heap with the given name
*/
public AhatHeap getHeap(String name) {
// We expect a small number of heaps (maybe 3 or 4 total), so a linear
@@ -93,30 +110,45 @@ public class AhatSnapshot implements Diffable<AhatSnapshot> {
/**
* Returns a list of heaps in the snapshot in canonical order.
- * Modifications to the returned list are visible to this AhatSnapshot,
- * which is used by diff to insert place holder heaps.
+ * <p>
+ * Note: modifications to the returned list are visible to this
+ * AhatSnapshot, which is used by diff to insert place holder heaps.
+ *
+ * @return list of heaps
*/
public List<AhatHeap> getHeaps() {
return mHeaps;
}
/**
- * Returns a collection of instances whose immediate dominator is the
- * SENTINEL_ROOT.
+ * Returns a collection of "rooted" instances.
+ * An instance is "rooted" if it is a GC root, or if it is retained by more
+ * than one GC root. These are reachable instances that are not immediately
+ * dominated by any other instance in the heap.
+ *
+ * @return collection of rooted instances
*/
public List<AhatInstance> getRooted() {
return mSuperRoot.getDominated();
}
/**
- * Returns the root site for this snapshot.
+ * Returns the root allocation site for this snapshot.
+ *
+ * @return the root allocation site
*/
public Site getRootSite() {
return mRootSite;
}
- // Get the site associated with the given id.
- // Returns the root site if no such site found.
+ /**
+ * Returns the site associated with the given id.
+ * Where the id of a site x is x.getId().
+ * Returns the root site if no site with the given id is found.
+ *
+ * @param id the id of the site to get
+ * @return the site with the given id
+ */
public Site getSite(long id) {
Site site = mRootSite.findSite(id);
return site == null ? mRootSite : site;
@@ -127,8 +159,10 @@ public class AhatSnapshot implements Diffable<AhatSnapshot> {
}
/**
- * Returns true if this snapshot has been diffed against another, different
+ * Returns true if this snapshot has been diffed against a different
* snapshot.
+ *
+ * @return true if the snapshot has been diffed
*/
public boolean isDiffed() {
return mBaseline != this;
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Diff.java b/tools/ahat/src/main/com/android/ahat/heapdump/Diff.java
index 98c7e58d56..b35b4244ae 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Diff.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Diff.java
@@ -25,9 +25,15 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
+/**
+ * Provides a static method to diff two heap dumps.
+ */
public class Diff {
+ private Diff() {
+ }
+
/**
- * Perform a diff between two heap lists.
+ * Performs a diff between two heap lists.
*
* Heaps are diffed based on heap name. PlaceHolder heaps will be added to
* the given lists as necessary so that every heap in A has a corresponding
@@ -312,8 +318,16 @@ public class Diff {
}
/**
- * Perform a diff of the two snapshots, setting each as the baseline for the
- * other.
+ * Performs a diff of two snapshots.
+ * Each snapshot will be set as the baseline for the other snapshot.
+ * <p>
+ * The diff algorithm attempts to match instances in snapshot <code>a</code>
+ * to corresponding instances in snapshot <code>b</code>. The snapshots need
+ * not come from the same running process, application version, or platform
+ * version.
+ *
+ * @param a one of the snapshots to diff
+ * @param b the other of the snapshots to diff
*/
public static void snapshots(AhatSnapshot a, AhatSnapshot b) {
a.setBaseline(b);
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/DiffFields.java b/tools/ahat/src/main/com/android/ahat/heapdump/DiffFields.java
index e3c671fe21..ff07af0028 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/DiffFields.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/DiffFields.java
@@ -22,12 +22,16 @@ import java.util.Comparator;
import java.util.List;
/**
- * This class contains a routine for diffing two collections of static or
- * instance fields.
+ * Provides a routine for diffing two collections of static or instance
+ * fields.
*/
public class DiffFields {
/**
- * Return the result of diffing two collections of field values.
+ * Returns the result of diffing two collections of field values.
+ *
+ * @param current a list of fields in the current heap dump
+ * @param baseline a list of fields in the baseline heap dump
+ * @return list of diffed fields
*/
public static List<DiffedFieldValue> diff(Iterable<FieldValue> current,
Iterable<FieldValue> baseline) {
@@ -85,5 +89,5 @@ public class DiffFields {
* by field name and type.
*/
private static final Comparator<FieldValue> FOR_DIFF
- = new Sort.WithPriority(Sort.FIELD_VALUE_BY_NAME, Sort.FIELD_VALUE_BY_TYPE);
+ = Sort.withPriority(Sort.FIELD_VALUE_BY_NAME, Sort.FIELD_VALUE_BY_TYPE);
}
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Diffable.java b/tools/ahat/src/main/com/android/ahat/heapdump/Diffable.java
index 53442c857e..09c8ee6d39 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Diffable.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Diffable.java
@@ -17,12 +17,19 @@
package com.android.ahat.heapdump;
/**
- * An interface for objects that have corresponding objects in a baseline heap
- * dump.
+ * An interface for instances/sites/heaps/etc in a heap dump that can be
+ * related to corresponding instances/sites/heaps/etc in a second heap dump
+ * when the two heap dumps have been diffed.
*/
public interface Diffable<T> {
/**
- * Return the baseline object that corresponds to this one.
+ * Returns the object in the other heap dump that corresponds to this object.
+ * When two heap dumps are diffed, diffable objects from the first heap dump
+ * will be matched to "baseline" objects from the second heap dump, and
+ * diffable objects from the second heap dump will be matched to "baseline"
+ * objects from the first heap dump.
+ *
+ * @return the matched object from the other heap dump
*/
T getBaseline();
@@ -32,6 +39,8 @@ public interface Diffable<T> {
* baseline heap dump that is not in this heap dump. In that case, we create
* a dummy place holder object in this heap dump as an indicator of the
* object removed from the baseline heap dump.
+ *
+ * @return true if the object is a placeholder
*/
boolean isPlaceHolder();
}
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/DiffedFieldValue.java b/tools/ahat/src/main/com/android/ahat/heapdump/DiffedFieldValue.java
index 3cd273ed98..8de337ea8c 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/DiffedFieldValue.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/DiffedFieldValue.java
@@ -18,25 +18,65 @@ package com.android.ahat.heapdump;
import java.util.Objects;
-/** DiffedFieldValue is used by the DiffedField class to return the result of
- * diffing two collections of fields.
+/**
+ * Used by the DiffedField class to return the result of diffing two
+ * collections of fields.
*/
public class DiffedFieldValue {
+ /**
+ * The name of the field.
+ */
public final String name;
+
+ /**
+ * The type of the field.
+ */
public final Type type;
+
+ /**
+ * The value of the field in the current heap dump.
+ */
public final Value current;
+
+ /**
+ * The value of the field in the baseline heap dump.
+ */
public final Value baseline;
+ /**
+ * Whether the field was added to, deleted from, or matched with a field in
+ * the baseline heap dump.
+ */
public final Status status;
+ /**
+ * A status enum to indicate whether a field was added to, deleted from, or
+ * matched with a field in the baseline heap dump.
+ */
public static enum Status {
- ADDED, // The current field has no matching baseline value.
- MATCHED, // The current field has a matching baseline value.
- DELETED // The baseline field has no matching current value.
+ /**
+ * The field exists in the current heap dump but not the baseline.
+ */
+ ADDED,
+
+ /**
+ * The field exists in both the current and baseline heap dumps.
+ */
+ MATCHED,
+
+ /**
+ * The field exists in the baseline heap dump but not the current.
+ */
+ DELETED
};
/**
- * Return a DiffedFieldValue where there is both a current and baseline.
+ * Constructs a DiffedFieldValue where there are both current and baseline
+ * fields.
+ *
+ * @param current the current field
+ * @param baseline the baseline field
+ * @return the constructed DiffedFieldValue
*/
public static DiffedFieldValue matched(FieldValue current, FieldValue baseline) {
return new DiffedFieldValue(current.name,
@@ -47,14 +87,20 @@ public class DiffedFieldValue {
}
/**
- * Return a DiffedFieldValue where there is no baseline.
+ * Constructs a DiffedFieldValue where there is no baseline field.
+ *
+ * @param current the current field
+ * @return the constructed DiffedFieldValue
*/
public static DiffedFieldValue added(FieldValue current) {
return new DiffedFieldValue(current.name, current.type, current.value, null, Status.ADDED);
}
/**
- * Return a DiffedFieldValue where there is no current.
+ * Constructs a DiffedFieldValue where there is no current field.
+ *
+ * @param baseline the baseline field
+ * @return the constructed DiffedFieldValue
*/
public static DiffedFieldValue deleted(FieldValue baseline) {
return new DiffedFieldValue(baseline.name, baseline.type, null, baseline.value, Status.DELETED);
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Field.java b/tools/ahat/src/main/com/android/ahat/heapdump/Field.java
index dff401796a..6494069dcb 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Field.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Field.java
@@ -16,10 +16,26 @@
package com.android.ahat.heapdump;
+/**
+ * A description of a field from a heap dump.
+ */
public class Field {
+ /**
+ * The name of the field.
+ */
public final String name;
+
+ /**
+ * The type of the field.
+ */
public final Type type;
+ /**
+ * Constructs a Field instance.
+ *
+ * @param name name of the field
+ * @param type type of the field
+ */
public Field(String name, Type type) {
this.name = name;
this.type = type;
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/FieldValue.java b/tools/ahat/src/main/com/android/ahat/heapdump/FieldValue.java
index 20e6da7271..70314da830 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/FieldValue.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/FieldValue.java
@@ -16,11 +16,32 @@
package com.android.ahat.heapdump;
+/**
+ * A description and value of a field from a heap dump.
+ */
public class FieldValue {
+ /**
+ * The name of the field.
+ */
public final String name;
+
+ /**
+ * The type of the field.
+ */
public final Type type;
+
+ /**
+ * The value of the field.
+ */
public final Value value;
+ /**
+ * Constructs an instance of FieldValue.
+ *
+ * @param name name of the field
+ * @param type type of the field
+ * @param value value of the field
+ */
public FieldValue(String name, Type type, Value value) {
this.name = name;
this.type = type;
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/HprofFormatException.java b/tools/ahat/src/main/com/android/ahat/heapdump/HprofFormatException.java
index 256a3b46f6..29ac9b0c5a 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/HprofFormatException.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/HprofFormatException.java
@@ -16,6 +16,10 @@
package com.android.ahat.heapdump;
+/**
+ * Exception thrown when the heap dump parser detects an improperly formatted
+ * heap dump file.
+ */
public class HprofFormatException extends Exception {
HprofFormatException(String msg) {
super(msg);
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java b/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java
index 3bed29bafc..13be57d415 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java
@@ -31,21 +31,43 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
+/**
+ * Provides methods for parsing heap dumps.
+ */
public class Parser {
private static final int ID_SIZE = 4;
+ private Parser() {
+ }
+
/**
- * Parse the given heap dump using the given proguard map for deobfuscation.
- * We make the following assumptions about valid heap dumps:
- * Class serial numbers, stack frames, and stack traces
- * individually satisfy the following:
- * - all elements are defined before they are referenced.
- * - ids are densely packed in some range [a, b] where a is not
- * necessarily 0.
- * - there are not more than 2^31 elements defined.
- * All classes are defined via a LOAD CLASS record before the first heap
- * dump segment.
- * The ID size used in the heap dump is 4 bytes.
+ * Parses a heap dump from a File.
+ * <p>
+ * The heap dump should be a heap dump in the J2SE HPROF format optionally
+ * with Android extensions and satisfying the following additional
+ * constraints:
+ * <ul>
+ * <li>
+ * Class serial numbers, stack frames, and stack traces individually satisfy
+ * the following:
+ * <ul>
+ * <li> All elements are defined before they are referenced.
+ * <li> Ids are densely packed in some range [a, b] where a is not necessarily 0.
+ * <li> There are not more than 2^31 elements defined.
+ * </ul>
+ * <li> All classes are defined via a LOAD CLASS record before the first
+ * heap dump segment.
+ * <li> The ID size used in the heap dump is 4 bytes.
+ * </ul>
+ * <p>
+ * The given proguard map will be used to deobfuscate class names, field
+ * names, and stack traces in the heap dump.
+ *
+ * @param hprof the hprof file to parse
+ * @param map the proguard map for deobfuscation
+ * @return the parsed heap dump
+ * @throws IOException if the heap dump could not be read
+ * @throws HprofFormatException if the heap dump is not properly formatted
*/
public static AhatSnapshot parseHeapDump(File hprof, ProguardMap map)
throws IOException, HprofFormatException {
@@ -57,7 +79,33 @@ public class Parser {
}
/**
- * Parse a heap dump from a byte buffer.
+ * Parses a heap dump from a byte buffer.
+ * <p>
+ * The heap dump should be a heap dump in the J2SE HPROF format optionally
+ * with Android extensions and satisfying the following additional
+ * constraints:
+ * <ul>
+ * <li>
+ * Class serial numbers, stack frames, and stack traces individually satisfy
+ * the following:
+ * <ul>
+ * <li> All elements are defined before they are referenced.
+ * <li> Ids are densely packed in some range [a, b] where a is not necessarily 0.
+ * <li> There are not more than 2^31 elements defined.
+ * </ul>
+ * <li> All classes are defined via a LOAD CLASS record before the first
+ * heap dump segment.
+ * <li> The ID size used in the heap dump is 4 bytes.
+ * </ul>
+ * <p>
+ * The given proguard map will be used to deobfuscate class names, field
+ * names, and stack traces in the heap dump.
+ *
+ * @param hprof the bytes of the hprof file to parse
+ * @param map the proguard map for deobfuscation
+ * @return the parsed heap dump
+ * @throws IOException if the heap dump could not be read
+ * @throws HprofFormatException if the heap dump is not properly formatted
*/
public static AhatSnapshot parseHeapDump(ByteBuffer hprof, ProguardMap map)
throws IOException, HprofFormatException {
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/PathElement.java b/tools/ahat/src/main/com/android/ahat/heapdump/PathElement.java
index 196a24628c..5ce0b1edfe 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/PathElement.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/PathElement.java
@@ -16,11 +16,51 @@
package com.android.ahat.heapdump;
+/**
+ * A single element along a reference path from a GC root to an instance in
+ * the heap dump.
+ * <p>
+ * For example, assuming object A is a root a path to some object X might look
+ * like:
+ * <pre>
+ * A.x --&gt; B.y --&gt; C.z --&gt; X
+ * </pre>
+ *
+ * A path element is a single node of that path, such as <code>B.y</code>.
+ * @see AhatInstance#getPathFromGcRoot
+ */
public class PathElement implements Diffable<PathElement> {
+ /**
+ * The instance along the reference path that this PathElement is associated
+ * with.
+ */
public final AhatInstance instance;
+
+ /**
+ * A human readable description of which field in <code>instance</code> is
+ * followed to reach the next element in the path.
+ * Some examples:
+ * <ul>
+ * <li> "mBlah" for a class instance
+ * <li> "[4]" for an array instance
+ * <li> "" for the last element of the path
+ * </ul>
+ */
public final String field;
+
+ /**
+ * True if <code>instance</code> is a (not necessarily immediate) dominator
+ * of the final object in the path.
+ */
public boolean isDominator;
+ /**
+ * Constructs a PathElement object.
+ * <code>isDominator</code> is set to false.
+ *
+ * @param instance the path element instance
+ * @param field the path element field
+ */
public PathElement(AhatInstance instance, String field) {
this.instance = instance;
this.field = field;
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/RootType.java b/tools/ahat/src/main/com/android/ahat/heapdump/RootType.java
index 734f889af6..99d85dc940 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/RootType.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/RootType.java
@@ -16,20 +16,80 @@
package com.android.ahat.heapdump;
+/**
+ * Enumeration representing object root types as defined in the binary heap
+ * dump format specification.
+ */
public enum RootType {
+ /**
+ * There is a JNI Global Reference for the object in question.
+ */
JNI_GLOBAL (1 << 0),
+
+ /**
+ * There is a JNI Local Reference for the object in question.
+ */
JNI_LOCAL (1 << 1),
+
+ /**
+ * The object in question is a parameter or local variable of a running
+ * method.
+ */
JAVA_FRAME (1 << 2),
+
+ /**
+ * The object in question is a parameter of a running JNI method.
+ */
NATIVE_STACK (1 << 3),
+
+ /**
+ * The object is a class object that cannot be unloaded.
+ */
STICKY_CLASS (1 << 4),
+
+ /**
+ * The object is referenced from an active thread block.
+ */
THREAD_BLOCK (1 << 5),
+
+ /**
+ * The object's monitor is currently in use.
+ */
MONITOR (1 << 6),
+
+ /**
+ * The object is a running thread.
+ */
THREAD (1 << 7),
+
+ /**
+ * The object is an interned string.
+ */
INTERNED_STRING (1 << 8),
+
+ /**
+ * The object is being used by the debugger.
+ */
DEBUGGER (1 << 9),
+
+ /**
+ * The object is being used by the VM internally.
+ */
VM_INTERNAL (1 << 10),
+
+ /**
+ * The object has no given reason for being considered a root.
+ */
UNKNOWN (1 << 11),
+
+ /**
+ * The object's monitor is currently in use from JNI.
+ */
JNI_MONITOR (1 << 12),
+
+ /**
+ * The object is waiting to be finalized.
+ */
FINALIZING (1 << 13);
final int mask;
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Site.java b/tools/ahat/src/main/com/android/ahat/heapdump/Site.java
index 4978d52830..72c0a4a750 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Site.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Site.java
@@ -24,6 +24,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+/**
+ * Used to collection information about objects allocated at a particular
+ * allocation site.
+ */
public class Site implements Diffable<Site> {
// The site that this site was directly called from.
// mParent is null for the root site.
@@ -61,18 +65,39 @@ public class Site implements Diffable<Site> {
private Site mBaseline;
+ /**
+ * Summary information about instances allocated at a particular allocation
+ * site that are instances of a particular class and allocated on a
+ * particular heap.
+ */
public static class ObjectsInfo implements Diffable<ObjectsInfo> {
+ /**
+ * The heap that the summarized objects belong to.
+ */
public AhatHeap heap;
- public AhatClassObj classObj; // May be null.
+
+ /**
+ * The class of the summarized objects.
+ */
+ public AhatClassObj classObj; // May be null. Not sure why.
+
+ /**
+ * The number of instances included in the summary.
+ */
public long numInstances;
+
+ /**
+ * The sum of the shallow size of each instance included in the summary.
+ */
public Size numBytes;
+
private ObjectsInfo baseline;
/**
- * Construct a new, empty objects info for the given heap and class
+ * Constructs a new, empty objects info for the given heap and class
* combination.
*/
- public ObjectsInfo(AhatHeap heap, AhatClassObj classObj) {
+ ObjectsInfo(AhatHeap heap, AhatClassObj classObj) {
this.heap = heap;
this.classObj = classObj;
this.numInstances = 0;
@@ -82,12 +107,14 @@ public class Site implements Diffable<Site> {
/**
* Returns the name of the class this ObjectsInfo is associated with.
+ *
+ * @return the name of this object info's class
*/
public String getClassName() {
return classObj == null ? "???" : classObj.getName();
}
- public void setBaseline(ObjectsInfo baseline) {
+ void setBaseline(ObjectsInfo baseline) {
this.baseline = baseline;
}
@@ -121,11 +148,11 @@ public class Site implements Diffable<Site> {
}
/**
- * Get a child site of this site.
- * Returns the site at which the instance was allocated.
- * @param frames - The list of frames in the stack trace, starting with the
- * inner-most frame. May be null, in which case this site is
- * returned.
+ * Gets a child site of this site.
+ * @param frames the list of frames in the stack trace, starting with the
+ * inner-most frame. May be null, in which case this site is
+ * returned.
+ * @return the child site
*/
Site getSite(ProguardMap.Frame[] frames) {
return frames == null ? this : getSite(this, frames);
@@ -211,22 +238,29 @@ public class Site implements Diffable<Site> {
return id;
}
- // Get the size of a site for a specific heap.
+ /**
+ * Returns the size of all objects on the given heap allocated at this site.
+ * Includes objects belonging to <code>heap</code> allocated at this and
+ * child sites.
+ *
+ * @param heap the heap to query the size for
+ * @return the total shallow size of objects in this site
+ */
public Size getSize(AhatHeap heap) {
return mSizesByHeap[heap.getIndex()];
}
/**
- * Collect the objects allocated under this site, optionally filtered by
+ * Collects the objects allocated under this site, optionally filtered by
* heap name or class name. Includes objects allocated in children sites.
- * @param heapName - The name of the heap the collected objects should
- * belong to. This may be null to indicate objects of
- * every heap should be collected.
- * @param className - The name of the class the collected objects should
- * belong to. This may be null to indicate objects of
- * every class should be collected.
- * @param objects - Out parameter. A collection of objects that all
- * collected objects should be added to.
+ * @param heapName the name of the heap the collected objects should
+ * belong to. This may be null to indicate objects of
+ * every heap should be collected.
+ * @param className the name of the class the collected objects should
+ * belong to. This may be null to indicate objects of
+ * every class should be collected.
+ * @param objects out parameter. A collection of objects that all
+ * collected objects should be added to.
*/
public void getObjects(String heapName, String className, Collection<AhatInstance> objects) {
for (AhatInstance inst : mObjects) {
@@ -263,11 +297,24 @@ public class Site implements Diffable<Site> {
return info;
}
+ /**
+ * Return a summary breakdown of the objects allocated at this site.
+ * Objects are grouped by class and heap and summarized into a single
+ * {@link ObjectsInfo}. This method returns all the groups for this
+ * allocation site.
+ *
+ * @return all ObjectInfo summaries for instances allocated at this site
+ */
public List<ObjectsInfo> getObjectsInfos() {
return mObjectsInfos;
}
- // Get the combined size of the site for all heaps.
+ /**
+ * Returns the combined size of the site for all heaps.
+ * Includes all objects allocated at this and child sites.
+ *
+ * @return total shallow size of objects in this site
+ */
public Size getTotalSize() {
Size total = Size.ZERO;
for (Size size : mSizesByHeap) {
@@ -277,39 +324,70 @@ public class Site implements Diffable<Site> {
}
/**
- * Return the site this site was called from.
+ * Returns the site this site was called from.
* Returns null for the root site.
+ *
+ * @return the site this site was called from
*/
public Site getParent() {
return mParent;
}
+ /**
+ * Returns the name of the method this allocation site belongs to.
+ * For example, "equals".
+ *
+ * @return the method name of the allocation site
+ */
public String getMethodName() {
return mMethodName;
}
+ /**
+ * Returns the signature of the method this allocation site belongs to.
+ * For example, "(Ljava/lang/Object;)Z".
+ *
+ * @return the signature of method the allocation site belongs to
+ */
public String getSignature() {
return mSignature;
}
+ /**
+ * Returns the name of the Java file where this allocation site is found.
+ *
+ * @return the file the allocation site belongs to
+ */
public String getFilename() {
return mFilename;
}
+ /**
+ * Returns the line number of the code in the source file that the
+ * allocation site refers to.
+ *
+ * @return the allocation site line number
+ */
public int getLineNumber() {
return mLineNumber;
}
/**
* Returns the unique id of this site.
+ * This is an arbitrary unique id computed after processing the heap dump.
+ *
+ * @return the site id
*/
public long getId() {
return mId;
}
/**
- * Find the child site with the given id.
+ * Returns the child site with the given id.
* Returns null if no such site was found.
+ *
+ * @param id the id of the child site to find
+ * @return the found child site
*/
public Site findSite(long id) {
if (id == mId) {
@@ -341,6 +419,8 @@ public class Site implements Diffable<Site> {
/**
* Returns an unmodifiable list of this site's immediate children.
+ *
+ * @return this site's child sites
*/
public List<Site> getChildren() {
return Collections.unmodifiableList(mChildren);
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Size.java b/tools/ahat/src/main/com/android/ahat/heapdump/Size.java
index 7c8db900df..a4593e195b 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Size.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Size.java
@@ -17,47 +17,76 @@
package com.android.ahat.heapdump;
/**
- * The Size class is used to represent how much space an instance takes up.
- *
+ * Used to represent how much space an instance takes up.
* An abstraction is introduced rather than using a long directly in order to
* more easily keep track of the different components of the size. For
* example, some instances may have associated native, code, or graphics
* sizes.
- *
+ * <p>
* Size objects are immutable.
*/
public class Size {
private final long mJavaSize;
private final long mRegisteredNativeSize;
+ /**
+ * An instance of Size with 0 for all categories.
+ */
public static Size ZERO = new Size(0, 0);
+ /**
+ * Constructs a new instance of Size.
+ *
+ * @param javaSize number of bytes in the java category
+ * @param registeredNativeSize number of bytes in the registeredNativeSize
+ * category
+ */
public Size(long javaSize, long registeredNativeSize) {
mJavaSize = javaSize;
mRegisteredNativeSize = registeredNativeSize;
}
+ /**
+ * Returns the sum of the size of all categories.
+ *
+ * @return the total size
+ */
public long getSize() {
return mJavaSize + mRegisteredNativeSize;
}
+ /**
+ * Returns the size of the java category.
+ *
+ * @return the java category size
+ */
public long getJavaSize() {
return mJavaSize;
}
+ /**
+ * Returns the size of the registered native category.
+ *
+ * @return the registered native category size
+ */
public long getRegisteredNativeSize() {
return mRegisteredNativeSize;
}
/**
- * Returns true if all the fields of this size object are zero.
+ * Returns true if all categories of this size are zero.
+ *
+ * @return true if the size is zero
*/
public boolean isZero() {
return mJavaSize == 0 && mRegisteredNativeSize == 0;
}
/**
- * Return a new Size object that is the sum of this size and the other.
+ * Returns a new Size object that is the sum of this size and the other.
+ *
+ * @param other the size to sum with this size
+ * @return the new size object
*/
public Size plus(Size other) {
if (isZero()) {
@@ -71,8 +100,11 @@ public class Size {
}
/**
- * Return a new Size object that has 'size' more registered native size than
- * this Size object.
+ * Returns a new Size object that has <code>size</code> more registered
+ * native size than this Size object.
+ *
+ * @param size the size to add to the registered native category
+ * @return the new size object
*/
public Size plusRegisteredNativeSize(long size) {
return new Size(mJavaSize, mRegisteredNativeSize + size);
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Sort.java b/tools/ahat/src/main/com/android/ahat/heapdump/Sort.java
index efe0d6b59b..a629b3ce7f 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Sort.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Sort.java
@@ -25,14 +25,14 @@ import java.util.List;
/**
* Provides Comparators and helper functions for sorting Instances, Sites, and
* other things.
- *
+ * <p>
* Note: The Comparators defined here impose orderings that are inconsistent
* with equals. They should not be used for element lookup or search. They
* should only be used for showing elements to the user in different orders.
*/
public class Sort {
/**
- * Compare sizes by their total size.
+ * Compares sizes by their total size.
* This sorts sizes from smaller total size to larger total size.
*/
public static final Comparator<Size> SIZE_BY_SIZE = new Comparator<Size>() {
@@ -43,7 +43,7 @@ public class Sort {
};
/**
- * Compare instances by their total retained size.
+ * Compares instances by their total retained size.
* Different instances with the same total retained size are considered
* equal for the purposes of comparison.
* This sorts instances from larger retained size to smaller retained size.
@@ -57,12 +57,12 @@ public class Sort {
};
/**
- * Compare instances by their retained size for a given heap index.
+ * Compares instances by their retained size for a given heap index.
* Different instances with the same total retained size are considered
* equal for the purposes of comparison.
* This sorts instances from larger retained size to smaller retained size.
*/
- public static class InstanceByHeapRetainedSize implements Comparator<AhatInstance> {
+ private static class InstanceByHeapRetainedSize implements Comparator<AhatInstance> {
private AhatHeap mHeap;
public InstanceByHeapRetainedSize(AhatHeap heap) {
@@ -76,16 +76,28 @@ public class Sort {
}
/**
- * Compare objects based on a list of comparators, giving priority to the
+ * Compares objects based on a list of comparators, giving priority to the
* earlier comparators in the list.
*/
- public static class WithPriority<T> implements Comparator<T> {
+ private static class WithPriority<T> implements Comparator<T> {
private List<Comparator<T>> mComparators;
+ /**
+ * Constructs a comparator giving sort priority to earlier comparators in
+ * the list.
+ *
+ * @param comparators the list of comparators to use for sorting
+ */
public WithPriority(Comparator<T>... comparators) {
mComparators = Arrays.asList(comparators);
}
+ /**
+ * Constructs a comparator giving sort priority to earlier comparators in
+ * the list.
+ *
+ * @param comparators the list of comparators to use for sorting
+ */
public WithPriority(List<Comparator<T>> comparators) {
mComparators = comparators;
}
@@ -101,6 +113,27 @@ public class Sort {
}
}
+ /**
+ * Returns a comparator that gives sort priority to earlier comparators in
+ * the list.
+ *
+ * @param <T> the type of object being sorted
+ * @param comparators the list of comparators to use for sorting
+ * @return the composite comparator
+ */
+ public static <T> Comparator<T> withPriority(Comparator<T>... comparators) {
+ return new WithPriority(comparators);
+ }
+
+ /**
+ * Returns a comparator that gives a default instance sort for the given
+ * snapshot.
+ * Objects are sorted by retained size, with priority given to the "app"
+ * heap if present.
+ *
+ * @param snapshot the snapshot to use the comparator with
+ * @return the default instance comparator
+ */
public static Comparator<AhatInstance> defaultInstanceCompare(AhatSnapshot snapshot) {
List<Comparator<AhatInstance>> comparators = new ArrayList<Comparator<AhatInstance>>();
@@ -116,14 +149,19 @@ public class Sort {
}
/**
- * Compare Sites by the size of objects allocated on a given heap.
+ * Compares Sites by the size of objects allocated on a given heap.
* Different object infos with the same size on the given heap are
* considered equal for the purposes of comparison.
* This sorts sites from larger size to smaller size.
*/
- public static class SiteByHeapSize implements Comparator<Site> {
+ private static class SiteByHeapSize implements Comparator<Site> {
AhatHeap mHeap;
+ /**
+ * Constructs a SiteByHeapSize comparator.
+ *
+ * @param heap the heap to use when comparing sizes
+ */
public SiteByHeapSize(AhatHeap heap) {
mHeap = heap;
}
@@ -135,7 +173,7 @@ public class Sort {
}
/**
- * Compare Sites by the total size of objects allocated.
+ * Compares Sites by the total size of objects allocated.
* This sorts sites from larger size to smaller size.
*/
public static final Comparator<Site> SITE_BY_TOTAL_SIZE = new Comparator<Site>() {
@@ -145,6 +183,14 @@ public class Sort {
}
};
+ /**
+ * Compares Sites using a default comparison order.
+ * This sorts sites from larger size to smaller size, giving preference to
+ * sites with more allocation on the "app" heap, if present.
+ *
+ * @param snapshot the snapshot to use the comparator with
+ * @return the default site comparator
+ */
public static Comparator<Site> defaultSiteCompare(AhatSnapshot snapshot) {
List<Comparator<Site>> comparators = new ArrayList<Comparator<Site>>();
@@ -174,7 +220,7 @@ public class Sort {
};
/**
- * Compare Site.ObjectsInfo by heap name.
+ * Compares Site.ObjectsInfo by heap name.
* Different object infos with the same heap name are considered equal for
* the purposes of comparison.
*/
@@ -187,7 +233,7 @@ public class Sort {
};
/**
- * Compare Site.ObjectsInfo by class name.
+ * Compares Site.ObjectsInfo by class name.
* Different object infos with the same class name are considered equal for
* the purposes of comparison.
*/
@@ -202,7 +248,7 @@ public class Sort {
};
/**
- * Compare FieldValue by field name.
+ * Compares FieldValue by field name.
*/
public static final Comparator<FieldValue> FIELD_VALUE_BY_NAME
= new Comparator<FieldValue>() {
@@ -213,7 +259,7 @@ public class Sort {
};
/**
- * Compare FieldValue by type name.
+ * Compares FieldValue by type name.
*/
public static final Comparator<FieldValue> FIELD_VALUE_BY_TYPE
= new Comparator<FieldValue>() {
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Type.java b/tools/ahat/src/main/com/android/ahat/heapdump/Type.java
index 40249615a2..ff79864505 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Type.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Type.java
@@ -16,18 +16,63 @@
package com.android.ahat.heapdump;
+/**
+ * Enum corresponding to basic types from the binary heap dump format.
+ */
public enum Type {
+ /**
+ * Type used for any Java object.
+ */
OBJECT("Object", 4),
+
+ /**
+ * The primitive boolean type.
+ */
BOOLEAN("boolean", 1),
+
+ /**
+ * The primitive char type.
+ */
CHAR("char", 2),
+
+ /**
+ * The primitive float type.
+ */
FLOAT("float", 4),
+
+ /**
+ * The primitive double type.
+ */
DOUBLE("double", 8),
+
+ /**
+ * The primitive byte type.
+ */
BYTE("byte", 1),
+
+ /**
+ * The primitive short type.
+ */
SHORT("short", 2),
+
+ /**
+ * The primitive int type.
+ */
INT("int", 4),
+
+ /**
+ * The primitive long type.
+ */
LONG("long", 8);
+ /**
+ * The name of the type.
+ */
public final String name;
+
+ /**
+ * The number of bytes taken up by values of this type in the Java heap.
+ */
final int size;
Type(String name, int size) {
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Value.java b/tools/ahat/src/main/com/android/ahat/heapdump/Value.java
index eea427774b..b219bf1564 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Value.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Value.java
@@ -17,48 +17,107 @@
package com.android.ahat.heapdump;
/**
- * Value represents a field value in a heap dump. The field value is either a
- * subclass of AhatInstance or a primitive Java type.
+ * A Java instance or primitive value from a parsed heap dump.
+ * Note: To save memory, a null Value is used to represent a null Java
+ * instance from the heap dump.
*/
public abstract class Value {
+ /**
+ * Constructs a Value for an AhatInstance.
+ * Note: returns null for null <code>value</code>.
+ *
+ * @param value the AhatInstance to make into a value
+ * @return the constructed value.
+ */
public static Value pack(AhatInstance value) {
return value == null ? null : new InstanceValue(value);
}
+ /**
+ * Constructs a Value for a boolean.
+ *
+ * @param value the boolean to make into a value
+ * @return the constructed value.
+ */
public static Value pack(boolean value) {
return new BooleanValue(value);
}
+ /**
+ * Constructs a Value for a char.
+ *
+ * @param value the char to make into a value
+ * @return the constructed value.
+ */
public static Value pack(char value) {
return new CharValue(value);
}
+ /**
+ * Constructs a Value for a float.
+ *
+ * @param value the float to make into a value
+ * @return the constructed value.
+ */
public static Value pack(float value) {
return new FloatValue(value);
}
+ /**
+ * Constructs a Value for a double.
+ *
+ * @param value the double to make into a value
+ * @return the constructed value.
+ */
public static Value pack(double value) {
return new DoubleValue(value);
}
+ /**
+ * Constructs a Value for a byte.
+ *
+ * @param value the byte to make into a value
+ * @return the constructed value.
+ */
public static Value pack(byte value) {
return new ByteValue(value);
}
+ /**
+ * Constructs a Value for a short.
+ *
+ * @param value the short to make into a value
+ * @return the constructed value.
+ */
public static Value pack(short value) {
return new ShortValue(value);
}
+ /**
+ * Constructs a Value for a int.
+ *
+ * @param value the int to make into a value
+ * @return the constructed value.
+ */
public static Value pack(int value) {
return new IntValue(value);
}
+ /**
+ * Constructs a Value for a long.
+ *
+ * @param value the long to make into a value
+ * @return the constructed value.
+ */
public static Value pack(long value) {
return new LongValue(value);
}
/**
- * Return the type of the given value.
+ * Returns the type of the given value.
+ *
+ * @param value the value to get the type of
+ * @return the value's type
*/
public static Type getType(Value value) {
return value == null ? Type.OBJECT : value.getType();
@@ -70,62 +129,78 @@ public abstract class Value {
abstract Type getType();
/**
- * Returns true if the Value is an AhatInstance, as opposed to a Java
- * primitive value.
+ * Returns true if the Value is an AhatInstance rather than a primitive
+ * value.
+ *
+ * @return true if the value is an AhatInstance
*/
public boolean isAhatInstance() {
return false;
}
/**
- * Return the Value as an AhatInstance if it is one.
+ * Returns the Value as an AhatInstance if it is one.
* Returns null if the Value represents a Java primitive value.
+ *
+ * @return the AhatInstance packed into this value
*/
public AhatInstance asAhatInstance() {
return null;
}
/**
- * Returns true if the Value is an Integer.
+ * Returns true if the Value is an int.
+ *
+ * @return true if the value is an int.
*/
public boolean isInteger() {
return false;
}
/**
- * Return the Value as an Integer if it is one.
- * Returns null if the Value does not represent an Integer.
+ * Returns the Value as an int if it is one.
+ * Returns null if the Value does not represent an int.
+ *
+ * @return the int packed into this value
*/
public Integer asInteger() {
return null;
}
/**
- * Returns true if the Value is an Long.
+ * Returns true if the Value is an long.
+ *
+ * @return true if the value is an long.
*/
public boolean isLong() {
return false;
}
/**
- * Return the Value as an Long if it is one.
- * Returns null if the Value does not represent an Long.
+ * Returns the Value as an long if it is one.
+ * Returns null if the Value does not represent an long.
+ *
+ * @return the long packed into this value
*/
public Long asLong() {
return null;
}
/**
- * Return the Value as a Byte if it is one.
- * Returns null if the Value does not represent a Byte.
+ * Returns the Value as an byte if it is one.
+ * Returns null if the Value does not represent an byte.
+ *
+ * @return the byte packed into this value
*/
public Byte asByte() {
return null;
}
/**
- * Return the Value as a Char if it is one.
- * Returns null if the Value does not represent a Char.
+ * Returns the Value as an char if it is one.
+ * Returns null if the Value does not represent an char.
+ *
+ * @return the char packed into this value
*/
public Character asChar() {
return null;
@@ -134,10 +209,18 @@ public abstract class Value {
@Override
public abstract String toString();
- public Value getBaseline() {
+ private Value getBaseline() {
return this;
}
+ /**
+ * Returns the baseline of the given value for the purposes of diff.
+ * This method can be used to handle the case when the Value is null.
+ *
+ * @param value the value to get the baseline of
+ * @return the baseline of the value
+ * @see Diffable#getBaseline
+ */
public static Value getBaseline(Value value) {
return value == null ? null : value.getBaseline();
}
@@ -313,7 +396,6 @@ public abstract class Value {
return mInstance.toString();
}
- @Override
public Value getBaseline() {
return InstanceValue.pack(mInstance.getBaseline());
}
diff --git a/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java b/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java
index 32bb209dc6..79a737cc18 100644
--- a/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java
+++ b/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java
@@ -26,7 +26,10 @@ import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
-// Class used to deobfuscate classes, fields, and stack frames.
+/**
+ * A representation of a proguard mapping for deobfuscating class names,
+ * field names, and stack frames.
+ */
public class ProguardMap {
private static final String ARRAY_SYMBOL = "[]";
@@ -98,6 +101,10 @@ public class ProguardMap {
private Map<String, ClassData> mClassesFromClearName = new HashMap<String, ClassData>();
private Map<String, ClassData> mClassesFromObfuscatedName = new HashMap<String, ClassData>();
+ /**
+ * Information associated with a stack frame that identifies a particular
+ * line of source code.
+ */
public static class Frame {
Frame(String method, String signature, String filename, int line) {
this.method = method;
@@ -106,9 +113,28 @@ public class ProguardMap {
this.line = line;
}
+ /**
+ * The name of the method the stack frame belongs to.
+ * For example, "equals".
+ */
public final String method;
+
+ /**
+ * The signature of the method the stack frame belongs to.
+ * For example, "(Ljava/lang/Object;)Z".
+ */
public final String signature;
+
+ /**
+ * The name of the file with containing the line of source that the stack
+ * frame refers to.
+ */
public final String filename;
+
+ /**
+ * The line number of the code in the source file that the stack frame
+ * refers to.
+ */
public final int line;
}
@@ -116,13 +142,44 @@ public class ProguardMap {
throw new ParseException(msg, 0);
}
- // Read in proguard mapping information from the given file.
+ /**
+ * Creates a new empty proguard mapping.
+ * The {@link #readFromFile readFromFile} and
+ * {@link #readFromReader readFromReader} methods can be used to populate
+ * the proguard mapping with proguard mapping information.
+ */
+ public ProguardMap() {
+ }
+
+ /**
+ * Adds the proguard mapping information in <code>mapFile</code> to this
+ * proguard mapping.
+ * The <code>mapFile</code> should be a proguard mapping file generated with
+ * the <code>-printmapping</code> option when proguard was run.
+ *
+ * @param mapFile the name of a file with proguard mapping information
+ * @throws FileNotFoundException If the <code>mapFile</code> could not be
+ * found
+ * @throws IOException If an input exception occurred.
+ * @throws ParseException If the <code>mapFile</code> is not a properly
+ * formatted proguard mapping file.
+ */
public void readFromFile(File mapFile)
throws FileNotFoundException, IOException, ParseException {
readFromReader(new FileReader(mapFile));
}
- // Read in proguard mapping information from the given Reader.
+ /**
+ * Adds the proguard mapping information read from <code>mapReader</code> to
+ * this proguard mapping.
+ * <code>mapReader</code> should be a Reader of a proguard mapping file
+ * generated with the <code>-printmapping</code> option when proguard was run.
+ *
+ * @param mapReader a Reader for reading the proguard mapping information
+ * @throws IOException If an input exception occurred.
+ * @throws ParseException If the <code>mapFile</code> is not a properly
+ * formatted proguard mapping file.
+ */
public void readFromReader(Reader mapReader) throws IOException, ParseException {
BufferedReader reader = new BufferedReader(mapReader);
String line = reader.readLine();
@@ -207,8 +264,15 @@ public class ProguardMap {
reader.close();
}
- // Returns the deobfuscated version of the given class name. If no
- // deobfuscated version is known, the original string is returned.
+ /**
+ * Returns the deobfuscated version of the given obfuscated class name.
+ * If this proguard mapping does not include information about how to
+ * deobfuscate the obfuscated class name, the obfuscated class name
+ * is returned.
+ *
+ * @param obfuscatedClassName the obfuscated class name to deobfuscate
+ * @return the deobfuscated class name.
+ */
public String getClassName(String obfuscatedClassName) {
// Class names for arrays may have trailing [] that need to be
// stripped before doing the lookup.
@@ -224,9 +288,17 @@ public class ProguardMap {
return clearBaseName + arraySuffix;
}
- // Returns the deobfuscated version of the given field name for the given
- // (clear) class name. If no deobfuscated version is known, the original
- // string is returned.
+ /**
+ * Returns the deobfuscated version of the obfuscated field name for the
+ * given deobfuscated class name.
+ * If this proguard mapping does not include information about how to
+ * deobfuscate the obfuscated field name, the obfuscated field name is
+ * returned.
+ *
+ * @param clearClass the deobfuscated name of the class the field belongs to
+ * @param obfuscatedField the obfuscated field name to deobfuscate
+ * @return the deobfuscated field name.
+ */
public String getFieldName(String clearClass, String obfuscatedField) {
ClassData classData = mClassesFromClearName.get(clearClass);
if (classData == null) {
@@ -235,8 +307,21 @@ public class ProguardMap {
return classData.getField(obfuscatedField);
}
- // Returns the deobfuscated frame for the given obfuscated frame and (clear)
- // class name. As much of the frame is deobfuscated as can be.
+ /**
+ * Returns the deobfuscated version of the obfuscated stack frame
+ * information for the given deobfuscated class name.
+ * If this proguard mapping does not include information about how to
+ * deobfuscate the obfuscated stack frame information, the obfuscated stack
+ * frame information is returned.
+ *
+ * @param clearClassName the deobfuscated name of the class the stack frame's
+ * method belongs to
+ * @param obfuscatedMethodName the obfuscated method name to deobfuscate
+ * @param obfuscatedSignature the obfuscated method signature to deobfuscate
+ * @param obfuscatedFilename the obfuscated file name to deobfuscate.
+ * @param obfuscatedLine the obfuscated line number to deobfuscate.
+ * @return the deobfuscated stack frame information.
+ */
public Frame getFrame(String clearClassName, String obfuscatedMethodName,
String obfuscatedSignature, String obfuscatedFilename, int obfuscatedLine) {
String clearSignature = getSignature(obfuscatedSignature);
diff --git a/tools/checker/README b/tools/checker/README
index 65f5bd25a5..b8dd80376e 100644
--- a/tools/checker/README
+++ b/tools/checker/README
@@ -76,3 +76,10 @@ Example:
/// CHECK-START-ARM64: int MyClass.MyMethod() constant_folding (after)
/// CHECK: <<ID:i\d+>> IntConstant {{11|22}}
/// CHECK: Return [<<ID>>]
+
+For convenience, several architectures can be specified as set after the
+'CHECK-START' keyword. Any listed architecture will match in that case,
+thereby avoiding to repeat the check lines if some, but not all architectures
+match. An example line looks like:
+
+ /// CHECK-START-{MIPS,ARM,ARM64}: int MyClass.MyMethod() constant_folding (after)
diff --git a/tools/checker/checker.py b/tools/checker/checker.py
index 2e9faba9fb..65b01a7f15 100755
--- a/tools/checker/checker.py
+++ b/tools/checker/checker.py
@@ -90,7 +90,8 @@ def RunTests(checkPrefix, checkPath, outputFilename, targetArch, debuggableMode)
for checkFilename in FindCheckerFiles(checkPath):
checkerFile = ParseCheckerStream(os.path.basename(checkFilename),
checkPrefix,
- open(checkFilename, "r"))
+ open(checkFilename, "r"),
+ targetArch)
MatchFiles(checkerFile, c1File, targetArch, debuggableMode)
diff --git a/tools/checker/file_format/checker/parser.py b/tools/checker/file_format/checker/parser.py
index f199a50ebe..7a5a4c8c26 100644
--- a/tools/checker/file_format/checker/parser.py
+++ b/tools/checker/file_format/checker/parser.py
@@ -44,7 +44,33 @@ def __extractLine(prefix, line, arch = None, debuggable = False):
else:
return None
-def __processLine(line, lineNo, prefix, fileName):
+def __preprocessLineForStart(prefix, line, targetArch):
+ """ This function modifies a CHECK-START-{x,y,z} into a matching
+ CHECK-START-y line for matching targetArch y. If no matching
+ architecture is found, CHECK-START-x is returned arbitrarily
+ to ensure all following check lines are put into a test that
+ is skipped. Any other line is left unmodified.
+ """
+ if targetArch is not None:
+ if prefix in line:
+ # Find { } on the line and assume that defines the set.
+ s = line.find('{')
+ e = line.find('}')
+ if 0 < s and s < e:
+ archs = line[s+1:e].split(',')
+ # First verify that every archs is valid. Return the
+ # full line on failure to prompt error back to user.
+ for arch in archs:
+ if not arch in archs_list:
+ return line
+ # Now accept matching arch or arbitrarily return first.
+ if targetArch in archs:
+ return line[:s] + targetArch + line[e + 1:]
+ else:
+ return line[:s] + archs[0] + line[e + 1:]
+ return line
+
+def __processLine(line, lineNo, prefix, fileName, targetArch):
""" This function is invoked on each line of the check file and returns a triplet
which instructs the parser how the line should be handled. If the line is
to be included in the current check group, it is returned in the first
@@ -56,10 +82,11 @@ def __processLine(line, lineNo, prefix, fileName):
return None, None, None
# Lines beginning with 'CHECK-START' start a new test case.
- # We currently only consider the architecture suffix in "CHECK-START" lines.
+ # We currently only consider the architecture suffix(es) in "CHECK-START" lines.
for debuggable in [True, False]:
+ sline = __preprocessLineForStart(prefix + "-START", line, targetArch)
for arch in [None] + archs_list:
- startLine = __extractLine(prefix + "-START", line, arch, debuggable)
+ startLine = __extractLine(prefix + "-START", sline, arch, debuggable)
if startLine is not None:
return None, startLine, (arch, debuggable)
@@ -164,9 +191,9 @@ def ParseCheckerAssertion(parent, line, variant, lineNo):
assertion.addExpression(TestExpression.createPatternFromPlainText(text))
return assertion
-def ParseCheckerStream(fileName, prefix, stream):
+def ParseCheckerStream(fileName, prefix, stream, targetArch = None):
checkerFile = CheckerFile(fileName)
- fnProcessLine = lambda line, lineNo: __processLine(line, lineNo, prefix, fileName)
+ fnProcessLine = lambda line, lineNo: __processLine(line, lineNo, prefix, fileName, targetArch)
fnLineOutsideChunk = lambda line, lineNo: \
Logger.fail("Checker line not inside a group", fileName, lineNo)
for caseName, caseLines, startLineNo, testData in \
diff --git a/tools/cpp-define-generator/constant_class.def b/tools/cpp-define-generator/constant_class.def
index f46cd339b0..4f1d875e5a 100644
--- a/tools/cpp-define-generator/constant_class.def
+++ b/tools/cpp-define-generator/constant_class.def
@@ -15,7 +15,6 @@
*/
#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "mirror/class.h" // kStatusInitialized
#include "modifiers.h" // kAccClassIsFinalizable
#include "base/bit_utils.h" // MostSignificantBit
#endif
@@ -23,7 +22,6 @@
#define DEFINE_FLAG_OFFSET(type_name, field_name, expr) \
DEFINE_EXPR(type_name ## _ ## field_name, uint32_t, (expr))
-DEFINE_FLAG_OFFSET(MIRROR_CLASS, STATUS_INITIALIZED, art::mirror::Class::kStatusInitialized)
DEFINE_FLAG_OFFSET(ACCESS_FLAGS, CLASS_IS_FINALIZABLE, art::kAccClassIsFinalizable)
DEFINE_FLAG_OFFSET(ACCESS_FLAGS, CLASS_IS_INTERFACE, art::kAccInterface)
// TODO: We should really have a BitPosition which also checks it's a power of 2.
diff --git a/tools/dt_fds_forward.py b/tools/dt_fds_forward.py
new file mode 100755
index 0000000000..516b7fef96
--- /dev/null
+++ b/tools/dt_fds_forward.py
@@ -0,0 +1,196 @@
+#!/usr/bin/env python3
+#
+# Copyright 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.
+
+"""
+A python program that simulates the plugin side of the dt_fd_forward transport for testing.
+
+This program will invoke a given java language runtime program and send down debugging arguments
+that cause it to use the dt_fd_forward transport. This will then create a normal server-port that
+debuggers can attach to.
+"""
+
+import argparse
+import array
+from multiprocessing import Process
+import contextlib
+import ctypes
+import os
+import select
+import socket
+import subprocess
+import sys
+import time
+
+LISTEN_START_MESSAGE = b"dt_fd_forward:START-LISTEN\x00"
+LISTEN_END_MESSAGE = b"dt_fd_forward:END-LISTEN\x00"
+ACCEPTED_MESSAGE = b"dt_fd_forward:ACCEPTED\x00"
+CLOSE_MESSAGE = b"dt_fd_forward:CLOSING\x00"
+
+libc = ctypes.cdll.LoadLibrary("libc.so.6")
+def eventfd(init_val, flags):
+ """
+ Creates an eventfd. See 'man 2 eventfd' for more information.
+ """
+ return libc.eventfd(init_val, flags)
+
+@contextlib.contextmanager
+def make_eventfd(init):
+ """
+ Creates an eventfd with given initial value that is closed after the manager finishes.
+ """
+ fd = eventfd(init, 0)
+ yield fd
+ os.close(fd)
+
+@contextlib.contextmanager
+def make_sockets():
+ """
+ Make a (remote,local) socket pair. The remote socket is inheritable by forked processes. They are
+ both linked together.
+ """
+ (rfd, lfd) = socket.socketpair(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+ yield (rfd, lfd)
+ rfd.close()
+ lfd.close()
+
+def send_fds(sock, remote_read, remote_write, remote_event):
+ """
+ Send the three fds over the given socket.
+ """
+ sock.sendmsg([b"!"], # We don't actually care what we send here.
+ [(socket.SOL_SOCKET, # Send over socket.
+ socket.SCM_RIGHTS, # Payload is file-descriptor array
+ array.array('i', [remote_read, remote_write, remote_event]))])
+
+
+def HandleSockets(host, port, local_sock, finish_event):
+ """
+ Handle the IO between the network and the runtime.
+
+ This is similar to what we will do with the plugin that controls the jdwp connection.
+
+ The main difference is it will keep around the connection and event-fd in order to let it send
+ ddms packets directly.
+ """
+ listening = False
+ with socket.socket() as sock:
+ sock.bind((host, port))
+ sock.listen()
+ while True:
+ sources = [local_sock, finish_event, sock]
+ print("Starting select on " + str(sources))
+ (rf, _, _) = select.select(sources, [], [])
+ if local_sock in rf:
+ buf = local_sock.recv(1024)
+ print("Local_sock has data: " + str(buf))
+ if buf == LISTEN_START_MESSAGE:
+ print("listening on " + str(sock))
+ listening = True
+ elif buf == LISTEN_END_MESSAGE:
+ print("End listening")
+ listening = False
+ elif buf == ACCEPTED_MESSAGE:
+ print("Fds were accepted.")
+ elif buf == CLOSE_MESSAGE:
+ # TODO Dup the fds and send a fake DDMS message like the actual plugin would.
+ print("Fds were closed")
+ else:
+ print("Unknown data received from socket " + str(buf))
+ return
+ elif sock in rf:
+ (conn, addr) = sock.accept()
+ with conn:
+ print("connection accepted from " + str(addr))
+ if listening:
+ with make_eventfd(1) as efd:
+ print("sending fds ({}, {}, {}) to target.".format(conn.fileno(), conn.fileno(), efd))
+ send_fds(local_sock, conn.fileno(), conn.fileno(), efd)
+ else:
+ print("Closing fds since we cannot accept them.")
+ if finish_event in rf:
+ print("woke up from finish_event")
+ return
+
+def StartChildProcess(cmd_pre, cmd_post, jdwp_lib, jdwp_ops, remote_sock, can_be_runtest):
+ """
+ Open the child java-language runtime process.
+ """
+ full_cmd = list(cmd_pre)
+ os.set_inheritable(remote_sock.fileno(), True)
+ jdwp_arg = jdwp_lib + "=" + \
+ jdwp_ops + "transport=dt_fd_forward,address=" + str(remote_sock.fileno())
+ if can_be_runtest and cmd_pre[0].endswith("run-test"):
+ print("Assuming run-test. Pass --no-run-test if this isn't true")
+ full_cmd += ["--with-agent", jdwp_arg]
+ else:
+ full_cmd.append("-agentpath:" + jdwp_arg)
+ full_cmd += cmd_post
+ print("Running " + str(full_cmd))
+ # Start the actual process with the fd being passed down.
+ proc = subprocess.Popen(full_cmd, close_fds=False)
+ # Get rid of the extra socket.
+ remote_sock.close()
+ proc.wait()
+
+def main():
+ parser = argparse.ArgumentParser(description="""
+ Runs a socket that forwards to dt_fds.
+
+ Pass '--' to start passing in the program we will pass the debug
+ options down to.
+ """)
+ parser.add_argument("--host", type=str, default="localhost",
+ help="Host we will listen for traffic on. Defaults to 'localhost'.")
+ parser.add_argument("--debug-lib", type=str, default="libjdwp.so",
+ help="jdwp library we pass to -agentpath:. Default is 'libjdwp.so'")
+ parser.add_argument("--debug-options", type=str, default="server=y,suspend=y,",
+ help="non-address options we pass to jdwp agent, default is " +
+ "'server=y,suspend=y,'")
+ parser.add_argument("--port", type=int, default=12345,
+ help="port we will expose the traffic on. Defaults to 12345.")
+ parser.add_argument("--no-run-test", default=False, action="store_true",
+ help="don't pass in arguments for run-test even if it looks like that is " +
+ "the program")
+ parser.add_argument("--pre-end", type=int, default=1,
+ help="number of 'rest' arguments to put before passing in the debug options")
+ end_idx = 0 if '--' not in sys.argv else sys.argv.index('--')
+ if end_idx == 0 and ('--help' in sys.argv or '-h' in sys.argv):
+ parser.print_help()
+ return
+ args = parser.parse_args(sys.argv[:end_idx][1:])
+ rest = sys.argv[1 + end_idx:]
+
+ with make_eventfd(0) as wakeup_event:
+ with make_sockets() as (remote_sock, local_sock):
+ invoker = Process(target=StartChildProcess,
+ args=(rest[:args.pre_end],
+ rest[args.pre_end:],
+ args.debug_lib,
+ args.debug_options,
+ remote_sock,
+ not args.no_run_test))
+ socket_handler = Process(target=HandleSockets,
+ args=(args.host, args.port, local_sock, wakeup_event))
+ socket_handler.start()
+ invoker.start()
+ invoker.join()
+ # Write any 64 bit value to the wakeup_event to make sure that the socket handler will wake
+ # up and exit.
+ os.write(wakeup_event, b'\x00\x00\x00\x00\x00\x00\x01\x00')
+ socket_handler.join()
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/libjdwp_oj_art_failures.txt b/tools/external_oj_libjdwp_art_failures.txt
index e1cc831303..c96830a592 100644
--- a/tools/libjdwp_oj_art_failures.txt
+++ b/tools/external_oj_libjdwp_art_failures.txt
@@ -1,6 +1,9 @@
/*
* This file contains expectations for ART's buildbot. The purpose of this file is
* to temporarily list failing tests and not break the bots.
+ *
+ * This file contains the expectations for the 'libjdwp-aot' and 'libjdwp-jit'
+ * test groups on the chromium buildbot.
*/
[
{
@@ -21,19 +24,6 @@
bug: 66905894,
name: "org.apache.harmony.jpda.tests.jdwp.ReferenceType.GetValues006Test#testGetValues006"
},
-{
- description: "Tests fail with assertion error on slot number",
- result: EXEC_FAILED,
- bug: 66905468,
- names: [ "org.apache.harmony.jpda.tests.jdwp.Method.VariableTableTest#testVariableTableTest001",
- "org.apache.harmony.jpda.tests.jdwp.Method.VariableTableWithGenericTest#testVariableTableWithGenericTest001" ]
-},
-{
- description: "Test fails with Error VM_DEAD when trying to resume during VM_DEATH event",
- result: EXEC_FAILED,
- bug: 66904725,
- name: "org.apache.harmony.jpda.tests.jdwp.Events.VMDeath002Test#testVMDeathRequest"
-},
/* TODO Categorize these failures more. */
{
description: "Tests that fail on both ART and RI. These tests are likely incorrect",
@@ -69,15 +59,16 @@
name: "org.apache.harmony.jpda.tests.jdwp.ObjectReference.IsCollectedTest#testIsCollected001"
},
{
- description: "Test for ddms extensions that are not yet implemented",
- result: EXEC_FAILED,
- bug: 69169846,
- name: "org.apache.harmony.jpda.tests.jdwp.DDM.DDMTest#testChunk001"
-},
-{
description: "Test crashes",
result: EXEC_FAILED,
bug: 69591477,
name: "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ExitTest#testExit001"
+},
+{
+ description: "Test times out on fugu-debug",
+ result: EXEC_FAILED,
+ bug: 70459916,
+ names: [ "org.apache.harmony.jpda.tests.jdwp.VMDebug.VMDebugTest#testVMDebug",
+ "org.apache.harmony.jpda.tests.jdwp.VMDebug.VMDebugTest002#testVMDebug" ]
}
]
diff --git a/tools/jfuzz/README.md b/tools/jfuzz/README.md
index 10d175b83d..eb0e71f53d 100644
--- a/tools/jfuzz/README.md
+++ b/tools/jfuzz/README.md
@@ -28,6 +28,8 @@ where
(higher values yield deeper nested conditionals)
-n : defines a fuzzing nest for for/while/do-while loops
(higher values yield deeper nested loops)
+ -t : defines a fuzzing nest for try-catch-finally blocks
+ (higher values yield deeper nested try-catch-finally blocks)
-v : prints version number and exits
-h : prints help and exits
@@ -48,7 +50,8 @@ How to start JFuzz testing
[--report_script=SCRIPT]
[--jfuzz_arg=ARG]
[--true_divergence]
- [--use_dx]
+ [--dexer=DEXER]
+ [--debug_info]
where
@@ -64,7 +67,8 @@ where
--report_script : path to script called for each divergence
--jfuzz_arg : argument for jfuzz
--true_divergence : don't bisect timeout divergences
- --use_dx : use dx (rather than jack)
+ --dexer=DEXER : use either dx, d8, or jack to obtain dex files
+ --debug_info : include debugging info
How to start JFuzz nightly testing
==================================
@@ -85,14 +89,16 @@ How to start J/DexFuzz testing (multi-layered)
[--num_tests=NUM_TESTS]
[--num_inputs=NUM_INPUTS]
[--device=DEVICE]
- [--use_dx]
+ [--dexer=DEXER]
+ [--debug_info]
where
- --num_tests : number of tests to run (10000 by default)
- --num_inputs: number of JFuzz programs to generate
- --device : target device serial number (passed to adb -s)
- --use_dx : use dx (rather than jack)
+ --num_tests : number of tests to run (10000 by default)
+ --num_inputs : number of JFuzz programs to generate
+ --device : target device serial number (passed to adb -s)
+ --dexer=DEXER : use either dx, d8, or jack to obtain dex files
+ --debug_info : include debugging info
Background
==========
diff --git a/tools/jfuzz/jfuzz.cc b/tools/jfuzz/jfuzz.cc
index 7990c6cf8e..60c62752ef 100644
--- a/tools/jfuzz/jfuzz.cc
+++ b/tools/jfuzz/jfuzz.cc
@@ -31,8 +31,6 @@ namespace {
* Operators.
*/
-#define EMIT(x) fputs((x)[random0(sizeof(x)/sizeof(const char*))], out_);
-
static constexpr const char* kIncDecOps[] = { "++", "--" };
static constexpr const char* kIntUnaryOps[] = { "+", "-", "~" };
static constexpr const char* kFpUnaryOps[] = { "+", "-" };
@@ -51,11 +49,21 @@ static constexpr const char* kBoolRelOps[] = { "==", "!=" };
static constexpr const char* kRelOps[] = { "==", "!=", ">", ">=", "<", "<=" };
/*
+ * Exceptions.
+ */
+static const char* kExceptionTypes[] = {
+ "IllegalStateException",
+ "NullPointerException",
+ "IllegalArgumentException",
+ "ArrayIndexOutOfBoundsException"
+};
+
+/*
* Version of JFuzz. Increase this each time changes are made to the program
* to preserve the property that a given version of JFuzz yields the same
* fuzzed program for a deterministic random seed.
*/
-const char* VERSION = "1.4";
+const char* VERSION = "1.5";
/*
* Maximum number of array dimensions, together with corresponding maximum size
@@ -64,6 +72,14 @@ const char* VERSION = "1.4";
static const uint32_t kMaxDim = 10;
static const uint32_t kMaxDimSize[kMaxDim + 1] = { 0, 1000, 32, 10, 6, 4, 3, 3, 2, 2, 2 };
+/*
+ * Utility function to return the number of elements in an array.
+ */
+template <typename T, uint32_t N>
+constexpr uint32_t countof(T const (&)[N]) {
+ return N;
+}
+
/**
* A class that generates a random program that compiles correctly. The program
* is generated using rules that generate various programming constructs. Each rule
@@ -78,7 +94,8 @@ class JFuzz {
uint32_t expr_depth,
uint32_t stmt_length,
uint32_t if_nest,
- uint32_t loop_nest)
+ uint32_t loop_nest,
+ uint32_t try_nest)
: out_(out),
fuzz_random_engine_(seed),
fuzz_seed_(seed),
@@ -86,6 +103,7 @@ class JFuzz {
fuzz_stmt_length_(stmt_length),
fuzz_if_nest_(if_nest),
fuzz_loop_nest_(loop_nest),
+ fuzz_try_nest_(try_nest),
return_type_(randomType()),
array_type_(randomType()),
array_dim_(random1(kMaxDim)),
@@ -97,6 +115,7 @@ class JFuzz {
loop_nest_(0),
switch_nest_(0),
do_nest_(0),
+ try_nest_(0),
boolean_local_(0),
int_local_(0),
long_local_(0),
@@ -168,6 +187,12 @@ class JFuzz {
}
}
+ // Emits a random strong selected from an array of operator strings.
+ template <std::uint32_t N>
+ inline void emitOneOf(const char* const (&ops)[N]) {
+ fputs(ops[random0(N)], out_);
+ }
+
//
// Expressions.
//
@@ -177,9 +202,9 @@ class JFuzz {
if (tp == kBoolean) {
fputc('!', out_);
} else if (isInteger(tp)) {
- EMIT(kIntUnaryOps);
+ emitOneOf(kIntUnaryOps);
} else { // isFP(tp)
- EMIT(kFpUnaryOps);
+ emitOneOf(kFpUnaryOps);
}
}
@@ -188,38 +213,38 @@ class JFuzz {
if (tp == kBoolean) {
// Not applicable, just leave "as is".
} else { // isInteger(tp) || isFP(tp)
- EMIT(kIncDecOps);
+ emitOneOf(kIncDecOps);
}
}
// Emit a binary operator (same type in-out).
void emitBinaryOp(Type tp) {
if (tp == kBoolean) {
- EMIT(kBoolBinOps);
+ emitOneOf(kBoolBinOps);
} else if (isInteger(tp)) {
- EMIT(kIntBinOps);
+ emitOneOf(kIntBinOps);
} else { // isFP(tp)
- EMIT(kFpBinOps);
+ emitOneOf(kFpBinOps);
}
}
// Emit an assignment operator (same type in-out).
void emitAssignmentOp(Type tp) {
if (tp == kBoolean) {
- EMIT(kBoolAssignOps);
+ emitOneOf(kBoolAssignOps);
} else if (isInteger(tp)) {
- EMIT(kIntAssignOps);
+ emitOneOf(kIntAssignOps);
} else { // isFP(tp)
- EMIT(kFpAssignOps);
+ emitOneOf(kFpAssignOps);
}
}
// Emit a relational operator (one type in, boolean out).
void emitRelationalOp(Type tp) {
if (tp == kBoolean) {
- EMIT(kBoolRelOps);
+ emitOneOf(kBoolRelOps);
} else { // isInteger(tp) || isFP(tp)
- EMIT(kRelOps);
+ emitOneOf(kRelOps);
}
}
@@ -808,7 +833,7 @@ class JFuzz {
fputs("{\n", out_);
indentation_ += 2;
emitIndentation();
- fprintf(out_, "int i%u = %d;", loop_nest_, isWhile ? -1 : 0);
+ fprintf(out_, "int i%u = %d;\n", loop_nest_, isWhile ? -1 : 0);
emitIndentation();
if (isWhile) {
fprintf(out_, "while (++i%u < ", loop_nest_);
@@ -871,6 +896,73 @@ class JFuzz {
return mayFollowTrue || mayFollowFalse;
}
+ bool emitTry() {
+ fputs("try {\n", out_);
+ indentation_ += 2;
+ bool mayFollow = emitStatementList();
+ indentation_ -= 2;
+ emitIndentation();
+ fputc('}', out_);
+ return mayFollow;
+ }
+
+ bool emitCatch() {
+ uint32_t count = random1(countof(kExceptionTypes));
+ bool mayFollow = false;
+ for (uint32_t i = 0; i < count; ++i) {
+ fprintf(out_, " catch (%s ex%u_%u) {\n", kExceptionTypes[i], try_nest_, i);
+ indentation_ += 2;
+ mayFollow |= emitStatementList();
+ indentation_ -= 2;
+ emitIndentation();
+ fputc('}', out_);
+ }
+ return mayFollow;
+ }
+
+ bool emitFinally() {
+ fputs(" finally {\n", out_);
+ indentation_ += 2;
+ bool mayFollow = emitStatementList();
+ indentation_ -= 2;
+ emitIndentation();
+ fputc('}', out_);
+ return mayFollow;
+ }
+
+ // Emit a try-catch-finally block.
+ bool emitTryCatchFinally() {
+ // Apply a hard limit on the number of catch blocks. This is for
+ // javac which fails if blocks within try-catch-finally are too
+ // large (much less than you'd expect).
+ if (try_nest_ > fuzz_try_nest_) {
+ return emitAssignment(); // fall back
+ }
+
+ ++try_nest_; // Entering try-catch-finally
+
+ bool mayFollow = emitTry();
+ switch (random0(3)) {
+ case 0: // try..catch
+ mayFollow |= emitCatch();
+ break;
+ case 1: // try..finally
+ mayFollow &= emitFinally();
+ break;
+ case 2: // try..catch..finally
+ // When determining whether code may follow, we observe that a
+ // finally block always follows after try and catch
+ // block. Code may only follow if the finally block permits
+ // and either the try or catch block allows code to follow.
+ mayFollow = (mayFollow | emitCatch()) & emitFinally();
+ break;
+ }
+ fputc('\n', out_);
+
+ --try_nest_; // Leaving try-catch-finally
+ return mayFollow;
+ }
+
// Emit a switch statement.
bool emitSwitch() {
// Continuing if nest becomes less likely as the depth grows.
@@ -915,6 +1007,11 @@ class JFuzz {
return mayFollow;
}
+ bool emitNopCall() {
+ fputs("nop();\n", out_);
+ return true;
+ }
+
// Emit an assignment statement.
bool emitAssignment() {
Type tp = randomType();
@@ -930,16 +1027,18 @@ class JFuzz {
// Emit a single statement. Returns true if statements may follow.
bool emitStatement() {
switch (random1(16)) { // favor assignments
- case 1: return emitReturn(false); break;
- case 2: return emitContinue(); break;
- case 3: return emitBreak(); break;
- case 4: return emitScope(); break;
- case 5: return emitArrayInit(); break;
- case 6: return emitForLoop(); break;
- case 7: return emitDoLoop(); break;
- case 8: return emitIfStmt(); break;
- case 9: return emitSwitch(); break;
- default: return emitAssignment(); break;
+ case 1: return emitReturn(false); break;
+ case 2: return emitContinue(); break;
+ case 3: return emitBreak(); break;
+ case 4: return emitScope(); break;
+ case 5: return emitArrayInit(); break;
+ case 6: return emitForLoop(); break;
+ case 7: return emitDoLoop(); break;
+ case 8: return emitIfStmt(); break;
+ case 9: return emitSwitch(); break;
+ case 10: return emitTryCatchFinally(); break;
+ case 11: return emitNopCall(); break;
+ default: return emitAssignment(); break;
}
}
@@ -1109,6 +1208,11 @@ class JFuzz {
fputs(" }\n", out_);
}
+ // Emit a static void method.
+ void emitStaticNopMethod() {
+ fputs(" public static void nop() {}\n\n", out_);
+ }
+
// Emit program header. Emit command line options in the comments.
void emitHeader() {
fputs("\n/**\n * AOSP JFuzz Tester.\n", out_);
@@ -1133,6 +1237,7 @@ class JFuzz {
emitArrayDecl();
emitTestConstructor();
emitTestMethod();
+ emitStaticNopMethod();
emitMainMethod();
indentation_ -= 2;
fputs("}\n\n", out_);
@@ -1167,6 +1272,7 @@ class JFuzz {
const uint32_t fuzz_stmt_length_;
const uint32_t fuzz_if_nest_;
const uint32_t fuzz_loop_nest_;
+ const uint32_t fuzz_try_nest_;
// Return and array setup.
const Type return_type_;
@@ -1182,6 +1288,7 @@ class JFuzz {
uint32_t loop_nest_;
uint32_t switch_nest_;
uint32_t do_nest_;
+ uint32_t try_nest_;
uint32_t boolean_local_;
uint32_t int_local_;
uint32_t long_local_;
@@ -1203,6 +1310,7 @@ int32_t main(int32_t argc, char** argv) {
uint32_t stmt_length = 8;
uint32_t if_nest = 2;
uint32_t loop_nest = 3;
+ uint32_t try_nest = 2;
// Parse options.
while (1) {
@@ -1226,6 +1334,9 @@ int32_t main(int32_t argc, char** argv) {
case 'n':
loop_nest = strtoul(optarg, nullptr, 0);
break;
+ case 't':
+ try_nest = strtoul(optarg, nullptr, 0);
+ break;
case 'v':
fprintf(stderr, "jfuzz version %s\n", VERSION);
return 0;
@@ -1234,7 +1345,7 @@ int32_t main(int32_t argc, char** argv) {
fprintf(stderr,
"usage: %s [-s seed] "
"[-d expr-depth] [-l stmt-length] "
- "[-i if-nest] [-n loop-nest] [-v] [-h]\n",
+ "[-i if-nest] [-n loop-nest] [-t try-nest] [-v] [-h]\n",
argv[0]);
return 1;
}
@@ -1244,7 +1355,7 @@ int32_t main(int32_t argc, char** argv) {
srand(seed);
// Generate fuzzed program.
- JFuzz fuzz(stdout, seed, expr_depth, stmt_length, if_nest, loop_nest);
+ JFuzz fuzz(stdout, seed, expr_depth, stmt_length, if_nest, loop_nest, try_nest);
fuzz.emitProgram();
return 0;
}
diff --git a/tools/jfuzz/run_dex_fuzz_test.py b/tools/jfuzz/run_dex_fuzz_test.py
index ca0aec01cc..a25ef3fca5 100755
--- a/tools/jfuzz/run_dex_fuzz_test.py
+++ b/tools/jfuzz/run_dex_fuzz_test.py
@@ -41,14 +41,15 @@ from common.common import RunCommand
class DexFuzzTester(object):
"""Tester that feeds JFuzz programs into DexFuzz testing."""
- def __init__(self, num_tests, num_inputs, device, use_dx):
+ def __init__(self, num_tests, num_inputs, device, dexer, debug_info):
"""Constructor for the tester.
Args:
num_tests: int, number of tests to run
num_inputs: int, number of JFuzz programs to generate
device: string, target device serial number (or None)
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
+ debug_info: boolean, if True include debugging info
"""
self._num_tests = num_tests
self._num_inputs = num_inputs
@@ -58,7 +59,8 @@ class DexFuzzTester(object):
self._dexfuzz_dir = None
self._inputs_dir = None
self._dexfuzz_env = None
- self._use_dx = use_dx
+ self._dexer = dexer
+ self._debug_info = debug_info
def __enter__(self):
"""On entry, enters new temp directory after saving current directory.
@@ -109,13 +111,15 @@ class DexFuzzTester(object):
Raises:
FatalError: error when compilation fails
"""
- if self._use_dx:
- if RunCommand(['javac', 'Test.java'],
+ if self._dexer == 'dx' or self._dexer == 'd8':
+ dbg = '-g' if self._debug_info else '-g:none'
+ if RunCommand(['javac', dbg, 'Test.java'],
out=None, err='jerr.txt', timeout=30) != RetCode.SUCCESS:
print('Unexpected error while running javac')
raise FatalError('Unexpected error while running javac')
cfiles = glob('*.class')
- if RunCommand(['dx', '--dex', '--output=classes.dex'] + cfiles,
+ dx = 'dx' if self._dexer == 'dx' else 'd8-compat-dx'
+ if RunCommand([dx, '--dex', '--output=classes.dex'] + cfiles,
out=None, err='dxerr.txt', timeout=30) != RetCode.SUCCESS:
print('Unexpected error while running dx')
raise FatalError('Unexpected error while running dx')
@@ -124,7 +128,8 @@ class DexFuzzTester(object):
os.unlink(cfile)
os.unlink('jerr.txt')
os.unlink('dxerr.txt')
- else:
+
+ elif self._dexer == 'jack':
jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.', 'Test.java']
if RunCommand(['jack'] + jack_args, out=None, err='jackerr.txt',
timeout=30) != RetCode.SUCCESS:
@@ -132,6 +137,8 @@ class DexFuzzTester(object):
raise FatalError('Unexpected error while running Jack')
# Cleanup on success (nothing to see).
os.unlink('jackerr.txt')
+ else:
+ raise FatalError('Unknown dexer: ' + self._dexer)
def GenerateJFuzzPrograms(self):
"""Generates JFuzz programs.
@@ -175,16 +182,21 @@ class DexFuzzTester(object):
def main():
# Handle arguments.
parser = argparse.ArgumentParser()
- parser.add_argument('--num_tests', default=1000,
- type=int, help='number of tests to run')
- parser.add_argument('--num_inputs', default=10,
- type=int, help='number of JFuzz program to generate')
- parser.add_argument('--use_dx', default=False, action='store_true',
- help='use dx (rather than jack)')
+ parser.add_argument('--num_tests', default=1000, type=int,
+ help='number of tests to run (default: 1000)')
+ parser.add_argument('--num_inputs', default=10, type=int,
+ help='number of JFuzz program to generate (default: 10)')
parser.add_argument('--device', help='target device serial number')
+ parser.add_argument('--dexer', default='dx', type=str,
+ help='defines dexer as dx, d8, or jack (default: dx)')
+ parser.add_argument('--debug_info', default=False, action='store_true',
+ help='include debugging info')
args = parser.parse_args()
# Run the DexFuzz tester.
- with DexFuzzTester(args.num_tests, args.num_inputs, args.device, args.use_dx) as fuzzer:
+ with DexFuzzTester(args.num_tests,
+ args.num_inputs,
+ args.device,
+ args.dexer, args.debug_info) as fuzzer:
fuzzer.Run()
if __name__ == '__main__':
diff --git a/tools/jfuzz/run_jfuzz_test.py b/tools/jfuzz/run_jfuzz_test.py
index dac1c79817..34180d993f 100755
--- a/tools/jfuzz/run_jfuzz_test.py
+++ b/tools/jfuzz/run_jfuzz_test.py
@@ -43,11 +43,12 @@ from common.common import DeviceTestEnv
BISECTABLE_RET_CODES = (RetCode.SUCCESS, RetCode.ERROR, RetCode.TIMEOUT)
-def GetExecutionModeRunner(use_dx, device, mode):
+def GetExecutionModeRunner(dexer, debug_info, device, mode):
"""Returns a runner for the given execution mode.
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
+ debug_info: boolean, if True include debugging info
device: string, target device serial number (or None)
mode: string, execution mode
Returns:
@@ -56,15 +57,15 @@ def GetExecutionModeRunner(use_dx, device, mode):
FatalError: error for unknown execution mode
"""
if mode == 'ri':
- return TestRunnerRIOnHost()
+ return TestRunnerRIOnHost(debug_info)
if mode == 'hint':
- return TestRunnerArtIntOnHost(use_dx)
+ return TestRunnerArtIntOnHost(dexer, debug_info)
if mode == 'hopt':
- return TestRunnerArtOptOnHost(use_dx)
+ return TestRunnerArtOptOnHost(dexer, debug_info)
if mode == 'tint':
- return TestRunnerArtIntOnTarget(use_dx, device)
+ return TestRunnerArtIntOnTarget(dexer, debug_info, device)
if mode == 'topt':
- return TestRunnerArtOptOnTarget(use_dx, device)
+ return TestRunnerArtOptOnTarget(dexer, debug_info, device)
raise FatalError('Unknown execution mode')
@@ -117,33 +118,47 @@ class TestRunner(object):
class TestRunnerWithHostCompilation(TestRunner):
"""Abstract test runner that supports compilation on host."""
- def __init__(self, use_dx):
+ def __init__(self, dexer, debug_info):
"""Constructor for the runner with host compilation.
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
+ debug_info: boolean, if True include debugging info
"""
+ self._dexer = dexer
+ self._debug_info = debug_info
self._jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.',
'Test.java']
- self._use_dx = use_dx
def CompileOnHost(self):
- if self._use_dx:
- if RunCommand(['javac', 'Test.java'],
+ if self._dexer == 'dx' or self._dexer == 'd8':
+ dbg = '-g' if self._debug_info else '-g:none'
+ if RunCommand(['javac', dbg, 'Test.java'],
out=None, err=None, timeout=30) == RetCode.SUCCESS:
- retc = RunCommand(['dx', '--dex', '--output=classes.dex'] + glob('*.class'),
+ dx = 'dx' if self._dexer == 'dx' else 'd8-compat-dx'
+ retc = RunCommand([dx, '--dex', '--output=classes.dex'] + glob('*.class'),
out=None, err='dxerr.txt', timeout=30)
else:
retc = RetCode.NOTCOMPILED
- else:
+ elif self._dexer == 'jack':
retc = RunCommand(['jack'] + self._jack_args,
out=None, err='jackerr.txt', timeout=30)
+ else:
+ raise FatalError('Unknown dexer: ' + self._dexer)
return retc
class TestRunnerRIOnHost(TestRunner):
"""Concrete test runner of the reference implementation on host."""
+ def __init__(self, debug_info):
+ """Constructor for the runner with host compilation.
+
+ Args:
+ debug_info: boolean, if True include debugging info
+ """
+ self._debug_info = debug_info
+
@property
def description(self):
return 'RI on host'
@@ -153,7 +168,8 @@ class TestRunnerRIOnHost(TestRunner):
return 'RI'
def CompileAndRunTest(self):
- if RunCommand(['javac', 'Test.java'],
+ dbg = '-g' if self._debug_info else '-g:none'
+ if RunCommand(['javac', dbg, 'Test.java'],
out=None, err=None, timeout=30) == RetCode.SUCCESS:
retc = RunCommand(['java', 'Test'], self.output_file, err=None)
else:
@@ -167,14 +183,15 @@ class TestRunnerRIOnHost(TestRunner):
class TestRunnerArtOnHost(TestRunnerWithHostCompilation):
"""Abstract test runner of Art on host."""
- def __init__(self, use_dx, extra_args=None):
+ def __init__(self, dexer, debug_info, extra_args=None):
"""Constructor for the Art on host tester.
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
+ debug_info: boolean, if True include debugging info
extra_args: list of strings, extra arguments for dalvikvm
"""
- super().__init__(use_dx)
+ super().__init__(dexer, debug_info)
self._art_cmd = ['/bin/bash', 'art', '-cp', 'classes.dex']
if extra_args is not None:
self._art_cmd += extra_args
@@ -191,13 +208,14 @@ class TestRunnerArtOnHost(TestRunnerWithHostCompilation):
class TestRunnerArtIntOnHost(TestRunnerArtOnHost):
"""Concrete test runner of interpreter mode Art on host."""
- def __init__(self, use_dx):
+ def __init__(self, dexer, debug_info):
"""Constructor for the Art on host tester (interpreter).
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
+ debug_info: boolean, if True include debugging info
"""
- super().__init__(use_dx, ['-Xint'])
+ super().__init__(dexer, debug_info, ['-Xint'])
@property
def description(self):
@@ -214,13 +232,14 @@ class TestRunnerArtIntOnHost(TestRunnerArtOnHost):
class TestRunnerArtOptOnHost(TestRunnerArtOnHost):
"""Concrete test runner of optimizing compiler mode Art on host."""
- def __init__(self, use_dx):
+ def __init__(self, dexer, debug_info):
"""Constructor for the Art on host tester (optimizing).
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
+ debug_info: boolean, if True include debugging info
"""
- super().__init__(use_dx, None)
+ super().__init__(dexer, debug_info, None)
@property
def description(self):
@@ -239,15 +258,16 @@ class TestRunnerArtOptOnHost(TestRunnerArtOnHost):
class TestRunnerArtOnTarget(TestRunnerWithHostCompilation):
"""Abstract test runner of Art on target."""
- def __init__(self, use_dx, device, extra_args=None):
+ def __init__(self, dexer, debug_info, device, extra_args=None):
"""Constructor for the Art on target tester.
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
+ debug_info: boolean, if True include debugging info
device: string, target device serial number (or None)
extra_args: list of strings, extra arguments for dalvikvm
"""
- super().__init__(use_dx)
+ super().__init__(dexer, debug_info)
self._test_env = DeviceTestEnv('jfuzz_', specific_device=device)
self._dalvik_cmd = ['dalvikvm']
if extra_args is not None:
@@ -281,14 +301,15 @@ class TestRunnerArtOnTarget(TestRunnerWithHostCompilation):
class TestRunnerArtIntOnTarget(TestRunnerArtOnTarget):
"""Concrete test runner of interpreter mode Art on target."""
- def __init__(self, use_dx, device):
+ def __init__(self, dexer, debug_info, device):
"""Constructor for the Art on target tester (interpreter).
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
+ debug_info: boolean, if True include debugging info
device: string, target device serial number (or None)
"""
- super().__init__(use_dx, device, ['-Xint'])
+ super().__init__(dexer, debug_info, device, ['-Xint'])
@property
def description(self):
@@ -305,14 +326,15 @@ class TestRunnerArtIntOnTarget(TestRunnerArtOnTarget):
class TestRunnerArtOptOnTarget(TestRunnerArtOnTarget):
"""Concrete test runner of optimizing compiler mode Art on target."""
- def __init__(self, use_dx, device):
+ def __init__(self, dexer, debug_info, device):
"""Constructor for the Art on target tester (optimizing).
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
+ debug_info: boolean, if True include debugging info
device: string, target device serial number (or None)
"""
- super().__init__(use_dx, device, None)
+ super().__init__(dexer, debug_info, device, None)
@property
def description(self):
@@ -342,7 +364,7 @@ class JFuzzTester(object):
"""Tester that runs JFuzz many times and report divergences."""
def __init__(self, num_tests, device, mode1, mode2, jfuzz_args,
- report_script, true_divergence_only, use_dx):
+ report_script, true_divergence_only, dexer, debug_info):
"""Constructor for the tester.
Args:
@@ -353,16 +375,18 @@ class JFuzzTester(object):
jfuzz_args: list of strings, additional arguments for jfuzz
report_script: string, path to script called for each divergence
true_divergence_only: boolean, if True don't bisect timeout divergences
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
+ debug_info: boolean, if True include debugging info
"""
self._num_tests = num_tests
self._device = device
- self._runner1 = GetExecutionModeRunner(use_dx, device, mode1)
- self._runner2 = GetExecutionModeRunner(use_dx, device, mode2)
+ self._runner1 = GetExecutionModeRunner(dexer, debug_info, device, mode1)
+ self._runner2 = GetExecutionModeRunner(dexer, debug_info, device, mode2)
self._jfuzz_args = jfuzz_args
self._report_script = report_script
self._true_divergence_only = true_divergence_only
- self._use_dx = use_dx
+ self._dexer = dexer
+ self._debug_info = debug_info
self._save_dir = None
self._results_dir = None
self._jfuzz_dir = None
@@ -405,7 +429,8 @@ class JFuzzTester(object):
print('Directory :', self._results_dir)
print('Exec-mode1:', self._runner1.description)
print('Exec-mode2:', self._runner2.description)
- print('Compiler :', 'dx' if self._use_dx else 'jack')
+ print('Dexer :', self._dexer)
+ print('Debug-info:', self._debug_info)
print()
self.ShowStats()
for self._test in range(1, self._num_tests + 1):
@@ -525,8 +550,8 @@ class JFuzzTester(object):
for arg in jfuzz_cmd_str.strip().split(' -')][1:]
wrapped_args = ['--jfuzz_arg={0}'.format(opt) for opt in jfuzz_args]
repro_cmd_str = (os.path.basename(__file__) +
- ' --num_tests=1 ' +
- ('--use_dx ' if self._use_dx else '') +
+ ' --num_tests=1 --dexer=' + self._dexer +
+ (' --debug_info ' if self._debug_info else ' ') +
' '.join(wrapped_args))
comment = 'jfuzz {0}\nReproduce test:\n{1}\nReproduce divergence:\n{2}\n'.format(
jfuzz_ver, jfuzz_cmd_str, repro_cmd_str)
@@ -592,29 +617,36 @@ class JFuzzTester(object):
def main():
# Handle arguments.
parser = argparse.ArgumentParser()
- parser.add_argument('--num_tests', default=10000,
- type=int, help='number of tests to run')
+ parser.add_argument('--num_tests', default=10000, type=int,
+ help='number of tests to run')
parser.add_argument('--device', help='target device serial number')
parser.add_argument('--mode1', default='ri',
help='execution mode 1 (default: ri)')
parser.add_argument('--mode2', default='hopt',
help='execution mode 2 (default: hopt)')
- parser.add_argument('--report_script', help='script called for each'
- ' divergence')
+ parser.add_argument('--report_script',
+ help='script called for each divergence')
parser.add_argument('--jfuzz_arg', default=[], dest='jfuzz_args',
- action='append', help='argument for jfuzz')
+ action='append',
+ help='argument for jfuzz')
parser.add_argument('--true_divergence', default=False, action='store_true',
- help='don\'t bisect timeout divergences')
- parser.add_argument('--use_dx', default=False, action='store_true',
- help='use dx (rather than jack)')
+ help='do not bisect timeout divergences')
+ parser.add_argument('--dexer', default='dx', type=str,
+ help='defines dexer as dx, d8, or jack (default: dx)')
+ parser.add_argument('--debug_info', default=False, action='store_true',
+ help='include debugging info')
args = parser.parse_args()
if args.mode1 == args.mode2:
raise FatalError('Identical execution modes given')
# Run the JFuzz tester.
with JFuzzTester(args.num_tests,
- args.device, args.mode1, args.mode2,
- args.jfuzz_args, args.report_script,
- args.true_divergence, args.use_dx) as fuzzer:
+ args.device,
+ args.mode1, args.mode2,
+ args.jfuzz_args,
+ args.report_script,
+ args.true_divergence,
+ args.dexer,
+ args.debug_info) as fuzzer:
fuzzer.Run()
if __name__ == '__main__':
diff --git a/tools/libjdwp_art_failures.txt b/tools/prebuilt_libjdwp_art_failures.txt
index abcc728890..7694a4c7e4 100644
--- a/tools/libjdwp_art_failures.txt
+++ b/tools/prebuilt_libjdwp_art_failures.txt
@@ -1,6 +1,9 @@
/*
* This file contains expectations for ART's buildbot. The purpose of this file is
* to temporarily list failing tests and not break the bots.
+ *
+ * This file contains the expectations for the 'prebuilt-libjdwp-aot' and
+ * 'prebuilt-libjdwp-jit' test groups on the chromium buildbot.
*/
[
{
@@ -64,6 +67,12 @@
"org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierTest#testMethodExit",
"org.apache.harmony.jpda.tests.jdwp.EventModifiers.InstanceOnlyModifierTest#testMethodExitWithReturnValue" ]
},
+{
+ description: "Tests for VMDebug functionality not implemented in the upstream libjdwp",
+ result: EXEC_FAILED,
+ names: [ "org.apache.harmony.jpda.tests.jdwp.VMDebug.VMDebugTest#testVMDebug",
+ "org.apache.harmony.jpda.tests.jdwp.VMDebug.VMDebugTest002#testVMDebug" ]
+},
/* TODO Categorize these failures more. */
{
description: "Tests that fail on both ART and RI. These tests are likely incorrect",
diff --git a/tools/run-libjdwp-tests.sh b/tools/run-libjdwp-tests.sh
index 47e7c4595d..e116facd98 100755
--- a/tools/run-libjdwp-tests.sh
+++ b/tools/run-libjdwp-tests.sh
@@ -79,7 +79,7 @@ else
args+=(-Xplugin:libopenjdkjvmti.so)
fi
-expect_path=$PWD/art/tools/libjdwp_oj_art_failures.txt
+expect_path=$PWD/art/tools/external_oj_libjdwp_art_failures.txt
function verbose_run() {
echo "$@"
env "$@"
diff --git a/tools/run-prebuilt-libjdwp-tests.sh b/tools/run-prebuilt-libjdwp-tests.sh
index 46c2a153a7..e7f028ae63 100755
--- a/tools/run-prebuilt-libjdwp-tests.sh
+++ b/tools/run-prebuilt-libjdwp-tests.sh
@@ -96,7 +96,7 @@ if [[ ! -f $plugin ]]; then
fi
props_path=$PWD/art/tools/libjdwp-compat.props
-expect_path=$PWD/art/tools/libjdwp_art_failures.txt
+expect_path=$PWD/art/tools/prebuilt_libjdwp_art_failures.txt
function verbose_run() {
echo "$@"
diff --git a/tools/titrace/instruction_decoder.cc b/tools/titrace/instruction_decoder.cc
index bc4660b497..d8fb713414 100644
--- a/tools/titrace/instruction_decoder.cc
+++ b/tools/titrace/instruction_decoder.cc
@@ -15,7 +15,7 @@
#include "instruction_decoder.h"
-#include "dex_instruction_list.h"
+#include "dex/dex_instruction_list.h"
#include <android-base/logging.h>