diff options
174 files changed, 4556 insertions, 3443 deletions
diff --git a/build/Android.common.mk b/build/Android.common.mk index bfb1f9b89b..82097250f9 100644 --- a/build/Android.common.mk +++ b/build/Android.common.mk @@ -14,6 +14,9 @@ # limitations under the License. # +ifndef ANDROID_COMMON_MK +ANDROID_COMMON_MK = true + # These can be overridden via the environment or by editing to # enable/disable certain build configuration. # @@ -163,11 +166,8 @@ ifneq ($(filter 4.6 4.6.%, $(TARGET_GCC_VERSION)),) else # Warn if not using GCC 4.6 for target builds when not doing a top-level or 'mma' build. ifneq ($(ONE_SHOT_MAKEFILE),) - ifneq ($(ART_THREAD_SAFETY_CHECK_WARNING),true) - # Enable target GCC 4.6 with: export TARGET_GCC_VERSION_EXP=4.6 - $(info Using target GCC $(TARGET_GCC_VERSION) disables thread-safety checks.) - ART_THREAD_SAFETY_CHECK_WARNING := true - endif + # Enable target GCC 4.6 with: export TARGET_GCC_VERSION_EXP=4.6 + $(info Using target GCC $(TARGET_GCC_VERSION) disables thread-safety checks.) endif endif # We build with GCC 4.6 on the host. @@ -219,3 +219,5 @@ ifeq ($(ART_BUILD_HOST_DEBUG),true) ART_BUILD_HOST := true ART_BUILD_DEBUG := true endif + +endif # ANDROID_COMMON_MK diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index ee1115a0dd..e069d88f19 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -17,6 +17,11 @@ LOCAL_PATH := art TEST_COMMON_SRC_FILES := \ + compiler/driver/compiler_driver_test.cc \ + compiler/elf_writer_test.cc \ + compiler/jni/jni_compiler_test.cc \ + compiler/utils/arm/managed_register_arm_test.cc \ + compiler/utils/x86/managed_register_x86_test.cc \ runtime/barrier_test.cc \ runtime/base/histogram_test.cc \ runtime/base/mutex_test.cc \ @@ -29,6 +34,7 @@ TEST_COMMON_SRC_FILES := \ runtime/dex_file_test.cc \ runtime/dex_instruction_visitor_test.cc \ runtime/dex_method_iterator_test.cc \ + runtime/entrypoints/math_entrypoints_test.cc \ runtime/exception_test.cc \ runtime/gc/accounting/space_bitmap_test.cc \ runtime/gc/heap_test.cc \ @@ -42,21 +48,15 @@ TEST_COMMON_SRC_FILES := \ runtime/mem_map_test.cc \ runtime/mirror/dex_cache_test.cc \ runtime/mirror/object_test.cc \ - runtime/oat/utils/arm/managed_register_arm_test.cc \ - runtime/oat/utils/x86/managed_register_x86_test.cc \ runtime/oat_test.cc \ runtime/output_stream_test.cc \ runtime/reference_table_test.cc \ - runtime/runtime_support_test.cc \ runtime/runtime_test.cc \ runtime/thread_pool_test.cc \ runtime/utils_test.cc \ runtime/verifier/method_verifier_test.cc \ runtime/verifier/reg_type_test.cc \ - runtime/zip_archive_test.cc \ - compiler/driver/compiler_driver_test.cc \ - compiler/elf_writer_test.cc \ - compiler/jni/jni_compiler_test.cc + runtime/zip_archive_test.cc ifeq ($(ART_SEA_IR_MODE),true) TEST_COMMON_SRC_FILES += \ @@ -68,7 +68,7 @@ TEST_TARGET_SRC_FILES := \ TEST_HOST_SRC_FILES := \ $(TEST_COMMON_SRC_FILES) \ - runtime/oat/utils/x86/assembler_x86_test.cc + compiler/utils/x86/assembler_x86_test.cc ART_HOST_TEST_EXECUTABLES := ART_TARGET_TEST_EXECUTABLES := diff --git a/compiler/Android.mk b/compiler/Android.mk index 9f250225ba..df77853abf 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -76,12 +76,20 @@ LIBART_COMPILER_SRC_FILES := \ llvm/runtime_support_builder_x86.cc \ stubs/portable/stubs.cc \ stubs/quick/stubs.cc \ + utils/arm/assembler_arm.cc \ + utils/arm/managed_register_arm.cc \ + utils/assembler.cc \ + utils/mips/assembler_mips.cc \ + utils/mips/managed_register_mips.cc \ + utils/x86/assembler_x86.cc \ + utils/x86/managed_register_x86.cc \ elf_fixup.cc \ elf_stripper.cc \ elf_writer.cc \ elf_writer_quick.cc \ image_writer.cc \ - oat_writer.cc + oat_writer.cc \ + vector_output_stream.cc ifeq ($(ART_SEA_IR_MODE),true) LIBART_COMPILER_SRC_FILES += \ diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 3c491ce20f..1ee29cbae1 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -36,9 +36,11 @@ const bool kEnableCheckCastEllision = true; class DexCompiler { public: DexCompiler(art::CompilerDriver& compiler, - const DexCompilationUnit& unit) + const DexCompilationUnit& unit, + DexToDexCompilationLevel dex_to_dex_compilation_level) : driver_(compiler), - unit_(unit) {} + unit_(unit), + dex_to_dex_compilation_level_(dex_to_dex_compilation_level) {} ~DexCompiler() {} @@ -55,6 +57,10 @@ class DexCompiler { return *const_cast<DexFile*>(unit_.GetDexFile()); } + bool PerformOptimizations() const { + return dex_to_dex_compilation_level_ >= kOptimize; + } + // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where // a barrier is required. void CompileReturnVoid(Instruction* inst, uint32_t dex_pc); @@ -84,6 +90,7 @@ class DexCompiler { CompilerDriver& driver_; const DexCompilationUnit& unit_; + const DexToDexCompilationLevel dex_to_dex_compilation_level_; DISALLOW_COPY_AND_ASSIGN(DexCompiler); }; @@ -138,6 +145,7 @@ class ScopedDexWriteAccess { }; void DexCompiler::Compile() { + DCHECK_GE(dex_to_dex_compilation_level_, kRequired); const DexFile::CodeItem* code_item = unit_.GetCodeItem(); const uint16_t* insns = code_item->insns_; const uint32_t insns_size = code_item->insns_size_in_code_units_; @@ -220,7 +228,7 @@ void DexCompiler::CompileReturnVoid(Instruction* inst, uint32_t dex_pc) { } Instruction* DexCompiler::CompileCheckCast(Instruction* inst, uint32_t dex_pc) { - if (!kEnableCheckCastEllision) { + if (!kEnableCheckCastEllision || !PerformOptimizations()) { return inst; } MethodReference referrer(&GetDexFile(), unit_.GetDexMethodIndex()); @@ -253,7 +261,7 @@ void DexCompiler::CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc, Instruction::Code new_opcode, bool is_put) { - if (!kEnableQuickening) { + if (!kEnableQuickening || !PerformOptimizations()) { return; } uint32_t field_idx = inst->VRegC_22c(); @@ -280,7 +288,7 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc, Instruction::Code new_opcode, bool is_range) { - if (!kEnableQuickening) { + if (!kEnableQuickening || !PerformOptimizations()) { return; } uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); @@ -320,14 +328,15 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, } // namespace optimizer } // namespace art -extern "C" art::CompiledMethod* - ArtCompileDEX(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, +extern "C" void ArtCompileDEX(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, - const art::DexFile& dex_file) { - art::DexCompilationUnit unit(NULL, class_loader, art::Runtime::Current()->GetClassLinker(), - dex_file, code_item, class_def_idx, method_idx, access_flags); - art::optimizer::DexCompiler dex_compiler(compiler, unit); - dex_compiler.Compile(); - return NULL; + const art::DexFile& dex_file, + art::DexToDexCompilationLevel dex_to_dex_compilation_level) { + if (dex_to_dex_compilation_level != art::kDontDexToDexCompile) { + art::DexCompilationUnit unit(NULL, class_loader, art::Runtime::Current()->GetClassLinker(), + dex_file, code_item, class_def_idx, method_idx, access_flags); + art::optimizer::DexCompiler dex_compiler(compiler, unit, dex_to_dex_compilation_level); + dex_compiler.Compile(); + } } diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index 64ebb6abbd..745e43dc38 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -19,7 +19,7 @@ #include "arm_lir.h" #include "codegen_arm.h" #include "dex/quick/mir_to_lir-inl.h" -#include "oat/runtime/oat_support_entrypoints.h" +#include "entrypoints/quick/quick_entrypoints.h" namespace art { @@ -432,7 +432,7 @@ void ArmMir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { // Making a call - use explicit registers FlushAllRegs(); /* Everything to home location */ LoadValueDirectFixed(rl_src, r0); - LoadWordDisp(rARM_SELF, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode), + LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode), rARM_LR); // Materialize a pointer to the fill data image NewLIR3(kThumb2Adr, r1, 0, reinterpret_cast<uintptr_t>(tab_rec)); @@ -488,7 +488,7 @@ void ArmMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { OpRegImm(kOpCmp, r1, 0); OpIT(kCondNe, "T"); // Go expensive route - artLockObjectFromCode(self, obj); - LoadWordDisp(rARM_SELF, ENTRYPOINT_OFFSET(pLockObjectFromCode), rARM_LR); + LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pLockObjectFromCode), rARM_LR); ClobberCalleeSave(); LIR* call_inst = OpReg(kOpBlx, rARM_LR); MarkSafepointPC(call_inst); @@ -519,7 +519,7 @@ void ArmMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { OpIT(kCondEq, "EE"); StoreWordDisp(r0, mirror::Object::MonitorOffset().Int32Value(), r3); // Go expensive route - UnlockObjectFromCode(obj); - LoadWordDisp(rARM_SELF, ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rARM_LR); + LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rARM_LR); ClobberCalleeSave(); LIR* call_inst = OpReg(kOpBlx, rARM_LR); MarkSafepointPC(call_inst); diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc index 1bb08c45e3..08d6778129 100644 --- a/compiler/dex/quick/arm/fp_arm.cc +++ b/compiler/dex/quick/arm/fp_arm.cc @@ -49,7 +49,8 @@ void ArmMir2Lir::GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest, case Instruction::REM_FLOAT_2ADDR: case Instruction::REM_FLOAT: FlushAllRegs(); // Send everything to home location - CallRuntimeHelperRegLocationRegLocation(ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, false); + CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, + false); rl_result = GetReturn(true); StoreValue(rl_dest, rl_result); return; @@ -91,7 +92,8 @@ void ArmMir2Lir::GenArithOpDouble(Instruction::Code opcode, case Instruction::REM_DOUBLE_2ADDR: case Instruction::REM_DOUBLE: FlushAllRegs(); // Send everything to home location - CallRuntimeHelperRegLocationRegLocation(ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2, false); + CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2, + false); rl_result = GetReturnWide(true); StoreValueWide(rl_dest, rl_result); return; @@ -140,16 +142,16 @@ void ArmMir2Lir::GenConversion(Instruction::Code opcode, op = kThumb2VcvtDI; break; case Instruction::LONG_TO_DOUBLE: - GenConversionCall(ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src); return; case Instruction::FLOAT_TO_LONG: - GenConversionCall(ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src); return; case Instruction::LONG_TO_FLOAT: - GenConversionCall(ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src); return; case Instruction::DOUBLE_TO_LONG: - GenConversionCall(ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src); return; default: LOG(FATAL) << "Unexpected opcode: " << opcode; @@ -315,7 +317,7 @@ bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) { branch = NewLIR2(kThumbBCond, 0, kArmCondEq); ClobberCalleeSave(); LockCallTemps(); // Using fixed registers - int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pSqrt)); + int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pSqrt)); NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg)); NewLIR1(kThumbBlxR, r_tgt); NewLIR3(kThumb2Fmdrr, S2d(rl_result.low_reg, rl_result.high_reg), r0, r1); diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index e1a77daba9..9db1016efa 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -19,8 +19,8 @@ #include "arm_lir.h" #include "codegen_arm.h" #include "dex/quick/mir_to_lir-inl.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "mirror/array.h" -#include "oat/runtime/oat_support_entrypoints.h" namespace art { @@ -665,7 +665,7 @@ void ArmMir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1, */ RegLocation rl_result; if (BadOverlap(rl_src1, rl_dest) || (BadOverlap(rl_src2, rl_dest))) { - int func_offset = ENTRYPOINT_OFFSET(pLmul); + int func_offset = QUICK_ENTRYPOINT_OFFSET(pLmul); FlushAllRegs(); CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_src2, false); rl_result = GetReturnWide(false); @@ -956,7 +956,7 @@ void ArmMir2Lir::GenArrayObjPut(int opt_flags, RegLocation rl_array, // Get the array's class. LoadWordDisp(r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class); - CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value, + CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value, r_array_class, true); // Redo LoadValues in case they didn't survive the call. LoadValueDirectFixed(rl_array, r_array); // Reload array diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 40db2c69d9..ebe10bb57e 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -17,8 +17,8 @@ #include "dex/compiler_ir.h" #include "dex/compiler_internals.h" #include "dex/quick/mir_to_lir-inl.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "mirror/array.h" -#include "oat/runtime/oat_support_entrypoints.h" #include "verifier/method_verifier.h" namespace art { @@ -211,9 +211,9 @@ void Mir2Lir::GenNewArray(uint32_t type_idx, RegLocation rl_dest, int func_offset; if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file, type_idx)) { - func_offset = ENTRYPOINT_OFFSET(pAllocArrayFromCode); + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArrayFromCode); } else { - func_offset= ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck); + func_offset= QUICK_ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck); } CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true); RegLocation rl_result = GetReturn(false); @@ -233,9 +233,9 @@ void Mir2Lir::GenFilledNewArray(CallInfo* info) { int func_offset; if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file, type_idx)) { - func_offset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode); + func_offset = QUICK_ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode); } else { - func_offset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck); + func_offset = QUICK_ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck); } CallRuntimeHelperImmMethodImm(func_offset, type_idx, elems, true); FreeTemp(TargetReg(kArg2)); @@ -375,7 +375,7 @@ void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_do // TUNING: fast path should fall through LIR* branch_over = OpCmpImmBranch(kCondNe, rBase, 0, NULL); LoadConstant(TargetReg(kArg0), ssb_index); - CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true); + CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true); if (cu_->instruction_set == kMips) { // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy OpRegCopy(rBase, TargetReg(kRet0)); @@ -408,9 +408,9 @@ void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_do FreeTemp(rBase); } else { FlushAllRegs(); // Everything to home locations - int setter_offset = is_long_or_double ? ENTRYPOINT_OFFSET(pSet64Static) : - (is_object ? ENTRYPOINT_OFFSET(pSetObjStatic) - : ENTRYPOINT_OFFSET(pSet32Static)); + int setter_offset = is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pSet64Static) : + (is_object ? QUICK_ENTRYPOINT_OFFSET(pSetObjStatic) + : QUICK_ENTRYPOINT_OFFSET(pSet32Static)); CallRuntimeHelperImmRegLocation(setter_offset, field_idx, rl_src, true); } } @@ -455,7 +455,7 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest, // or NULL if not initialized. Check for NULL and call helper if NULL. // TUNING: fast path should fall through LIR* branch_over = OpCmpImmBranch(kCondNe, rBase, 0, NULL); - CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true); + CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true); if (cu_->instruction_set == kMips) { // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy OpRegCopy(rBase, TargetReg(kRet0)); @@ -483,9 +483,9 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest, } } else { FlushAllRegs(); // Everything to home locations - int getterOffset = is_long_or_double ? ENTRYPOINT_OFFSET(pGet64Static) : - (is_object ? ENTRYPOINT_OFFSET(pGetObjStatic) - : ENTRYPOINT_OFFSET(pGet32Static)); + int getterOffset = is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pGet64Static) : + (is_object ? QUICK_ENTRYPOINT_OFFSET(pGetObjStatic) + : QUICK_ENTRYPOINT_OFFSET(pGet32Static)); CallRuntimeHelperImm(getterOffset, field_idx, true); if (is_long_or_double) { RegLocation rl_result = GetReturnWide(rl_dest.fp); @@ -499,7 +499,7 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest, void Mir2Lir::HandleSuspendLaunchPads() { int num_elems = suspend_launchpads_.Size(); - int helper_offset = ENTRYPOINT_OFFSET(pTestSuspendFromCode); + int helper_offset = QUICK_ENTRYPOINT_OFFSET(pTestSuspendFromCode); for (int i = 0; i < num_elems; i++) { ResetRegPool(); ResetDefTracking(); @@ -545,7 +545,7 @@ void Mir2Lir::HandleThrowLaunchPads() { bool target_x86 = (cu_->instruction_set == kX86); switch (lab->operands[0]) { case kThrowNullPointer: - func_offset = ENTRYPOINT_OFFSET(pThrowNullPointerFromCode); + func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowNullPointerFromCode); break; case kThrowConstantArrayBounds: // v1 is length reg (for Arm/Mips), v2 constant index // v1 holds the constant array index. Mips/Arm uses v2 for length, x86 reloads. @@ -557,7 +557,7 @@ void Mir2Lir::HandleThrowLaunchPads() { // Make sure the following LoadConstant doesn't mess with kArg1. LockTemp(TargetReg(kArg1)); LoadConstant(TargetReg(kArg0), v2); - func_offset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode); + func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode); break; case kThrowArrayBounds: // Move v1 (array index) to kArg0 and v2 (array length) to kArg1 @@ -590,18 +590,18 @@ void Mir2Lir::HandleThrowLaunchPads() { OpRegCopy(TargetReg(kArg0), v1); } } - func_offset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode); + func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode); break; case kThrowDivZero: - func_offset = ENTRYPOINT_OFFSET(pThrowDivZeroFromCode); + func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowDivZeroFromCode); break; case kThrowNoSuchMethod: OpRegCopy(TargetReg(kArg0), v1); func_offset = - ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode); + QUICK_ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode); break; case kThrowStackOverflow: - func_offset = ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode); + func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode); // Restore stack alignment if (target_x86) { OpRegImm(kOpAdd, TargetReg(kSp), frame_size_); @@ -664,9 +664,9 @@ void Mir2Lir::GenIGet(uint32_t field_idx, int opt_flags, OpSize size, StoreValue(rl_dest, rl_result); } } else { - int getterOffset = is_long_or_double ? ENTRYPOINT_OFFSET(pGet64Instance) : - (is_object ? ENTRYPOINT_OFFSET(pGetObjInstance) - : ENTRYPOINT_OFFSET(pGet32Instance)); + int getterOffset = is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pGet64Instance) : + (is_object ? QUICK_ENTRYPOINT_OFFSET(pGetObjInstance) + : QUICK_ENTRYPOINT_OFFSET(pGet32Instance)); CallRuntimeHelperImmRegLocation(getterOffset, field_idx, rl_obj, true); if (is_long_or_double) { RegLocation rl_result = GetReturnWide(rl_dest.fp); @@ -719,9 +719,9 @@ void Mir2Lir::GenIPut(uint32_t field_idx, int opt_flags, OpSize size, } } } else { - int setter_offset = is_long_or_double ? ENTRYPOINT_OFFSET(pSet64Instance) : - (is_object ? ENTRYPOINT_OFFSET(pSetObjInstance) - : ENTRYPOINT_OFFSET(pSet32Instance)); + int setter_offset = is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pSet64Instance) : + (is_object ? QUICK_ENTRYPOINT_OFFSET(pSetObjInstance) + : QUICK_ENTRYPOINT_OFFSET(pSet32Instance)); CallRuntimeHelperImmRegLocationRegLocation(setter_offset, field_idx, rl_obj, rl_src, true); } } @@ -735,7 +735,7 @@ void Mir2Lir::GenConstClass(uint32_t type_idx, RegLocation rl_dest) { type_idx)) { // Call out to helper which resolves type and verifies access. // Resolved type returned in kRet0. - CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode), + CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode), type_idx, rl_method.low_reg, true); RegLocation rl_result = GetReturn(false); StoreValue(rl_dest, rl_result); @@ -764,7 +764,7 @@ void Mir2Lir::GenConstClass(uint32_t type_idx, RegLocation rl_dest) { // TUNING: move slow path to end & remove unconditional branch LIR* target1 = NewLIR0(kPseudoTargetLabel); // Call out to helper, which will return resolved type in kArg0 - CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, + CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, rl_method.low_reg, true); RegLocation rl_result = GetReturn(false); StoreValue(rl_dest, rl_result); @@ -797,7 +797,7 @@ void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) { LoadWordDisp(TargetReg(kArg2), mirror::AbstractMethod::DexCacheStringsOffset().Int32Value(), TargetReg(kArg0)); // Might call out to helper, which will return resolved string in kRet0 - int r_tgt = CallHelperSetup(ENTRYPOINT_OFFSET(pResolveStringFromCode)); + int r_tgt = CallHelperSetup(QUICK_ENTRYPOINT_OFFSET(pResolveStringFromCode)); LoadWordDisp(TargetReg(kArg0), offset_of_string, TargetReg(kRet0)); LoadConstant(TargetReg(kArg1), string_idx); if (cu_->instruction_set == kThumb2) { @@ -821,7 +821,8 @@ void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) { branch->target = target; } else { DCHECK_EQ(cu_->instruction_set, kX86); - CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pResolveStringFromCode), TargetReg(kArg2), TargetReg(kArg1), true); + CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pResolveStringFromCode), TargetReg(kArg2), + TargetReg(kArg1), true); } GenBarrier(); StoreValue(rl_dest, GetReturn(false)); @@ -847,9 +848,9 @@ void Mir2Lir::GenNewInstance(uint32_t type_idx, RegLocation rl_dest) { int func_offset; if (cu_->compiler_driver->CanAccessInstantiableTypeWithoutChecks( cu_->method_idx, *cu_->dex_file, type_idx)) { - func_offset = ENTRYPOINT_OFFSET(pAllocObjectFromCode); + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectFromCode); } else { - func_offset = ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck); + func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck); } CallRuntimeHelperImmMethod(func_offset, type_idx, true); RegLocation rl_result = GetReturn(false); @@ -858,7 +859,7 @@ void Mir2Lir::GenNewInstance(uint32_t type_idx, RegLocation rl_dest) { void Mir2Lir::GenThrow(RegLocation rl_src) { FlushAllRegs(); - CallRuntimeHelperRegLocation(ENTRYPOINT_OFFSET(pDeliverException), rl_src, true); + CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(pDeliverException), rl_src, true); } // For final classes there are no sub-classes to check and so we can answer the instance-of @@ -928,7 +929,7 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know if (needs_access_check) { // Check we have access to type_idx and if not throw IllegalAccessError, // returns Class* in kArg0 - CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode), + CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode), type_idx, true); OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref @@ -950,7 +951,7 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL); // Not resolved // Call out to helper, which will return resolved type in kRet0 - CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, true); + CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, true); OpRegCopy(TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path LoadValueDirectFixed(rl_src, TargetReg(kArg0)); /* reload Ref */ // Rejoin code paths @@ -985,7 +986,7 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know } } else { if (cu_->instruction_set == kThumb2) { - int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode)); + int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode)); if (!type_known_abstract) { /* Uses conditional nullification */ OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same? @@ -1002,13 +1003,13 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL); } if (cu_->instruction_set != kX86) { - int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode)); + int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode)); OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class) FreeTemp(r_tgt); } else { OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); - OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode)); + OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode)); } } } @@ -1068,7 +1069,7 @@ void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_ // Check we have access to type_idx and if not throw IllegalAccessError, // returns Class* in kRet0 // InitializeTypeAndVerifyAccess(idx, method) - CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode), + CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode), type_idx, TargetReg(kArg1), true); OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path } else if (use_declaring_class) { @@ -1088,8 +1089,8 @@ void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_ // Not resolved // Call out to helper, which will return resolved type in kArg0 // InitializeTypeFromCode(idx, method) - CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, TargetReg(kArg1), - true); + CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, + TargetReg(kArg1), true); OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path // Rejoin code paths LIR* hop_target = NewLIR0(kPseudoTargetLabel); @@ -1108,8 +1109,8 @@ void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_ if (!type_known_abstract) { branch2 = OpCmpBranch(kCondEq, TargetReg(kArg1), class_reg, NULL); } - CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2), - true); + CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), + TargetReg(kArg2), true); /* branch target here */ LIR* target = NewLIR0(kPseudoTargetLabel); branch1->target = target; @@ -1172,15 +1173,15 @@ void Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest, switch (opcode) { case Instruction::SHL_LONG: case Instruction::SHL_LONG_2ADDR: - func_offset = ENTRYPOINT_OFFSET(pShlLong); + func_offset = QUICK_ENTRYPOINT_OFFSET(pShlLong); break; case Instruction::SHR_LONG: case Instruction::SHR_LONG_2ADDR: - func_offset = ENTRYPOINT_OFFSET(pShrLong); + func_offset = QUICK_ENTRYPOINT_OFFSET(pShrLong); break; case Instruction::USHR_LONG: case Instruction::USHR_LONG_2ADDR: - func_offset = ENTRYPOINT_OFFSET(pUshrLong); + func_offset = QUICK_ENTRYPOINT_OFFSET(pUshrLong); break; default: LOG(FATAL) << "Unexpected case"; @@ -1302,7 +1303,7 @@ void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, } rl_result = GenDivRem(rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv); } else { - int func_offset = ENTRYPOINT_OFFSET(pIdivmod); + int func_offset = QUICK_ENTRYPOINT_OFFSET(pIdivmod); FlushAllRegs(); /* Send everything to home location */ LoadValueDirectFixed(rl_src2, TargetReg(kArg1)); int r_tgt = CallHelperSetup(func_offset); @@ -1557,7 +1558,7 @@ void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, Re FlushAllRegs(); /* Everything to home location */ LoadValueDirectFixed(rl_src, TargetReg(kArg0)); Clobber(TargetReg(kArg0)); - int func_offset = ENTRYPOINT_OFFSET(pIdivmod); + int func_offset = QUICK_ENTRYPOINT_OFFSET(pIdivmod); CallRuntimeHelperRegImm(func_offset, TargetReg(kArg0), lit, false); if (is_div) rl_result = GetReturn(false); @@ -1634,7 +1635,7 @@ void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, } else { call_out = true; ret_reg = TargetReg(kRet0); - func_offset = ENTRYPOINT_OFFSET(pLmul); + func_offset = QUICK_ENTRYPOINT_OFFSET(pLmul); } break; case Instruction::DIV_LONG: @@ -1642,13 +1643,13 @@ void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, call_out = true; check_zero = true; ret_reg = TargetReg(kRet0); - func_offset = ENTRYPOINT_OFFSET(pLdiv); + func_offset = QUICK_ENTRYPOINT_OFFSET(pLdiv); break; case Instruction::REM_LONG: case Instruction::REM_LONG_2ADDR: call_out = true; check_zero = true; - func_offset = ENTRYPOINT_OFFSET(pLdivmod); + func_offset = QUICK_ENTRYPOINT_OFFSET(pLdivmod); /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */ ret_reg = (cu_->instruction_set == kThumb2) ? TargetReg(kArg2) : TargetReg(kRet0); break; diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index cae13190ec..1b34e99a72 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -16,11 +16,11 @@ #include "dex/compiler_ir.h" #include "dex_file-inl.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "invoke_type.h" #include "mirror/array.h" #include "mirror/string.h" #include "mir_to_lir-inl.h" -#include "oat/runtime/oat_support_entrypoints.h" #include "x86/codegen_x86.h" namespace art { @@ -471,7 +471,7 @@ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state, direct_method = 0; } int trampoline = (cu->instruction_set == kX86) ? 0 - : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline); + : QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline); if (direct_method != 0) { switch (state) { @@ -555,7 +555,7 @@ static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info, uint32_t method_idx, uintptr_t unused, uintptr_t unused2, InvokeType unused3) { - int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck); + int trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck); return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0); } @@ -563,7 +563,7 @@ static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state, const MethodReference& target_method, uint32_t method_idx, uintptr_t unused, uintptr_t unused2, InvokeType unused3) { - int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck); + int trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck); return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0); } @@ -571,7 +571,7 @@ static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state, const MethodReference& target_method, uint32_t method_idx, uintptr_t unused, uintptr_t unused2, InvokeType unused3) { - int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck); + int trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck); return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0); } @@ -579,7 +579,7 @@ static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state, const MethodReference& target_method, uint32_t method_idx, uintptr_t unused, uintptr_t unused2, InvokeType unused3) { - int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck); + int trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck); return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0); } @@ -589,7 +589,7 @@ static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu, uint32_t unused, uintptr_t unused2, uintptr_t unused3, InvokeType unused4) { - int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck); + int trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck); return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0); } @@ -773,14 +773,14 @@ int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state, // Generate memcpy OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset); OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset); - CallRuntimeHelperRegRegImm(ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0), + CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0), TargetReg(kArg1), (info->num_arg_words - 3) * 4, false); } else { if (info->num_arg_words >= 20) { // Generate memcpy OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset); OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset); - CallRuntimeHelperRegRegImm(ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0), + CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0), TargetReg(kArg1), (info->num_arg_words - 3) * 4, false); } else { // Use vldm/vstm pair using kArg3 as a temp @@ -1047,7 +1047,7 @@ bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) { } else { LoadValueDirectFixed(rl_start, reg_start); } - int r_tgt = (cu_->instruction_set != kX86) ? LoadHelper(ENTRYPOINT_OFFSET(pIndexOf)) : 0; + int r_tgt = (cu_->instruction_set != kX86) ? LoadHelper(QUICK_ENTRYPOINT_OFFSET(pIndexOf)) : 0; GenNullCheck(rl_obj.s_reg_low, reg_ptr, info->opt_flags); LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info)); intrinsic_launchpads_.Insert(launch_pad); @@ -1056,7 +1056,7 @@ bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) { if (cu_->instruction_set != kX86) { OpReg(kOpBlx, r_tgt); } else { - OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pIndexOf)); + OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pIndexOf)); } LIR* resume_tgt = NewLIR0(kPseudoTargetLabel); launch_pad->operands[2] = reinterpret_cast<uintptr_t>(resume_tgt); @@ -1084,7 +1084,7 @@ bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info) { LoadValueDirectFixed(rl_this, reg_this); LoadValueDirectFixed(rl_cmp, reg_cmp); int r_tgt = (cu_->instruction_set != kX86) ? - LoadHelper(ENTRYPOINT_OFFSET(pStringCompareTo)) : 0; + LoadHelper(QUICK_ENTRYPOINT_OFFSET(pStringCompareTo)) : 0; GenNullCheck(rl_this.s_reg_low, reg_this, info->opt_flags); // TUNING: check if rl_cmp.s_reg_low is already null checked LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info)); @@ -1094,7 +1094,7 @@ bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info) { if (cu_->instruction_set != kX86) { OpReg(kOpBlx, r_tgt); } else { - OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pStringCompareTo)); + OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pStringCompareTo)); } launch_pad->operands[2] = 0; // No return possible // Record that we've already inlined & null checked @@ -1409,20 +1409,20 @@ void Mir2Lir::GenInvoke(CallInfo* info) { int trampoline = 0; switch (info->type) { case kInterface: - trampoline = fast_path ? ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline) - : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck); + trampoline = fast_path ? QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline) + : QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck); break; case kDirect: - trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck); + trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck); break; case kStatic: - trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck); + trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck); break; case kSuper: - trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck); + trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck); break; case kVirtual: - trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck); + trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck); break; default: LOG(FATAL) << "Unexpected invoke type"; diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc index 8b375ea2f0..846c055ac2 100644 --- a/compiler/dex/quick/mips/call_mips.cc +++ b/compiler/dex/quick/mips/call_mips.cc @@ -18,8 +18,8 @@ #include "codegen_mips.h" #include "dex/quick/mir_to_lir-inl.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "mips_lir.h" -#include "oat/runtime/oat_support_entrypoints.h" namespace art { @@ -247,7 +247,7 @@ void MipsMir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { GenBarrier(); NewLIR0(kMipsCurrPC); // Really a jal to .+8 // Now, fill the branch delay slot with the helper load - int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode)); + int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode)); GenBarrier(); // Scheduling barrier // Construct BaseLabel and set up table base register @@ -272,7 +272,7 @@ void MipsMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { LockCallTemps(); // Prepare for explicit register usage GenNullCheck(rl_src.s_reg_low, rMIPS_ARG0, opt_flags); // Go expensive route - artLockObjectFromCode(self, obj); - int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pLockObjectFromCode)); + int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pLockObjectFromCode)); ClobberCalleeSave(); LIR* call_inst = OpReg(kOpBlx, r_tgt); MarkSafepointPC(call_inst); @@ -287,7 +287,7 @@ void MipsMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { LockCallTemps(); // Prepare for explicit register usage GenNullCheck(rl_src.s_reg_low, rMIPS_ARG0, opt_flags); // Go expensive route - UnlockObjectFromCode(obj); - int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pUnlockObjectFromCode)); + int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pUnlockObjectFromCode)); ClobberCalleeSave(); LIR* call_inst = OpReg(kOpBlx, r_tgt); MarkSafepointPC(call_inst); diff --git a/compiler/dex/quick/mips/fp_mips.cc b/compiler/dex/quick/mips/fp_mips.cc index 6cd9acc099..320301726b 100644 --- a/compiler/dex/quick/mips/fp_mips.cc +++ b/compiler/dex/quick/mips/fp_mips.cc @@ -16,8 +16,8 @@ #include "codegen_mips.h" #include "dex/quick/mir_to_lir-inl.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "mips_lir.h" -#include "oat/runtime/oat_support_entrypoints.h" namespace art { @@ -50,7 +50,8 @@ void MipsMir2Lir::GenArithOpFloat(Instruction::Code opcode, case Instruction::REM_FLOAT_2ADDR: case Instruction::REM_FLOAT: FlushAllRegs(); // Send everything to home location - CallRuntimeHelperRegLocationRegLocation(ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, false); + CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, + false); rl_result = GetReturn(true); StoreValue(rl_dest, rl_result); return; @@ -92,7 +93,8 @@ void MipsMir2Lir::GenArithOpDouble(Instruction::Code opcode, case Instruction::REM_DOUBLE_2ADDR: case Instruction::REM_DOUBLE: FlushAllRegs(); // Send everything to home location - CallRuntimeHelperRegLocationRegLocation(ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2, false); + CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2, + false); rl_result = GetReturnWide(true); StoreValueWide(rl_dest, rl_result); return; @@ -133,22 +135,22 @@ void MipsMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, op = kMipsFcvtdw; break; case Instruction::FLOAT_TO_INT: - GenConversionCall(ENTRYPOINT_OFFSET(pF2iz), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2iz), rl_dest, rl_src); return; case Instruction::DOUBLE_TO_INT: - GenConversionCall(ENTRYPOINT_OFFSET(pD2iz), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2iz), rl_dest, rl_src); return; case Instruction::LONG_TO_DOUBLE: - GenConversionCall(ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src); return; case Instruction::FLOAT_TO_LONG: - GenConversionCall(ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src); return; case Instruction::LONG_TO_FLOAT: - GenConversionCall(ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src); return; case Instruction::DOUBLE_TO_LONG: - GenConversionCall(ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src); return; default: LOG(FATAL) << "Unexpected opcode: " << opcode; @@ -178,18 +180,18 @@ void MipsMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, switch (opcode) { case Instruction::CMPL_FLOAT: - offset = ENTRYPOINT_OFFSET(pCmplFloat); + offset = QUICK_ENTRYPOINT_OFFSET(pCmplFloat); wide = false; break; case Instruction::CMPG_FLOAT: - offset = ENTRYPOINT_OFFSET(pCmpgFloat); + offset = QUICK_ENTRYPOINT_OFFSET(pCmpgFloat); wide = false; break; case Instruction::CMPL_DOUBLE: - offset = ENTRYPOINT_OFFSET(pCmplDouble); + offset = QUICK_ENTRYPOINT_OFFSET(pCmplDouble); break; case Instruction::CMPG_DOUBLE: - offset = ENTRYPOINT_OFFSET(pCmpgDouble); + offset = QUICK_ENTRYPOINT_OFFSET(pCmpgDouble); break; default: LOG(FATAL) << "Unexpected opcode: " << opcode; diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc index ea7da6030e..bd044c66bd 100644 --- a/compiler/dex/quick/mips/int_mips.cc +++ b/compiler/dex/quick/mips/int_mips.cc @@ -18,9 +18,9 @@ #include "codegen_mips.h" #include "dex/quick/mir_to_lir-inl.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "mips_lir.h" #include "mirror/array.h" -#include "oat/runtime/oat_support_entrypoints.h" namespace art { @@ -579,7 +579,7 @@ void MipsMir2Lir::GenArrayObjPut(int opt_flags, RegLocation rl_array, // Get the array's class. LoadWordDisp(r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class); - CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value, + CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value, r_array_class, true); // Redo LoadValues in case they didn't survive the call. LoadValueDirectFixed(rl_array, r_array); // Reload array diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc index d530a1c644..1c395def55 100644 --- a/compiler/dex/quick/x86/call_x86.cc +++ b/compiler/dex/quick/x86/call_x86.cc @@ -148,7 +148,7 @@ void X86Mir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { NewLIR1(kX86StartOfMethod, rX86_ARG2); NewLIR2(kX86PcRelAdr, rX86_ARG1, reinterpret_cast<uintptr_t>(tab_rec)); NewLIR2(kX86Add32RR, rX86_ARG1, rX86_ARG2); - CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode), rX86_ARG0, + CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode), rX86_ARG0, rX86_ARG1, true); } @@ -165,7 +165,7 @@ void X86Mir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { NewLIR3(kX86LockCmpxchgMR, rCX, mirror::Object::MonitorOffset().Int32Value(), rDX); LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondEq); // If lock is held, go the expensive route - artLockObjectFromCode(self, obj); - CallRuntimeHelperReg(ENTRYPOINT_OFFSET(pLockObjectFromCode), rCX, true); + CallRuntimeHelperReg(QUICK_ENTRYPOINT_OFFSET(pLockObjectFromCode), rCX, true); branch->target = NewLIR0(kPseudoTargetLabel); } @@ -185,7 +185,7 @@ void X86Mir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { LIR* branch2 = NewLIR1(kX86Jmp8, 0); branch->target = NewLIR0(kPseudoTargetLabel); // Otherwise, go the expensive route - UnlockObjectFromCode(obj); - CallRuntimeHelperReg(ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rAX, true); + CallRuntimeHelperReg(QUICK_ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rAX, true); branch2->target = NewLIR0(kPseudoTargetLabel); } diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc index cc6f374488..f736b5e28f 100644 --- a/compiler/dex/quick/x86/fp_x86.cc +++ b/compiler/dex/quick/x86/fp_x86.cc @@ -49,7 +49,8 @@ void X86Mir2Lir::GenArithOpFloat(Instruction::Code opcode, case Instruction::REM_FLOAT_2ADDR: case Instruction::REM_FLOAT: FlushAllRegs(); // Send everything to home location - CallRuntimeHelperRegLocationRegLocation(ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, false); + CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, + false); rl_result = GetReturn(true); StoreValue(rl_dest, rl_result); return; @@ -99,7 +100,8 @@ void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode, case Instruction::REM_DOUBLE_2ADDR: case Instruction::REM_DOUBLE: FlushAllRegs(); // Send everything to home location - CallRuntimeHelperRegLocationRegLocation(ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2, false); + CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2, + false); rl_result = GetReturnWide(true); StoreValueWide(rl_dest, rl_result); return; @@ -196,17 +198,17 @@ void X86Mir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, return; } case Instruction::LONG_TO_DOUBLE: - GenConversionCall(ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src); return; case Instruction::LONG_TO_FLOAT: // TODO: inline by using memory as a 64-bit source. Be careful about promoted registers. - GenConversionCall(ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src); return; case Instruction::FLOAT_TO_LONG: - GenConversionCall(ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src); return; case Instruction::DOUBLE_TO_LONG: - GenConversionCall(ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src); + GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src); return; default: LOG(INFO) << "Unexpected opcode: " << opcode; diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc index 3be24df565..0b4b4be04e 100644 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -532,7 +532,7 @@ void X86Mir2Lir::GenArrayObjPut(int opt_flags, RegLocation rl_array, // Get the array's class. LoadWordDisp(r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class); - CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value, + CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value, r_array_class, true); // Redo LoadValues in case they didn't survive the call. LoadValueDirectFixed(rl_array, r_array); // Reload array diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 038957e128..38d00a0804 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -369,7 +369,7 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet compiler_ = reinterpret_cast<CompilerFn>(ArtQuickCompileMethod); } - dex_to_dex_compiler_ = reinterpret_cast<CompilerFn>(ArtCompileDEX); + dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX); #ifdef ART_SEA_IR_MODE sea_ir_compiler_ = NULL; @@ -495,7 +495,7 @@ const std::vector<uint8_t>* CompilerDriver::CreateInterpreterToQuickEntry() cons void CompilerDriver::CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files, - TimingLogger& timings) { + base::TimingLogger& timings) { DCHECK(!Runtime::Current()->IsStarted()); UniquePtr<ThreadPool> thread_pool(new ThreadPool(thread_count_)); PreCompile(class_loader, dex_files, *thread_pool.get(), timings); @@ -505,16 +505,10 @@ void CompilerDriver::CompileAll(jobject class_loader, } } -static bool IsDexToDexCompilationAllowed(mirror::ClassLoader* class_loader, - const DexFile& dex_file, - const DexFile::ClassDef& class_def) +static DexToDexCompilationLevel GetDexToDexCompilationlevel(mirror::ClassLoader* class_loader, + const DexFile& dex_file, + const DexFile::ClassDef& class_def) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - // Do not allow DEX-to-DEX compilation of image classes. This is to prevent the - // verifier from passing on "quick" instruction at compilation time. It must - // only pass on quick instructions at runtime. - if (class_loader == NULL) { - return false; - } const char* descriptor = dex_file.GetClassDescriptor(class_def); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); mirror::Class* klass = class_linker->FindClass(descriptor, class_loader); @@ -522,13 +516,30 @@ static bool IsDexToDexCompilationAllowed(mirror::ClassLoader* class_loader, Thread* self = Thread::Current(); CHECK(self->IsExceptionPending()); self->ClearException(); - return false; + return kDontDexToDexCompile; + } + // The verifier can only run on "quick" instructions at runtime (see usage of + // FindAccessedFieldAtDexPc and FindInvokedMethodAtDexPc in ThrowNullPointerExceptionFromDexPC + // function). Since image classes can be verified again while compiling an application, + // we must prevent the DEX-to-DEX compiler from introducing them. + // TODO: find a way to enable "quick" instructions for image classes and remove this check. + bool compiling_image_classes = (class_loader == NULL); + if (compiling_image_classes) { + return kRequired; + } else if (klass->IsVerified()) { + // Class is verified so we can enable DEX-to-DEX compilation for performance. + return kOptimize; + } else if (klass->IsCompileTimeVerified()) { + // Class verification has soft-failed. Anyway, ensure at least correctness. + DCHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime); + return kRequired; + } else { + // Class verification has failed: do not run DEX-to-DEX compilation. + return kDontDexToDexCompile; } - // DEX-to-DEX compilation is only allowed on preverified classes. - return klass->IsVerified(); } -void CompilerDriver::CompileOne(const mirror::AbstractMethod* method, TimingLogger& timings) { +void CompilerDriver::CompileOne(const mirror::AbstractMethod* method, base::TimingLogger& timings) { DCHECK(!Runtime::Current()->IsStarted()); Thread* self = Thread::Current(); jobject jclass_loader; @@ -556,15 +567,15 @@ void CompilerDriver::CompileOne(const mirror::AbstractMethod* method, TimingLogg uint32_t method_idx = method->GetDexMethodIndex(); const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset()); // Can we run DEX-to-DEX compiler on this class ? - bool allow_dex_compilation; + DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile; { ScopedObjectAccess soa(Thread::Current()); const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader); - allow_dex_compilation = IsDexToDexCompilationAllowed(class_loader, *dex_file, class_def); + dex_to_dex_compilation_level = GetDexToDexCompilationlevel(class_loader, *dex_file, class_def); } CompileMethod(code_item, method->GetAccessFlags(), method->GetInvokeType(), - class_def_idx, method_idx, jclass_loader, *dex_file, allow_dex_compilation); + class_def_idx, method_idx, jclass_loader, *dex_file, dex_to_dex_compilation_level); self->GetJniEnv()->DeleteGlobalRef(jclass_loader); @@ -572,7 +583,7 @@ void CompilerDriver::CompileOne(const mirror::AbstractMethod* method, TimingLogg } void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files, - ThreadPool& thread_pool, TimingLogger& timings) { + ThreadPool& thread_pool, base::TimingLogger& timings) { for (size_t i = 0; i != dex_files.size(); ++i) { const DexFile* dex_file = dex_files[i]; CHECK(dex_file != NULL); @@ -581,7 +592,7 @@ void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFi } void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, - ThreadPool& thread_pool, TimingLogger& timings) { + ThreadPool& thread_pool, base::TimingLogger& timings) { LoadImageClasses(timings); Resolve(class_loader, dex_files, thread_pool, timings); @@ -666,12 +677,13 @@ static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg) } // Make a list of descriptors for classes to include in the image -void CompilerDriver::LoadImageClasses(TimingLogger& timings) +void CompilerDriver::LoadImageClasses(base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_) { if (image_classes_.get() == NULL) { return; } + timings.NewSplit("LoadImageClasses"); // Make a first class to load all classes explicitly listed in the file Thread* self = Thread::Current(); ScopedObjectAccess soa(self); @@ -726,7 +738,6 @@ void CompilerDriver::LoadImageClasses(TimingLogger& timings) class_linker->VisitClasses(RecordImageClassesVisitor, image_classes_.get()); CHECK_NE(image_classes_->size(), 0U); - timings.AddSplit("LoadImageClasses"); } static void MaybeAddToImageClasses(mirror::Class* klass, CompilerDriver::DescriptorSet* image_classes) @@ -758,11 +769,13 @@ void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void MaybeAddToImageClasses(object->GetClass(), compiler_driver->image_classes_.get()); } -void CompilerDriver::UpdateImageClasses(TimingLogger& timings) { +void CompilerDriver::UpdateImageClasses(base::TimingLogger& timings) { if (image_classes_.get() == NULL) { return; } + timings.NewSplit("UpdateImageClasses"); + // Update image_classes_ with classes for objects created by <clinit> methods. Thread* self = Thread::Current(); const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter"); @@ -772,7 +785,6 @@ void CompilerDriver::UpdateImageClasses(TimingLogger& timings) { heap->FlushAllocStack(); heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this); self->EndAssertNoThreadSuspension(old_cause); - timings.AddSplit("UpdateImageClasses"); } void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) { @@ -1551,22 +1563,22 @@ static void ResolveType(const ParallelCompilationManager* manager, size_t type_i } void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_file, - ThreadPool& thread_pool, TimingLogger& timings) { + ThreadPool& thread_pool, base::TimingLogger& timings) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); // TODO: we could resolve strings here, although the string table is largely filled with class // and method names. + timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " Types").c_str())); ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool); context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_); - timings.AddSplit("Resolve " + dex_file.GetLocation() + " Types"); + timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " MethodsAndFields").c_str())); context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_); - timings.AddSplit("Resolve " + dex_file.GetLocation() + " MethodsAndFields"); } void CompilerDriver::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files, - ThreadPool& thread_pool, TimingLogger& timings) { + ThreadPool& thread_pool, base::TimingLogger& timings) { for (size_t i = 0; i != dex_files.size(); ++i) { const DexFile* dex_file = dex_files[i]; CHECK(dex_file != NULL); @@ -1620,11 +1632,11 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ } void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file, - ThreadPool& thread_pool, TimingLogger& timings) { + ThreadPool& thread_pool, base::TimingLogger& timings) { + timings.NewSplit(strdup(("Verify " + dex_file.GetLocation()).c_str())); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool); context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_); - timings.AddSplit("Verify " + dex_file.GetLocation()); } static const char* class_initializer_black_list[] = { @@ -2116,7 +2128,8 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl } void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file, - ThreadPool& thread_pool, TimingLogger& timings) { + ThreadPool& thread_pool, base::TimingLogger& timings) { + timings.NewSplit(strdup(("InitializeNoClinit " + dex_file.GetLocation()).c_str())); #ifndef NDEBUG for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) { const char* descriptor = class_initializer_black_list[i]; @@ -2126,12 +2139,11 @@ void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, thread_pool); context.ForAll(0, dex_file.NumClassDefs(), InitializeClass, thread_count_); - timings.AddSplit("InitializeNoClinit " + dex_file.GetLocation()); } void CompilerDriver::InitializeClasses(jobject class_loader, const std::vector<const DexFile*>& dex_files, - ThreadPool& thread_pool, TimingLogger& timings) { + ThreadPool& thread_pool, base::TimingLogger& timings) { for (size_t i = 0; i != dex_files.size(); ++i) { const DexFile* dex_file = dex_files[i]; CHECK(dex_file != NULL); @@ -2140,7 +2152,7 @@ void CompilerDriver::InitializeClasses(jobject class_loader, } void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files, - ThreadPool& thread_pool, TimingLogger& timings) { + ThreadPool& thread_pool, base::TimingLogger& timings) { for (size_t i = 0; i != dex_files.size(); ++i) { const DexFile* dex_file = dex_files[i]; CHECK(dex_file != NULL); @@ -2170,11 +2182,11 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz return; } // Can we run DEX-to-DEX compiler on this class ? - bool allow_dex_compilation; + DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile; { ScopedObjectAccess soa(Thread::Current()); mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader); - allow_dex_compilation = IsDexToDexCompilationAllowed(class_loader, dex_file, class_def); + dex_to_dex_compilation_level = GetDexToDexCompilationlevel(class_loader, dex_file, class_def); } ClassDataItemIterator it(dex_file, class_data); // Skip fields @@ -2197,7 +2209,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz previous_direct_method_idx = method_idx; manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(), it.GetMethodInvokeType(class_def), class_def_index, - method_idx, jclass_loader, dex_file, allow_dex_compilation); + method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level); it.Next(); } // Compile virtual methods @@ -2213,24 +2225,24 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz previous_virtual_method_idx = method_idx; manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(), it.GetMethodInvokeType(class_def), class_def_index, - method_idx, jclass_loader, dex_file, allow_dex_compilation); + method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level); it.Next(); } DCHECK(!it.HasNext()); } void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file, - ThreadPool& thread_pool, TimingLogger& timings) { + ThreadPool& thread_pool, base::TimingLogger& timings) { + timings.NewSplit(strdup(("Compile " + dex_file.GetLocation()).c_str())); ParallelCompilationManager context(NULL, class_loader, this, &dex_file, thread_pool); context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_); - timings.AddSplit("Compile " + dex_file.GetLocation()); } void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, - bool allow_dex_to_dex_compilation) { + DexToDexCompilationLevel dex_to_dex_compilation_level) { CompiledMethod* compiled_method = NULL; uint64_t start_ns = NanoTime(); @@ -2239,18 +2251,8 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t CHECK(compiled_method != NULL); } else if ((access_flags & kAccAbstract) != 0) { } else { - // In small mode we only compile image classes. - bool dont_compile = (Runtime::Current()->IsSmallMode() && - ((image_classes_.get() == NULL) || (image_classes_->size() == 0))); - - // Don't compile class initializers, ever. - if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) { - dont_compile = true; - } else if (code_item->insns_size_in_code_units_ < Runtime::Current()->GetSmallModeMethodDexSizeLimit()) { - // Do compile small methods. - dont_compile = false; - } - if (!dont_compile) { + bool compile = verifier::MethodVerifier::IsCandidateForCompilation(code_item, access_flags); + if (compile) { CompilerFn compiler = compiler_; #ifdef ART_SEA_IR_MODE bool use_sea = Runtime::Current()->IsSeaIRMode(); @@ -2262,13 +2264,12 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t compiled_method = (*compiler)(*this, code_item, access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file); CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file); - } else if (allow_dex_to_dex_compilation) { + } else if (dex_to_dex_compilation_level != kDontDexToDexCompile) { // TODO: add a mode to disable DEX-to-DEX compilation ? - compiled_method = (*dex_to_dex_compiler_)(*this, code_item, access_flags, - invoke_type, class_def_idx, - method_idx, class_loader, dex_file); - // No native code is generated. - CHECK(compiled_method == NULL) << PrettyMethod(method_idx, dex_file); + (*dex_to_dex_compiler_)(*this, code_item, access_flags, + invoke_type, class_def_idx, + method_idx, class_loader, dex_file, + dex_to_dex_compilation_level); } } uint64_t duration_ns = NanoTime() - start_ns; diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index f3f72dd3c7..18f852dc6f 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -48,6 +48,12 @@ enum CompilerBackend { kNoBackend }; +enum DexToDexCompilationLevel { + kDontDexToDexCompile, // Only meaning wrt image time interpretation. + kRequired, // Dex-to-dex compilation required for correctness. + kOptimize // Perform required transformation and peep-hole optimizations. +}; + // Thread-local storage compiler worker threads class CompilerTls { public: @@ -78,11 +84,11 @@ class CompilerDriver { ~CompilerDriver(); void CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files, - TimingLogger& timings) + base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_); // Compile a single Method - void CompileOne(const mirror::AbstractMethod* method, TimingLogger& timings) + void CompileOne(const mirror::AbstractMethod* method, base::TimingLogger& timings) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); InstructionSet GetInstructionSet() const { @@ -284,47 +290,47 @@ class CompilerDriver { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, - ThreadPool& thread_pool, TimingLogger& timings) + ThreadPool& thread_pool, base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_); - void LoadImageClasses(TimingLogger& timings); + void LoadImageClasses(base::TimingLogger& timings); // Attempt to resolve all type, methods, fields, and strings // referenced from code in the dex file following PathClassLoader // ordering semantics. void Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files, - ThreadPool& thread_pool, TimingLogger& timings) + ThreadPool& thread_pool, base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_); void ResolveDexFile(jobject class_loader, const DexFile& dex_file, - ThreadPool& thread_pool, TimingLogger& timings) + ThreadPool& thread_pool, base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_); void Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files, - ThreadPool& thread_pool, TimingLogger& timings); + ThreadPool& thread_pool, base::TimingLogger& timings); void VerifyDexFile(jobject class_loader, const DexFile& dex_file, - ThreadPool& thread_pool, TimingLogger& timings) + ThreadPool& thread_pool, base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_); void InitializeClasses(jobject class_loader, const std::vector<const DexFile*>& dex_files, - ThreadPool& thread_pool, TimingLogger& timings) + ThreadPool& thread_pool, base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_); void InitializeClasses(jobject class_loader, const DexFile& dex_file, - ThreadPool& thread_pool, TimingLogger& timings) + ThreadPool& thread_pool, base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_, compiled_classes_lock_); - void UpdateImageClasses(TimingLogger& timings); + void UpdateImageClasses(base::TimingLogger& timings); static void FindClinitImageClassesCallback(mirror::Object* object, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files, - ThreadPool& thread_pool, TimingLogger& timings); + ThreadPool& thread_pool, base::TimingLogger& timings); void CompileDexFile(jobject class_loader, const DexFile& dex_file, - ThreadPool& thread_pool, TimingLogger& timings) + ThreadPool& thread_pool, base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_); void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, - bool allow_dex_to_dex_compilation) + DexToDexCompilationLevel dex_to_dex_compilation_level) LOCKS_EXCLUDED(compiled_methods_lock_); static void CompileClass(const ParallelCompilationManager* context, size_t class_def_index) @@ -375,12 +381,19 @@ class CompilerDriver { uint32_t access_flags, InvokeType invoke_type, uint32_t class_dex_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file); + + typedef void (*DexToDexCompilerFn)(CompilerDriver& driver, + const DexFile::CodeItem* code_item, + uint32_t access_flags, InvokeType invoke_type, + uint32_t class_dex_idx, uint32_t method_idx, + jobject class_loader, const DexFile& dex_file, + DexToDexCompilationLevel dex_to_dex_compilation_level); CompilerFn compiler_; #ifdef ART_SEA_IR_MODE CompilerFn sea_ir_compiler_; #endif - CompilerFn dex_to_dex_compiler_; + DexToDexCompilerFn dex_to_dex_compiler_; void* compiler_context_; diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 78cacaf08e..8ee9cf6442 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -36,7 +36,8 @@ namespace art { class CompilerDriverTest : public CommonTest { protected: void CompileAll(jobject class_loader) LOCKS_EXCLUDED(Locks::mutator_lock_) { - TimingLogger timings("CompilerDriverTest::CompileAll", false); + base::TimingLogger timings("CompilerDriverTest::CompileAll", false, false); + timings.StartSplit("CompileAll"); compiler_driver_->CompileAll(class_loader, Runtime::Current()->GetCompileTimeClassPath(class_loader), timings); diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc index e9b09c5bba..9778293ee7 100644 --- a/compiler/jni/quick/arm/calling_convention_arm.cc +++ b/compiler/jni/quick/arm/calling_convention_arm.cc @@ -16,7 +16,7 @@ #include "base/logging.h" #include "calling_convention_arm.h" -#include "oat/utils/arm/managed_register_arm.h" +#include "utils/arm/managed_register_arm.h" namespace art { namespace arm { diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h index d492b42237..f2b7fd9a4a 100644 --- a/compiler/jni/quick/calling_convention.h +++ b/compiler/jni/quick/calling_convention.h @@ -18,9 +18,9 @@ #define ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_ #include <vector> -#include "oat/utils/managed_register.h" #include "stack_indirect_reference_table.h" #include "thread.h" +#include "utils/managed_register.h" namespace art { diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index fa227f7fbb..b069fbd4a1 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -25,13 +25,13 @@ #include "dex_file-inl.h" #include "driver/compiler_driver.h" #include "disassembler.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "jni_internal.h" -#include "oat/runtime/oat_support_entrypoints.h" -#include "oat/utils/assembler.h" -#include "oat/utils/managed_register.h" -#include "oat/utils/arm/managed_register_arm.h" -#include "oat/utils/mips/managed_register_mips.h" -#include "oat/utils/x86/managed_register_x86.h" +#include "utils/assembler.h" +#include "utils/managed_register.h" +#include "utils/arm/managed_register_arm.h" +#include "utils/mips/managed_register_mips.h" +#include "utils/x86/managed_register_x86.h" #include "thread.h" #include "UniquePtr.h" @@ -172,8 +172,8 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler, // can occur. The result is the saved JNI local state that is restored by the exit call. We // abuse the JNI calling convention here, that is guaranteed to support passing 2 pointer // arguments. - uintptr_t jni_start = is_synchronized ? ENTRYPOINT_OFFSET(pJniMethodStartSynchronized) - : ENTRYPOINT_OFFSET(pJniMethodStart); + uintptr_t jni_start = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(pJniMethodStartSynchronized) + : QUICK_ENTRYPOINT_OFFSET(pJniMethodStart); main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size)); FrameOffset locked_object_sirt_offset(0); if (is_synchronized) { @@ -304,13 +304,13 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler, uintptr_t jni_end; if (reference_return) { // Pass result. - jni_end = is_synchronized ? ENTRYPOINT_OFFSET(pJniMethodEndWithReferenceSynchronized) - : ENTRYPOINT_OFFSET(pJniMethodEndWithReference); + jni_end = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(pJniMethodEndWithReferenceSynchronized) + : QUICK_ENTRYPOINT_OFFSET(pJniMethodEndWithReference); SetNativeParameter(jni_asm.get(), end_jni_conv.get(), end_jni_conv->ReturnRegister()); end_jni_conv->Next(); } else { - jni_end = is_synchronized ? ENTRYPOINT_OFFSET(pJniMethodEndSynchronized) - : ENTRYPOINT_OFFSET(pJniMethodEnd); + jni_end = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(pJniMethodEndSynchronized) + : QUICK_ENTRYPOINT_OFFSET(pJniMethodEnd); } // Pass saved local reference state. if (end_jni_conv->IsCurrentParamOnStack()) { diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc index 053ab44eb4..0a48500380 100644 --- a/compiler/jni/quick/mips/calling_convention_mips.cc +++ b/compiler/jni/quick/mips/calling_convention_mips.cc @@ -17,7 +17,7 @@ #include "calling_convention_mips.h" #include "base/logging.h" -#include "oat/utils/mips/managed_register_mips.h" +#include "utils/mips/managed_register_mips.h" namespace art { namespace mips { diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc index 45dd42960c..8b5c86d683 100644 --- a/compiler/jni/quick/x86/calling_convention_x86.cc +++ b/compiler/jni/quick/x86/calling_convention_x86.cc @@ -17,7 +17,7 @@ #include "calling_convention_x86.h" #include "base/logging.h" -#include "oat/utils/x86/managed_register_x86.h" +#include "utils/x86/managed_register_x86.h" #include "utils.h" namespace art { diff --git a/compiler/llvm/runtime_support_builder.cc b/compiler/llvm/runtime_support_builder.cc index 729980309d..24e283d309 100644 --- a/compiler/llvm/runtime_support_builder.cc +++ b/compiler/llvm/runtime_support_builder.cc @@ -20,6 +20,7 @@ #include "ir_builder.h" #include "monitor.h" #include "mirror/object.h" +#include "runtime_support_llvm_func_list.h" #include "thread.h" #include <llvm/IR/DerivedTypes.h> @@ -47,10 +48,7 @@ RuntimeSupportBuilder::RuntimeSupportBuilder(::llvm::LLVMContext& context, runtime_support_func_decls_[runtime_support::ID] = fn; \ } while (0); -#include "runtime_support_llvm_func_list.h" RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL) -#undef RUNTIME_SUPPORT_FUNC_LIST -#undef GET_RUNTIME_SUPPORT_FUNC_DECL } diff --git a/compiler/llvm/runtime_support_llvm_func.h b/compiler/llvm/runtime_support_llvm_func.h index 2634c683f1..a5ad852b49 100644 --- a/compiler/llvm/runtime_support_llvm_func.h +++ b/compiler/llvm/runtime_support_llvm_func.h @@ -17,16 +17,15 @@ #ifndef ART_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_FUNC_H_ #define ART_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_FUNC_H_ +#include "runtime_support_llvm_func_list.h" + namespace art { namespace llvm { namespace runtime_support { enum RuntimeId { #define DEFINE_RUNTIME_SUPPORT_FUNC_ID(ID, NAME) ID, -#include "runtime_support_llvm_func_list.h" RUNTIME_SUPPORT_FUNC_LIST(DEFINE_RUNTIME_SUPPORT_FUNC_ID) -#undef RUNTIME_SUPPORT_FUNC_LIST -#undef DEFINE_RUNTIME_SUPPORT_FUNC_ID MAX_ID }; diff --git a/runtime/runtime_support_llvm_func_list.h b/compiler/llvm/runtime_support_llvm_func_list.h index 8b635cbd2c..b5ac1ffe63 100644 --- a/runtime/runtime_support_llvm_func_list.h +++ b/compiler/llvm/runtime_support_llvm_func_list.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_RUNTIME_SUPPORT_LLVM_FUNC_LIST_H_ -#define ART_RUNTIME_RUNTIME_SUPPORT_LLVM_FUNC_LIST_H_ +#ifndef ART_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_FUNC_LIST_H_ +#define ART_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_FUNC_LIST_H_ #define RUNTIME_SUPPORT_FUNC_LIST(V) \ V(LockObject, art_portable_lock_object_from_code) \ @@ -78,5 +78,4 @@ V(JniMethodEndWithReference, art_portable_jni_method_end_with_reference) \ V(JniMethodEndWithReferenceSynchronized, art_portable_jni_method_end_with_reference_synchronized) -#endif // ART_RUNTIME_RUNTIME_SUPPORT_LLVM_FUNC_LIST_H_ -#undef ART_RUNTIME_RUNTIME_SUPPORT_LLVM_FUNC_LIST_H_ // the guard in this file is just for cpplint +#endif // ART_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_FUNC_LIST_H_ diff --git a/compiler/sea_ir/code_gen.cc b/compiler/sea_ir/code_gen.cc index f359849d4d..a513907b38 100644 --- a/compiler/sea_ir/code_gen.cc +++ b/compiler/sea_ir/code_gen.cc @@ -66,7 +66,8 @@ void CodeGenPrepassVisitor::Visit(SeaGraph* graph) { std::vector<llvm::Type*> parameter_types(parameters->size(), llvm::Type::getInt32Ty(*llvm_data_->context_)); // Build llvm function name. - std::string function_name = art::StringPrintf("class=%d_method=%d", graph->class_def_idx_, graph->method_idx_); + std::string function_name = art::StringPrintf( + "class=%d_method=%d", graph->class_def_idx_, graph->method_idx_); // Build llvm function type and parameters. llvm::FunctionType *function_type = llvm::FunctionType::get( @@ -259,15 +260,18 @@ void CodeGenPostpassVisitor::Visit(PhiInstructionNode* phi) { void CodeGenVisitor::Visit(SignatureNode* signature) { std::cout << "Signature: ;" << "Id:" << signature->StringId() << std::endl; - DCHECK_EQ(signature->GetDefinitions().size(), 1u) << "Signature nodes must correspond to a single parameter register."; + DCHECK_EQ(signature->GetDefinitions().size(), 1u) << + "Signature nodes must correspond to a single parameter register."; } void CodeGenPrepassVisitor::Visit(SignatureNode* signature) { std::cout << "Signature: ;" << "Id:" << signature->StringId() << std::endl; - DCHECK_EQ(signature->GetDefinitions().size(), 1u) << "Signature nodes must correspond to a single parameter register."; + DCHECK_EQ(signature->GetDefinitions().size(), 1u) << + "Signature nodes must correspond to a single parameter register."; } void CodeGenPostpassVisitor::Visit(SignatureNode* signature) { std::cout << "Signature: ;" << "Id:" << signature->StringId() << std::endl; - DCHECK_EQ(signature->GetDefinitions().size(), 1u) << "Signature nodes must correspond to a single parameter register."; + DCHECK_EQ(signature->GetDefinitions().size(), 1u) << + "Signature nodes must correspond to a single parameter register."; } } // namespace sea_ir diff --git a/compiler/sea_ir/frontend.cc b/compiler/sea_ir/frontend.cc index 8fc1cf8315..5843388c42 100644 --- a/compiler/sea_ir/frontend.cc +++ b/compiler/sea_ir/frontend.cc @@ -40,7 +40,7 @@ static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler, // NOTE: Instead of keeping the convention from the Dalvik frontend.cc // and silencing the cpplint.py warning, I just corrected the formatting. VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "..."; - sea_ir::SeaGraph* sg = sea_ir::SeaGraph::GetCurrentGraph(); + sea_ir::SeaGraph* sg = sea_ir::SeaGraph::GetCurrentGraph(dex_file); sg->CompileMethod(code_item, class_def_idx, method_idx, dex_file); sg->DumpSea("/tmp/temp.dot"); CHECK(0 && "No SEA compiled function exists yet."); @@ -57,8 +57,8 @@ CompiledMethod* SeaIrCompileOneMethod(CompilerDriver& compiler, jobject class_loader, const DexFile& dex_file, llvm::LlvmCompilationUnit* llvm_compilation_unit) { - return CompileMethodWithSeaIr(compiler, backend, code_item, access_flags, invoke_type, class_def_idx, - method_idx, class_loader, dex_file + return CompileMethodWithSeaIr(compiler, backend, code_item, access_flags, invoke_type, + class_def_idx, method_idx, class_loader, dex_file #if defined(ART_USE_PORTABLE_COMPILER) , llvm_compilation_unit #endif @@ -71,7 +71,8 @@ extern "C" art::CompiledMethod* uint32_t access_flags, art::InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file) { - // TODO: check method fingerprint here to determine appropriate backend type. Until then, use build default + // TODO: Check method fingerprint here to determine appropriate backend type. + // Until then, use build default art::CompilerBackend backend = compiler.GetCompilerBackend(); return art::SeaIrCompileOneMethod(compiler, backend, code_item, access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file, diff --git a/compiler/sea_ir/instruction_nodes.h b/compiler/sea_ir/instruction_nodes.h index 5c9cfe19dc..6f9bdddf77 100644 --- a/compiler/sea_ir/instruction_nodes.h +++ b/compiler/sea_ir/instruction_nodes.h @@ -50,13 +50,14 @@ class InstructionNode: public SeaNode { // Returns the set of register numbers that are used by the instruction. virtual std::vector<int> GetUses(); // Appends to @result the .dot string representation of the instruction. - virtual void ToDot(std::string& result) const; + virtual void ToDot(std::string& result, const art::DexFile& dex_file) const; // Mark the current instruction as a downward exposed definition. void MarkAsDEDef(); // Rename the use of @reg_no to refer to the instruction @definition, // essentially creating SSA form. void RenameToSSA(int reg_no, InstructionNode* definition) { definition_edges_.insert(std::pair<int, InstructionNode*>(reg_no, definition)); + definition->AddSSAUse(this); } // Returns the ordered set of Instructions that define the input operands of this instruction. // Precondition: SeaGraph.ConvertToSSA(). @@ -69,6 +70,10 @@ class InstructionNode: public SeaNode { return ssa_uses; } + virtual void AddSSAUse(InstructionNode* use) { + used_in_.push_back(use); + } + void Accept(IRVisitor* v) { v->Visit(this); v->Traverse(this); @@ -85,11 +90,14 @@ class InstructionNode: public SeaNode { protected: explicit InstructionNode(const art::Instruction* in): - SeaNode(), instruction_(in), de_def_(false), region_(NULL) { } + SeaNode(), instruction_(in), used_in_(), de_def_(false), region_(NULL) { } + void ToDotSSAEdges(std::string& result) const; protected: const art::Instruction* const instruction_; std::map<int, InstructionNode* > definition_edges_; + // Stores pointers to instructions that use the result of the current instruction. + std::vector<InstructionNode*> used_in_; bool de_def_; Region* region_; }; @@ -126,7 +134,7 @@ class UnnamedConstInstructionNode: public ConstInstructionNode { return value_; } - void ToDot(std::string& result) const { + void ToDot(std::string& result, const art::DexFile& dex_file) const { std::ostringstream sstream; sstream << GetConstValue(); const std::string value_as_string(sstream.str()); @@ -136,17 +144,7 @@ class UnnamedConstInstructionNode: public ConstInstructionNode { result += "style=bold"; } result += "];\n"; - // SSA definitions: - for (std::map<int, InstructionNode* >::const_iterator def_it = definition_edges_.begin(); - def_it != definition_edges_.end(); def_it++) { - if (NULL != def_it->second) { - result += def_it->second->StringId() + " -> " + StringId() +"[color=red,label=\""; - std::stringstream ss; - ss << def_it->first; - result.append(ss.str()); - result += "\"] ; // ssa edge\n"; - } - } + ToDotSSAEdges(result); } private: diff --git a/compiler/sea_ir/sea.cc b/compiler/sea_ir/sea.cc index 3488afd5be..99b21f8771 100644 --- a/compiler/sea_ir/sea.cc +++ b/compiler/sea_ir/sea.cc @@ -27,7 +27,6 @@ namespace sea_ir { -SeaGraph SeaGraph::graph_; int SeaNode::current_max_node_id_ = 0; void IRVisitor::Traverse(Region* region) { @@ -51,16 +50,16 @@ void IRVisitor::Traverse(SeaGraph* graph) { } } -SeaGraph* SeaGraph::GetCurrentGraph() { - return &sea_ir::SeaGraph::graph_; +SeaGraph* SeaGraph::GetCurrentGraph(const art::DexFile& dex_file) { + return new SeaGraph(dex_file); } void SeaGraph::DumpSea(std::string filename) const { LOG(INFO) << "Starting to write SEA string to file."; std::string result; - result += "digraph seaOfNodes {\n"; + result += "digraph seaOfNodes {\ncompound=true\n"; for (std::vector<Region*>::const_iterator cit = regions_.begin(); cit != regions_.end(); cit++) { - (*cit)->ToDot(result); + (*cit)->ToDot(result, dex_file_); } result += "}\n"; art::File* file = art::OS::OpenFile(filename.c_str(), true, true); @@ -238,7 +237,8 @@ void SeaGraph::BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, sea_ir::InstructionNode* node = NULL; while (i < size_in_code_units) { const art::Instruction* inst = art::Instruction::At(&code[i]); - std::vector<InstructionNode*> sea_instructions_for_dalvik = sea_ir::InstructionNode::Create(inst); + std::vector<InstructionNode*> sea_instructions_for_dalvik = + sea_ir::InstructionNode::Create(inst); for (std::vector<InstructionNode*>::const_iterator cit = sea_instructions_for_dalvik.begin(); sea_instructions_for_dalvik.end() != cit; ++cit) { last_node = node; @@ -250,7 +250,6 @@ void SeaGraph::BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, DCHECK(it != target_regions.end()); AddEdge(r, it->second); // Add edge to branch target. } - std::map<const uint16_t*, Region*>::iterator it = target_regions.find(&code[i]); if (target_regions.end() != it) { // Get the already created region because this is a branch target. @@ -332,7 +331,8 @@ void SeaGraph::ConvertToSSA() { int global = *globals_it; // Copy the set, because we will modify the worklist as we go. std::set<Region*> worklist((*(blocks.find(global))).second); - for (std::set<Region*>::const_iterator b_it = worklist.begin(); b_it != worklist.end(); b_it++) { + for (std::set<Region*>::const_iterator b_it = worklist.begin(); + b_it != worklist.end(); b_it++) { std::set<Region*>* df = (*b_it)->GetDominanceFrontier(); for (std::set<Region*>::const_iterator df_it = df->begin(); df_it != df->end(); df_it++) { if ((*df_it)->InsertPhiFor(global)) { @@ -490,53 +490,44 @@ SeaNode* Region::GetLastChild() const { return NULL; } -void Region::ToDot(std::string& result) const { - result += "\n// Region: \n" + StringId() + " [label=\"region " + StringId() + "(rpo="; +void Region::ToDot(std::string& result, const art::DexFile& dex_file) const { + result += "\n// Region: \nsubgraph " + StringId() + " { label=\"region " + StringId() + "(rpo="; result += art::StringPrintf("%d", rpo_number_); if (NULL != GetIDominator()) { result += " dom=" + GetIDominator()->StringId(); } - result += ")\"];\n"; + result += ")\";\n"; + + for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions_.begin(); + cit != phi_instructions_.end(); cit++) { + result += (*cit)->StringId() +";\n"; + } + + for (std::vector<InstructionNode*>::const_iterator cit = instructions_.begin(); + cit != instructions_.end(); cit++) { + result += (*cit)->StringId() +";\n"; + } + + result += "} // End Region.\n"; // Save phi-nodes. for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions_.begin(); cit != phi_instructions_.end(); cit++) { - (*cit)->ToDot(result); - result += StringId() + " -> " + (*cit)->StringId() + "; // phi-function \n"; + (*cit)->ToDot(result, dex_file); } // Save instruction nodes. for (std::vector<InstructionNode*>::const_iterator cit = instructions_.begin(); cit != instructions_.end(); cit++) { - (*cit)->ToDot(result); - result += StringId() + " -> " + (*cit)->StringId() + "; // region -> instruction \n"; + (*cit)->ToDot(result, dex_file); } for (std::vector<Region*>::const_iterator cit = successors_.begin(); cit != successors_.end(); cit++) { DCHECK(NULL != *cit) << "Null successor found for SeaNode" << GetLastChild()->StringId() << "."; - result += GetLastChild()->StringId() + " -> " + (*cit)->StringId() + ";\n\n"; - } - // Save reaching definitions. - for (std::map<int, std::set<sea_ir::InstructionNode*>* >::const_iterator cit = - reaching_defs_.begin(); - cit != reaching_defs_.end(); cit++) { - for (std::set<sea_ir::InstructionNode*>::const_iterator - reaching_set_it = (*cit).second->begin(); - reaching_set_it != (*cit).second->end(); - reaching_set_it++) { - result += (*reaching_set_it)->StringId() + - " -> " + StringId() + - " [style=dotted]; // Reaching def.\n"; - } - } - // Save dominance frontier. - for (std::set<Region*>::const_iterator cit = df_.begin(); cit != df_.end(); cit++) { - result += StringId() + - " -> " + (*cit)->StringId() + - " [color=gray]; // Dominance frontier.\n"; + result += GetLastChild()->StringId() + " -> " + (*cit)->GetLastChild()->StringId() + + "[lhead=" + (*cit)->StringId() + ", " + "ltail=" + StringId() + "];\n\n"; } - result += "// End Region.\n"; } void Region::ComputeDownExposedDefs() { @@ -570,7 +561,8 @@ bool Region::UpdateReachingDefs() { pred_it != predecessors_.end(); pred_it++) { // The reaching_defs variable will contain reaching defs __for current predecessor only__ std::map<int, std::set<sea_ir::InstructionNode*>* > reaching_defs; - std::map<int, std::set<sea_ir::InstructionNode*>* >* pred_reaching = (*pred_it)->GetReachingDefs(); + std::map<int, std::set<sea_ir::InstructionNode*>* >* pred_reaching = + (*pred_it)->GetReachingDefs(); const std::map<int, InstructionNode*>* de_defs = (*pred_it)->GetDownExposedDefs(); // The definitions from the reaching set of the predecessor @@ -588,7 +580,8 @@ bool Region::UpdateReachingDefs() { // Now we combine the reaching map coming from the current predecessor (reaching_defs) // with the accumulated set from all predecessors so far (from new_reaching). - std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator reaching_it = reaching_defs.begin(); + std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator reaching_it = + reaching_defs.begin(); for (; reaching_it != reaching_defs.end(); reaching_it++) { std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator crt_entry = new_reaching.find(reaching_it->first); @@ -608,7 +601,8 @@ bool Region::UpdateReachingDefs() { // TODO: Find formal proof. int old_size = 0; if (-1 == reaching_defs_size_) { - std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator reaching_it = reaching_defs_.begin(); + std::map<int, std::set<sea_ir::InstructionNode*>*>::iterator reaching_it = + reaching_defs_.begin(); for (; reaching_it != reaching_defs_.end(); reaching_it++) { old_size += (*reaching_it).second->size(); } @@ -698,22 +692,36 @@ std::vector<InstructionNode*> InstructionNode::Create(const art::Instruction* in return sea_instructions; } -void InstructionNode::ToDot(std::string& result) const { - result += "// Instruction ("+StringId()+"): \n" + StringId() + - " [label=\"" + instruction_->DumpString(NULL) + "\""; - if (de_def_) { - result += "style=bold"; - } - result += "];\n"; +void InstructionNode::ToDotSSAEdges(std::string& result) const { // SSA definitions: - for (std::map<int, InstructionNode* >::const_iterator def_it = definition_edges_.begin(); + for (std::map<int, InstructionNode*>::const_iterator def_it = definition_edges_.begin(); def_it != definition_edges_.end(); def_it++) { if (NULL != def_it->second) { - result += def_it->second->StringId() + " -> " + StringId() +"[color=red,label=\""; - result += art::StringPrintf("%d", def_it->first); - result += "\"] ; // ssa edge\n"; + result += def_it->second->StringId() + " -> " + StringId() + "[color=gray,label=\""; + result += art::StringPrintf("vR = %d", def_it->first); + result += "\"] ; // ssa edge\n"; } } + + // SSA used-by: + if (DotConversion::SaveUseEdges()) { + for (std::vector<InstructionNode*>::const_iterator cit = used_in_.begin(); + cit != used_in_.end(); cit++) { + result += (*cit)->StringId() + " -> " + StringId() + "[color=gray,label=\""; + result += "\"] ; // SSA used-by edge\n"; + } + } +} + +void InstructionNode::ToDot(std::string& result, const art::DexFile& dex_file) const { + result += "// Instruction ("+StringId()+"): \n" + StringId() + + " [label=\"" + instruction_->DumpString(&dex_file) + "\""; + if (de_def_) { + result += "style=bold"; + } + result += "];\n"; + + ToDotSSAEdges(result); } void InstructionNode::MarkAsDEDef() { @@ -756,22 +764,12 @@ std::vector<int> InstructionNode::GetUses() { return uses; } -void PhiInstructionNode::ToDot(std::string& result) const { +void PhiInstructionNode::ToDot(std::string& result, const art::DexFile& dex_file) const { result += "// PhiInstruction: \n" + StringId() + " [label=\"" + "PHI("; result += art::StringPrintf("%d", register_no_); result += ")\""; result += "];\n"; - - for (std::vector<std::vector<InstructionNode*>*>::const_iterator pred_it = definition_edges_.begin(); - pred_it != definition_edges_.end(); pred_it++) { - std::vector<InstructionNode*>* defs_from_pred = *pred_it; - for (std::vector<InstructionNode* >::const_iterator def_it = defs_from_pred->begin(); - def_it != defs_from_pred->end(); def_it++) { - result += (*def_it)->StringId() + " -> " + StringId() +"[color=red,label=\"vR = "; - result += art::StringPrintf("%d", GetRegisterNumber()); - result += "\"] ; // phi-ssa edge\n"; - } - } + ToDotSSAEdges(result); } } // namespace sea_ir diff --git a/compiler/sea_ir/sea.h b/compiler/sea_ir/sea.h index 25ab1fed10..5cb84240ae 100644 --- a/compiler/sea_ir/sea.h +++ b/compiler/sea_ir/sea.h @@ -35,6 +35,17 @@ enum RegionNumbering { VISITING = -2 }; +// Stores options for turning a SEA IR graph to a .dot file. +class DotConversion { + public: + static bool SaveUseEdges() { + return save_use_edges_; + } + + private: + static const bool save_use_edges_ = false; // TODO: Enable per-sea graph configuration. +}; + class Region; class InstructionNode; @@ -49,10 +60,11 @@ class SignatureNode: public InstructionNode { explicit SignatureNode(unsigned int parameter_register):InstructionNode(NULL), parameter_register_(parameter_register) { } - void ToDot(std::string& result) const { + void ToDot(std::string& result, const art::DexFile& dex_file) const { result += StringId() +" [label=\"signature:"; result += art::StringPrintf("r%d", GetResultRegister()); result += "\"] // signature node\n"; + ToDotSSAEdges(result); } int GetResultRegister() const { @@ -77,7 +89,7 @@ class PhiInstructionNode: public InstructionNode { explicit PhiInstructionNode(int register_no): InstructionNode(NULL), register_no_(register_no), definition_edges_() {} // Appends to @result the .dot string representation of the instruction. - void ToDot(std::string& result) const; + void ToDot(std::string& result, const art::DexFile& dex_file) const; // Returns the register on which this phi-function is used. int GetRegisterNumber() const { return register_no_; @@ -98,6 +110,7 @@ class PhiInstructionNode: public InstructionNode { definition_edges_[predecessor_id] = new std::vector<InstructionNode*>(); } definition_edges_[predecessor_id]->push_back(definition); + definition->AddSSAUse(this); } // Returns the instruction that defines the phi register from predecessor @@ -125,7 +138,9 @@ class Region : public SeaNode { public: explicit Region(): SeaNode(), successors_(), predecessors_(), reaching_defs_size_(0), - rpo_number_(NOT_VISITED), idom_(NULL), idominated_set_(), df_(), phi_set_() {} + rpo_number_(NOT_VISITED), idom_(NULL), idominated_set_(), df_(), phi_set_() { + string_id_ = "cluster_" + string_id_; + } // Adds @instruction as an instruction node child in the current region. void AddChild(sea_ir::InstructionNode* instruction); // Returns the last instruction node child of the current region. @@ -138,7 +153,7 @@ class Region : public SeaNode { // Appends to @result a dot language formatted string representing the node and // (by convention) outgoing edges, so that the composition of theToDot() of all nodes // builds a complete dot graph (without prolog and epilog though). - virtual void ToDot(std::string& result) const; + virtual void ToDot(std::string& result, const art::DexFile& dex_file) const; // Computes Downward Exposed Definitions for the current node. void ComputeDownExposedDefs(); const std::map<int, sea_ir::InstructionNode*>* GetDownExposedDefs() const; @@ -242,7 +257,7 @@ class Region : public SeaNode { // and acts as starting point for visitors (ex: during code generation). class SeaGraph: IVisitable { public: - static SeaGraph* GetCurrentGraph(); + static SeaGraph* GetCurrentGraph(const art::DexFile&); void CompileMethod(const art::DexFile::CodeItem* code_item, uint32_t class_def_idx, uint32_t method_idx, const art::DexFile& dex_file); @@ -264,7 +279,8 @@ class SeaGraph: IVisitable { uint32_t method_idx_; private: - SeaGraph(): class_def_idx_(0), method_idx_(0), regions_(), parameters_() { + explicit SeaGraph(const art::DexFile& df): + class_def_idx_(0), method_idx_(0), regions_(), parameters_(), dex_file_(df) { } // Registers @childReg as a region belonging to the SeaGraph instance. void AddRegion(Region* childReg); @@ -319,6 +335,7 @@ class SeaGraph: IVisitable { static SeaGraph graph_; std::vector<Region*> regions_; std::vector<SignatureNode*> parameters_; + const art::DexFile& dex_file_; }; } // namespace sea_ir #endif // ART_COMPILER_SEA_IR_SEA_H_ diff --git a/compiler/sea_ir/sea_node.h b/compiler/sea_ir/sea_node.h index 5d28f8aa72..c13e5d6aba 100644 --- a/compiler/sea_ir/sea_node.h +++ b/compiler/sea_ir/sea_node.h @@ -30,7 +30,7 @@ class IVisitable { }; // This abstract class provides the essential services that -// we want each SEA IR element should have. +// we want each SEA IR element to have. // At the moment, these are: // - an id and corresponding string representation. // - a .dot graph language representation for .dot output. @@ -42,6 +42,7 @@ class SeaNode: public IVisitable { explicit SeaNode():id_(GetNewId()), string_id_() { string_id_ = art::StringPrintf("%d", id_); } + // Adds CFG predecessors and successors to each block. void AddSuccessor(Region* successor); void AddPredecessor(Region* predecesor); @@ -58,7 +59,7 @@ class SeaNode: public IVisitable { // Appends to @result a dot language formatted string representing the node and // (by convention) outgoing edges, so that the composition of theToDot() of all nodes // builds a complete dot graph, but without prolog ("digraph {") and epilog ("}"). - virtual void ToDot(std::string& result) const = 0; + virtual void ToDot(std::string& result, const art::DexFile& dex_file) const = 0; virtual ~SeaNode() { } diff --git a/compiler/stubs/portable/stubs.cc b/compiler/stubs/portable/stubs.cc index 69568d7a19..def43e2bd2 100644 --- a/compiler/stubs/portable/stubs.cc +++ b/compiler/stubs/portable/stubs.cc @@ -16,11 +16,11 @@ #include "stubs/stubs.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "jni_internal.h" -#include "oat/utils/arm/assembler_arm.h" -#include "oat/utils/mips/assembler_mips.h" -#include "oat/utils/x86/assembler_x86.h" -#include "oat/runtime/oat_support_entrypoints.h" +#include "utils/arm/assembler_arm.h" +#include "utils/mips/assembler_mips.h" +#include "utils/x86/assembler_x86.h" #include "stack_indirect_reference_table.h" #include "sirt_ref.h" @@ -34,7 +34,8 @@ const std::vector<uint8_t>* CreatePortableResolutionTrampoline() { RegList save = (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | (1 << LR); __ PushList(save); - __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode)); + __ LoadFromOffset(kLoadWord, R12, TR, + PORTABLE_ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode)); __ mov(R3, ShifterOperand(TR)); // Pass Thread::Current() in R3 __ mov(R2, ShifterOperand(SP)); // Pass sp for Method** callee_addr __ IncreaseFrameSize(12); // 3 words of space for alignment @@ -69,7 +70,7 @@ const std::vector<uint8_t>* CreatePortableResolutionTrampoline() { __ StoreToOffset(kStoreWord, A0, SP, 0); __ LoadFromOffset(kLoadWord, T9, S1, - ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode)); + PORTABLE_ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode)); __ Move(A3, S1); // Pass Thread::Current() in A3 __ Move(A2, SP); // Pass SP for Method** callee_addr __ Jalr(T9); // Call to resolution trampoline (callee, receiver, callee_addr, Thread*) @@ -112,7 +113,7 @@ const std::vector<uint8_t>* CreatePortableResolutionTrampoline() { __ pushl(ECX); // pass receiver __ pushl(EAX); // pass called // Call to resolve method. - __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode)), + __ Call(ThreadOffset(PORTABLE_ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode)), X86ManagedRegister::FromCpuRegister(ECX)); __ leave(); diff --git a/compiler/stubs/quick/stubs.cc b/compiler/stubs/quick/stubs.cc index 8fc2a81d24..912f1c0746 100644 --- a/compiler/stubs/quick/stubs.cc +++ b/compiler/stubs/quick/stubs.cc @@ -16,11 +16,11 @@ #include "stubs/stubs.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "jni_internal.h" -#include "oat/runtime/oat_support_entrypoints.h" -#include "oat/utils/arm/assembler_arm.h" -#include "oat/utils/mips/assembler_mips.h" -#include "oat/utils/x86/assembler_x86.h" +#include "utils/arm/assembler_arm.h" +#include "utils/mips/assembler_mips.h" +#include "utils/x86/assembler_x86.h" #include "sirt_ref.h" #include "stack_indirect_reference_table.h" @@ -46,7 +46,7 @@ const std::vector<uint8_t>* CreateQuickResolutionTrampoline() { // TODO: enable when GetCalleeSaveMethod is available at stub generation time // DCHECK_EQ(save, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetCoreSpillMask()); __ PushList(save); - __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode)); + __ LoadFromOffset(kLoadWord, R12, TR, QUICK_ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode)); __ mov(R3, ShifterOperand(TR)); // Pass Thread::Current() in R3 __ IncreaseFrameSize(8); // 2 words of space for alignment __ mov(R2, ShifterOperand(SP)); // Pass SP @@ -71,7 +71,7 @@ const std::vector<uint8_t>* CreateQuickResolutionTrampoline() { const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() { UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm))); - __ LoadFromOffset(kLoadWord, PC, R0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry)); + __ LoadFromOffset(kLoadWord, PC, R0, QUICK_ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry)); __ bkpt(0); size_t cs = assembler->CodeSize(); @@ -85,7 +85,7 @@ const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() { const std::vector<uint8_t>* CreateInterpreterToQuickEntry() { UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm))); - __ LoadFromOffset(kLoadWord, PC, R0, ENTRYPOINT_OFFSET(pInterpreterToQuickEntry)); + __ LoadFromOffset(kLoadWord, PC, R0, QUICK_ENTRYPOINT_OFFSET(pInterpreterToQuickEntry)); __ bkpt(0); size_t cs = assembler->CodeSize(); @@ -123,7 +123,7 @@ const std::vector<uint8_t>* CreateQuickResolutionTrampoline() { __ StoreToOffset(kStoreWord, A2, SP, 8); __ StoreToOffset(kStoreWord, A1, SP, 4); - __ LoadFromOffset(kLoadWord, T9, S1, ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode)); + __ LoadFromOffset(kLoadWord, T9, S1, QUICK_ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode)); __ Move(A3, S1); // Pass Thread::Current() in A3 __ Move(A2, SP); // Pass SP for Method** callee_addr __ Jalr(T9); // Call to resolution trampoline (method_idx, receiver, sp, Thread*) @@ -161,7 +161,7 @@ const std::vector<uint8_t>* CreateQuickResolutionTrampoline() { const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() { UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips))); - __ LoadFromOffset(kLoadWord, T9, A0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry)); + __ LoadFromOffset(kLoadWord, T9, A0, QUICK_ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry)); __ Jr(T9); __ Break(); @@ -176,7 +176,7 @@ const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() { const std::vector<uint8_t>* CreateInterpreterToQuickEntry() { UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips))); - __ LoadFromOffset(kLoadWord, T9, A0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry)); + __ LoadFromOffset(kLoadWord, T9, A0, QUICK_ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry)); __ Jr(T9); __ Break(); @@ -208,7 +208,7 @@ const std::vector<uint8_t>* CreateQuickResolutionTrampoline() { __ pushl(EAX); // pass Method* // Call to resolve method. - __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode)), + __ Call(ThreadOffset(QUICK_ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode)), X86ManagedRegister::FromCpuRegister(ECX)); __ movl(EDI, EAX); // save code pointer in EDI @@ -236,7 +236,7 @@ const std::vector<uint8_t>* CreateQuickResolutionTrampoline() { const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() { UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86))); - __ fs()->jmp(Address::Absolute(ThreadOffset(ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry)))); + __ fs()->jmp(Address::Absolute(ThreadOffset(QUICK_ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry)))); size_t cs = assembler->CodeSize(); UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs)); @@ -249,7 +249,7 @@ const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() { const std::vector<uint8_t>* CreateInterpreterToQuickEntry() { UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86))); - __ fs()->jmp(Address::Absolute(ThreadOffset(ENTRYPOINT_OFFSET(pInterpreterToQuickEntry)))); + __ fs()->jmp(Address::Absolute(ThreadOffset(QUICK_ENTRYPOINT_OFFSET(pInterpreterToQuickEntry)))); size_t cs = assembler->CodeSize(); UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs)); diff --git a/runtime/oat/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc index 960a60dfad..fa202c3017 100644 --- a/runtime/oat/utils/arm/assembler_arm.cc +++ b/compiler/utils/arm/assembler_arm.cc @@ -17,7 +17,7 @@ #include "assembler_arm.h" #include "base/logging.h" -#include "oat/runtime/oat_support_entrypoints.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "offsets.h" #include "thread.h" #include "utils.h" @@ -1884,7 +1884,7 @@ void ArmExceptionSlowPath::Emit(Assembler* sasm) { // Don't care about preserving R0 as this call won't return __ mov(R0, ShifterOperand(scratch_.AsCoreRegister())); // Set up call to Thread::Current()->pDeliverException - __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pDeliverException)); + __ LoadFromOffset(kLoadWord, R12, TR, QUICK_ENTRYPOINT_OFFSET(pDeliverException)); __ blx(R12); // Call never returns __ bkpt(0); diff --git a/runtime/oat/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index b8c79d21b9..757a8a2e99 100644 --- a/runtime/oat/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -14,15 +14,15 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_UTILS_ARM_ASSEMBLER_ARM_H_ -#define ART_RUNTIME_OAT_UTILS_ARM_ASSEMBLER_ARM_H_ +#ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_ +#define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_ #include <vector> #include "base/logging.h" #include "constants_arm.h" -#include "oat/utils/arm/managed_register_arm.h" -#include "oat/utils/assembler.h" +#include "utils/arm/managed_register_arm.h" +#include "utils/assembler.h" #include "offsets.h" #include "utils.h" @@ -656,4 +656,4 @@ class ArmExceptionSlowPath : public SlowPath { } // namespace arm } // namespace art -#endif // ART_RUNTIME_OAT_UTILS_ARM_ASSEMBLER_ARM_H_ +#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_ diff --git a/runtime/constants_arm.h b/compiler/utils/arm/constants_arm.h index bbb9242def..cc795b1482 100644 --- a/runtime/constants_arm.h +++ b/compiler/utils/arm/constants_arm.h @@ -14,13 +14,14 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_CONSTANTS_ARM_H_ -#define ART_RUNTIME_CONSTANTS_ARM_H_ +#ifndef ART_COMPILER_UTILS_ARM_CONSTANTS_ARM_H_ +#define ART_COMPILER_UTILS_ARM_CONSTANTS_ARM_H_ #include <stdint.h> #include <iosfwd> +#include "arch/arm/registers_arm.h" #include "base/casts.h" #include "base/logging.h" #include "globals.h" @@ -47,36 +48,6 @@ namespace arm { #endif -// Values for registers. -enum Register { - R0 = 0, - R1 = 1, - R2 = 2, - R3 = 3, - R4 = 4, - R5 = 5, - R6 = 6, - R7 = 7, - R8 = 8, - R9 = 9, - R10 = 10, - R11 = 11, - R12 = 12, - R13 = 13, - R14 = 14, - R15 = 15, - TR = 9, // thread register - FP = 11, - IP = 12, - SP = 13, - LR = 14, - PC = 15, - kNumberOfCoreRegisters = 16, - kNoRegister = -1, -}; -std::ostream& operator<<(std::ostream& os, const Register& rhs); - - enum ScaleFactor { TIMES_1 = 0, TIMES_2 = 1, @@ -84,47 +55,6 @@ enum ScaleFactor { TIMES_8 = 3 }; - -// Values for single-precision floating point registers. -enum SRegister { - S0 = 0, - S1 = 1, - S2 = 2, - S3 = 3, - S4 = 4, - S5 = 5, - S6 = 6, - S7 = 7, - S8 = 8, - S9 = 9, - S10 = 10, - S11 = 11, - S12 = 12, - S13 = 13, - S14 = 14, - S15 = 15, - S16 = 16, - S17 = 17, - S18 = 18, - S19 = 19, - S20 = 20, - S21 = 21, - S22 = 22, - S23 = 23, - S24 = 24, - S25 = 25, - S26 = 26, - S27 = 27, - S28 = 28, - S29 = 29, - S30 = 30, - S31 = 31, - kNumberOfSRegisters = 32, - kNoSRegister = -1, -}; -std::ostream& operator<<(std::ostream& os, const SRegister& rhs); - - // Values for double-precision floating point registers. enum DRegister { D0 = 0, @@ -516,4 +446,4 @@ class Instr { } // namespace arm } // namespace art -#endif // ART_RUNTIME_CONSTANTS_ARM_H_ +#endif // ART_COMPILER_UTILS_ARM_CONSTANTS_ARM_H_ diff --git a/runtime/oat/utils/arm/managed_register_arm.cc b/compiler/utils/arm/managed_register_arm.cc index 57c23059de..57c23059de 100644 --- a/runtime/oat/utils/arm/managed_register_arm.cc +++ b/compiler/utils/arm/managed_register_arm.cc diff --git a/runtime/oat/utils/arm/managed_register_arm.h b/compiler/utils/arm/managed_register_arm.h index 01596bb6b1..a496c87150 100644 --- a/runtime/oat/utils/arm/managed_register_arm.h +++ b/compiler/utils/arm/managed_register_arm.h @@ -14,12 +14,12 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_UTILS_ARM_MANAGED_REGISTER_ARM_H_ -#define ART_RUNTIME_OAT_UTILS_ARM_MANAGED_REGISTER_ARM_H_ +#ifndef ART_COMPILER_UTILS_ARM_MANAGED_REGISTER_ARM_H_ +#define ART_COMPILER_UTILS_ARM_MANAGED_REGISTER_ARM_H_ #include "base/logging.h" #include "constants_arm.h" -#include "oat/utils/managed_register.h" +#include "utils/managed_register.h" namespace art { namespace arm { @@ -271,4 +271,4 @@ inline arm::ArmManagedRegister ManagedRegister::AsArm() const { } // namespace art -#endif // ART_RUNTIME_OAT_UTILS_ARM_MANAGED_REGISTER_ARM_H_ +#endif // ART_COMPILER_UTILS_ARM_MANAGED_REGISTER_ARM_H_ diff --git a/runtime/oat/utils/arm/managed_register_arm_test.cc b/compiler/utils/arm/managed_register_arm_test.cc index f5d4cc0d10..f5d4cc0d10 100644 --- a/runtime/oat/utils/arm/managed_register_arm_test.cc +++ b/compiler/utils/arm/managed_register_arm_test.cc diff --git a/runtime/oat/utils/assembler.cc b/compiler/utils/assembler.cc index 92ce0b8001..92ce0b8001 100644 --- a/runtime/oat/utils/assembler.cc +++ b/compiler/utils/assembler.cc diff --git a/runtime/oat/utils/assembler.h b/compiler/utils/assembler.h index 05e2732c5f..9d79002625 100644 --- a/runtime/oat/utils/assembler.h +++ b/compiler/utils/assembler.h @@ -14,16 +14,16 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_UTILS_ASSEMBLER_H_ -#define ART_RUNTIME_OAT_UTILS_ASSEMBLER_H_ +#ifndef ART_COMPILER_UTILS_ASSEMBLER_H_ +#define ART_COMPILER_UTILS_ASSEMBLER_H_ #include <vector> #include "base/logging.h" #include "base/macros.h" -#include "constants_arm.h" -#include "constants_mips.h" -#include "constants_x86.h" +#include "arm/constants_arm.h" +#include "mips/constants_mips.h" +#include "x86/constants_x86.h" #include "instruction_set.h" #include "managed_register.h" #include "memory_region.h" @@ -456,4 +456,4 @@ class Assembler { } // namespace art -#endif // ART_RUNTIME_OAT_UTILS_ASSEMBLER_H_ +#endif // ART_COMPILER_UTILS_ASSEMBLER_H_ diff --git a/runtime/oat/utils/managed_register.h b/compiler/utils/managed_register.h index 4dd2acd8fe..4ad1763754 100644 --- a/runtime/oat/utils/managed_register.h +++ b/compiler/utils/managed_register.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_UTILS_MANAGED_REGISTER_H_ -#define ART_RUNTIME_OAT_UTILS_MANAGED_REGISTER_H_ +#ifndef ART_COMPILER_UTILS_MANAGED_REGISTER_H_ +#define ART_COMPILER_UTILS_MANAGED_REGISTER_H_ namespace art { @@ -69,4 +69,4 @@ class ManagedRegister { } // namespace art -#endif // ART_RUNTIME_OAT_UTILS_MANAGED_REGISTER_H_ +#endif // ART_COMPILER_UTILS_MANAGED_REGISTER_H_ diff --git a/runtime/oat/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc index 25ba9b2219..931d7ab0f7 100644 --- a/runtime/oat/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -17,8 +17,8 @@ #include "assembler_mips.h" #include "base/casts.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "memory_region.h" -#include "oat/runtime/oat_support_entrypoints.h" #include "thread.h" namespace art { @@ -36,30 +36,6 @@ class DirectCallRelocation : public AssemblerFixup { }; #endif -static const char* kRegisterNames[] = { - "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra", -}; -std::ostream& operator<<(std::ostream& os, const Register& rhs) { - if (rhs >= ZERO && rhs <= RA) { - os << kRegisterNames[rhs]; - } else { - os << "Register[" << static_cast<int>(rhs) << "]"; - } - return os; -} - -std::ostream& operator<<(std::ostream& os, const FRegister& rhs) { - if (rhs >= F0 && rhs < kNumberOfFRegisters) { - os << "f" << static_cast<int>(rhs); - } else { - os << "FRegister[" << static_cast<int>(rhs) << "]"; - } - return os; -} - std::ostream& operator<<(std::ostream& os, const DRegister& rhs) { if (rhs >= D0 && rhs < kNumberOfDRegisters) { os << "d" << static_cast<int>(rhs); @@ -1012,7 +988,7 @@ void MipsExceptionSlowPath::Emit(Assembler* sasm) { // Don't care about preserving A0 as this call won't return __ Move(A0, scratch_.AsCoreRegister()); // Set up call to Thread::Current()->pDeliverException - __ LoadFromOffset(kLoadWord, T9, S1, ENTRYPOINT_OFFSET(pDeliverException)); + __ LoadFromOffset(kLoadWord, T9, S1, QUICK_ENTRYPOINT_OFFSET(pDeliverException)); __ Jr(T9); // Call never returns __ Break(); diff --git a/runtime/oat/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h index 8f4a33a40e..0f5f2fe199 100644 --- a/runtime/oat/utils/mips/assembler_mips.h +++ b/compiler/utils/mips/assembler_mips.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_UTILS_MIPS_ASSEMBLER_MIPS_H_ -#define ART_RUNTIME_OAT_UTILS_MIPS_ASSEMBLER_MIPS_H_ +#ifndef ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_ +#define ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_ #include <vector> @@ -23,7 +23,7 @@ #include "constants_mips.h" #include "globals.h" #include "managed_register_mips.h" -#include "oat/utils/assembler.h" +#include "utils/assembler.h" #include "offsets.h" #include "utils.h" @@ -504,4 +504,4 @@ class MipsExceptionSlowPath : public SlowPath { } // namespace mips } // namespace art -#endif // ART_RUNTIME_OAT_UTILS_MIPS_ASSEMBLER_MIPS_H_ +#endif // ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_ diff --git a/runtime/constants_mips.h b/compiler/utils/mips/constants_mips.h index fb56493a14..44ed5cc124 100644 --- a/runtime/constants_mips.h +++ b/compiler/utils/mips/constants_mips.h @@ -14,11 +14,12 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_CONSTANTS_MIPS_H_ -#define ART_RUNTIME_CONSTANTS_MIPS_H_ +#ifndef ART_COMPILER_UTILS_MIPS_CONSTANTS_MIPS_H_ +#define ART_COMPILER_UTILS_MIPS_CONSTANTS_MIPS_H_ #include <iosfwd> +#include "arch/mips/registers_mips.h" #include "base/logging.h" #include "base/macros.h" #include "globals.h" @@ -26,83 +27,6 @@ namespace art { namespace mips { -enum Register { - ZERO = 0, - AT = 1, // Assembler temporary. - V0 = 2, // Values. - V1 = 3, - A0 = 4, // Arguments. - A1 = 5, - A2 = 6, - A3 = 7, - T0 = 8, // Temporaries. - T1 = 9, - T2 = 10, - T3 = 11, - T4 = 12, - T5 = 13, - T6 = 14, - T7 = 15, - S0 = 16, // Saved values. - S1 = 17, - S2 = 18, - S3 = 19, - S4 = 20, - S5 = 21, - S6 = 22, - S7 = 23, - T8 = 24, // More temporaries. - T9 = 25, - K0 = 26, // Reserved for trap handler. - K1 = 27, - GP = 28, // Global pointer. - SP = 29, // Stack pointer. - FP = 30, // Saved value/frame pointer. - RA = 31, // Return address. - kNumberOfCoreRegisters = 32, - kNoRegister = -1 // Signals an illegal register. -}; -std::ostream& operator<<(std::ostream& os, const Register& rhs); - -// Values for single-precision floating point registers. -enum FRegister { - F0 = 0, - F1 = 1, - F2 = 2, - F3 = 3, - F4 = 4, - F5 = 5, - F6 = 6, - F7 = 7, - F8 = 8, - F9 = 9, - F10 = 10, - F11 = 11, - F12 = 12, - F13 = 13, - F14 = 14, - F15 = 15, - F16 = 16, - F17 = 17, - F18 = 18, - F19 = 19, - F20 = 20, - F21 = 21, - F22 = 22, - F23 = 23, - F24 = 24, - F25 = 25, - F26 = 26, - F27 = 27, - F28 = 28, - F29 = 29, - F30 = 30, - F31 = 31, - kNumberOfFRegisters = 32, - kNoFRegister = -1, -}; -std::ostream& operator<<(std::ostream& os, const FRegister& rhs); - // Values for double-precision floating point registers. enum DRegister { D0 = 0, @@ -183,4 +107,4 @@ class Instr { } // namespace mips } // namespace art -#endif // ART_RUNTIME_CONSTANTS_MIPS_H_ +#endif // ART_COMPILER_UTILS_MIPS_CONSTANTS_MIPS_H_ diff --git a/runtime/oat/utils/mips/managed_register_mips.cc b/compiler/utils/mips/managed_register_mips.cc index 195dafb0a1..195dafb0a1 100644 --- a/runtime/oat/utils/mips/managed_register_mips.cc +++ b/compiler/utils/mips/managed_register_mips.cc diff --git a/runtime/oat/utils/mips/managed_register_mips.h b/compiler/utils/mips/managed_register_mips.h index b335ff9649..dd55cc4e6a 100644 --- a/runtime/oat/utils/mips/managed_register_mips.h +++ b/compiler/utils/mips/managed_register_mips.h @@ -14,11 +14,11 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_ -#define ART_RUNTIME_OAT_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_ +#ifndef ART_COMPILER_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_ +#define ART_COMPILER_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_ #include "constants_mips.h" -#include "oat/utils/managed_register.h" +#include "utils/managed_register.h" namespace art { namespace mips { @@ -225,4 +225,4 @@ inline mips::MipsManagedRegister ManagedRegister::AsMips() const { } // namespace art -#endif // ART_RUNTIME_OAT_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_ +#endif // ART_COMPILER_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_ diff --git a/runtime/oat/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index fd8f152c54..9095180246 100644 --- a/runtime/oat/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -17,8 +17,8 @@ #include "assembler_x86.h" #include "base/casts.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "memory_region.h" -#include "oat/runtime/oat_support_entrypoints.h" #include "thread.h" namespace art { @@ -35,18 +35,6 @@ class DirectCallRelocation : public AssemblerFixup { } }; -static const char* kRegisterNames[] = { - "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", -}; -std::ostream& operator<<(std::ostream& os, const Register& rhs) { - if (rhs >= EAX && rhs <= EDI) { - os << kRegisterNames[rhs]; - } else { - os << "Register[" << static_cast<int>(rhs) << "]"; - } - return os; -} - std::ostream& operator<<(std::ostream& os, const XmmRegister& reg) { return os << "XMM" << static_cast<int>(reg); } @@ -1849,7 +1837,7 @@ void X86ExceptionSlowPath::Emit(Assembler *sasm) { } // Pass exception as argument in EAX __ fs()->movl(EAX, Address::Absolute(Thread::ExceptionOffset())); - __ fs()->call(Address::Absolute(ENTRYPOINT_OFFSET(pDeliverException))); + __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(pDeliverException))); // this call should never return __ int3(); #undef __ diff --git a/runtime/oat/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index e0fbe0e7a3..4ba03d1bd3 100644 --- a/runtime/oat/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -14,16 +14,16 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_UTILS_X86_ASSEMBLER_X86_H_ -#define ART_RUNTIME_OAT_UTILS_X86_ASSEMBLER_X86_H_ +#ifndef ART_COMPILER_UTILS_X86_ASSEMBLER_X86_H_ +#define ART_COMPILER_UTILS_X86_ASSEMBLER_X86_H_ #include <vector> #include "base/macros.h" #include "constants_x86.h" #include "globals.h" #include "managed_register_x86.h" -#include "oat/utils/assembler.h" #include "offsets.h" +#include "utils/assembler.h" #include "utils.h" namespace art { @@ -643,4 +643,4 @@ class X86ExceptionSlowPath : public SlowPath { } // namespace x86 } // namespace art -#endif // ART_RUNTIME_OAT_UTILS_X86_ASSEMBLER_X86_H_ +#endif // ART_COMPILER_UTILS_X86_ASSEMBLER_X86_H_ diff --git a/runtime/oat/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc index 5d8a3b1521..5d8a3b1521 100644 --- a/runtime/oat/utils/x86/assembler_x86_test.cc +++ b/compiler/utils/x86/assembler_x86_test.cc diff --git a/runtime/constants_x86.h b/compiler/utils/x86/constants_x86.h index bb18b6b23b..45c3834a98 100644 --- a/runtime/constants_x86.h +++ b/compiler/utils/x86/constants_x86.h @@ -14,11 +14,12 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_CONSTANTS_X86_H_ -#define ART_RUNTIME_CONSTANTS_X86_H_ +#ifndef ART_COMPILER_UTILS_X86_CONSTANTS_X86_H_ +#define ART_COMPILER_UTILS_X86_CONSTANTS_X86_H_ #include <iosfwd> +#include "arch/x86/registers_x86.h" #include "base/logging.h" #include "base/macros.h" #include "globals.h" @@ -26,21 +27,6 @@ namespace art { namespace x86 { -enum Register { - EAX = 0, - ECX = 1, - EDX = 2, - EBX = 3, - ESP = 4, - EBP = 5, - ESI = 6, - EDI = 7, - kNumberOfCpuRegisters = 8, - kFirstByteUnsafeRegister = 4, - kNoRegister = -1 // Signals an illegal register. -}; -std::ostream& operator<<(std::ostream& os, const Register& rhs); - enum ByteRegister { AL = 0, CL = 1, @@ -137,4 +123,4 @@ class Instr { } // namespace x86 } // namespace art -#endif // ART_RUNTIME_CONSTANTS_X86_H_ +#endif // ART_COMPILER_UTILS_X86_CONSTANTS_X86_H_ diff --git a/runtime/oat/utils/x86/managed_register_x86.cc b/compiler/utils/x86/managed_register_x86.cc index 4697d06136..4697d06136 100644 --- a/runtime/oat/utils/x86/managed_register_x86.cc +++ b/compiler/utils/x86/managed_register_x86.cc diff --git a/runtime/oat/utils/x86/managed_register_x86.h b/compiler/utils/x86/managed_register_x86.h index b564a8396f..0201a96ad0 100644 --- a/runtime/oat/utils/x86/managed_register_x86.h +++ b/compiler/utils/x86/managed_register_x86.h @@ -14,11 +14,11 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_UTILS_X86_MANAGED_REGISTER_X86_H_ -#define ART_RUNTIME_OAT_UTILS_X86_MANAGED_REGISTER_X86_H_ +#ifndef ART_COMPILER_UTILS_X86_MANAGED_REGISTER_X86_H_ +#define ART_COMPILER_UTILS_X86_MANAGED_REGISTER_X86_H_ #include "constants_x86.h" -#include "oat/utils/managed_register.h" +#include "utils/managed_register.h" namespace art { namespace x86 { @@ -215,4 +215,4 @@ inline x86::X86ManagedRegister ManagedRegister::AsX86() const { } // namespace art -#endif // ART_RUNTIME_OAT_UTILS_X86_MANAGED_REGISTER_X86_H_ +#endif // ART_COMPILER_UTILS_X86_MANAGED_REGISTER_X86_H_ diff --git a/runtime/oat/utils/x86/managed_register_x86_test.cc b/compiler/utils/x86/managed_register_x86_test.cc index 4fbafdadf9..4fbafdadf9 100644 --- a/runtime/oat/utils/x86/managed_register_x86_test.cc +++ b/compiler/utils/x86/managed_register_x86_test.cc diff --git a/runtime/vector_output_stream.cc b/compiler/vector_output_stream.cc index e5ff729036..e5ff729036 100644 --- a/runtime/vector_output_stream.cc +++ b/compiler/vector_output_stream.cc diff --git a/runtime/vector_output_stream.h b/compiler/vector_output_stream.h index 7daa39ffa5..a3f82262af 100644 --- a/runtime/vector_output_stream.h +++ b/compiler/vector_output_stream.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_VECTOR_OUTPUT_STREAM_H_ -#define ART_RUNTIME_VECTOR_OUTPUT_STREAM_H_ +#ifndef ART_COMPILER_VECTOR_OUTPUT_STREAM_H_ +#define ART_COMPILER_VECTOR_OUTPUT_STREAM_H_ #include "output_stream.h" @@ -62,4 +62,4 @@ class VectorOutputStream : public OutputStream { } // namespace art -#endif // ART_RUNTIME_VECTOR_OUTPUT_STREAM_H_ +#endif // ART_COMPILER_VECTOR_OUTPUT_STREAM_H_ diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index f79ddb1935..c8c43476dc 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -230,7 +230,7 @@ class Dex2Oat { bool image, UniquePtr<CompilerDriver::DescriptorSet>& image_classes, bool dump_stats, - TimingLogger& timings) + base::TimingLogger& timings) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // SirtRef and ClassLoader creation needs to come after Runtime::Create jobject class_loader = NULL; @@ -263,11 +263,11 @@ class Dex2Oat { Thread::Current()->TransitionFromRunnableToSuspended(kNative); - timings.AddSplit("dex2oat Setup"); driver->CompileAll(class_loader, dex_files, timings); Thread::Current()->TransitionFromSuspendedToRunnable(); + timings.NewSplit("dex2oat OatWriter"); std::string image_file_location; uint32_t image_file_location_oat_checksum = 0; uint32_t image_file_location_oat_data_begin = 0; @@ -287,13 +287,11 @@ class Dex2Oat { image_file_location_oat_data_begin, image_file_location, driver.get()); - timings.AddSplit("dex2oat OatWriter"); if (!driver->WriteElf(android_root, is_host, dex_files, oat_writer, oat_file)) { LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath(); return NULL; } - timings.AddSplit("dex2oat ElfWriter"); return driver.release(); } @@ -563,7 +561,7 @@ const unsigned int WatchDog::kWatchDogWarningSeconds; const unsigned int WatchDog::kWatchDogTimeoutSeconds; static int dex2oat(int argc, char** argv) { - TimingLogger timings("compiler", false); + base::TimingLogger timings("compiler", false, false); InitLogging(argv); @@ -928,6 +926,7 @@ static int dex2oat(int argc, char** argv) { } } + timings.StartSplit("dex2oat Setup"); UniquePtr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option, host_prefix.get(), android_root, @@ -998,13 +997,13 @@ static int dex2oat(int argc, char** argv) { // Elf32_Phdr.p_vaddr values by the desired base address. // if (image) { + timings.NewSplit("dex2oat ImageWriter"); Thread::Current()->TransitionFromRunnableToSuspended(kNative); bool image_creation_success = dex2oat->CreateImageFile(image_filename, image_base, oat_unstripped, oat_location, *compiler.get()); - timings.AddSplit("dex2oat ImageWriter"); Thread::Current()->TransitionFromSuspendedToRunnable(); if (!image_creation_success) { return EXIT_FAILURE; @@ -1014,7 +1013,7 @@ static int dex2oat(int argc, char** argv) { if (is_host) { if (dump_timings && timings.GetTotalNs() > MsToNs(1000)) { - LOG(INFO) << Dumpable<TimingLogger>(timings); + LOG(INFO) << Dumpable<base::TimingLogger>(timings); } return EXIT_SUCCESS; } @@ -1022,6 +1021,7 @@ static int dex2oat(int argc, char** argv) { // If we don't want to strip in place, copy from unstripped location to stripped location. // We need to strip after image creation because FixupElf needs to use .strtab. if (oat_unstripped != oat_stripped) { + timings.NewSplit("dex2oat OatFile copy"); oat_file.reset(); UniquePtr<File> in(OS::OpenFile(oat_unstripped.c_str(), false)); UniquePtr<File> out(OS::OpenFile(oat_stripped.c_str(), true)); @@ -1036,23 +1036,25 @@ static int dex2oat(int argc, char** argv) { CHECK(write_ok); } oat_file.reset(out.release()); - timings.AddSplit("dex2oat OatFile copy"); LOG(INFO) << "Oat file copied successfully (stripped): " << oat_stripped; } #if ART_USE_PORTABLE_COMPILER // We currently only generate symbols on Portable + timings.NewSplit("dex2oat ElfStripper"); // Strip unneeded sections for target off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET); CHECK_EQ(0, seek_actual); ElfStripper::Strip(oat_file.get()); - timings.AddSplit("dex2oat ElfStripper"); + // We wrote the oat file successfully, and want to keep it. LOG(INFO) << "Oat file written successfully (stripped): " << oat_location; #endif // ART_USE_PORTABLE_COMPILER + timings.EndSplit(); + if (dump_timings && timings.GetTotalNs() > MsToNs(1000)) { - LOG(INFO) << Dumpable<TimingLogger>(timings); + LOG(INFO) << Dumpable<base::TimingLogger>(timings); } return EXIT_SUCCESS; } diff --git a/runtime/Android.mk b/runtime/Android.mk index 7734aa5d08..51bb3eb2d3 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -111,13 +111,6 @@ LIBART_COMMON_SRC_FILES := \ native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc \ native/sun_misc_Unsafe.cc \ oat.cc \ - oat/utils/arm/assembler_arm.cc \ - oat/utils/arm/managed_register_arm.cc \ - oat/utils/assembler.cc \ - oat/utils/mips/assembler_mips.cc \ - oat/utils/mips/managed_register_mips.cc \ - oat/utils/x86/assembler_x86.cc \ - oat/utils/x86/managed_register_x86.cc \ oat_file.cc \ offsets.cc \ os_linux.cc \ @@ -125,8 +118,6 @@ LIBART_COMMON_SRC_FILES := \ reference_table.cc \ reflection.cc \ runtime.cc \ - runtime_support.cc \ - runtime_support_llvm.cc \ signal_catcher.cc \ stack.cc \ thread.cc \ @@ -136,7 +127,6 @@ LIBART_COMMON_SRC_FILES := \ trace.cc \ utf.cc \ utils.cc \ - vector_output_stream.cc \ verifier/dex_gc_map.cc \ verifier/instruction_flags.cc \ verifier/method_verifier.cc \ @@ -147,23 +137,41 @@ LIBART_COMMON_SRC_FILES := \ zip_archive.cc LIBART_COMMON_SRC_FILES += \ - oat/runtime/context.cc \ - oat/runtime/support_alloc.cc \ - oat/runtime/support_cast.cc \ - oat/runtime/support_deoptimize.cc \ - oat/runtime/support_dexcache.cc \ - oat/runtime/support_field.cc \ - oat/runtime/support_fillarray.cc \ - oat/runtime/support_instrumentation.cc \ - oat/runtime/support_invoke.cc \ - oat/runtime/support_jni.cc \ - oat/runtime/support_locks.cc \ - oat/runtime/support_math.cc \ - oat/runtime/support_proxy.cc \ - oat/runtime/support_stubs.cc \ - oat/runtime/support_thread.cc \ - oat/runtime/support_throw.cc \ - oat/runtime/support_interpreter.cc + arch/context.cc \ + arch/arm/registers_arm.cc \ + arch/x86/registers_x86.cc \ + arch/mips/registers_mips.cc \ + entrypoints/entrypoint_utils.cc \ + entrypoints/jni/jni_entrypoints.cc \ + entrypoints/math_entrypoints.cc \ + entrypoints/portable/portable_alloc_entrypoints.cc \ + entrypoints/portable/portable_cast_entrypoints.cc \ + entrypoints/portable/portable_dexcache_entrypoints.cc \ + entrypoints/portable/portable_field_entrypoints.cc \ + entrypoints/portable/portable_fillarray_entrypoints.cc \ + entrypoints/portable/portable_invoke_entrypoints.cc \ + entrypoints/portable/portable_jni_entrypoints.cc \ + entrypoints/portable/portable_lock_entrypoints.cc \ + entrypoints/portable/portable_proxy_entrypoints.cc \ + entrypoints/portable/portable_stub_entrypoints.cc \ + entrypoints/portable/portable_thread_entrypoints.cc \ + entrypoints/portable/portable_throw_entrypoints.cc \ + entrypoints/quick/quick_alloc_entrypoints.cc \ + entrypoints/quick/quick_cast_entrypoints.cc \ + entrypoints/quick/quick_deoptimization_entrypoints.cc \ + entrypoints/quick/quick_dexcache_entrypoints.cc \ + entrypoints/quick/quick_field_entrypoints.cc \ + entrypoints/quick/quick_fillarray_entrypoints.cc \ + entrypoints/quick/quick_instrumentation_entrypoints.cc \ + entrypoints/quick/quick_interpreter_entrypoints.cc \ + entrypoints/quick/quick_invoke_entrypoints.cc \ + entrypoints/quick/quick_jni_entrypoints.cc \ + entrypoints/quick/quick_lock_entrypoints.cc \ + entrypoints/quick/quick_math_entrypoints.cc \ + entrypoints/quick/quick_proxy_entrypoints.cc \ + entrypoints/quick/quick_stub_entrypoints.cc \ + entrypoints/quick/quick_thread_entrypoints.cc \ + entrypoints/quick/quick_throw_entrypoints.cc LIBART_TARGET_SRC_FILES := \ $(LIBART_COMMON_SRC_FILES) \ @@ -175,40 +183,36 @@ LIBART_TARGET_SRC_FILES := \ ifeq ($(TARGET_ARCH),arm) LIBART_TARGET_SRC_FILES += \ - oat/runtime/arm/context_arm.cc.arm \ - oat/runtime/arm/oat_support_entrypoints_arm.cc \ - oat/runtime/arm/runtime_support_arm.S + arch/arm/context_arm.cc.arm \ + arch/arm/entrypoints_init_arm.cc \ + arch/arm/jni_entrypoints_arm.S \ + arch/arm/portable_entrypoints_arm.S \ + arch/arm/quick_entrypoints_arm.S \ + arch/arm/thread_arm.cc else # TARGET_ARCH != arm ifeq ($(TARGET_ARCH),x86) LIBART_TARGET_SRC_FILES += \ - oat/runtime/x86/context_x86.cc \ - oat/runtime/x86/oat_support_entrypoints_x86.cc \ - oat/runtime/x86/runtime_support_x86.S + arch/x86/context_x86.cc \ + arch/x86/entrypoints_init_x86.cc \ + arch/x86/jni_entrypoints_x86.S \ + arch/x86/portable_entrypoints_x86.S \ + arch/x86/quick_entrypoints_x86.S \ + arch/x86/thread_x86.cc else # TARGET_ARCH != x86 ifeq ($(TARGET_ARCH),mips) LIBART_TARGET_SRC_FILES += \ - oat/runtime/mips/context_mips.cc \ - oat/runtime/mips/oat_support_entrypoints_mips.cc \ - oat/runtime/mips/runtime_support_mips.S + arch/mips/context_mips.cc \ + arch/mips/entrypoints_init_mips.cc \ + arch/mips/jni_entrypoints_mips.S \ + arch/mips/portable_entrypoints_mips.S \ + arch/mips/quick_entrypoints_mips.S \ + arch/mips/thread_mips.cc else # TARGET_ARCH != mips $(error unsupported TARGET_ARCH=$(TARGET_ARCH)) endif # TARGET_ARCH != mips endif # TARGET_ARCH != x86 endif # TARGET_ARCH != arm -ifeq ($(TARGET_ARCH),arm) -LIBART_TARGET_SRC_FILES += thread_arm.cc -else # TARGET_ARCH != arm -ifeq ($(TARGET_ARCH),x86) -LIBART_TARGET_SRC_FILES += thread_x86.cc -else # TARGET_ARCH != x86 -ifeq ($(TARGET_ARCH),mips) -LIBART_TARGET_SRC_FILES += thread_mips.cc -else # TARGET_ARCH != mips -$(error unsupported TARGET_ARCH=$(TARGET_ARCH)) -endif # TARGET_ARCH != mips -endif # TARGET_ARCH != x86 -endif # TARGET_ARCH != arm LIBART_HOST_SRC_FILES := \ $(LIBART_COMMON_SRC_FILES) \ @@ -219,15 +223,12 @@ LIBART_HOST_SRC_FILES := \ ifeq ($(HOST_ARCH),x86) LIBART_HOST_SRC_FILES += \ - oat/runtime/x86/context_x86.cc \ - oat/runtime/x86/oat_support_entrypoints_x86.cc \ - oat/runtime/x86/runtime_support_x86.S -else # HOST_ARCH != x86 -$(error unsupported HOST_ARCH=$(HOST_ARCH)) -endif # HOST_ARCH != x86 - -ifeq ($(HOST_ARCH),x86) -LIBART_HOST_SRC_FILES += thread_x86.cc + arch/x86/context_x86.cc \ + arch/x86/entrypoints_init_x86.cc \ + arch/x86/jni_entrypoints_x86.S \ + arch/x86/portable_entrypoints_x86.S \ + arch/x86/quick_entrypoints_x86.S \ + arch/x86/thread_x86.cc else # HOST_ARCH != x86 $(error unsupported HOST_ARCH=$(HOST_ARCH)) endif # HOST_ARCH != x86 diff --git a/runtime/arch/arm/asm_support_arm.S b/runtime/arch/arm/asm_support_arm.S new file mode 100644 index 0000000000..ed655e95b1 --- /dev/null +++ b/runtime/arch/arm/asm_support_arm.S @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_ +#define ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_ + +#include "asm_support_arm.h" + +.macro ENTRY name + .type \name, #function + .global \name + /* Cache alignment for function entry */ + .balign 16 +\name: + .cfi_startproc + .fnstart +.endm + +.macro END name + .fnend + .cfi_endproc + .size \name, .-\name +.endm + +#endif // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_ diff --git a/runtime/arch/arm/asm_support_arm.h b/runtime/arch/arm/asm_support_arm.h new file mode 100644 index 0000000000..ed3d476b24 --- /dev/null +++ b/runtime/arch/arm/asm_support_arm.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef ART_RUNTIME_ARCH_ARM_ASM_SUPPORT_ARM_H_ +#define ART_RUNTIME_ARCH_ARM_ASM_SUPPORT_ARM_H_ + +#include "asm_support.h" + +// Register holding suspend check count down. +#define rSUSPEND r4 +// Register holding Thread::Current(). +#define rSELF r9 +// Offset of field Thread::suspend_count_ verified in InitCpu +#define THREAD_FLAGS_OFFSET 0 +// Offset of field Thread::exception_ verified in InitCpu +#define THREAD_EXCEPTION_OFFSET 12 + +#endif // ART_RUNTIME_ARCH_ARM_ASM_SUPPORT_ARM_H_ diff --git a/runtime/oat/runtime/arm/context_arm.cc b/runtime/arch/arm/context_arm.cc index 6b9538e801..6b9538e801 100644 --- a/runtime/oat/runtime/arm/context_arm.cc +++ b/runtime/arch/arm/context_arm.cc diff --git a/runtime/oat/runtime/arm/context_arm.h b/runtime/arch/arm/context_arm.h index 0be85e3577..00651ffb80 100644 --- a/runtime/oat/runtime/arm/context_arm.h +++ b/runtime/arch/arm/context_arm.h @@ -14,12 +14,13 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_RUNTIME_ARM_CONTEXT_ARM_H_ -#define ART_RUNTIME_OAT_RUNTIME_ARM_CONTEXT_ARM_H_ +#ifndef ART_RUNTIME_ARCH_ARM_CONTEXT_ARM_H_ +#define ART_RUNTIME_ARCH_ARM_CONTEXT_ARM_H_ #include "locks.h" -#include "constants_arm.h" -#include "oat/runtime/context.h" +#include "arch/context.h" +#include "base/logging.h" +#include "registers_arm.h" namespace art { namespace arm { @@ -45,7 +46,7 @@ class ArmContext : public Context { } virtual uintptr_t GetGPR(uint32_t reg) { - CHECK_LT(reg, static_cast<uint32_t>(kNumberOfCoreRegisters)); + DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfCoreRegisters)); return *gprs_[reg]; } @@ -64,4 +65,4 @@ class ArmContext : public Context { } // namespace arm } // namespace art -#endif // ART_RUNTIME_OAT_RUNTIME_ARM_CONTEXT_ARM_H_ +#endif // ART_RUNTIME_ARCH_ARM_CONTEXT_ARM_H_ diff --git a/runtime/oat/runtime/arm/oat_support_entrypoints_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc index 2e9453ce9c..b71a158289 100644 --- a/runtime/oat/runtime/arm/oat_support_entrypoints_arm.cc +++ b/runtime/arch/arm/entrypoints_init_arm.cc @@ -14,8 +14,10 @@ * limitations under the License. */ -#include "oat/runtime/oat_support_entrypoints.h" -#include "runtime_support.h" +#include "entrypoints/portable/portable_entrypoints.h" +#include "entrypoints/quick/quick_entrypoints.h" +#include "entrypoints/entrypoint_utils.h" +#include "entrypoints/math_entrypoints.h" namespace art { @@ -130,108 +132,110 @@ extern "C" void art_quick_throw_no_such_method_from_code(int32_t method_idx); extern "C" void art_quick_throw_null_pointer_exception_from_code(); extern "C" void art_quick_throw_stack_overflow_from_code(void*); -void InitEntryPoints(EntryPoints* points) { +void InitEntryPoints(QuickEntryPoints* qpoints, PortableEntryPoints* ppoints) { // Alloc - points->pAllocArrayFromCode = art_quick_alloc_array_from_code; - points->pAllocArrayFromCodeWithAccessCheck = art_quick_alloc_array_from_code_with_access_check; - points->pAllocObjectFromCode = art_quick_alloc_object_from_code; - points->pAllocObjectFromCodeWithAccessCheck = art_quick_alloc_object_from_code_with_access_check; - points->pCheckAndAllocArrayFromCode = art_quick_check_and_alloc_array_from_code; - points->pCheckAndAllocArrayFromCodeWithAccessCheck = art_quick_check_and_alloc_array_from_code_with_access_check; + qpoints->pAllocArrayFromCode = art_quick_alloc_array_from_code; + qpoints->pAllocArrayFromCodeWithAccessCheck = art_quick_alloc_array_from_code_with_access_check; + qpoints->pAllocObjectFromCode = art_quick_alloc_object_from_code; + qpoints->pAllocObjectFromCodeWithAccessCheck = art_quick_alloc_object_from_code_with_access_check; + qpoints->pCheckAndAllocArrayFromCode = art_quick_check_and_alloc_array_from_code; + qpoints->pCheckAndAllocArrayFromCodeWithAccessCheck = art_quick_check_and_alloc_array_from_code_with_access_check; // Cast - points->pInstanceofNonTrivialFromCode = artIsAssignableFromCode; - points->pCanPutArrayElementFromCode = art_quick_can_put_array_element_from_code; - points->pCheckCastFromCode = art_quick_check_cast_from_code; + qpoints->pInstanceofNonTrivialFromCode = artIsAssignableFromCode; + qpoints->pCanPutArrayElementFromCode = art_quick_can_put_array_element_from_code; + qpoints->pCheckCastFromCode = art_quick_check_cast_from_code; // DexCache - points->pInitializeStaticStorage = art_quick_initialize_static_storage_from_code; - points->pInitializeTypeAndVerifyAccessFromCode = art_quick_initialize_type_and_verify_access_from_code; - points->pInitializeTypeFromCode = art_quick_initialize_type_from_code; - points->pResolveStringFromCode = art_quick_resolve_string_from_code; + qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage_from_code; + qpoints->pInitializeTypeAndVerifyAccessFromCode = art_quick_initialize_type_and_verify_access_from_code; + qpoints->pInitializeTypeFromCode = art_quick_initialize_type_from_code; + qpoints->pResolveStringFromCode = art_quick_resolve_string_from_code; // Field - points->pSet32Instance = art_quick_set32_instance_from_code; - points->pSet32Static = art_quick_set32_static_from_code; - points->pSet64Instance = art_quick_set64_instance_from_code; - points->pSet64Static = art_quick_set64_static_from_code; - points->pSetObjInstance = art_quick_set_obj_instance_from_code; - points->pSetObjStatic = art_quick_set_obj_static_from_code; - points->pGet32Instance = art_quick_get32_instance_from_code; - points->pGet64Instance = art_quick_get64_instance_from_code; - points->pGetObjInstance = art_quick_get_obj_instance_from_code; - points->pGet32Static = art_quick_get32_static_from_code; - points->pGet64Static = art_quick_get64_static_from_code; - points->pGetObjStatic = art_quick_get_obj_static_from_code; + qpoints->pSet32Instance = art_quick_set32_instance_from_code; + qpoints->pSet32Static = art_quick_set32_static_from_code; + qpoints->pSet64Instance = art_quick_set64_instance_from_code; + qpoints->pSet64Static = art_quick_set64_static_from_code; + qpoints->pSetObjInstance = art_quick_set_obj_instance_from_code; + qpoints->pSetObjStatic = art_quick_set_obj_static_from_code; + qpoints->pGet32Instance = art_quick_get32_instance_from_code; + qpoints->pGet64Instance = art_quick_get64_instance_from_code; + qpoints->pGetObjInstance = art_quick_get_obj_instance_from_code; + qpoints->pGet32Static = art_quick_get32_static_from_code; + qpoints->pGet64Static = art_quick_get64_static_from_code; + qpoints->pGetObjStatic = art_quick_get_obj_static_from_code; // FillArray - points->pHandleFillArrayDataFromCode = art_quick_handle_fill_data_from_code; + qpoints->pHandleFillArrayDataFromCode = art_quick_handle_fill_data_from_code; // JNI - points->pJniMethodStart = JniMethodStart; - points->pJniMethodStartSynchronized = JniMethodStartSynchronized; - points->pJniMethodEnd = JniMethodEnd; - points->pJniMethodEndSynchronized = JniMethodEndSynchronized; - points->pJniMethodEndWithReference = JniMethodEndWithReference; - points->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; + qpoints->pJniMethodStart = JniMethodStart; + qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized; + qpoints->pJniMethodEnd = JniMethodEnd; + qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized; + qpoints->pJniMethodEndWithReference = JniMethodEndWithReference; + qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; // Locks - points->pLockObjectFromCode = art_quick_lock_object_from_code; - points->pUnlockObjectFromCode = art_quick_unlock_object_from_code; + qpoints->pLockObjectFromCode = art_quick_lock_object_from_code; + qpoints->pUnlockObjectFromCode = art_quick_unlock_object_from_code; // Math - points->pCmpgDouble = CmpgDouble; - points->pCmpgFloat = CmpgFloat; - points->pCmplDouble = CmplDouble; - points->pCmplFloat = CmplFloat; - points->pFmod = fmod; - points->pSqrt = sqrt; - points->pL2d = __aeabi_l2d; - points->pFmodf = fmodf; - points->pL2f = __aeabi_l2f; - points->pD2iz = __aeabi_d2iz; - points->pF2iz = __aeabi_f2iz; - points->pIdivmod = __aeabi_idivmod; - points->pD2l = art_d2l; - points->pF2l = art_f2l; - points->pLdiv = __aeabi_ldivmod; - points->pLdivmod = __aeabi_ldivmod; // result returned in r2:r3 - points->pLmul = art_quick_mul_long; - points->pShlLong = art_quick_shl_long; - points->pShrLong = art_quick_shr_long; - points->pUshrLong = art_quick_ushr_long; + qpoints->pCmpgDouble = CmpgDouble; + qpoints->pCmpgFloat = CmpgFloat; + qpoints->pCmplDouble = CmplDouble; + qpoints->pCmplFloat = CmplFloat; + qpoints->pFmod = fmod; + qpoints->pSqrt = sqrt; + qpoints->pL2d = __aeabi_l2d; + qpoints->pFmodf = fmodf; + qpoints->pL2f = __aeabi_l2f; + qpoints->pD2iz = __aeabi_d2iz; + qpoints->pF2iz = __aeabi_f2iz; + qpoints->pIdivmod = __aeabi_idivmod; + qpoints->pD2l = art_d2l; + qpoints->pF2l = art_f2l; + qpoints->pLdiv = __aeabi_ldivmod; + qpoints->pLdivmod = __aeabi_ldivmod; // result returned in r2:r3 + qpoints->pLmul = art_quick_mul_long; + qpoints->pShlLong = art_quick_shl_long; + qpoints->pShrLong = art_quick_shr_long; + qpoints->pUshrLong = art_quick_ushr_long; // Interpreter - points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry; - points->pInterpreterToQuickEntry = artInterpreterToQuickEntry; + qpoints->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry; + qpoints->pInterpreterToQuickEntry = artInterpreterToQuickEntry; // Intrinsics - points->pIndexOf = art_quick_indexof; - points->pMemcmp16 = __memcmp16; - points->pStringCompareTo = art_quick_string_compareto; - points->pMemcpy = memcpy; + qpoints->pIndexOf = art_quick_indexof; + qpoints->pMemcmp16 = __memcmp16; + qpoints->pStringCompareTo = art_quick_string_compareto; + qpoints->pMemcpy = memcpy; // Invocation - points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline; - points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline; - points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; - points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; - points->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; - points->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; - points->pInvokeVirtualTrampolineWithAccessCheck = art_quick_invoke_virtual_trampoline_with_access_check; + qpoints->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline; + qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; + qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; + qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; + qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; + qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; + qpoints->pInvokeVirtualTrampolineWithAccessCheck = art_quick_invoke_virtual_trampoline_with_access_check; // Thread - points->pCheckSuspendFromCode = CheckSuspendFromCode; - points->pTestSuspendFromCode = art_quick_test_suspend; + qpoints->pCheckSuspendFromCode = CheckSuspendFromCode; + qpoints->pTestSuspendFromCode = art_quick_test_suspend; // Throws - points->pDeliverException = art_quick_deliver_exception_from_code; - points->pThrowArrayBoundsFromCode = art_quick_throw_array_bounds_from_code; - points->pThrowDivZeroFromCode = art_quick_throw_div_zero_from_code; - points->pThrowNoSuchMethodFromCode = art_quick_throw_no_such_method_from_code; - points->pThrowNullPointerFromCode = art_quick_throw_null_pointer_exception_from_code; - points->pThrowStackOverflowFromCode = art_quick_throw_stack_overflow_from_code; + qpoints->pDeliverException = art_quick_deliver_exception_from_code; + qpoints->pThrowArrayBoundsFromCode = art_quick_throw_array_bounds_from_code; + qpoints->pThrowDivZeroFromCode = art_quick_throw_div_zero_from_code; + qpoints->pThrowNoSuchMethodFromCode = art_quick_throw_no_such_method_from_code; + qpoints->pThrowNullPointerFromCode = art_quick_throw_null_pointer_exception_from_code; + qpoints->pThrowStackOverflowFromCode = art_quick_throw_stack_overflow_from_code; + + // Portable + ppoints->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline; }; } // namespace art diff --git a/runtime/arch/arm/jni_entrypoints_arm.S b/runtime/arch/arm/jni_entrypoints_arm.S new file mode 100644 index 0000000000..0a0d06a22a --- /dev/null +++ b/runtime/arch/arm/jni_entrypoints_arm.S @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "asm_support_arm.S" + + /* + * Jni dlsym lookup stub. + */ + .extern artFindNativeMethod +ENTRY art_jni_dlsym_lookup_stub + push {r0, r1, r2, r3, lr} @ spill regs + .save {r0, r1, r2, r3, lr} + .pad #20 + .cfi_adjust_cfa_offset 20 + sub sp, #12 @ pad stack pointer to align frame + .pad #12 + .cfi_adjust_cfa_offset 12 + mov r0, r9 @ pass Thread::Current + blx artFindNativeMethod @ (Thread*) + mov r12, r0 @ save result in r12 + add sp, #12 @ restore stack pointer + .cfi_adjust_cfa_offset -12 + pop {r0, r1, r2, r3, lr} @ restore regs + .cfi_adjust_cfa_offset -20 + cmp r12, #0 @ is method code null? + bxne r12 @ if non-null, tail call to method's code + bx lr @ otherwise, return to caller to handle exception +END art_jni_dlsym_lookup_stub + + /* + * Entry point of native methods when JNI bug compatibility is enabled. + */ + .extern artWorkAroundAppJniBugs +ENTRY art_quick_work_around_app_jni_bugs + @ save registers that may contain arguments and LR that will be crushed by a call + push {r0-r3, lr} + .save {r0-r3, lr} + .cfi_adjust_cfa_offset 16 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r1, 4 + .cfi_rel_offset r2, 8 + .cfi_rel_offset r3, 12 + sub sp, #12 @ 3 words of space for alignment + mov r0, r9 @ pass Thread::Current + mov r1, sp @ pass SP + bl artWorkAroundAppJniBugs @ (Thread*, SP) + add sp, #12 @ rewind stack + mov r12, r0 @ save target address + pop {r0-r3, lr} @ restore possibly modified argument registers + .cfi_adjust_cfa_offset -16 + bx r12 @ tail call into JNI routine +END art_quick_work_around_app_jni_bugs diff --git a/runtime/arch/arm/portable_entrypoints_arm.S b/runtime/arch/arm/portable_entrypoints_arm.S new file mode 100644 index 0000000000..4cc6654ebb --- /dev/null +++ b/runtime/arch/arm/portable_entrypoints_arm.S @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "asm_support_arm.S" + + /* + * Portable invocation stub. + * On entry: + * r0 = method pointer + * r1 = argument array or NULL for no argument methods + * r2 = size of argument array in bytes + * r3 = (managed) thread pointer + * [sp] = JValue* result + * [sp + 4] = result type char + */ +ENTRY art_portable_invoke_stub + push {r0, r4, r5, r9, r11, lr} @ spill regs + .save {r0, r4, r5, r9, r11, lr} + .pad #24 + .cfi_adjust_cfa_offset 24 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r4, 4 + .cfi_rel_offset r5, 8 + .cfi_rel_offset r9, 12 + .cfi_rel_offset r11, 16 + .cfi_rel_offset lr, 20 + mov r11, sp @ save the stack pointer + .cfi_def_cfa_register r11 + mov r9, r3 @ move managed thread pointer into r9 + mov r4, #SUSPEND_CHECK_INTERVAL @ reset r4 to suspend check interval + add r5, r2, #16 @ create space for method pointer in frame + and r5, #0xFFFFFFF0 @ align frame size to 16 bytes + sub sp, r5 @ reserve stack space for argument array + add r0, sp, #4 @ pass stack pointer + method ptr as dest for memcpy + bl memcpy @ memcpy (dest, src, bytes) + ldr r0, [r11] @ restore method* + ldr r1, [sp, #4] @ copy arg value for r1 + ldr r2, [sp, #8] @ copy arg value for r2 + ldr r3, [sp, #12] @ copy arg value for r3 + mov ip, #0 @ set ip to 0 + str ip, [sp] @ store NULL for method* at bottom of frame + add sp, #16 @ first 4 args are not passed on stack for portable + ldr ip, [r0, #METHOD_CODE_OFFSET] @ get pointer to the code + blx ip @ call the method + mov sp, r11 @ restore the stack pointer + ldr ip, [sp, #24] @ load the result pointer + strd r0, [ip] @ store r0/r1 into result pointer + pop {r0, r4, r5, r9, r11, lr} @ restore spill regs + .cfi_adjust_cfa_offset -24 + bx lr +END art_portable_invoke_stub + + .extern artPortableProxyInvokeHandler +ENTRY art_portable_proxy_invoke_handler + @ Fake callee save ref and args frame set up, note portable doesn't use callee save frames. + @ TODO: just save the registers that are needed in artPortableProxyInvokeHandler. + push {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves + .save {r1-r3, r5-r8, r10-r11, lr} + .cfi_adjust_cfa_offset 40 + .cfi_rel_offset r1, 0 + .cfi_rel_offset r2, 4 + .cfi_rel_offset r3, 8 + .cfi_rel_offset r5, 12 + .cfi_rel_offset r6, 16 + .cfi_rel_offset r7, 20 + .cfi_rel_offset r8, 24 + .cfi_rel_offset r10, 28 + .cfi_rel_offset r11, 32 + .cfi_rel_offset lr, 36 + sub sp, #8 @ 2 words of space, bottom word will hold Method* + .pad #8 + .cfi_adjust_cfa_offset 8 + @ Begin argument set up. + str r0, [sp, #0] @ place proxy method at bottom of frame + mov r2, r9 @ pass Thread::Current + mov r3, sp @ pass SP + blx artPortableProxyInvokeHandler @ (Method* proxy method, receiver, Thread*, SP) + ldr r12, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ + ldr lr, [sp, #44] @ restore lr + add sp, #48 @ pop frame + .cfi_adjust_cfa_offset -48 + bx lr @ return +END art_portable_proxy_invoke_handler diff --git a/runtime/oat/runtime/arm/runtime_support_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index f19e8bada0..9b8d238ab8 100644 --- a/runtime/oat/runtime/arm/runtime_support_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -14,29 +14,13 @@ * limitations under the License. */ -#include "asm_support.h" +#include "asm_support_arm.S" /* Deliver the given exception */ .extern artDeliverExceptionFromCode /* Deliver an exception pending on a thread */ .extern artDeliverPendingException -.macro ENTRY name - .type \name, #function - .global \name - /* Cache alignment for function entry */ - .balign 16 -\name: - .cfi_startproc - .fnstart -.endm - -.macro END name - .fnend - .cfi_endproc - .size \name, .-\name -.endm - /* * Macro that sets up the callee save frame to conform with * Runtime::CreateCalleeSaveMethod(kSaveAll) @@ -247,53 +231,6 @@ INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvoke INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck /* - * Portable invocation stub. - * On entry: - * r0 = method pointer - * r1 = argument array or NULL for no argument methods - * r2 = size of argument array in bytes - * r3 = (managed) thread pointer - * [sp] = JValue* result - * [sp + 4] = result type char - */ -ENTRY art_portable_invoke_stub - push {r0, r4, r5, r9, r11, lr} @ spill regs - .save {r0, r4, r5, r9, r11, lr} - .pad #24 - .cfi_adjust_cfa_offset 24 - .cfi_rel_offset r0, 0 - .cfi_rel_offset r4, 4 - .cfi_rel_offset r5, 8 - .cfi_rel_offset r9, 12 - .cfi_rel_offset r11, 16 - .cfi_rel_offset lr, 20 - mov r11, sp @ save the stack pointer - .cfi_def_cfa_register r11 - mov r9, r3 @ move managed thread pointer into r9 - mov r4, #SUSPEND_CHECK_INTERVAL @ reset r4 to suspend check interval - add r5, r2, #16 @ create space for method pointer in frame - and r5, #0xFFFFFFF0 @ align frame size to 16 bytes - sub sp, r5 @ reserve stack space for argument array - add r0, sp, #4 @ pass stack pointer + method ptr as dest for memcpy - bl memcpy @ memcpy (dest, src, bytes) - ldr r0, [r11] @ restore method* - ldr r1, [sp, #4] @ copy arg value for r1 - ldr r2, [sp, #8] @ copy arg value for r2 - ldr r3, [sp, #12] @ copy arg value for r3 - mov ip, #0 @ set ip to 0 - str ip, [sp] @ store NULL for method* at bottom of frame - add sp, #16 @ first 4 args are not passed on stack for portable - ldr ip, [r0, #METHOD_CODE_OFFSET] @ get pointer to the code - blx ip @ call the method - mov sp, r11 @ restore the stack pointer - ldr ip, [sp, #24] @ load the result pointer - strd r0, [ip] @ store r0/r1 into result pointer - pop {r0, r4, r5, r9, r11, lr} @ restore spill regs - .cfi_adjust_cfa_offset -24 - bx lr -END art_portable_invoke_stub - - /* * Quick invocation stub. * On entry: * r0 = method pointer @@ -353,30 +290,6 @@ ENTRY art_quick_do_long_jump END art_quick_do_long_jump /* - * Entry point of native methods when JNI bug compatibility is enabled. - */ - .extern artWorkAroundAppJniBugs -ENTRY art_quick_work_around_app_jni_bugs - @ save registers that may contain arguments and LR that will be crushed by a call - push {r0-r3, lr} - .save {r0-r3, lr} - .cfi_adjust_cfa_offset 16 - .cfi_rel_offset r0, 0 - .cfi_rel_offset r1, 4 - .cfi_rel_offset r2, 8 - .cfi_rel_offset r3, 12 - sub sp, #12 @ 3 words of space for alignment - mov r0, r9 @ pass Thread::Current - mov r1, sp @ pass SP - bl artWorkAroundAppJniBugs @ (Thread*, SP) - add sp, #12 @ rewind stack - mov r12, r0 @ save target address - pop {r0-r3, lr} @ restore possibly modified argument registers - .cfi_adjust_cfa_offset -16 - bx r12 @ tail call into JNI routine -END art_quick_work_around_app_jni_bugs - - /* * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on * failure. */ @@ -906,20 +819,6 @@ ENTRY art_quick_test_suspend RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN END art_quick_test_suspend - .extern artPortableProxyInvokeHandler -ENTRY art_portable_proxy_invoke_handler - SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME - str r0, [sp, #0] @ place proxy method at bottom of frame - mov r2, r9 @ pass Thread::Current - mov r3, sp @ pass SP - blx artPortableProxyInvokeHandler @ (Method* proxy method, receiver, Thread*, SP) - ldr r12, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ - ldr lr, [sp, #44] @ restore lr - add sp, #48 @ pop frame - .cfi_adjust_cfa_offset -48 - bx lr @ return -END art_portable_proxy_invoke_handler - /* * Called by managed code that is attempting to call a method on a proxy class. On entry * r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The @@ -1045,30 +944,6 @@ ENTRY art_quick_abstract_method_error_stub END art_quick_abstract_method_error_stub /* - * Jni dlsym lookup stub. - */ - .extern artFindNativeMethod -ENTRY art_jni_dlsym_lookup_stub - push {r0, r1, r2, r3, lr} @ spill regs - .save {r0, r1, r2, r3, lr} - .pad #20 - .cfi_adjust_cfa_offset 20 - sub sp, #12 @ pad stack pointer to align frame - .pad #12 - .cfi_adjust_cfa_offset 12 - mov r0, r9 @ pass Thread::Current - blx artFindNativeMethod @ (Thread*) - mov r12, r0 @ save result in r12 - add sp, #12 @ restore stack pointer - .cfi_adjust_cfa_offset -12 - pop {r0, r1, r2, r3, lr} @ restore regs - .cfi_adjust_cfa_offset -20 - cmp r12, #0 @ is method code null? - bxne r12 @ if non-null, tail call to method's code - bx lr @ otherwise, return to caller to handle exception -END art_jni_dlsym_lookup_stub - - /* * Signed 64-bit integer multiply. * * Consider WXxYZ (r1r0 x r3r2) with a long multiply: diff --git a/runtime/arch/arm/registers_arm.cc b/runtime/arch/arm/registers_arm.cc new file mode 100644 index 0000000000..4f046479f1 --- /dev/null +++ b/runtime/arch/arm/registers_arm.cc @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "registers_arm.h" + +#include <ostream> + +namespace art { +namespace arm { + +static const char* kRegisterNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "fp", "ip", "sp", "lr", "pc" +}; +std::ostream& operator<<(std::ostream& os, const Register& rhs) { + if (rhs >= R0 && rhs <= PC) { + os << kRegisterNames[rhs]; + } else { + os << "Register[" << static_cast<int>(rhs) << "]"; + } + return os; +} + +std::ostream& operator<<(std::ostream& os, const SRegister& rhs) { + if (rhs >= S0 && rhs < kNumberOfSRegisters) { + os << "s" << static_cast<int>(rhs); + } else { + os << "SRegister[" << static_cast<int>(rhs) << "]"; + } + return os; +} + +} // namespace arm +} // namespace art diff --git a/runtime/arch/arm/registers_arm.h b/runtime/arch/arm/registers_arm.h new file mode 100644 index 0000000000..932095d0c9 --- /dev/null +++ b/runtime/arch/arm/registers_arm.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2009 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_ARCH_ARM_REGISTERS_ARM_H_ +#define ART_RUNTIME_ARCH_ARM_REGISTERS_ARM_H_ + +#include <iosfwd> + +namespace art { +namespace arm { + +// Values for registers. +enum Register { + R0 = 0, + R1 = 1, + R2 = 2, + R3 = 3, + R4 = 4, + R5 = 5, + R6 = 6, + R7 = 7, + R8 = 8, + R9 = 9, + R10 = 10, + R11 = 11, + R12 = 12, + R13 = 13, + R14 = 14, + R15 = 15, + TR = 9, // thread register + FP = 11, + IP = 12, + SP = 13, + LR = 14, + PC = 15, + kNumberOfCoreRegisters = 16, + kNoRegister = -1, +}; +std::ostream& operator<<(std::ostream& os, const Register& rhs); + + +// Values for single-precision floating point registers. +enum SRegister { + S0 = 0, + S1 = 1, + S2 = 2, + S3 = 3, + S4 = 4, + S5 = 5, + S6 = 6, + S7 = 7, + S8 = 8, + S9 = 9, + S10 = 10, + S11 = 11, + S12 = 12, + S13 = 13, + S14 = 14, + S15 = 15, + S16 = 16, + S17 = 17, + S18 = 18, + S19 = 19, + S20 = 20, + S21 = 21, + S22 = 22, + S23 = 23, + S24 = 24, + S25 = 25, + S26 = 26, + S27 = 27, + S28 = 28, + S29 = 29, + S30 = 30, + S31 = 31, + kNumberOfSRegisters = 32, + kNoSRegister = -1, +}; +std::ostream& operator<<(std::ostream& os, const SRegister& rhs); + +} // namespace arm +} // namespace art + +#endif // ART_RUNTIME_ARCH_ARM_REGISTERS_ARM_H_ diff --git a/runtime/thread_arm.cc b/runtime/arch/arm/thread_arm.cc index 0ef26bff5e..ea908be22c 100644 --- a/runtime/thread_arm.cc +++ b/runtime/arch/arm/thread_arm.cc @@ -16,8 +16,8 @@ #include "thread.h" -#include "asm_support.h" -#include "base/macros.h" +#include "asm_support_arm.h" +#include "base/logging.h" namespace art { diff --git a/runtime/oat/runtime/context.cc b/runtime/arch/context.cc index 7075e42575..7075e42575 100644 --- a/runtime/oat/runtime/context.cc +++ b/runtime/arch/context.cc diff --git a/runtime/oat/runtime/context.h b/runtime/arch/context.h index ac43e9a7e9..91e0cd69db 100644 --- a/runtime/oat/runtime/context.h +++ b/runtime/arch/context.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_RUNTIME_CONTEXT_H_ -#define ART_RUNTIME_OAT_RUNTIME_CONTEXT_H_ +#ifndef ART_RUNTIME_ARCH_CONTEXT_H_ +#define ART_RUNTIME_ARCH_CONTEXT_H_ #include <stddef.h> #include <stdint.h> @@ -67,4 +67,4 @@ class Context { } // namespace art -#endif // ART_RUNTIME_OAT_RUNTIME_CONTEXT_H_ +#endif // ART_RUNTIME_ARCH_CONTEXT_H_ diff --git a/runtime/arch/mips/asm_support_mips.S b/runtime/arch/mips/asm_support_mips.S new file mode 100644 index 0000000000..8a34b9dbd0 --- /dev/null +++ b/runtime/arch/mips/asm_support_mips.S @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_S_ +#define ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_S_ + +#include "asm_support_mips.h" + + /* Cache alignment for function entry */ +.macro ENTRY name + .type \name, %function + .global \name + .balign 16 +\name: + .cfi_startproc +.endm + +.macro END name + .cfi_endproc + .size \name, .-\name +.endm + + /* Generates $gp for function calls */ +.macro GENERATE_GLOBAL_POINTER + .cpload $t9 +.endm + +#endif // ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_S_ diff --git a/runtime/arch/mips/asm_support_mips.h b/runtime/arch/mips/asm_support_mips.h new file mode 100644 index 0000000000..9a66352ad1 --- /dev/null +++ b/runtime/arch/mips/asm_support_mips.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_H_ +#define ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_H_ + +#include "asm_support.h" + +// Register holding suspend check count down. +#define rSUSPEND $s0 +// Register holding Thread::Current(). +#define rSELF $s1 +// Offset of field Thread::suspend_count_ verified in InitCpu +#define THREAD_FLAGS_OFFSET 0 +// Offset of field Thread::exception_ verified in InitCpu +#define THREAD_EXCEPTION_OFFSET 12 + +#endif // ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_H_ diff --git a/runtime/oat/runtime/mips/context_mips.cc b/runtime/arch/mips/context_mips.cc index a78e5ee80d..a78e5ee80d 100644 --- a/runtime/oat/runtime/mips/context_mips.cc +++ b/runtime/arch/mips/context_mips.cc diff --git a/runtime/oat/runtime/mips/context_mips.h b/runtime/arch/mips/context_mips.h index f27124c79b..5595f8631e 100644 --- a/runtime/oat/runtime/mips/context_mips.h +++ b/runtime/arch/mips/context_mips.h @@ -14,11 +14,12 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_RUNTIME_MIPS_CONTEXT_MIPS_H_ -#define ART_RUNTIME_OAT_RUNTIME_MIPS_CONTEXT_MIPS_H_ +#ifndef ART_RUNTIME_ARCH_MIPS_CONTEXT_MIPS_H_ +#define ART_RUNTIME_ARCH_MIPS_CONTEXT_MIPS_H_ -#include "constants_mips.h" -#include "oat/runtime/context.h" +#include "arch/context.h" +#include "base/logging.h" +#include "registers_mips.h" namespace art { namespace mips { @@ -61,4 +62,4 @@ class MipsContext : public Context { } // namespace mips } // namespace art -#endif // ART_RUNTIME_OAT_RUNTIME_MIPS_CONTEXT_MIPS_H_ +#endif // ART_RUNTIME_ARCH_MIPS_CONTEXT_MIPS_H_ diff --git a/runtime/oat/runtime/mips/oat_support_entrypoints_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc index 8e066118cd..0a62a4096d 100644 --- a/runtime/oat/runtime/mips/oat_support_entrypoints_mips.cc +++ b/runtime/arch/mips/entrypoints_init_mips.cc @@ -14,8 +14,10 @@ * limitations under the License. */ -#include "runtime_support.h" -#include "oat/runtime/oat_support_entrypoints.h" +#include "entrypoints/portable/portable_entrypoints.h" +#include "entrypoints/quick/quick_entrypoints.h" +#include "entrypoints/entrypoint_utils.h" +#include "entrypoints/math_entrypoints.h" namespace art { @@ -132,107 +134,109 @@ extern "C" void art_quick_throw_no_such_method_from_code(int32_t method_idx); extern "C" void art_quick_throw_null_pointer_exception_from_code(); extern "C" void art_quick_throw_stack_overflow_from_code(void*); -void InitEntryPoints(EntryPoints* points) { +void InitEntryPoints(QuickEntryPoints* qpoints, PortableEntryPoints* ppoints) { // Alloc - points->pAllocArrayFromCode = art_quick_alloc_array_from_code; - points->pAllocArrayFromCodeWithAccessCheck = art_quick_alloc_array_from_code_with_access_check; - points->pAllocObjectFromCode = art_quick_alloc_object_from_code; - points->pAllocObjectFromCodeWithAccessCheck = art_quick_alloc_object_from_code_with_access_check; - points->pCheckAndAllocArrayFromCode = art_quick_check_and_alloc_array_from_code; - points->pCheckAndAllocArrayFromCodeWithAccessCheck = art_quick_check_and_alloc_array_from_code_with_access_check; + qpoints->pAllocArrayFromCode = art_quick_alloc_array_from_code; + qpoints->pAllocArrayFromCodeWithAccessCheck = art_quick_alloc_array_from_code_with_access_check; + qpoints->pAllocObjectFromCode = art_quick_alloc_object_from_code; + qpoints->pAllocObjectFromCodeWithAccessCheck = art_quick_alloc_object_from_code_with_access_check; + qpoints->pCheckAndAllocArrayFromCode = art_quick_check_and_alloc_array_from_code; + qpoints->pCheckAndAllocArrayFromCodeWithAccessCheck = art_quick_check_and_alloc_array_from_code_with_access_check; // Cast - points->pInstanceofNonTrivialFromCode = artIsAssignableFromCode; - points->pCanPutArrayElementFromCode = art_quick_can_put_array_element_from_code; - points->pCheckCastFromCode = art_quick_check_cast_from_code; + qpoints->pInstanceofNonTrivialFromCode = artIsAssignableFromCode; + qpoints->pCanPutArrayElementFromCode = art_quick_can_put_array_element_from_code; + qpoints->pCheckCastFromCode = art_quick_check_cast_from_code; // DexCache - points->pInitializeStaticStorage = art_quick_initialize_static_storage_from_code; - points->pInitializeTypeAndVerifyAccessFromCode = art_quick_initialize_type_and_verify_access_from_code; - points->pInitializeTypeFromCode = art_quick_initialize_type_from_code; - points->pResolveStringFromCode = art_quick_resolve_string_from_code; + qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage_from_code; + qpoints->pInitializeTypeAndVerifyAccessFromCode = art_quick_initialize_type_and_verify_access_from_code; + qpoints->pInitializeTypeFromCode = art_quick_initialize_type_from_code; + qpoints->pResolveStringFromCode = art_quick_resolve_string_from_code; // Field - points->pSet32Instance = art_quick_set32_instance_from_code; - points->pSet32Static = art_quick_set32_static_from_code; - points->pSet64Instance = art_quick_set64_instance_from_code; - points->pSet64Static = art_quick_set64_static_from_code; - points->pSetObjInstance = art_quick_set_obj_instance_from_code; - points->pSetObjStatic = art_quick_set_obj_static_from_code; - points->pGet32Instance = art_quick_get32_instance_from_code; - points->pGet64Instance = art_quick_get64_instance_from_code; - points->pGetObjInstance = art_quick_get_obj_instance_from_code; - points->pGet32Static = art_quick_get32_static_from_code; - points->pGet64Static = art_quick_get64_static_from_code; - points->pGetObjStatic = art_quick_get_obj_static_from_code; + qpoints->pSet32Instance = art_quick_set32_instance_from_code; + qpoints->pSet32Static = art_quick_set32_static_from_code; + qpoints->pSet64Instance = art_quick_set64_instance_from_code; + qpoints->pSet64Static = art_quick_set64_static_from_code; + qpoints->pSetObjInstance = art_quick_set_obj_instance_from_code; + qpoints->pSetObjStatic = art_quick_set_obj_static_from_code; + qpoints->pGet32Instance = art_quick_get32_instance_from_code; + qpoints->pGet64Instance = art_quick_get64_instance_from_code; + qpoints->pGetObjInstance = art_quick_get_obj_instance_from_code; + qpoints->pGet32Static = art_quick_get32_static_from_code; + qpoints->pGet64Static = art_quick_get64_static_from_code; + qpoints->pGetObjStatic = art_quick_get_obj_static_from_code; // FillArray - points->pHandleFillArrayDataFromCode = art_quick_handle_fill_data_from_code; + qpoints->pHandleFillArrayDataFromCode = art_quick_handle_fill_data_from_code; // JNI - points->pJniMethodStart = JniMethodStart; - points->pJniMethodStartSynchronized = JniMethodStartSynchronized; - points->pJniMethodEnd = JniMethodEnd; - points->pJniMethodEndSynchronized = JniMethodEndSynchronized; - points->pJniMethodEndWithReference = JniMethodEndWithReference; - points->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; + qpoints->pJniMethodStart = JniMethodStart; + qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized; + qpoints->pJniMethodEnd = JniMethodEnd; + qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized; + qpoints->pJniMethodEndWithReference = JniMethodEndWithReference; + qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; // Locks - points->pLockObjectFromCode = art_quick_lock_object_from_code; - points->pUnlockObjectFromCode = art_quick_unlock_object_from_code; + qpoints->pLockObjectFromCode = art_quick_lock_object_from_code; + qpoints->pUnlockObjectFromCode = art_quick_unlock_object_from_code; // Math - points->pCmpgDouble = CmpgDouble; - points->pCmpgFloat = CmpgFloat; - points->pCmplDouble = CmplDouble; - points->pCmplFloat = CmplFloat; - points->pFmod = fmod; - points->pL2d = __floatdidf; - points->pFmodf = fmodf; - points->pL2f = __floatdisf; - points->pD2iz = __fixdfsi; - points->pF2iz = __fixsfsi; - points->pIdivmod = NULL; - points->pD2l = art_d2l; - points->pF2l = art_f2l; - points->pLdiv = artLdivFromCode; - points->pLdivmod = artLdivmodFromCode; - points->pLmul = artLmulFromCode; - points->pShlLong = art_quick_shl_long; - points->pShrLong = art_quick_shr_long; - points->pUshrLong = art_quick_ushr_long; + qpoints->pCmpgDouble = CmpgDouble; + qpoints->pCmpgFloat = CmpgFloat; + qpoints->pCmplDouble = CmplDouble; + qpoints->pCmplFloat = CmplFloat; + qpoints->pFmod = fmod; + qpoints->pL2d = __floatdidf; + qpoints->pFmodf = fmodf; + qpoints->pL2f = __floatdisf; + qpoints->pD2iz = __fixdfsi; + qpoints->pF2iz = __fixsfsi; + qpoints->pIdivmod = NULL; + qpoints->pD2l = art_d2l; + qpoints->pF2l = art_f2l; + qpoints->pLdiv = artLdivFromCode; + qpoints->pLdivmod = artLdivmodFromCode; + qpoints->pLmul = artLmulFromCode; + qpoints->pShlLong = art_quick_shl_long; + qpoints->pShrLong = art_quick_shr_long; + qpoints->pUshrLong = art_quick_ushr_long; // Interpreter - points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry; - points->pInterpreterToQuickEntry = artInterpreterToQuickEntry; + qpoints->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry; + qpoints->pInterpreterToQuickEntry = artInterpreterToQuickEntry; // Intrinsics - points->pIndexOf = art_quick_indexof; - points->pMemcmp16 = __memcmp16; - points->pStringCompareTo = art_quick_string_compareto; - points->pMemcpy = memcpy; + qpoints->pIndexOf = art_quick_indexof; + qpoints->pMemcmp16 = __memcmp16; + qpoints->pStringCompareTo = art_quick_string_compareto; + qpoints->pMemcpy = memcpy; // Invocation - points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline; - points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline; - points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; - points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; - points->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; - points->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; - points->pInvokeVirtualTrampolineWithAccessCheck = art_quick_invoke_virtual_trampoline_with_access_check; + qpoints->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline; + qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; + qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; + qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; + qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; + qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; + qpoints->pInvokeVirtualTrampolineWithAccessCheck = art_quick_invoke_virtual_trampoline_with_access_check; // Thread - points->pCheckSuspendFromCode = CheckSuspendFromCode; - points->pTestSuspendFromCode = art_quick_test_suspend; + qpoints->pCheckSuspendFromCode = CheckSuspendFromCode; + qpoints->pTestSuspendFromCode = art_quick_test_suspend; // Throws - points->pDeliverException = art_quick_deliver_exception_from_code; - points->pThrowArrayBoundsFromCode = art_quick_throw_array_bounds_from_code; - points->pThrowDivZeroFromCode = art_quick_throw_div_zero_from_code; - points->pThrowNoSuchMethodFromCode = art_quick_throw_no_such_method_from_code; - points->pThrowNullPointerFromCode = art_quick_throw_null_pointer_exception_from_code; - points->pThrowStackOverflowFromCode = art_quick_throw_stack_overflow_from_code; + qpoints->pDeliverException = art_quick_deliver_exception_from_code; + qpoints->pThrowArrayBoundsFromCode = art_quick_throw_array_bounds_from_code; + qpoints->pThrowDivZeroFromCode = art_quick_throw_div_zero_from_code; + qpoints->pThrowNoSuchMethodFromCode = art_quick_throw_no_such_method_from_code; + qpoints->pThrowNullPointerFromCode = art_quick_throw_null_pointer_exception_from_code; + qpoints->pThrowStackOverflowFromCode = art_quick_throw_stack_overflow_from_code; + + // Portable + ppoints->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline; }; } // namespace art diff --git a/runtime/arch/mips/jni_entrypoints_mips.S b/runtime/arch/mips/jni_entrypoints_mips.S new file mode 100644 index 0000000000..fca6d777ab --- /dev/null +++ b/runtime/arch/mips/jni_entrypoints_mips.S @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "asm_support_mips.S" + + .set noreorder + .balign 4 + + /* + * Jni dlsym lookup stub. + */ + .extern artFindNativeMethod +ENTRY art_jni_dlsym_lookup_stub + GENERATE_GLOBAL_POINTER + addiu $sp, $sp, -32 # leave room for $a0, $a1, $a2, $a3, and $ra + .cfi_adjust_cfa_offset 32 + sw $ra, 16($sp) + .cfi_rel_offset 31, 16 + sw $a3, 12($sp) + .cfi_rel_offset 7, 12 + sw $a2, 8($sp) + .cfi_rel_offset 6, 8 + sw $a1, 4($sp) + .cfi_rel_offset 5, 4 + sw $a0, 0($sp) + .cfi_rel_offset 4, 0 + jal artFindNativeMethod # (Thread*) + move $a0, $s1 # pass Thread::Current() + lw $a0, 0($sp) # restore registers from stack + lw $a1, 4($sp) + lw $a2, 8($sp) + lw $a3, 12($sp) + lw $ra, 16($sp) + beq $v0, $zero, no_native_code_found + addiu $sp, $sp, 32 # restore the stack + .cfi_adjust_cfa_offset -32 + move $t9, $v0 # put method code result in $t9 + jr $t9 # leaf call to method's code + nop +no_native_code_found: + jr $ra + nop +END art_jni_dlsym_lookup_stub + + /* + * Entry point of native methods when JNI bug compatibility is enabled. + */ + .extern artWorkAroundAppJniBugs +ENTRY art_quick_work_around_app_jni_bugs + GENERATE_GLOBAL_POINTER + # save registers that may contain arguments and LR that will be crushed by a call + addiu $sp, $sp, -32 + .cfi_adjust_cfa_offset 32 + sw $ra, 28($sp) + .cfi_rel_offset 31, 28 + sw $a3, 24($sp) + .cfi_rel_offset 7, 28 + sw $a2, 20($sp) + .cfi_rel_offset 6, 28 + sw $a1, 16($sp) + .cfi_rel_offset 5, 28 + sw $a0, 12($sp) + .cfi_rel_offset 4, 28 + move $a0, rSELF # pass Thread::Current + jal artWorkAroundAppJniBugs # (Thread*, $sp) + move $a1, $sp # pass $sp + move $t9, $v0 # save target address + lw $a0, 12($sp) + lw $a1, 16($sp) + lw $a2, 20($sp) + lw $a3, 24($sp) + lw $ra, 28($sp) + jr $t9 # tail call into JNI routine + addiu $sp, $sp, 32 + .cfi_adjust_cfa_offset -32 +END art_quick_work_around_app_jni_bugs diff --git a/runtime/arch/mips/portable_entrypoints_mips.S b/runtime/arch/mips/portable_entrypoints_mips.S new file mode 100644 index 0000000000..e7a9b0fb60 --- /dev/null +++ b/runtime/arch/mips/portable_entrypoints_mips.S @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "asm_support_mips.S" + + .set noreorder + .balign 4 + + .extern artPortableProxyInvokeHandler +ENTRY art_portable_proxy_invoke_handler + GENERATE_GLOBAL_POINTER + # Fake callee save ref and args frame set up, note portable doesn't use callee save frames. + # TODO: just save the registers that are needed in artPortableProxyInvokeHandler. + addiu $sp, $sp, -64 + .cfi_adjust_cfa_offset 64 + sw $ra, 60($sp) + .cfi_rel_offset 31, 60 + sw $s8, 56($sp) + .cfi_rel_offset 30, 56 + sw $gp, 52($sp) + .cfi_rel_offset 28, 52 + sw $s7, 48($sp) + .cfi_rel_offset 23, 48 + sw $s6, 44($sp) + .cfi_rel_offset 22, 44 + sw $s5, 40($sp) + .cfi_rel_offset 21, 40 + sw $s4, 36($sp) + .cfi_rel_offset 20, 36 + sw $s3, 32($sp) + .cfi_rel_offset 19, 32 + sw $s2, 28($sp) + .cfi_rel_offset 18, 28 + sw $a3, 12($sp) + .cfi_rel_offset 7, 12 + sw $a2, 8($sp) + .cfi_rel_offset 6, 8 + sw $a1, 4($sp) + .cfi_rel_offset 5, 4 + # Begin argument set up. + sw $a0, 0($sp) # place proxy method at bottom of frame + move $a2, rSELF # pass Thread::Current + jal artPortableProxyInvokeHandler # (Method* proxy method, receiver, Thread*, SP) + move $a3, $sp # pass $sp + lw $ra, 60($sp) # restore $ra + jr $ra + addiu $sp, $sp, 64 # pop frame + .cfi_adjust_cfa_offset -64 +END art_portable_proxy_invoke_handler + + /* + * Portable abstract method error stub. $a0 contains method* on entry. SP unused in portable. + */ + .extern artThrowAbstractMethodErrorFromCode +ENTRY art_portable_abstract_method_error_stub + GENERATE_GLOBAL_POINTER + la $t9, artThrowAbstractMethodErrorFromCode + jr $t9 # (Method*, Thread*, SP) + move $a1, $s1 # pass Thread::Current +END art_portable_abstract_method_error_stub diff --git a/runtime/oat/runtime/mips/runtime_support_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S index 45d583e097..d32a2b4a15 100644 --- a/runtime/oat/runtime/mips/runtime_support_mips.S +++ b/runtime/arch/mips/quick_entrypoints_mips.S @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "asm_support.h" +#include "asm_support_mips.S" .set noreorder .balign 4 @@ -24,25 +24,6 @@ /* Deliver an exception pending on a thread */ .extern artDeliverPendingExceptionFromCode - /* Cache alignment for function entry */ -.macro ENTRY name - .type \name, %function - .global \name - .balign 16 -\name: - .cfi_startproc -.endm - -.macro END name - .cfi_endproc - .size \name, .-\name -.endm - - /* Generates $gp for function calls */ -.macro GENERATE_GLOBAL_POINTER - .cpload $t9 -.endm - /* * Macro that sets up the callee save frame to conform with * Runtime::CreateCalleeSaveMethod(kSaveAll) @@ -481,39 +462,6 @@ END art_quick_invoke_stub .size art_portable_invoke_stub, .-art_portable_invoke_stub /* - * Entry point of native methods when JNI bug compatibility is enabled. - */ - .extern artWorkAroundAppJniBugs -ENTRY art_quick_work_around_app_jni_bugs - GENERATE_GLOBAL_POINTER - # save registers that may contain arguments and LR that will be crushed by a call - addiu $sp, $sp, -32 - .cfi_adjust_cfa_offset 32 - sw $ra, 28($sp) - .cfi_rel_offset 31, 28 - sw $a3, 24($sp) - .cfi_rel_offset 7, 28 - sw $a2, 20($sp) - .cfi_rel_offset 6, 28 - sw $a1, 16($sp) - .cfi_rel_offset 5, 28 - sw $a0, 12($sp) - .cfi_rel_offset 4, 28 - move $a0, rSELF # pass Thread::Current - jal artWorkAroundAppJniBugs # (Thread*, $sp) - move $a1, $sp # pass $sp - move $t9, $v0 # save target address - lw $a0, 12($sp) - lw $a1, 16($sp) - lw $a2, 20($sp) - lw $a3, 24($sp) - lw $ra, 28($sp) - jr $t9 # tail call into JNI routine - addiu $sp, $sp, 32 - .cfi_adjust_cfa_offset -32 -END art_quick_work_around_app_jni_bugs - - /* * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on * failure. */ @@ -912,20 +860,6 @@ ENTRY art_quick_test_suspend RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN END art_quick_test_suspend - .extern artPortableProxyInvokeHandler -ENTRY art_portable_proxy_invoke_handler - GENERATE_GLOBAL_POINTER - SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME - sw $a0, 0($sp) # place proxy method at bottom of frame - move $a2, rSELF # pass Thread::Current - jal artPortableProxyInvokeHandler # (Method* proxy method, receiver, Thread*, SP) - move $a3, $sp # pass $sp - lw $ra, 60($sp) # restore $ra - jr $ra - addiu $sp, $sp, 64 # pop frame - .cfi_adjust_cfa_offset -64 -END art_portable_proxy_invoke_handler - /* * Called by managed code that is attempting to call a method on a proxy class. On entry * r0 holds the proxy method; r1, r2 and r3 may contain arguments. @@ -1044,17 +978,6 @@ ENTRY art_quick_deoptimize END art_quick_deoptimize /* - * Portable abstract method error stub. $a0 contains method* on entry. SP unused in portable. - */ - .extern artThrowAbstractMethodErrorFromCode -ENTRY art_portable_abstract_method_error_stub - GENERATE_GLOBAL_POINTER - la $t9, artThrowAbstractMethodErrorFromCode - jr $t9 # (Method*, Thread*, SP) - move $a1, $s1 # pass Thread::Current -END art_portable_abstract_method_error_stub - - /* * Quick abstract method error stub. $a0 contains method* on entry. */ ENTRY art_quick_abstract_method_error_stub @@ -1067,42 +990,6 @@ ENTRY art_quick_abstract_method_error_stub END art_quick_abstract_method_error_stub /* - * Jni dlsym lookup stub. - */ - .extern artFindNativeMethod -ENTRY art_jni_dlsym_lookup_stub - GENERATE_GLOBAL_POINTER - addiu $sp, $sp, -32 # leave room for $a0, $a1, $a2, $a3, and $ra - .cfi_adjust_cfa_offset 32 - sw $ra, 16($sp) - .cfi_rel_offset 31, 16 - sw $a3, 12($sp) - .cfi_rel_offset 7, 12 - sw $a2, 8($sp) - .cfi_rel_offset 6, 8 - sw $a1, 4($sp) - .cfi_rel_offset 5, 4 - sw $a0, 0($sp) - .cfi_rel_offset 4, 0 - jal artFindNativeMethod # (Thread*) - move $a0, $s1 # pass Thread::Current() - lw $a0, 0($sp) # restore registers from stack - lw $a1, 4($sp) - lw $a2, 8($sp) - lw $a3, 12($sp) - lw $ra, 16($sp) - beq $v0, $zero, no_native_code_found - addiu $sp, $sp, 32 # restore the stack - .cfi_adjust_cfa_offset -32 - move $t9, $v0 # put method code result in $t9 - jr $t9 # leaf call to method's code - nop -no_native_code_found: - jr $ra - nop -END art_jni_dlsym_lookup_stub - - /* * Long integer shift. This is different from the generic 32/64-bit * binary operations because vAA/vBB are 64-bit but vCC (the shift * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low diff --git a/runtime/arch/mips/registers_mips.cc b/runtime/arch/mips/registers_mips.cc new file mode 100644 index 0000000000..5d31f2f910 --- /dev/null +++ b/runtime/arch/mips/registers_mips.cc @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "registers_mips.h" + +#include <ostream> + +namespace art { +namespace mips { + +static const char* kRegisterNames[] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra", +}; +std::ostream& operator<<(std::ostream& os, const Register& rhs) { + if (rhs >= ZERO && rhs <= RA) { + os << kRegisterNames[rhs]; + } else { + os << "Register[" << static_cast<int>(rhs) << "]"; + } + return os; +} + +std::ostream& operator<<(std::ostream& os, const FRegister& rhs) { + if (rhs >= F0 && rhs < kNumberOfFRegisters) { + os << "f" << static_cast<int>(rhs); + } else { + os << "FRegister[" << static_cast<int>(rhs) << "]"; + } + return os; +} + +} // namespace mips +} // namespace art diff --git a/runtime/arch/mips/registers_mips.h b/runtime/arch/mips/registers_mips.h new file mode 100644 index 0000000000..0f784ed43f --- /dev/null +++ b/runtime/arch/mips/registers_mips.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_ARCH_MIPS_REGISTERS_MIPS_H_ +#define ART_RUNTIME_ARCH_MIPS_REGISTERS_MIPS_H_ + +#include <iosfwd> + +#include "base/logging.h" +#include "base/macros.h" +#include "globals.h" + +namespace art { +namespace mips { + +enum Register { + ZERO = 0, + AT = 1, // Assembler temporary. + V0 = 2, // Values. + V1 = 3, + A0 = 4, // Arguments. + A1 = 5, + A2 = 6, + A3 = 7, + T0 = 8, // Temporaries. + T1 = 9, + T2 = 10, + T3 = 11, + T4 = 12, + T5 = 13, + T6 = 14, + T7 = 15, + S0 = 16, // Saved values. + S1 = 17, + S2 = 18, + S3 = 19, + S4 = 20, + S5 = 21, + S6 = 22, + S7 = 23, + T8 = 24, // More temporaries. + T9 = 25, + K0 = 26, // Reserved for trap handler. + K1 = 27, + GP = 28, // Global pointer. + SP = 29, // Stack pointer. + FP = 30, // Saved value/frame pointer. + RA = 31, // Return address. + kNumberOfCoreRegisters = 32, + kNoRegister = -1 // Signals an illegal register. +}; +std::ostream& operator<<(std::ostream& os, const Register& rhs); + +// Values for single-precision floating point registers. +enum FRegister { + F0 = 0, + F1 = 1, + F2 = 2, + F3 = 3, + F4 = 4, + F5 = 5, + F6 = 6, + F7 = 7, + F8 = 8, + F9 = 9, + F10 = 10, + F11 = 11, + F12 = 12, + F13 = 13, + F14 = 14, + F15 = 15, + F16 = 16, + F17 = 17, + F18 = 18, + F19 = 19, + F20 = 20, + F21 = 21, + F22 = 22, + F23 = 23, + F24 = 24, + F25 = 25, + F26 = 26, + F27 = 27, + F28 = 28, + F29 = 29, + F30 = 30, + F31 = 31, + kNumberOfFRegisters = 32, + kNoFRegister = -1, +}; +std::ostream& operator<<(std::ostream& os, const FRegister& rhs); + +} // namespace mips +} // namespace art + +#endif // ART_RUNTIME_ARCH_MIPS_REGISTERS_MIPS_H_ diff --git a/runtime/thread_mips.cc b/runtime/arch/mips/thread_mips.cc index 0ef26bff5e..7364de067e 100644 --- a/runtime/thread_mips.cc +++ b/runtime/arch/mips/thread_mips.cc @@ -16,8 +16,8 @@ #include "thread.h" -#include "asm_support.h" -#include "base/macros.h" +#include "asm_support_mips.h" +#include "base/logging.h" namespace art { diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S new file mode 100644 index 0000000000..7e6dce9c6a --- /dev/null +++ b/runtime/arch/x86/asm_support_x86.S @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#ifndef ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_ +#define ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_ + +#include "asm_support_x86.h" + +#if defined(__APPLE__) + // Mac OS' as(1) doesn't let you name macro parameters. + #define MACRO0(macro_name) .macro macro_name + #define MACRO1(macro_name, macro_arg1) .macro macro_name + #define MACRO2(macro_name, macro_arg1, macro_args2) .macro macro_name + #define MACRO3(macro_name, macro_arg1, macro_args2, macro_args3) .macro macro_name + #define END_MACRO .endmacro + + // Mac OS' as(1) uses $0, $1, and so on for macro arguments, and function names + // are mangled with an extra underscore prefix. The use of $x for arguments + // mean that literals need to be represented with $$x in macros. + #define SYMBOL(name) _ ## name + #define VAR(name,index) SYMBOL($index) + #define REG_VAR(name,index) %$index + #define CALL_MACRO(name,index) $index + #define LITERAL(value) $value + #define MACRO_LITERAL(value) $$value +#else + // Regular gas(1) lets you name macro parameters. + #define MACRO0(macro_name) .macro macro_name + #define MACRO1(macro_name, macro_arg1) .macro macro_name macro_arg1 + #define MACRO2(macro_name, macro_arg1, macro_arg2) .macro macro_name macro_arg1, macro_arg2 + #define MACRO3(macro_name, macro_arg1, macro_arg2, macro_arg3) .macro macro_name macro_arg1, macro_arg2, macro_arg3 + #define END_MACRO .endm + + // Regular gas(1) uses \argument_name for macro arguments. + // We need to turn on alternate macro syntax so we can use & instead or the preprocessor + // will screw us by inserting a space between the \ and the name. Even in this mode there's + // no special meaning to $, so literals are still just $x. The use of altmacro means % is a + // special character meaning care needs to be taken when passing registers as macro arguments. + .altmacro + #define SYMBOL(name) name + #define VAR(name,index) name& + #define REG_VAR(name,index) %name + #define CALL_MACRO(name,index) name& + #define LITERAL(value) $value + #define MACRO_LITERAL(value) $value +#endif + + /* Cache alignment for function entry */ +MACRO0(ALIGN_FUNCTION_ENTRY) + .balign 16 +END_MACRO + +MACRO1(DEFINE_FUNCTION, c_name) + .type VAR(c_name, 0), @function + .globl VAR(c_name, 0) + ALIGN_FUNCTION_ENTRY +VAR(c_name, 0): + .cfi_startproc +END_MACRO + +MACRO1(END_FUNCTION, c_name) + .cfi_endproc + .size \c_name, .-\c_name +END_MACRO + +MACRO1(PUSH, reg) + pushl REG_VAR(reg, 0) + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset REG_VAR(reg, 0), 0 +END_MACRO + +MACRO1(POP, reg) + popl REG_VAR(reg,0) + .cfi_adjust_cfa_offset -4 + .cfi_restore REG_VAR(reg,0) +END_MACRO + +#endif // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_ diff --git a/runtime/arch/x86/asm_support_x86.h b/runtime/arch/x86/asm_support_x86.h new file mode 100644 index 0000000000..1092910d78 --- /dev/null +++ b/runtime/arch/x86/asm_support_x86.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#ifndef ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_ +#define ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_ + +#include "asm_support.h" + +// Offset of field Thread::self_ verified in InitCpu +#define THREAD_SELF_OFFSET 40 +// Offset of field Thread::exception_ verified in InitCpu +#define THREAD_EXCEPTION_OFFSET 12 + +#endif // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_ diff --git a/runtime/oat/runtime/x86/context_x86.cc b/runtime/arch/x86/context_x86.cc index c728ae97ec..c728ae97ec 100644 --- a/runtime/oat/runtime/x86/context_x86.cc +++ b/runtime/arch/x86/context_x86.cc diff --git a/runtime/oat/runtime/x86/context_x86.h b/runtime/arch/x86/context_x86.h index 4ecfc51b04..d7d22101cc 100644 --- a/runtime/oat/runtime/x86/context_x86.h +++ b/runtime/arch/x86/context_x86.h @@ -14,11 +14,12 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_RUNTIME_X86_CONTEXT_X86_H_ -#define ART_RUNTIME_OAT_RUNTIME_X86_CONTEXT_X86_H_ +#ifndef ART_RUNTIME_ARCH_X86_CONTEXT_X86_H_ +#define ART_RUNTIME_ARCH_X86_CONTEXT_X86_H_ -#include "constants_x86.h" -#include "oat/runtime/context.h" +#include "arch/context.h" +#include "base/logging.h" +#include "registers_x86.h" namespace art { namespace x86 { @@ -43,7 +44,8 @@ class X86Context : public Context { } virtual uintptr_t GetGPR(uint32_t reg) { - CHECK_LT(reg, static_cast<uint32_t>(kNumberOfCpuRegisters)); + const uint32_t kNumberOfCpuRegisters = 8; + DCHECK_LT(reg, kNumberOfCpuRegisters); return *gprs_[reg]; } @@ -64,4 +66,4 @@ class X86Context : public Context { } // namespace x86 } // namespace art -#endif // ART_RUNTIME_OAT_RUNTIME_X86_CONTEXT_X86_H_ +#endif // ART_RUNTIME_ARCH_X86_CONTEXT_X86_H_ diff --git a/runtime/oat/runtime/x86/oat_support_entrypoints_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc index 7dfb07c21e..d47dfef047 100644 --- a/runtime/oat/runtime/x86/oat_support_entrypoints_x86.cc +++ b/runtime/arch/x86/entrypoints_init_x86.cc @@ -14,8 +14,9 @@ * limitations under the License. */ -#include "oat/runtime/oat_support_entrypoints.h" -#include "runtime_support.h" +#include "entrypoints/portable/portable_entrypoints.h" +#include "entrypoints/quick/quick_entrypoints.h" +#include "entrypoints/entrypoint_utils.h" namespace art { @@ -115,107 +116,109 @@ extern "C" void art_quick_throw_no_such_method_from_code(int32_t method_idx); extern "C" void art_quick_throw_null_pointer_exception_from_code(); extern "C" void art_quick_throw_stack_overflow_from_code(void*); -void InitEntryPoints(EntryPoints* points) { +void InitEntryPoints(QuickEntryPoints* qpoints, PortableEntryPoints* ppoints) { // Alloc - points->pAllocArrayFromCode = art_quick_alloc_array_from_code; - points->pAllocArrayFromCodeWithAccessCheck = art_quick_alloc_array_from_code_with_access_check; - points->pAllocObjectFromCode = art_quick_alloc_object_from_code; - points->pAllocObjectFromCodeWithAccessCheck = art_quick_alloc_object_from_code_with_access_check; - points->pCheckAndAllocArrayFromCode = art_quick_check_and_alloc_array_from_code; - points->pCheckAndAllocArrayFromCodeWithAccessCheck = art_quick_check_and_alloc_array_from_code_with_access_check; + qpoints->pAllocArrayFromCode = art_quick_alloc_array_from_code; + qpoints->pAllocArrayFromCodeWithAccessCheck = art_quick_alloc_array_from_code_with_access_check; + qpoints->pAllocObjectFromCode = art_quick_alloc_object_from_code; + qpoints->pAllocObjectFromCodeWithAccessCheck = art_quick_alloc_object_from_code_with_access_check; + qpoints->pCheckAndAllocArrayFromCode = art_quick_check_and_alloc_array_from_code; + qpoints->pCheckAndAllocArrayFromCodeWithAccessCheck = art_quick_check_and_alloc_array_from_code_with_access_check; // Cast - points->pInstanceofNonTrivialFromCode = art_quick_is_assignable_from_code; - points->pCanPutArrayElementFromCode = art_quick_can_put_array_element_from_code; - points->pCheckCastFromCode = art_quick_check_cast_from_code; + qpoints->pInstanceofNonTrivialFromCode = art_quick_is_assignable_from_code; + qpoints->pCanPutArrayElementFromCode = art_quick_can_put_array_element_from_code; + qpoints->pCheckCastFromCode = art_quick_check_cast_from_code; // DexCache - points->pInitializeStaticStorage = art_quick_initialize_static_storage_from_code; - points->pInitializeTypeAndVerifyAccessFromCode = art_quick_initialize_type_and_verify_access_from_code; - points->pInitializeTypeFromCode = art_quick_initialize_type_from_code; - points->pResolveStringFromCode = art_quick_resolve_string_from_code; + qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage_from_code; + qpoints->pInitializeTypeAndVerifyAccessFromCode = art_quick_initialize_type_and_verify_access_from_code; + qpoints->pInitializeTypeFromCode = art_quick_initialize_type_from_code; + qpoints->pResolveStringFromCode = art_quick_resolve_string_from_code; // Field - points->pSet32Instance = art_quick_set32_instance_from_code; - points->pSet32Static = art_quick_set32_static_from_code; - points->pSet64Instance = art_quick_set64_instance_from_code; - points->pSet64Static = art_quick_set64_static_from_code; - points->pSetObjInstance = art_quick_set_obj_instance_from_code; - points->pSetObjStatic = art_quick_set_obj_static_from_code; - points->pGet32Instance = art_quick_get32_instance_from_code; - points->pGet64Instance = art_quick_get64_instance_from_code; - points->pGetObjInstance = art_quick_get_obj_instance_from_code; - points->pGet32Static = art_quick_get32_static_from_code; - points->pGet64Static = art_quick_get64_static_from_code; - points->pGetObjStatic = art_quick_get_obj_static_from_code; + qpoints->pSet32Instance = art_quick_set32_instance_from_code; + qpoints->pSet32Static = art_quick_set32_static_from_code; + qpoints->pSet64Instance = art_quick_set64_instance_from_code; + qpoints->pSet64Static = art_quick_set64_static_from_code; + qpoints->pSetObjInstance = art_quick_set_obj_instance_from_code; + qpoints->pSetObjStatic = art_quick_set_obj_static_from_code; + qpoints->pGet32Instance = art_quick_get32_instance_from_code; + qpoints->pGet64Instance = art_quick_get64_instance_from_code; + qpoints->pGetObjInstance = art_quick_get_obj_instance_from_code; + qpoints->pGet32Static = art_quick_get32_static_from_code; + qpoints->pGet64Static = art_quick_get64_static_from_code; + qpoints->pGetObjStatic = art_quick_get_obj_static_from_code; // FillArray - points->pHandleFillArrayDataFromCode = art_quick_handle_fill_data_from_code; + qpoints->pHandleFillArrayDataFromCode = art_quick_handle_fill_data_from_code; // JNI - points->pJniMethodStart = JniMethodStart; - points->pJniMethodStartSynchronized = JniMethodStartSynchronized; - points->pJniMethodEnd = JniMethodEnd; - points->pJniMethodEndSynchronized = JniMethodEndSynchronized; - points->pJniMethodEndWithReference = JniMethodEndWithReference; - points->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; + qpoints->pJniMethodStart = JniMethodStart; + qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized; + qpoints->pJniMethodEnd = JniMethodEnd; + qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized; + qpoints->pJniMethodEndWithReference = JniMethodEndWithReference; + qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; // Locks - points->pLockObjectFromCode = art_quick_lock_object_from_code; - points->pUnlockObjectFromCode = art_quick_unlock_object_from_code; + qpoints->pLockObjectFromCode = art_quick_lock_object_from_code; + qpoints->pUnlockObjectFromCode = art_quick_unlock_object_from_code; // Math // points->pCmpgDouble = NULL; // Not needed on x86. // points->pCmpgFloat = NULL; // Not needed on x86. // points->pCmplDouble = NULL; // Not needed on x86. // points->pCmplFloat = NULL; // Not needed on x86. - points->pFmod = art_quick_fmod_from_code; - points->pL2d = art_quick_l2d_from_code; - points->pFmodf = art_quick_fmodf_from_code; - points->pL2f = art_quick_l2f_from_code; + qpoints->pFmod = art_quick_fmod_from_code; + qpoints->pL2d = art_quick_l2d_from_code; + qpoints->pFmodf = art_quick_fmodf_from_code; + qpoints->pL2f = art_quick_l2f_from_code; // points->pD2iz = NULL; // Not needed on x86. // points->pF2iz = NULL; // Not needed on x86. - points->pIdivmod = art_quick_idivmod_from_code; - points->pD2l = art_quick_d2l_from_code; - points->pF2l = art_quick_f2l_from_code; - points->pLdiv = art_quick_ldiv_from_code; - points->pLdivmod = art_quick_ldivmod_from_code; - points->pLmul = art_quick_lmul_from_code; - points->pShlLong = art_quick_lshl_from_code; - points->pShrLong = art_quick_lshr_from_code; - points->pUshrLong = art_quick_lushr_from_code; + qpoints->pIdivmod = art_quick_idivmod_from_code; + qpoints->pD2l = art_quick_d2l_from_code; + qpoints->pF2l = art_quick_f2l_from_code; + qpoints->pLdiv = art_quick_ldiv_from_code; + qpoints->pLdivmod = art_quick_ldivmod_from_code; + qpoints->pLmul = art_quick_lmul_from_code; + qpoints->pShlLong = art_quick_lshl_from_code; + qpoints->pShrLong = art_quick_lshr_from_code; + qpoints->pUshrLong = art_quick_lushr_from_code; // Interpreter - points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry; - points->pInterpreterToQuickEntry = artInterpreterToQuickEntry; + qpoints->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry; + qpoints->pInterpreterToQuickEntry = artInterpreterToQuickEntry; // Intrinsics - points->pIndexOf = art_quick_indexof; - points->pMemcmp16 = art_quick_memcmp16; - points->pStringCompareTo = art_quick_string_compareto; - points->pMemcpy = art_quick_memcpy; + qpoints->pIndexOf = art_quick_indexof; + qpoints->pMemcmp16 = art_quick_memcmp16; + qpoints->pStringCompareTo = art_quick_string_compareto; + qpoints->pMemcpy = art_quick_memcpy; // Invocation - points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline; - points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline; - points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; - points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; - points->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; - points->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; - points->pInvokeVirtualTrampolineWithAccessCheck = art_quick_invoke_virtual_trampoline_with_access_check; + qpoints->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline; + qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; + qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; + qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; + qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; + qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; + qpoints->pInvokeVirtualTrampolineWithAccessCheck = art_quick_invoke_virtual_trampoline_with_access_check; // Thread - points->pCheckSuspendFromCode = CheckSuspendFromCode; - points->pTestSuspendFromCode = art_quick_test_suspend; + qpoints->pCheckSuspendFromCode = CheckSuspendFromCode; + qpoints->pTestSuspendFromCode = art_quick_test_suspend; // Throws - points->pDeliverException = art_quick_deliver_exception_from_code; - points->pThrowArrayBoundsFromCode = art_quick_throw_array_bounds_from_code; - points->pThrowDivZeroFromCode = art_quick_throw_div_zero_from_code; - points->pThrowNoSuchMethodFromCode = art_quick_throw_no_such_method_from_code; - points->pThrowNullPointerFromCode = art_quick_throw_null_pointer_exception_from_code; - points->pThrowStackOverflowFromCode = art_quick_throw_stack_overflow_from_code; + qpoints->pDeliverException = art_quick_deliver_exception_from_code; + qpoints->pThrowArrayBoundsFromCode = art_quick_throw_array_bounds_from_code; + qpoints->pThrowDivZeroFromCode = art_quick_throw_div_zero_from_code; + qpoints->pThrowNoSuchMethodFromCode = art_quick_throw_no_such_method_from_code; + qpoints->pThrowNullPointerFromCode = art_quick_throw_null_pointer_exception_from_code; + qpoints->pThrowStackOverflowFromCode = art_quick_throw_stack_overflow_from_code; + + // Portable + ppoints->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline; }; } // namespace art diff --git a/runtime/arch/x86/jni_entrypoints_x86.S b/runtime/arch/x86/jni_entrypoints_x86.S new file mode 100644 index 0000000000..e9c88fec02 --- /dev/null +++ b/runtime/arch/x86/jni_entrypoints_x86.S @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "asm_support_x86.S" + + /* + * Portable resolution trampoline. + */ +DEFINE_FUNCTION art_jni_dlsym_lookup_stub + subl LITERAL(8), %esp // align stack + .cfi_adjust_cfa_offset 8 + pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() + .cfi_adjust_cfa_offset 4 + call SYMBOL(artFindNativeMethod) // (Thread*) + addl LITERAL(12), %esp // restore the stack + .cfi_adjust_cfa_offset -12 + cmpl LITERAL(0), %eax // check if returned method code is null + je no_native_code_found // if null, jump to return to handle + jmp *%eax // otherwise, tail call to intended method +no_native_code_found: + ret +END_FUNCTION art_jni_dlsym_lookup_stub diff --git a/runtime/arch/x86/portable_entrypoints_x86.S b/runtime/arch/x86/portable_entrypoints_x86.S new file mode 100644 index 0000000000..a0fca6cee3 --- /dev/null +++ b/runtime/arch/x86/portable_entrypoints_x86.S @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "asm_support_x86.S" + + /* + * Portable invocation stub. + * On entry: + * [sp] = return address + * [sp + 4] = method pointer + * [sp + 8] = argument array or NULL for no argument methods + * [sp + 12] = size of argument array in bytes + * [sp + 16] = (managed) thread pointer + * [sp + 20] = JValue* result + * [sp + 24] = result type char + */ +DEFINE_FUNCTION art_portable_invoke_stub + PUSH ebp // save ebp + PUSH ebx // save ebx + mov %esp, %ebp // copy value of stack pointer into base pointer + .cfi_def_cfa_register ebp + mov 20(%ebp), %ebx // get arg array size + addl LITERAL(28), %ebx // reserve space for return addr, method*, ebx, and ebp in frame + andl LITERAL(0xFFFFFFF0), %ebx // align frame size to 16 bytes + subl LITERAL(12), %ebx // remove space for return address, ebx, and ebp + subl %ebx, %esp // reserve stack space for argument array + lea 4(%esp), %eax // use stack pointer + method ptr as dest for memcpy + pushl 20(%ebp) // push size of region to memcpy + pushl 16(%ebp) // push arg array as source of memcpy + pushl %eax // push stack pointer as destination of memcpy + call SYMBOL(memcpy) // (void*, const void*, size_t) + addl LITERAL(12), %esp // pop arguments to memcpy + mov 12(%ebp), %eax // move method pointer into eax + mov %eax, (%esp) // push method pointer onto stack + call *METHOD_CODE_OFFSET(%eax) // call the method + mov %ebp, %esp // restore stack pointer + POP ebx // pop ebx + POP ebp // pop ebp + mov 20(%esp), %ecx // get result pointer + cmpl LITERAL(68), 24(%esp) // test if result type char == 'D' + je return_double_portable + cmpl LITERAL(70), 24(%esp) // test if result type char == 'F' + je return_float_portable + mov %eax, (%ecx) // store the result + mov %edx, 4(%ecx) // store the other half of the result + ret +return_double_portable: + fstpl (%ecx) // store the floating point result as double + ret +return_float_portable: + fstps (%ecx) // store the floating point result as float + ret +END_FUNCTION art_portable_invoke_stub + +DEFINE_FUNCTION art_portable_proxy_invoke_handler + // Fake callee save ref and args frame set up, note portable doesn't use callee save frames. + // TODO: just save the registers that are needed in artPortableProxyInvokeHandler. + PUSH edi // Save callee saves + PUSH esi + PUSH ebp + PUSH ebx // Save args + PUSH edx + PUSH ecx + PUSH eax // Align stack, eax will be clobbered by Method* + // Begin argument set up. + PUSH esp // pass SP + pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() + .cfi_adjust_cfa_offset 4 + PUSH ecx // pass receiver + PUSH eax // pass proxy method + call SYMBOL(artPortableProxyInvokeHandler) // (proxy method, receiver, Thread*, SP) + movd %eax, %xmm0 // place return value also into floating point return value + movd %edx, %xmm1 + punpckldq %xmm1, %xmm0 + addl LITERAL(44), %esp // pop arguments + .cfi_adjust_cfa_offset -44 + ret +END_FUNCTION art_portable_proxy_invoke_handler + + /* + * Portable abstract method error stub. method* is at %esp + 4 on entry. + */ +DEFINE_FUNCTION art_portable_abstract_method_error_stub + PUSH ebp + movl %esp, %ebp // Remember SP. + .cfi_def_cfa_register ebp + subl LITERAL(12), %esp // Align stack. + PUSH esp // Pass sp (not used). + pushl %fs:THREAD_SELF_OFFSET // Pass Thread::Current(). + pushl 8(%ebp) // Pass Method*. + call SYMBOL(artThrowAbstractMethodErrorFromCode) // (Method*, Thread*, SP) + leave // Restore the stack and %ebp. + .cfi_def_cfa esp, 4 + .cfi_restore ebp + ret // Return to caller to handle pending exception. +END_FUNCTION art_portable_abstract_method_error_stub diff --git a/runtime/oat/runtime/x86/runtime_support_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index ee6db0c3f8..89ea71a902 100644 --- a/runtime/oat/runtime/x86/runtime_support_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -14,76 +14,7 @@ * limitations under the License. */ -#include "asm_support.h" - -#if defined(__APPLE__) - // Mac OS' as(1) doesn't let you name macro parameters. - #define MACRO0(macro_name) .macro macro_name - #define MACRO1(macro_name, macro_arg1) .macro macro_name - #define MACRO2(macro_name, macro_arg1, macro_args2) .macro macro_name - #define MACRO3(macro_name, macro_arg1, macro_args2, macro_args3) .macro macro_name - #define END_MACRO .endmacro - - // Mac OS' as(1) uses $0, $1, and so on for macro arguments, and function names - // are mangled with an extra underscore prefix. The use of $x for arguments - // mean that literals need to be represented with $$x in macros. - #define SYMBOL(name) _ ## name - #define VAR(name,index) SYMBOL($index) - #define REG_VAR(name,index) %$index - #define CALL_MACRO(name,index) $index - #define LITERAL(value) $value - #define MACRO_LITERAL(value) $$value -#else - // Regular gas(1) lets you name macro parameters. - #define MACRO0(macro_name) .macro macro_name - #define MACRO1(macro_name, macro_arg1) .macro macro_name macro_arg1 - #define MACRO2(macro_name, macro_arg1, macro_arg2) .macro macro_name macro_arg1, macro_arg2 - #define MACRO3(macro_name, macro_arg1, macro_arg2, macro_arg3) .macro macro_name macro_arg1, macro_arg2, macro_arg3 - #define END_MACRO .endm - - // Regular gas(1) uses \argument_name for macro arguments. - // We need to turn on alternate macro syntax so we can use & instead or the preprocessor - // will screw us by inserting a space between the \ and the name. Even in this mode there's - // no special meaning to $, so literals are still just $x. The use of altmacro means % is a - // special character meaning care needs to be taken when passing registers as macro arguments. - .altmacro - #define SYMBOL(name) name - #define VAR(name,index) name& - #define REG_VAR(name,index) %name - #define CALL_MACRO(name,index) name& - #define LITERAL(value) $value - #define MACRO_LITERAL(value) $value -#endif - - /* Cache alignment for function entry */ -MACRO0(ALIGN_FUNCTION_ENTRY) - .balign 16 -END_MACRO - -MACRO1(DEFINE_FUNCTION, c_name) - .type VAR(c_name, 0), @function - .globl VAR(c_name, 0) - ALIGN_FUNCTION_ENTRY -VAR(c_name, 0): - .cfi_startproc -END_MACRO - -MACRO1(END_FUNCTION, c_name) - .cfi_endproc - .size \c_name, .-\c_name -END_MACRO - -MACRO1(PUSH, reg) - pushl REG_VAR(reg, 0) - .cfi_adjust_cfa_offset 4 - .cfi_rel_offset REG_VAR(reg, 0), 0 -END_MACRO - -MACRO1(POP, reg) - popl REG_VAR(reg,0) - .cfi_adjust_cfa_offset -4 - .cfi_restore REG_VAR(reg,0) -END_MACRO +#include "asm_support_x86.S" /* * Macro that sets up the callee save frame to conform with @@ -302,55 +233,6 @@ INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvoke INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck /* - * Portable invocation stub. - * On entry: - * [sp] = return address - * [sp + 4] = method pointer - * [sp + 8] = argument array or NULL for no argument methods - * [sp + 12] = size of argument array in bytes - * [sp + 16] = (managed) thread pointer - * [sp + 20] = JValue* result - * [sp + 24] = result type char - */ -DEFINE_FUNCTION art_portable_invoke_stub - PUSH ebp // save ebp - PUSH ebx // save ebx - mov %esp, %ebp // copy value of stack pointer into base pointer - .cfi_def_cfa_register ebp - mov 20(%ebp), %ebx // get arg array size - addl LITERAL(28), %ebx // reserve space for return addr, method*, ebx, and ebp in frame - andl LITERAL(0xFFFFFFF0), %ebx // align frame size to 16 bytes - subl LITERAL(12), %ebx // remove space for return address, ebx, and ebp - subl %ebx, %esp // reserve stack space for argument array - lea 4(%esp), %eax // use stack pointer + method ptr as dest for memcpy - pushl 20(%ebp) // push size of region to memcpy - pushl 16(%ebp) // push arg array as source of memcpy - pushl %eax // push stack pointer as destination of memcpy - call SYMBOL(memcpy) // (void*, const void*, size_t) - addl LITERAL(12), %esp // pop arguments to memcpy - mov 12(%ebp), %eax // move method pointer into eax - mov %eax, (%esp) // push method pointer onto stack - call *METHOD_CODE_OFFSET(%eax) // call the method - mov %ebp, %esp // restore stack pointer - POP ebx // pop ebx - POP ebp // pop ebp - mov 20(%esp), %ecx // get result pointer - cmpl LITERAL(68), 24(%esp) // test if result type char == 'D' - je return_double_portable - cmpl LITERAL(70), 24(%esp) // test if result type char == 'F' - je return_float_portable - mov %eax, (%ecx) // store the result - mov %edx, 4(%ecx) // store the other half of the result - ret -return_double_portable: - fstpl (%ecx) // store the floating point result as double - ret -return_float_portable: - fstps (%ecx) // store the floating point result as float - ret -END_FUNCTION art_portable_invoke_stub - - /* * Quick invocation stub. * On entry: * [sp] = return address @@ -920,22 +802,6 @@ DEFINE_FUNCTION art_quick_get_obj_static_from_code RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception END_FUNCTION art_quick_get_obj_static_from_code -DEFINE_FUNCTION art_portable_proxy_invoke_handler - SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME // save frame and Method* - PUSH esp // pass SP - pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() - .cfi_adjust_cfa_offset 4 - PUSH ecx // pass receiver - PUSH eax // pass proxy method - call SYMBOL(artPortableProxyInvokeHandler) // (proxy method, receiver, Thread*, SP) - movd %eax, %xmm0 // place return value also into floating point return value - movd %edx, %xmm1 - punpckldq %xmm1, %xmm0 - addl LITERAL(44), %esp // pop arguments - .cfi_adjust_cfa_offset -44 - ret -END_FUNCTION art_portable_proxy_invoke_handler - DEFINE_FUNCTION art_quick_proxy_invoke_handler SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME // save frame and Method* PUSH esp // pass SP @@ -1054,24 +920,6 @@ DEFINE_FUNCTION art_quick_deoptimize END_FUNCTION art_quick_deoptimize /* - * Portable abstract method error stub. method* is at %esp + 4 on entry. - */ -DEFINE_FUNCTION art_portable_abstract_method_error_stub - PUSH ebp - movl %esp, %ebp // Remember SP. - .cfi_def_cfa_register ebp - subl LITERAL(12), %esp // Align stack. - PUSH esp // Pass sp (not used). - pushl %fs:THREAD_SELF_OFFSET // Pass Thread::Current(). - pushl 8(%ebp) // Pass Method*. - call SYMBOL(artThrowAbstractMethodErrorFromCode) // (Method*, Thread*, SP) - leave // Restore the stack and %ebp. - .cfi_def_cfa esp, 4 - .cfi_restore ebp - ret // Return to caller to handle pending exception. -END_FUNCTION art_portable_abstract_method_error_stub - - /* * Quick abstract method error stub. %eax contains method* on entry. */ DEFINE_FUNCTION art_quick_abstract_method_error_stub @@ -1087,24 +935,6 @@ DEFINE_FUNCTION art_quick_abstract_method_error_stub END_FUNCTION art_quick_abstract_method_error_stub /* - * Portable resolution trampoline. - */ -DEFINE_FUNCTION art_jni_dlsym_lookup_stub - subl LITERAL(8), %esp // align stack - .cfi_adjust_cfa_offset 8 - pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() - .cfi_adjust_cfa_offset 4 - call SYMBOL(artFindNativeMethod) // (Thread*) - addl LITERAL(12), %esp // restore the stack - .cfi_adjust_cfa_offset -12 - cmpl LITERAL(0), %eax // check if returned method code is null - je no_native_code_found // if null, jump to return to handle - jmp *%eax // otherwise, tail call to intended method -no_native_code_found: - ret -END_FUNCTION art_jni_dlsym_lookup_stub - - /* * String's indexOf. * * On entry: diff --git a/runtime/arch/x86/registers_x86.cc b/runtime/arch/x86/registers_x86.cc new file mode 100644 index 0000000000..4255d6457f --- /dev/null +++ b/runtime/arch/x86/registers_x86.cc @@ -0,0 +1,37 @@ +/* + * 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 "registers_x86.h" + +#include <ostream> + +namespace art { +namespace x86 { + +static const char* kRegisterNames[] = { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", +}; +std::ostream& operator<<(std::ostream& os, const Register& rhs) { + if (rhs >= EAX && rhs <= EDI) { + os << kRegisterNames[rhs]; + } else { + os << "Register[" << static_cast<int>(rhs) << "]"; + } + return os; +} + +} // namespace x86 +} // namespace art diff --git a/runtime/arch/x86/registers_x86.h b/runtime/arch/x86/registers_x86.h new file mode 100644 index 0000000000..23027ed7d7 --- /dev/null +++ b/runtime/arch/x86/registers_x86.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_ARCH_X86_REGISTERS_X86_H_ +#define ART_RUNTIME_ARCH_X86_REGISTERS_X86_H_ + +#include <iosfwd> + +#include "base/logging.h" +#include "base/macros.h" +#include "globals.h" + +namespace art { +namespace x86 { + +enum Register { + EAX = 0, + ECX = 1, + EDX = 2, + EBX = 3, + ESP = 4, + EBP = 5, + ESI = 6, + EDI = 7, + kNumberOfCpuRegisters = 8, + kFirstByteUnsafeRegister = 4, + kNoRegister = -1 // Signals an illegal register. +}; +std::ostream& operator<<(std::ostream& os, const Register& rhs); + +} // namespace x86 +} // namespace art + +#endif // ART_RUNTIME_ARCH_X86_REGISTERS_X86_H_ diff --git a/runtime/thread_x86.cc b/runtime/arch/x86/thread_x86.cc index c398b2877a..dd3e7dd137 100644 --- a/runtime/thread_x86.cc +++ b/runtime/arch/x86/thread_x86.cc @@ -19,7 +19,7 @@ #include <sys/syscall.h> #include <sys/types.h> -#include "asm_support.h" +#include "asm_support_x86.h" #include "base/macros.h" #include "thread.h" #include "thread_list.h" diff --git a/runtime/asm_support.h b/runtime/asm_support.h index 7b20c7aee0..aca93a5552 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -30,29 +30,4 @@ // Offset of field Method::entry_point_from_compiled_code_ #define METHOD_CODE_OFFSET 40 -#if defined(__arm__) -// Register holding suspend check count down. -#define rSUSPEND r4 -// Register holding Thread::Current(). -#define rSELF r9 -// Offset of field Thread::suspend_count_ verified in InitCpu -#define THREAD_FLAGS_OFFSET 0 -// Offset of field Thread::exception_ verified in InitCpu -#define THREAD_EXCEPTION_OFFSET 12 -#elif defined(__mips__) -// Register holding suspend check count down. -#define rSUSPEND $s0 -// Register holding Thread::Current(). -#define rSELF $s1 -// Offset of field Thread::suspend_count_ verified in InitCpu -#define THREAD_FLAGS_OFFSET 0 -// Offset of field Thread::exception_ verified in InitCpu -#define THREAD_EXCEPTION_OFFSET 12 -#elif defined(__i386__) -// Offset of field Thread::self_ verified in InitCpu -#define THREAD_SELF_OFFSET 40 -// Offset of field Thread::exception_ verified in InitCpu -#define THREAD_EXCEPTION_OFFSET 12 -#endif - #endif // ART_RUNTIME_ASM_SUPPORT_H_ diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h index dea52a6615..b924798acf 100644 --- a/runtime/base/mutex.h +++ b/runtime/base/mutex.h @@ -53,7 +53,7 @@ namespace art { class ScopedContentionRecorder; class Thread; -const bool kDebugLocking = kIsDebugBuild; +const bool kDebugLocking = true || kIsDebugBuild; // Base class for all Mutex implementations class BaseMutex { diff --git a/runtime/base/timing_logger.cc b/runtime/base/timing_logger.cc index bf6fd17a49..dfb0220d46 100644 --- a/runtime/base/timing_logger.cc +++ b/runtime/base/timing_logger.cc @@ -14,6 +14,11 @@ * limitations under the License. */ + +#define ATRACE_TAG ATRACE_TAG_DALVIK +#include <stdio.h> +#include <cutils/trace.h> + #include "timing_logger.h" #include "base/logging.h" @@ -26,49 +31,6 @@ namespace art { -void TimingLogger::Reset() { - times_.clear(); - labels_.clear(); - AddSplit(""); -} - -TimingLogger::TimingLogger(const std::string &name, bool precise) - : name_(name), - precise_(precise) { - AddSplit(""); -} - -void TimingLogger::AddSplit(const std::string &label) { - times_.push_back(NanoTime()); - labels_.push_back(label); -} - -uint64_t TimingLogger::GetTotalNs() const { - return times_.back() - times_.front(); -} - -void TimingLogger::Dump(std::ostream &os) const { - uint64_t largest_time = 0; - os << name_ << ": begin\n"; - for (size_t i = 1; i < times_.size(); ++i) { - uint64_t delta_time = times_[i] - times_[i - 1]; - largest_time = std::max(largest_time, delta_time); - } - // Compute which type of unit we will use for printing the timings. - TimeUnit tu = GetAppropriateTimeUnit(largest_time); - uint64_t divisor = GetNsToTimeUnitDivisor(tu); - for (size_t i = 1; i < times_.size(); ++i) { - uint64_t delta_time = times_[i] - times_[i - 1]; - if (!precise_ && divisor >= 1000) { - // Make the fraction 0. - delta_time -= delta_time % (divisor / 1000); - } - os << name_ << ": " << std::setw(8) << FormatDuration(delta_time, tu) << " " - << labels_[i] << "\n"; - } - os << name_ << ": end, " << NsToMs(GetTotalNs()) << " ms\n"; -} - CumulativeLogger::CumulativeLogger(const std::string& name) : name_(name), lock_name_("CumulativeLoggerLock" + name), @@ -112,17 +74,8 @@ uint64_t CumulativeLogger::GetTotalTime() const { return total; } -void CumulativeLogger::AddLogger(const TimingLogger &logger) { - MutexLock mu(Thread::Current(), lock_); - DCHECK_EQ(logger.times_.size(), logger.labels_.size()); - for (size_t i = 1; i < logger.times_.size(); ++i) { - const uint64_t delta_time = logger.times_[i] - logger.times_[i - 1]; - const std::string &label = logger.labels_[i]; - AddPair(label, delta_time); - } -} -void CumulativeLogger::AddNewLogger(const base::NewTimingLogger &logger) { +void CumulativeLogger::AddLogger(const base::TimingLogger &logger) { MutexLock mu(Thread::Current(), lock_); const std::vector<std::pair<uint64_t, const char*> >& splits = logger.GetSplits(); typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It; @@ -183,51 +136,55 @@ void CumulativeLogger::DumpHistogram(std::ostream &os) { namespace base { -NewTimingLogger::NewTimingLogger(const char* name, bool precise, bool verbose) +TimingLogger::TimingLogger(const char* name, bool precise, bool verbose) : name_(name), precise_(precise), verbose_(verbose), current_split_(NULL), current_split_start_ns_(0) { } -void NewTimingLogger::Reset() { +void TimingLogger::Reset() { current_split_ = NULL; current_split_start_ns_ = 0; splits_.clear(); } -void NewTimingLogger::StartSplit(const char* new_split_label) { +void TimingLogger::StartSplit(const char* new_split_label) { DCHECK(current_split_ == NULL); if (verbose_) { LOG(INFO) << "Begin: " << new_split_label; } current_split_ = new_split_label; + ATRACE_BEGIN(current_split_); current_split_start_ns_ = NanoTime(); } // Ends the current split and starts the one given by the label. -void NewTimingLogger::NewSplit(const char* new_split_label) { +void TimingLogger::NewSplit(const char* new_split_label) { DCHECK(current_split_ != NULL); uint64_t current_time = NanoTime(); uint64_t split_time = current_time - current_split_start_ns_; + ATRACE_END(); splits_.push_back(std::pair<uint64_t, const char*>(split_time, current_split_)); if (verbose_) { LOG(INFO) << "End: " << current_split_ << " " << PrettyDuration(split_time) << "\n" << "Begin: " << new_split_label; } current_split_ = new_split_label; + ATRACE_BEGIN(current_split_); current_split_start_ns_ = current_time; } -void NewTimingLogger::EndSplit() { +void TimingLogger::EndSplit() { DCHECK(current_split_ != NULL); uint64_t current_time = NanoTime(); uint64_t split_time = current_time - current_split_start_ns_; + ATRACE_END(); if (verbose_) { LOG(INFO) << "End: " << current_split_ << " " << PrettyDuration(split_time); } splits_.push_back(std::pair<uint64_t, const char*>(split_time, current_split_)); } -uint64_t NewTimingLogger::GetTotalNs() const { +uint64_t TimingLogger::GetTotalNs() const { uint64_t total_ns = 0; typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It; for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) { @@ -237,7 +194,7 @@ uint64_t NewTimingLogger::GetTotalNs() const { return total_ns; } -void NewTimingLogger::Dump(std::ostream &os) const { +void TimingLogger::Dump(std::ostream &os) const { uint64_t longest_split = 0; uint64_t total_ns = 0; typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It; diff --git a/runtime/base/timing_logger.h b/runtime/base/timing_logger.h index 0f00a046e5..0998837517 100644 --- a/runtime/base/timing_logger.h +++ b/runtime/base/timing_logger.h @@ -26,27 +26,8 @@ namespace art { -class CumulativeLogger; - -class TimingLogger { - public: - explicit TimingLogger(const std::string& name, bool precise); - void AddSplit(const std::string& label); - void Dump(std::ostream& os) const; - void Reset(); - uint64_t GetTotalNs() const; - - protected: - const std::string name_; - const bool precise_; - std::vector<uint64_t> times_; - std::vector<std::string> labels_; - - friend class CumulativeLogger; -}; - namespace base { - class NewTimingLogger; + class TimingLogger; } // namespace base class CumulativeLogger { @@ -62,8 +43,7 @@ class CumulativeLogger { // Allow the name to be modified, particularly when the cumulative logger is a field within a // parent class that is unable to determine the "name" of a sub-class. void SetName(const std::string& name); - void AddLogger(const TimingLogger& logger) LOCKS_EXCLUDED(lock_); - void AddNewLogger(const base::NewTimingLogger& logger) LOCKS_EXCLUDED(lock_); + void AddLogger(const base::TimingLogger& logger) LOCKS_EXCLUDED(lock_); private: void AddPair(const std::string &label, uint64_t delta_time) @@ -84,16 +64,15 @@ class CumulativeLogger { namespace base { // A replacement to timing logger that know when a split starts for the purposes of logging. -// TODO: replace uses of TimingLogger with base::NewTimingLogger. -class NewTimingLogger { +class TimingLogger { public: - explicit NewTimingLogger(const char* name, bool precise, bool verbose); + explicit TimingLogger(const char* name, bool precise, bool verbose); // Clears current splits and labels. void Reset(); // Starts a split, a split shouldn't be in progress. - void StartSplit(const char* new_split_label); + void StartSplit(const char* new_split_label); // Ends the current split and starts the one given by the label. void NewSplit(const char* new_split_label); @@ -111,7 +90,7 @@ class NewTimingLogger { protected: // The name of the timing logger. - const std::string name_; + const char* name_; // Do we want to print the exactly recorded split (true) or round down to the time unit being // used (false). @@ -130,7 +109,7 @@ class NewTimingLogger { std::vector<std::pair<uint64_t, const char*> > splits_; private: - DISALLOW_COPY_AND_ASSIGN(NewTimingLogger); + DISALLOW_COPY_AND_ASSIGN(TimingLogger); }; } // namespace base diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 40033b7743..84f186d4b3 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -58,10 +58,7 @@ #include "object_utils.h" #include "os.h" #include "runtime.h" -#include "runtime_support.h" -#if defined(ART_USE_PORTABLE_COMPILER) -#include "runtime_support_llvm.h" -#endif +#include "entrypoints/entrypoint_utils.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change.h" #include "sirt_ref.h" @@ -1022,15 +1019,19 @@ void ClassLinker::InitFromImageCallback(mirror::Object* obj, void* arg) { return; } - // Set entry points to interpreter for methods in interpreter only mode. if (obj->IsMethod()) { mirror::AbstractMethod* method = obj->AsMethod(); + // Set entry points to interpreter for methods in interpreter only mode. if (Runtime::Current()->GetInstrumentation()->InterpretOnly() && !method->IsNative()) { method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry); if (method != Runtime::Current()->GetResolutionMethod()) { method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint()); } } + // Populate native method pointer with jni lookup stub. + if (method->IsNative()) { + method->UnregisterNative(Thread::Current()); + } } } @@ -1523,6 +1524,13 @@ const OatFile::OatMethod ClassLinker::GetOatMethodFor(const mirror::AbstractMeth // Special case to get oat code without overwriting a trampoline. const void* ClassLinker::GetOatCodeFor(const mirror::AbstractMethod* method) { CHECK(!method->IsAbstract()) << PrettyMethod(method); + if (method->IsProxyMethod()) { +#if !defined(ART_USE_PORTABLE_COMPILER) + return reinterpret_cast<void*>(art_quick_proxy_invoke_handler); +#else + return reinterpret_cast<void*>(art_portable_proxy_invoke_handler); +#endif + } const void* result = GetOatMethodFor(method).GetCode(); if (result == NULL) { // No code? You must mean to go into the interpreter. diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 75886cf7f0..4659fd1982 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -22,6 +22,7 @@ #include "class_linker-inl.h" #include "common_test.h" #include "dex_file.h" +#include "entrypoints/entrypoint_utils.h" #include "gc/heap.h" #include "mirror/class-inl.h" #include "mirror/dex_cache.h" @@ -32,7 +33,6 @@ #include "mirror/object_array-inl.h" #include "mirror/proxy.h" #include "mirror/stack_trace_element.h" -#include "runtime_support.h" #include "sirt_ref.h" using ::art::mirror::AbstractMethod; diff --git a/runtime/common_test.h b/runtime/common_test.h index 842f959cd5..7ee6fe20b2 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -31,6 +31,7 @@ #include "class_linker.h" #include "compiler/driver/compiler_driver.h" #include "dex_file-inl.h" +#include "entrypoints/entrypoint_utils.h" #include "gc/heap.h" #include "gtest/gtest.h" #include "instruction_set.h" @@ -39,7 +40,6 @@ #include "object_utils.h" #include "os.h" #include "runtime.h" -#include "runtime_support.h" #include "scoped_thread_state_change.h" #include "ScopedLocalRef.h" #include "thread.h" @@ -473,7 +473,8 @@ class CommonTest : public testing::Test { void CompileMethod(mirror::AbstractMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { CHECK(method != NULL); - TimingLogger timings("CommonTest::CompileMethod", false); + base::TimingLogger timings("CommonTest::CompileMethod", false, false); + timings.StartSplit("CompileOne"); compiler_driver_->CompileOne(method, timings); MakeExecutable(method); } diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 7ebd6a3ae0..3591a5097b 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -20,6 +20,7 @@ #include <set> +#include "arch/context.h" #include "class_linker.h" #include "class_linker-inl.h" #include "dex_file-inl.h" @@ -37,7 +38,6 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/throwable.h" -#include "oat/runtime/context.h" #include "object_utils.h" #include "safe_map.h" #include "scoped_thread_state_change.h" diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h index 6be249c76a..13b0f1c270 100644 --- a/runtime/dex_instruction.h +++ b/runtime/dex_instruction.h @@ -281,9 +281,7 @@ class Instruction { // Returns the opcode field of the instruction. Code Opcode() const { - const uint16_t* insns = reinterpret_cast<const uint16_t*>(this); - int opcode = *insns & 0xFF; - return static_cast<Code>(opcode); + return static_cast<Code>(Fetch16(0) & 0xFF); } void SetOpcode(Code opcode) { diff --git a/runtime/runtime_support.cc b/runtime/entrypoints/entrypoint_utils.cc index d28aad1e8f..c29784151c 100644 --- a/runtime/runtime_support.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "runtime_support.h" +#include "entrypoints/entrypoint_utils.h" #include "class_linker-inl.h" #include "dex_file-inl.h" @@ -30,74 +30,6 @@ #include "ScopedLocalRef.h" #include "well_known_classes.h" -double art_l2d(int64_t l) { - return static_cast<double>(l); -} - -float art_l2f(int64_t l) { - return static_cast<float>(l); -} - -/* - * Float/double conversion requires clamping to min and max of integer form. If - * target doesn't support this normally, use these. - */ -int64_t art_d2l(double d) { - static const double kMaxLong = static_cast<double>(static_cast<int64_t>(0x7fffffffffffffffULL)); - static const double kMinLong = static_cast<double>(static_cast<int64_t>(0x8000000000000000ULL)); - if (d >= kMaxLong) { - return static_cast<int64_t>(0x7fffffffffffffffULL); - } else if (d <= kMinLong) { - return static_cast<int64_t>(0x8000000000000000ULL); - } else if (d != d) { // NaN case - return 0; - } else { - return static_cast<int64_t>(d); - } -} - -int64_t art_f2l(float f) { - static const float kMaxLong = static_cast<float>(static_cast<int64_t>(0x7fffffffffffffffULL)); - static const float kMinLong = static_cast<float>(static_cast<int64_t>(0x8000000000000000ULL)); - if (f >= kMaxLong) { - return static_cast<int64_t>(0x7fffffffffffffffULL); - } else if (f <= kMinLong) { - return static_cast<int64_t>(0x8000000000000000ULL); - } else if (f != f) { // NaN case - return 0; - } else { - return static_cast<int64_t>(f); - } -} - -int32_t art_d2i(double d) { - static const double kMaxInt = static_cast<double>(static_cast<int32_t>(0x7fffffffUL)); - static const double kMinInt = static_cast<double>(static_cast<int32_t>(0x80000000UL)); - if (d >= kMaxInt) { - return static_cast<int32_t>(0x7fffffffUL); - } else if (d <= kMinInt) { - return static_cast<int32_t>(0x80000000UL); - } else if (d != d) { // NaN case - return 0; - } else { - return static_cast<int32_t>(d); - } -} - -int32_t art_f2i(float f) { - static const float kMaxInt = static_cast<float>(static_cast<int32_t>(0x7fffffffUL)); - static const float kMinInt = static_cast<float>(static_cast<int32_t>(0x80000000UL)); - if (f >= kMaxInt) { - return static_cast<int32_t>(0x7fffffffUL); - } else if (f <= kMinInt) { - return static_cast<int32_t>(0x80000000UL); - } else if (f != f) { // NaN case - return 0; - } else { - return static_cast<int32_t>(f); - } -} - namespace art { // Helper function to allocate array for FILLED_NEW_ARRAY. diff --git a/runtime/runtime_support.h b/runtime/entrypoints/entrypoint_utils.h index 43c678428b..3f28b5e41f 100644 --- a/runtime/runtime_support.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_RUNTIME_SUPPORT_H_ -#define ART_RUNTIME_RUNTIME_SUPPORT_H_ +#ifndef ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_ +#define ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_ #include "class_linker.h" #include "common_throws.h" @@ -42,13 +42,6 @@ extern "C" void art_quick_interpreter_entry(void*); extern "C" void art_quick_proxy_invoke_handler(); extern "C" void art_work_around_app_jni_bugs(); -extern "C" double art_l2d(int64_t l); -extern "C" float art_l2f(int64_t l); -extern "C" int64_t art_d2l(double d); -extern "C" int32_t art_d2i(double d); -extern "C" int64_t art_f2l(float f); -extern "C" int32_t art_f2i(float f); - namespace art { namespace mirror { class Class; @@ -416,4 +409,4 @@ static inline void* GetJniDlsymLookupStub() { } // namespace art -#endif // ART_RUNTIME_RUNTIME_SUPPORT_H_ +#endif // ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_ diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc new file mode 100644 index 0000000000..98f7b1283c --- /dev/null +++ b/runtime/entrypoints/jni/jni_entrypoints.cc @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "base/logging.h" +#include "mirror/abstract_method.h" +#include "scoped_thread_state_change.h" +#include "thread.h" + +namespace art { + +// Used by the JNI dlsym stub to find the native method to invoke if none is registered. +extern "C" void* artFindNativeMethod(Thread* self) { + Locks::mutator_lock_->AssertNotHeld(self); // We come here as Native. + DCHECK(Thread::Current() == self); + ScopedObjectAccess soa(self); + + mirror::AbstractMethod* method = self->GetCurrentMethod(NULL); + DCHECK(method != NULL); + + // Lookup symbol address for method, on failure we'll return NULL with an + // exception set, otherwise we return the address of the method we found. + void* native_code = soa.Vm()->FindCodeForNativeMethod(method); + if (native_code == NULL) { + DCHECK(self->IsExceptionPending()); + return NULL; + } else { + // Register so that future calls don't come here + method->RegisterNative(self, native_code); + return native_code; + } +} + +} // namespace art diff --git a/runtime/entrypoints/math_entrypoints.cc b/runtime/entrypoints/math_entrypoints.cc new file mode 100644 index 0000000000..31d13c8cd5 --- /dev/null +++ b/runtime/entrypoints/math_entrypoints.cc @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "math_entrypoints.h" + +namespace art { + +extern "C" double art_l2d(int64_t l) { + return static_cast<double>(l); +} + +extern "C" float art_l2f(int64_t l) { + return static_cast<float>(l); +} + +/* + * Float/double conversion requires clamping to min and max of integer form. If + * target doesn't support this normally, use these. + */ +extern "C" int64_t art_d2l(double d) { + static const double kMaxLong = static_cast<double>(static_cast<int64_t>(0x7fffffffffffffffULL)); + static const double kMinLong = static_cast<double>(static_cast<int64_t>(0x8000000000000000ULL)); + if (d >= kMaxLong) { + return static_cast<int64_t>(0x7fffffffffffffffULL); + } else if (d <= kMinLong) { + return static_cast<int64_t>(0x8000000000000000ULL); + } else if (d != d) { // NaN case + return 0; + } else { + return static_cast<int64_t>(d); + } +} + +extern "C" int64_t art_f2l(float f) { + static const float kMaxLong = static_cast<float>(static_cast<int64_t>(0x7fffffffffffffffULL)); + static const float kMinLong = static_cast<float>(static_cast<int64_t>(0x8000000000000000ULL)); + if (f >= kMaxLong) { + return static_cast<int64_t>(0x7fffffffffffffffULL); + } else if (f <= kMinLong) { + return static_cast<int64_t>(0x8000000000000000ULL); + } else if (f != f) { // NaN case + return 0; + } else { + return static_cast<int64_t>(f); + } +} + +extern "C" int32_t art_d2i(double d) { + static const double kMaxInt = static_cast<double>(static_cast<int32_t>(0x7fffffffUL)); + static const double kMinInt = static_cast<double>(static_cast<int32_t>(0x80000000UL)); + if (d >= kMaxInt) { + return static_cast<int32_t>(0x7fffffffUL); + } else if (d <= kMinInt) { + return static_cast<int32_t>(0x80000000UL); + } else if (d != d) { // NaN case + return 0; + } else { + return static_cast<int32_t>(d); + } +} + +extern "C" int32_t art_f2i(float f) { + static const float kMaxInt = static_cast<float>(static_cast<int32_t>(0x7fffffffUL)); + static const float kMinInt = static_cast<float>(static_cast<int32_t>(0x80000000UL)); + if (f >= kMaxInt) { + return static_cast<int32_t>(0x7fffffffUL); + } else if (f <= kMinInt) { + return static_cast<int32_t>(0x80000000UL); + } else if (f != f) { // NaN case + return 0; + } else { + return static_cast<int32_t>(f); + } +} + +} // namespace art diff --git a/runtime/runtime_support_llvm.h b/runtime/entrypoints/math_entrypoints.h index 43ea953a96..717c7349bd 100644 --- a/runtime/runtime_support_llvm.h +++ b/runtime/entrypoints/math_entrypoints.h @@ -14,14 +14,16 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_RUNTIME_SUPPORT_LLVM_H_ -#define ART_RUNTIME_RUNTIME_SUPPORT_LLVM_H_ +#ifndef ART_RUNTIME_ENTRYPOINTS_MATH_ENTRYPOINTS_H_ +#define ART_RUNTIME_ENTRYPOINTS_MATH_ENTRYPOINTS_H_ -extern "C" { -//---------------------------------------------------------------------------- -// Runtime Support Function Lookup Callback -//---------------------------------------------------------------------------- -void* art_portable_find_runtime_support_func(void* context, const char* name); -} // extern "C" +#include <stdint.h> -#endif // ART_RUNTIME_RUNTIME_SUPPORT_LLVM_H_ +extern "C" double art_l2d(int64_t l); +extern "C" float art_l2f(int64_t l); +extern "C" int64_t art_d2l(double d); +extern "C" int32_t art_d2i(double d); +extern "C" int64_t art_f2l(float f); +extern "C" int32_t art_f2i(float f); + +#endif // ART_RUNTIME_ENTRYPOINTS_MATH_ENTRYPOINTS_H_ diff --git a/runtime/runtime_support_test.cc b/runtime/entrypoints/math_entrypoints_test.cc index b827813146..ca8b931309 100644 --- a/runtime/runtime_support_test.cc +++ b/runtime/entrypoints/math_entrypoints_test.cc @@ -14,16 +14,16 @@ * limitations under the License. */ -#include "runtime_support.h" +#include "math_entrypoints.h" #include "common_test.h" #include <limits> namespace art { -class RuntimeSupportTest : public CommonTest {}; +class MathEntrypointsTest : public CommonTest {}; -TEST_F(RuntimeSupportTest, DoubleToLong) { +TEST_F(MathEntrypointsTest, DoubleToLong) { EXPECT_EQ(std::numeric_limits<int64_t>::max(), art_d2l(1.85e19)); EXPECT_EQ(std::numeric_limits<int64_t>::min(), art_d2l(-1.85e19)); EXPECT_EQ(0LL, art_d2l(0)); @@ -35,7 +35,7 @@ TEST_F(RuntimeSupportTest, DoubleToLong) { EXPECT_EQ(-100LL, art_d2l(-100.0)); } -TEST_F(RuntimeSupportTest, FloatToLong) { +TEST_F(MathEntrypointsTest, FloatToLong) { EXPECT_EQ(std::numeric_limits<int64_t>::max(), art_f2l(1.85e19)); EXPECT_EQ(std::numeric_limits<int64_t>::min(), art_f2l(-1.85e19)); EXPECT_EQ(0LL, art_f2l(0)); @@ -47,7 +47,7 @@ TEST_F(RuntimeSupportTest, FloatToLong) { EXPECT_EQ(-100LL, art_f2l(-100.0)); } -TEST_F(RuntimeSupportTest, DoubleToInt) { +TEST_F(MathEntrypointsTest, DoubleToInt) { EXPECT_EQ(std::numeric_limits<int32_t>::max(), art_d2i(4.3e9)); EXPECT_EQ(std::numeric_limits<int32_t>::min(), art_d2i(-4.3e9)); EXPECT_EQ(0L, art_d2i(0)); @@ -59,7 +59,7 @@ TEST_F(RuntimeSupportTest, DoubleToInt) { EXPECT_EQ(-100L, art_d2i(-100.0)); } -TEST_F(RuntimeSupportTest, FloatToInt) { +TEST_F(MathEntrypointsTest, FloatToInt) { EXPECT_EQ(std::numeric_limits<int32_t>::max(), art_f2i(4.3e9)); EXPECT_EQ(std::numeric_limits<int32_t>::min(), art_f2i(-4.3e9)); EXPECT_EQ(0L, art_f2i(0)); diff --git a/runtime/entrypoints/portable/portable_alloc_entrypoints.cc b/runtime/entrypoints/portable/portable_alloc_entrypoints.cc new file mode 100644 index 0000000000..286926909c --- /dev/null +++ b/runtime/entrypoints/portable/portable_alloc_entrypoints.cc @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "entrypoints/entrypoint_utils.h" +#include "mirror/abstract_method-inl.h" +#include "mirror/object-inl.h" + +namespace art { + +extern "C" mirror::Object* art_portable_alloc_object_from_code(uint32_t type_idx, + mirror::AbstractMethod* referrer, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return AllocObjectFromCode(type_idx, referrer, thread, false); +} + +extern "C" mirror::Object* art_portable_alloc_object_from_code_with_access_check(uint32_t type_idx, + mirror::AbstractMethod* referrer, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return AllocObjectFromCode(type_idx, referrer, thread, true); +} + +extern "C" mirror::Object* art_portable_alloc_array_from_code(uint32_t type_idx, + mirror::AbstractMethod* referrer, + uint32_t length, + Thread* self) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return AllocArrayFromCode(type_idx, referrer, length, self, false); +} + +extern "C" mirror::Object* art_portable_alloc_array_from_code_with_access_check(uint32_t type_idx, + mirror::AbstractMethod* referrer, + uint32_t length, + Thread* self) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return AllocArrayFromCode(type_idx, referrer, length, self, true); +} + +extern "C" mirror::Object* art_portable_check_and_alloc_array_from_code(uint32_t type_idx, + mirror::AbstractMethod* referrer, + uint32_t length, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, false); +} + +extern "C" mirror::Object* art_portable_check_and_alloc_array_from_code_with_access_check(uint32_t type_idx, + mirror::AbstractMethod* referrer, + uint32_t length, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, true); +} + +} // namespace art diff --git a/runtime/entrypoints/portable/portable_argument_visitor.h b/runtime/entrypoints/portable/portable_argument_visitor.h new file mode 100644 index 0000000000..f268baf790 --- /dev/null +++ b/runtime/entrypoints/portable/portable_argument_visitor.h @@ -0,0 +1,136 @@ +/* + * 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. + */ + +#ifndef ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ +#define ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ + +#include "object_utils.h" + +namespace art { + +// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame. +class PortableArgumentVisitor { + public: +// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame. +// Size of Runtime::kRefAndArgs callee save frame. +// Size of Method* and register parameters in out stack arguments. +#if defined(__arm__) +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8 +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48 +#define PORTABLE_STACK_ARG_SKIP 0 +#elif defined(__mips__) +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4 +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64 +#define PORTABLE_STACK_ARG_SKIP 16 +#elif defined(__i386__) +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4 +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32 +#define PORTABLE_STACK_ARG_SKIP 4 +#else +#error "Unsupported architecture" +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0 +#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0 +#define PORTABLE_STACK_ARG_SKIP 0 +#endif + + PortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : + caller_mh_(caller_mh), + args_in_regs_(ComputeArgsInRegs(caller_mh)), + num_params_(caller_mh.NumArgs()), + reg_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET), + stack_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE + + PORTABLE_STACK_ARG_SKIP), + cur_args_(reg_args_), + cur_arg_index_(0), + param_index_(0) { + } + + virtual ~PortableArgumentVisitor() {} + + virtual void Visit() = 0; + + bool IsParamAReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return caller_mh_.IsParamAReference(param_index_); + } + + bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return caller_mh_.IsParamALongOrDouble(param_index_); + } + + Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return caller_mh_.GetParamPrimitiveType(param_index_); + } + + byte* GetParamAddress() const { + return cur_args_ + (cur_arg_index_ * kPointerSize); + } + + void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + for (cur_arg_index_ = 0; cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) { +#if (defined(__arm__) || defined(__mips__)) + if (IsParamALongOrDouble() && cur_arg_index_ == 2) { + break; + } +#endif + Visit(); + cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1); + param_index_++; + } + cur_args_ = stack_args_; + cur_arg_index_ = 0; + while (param_index_ < num_params_) { +#if (defined(__arm__) || defined(__mips__)) + if (IsParamALongOrDouble() && cur_arg_index_ % 2 != 0) { + cur_arg_index_++; + } +#endif + Visit(); + cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1); + param_index_++; + } + } + + private: + static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +#if (defined(__i386__)) + return 0; +#else + size_t args_in_regs = 0; + size_t num_params = mh.NumArgs(); + for (size_t i = 0; i < num_params; i++) { + args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1); + if (args_in_regs > 3) { + args_in_regs = 3; + break; + } + } + return args_in_regs; +#endif + } + MethodHelper& caller_mh_; + const size_t args_in_regs_; + const size_t num_params_; + byte* const reg_args_; + byte* const stack_args_; + byte* cur_args_; + size_t cur_arg_index_; + size_t param_index_; +}; + +} // namespace art + +#endif // ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ diff --git a/runtime/entrypoints/portable/portable_cast_entrypoints.cc b/runtime/entrypoints/portable/portable_cast_entrypoints.cc new file mode 100644 index 0000000000..d343c5dc1f --- /dev/null +++ b/runtime/entrypoints/portable/portable_cast_entrypoints.cc @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_throws.h" +#include "entrypoints/entrypoint_utils.h" +#include "mirror/object-inl.h" + +namespace art { + +extern "C" int32_t art_portable_is_assignable_from_code(const mirror::Class* dest_type, + const mirror::Class* src_type) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(dest_type != NULL); + DCHECK(src_type != NULL); + return dest_type->IsAssignableFrom(src_type) ? 1 : 0; +} + +extern "C" void art_portable_check_cast_from_code(const mirror::Class* dest_type, + const mirror::Class* src_type) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(dest_type->IsClass()) << PrettyClass(dest_type); + DCHECK(src_type->IsClass()) << PrettyClass(src_type); + if (UNLIKELY(!dest_type->IsAssignableFrom(src_type))) { + ThrowClassCastException(dest_type, src_type); + } +} + +extern "C" void art_portable_check_put_array_element_from_code(const mirror::Object* element, + const mirror::Object* array) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (element == NULL) { + return; + } + DCHECK(array != NULL); + mirror::Class* array_class = array->GetClass(); + DCHECK(array_class != NULL); + mirror::Class* component_type = array_class->GetComponentType(); + mirror::Class* element_class = element->GetClass(); + if (UNLIKELY(!component_type->IsAssignableFrom(element_class))) { + ThrowArrayStoreException(element_class, array_class); + } +} + +} // namespace art diff --git a/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc b/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc new file mode 100644 index 0000000000..bdab587797 --- /dev/null +++ b/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "entrypoints/entrypoint_utils.h" +#include "gc/accounting/card_table-inl.h" +#include "mirror/abstract_method-inl.h" +#include "mirror/object-inl.h" + +namespace art { + +extern "C" mirror::Object* art_portable_initialize_static_storage_from_code(uint32_t type_idx, + mirror::AbstractMethod* referrer, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return ResolveVerifyAndClinit(type_idx, referrer, thread, true, false); +} + +extern "C" mirror::Object* art_portable_initialize_type_from_code(uint32_t type_idx, + mirror::AbstractMethod* referrer, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return ResolveVerifyAndClinit(type_idx, referrer, thread, false, false); +} + +extern "C" mirror::Object* art_portable_initialize_type_and_verify_access_from_code(uint32_t type_idx, + mirror::AbstractMethod* referrer, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // Called when caller isn't guaranteed to have access to a type and the dex cache may be + // unpopulated + return ResolveVerifyAndClinit(type_idx, referrer, thread, false, true); +} + +extern "C" mirror::Object* art_portable_resolve_string_from_code(mirror::AbstractMethod* referrer, + uint32_t string_idx) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return ResolveStringFromCode(referrer, string_idx); +} + +} // namespace art diff --git a/runtime/entrypoints/portable/portable_entrypoints.h b/runtime/entrypoints/portable/portable_entrypoints.h new file mode 100644 index 0000000000..a229c76dbd --- /dev/null +++ b/runtime/entrypoints/portable/portable_entrypoints.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#ifndef ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ENTRYPOINTS_H_ +#define ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ENTRYPOINTS_H_ + +#include "dex_file-inl.h" +#include "runtime.h" + +namespace art { +namespace mirror { + class AbstractMethod; + class Object; +} // namespace mirror +class Thread; + +#define PORTABLE_ENTRYPOINT_OFFSET(x) \ + (static_cast<uintptr_t>(OFFSETOF_MEMBER(Thread, portable_entrypoints_)) + \ + static_cast<uintptr_t>(OFFSETOF_MEMBER(PortableEntryPoints, x))) + +// Pointers to functions that are called by code generated by compiler's adhering to the portable +// compiler ABI. +struct PACKED(4) PortableEntryPoints { + // Invocation + const void* (*pPortableResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*, + mirror::AbstractMethod**, Thread*); +}; + +} // namespace art + +#endif // ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ENTRYPOINTS_H_ diff --git a/runtime/entrypoints/portable/portable_field_entrypoints.cc b/runtime/entrypoints/portable/portable_field_entrypoints.cc new file mode 100644 index 0000000000..aa0f03ce8b --- /dev/null +++ b/runtime/entrypoints/portable/portable_field_entrypoints.cc @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "entrypoints/entrypoint_utils.h" +#include "mirror/abstract_method-inl.h" +#include "mirror/field-inl.h" +#include "mirror/object-inl.h" + +namespace art { + +extern "C" int32_t art_portable_set32_static_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer, + int32_t new_value) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, + referrer, + StaticPrimitiveWrite, + sizeof(uint32_t)); + if (LIKELY(field != NULL)) { + field->Set32(field->GetDeclaringClass(), new_value); + return 0; + } + field = FindFieldFromCode(field_idx, + referrer, + Thread::Current(), + StaticPrimitiveWrite, + sizeof(uint32_t), + true); + if (LIKELY(field != NULL)) { + field->Set32(field->GetDeclaringClass(), new_value); + return 0; + } + return -1; +} + +extern "C" int32_t art_portable_set64_static_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer, + int64_t new_value) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint64_t)); + if (LIKELY(field != NULL)) { + field->Set64(field->GetDeclaringClass(), new_value); + return 0; + } + field = FindFieldFromCode(field_idx, + referrer, + Thread::Current(), + StaticPrimitiveWrite, + sizeof(uint64_t), + true); + if (LIKELY(field != NULL)) { + field->Set64(field->GetDeclaringClass(), new_value); + return 0; + } + return -1; +} + +extern "C" int32_t art_portable_set_obj_static_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer, + mirror::Object* new_value) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, referrer, StaticObjectWrite, + sizeof(mirror::Object*)); + if (LIKELY(field != NULL)) { + field->SetObj(field->GetDeclaringClass(), new_value); + return 0; + } + field = FindFieldFromCode(field_idx, referrer, Thread::Current(), + StaticObjectWrite, sizeof(mirror::Object*), true); + if (LIKELY(field != NULL)) { + field->SetObj(field->GetDeclaringClass(), new_value); + return 0; + } + return -1; +} + +extern "C" int32_t art_portable_get32_static_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint32_t)); + if (LIKELY(field != NULL)) { + return field->Get32(field->GetDeclaringClass()); + } + field = FindFieldFromCode(field_idx, referrer, Thread::Current(), + StaticPrimitiveRead, sizeof(uint32_t), true); + if (LIKELY(field != NULL)) { + return field->Get32(field->GetDeclaringClass()); + } + return 0; +} + +extern "C" int64_t art_portable_get64_static_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint64_t)); + if (LIKELY(field != NULL)) { + return field->Get64(field->GetDeclaringClass()); + } + field = FindFieldFromCode(field_idx, referrer, Thread::Current(), + StaticPrimitiveRead, sizeof(uint64_t), true); + if (LIKELY(field != NULL)) { + return field->Get64(field->GetDeclaringClass()); + } + return 0; +} + +extern "C" mirror::Object* art_portable_get_obj_static_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, referrer, StaticObjectRead, + sizeof(mirror::Object*)); + if (LIKELY(field != NULL)) { + return field->GetObj(field->GetDeclaringClass()); + } + field = FindFieldFromCode(field_idx, referrer, Thread::Current(), + StaticObjectRead, sizeof(mirror::Object*), true); + if (LIKELY(field != NULL)) { + return field->GetObj(field->GetDeclaringClass()); + } + return 0; +} + +extern "C" int32_t art_portable_set32_instance_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer, + mirror::Object* obj, uint32_t new_value) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint32_t)); + if (LIKELY(field != NULL)) { + field->Set32(obj, new_value); + return 0; + } + field = FindFieldFromCode(field_idx, referrer, Thread::Current(), + InstancePrimitiveWrite, sizeof(uint32_t), true); + if (LIKELY(field != NULL)) { + field->Set32(obj, new_value); + return 0; + } + return -1; +} + +extern "C" int32_t art_portable_set64_instance_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer, + mirror::Object* obj, int64_t new_value) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint64_t)); + if (LIKELY(field != NULL)) { + field->Set64(obj, new_value); + return 0; + } + field = FindFieldFromCode(field_idx, referrer, Thread::Current(), + InstancePrimitiveWrite, sizeof(uint64_t), true); + if (LIKELY(field != NULL)) { + field->Set64(obj, new_value); + return 0; + } + return -1; +} + +extern "C" int32_t art_portable_set_obj_instance_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer, + mirror::Object* obj, + mirror::Object* new_value) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite, + sizeof(mirror::Object*)); + if (LIKELY(field != NULL)) { + field->SetObj(obj, new_value); + return 0; + } + field = FindFieldFromCode(field_idx, referrer, Thread::Current(), + InstanceObjectWrite, sizeof(mirror::Object*), true); + if (LIKELY(field != NULL)) { + field->SetObj(obj, new_value); + return 0; + } + return -1; +} + +extern "C" int32_t art_portable_get32_instance_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer, + mirror::Object* obj) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint32_t)); + if (LIKELY(field != NULL)) { + return field->Get32(obj); + } + field = FindFieldFromCode(field_idx, referrer, Thread::Current(), + InstancePrimitiveRead, sizeof(uint32_t), true); + if (LIKELY(field != NULL)) { + return field->Get32(obj); + } + return 0; +} + +extern "C" int64_t art_portable_get64_instance_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer, + mirror::Object* obj) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint64_t)); + if (LIKELY(field != NULL)) { + return field->Get64(obj); + } + field = FindFieldFromCode(field_idx, referrer, Thread::Current(), + InstancePrimitiveRead, sizeof(uint64_t), true); + if (LIKELY(field != NULL)) { + return field->Get64(obj); + } + return 0; +} + +extern "C" mirror::Object* art_portable_get_obj_instance_from_code(uint32_t field_idx, + mirror::AbstractMethod* referrer, + mirror::Object* obj) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Field* field = FindFieldFast(field_idx, referrer, InstanceObjectRead, + sizeof(mirror::Object*)); + if (LIKELY(field != NULL)) { + return field->GetObj(obj); + } + field = FindFieldFromCode(field_idx, referrer, Thread::Current(), + InstanceObjectRead, sizeof(mirror::Object*), true); + if (LIKELY(field != NULL)) { + return field->GetObj(obj); + } + return 0; +} + +} // namespace art diff --git a/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc b/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc new file mode 100644 index 0000000000..771608b604 --- /dev/null +++ b/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dex_instruction.h" +#include "entrypoints/entrypoint_utils.h" +#include "mirror/abstract_method-inl.h" +#include "mirror/object-inl.h" + +namespace art { + +extern "C" void art_portable_fill_array_data_from_code(mirror::AbstractMethod* method, + uint32_t dex_pc, + mirror::Array* array, + uint32_t payload_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem(); + const Instruction::ArrayDataPayload* payload = + reinterpret_cast<const Instruction::ArrayDataPayload*>(code_item->insns_ + payload_offset); + DCHECK_EQ(payload->ident, static_cast<uint16_t>(Instruction::kArrayDataSignature)); + if (UNLIKELY(array == NULL)) { + ThrowNullPointerException(NULL, "null array in FILL_ARRAY_DATA"); + return; // Error + } + DCHECK(array->IsArrayInstance() && !array->IsObjectArray()); + if (UNLIKELY(static_cast<int32_t>(payload->element_count) > array->GetLength())) { + Thread* self = Thread::Current(); + ThrowLocation throw_location = self->GetCurrentLocationForThrow(); + self->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;", + "failed FILL_ARRAY_DATA; length=%d, index=%d", + array->GetLength(), payload->element_count - 1); + return; // Error + } + uint32_t size_in_bytes = payload->element_count * payload->element_width; + memcpy(array->GetRawData(payload->element_width), payload->data, size_in_bytes); +} + +} // namespace art diff --git a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc new file mode 100644 index 0000000000..5911ba3d8b --- /dev/null +++ b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "entrypoints/entrypoint_utils.h" +#include "mirror/abstract_method-inl.h" +#include "mirror/dex_cache-inl.h" +#include "mirror/object-inl.h" + +namespace art { + +static mirror::AbstractMethod* FindMethodHelper(uint32_t method_idx, + mirror::Object* this_object, + mirror::AbstractMethod* caller_method, + bool access_check, + InvokeType type, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::AbstractMethod* method = FindMethodFast(method_idx, + this_object, + caller_method, + access_check, + type); + if (UNLIKELY(method == NULL)) { + method = FindMethodFromCode(method_idx, this_object, caller_method, + thread, access_check, type); + if (UNLIKELY(method == NULL)) { + CHECK(thread->IsExceptionPending()); + return 0; // failure + } + } + DCHECK(!thread->IsExceptionPending()); + const void* code = method->GetEntryPointFromCompiledCode(); + + // When we return, the caller will branch to this address, so it had better not be 0! + if (UNLIKELY(code == NULL)) { + MethodHelper mh(method); + LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method) + << " location: " << mh.GetDexFile().GetLocation(); + } + return method; +} + +extern "C" mirror::Object* art_portable_find_static_method_from_code_with_access_check(uint32_t method_idx, + mirror::Object* this_object, + mirror::AbstractMethod* referrer, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return FindMethodHelper(method_idx, this_object, referrer, true, kStatic, thread); +} + +extern "C" mirror::Object* art_portable_find_direct_method_from_code_with_access_check(uint32_t method_idx, + mirror::Object* this_object, + mirror::AbstractMethod* referrer, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return FindMethodHelper(method_idx, this_object, referrer, true, kDirect, thread); +} + +extern "C" mirror::Object* art_portable_find_virtual_method_from_code_with_access_check(uint32_t method_idx, + mirror::Object* this_object, + mirror::AbstractMethod* referrer, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return FindMethodHelper(method_idx, this_object, referrer, true, kVirtual, thread); +} + +extern "C" mirror::Object* art_portable_find_super_method_from_code_with_access_check(uint32_t method_idx, + mirror::Object* this_object, + mirror::AbstractMethod* referrer, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return FindMethodHelper(method_idx, this_object, referrer, true, kSuper, thread); +} + +extern "C" mirror::Object* art_portable_find_interface_method_from_code_with_access_check(uint32_t method_idx, + mirror::Object* this_object, + mirror::AbstractMethod* referrer, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return FindMethodHelper(method_idx, this_object, referrer, true, kInterface, thread); +} + +extern "C" mirror::Object* art_portable_find_interface_method_from_code(uint32_t method_idx, + mirror::Object* this_object, + mirror::AbstractMethod* referrer, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return FindMethodHelper(method_idx, this_object, referrer, false, kInterface, thread); +} + +} // namespace art diff --git a/runtime/entrypoints/portable/portable_jni_entrypoints.cc b/runtime/entrypoints/portable/portable_jni_entrypoints.cc new file mode 100644 index 0000000000..8df16ae931 --- /dev/null +++ b/runtime/entrypoints/portable/portable_jni_entrypoints.cc @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "entrypoints/entrypoint_utils.h" +#include "mirror/abstract_method-inl.h" +#include "mirror/object-inl.h" +#include "thread-inl.h" + +namespace art { + +// Called on entry to JNI, transition out of Runnable and release share of mutator_lock_. +extern "C" uint32_t art_portable_jni_method_start(Thread* self) + UNLOCK_FUNCTION(GlobalSynchronizatio::mutator_lock_) { + JNIEnvExt* env = self->GetJniEnv(); + uint32_t saved_local_ref_cookie = env->local_ref_cookie; + env->local_ref_cookie = env->locals.GetSegmentState(); + self->TransitionFromRunnableToSuspended(kNative); + return saved_local_ref_cookie; +} + +extern "C" uint32_t art_portable_jni_method_start_synchronized(jobject to_lock, Thread* self) + UNLOCK_FUNCTION(Locks::mutator_lock_) { + self->DecodeJObject(to_lock)->MonitorEnter(self); + return art_portable_jni_method_start(self); +} + +static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self) { + JNIEnvExt* env = self->GetJniEnv(); + env->locals.SetSegmentState(env->local_ref_cookie); + env->local_ref_cookie = saved_local_ref_cookie; +} + +extern "C" void art_portable_jni_method_end(uint32_t saved_local_ref_cookie, Thread* self) + SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { + self->TransitionFromSuspendedToRunnable(); + PopLocalReferences(saved_local_ref_cookie, self); +} + + +extern "C" void art_portable_jni_method_end_synchronized(uint32_t saved_local_ref_cookie, + jobject locked, + Thread* self) + SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { + self->TransitionFromSuspendedToRunnable(); + UnlockJniSynchronizedMethod(locked, self); // Must decode before pop. + PopLocalReferences(saved_local_ref_cookie, self); +} + +extern "C" mirror::Object* art_portable_jni_method_end_with_reference(jobject result, + uint32_t saved_local_ref_cookie, + Thread* self) + SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { + self->TransitionFromSuspendedToRunnable(); + mirror::Object* o = self->DecodeJObject(result); // Must decode before pop. + PopLocalReferences(saved_local_ref_cookie, self); + // Process result. + if (UNLIKELY(self->GetJniEnv()->check_jni)) { + if (self->IsExceptionPending()) { + return NULL; + } + CheckReferenceResult(o, self); + } + return o; +} + +extern "C" mirror::Object* art_portable_jni_method_end_with_reference_synchronized(jobject result, + uint32_t saved_local_ref_cookie, + jobject locked, + Thread* self) + SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { + self->TransitionFromSuspendedToRunnable(); + UnlockJniSynchronizedMethod(locked, self); // Must decode before pop. + mirror::Object* o = self->DecodeJObject(result); + PopLocalReferences(saved_local_ref_cookie, self); + // Process result. + if (UNLIKELY(self->GetJniEnv()->check_jni)) { + if (self->IsExceptionPending()) { + return NULL; + } + CheckReferenceResult(o, self); + } + return o; +} + +} // namespace art diff --git a/runtime/entrypoints/portable/portable_lock_entrypoints.cc b/runtime/entrypoints/portable/portable_lock_entrypoints.cc new file mode 100644 index 0000000000..44d3da9897 --- /dev/null +++ b/runtime/entrypoints/portable/portable_lock_entrypoints.cc @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "entrypoints/entrypoint_utils.h" +#include "mirror/object-inl.h" + +namespace art { + +extern "C" void art_portable_lock_object_from_code(mirror::Object* obj, Thread* thread) + EXCLUSIVE_LOCK_FUNCTION(monitor_lock_) { + DCHECK(obj != NULL); // Assumed to have been checked before entry. + obj->MonitorEnter(thread); // May block. + DCHECK(thread->HoldsLock(obj)); + // Only possible exception is NPE and is handled before entry. + DCHECK(!thread->IsExceptionPending()); +} + +extern "C" void art_portable_unlock_object_from_code(mirror::Object* obj, Thread* thread) + UNLOCK_FUNCTION(monitor_lock_) { + DCHECK(obj != NULL); // Assumed to have been checked before entry. + // MonitorExit may throw exception. + obj->MonitorExit(thread); +} + +} // namespace art diff --git a/runtime/entrypoints/portable/portable_proxy_entrypoints.cc b/runtime/entrypoints/portable/portable_proxy_entrypoints.cc new file mode 100644 index 0000000000..3db39cd0bd --- /dev/null +++ b/runtime/entrypoints/portable/portable_proxy_entrypoints.cc @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "entrypoints/entrypoint_utils.h" +#include "mirror/abstract_method-inl.h" +#include "mirror/object-inl.h" +#include "portable_argument_visitor.h" +#include "scoped_thread_state_change.h" + +namespace art { + +// Visits arguments on the stack placing them into the args vector, Object* arguments are converted +// to jobjects. +class BuildPortableArgumentVisitor : public PortableArgumentVisitor { + public: + BuildPortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp, + ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) : + PortableArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {} + + virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + jvalue val; + Primitive::Type type = GetParamPrimitiveType(); + switch (type) { + case Primitive::kPrimNot: { + mirror::Object* obj = *reinterpret_cast<mirror::Object**>(GetParamAddress()); + val.l = soa_.AddLocalReference<jobject>(obj); + break; + } + case Primitive::kPrimLong: // Fall-through. + case Primitive::kPrimDouble: + val.j = *reinterpret_cast<jlong*>(GetParamAddress()); + break; + case Primitive::kPrimBoolean: // Fall-through. + case Primitive::kPrimByte: // Fall-through. + case Primitive::kPrimChar: // Fall-through. + case Primitive::kPrimShort: // Fall-through. + case Primitive::kPrimInt: // Fall-through. + case Primitive::kPrimFloat: + val.i = *reinterpret_cast<jint*>(GetParamAddress()); + break; + case Primitive::kPrimVoid: + LOG(FATAL) << "UNREACHABLE"; + val.j = 0; + break; + } + args_.push_back(val); + } + + private: + ScopedObjectAccessUnchecked& soa_; + std::vector<jvalue>& args_; + + DISALLOW_COPY_AND_ASSIGN(BuildPortableArgumentVisitor); +}; + +// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method +// which is responsible for recording callee save registers. We explicitly place into jobjects the +// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a +// field within the proxy object, which will box the primitive arguments and deal with error cases. +extern "C" uint64_t artPortableProxyInvokeHandler(mirror::AbstractMethod* proxy_method, + mirror::Object* receiver, + Thread* self, mirror::AbstractMethod** sp) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // Ensure we don't get thread suspension until the object arguments are safely in jobjects. + const char* old_cause = + self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments"); + self->VerifyStack(); + // Start new JNI local reference state. + JNIEnvExt* env = self->GetJniEnv(); + ScopedObjectAccessUnchecked soa(env); + ScopedJniEnvLocalRefState env_state(env); + // Create local ref. copies of proxy method and the receiver. + jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver); + + // Placing arguments into args vector and remove the receiver. + MethodHelper proxy_mh(proxy_method); + std::vector<jvalue> args; + BuildPortableArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args); + local_ref_visitor.VisitArguments(); + args.erase(args.begin()); + + // Convert proxy method into expected interface method. + mirror::AbstractMethod* interface_method = proxy_method->FindOverriddenMethod(); + DCHECK(interface_method != NULL); + DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method); + jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method); + + // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code + // that performs allocations. + self->EndAssertNoThreadSuspension(old_cause); + JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(), + rcvr_jobj, interface_method_jobj, args); + return result.GetJ(); +} + +} // namespace art diff --git a/runtime/entrypoints/portable/portable_stub_entrypoints.cc b/runtime/entrypoints/portable/portable_stub_entrypoints.cc new file mode 100644 index 0000000000..c510c653ba --- /dev/null +++ b/runtime/entrypoints/portable/portable_stub_entrypoints.cc @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dex_instruction-inl.h" +#include "entrypoints/entrypoint_utils.h" +#include "mirror/abstract_method-inl.h" +#include "mirror/object-inl.h" + +namespace art { + +// Lazily resolve a method for portable. Called by stub code. +extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called, + mirror::Object* receiver, + mirror::AbstractMethod** called_addr, + Thread* thread) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + uint32_t dex_pc; + mirror::AbstractMethod* caller = thread->GetCurrentMethod(&dex_pc); + + ClassLinker* linker = Runtime::Current()->GetClassLinker(); + InvokeType invoke_type; + bool is_range; + if (called->IsRuntimeMethod()) { + const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem(); + CHECK_LT(dex_pc, code->insns_size_in_code_units_); + const Instruction* instr = Instruction::At(&code->insns_[dex_pc]); + Instruction::Code instr_code = instr->Opcode(); + switch (instr_code) { + case Instruction::INVOKE_DIRECT: + invoke_type = kDirect; + is_range = false; + break; + case Instruction::INVOKE_DIRECT_RANGE: + invoke_type = kDirect; + is_range = true; + break; + case Instruction::INVOKE_STATIC: + invoke_type = kStatic; + is_range = false; + break; + case Instruction::INVOKE_STATIC_RANGE: + invoke_type = kStatic; + is_range = true; + break; + case Instruction::INVOKE_SUPER: + invoke_type = kSuper; + is_range = false; + break; + case Instruction::INVOKE_SUPER_RANGE: + invoke_type = kSuper; + is_range = true; + break; + case Instruction::INVOKE_VIRTUAL: + invoke_type = kVirtual; + is_range = false; + break; + case Instruction::INVOKE_VIRTUAL_RANGE: + invoke_type = kVirtual; + is_range = true; + break; + case Instruction::INVOKE_INTERFACE: + invoke_type = kInterface; + is_range = false; + break; + case Instruction::INVOKE_INTERFACE_RANGE: + invoke_type = kInterface; + is_range = true; + break; + default: + LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL); + // Avoid used uninitialized warnings. + invoke_type = kDirect; + is_range = true; + } + uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c(); + called = linker->ResolveMethod(dex_method_idx, caller, invoke_type); + // Refine called method based on receiver. + if (invoke_type == kVirtual) { + called = receiver->GetClass()->FindVirtualMethodForVirtual(called); + } else if (invoke_type == kInterface) { + called = receiver->GetClass()->FindVirtualMethodForInterface(called); + } + } else { + CHECK(called->IsStatic()) << PrettyMethod(called); + invoke_type = kStatic; + } + const void* code = NULL; + if (LIKELY(!thread->IsExceptionPending())) { + // Incompatible class change should have been handled in resolve method. + CHECK(!called->CheckIncompatibleClassChange(invoke_type)); + // Ensure that the called method's class is initialized. + mirror::Class* called_class = called->GetDeclaringClass(); + linker->EnsureInitialized(called_class, true, true); + if (LIKELY(called_class->IsInitialized())) { + code = called->GetEntryPointFromCompiledCode(); + // TODO: remove this after we solve the link issue. + { // for lazy link. + if (code == NULL) { + code = linker->GetOatCodeFor(called); + } + } + } else if (called_class->IsInitializing()) { + if (invoke_type == kStatic) { + // Class is still initializing, go to oat and grab code (trampoline must be left in place + // until class is initialized to stop races between threads). + code = linker->GetOatCodeFor(called); + } else { + // No trampoline for non-static methods. + code = called->GetEntryPointFromCompiledCode(); + // TODO: remove this after we solve the link issue. + { // for lazy link. + if (code == NULL) { + code = linker->GetOatCodeFor(called); + } + } + } + } else { + DCHECK(called_class->IsErroneous()); + } + } + if (LIKELY(code != NULL)) { + // Expect class to at least be initializing. + DCHECK(called->GetDeclaringClass()->IsInitializing()); + // Don't want infinite recursion. + DCHECK(code != GetResolutionTrampoline(linker)); + // Set up entry into main method + *called_addr = called; + } + return code; +} + +} // namespace art diff --git a/runtime/entrypoints/portable/portable_thread_entrypoints.cc b/runtime/entrypoints/portable/portable_thread_entrypoints.cc new file mode 100644 index 0000000000..dac73885a5 --- /dev/null +++ b/runtime/entrypoints/portable/portable_thread_entrypoints.cc @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "entrypoints/entrypoint_utils.h" +#include "mirror/abstract_method.h" +#include "mirror/object-inl.h" +#include "verifier/dex_gc_map.h" +#include "stack.h" + +namespace art { + +class ShadowFrameCopyVisitor : public StackVisitor { + public: + explicit ShadowFrameCopyVisitor(Thread* self) : StackVisitor(self, NULL), prev_frame_(NULL), + top_frame_(NULL) {} + + bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (IsShadowFrame()) { + ShadowFrame* cur_frame = GetCurrentShadowFrame(); + size_t num_regs = cur_frame->NumberOfVRegs(); + mirror::AbstractMethod* method = cur_frame->GetMethod(); + uint32_t dex_pc = cur_frame->GetDexPC(); + ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, method, dex_pc); + + const uint8_t* gc_map = method->GetNativeGcMap(); + uint32_t gc_map_length = static_cast<uint32_t>((gc_map[0] << 24) | + (gc_map[1] << 16) | + (gc_map[2] << 8) | + (gc_map[3] << 0)); + verifier::DexPcToReferenceMap dex_gc_map(gc_map + 4, gc_map_length); + const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc); + for (size_t reg = 0; reg < num_regs; ++reg) { + if (TestBitmap(reg, reg_bitmap)) { + new_frame->SetVRegReference(reg, cur_frame->GetVRegReference(reg)); + } else { + new_frame->SetVReg(reg, cur_frame->GetVReg(reg)); + } + } + + if (prev_frame_ != NULL) { + prev_frame_->SetLink(new_frame); + } else { + top_frame_ = new_frame; + } + prev_frame_ = new_frame; + } + return true; + } + + ShadowFrame* GetShadowFrameCopy() { + return top_frame_; + } + + private: + static bool TestBitmap(int reg, const uint8_t* reg_vector) { + return ((reg_vector[reg / 8] >> (reg % 8)) & 0x01) != 0; + } + + ShadowFrame* prev_frame_; + ShadowFrame* top_frame_; +}; + +extern "C" void art_portable_test_suspend_from_code(Thread* self) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + CheckSuspend(self); + if (Runtime::Current()->GetInstrumentation()->ShouldPortableCodeDeoptimize()) { + // Save out the shadow frame to the heap + ShadowFrameCopyVisitor visitor(self); + visitor.WalkStack(true); + self->SetDeoptimizationShadowFrame(visitor.GetShadowFrameCopy()); + self->SetDeoptimizationReturnValue(JValue()); + self->SetException(ThrowLocation(), reinterpret_cast<mirror::Throwable*>(-1)); + } +} + +extern "C" ShadowFrame* art_portable_push_shadow_frame_from_code(Thread* thread, + ShadowFrame* new_shadow_frame, + mirror::AbstractMethod* method, + uint32_t num_vregs) { + ShadowFrame* old_frame = thread->PushShadowFrame(new_shadow_frame); + new_shadow_frame->SetMethod(method); + new_shadow_frame->SetNumberOfVRegs(num_vregs); + return old_frame; +} + +} // namespace art diff --git a/runtime/entrypoints/portable/portable_throw_entrypoints.cc b/runtime/entrypoints/portable/portable_throw_entrypoints.cc new file mode 100644 index 0000000000..64a67ebb4c --- /dev/null +++ b/runtime/entrypoints/portable/portable_throw_entrypoints.cc @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dex_instruction.h" +#include "entrypoints/entrypoint_utils.h" +#include "mirror/abstract_method-inl.h" +#include "mirror/object-inl.h" + +namespace art { + +extern "C" void art_portable_throw_div_zero_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + ThrowArithmeticExceptionDivideByZero(); +} + +extern "C" void art_portable_throw_array_bounds_from_code(int32_t index, int32_t length) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + ThrowArrayIndexOutOfBoundsException(index, length); +} + +extern "C" void art_portable_throw_no_such_method_from_code(int32_t method_idx) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + ThrowNoSuchMethodError(method_idx); +} + +extern "C" void art_portable_throw_null_pointer_exception_from_code(uint32_t dex_pc) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // TODO: remove dex_pc argument from caller. + UNUSED(dex_pc); + Thread* self = Thread::Current(); + ThrowLocation throw_location = self->GetCurrentLocationForThrow(); + ThrowNullPointerExceptionFromDexPC(throw_location); +} + +extern "C" void art_portable_throw_stack_overflow_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + ThrowStackOverflowError(Thread::Current()); +} + +extern "C" void art_portable_throw_exception_from_code(mirror::Throwable* exception) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Thread* self = Thread::Current(); + ThrowLocation throw_location = self->GetCurrentLocationForThrow(); + if (exception == NULL) { + ThrowNullPointerException(NULL, "throw with null exception"); + } else { + self->SetException(throw_location, exception); + } +} + +extern "C" void* art_portable_get_and_clear_exception(Thread* self) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(self->IsExceptionPending()); + // TODO: make this inline. + mirror::Throwable* exception = self->GetException(NULL); + self->ClearException(); + return exception; +} + +extern "C" int32_t art_portable_find_catch_block_from_code(mirror::AbstractMethod* current_method, + uint32_t ti_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Thread* self = Thread::Current(); // TODO: make an argument. + ThrowLocation throw_location; + mirror::Throwable* exception = self->GetException(&throw_location); + // Check for special deoptimization exception. + if (UNLIKELY(reinterpret_cast<int32_t>(exception) == -1)) { + return -1; + } + mirror::Class* exception_type = exception->GetClass(); + MethodHelper mh(current_method); + const DexFile::CodeItem* code_item = mh.GetCodeItem(); + DCHECK_LT(ti_offset, code_item->tries_size_); + const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item, ti_offset); + + int iter_index = 0; + int result = -1; + uint32_t catch_dex_pc = -1; + // Iterate over the catch handlers associated with dex_pc + for (CatchHandlerIterator it(*code_item, *try_item); it.HasNext(); it.Next()) { + uint16_t iter_type_idx = it.GetHandlerTypeIndex(); + // Catch all case + if (iter_type_idx == DexFile::kDexNoIndex16) { + catch_dex_pc = it.GetHandlerAddress(); + result = iter_index; + break; + } + // Does this catch exception type apply? + mirror::Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx); + if (UNLIKELY(iter_exception_type == NULL)) { + // TODO: check, the verifier (class linker?) should take care of resolving all exception + // classes early. + LOG(WARNING) << "Unresolved exception class when finding catch block: " + << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx); + } else if (iter_exception_type->IsAssignableFrom(exception_type)) { + catch_dex_pc = it.GetHandlerAddress(); + result = iter_index; + break; + } + ++iter_index; + } + if (result != -1) { + // Handler found. + Runtime::Current()->GetInstrumentation()->ExceptionCaughtEvent(self, + throw_location, + current_method, + catch_dex_pc, + exception); + // If the catch block has no move-exception then clear the exception for it. + const Instruction* first_catch_instr = Instruction::At(&mh.GetCodeItem()->insns_[catch_dex_pc]); + if (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION) { + self->ClearException(); + } + } + return result; +} + +} // namespace art diff --git a/runtime/oat/runtime/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h index 59f46acbac..0cb578ddd0 100644 --- a/runtime/oat/runtime/callee_save_frame.h +++ b/runtime/entrypoints/quick/callee_save_frame.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_RUNTIME_CALLEE_SAVE_FRAME_H_ -#define ART_RUNTIME_OAT_RUNTIME_CALLEE_SAVE_FRAME_H_ +#ifndef ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_ +#define ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_ #include "base/mutex.h" #include "thread-inl.h" @@ -38,4 +38,4 @@ static void FinishCalleeSaveFrameSetup(Thread* self, mirror::AbstractMethod** sp } // namespace art -#endif // ART_RUNTIME_OAT_RUNTIME_CALLEE_SAVE_FRAME_H_ +#endif // ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_ diff --git a/runtime/oat/runtime/support_alloc.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc index f66fc848d5..9ed802a2bb 100644 --- a/runtime/oat/runtime/support_alloc.cc +++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc @@ -15,11 +15,11 @@ */ #include "callee_save_frame.h" +#include "entrypoints/entrypoint_utils.h" #include "mirror/class-inl.h" #include "mirror/abstract_method-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" -#include "runtime_support.h" namespace art { diff --git a/runtime/oat/runtime/argument_visitor.h b/runtime/entrypoints/quick/quick_argument_visitor.h index aaf93f7db7..35fa97269c 100644 --- a/runtime/oat/runtime/argument_visitor.h +++ b/runtime/entrypoints/quick/quick_argument_visitor.h @@ -14,124 +14,14 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_RUNTIME_ARGUMENT_VISITOR_H_ -#define ART_RUNTIME_OAT_RUNTIME_ARGUMENT_VISITOR_H_ +#ifndef ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ARGUMENT_VISITOR_H_ +#define ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ARGUMENT_VISITOR_H_ #include "object_utils.h" namespace art { // Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame. -class PortableArgumentVisitor { - public: -// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame. -// Size of Runtime::kRefAndArgs callee save frame. -// Size of Method* and register parameters in out stack arguments. -#if defined(__arm__) -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8 -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48 -#define PORTABLE_STACK_ARG_SKIP 0 -#elif defined(__mips__) -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4 -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64 -#define PORTABLE_STACK_ARG_SKIP 16 -#elif defined(__i386__) -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4 -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32 -#define PORTABLE_STACK_ARG_SKIP 4 -#else -#error "Unsupported architecture" -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0 -#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0 -#define PORTABLE_STACK_ARG_SKIP 0 -#endif - - PortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : - caller_mh_(caller_mh), - args_in_regs_(ComputeArgsInRegs(caller_mh)), - num_params_(caller_mh.NumArgs()), - reg_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET), - stack_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE - + PORTABLE_STACK_ARG_SKIP), - cur_args_(reg_args_), - cur_arg_index_(0), - param_index_(0) { - } - - virtual ~PortableArgumentVisitor() {} - - virtual void Visit() = 0; - - bool IsParamAReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return caller_mh_.IsParamAReference(param_index_); - } - - bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return caller_mh_.IsParamALongOrDouble(param_index_); - } - - Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return caller_mh_.GetParamPrimitiveType(param_index_); - } - - byte* GetParamAddress() const { - return cur_args_ + (cur_arg_index_ * kPointerSize); - } - - void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - for (cur_arg_index_ = 0; cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) { -#if (defined(__arm__) || defined(__mips__)) - if (IsParamALongOrDouble() && cur_arg_index_ == 2) { - break; - } -#endif - Visit(); - cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1); - param_index_++; - } - cur_args_ = stack_args_; - cur_arg_index_ = 0; - while (param_index_ < num_params_) { -#if (defined(__arm__) || defined(__mips__)) - if (IsParamALongOrDouble() && cur_arg_index_ % 2 != 0) { - cur_arg_index_++; - } -#endif - Visit(); - cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1); - param_index_++; - } - } - - private: - static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { -#if (defined(__i386__)) - return 0; -#else - size_t args_in_regs = 0; - size_t num_params = mh.NumArgs(); - for (size_t i = 0; i < num_params; i++) { - args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1); - if (args_in_regs > 3) { - args_in_regs = 3; - break; - } - } - return args_in_regs; -#endif - } - MethodHelper& caller_mh_; - const size_t args_in_regs_; - const size_t num_params_; - byte* const reg_args_; - byte* const stack_args_; - byte* cur_args_; - size_t cur_arg_index_; - size_t param_index_; -}; - -// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame. class QuickArgumentVisitor { public: // Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame. @@ -245,4 +135,4 @@ class QuickArgumentVisitor { } // namespace art -#endif // ART_RUNTIME_OAT_RUNTIME_ARGUMENT_VISITOR_H_ +#endif // ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ARGUMENT_VISITOR_H_ diff --git a/runtime/oat/runtime/support_cast.cc b/runtime/entrypoints/quick/quick_cast_entrypoints.cc index fe91e617bb..b810bb70a6 100644 --- a/runtime/oat/runtime/support_cast.cc +++ b/runtime/entrypoints/quick/quick_cast_entrypoints.cc @@ -15,10 +15,10 @@ */ #include "callee_save_frame.h" +#include "entrypoints/entrypoint_utils.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" -#include "runtime_support.h" namespace art { diff --git a/runtime/oat/runtime/support_deoptimize.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc index 43fc9d2a2d..43fc9d2a2d 100644 --- a/runtime/oat/runtime/support_deoptimize.cc +++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc diff --git a/runtime/oat/runtime/support_dexcache.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc index 0af7a6281d..6400161b3e 100644 --- a/runtime/oat/runtime/support_dexcache.cc +++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc @@ -15,13 +15,13 @@ */ #include "callee_save_frame.h" -#include "gc/accounting/card_table-inl.h" +#include "entrypoints/entrypoint_utils.h" #include "class_linker-inl.h" #include "dex_file-inl.h" +#include "gc/accounting/card_table-inl.h" #include "mirror/abstract_method-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" -#include "runtime_support.h" namespace art { diff --git a/runtime/oat/runtime/oat_support_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h index 546ee01c6f..74b8cfd09b 100644 --- a/runtime/oat/runtime/oat_support_entrypoints.h +++ b/runtime/entrypoints/quick/quick_entrypoints.h @@ -14,28 +14,29 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_ -#define ART_RUNTIME_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_ +#ifndef ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ENTRYPOINTS_H_ +#define ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ENTRYPOINTS_H_ #include "dex_file-inl.h" #include "runtime.h" -#define ENTRYPOINT_OFFSET(x) \ - (static_cast<uintptr_t>(OFFSETOF_MEMBER(Thread, entrypoints_)) + \ - static_cast<uintptr_t>(OFFSETOF_MEMBER(EntryPoints, x))) +#define QUICK_ENTRYPOINT_OFFSET(x) \ + (static_cast<uintptr_t>(OFFSETOF_MEMBER(Thread, quick_entrypoints_)) + \ + static_cast<uintptr_t>(OFFSETOF_MEMBER(QuickEntryPoints, x))) namespace art { namespace mirror { -class AbstractMethod; -class Class; -class Object; + class AbstractMethod; + class Class; + class Object; } // namespace mirror class DvmDex; class MethodHelper; class ShadowFrame; class Thread; -struct PACKED(4) EntryPoints { +// Pointers to functions that are called by quick compiler generated code via thread-local storage. +struct PACKED(4) QuickEntryPoints { // Alloc void* (*pAllocArrayFromCode)(uint32_t, void*, int32_t); void* (*pAllocArrayFromCodeWithAccessCheck)(uint32_t, void*, int32_t); @@ -122,8 +123,6 @@ struct PACKED(4) EntryPoints { void* (*pMemcpy)(void*, const void*, size_t); // Invocation - const void* (*pPortableResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*, - mirror::AbstractMethod**, Thread*); const void* (*pQuickResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*, mirror::AbstractMethod**, Thread*); void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*); @@ -166,12 +165,6 @@ extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result, jobject locked, Thread* self) SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR; -// Initialize an entry point data structure. -void InitEntryPoints(EntryPoints* points); - -// Change the debugger entry point in the data structure. -void ChangeDebuggerEntryPoint(EntryPoints* points, bool enabled); - } // namespace art -#endif // ART_RUNTIME_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_ +#endif // ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ENTRYPOINTS_H_ diff --git a/runtime/oat/runtime/support_field.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc index c20326c63e..a4e9dc9b27 100644 --- a/runtime/oat/runtime/support_field.cc +++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc @@ -16,10 +16,10 @@ #include "callee_save_frame.h" #include "dex_file-inl.h" +#include "entrypoints/entrypoint_utils.h" #include "mirror/abstract_method-inl.h" #include "mirror/class-inl.h" #include "mirror/field-inl.h" -#include "runtime_support.h" #include <stdint.h> diff --git a/runtime/oat/runtime/support_fillarray.cc b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc index a0b06fb521..b81ad12b7b 100644 --- a/runtime/oat/runtime/support_fillarray.cc +++ b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc @@ -52,7 +52,7 @@ extern "C" int artHandleFillArrayDataFromCode(mirror::Array* array, ThrowLocation throw_location = self->GetCurrentLocationForThrow(); self->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;", "failed FILL_ARRAY_DATA; length=%d, index=%d", - array->GetLength(), payload->element_count); + array->GetLength(), payload->element_count - 1); return -1; // Error } uint32_t size_in_bytes = payload->element_count * payload->element_width; diff --git a/runtime/oat/runtime/support_instrumentation.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc index 7ecd296742..7ecd296742 100644 --- a/runtime/oat/runtime/support_instrumentation.cc +++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc diff --git a/runtime/oat/runtime/support_interpreter.cc b/runtime/entrypoints/quick/quick_interpreter_entrypoints.cc index 78b7e10b2a..656df8de5b 100644 --- a/runtime/oat/runtime/support_interpreter.cc +++ b/runtime/entrypoints/quick/quick_interpreter_entrypoints.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "argument_visitor.h" +#include "quick_argument_visitor.h" #include "callee_save_frame.h" #include "dex_file-inl.h" #include "interpreter/interpreter.h" diff --git a/runtime/oat/runtime/support_invoke.cc b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc index 6a95f3c8ff..53b3628e2f 100644 --- a/runtime/oat/runtime/support_invoke.cc +++ b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc @@ -16,12 +16,12 @@ #include "callee_save_frame.h" #include "dex_instruction-inl.h" +#include "entrypoints/entrypoint_utils.h" #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" #include "mirror/abstract_method-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" -#include "runtime_support.h" namespace art { diff --git a/runtime/oat/runtime/support_jni.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc index 2d31160a4b..23a28f9cce 100644 --- a/runtime/oat/runtime/support_jni.cc +++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc @@ -15,13 +15,13 @@ */ #include "dex_file-inl.h" +#include "entrypoints/entrypoint_utils.h" #include "mirror/class-inl.h" #include "mirror/abstract_method-inl.h" #include "mirror/object.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "object_utils.h" -#include "runtime_support.h" #include "scoped_thread_state_change.h" #include "thread.h" diff --git a/runtime/oat/runtime/support_locks.cc b/runtime/entrypoints/quick/quick_lock_entrypoints.cc index 79bb7a69f1..79bb7a69f1 100644 --- a/runtime/oat/runtime/support_locks.cc +++ b/runtime/entrypoints/quick/quick_lock_entrypoints.cc diff --git a/runtime/oat/runtime/support_math.cc b/runtime/entrypoints/quick/quick_math_entrypoints.cc index 0bfe59dc2f..0bfe59dc2f 100644 --- a/runtime/oat/runtime/support_math.cc +++ b/runtime/entrypoints/quick/quick_math_entrypoints.cc diff --git a/runtime/oat/runtime/support_proxy.cc b/runtime/entrypoints/quick/quick_proxy_entrypoints.cc index d4d0ca1034..4e3d749e27 100644 --- a/runtime/oat/runtime/support_proxy.cc +++ b/runtime/entrypoints/quick/quick_proxy_entrypoints.cc @@ -14,14 +14,14 @@ * limitations under the License. */ -#include "argument_visitor.h" +#include "quick_argument_visitor.h" #include "dex_file-inl.h" +#include "entrypoints/entrypoint_utils.h" #include "mirror/abstract_method-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" #include "object_utils.h" #include "reflection.h" -#include "runtime_support.h" #include "scoped_thread_state_change.h" #include "thread.h" #include "well_known_classes.h" @@ -32,50 +32,6 @@ namespace art { // Visits arguments on the stack placing them into the args vector, Object* arguments are converted // to jobjects. -class BuildPortableArgumentVisitor : public PortableArgumentVisitor { - public: - BuildPortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp, - ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) : - PortableArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {} - - virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - jvalue val; - Primitive::Type type = GetParamPrimitiveType(); - switch (type) { - case Primitive::kPrimNot: { - mirror::Object* obj = *reinterpret_cast<mirror::Object**>(GetParamAddress()); - val.l = soa_.AddLocalReference<jobject>(obj); - break; - } - case Primitive::kPrimLong: // Fall-through. - case Primitive::kPrimDouble: - val.j = *reinterpret_cast<jlong*>(GetParamAddress()); - break; - case Primitive::kPrimBoolean: // Fall-through. - case Primitive::kPrimByte: // Fall-through. - case Primitive::kPrimChar: // Fall-through. - case Primitive::kPrimShort: // Fall-through. - case Primitive::kPrimInt: // Fall-through. - case Primitive::kPrimFloat: - val.i = *reinterpret_cast<jint*>(GetParamAddress()); - break; - case Primitive::kPrimVoid: - LOG(FATAL) << "UNREACHABLE"; - val.j = 0; - break; - } - args_.push_back(val); - } - - private: - ScopedObjectAccessUnchecked& soa_; - std::vector<jvalue>& args_; - - DISALLOW_COPY_AND_ASSIGN(BuildPortableArgumentVisitor); -}; - -// Visits arguments on the stack placing them into the args vector, Object* arguments are converted -// to jobjects. class BuildQuickArgumentVisitor : public QuickArgumentVisitor { public: BuildQuickArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp, @@ -126,46 +82,6 @@ class BuildQuickArgumentVisitor : public QuickArgumentVisitor { // which is responsible for recording callee save registers. We explicitly place into jobjects the // incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a // field within the proxy object, which will box the primitive arguments and deal with error cases. -extern "C" uint64_t artPortableProxyInvokeHandler(mirror::AbstractMethod* proxy_method, - mirror::Object* receiver, - Thread* self, mirror::AbstractMethod** sp) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - // Ensure we don't get thread suspension until the object arguments are safely in jobjects. - const char* old_cause = - self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments"); - self->VerifyStack(); - // Start new JNI local reference state. - JNIEnvExt* env = self->GetJniEnv(); - ScopedObjectAccessUnchecked soa(env); - ScopedJniEnvLocalRefState env_state(env); - // Create local ref. copies of proxy method and the receiver. - jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver); - - // Placing arguments into args vector and remove the receiver. - MethodHelper proxy_mh(proxy_method); - std::vector<jvalue> args; - BuildPortableArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args); - local_ref_visitor.VisitArguments(); - args.erase(args.begin()); - - // Convert proxy method into expected interface method. - mirror::AbstractMethod* interface_method = proxy_method->FindOverriddenMethod(); - DCHECK(interface_method != NULL); - DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method); - jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method); - - // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code - // that performs allocations. - self->EndAssertNoThreadSuspension(old_cause); - JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(), - rcvr_jobj, interface_method_jobj, args); - return result.GetJ(); -} - -// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method -// which is responsible for recording callee save registers. We explicitly place into jobjects the -// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a -// field within the proxy object, which will box the primitive arguments and deal with error cases. extern "C" uint64_t artQuickProxyInvokeHandler(mirror::AbstractMethod* proxy_method, mirror::Object* receiver, Thread* self, mirror::AbstractMethod** sp) diff --git a/runtime/oat/runtime/support_stubs.cc b/runtime/entrypoints/quick/quick_stub_entrypoints.cc index f2af6d28dc..d78bbf3bc8 100644 --- a/runtime/oat/runtime/support_stubs.cc +++ b/runtime/entrypoints/quick/quick_stub_entrypoints.cc @@ -30,127 +30,6 @@ extern "C" void art_quick_deliver_exception_from_code(void*); namespace art { -// Lazily resolve a method for portable. Called by stub code. -extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called, - mirror::Object* receiver, - mirror::AbstractMethod** called_addr, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - uint32_t dex_pc; - mirror::AbstractMethod* caller = thread->GetCurrentMethod(&dex_pc); - - ClassLinker* linker = Runtime::Current()->GetClassLinker(); - InvokeType invoke_type; - bool is_range; - if (called->IsRuntimeMethod()) { - const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem(); - CHECK_LT(dex_pc, code->insns_size_in_code_units_); - const Instruction* instr = Instruction::At(&code->insns_[dex_pc]); - Instruction::Code instr_code = instr->Opcode(); - switch (instr_code) { - case Instruction::INVOKE_DIRECT: - invoke_type = kDirect; - is_range = false; - break; - case Instruction::INVOKE_DIRECT_RANGE: - invoke_type = kDirect; - is_range = true; - break; - case Instruction::INVOKE_STATIC: - invoke_type = kStatic; - is_range = false; - break; - case Instruction::INVOKE_STATIC_RANGE: - invoke_type = kStatic; - is_range = true; - break; - case Instruction::INVOKE_SUPER: - invoke_type = kSuper; - is_range = false; - break; - case Instruction::INVOKE_SUPER_RANGE: - invoke_type = kSuper; - is_range = true; - break; - case Instruction::INVOKE_VIRTUAL: - invoke_type = kVirtual; - is_range = false; - break; - case Instruction::INVOKE_VIRTUAL_RANGE: - invoke_type = kVirtual; - is_range = true; - break; - case Instruction::INVOKE_INTERFACE: - invoke_type = kInterface; - is_range = false; - break; - case Instruction::INVOKE_INTERFACE_RANGE: - invoke_type = kInterface; - is_range = true; - break; - default: - LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL); - // Avoid used uninitialized warnings. - invoke_type = kDirect; - is_range = true; - } - uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c(); - called = linker->ResolveMethod(dex_method_idx, caller, invoke_type); - // Refine called method based on receiver. - if (invoke_type == kVirtual) { - called = receiver->GetClass()->FindVirtualMethodForVirtual(called); - } else if (invoke_type == kInterface) { - called = receiver->GetClass()->FindVirtualMethodForInterface(called); - } - } else { - CHECK(called->IsStatic()) << PrettyMethod(called); - invoke_type = kStatic; - } - const void* code = NULL; - if (LIKELY(!thread->IsExceptionPending())) { - // Incompatible class change should have been handled in resolve method. - CHECK(!called->CheckIncompatibleClassChange(invoke_type)); - // Ensure that the called method's class is initialized. - mirror::Class* called_class = called->GetDeclaringClass(); - linker->EnsureInitialized(called_class, true, true); - if (LIKELY(called_class->IsInitialized())) { - code = called->GetEntryPointFromCompiledCode(); - // TODO: remove this after we solve the link issue. - { // for lazy link. - if (code == NULL) { - code = linker->GetOatCodeFor(called); - } - } - } else if (called_class->IsInitializing()) { - if (invoke_type == kStatic) { - // Class is still initializing, go to oat and grab code (trampoline must be left in place - // until class is initialized to stop races between threads). - code = linker->GetOatCodeFor(called); - } else { - // No trampoline for non-static methods. - code = called->GetEntryPointFromCompiledCode(); - // TODO: remove this after we solve the link issue. - { // for lazy link. - if (code == NULL) { - code = linker->GetOatCodeFor(called); - } - } - } - } else { - DCHECK(called_class->IsErroneous()); - } - } - if (LIKELY(code != NULL)) { - // Expect class to at least be initializing. - DCHECK(called->GetDeclaringClass()->IsInitializing()); - // Don't want infinite recursion. - DCHECK(code != GetResolutionTrampoline(linker)); - // Set up entry into main method - *called_addr = called; - } - return code; -} - // Lazily resolve a method for quick. Called by stub code. extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called, mirror::Object* receiver, @@ -413,26 +292,4 @@ extern "C" void artThrowAbstractMethodErrorFromCode(mirror::AbstractMethod* meth self->QuickDeliverException(); } -// Used by the JNI dlsym stub to find the native method to invoke if none is registered. -extern "C" void* artFindNativeMethod(Thread* self) { - Locks::mutator_lock_->AssertNotHeld(self); // We come here as Native. - DCHECK(Thread::Current() == self); - ScopedObjectAccess soa(self); - - mirror::AbstractMethod* method = self->GetCurrentMethod(NULL); - DCHECK(method != NULL); - - // Lookup symbol address for method, on failure we'll return NULL with an - // exception set, otherwise we return the address of the method we found. - void* native_code = soa.Vm()->FindCodeForNativeMethod(method); - if (native_code == NULL) { - DCHECK(self->IsExceptionPending()); - return NULL; - } else { - // Register so that future calls don't come here - method->RegisterNative(self, native_code); - return native_code; - } -} - } // namespace art diff --git a/runtime/oat/runtime/support_thread.cc b/runtime/entrypoints/quick/quick_thread_entrypoints.cc index e7117147a9..b4d6c0ba8d 100644 --- a/runtime/oat/runtime/support_thread.cc +++ b/runtime/entrypoints/quick/quick_thread_entrypoints.cc @@ -15,7 +15,7 @@ */ #include "callee_save_frame.h" -#include "runtime_support.h" +#include "entrypoints/entrypoint_utils.h" #include "thread.h" #include "thread_list.h" diff --git a/runtime/oat/runtime/support_throw.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc index 9588698bb2..3bfa2f2611 100644 --- a/runtime/oat/runtime/support_throw.cc +++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc @@ -15,9 +15,9 @@ */ #include "callee_save_frame.h" +#include "entrypoints/entrypoint_utils.h" #include "mirror/object.h" #include "object_utils.h" -#include "runtime_support.h" #include "thread.h" #include "well_known_classes.h" diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h index 92d9ea2828..a732566f65 100644 --- a/runtime/gc/accounting/atomic_stack.h +++ b/runtime/gc/accounting/atomic_stack.h @@ -47,7 +47,7 @@ class AtomicStack { DCHECK(begin_ != NULL); front_index_ = 0; back_index_ = 0; - is_sorted_ = true; + debug_is_sorted_ = true; int result = madvise(begin_, sizeof(T) * capacity_, MADV_DONTNEED); if (result == -1) { PLOG(WARNING) << "madvise failed"; @@ -58,8 +58,10 @@ class AtomicStack { // Returns false if we overflowed the stack. bool AtomicPushBack(const T& value) { + if (kIsDebugBuild) { + debug_is_sorted_ = false; + } int32_t index; - is_sorted_ = false; do { index = back_index_; if (UNLIKELY(static_cast<size_t>(index) >= capacity_)) { @@ -72,7 +74,9 @@ class AtomicStack { } void PushBack(const T& value) { - is_sorted_ = false; + if (kIsDebugBuild) { + debug_is_sorted_ = false; + } int32_t index = back_index_; DCHECK_LT(static_cast<size_t>(index), capacity_); back_index_ = index + 1; @@ -122,22 +126,23 @@ class AtomicStack { } void Sort() { - if (!is_sorted_) { - int32_t start_back_index = back_index_.load(); - int32_t start_front_index = front_index_.load(); - is_sorted_ = true; - std::sort(Begin(), End()); - CHECK_EQ(start_back_index, back_index_.load()); - CHECK_EQ(start_front_index, front_index_.load()); + int32_t start_back_index = back_index_.load(); + int32_t start_front_index = front_index_.load(); + std::sort(Begin(), End()); + CHECK_EQ(start_back_index, back_index_.load()); + CHECK_EQ(start_front_index, front_index_.load()); + if (kIsDebugBuild) { + debug_is_sorted_ = true; } } + bool ContainsSorted(const T& value) const { + DCHECK(debug_is_sorted_); + return std::binary_search(Begin(), End(), value); + } + bool Contains(const T& value) const { - if (is_sorted_) { - return std::binary_search(Begin(), End(), value); - } else { - return std::find(Begin(), End(), value) != End(); - } + return std::find(Begin(), End(), value) != End(); } private: @@ -147,7 +152,7 @@ class AtomicStack { front_index_(0), begin_(NULL), capacity_(capacity), - is_sorted_(true) { + debug_is_sorted_(true) { } // Size in number of elements. @@ -156,6 +161,7 @@ class AtomicStack { CHECK(mem_map_.get() != NULL) << "couldn't allocate mark stack"; byte* addr = mem_map_->Begin(); CHECK(addr != NULL); + debug_is_sorted_ = true; begin_ = reinterpret_cast<T*>(addr); Reset(); } @@ -178,7 +184,8 @@ class AtomicStack { // Maximum number of elements. size_t capacity_; - bool is_sorted_; + // Whether or not the stack is sorted, only updated in debug mode to avoid performance overhead. + bool debug_is_sorted_; DISALLOW_COPY_AND_ASSIGN(AtomicStack); }; diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h index 1684664eff..0f566c954b 100644 --- a/runtime/gc/collector/garbage_collector.h +++ b/runtime/gc/collector/garbage_collector.h @@ -64,7 +64,7 @@ class GarbageCollector { void RegisterPause(uint64_t nano_length); - base::NewTimingLogger& GetTimings() { + base::TimingLogger& GetTimings() { return timings_; } @@ -101,7 +101,7 @@ class GarbageCollector { const bool verbose_; uint64_t duration_ns_; - base::NewTimingLogger timings_; + base::TimingLogger timings_; // Cumulative statistics. uint64_t total_time_ns_; diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index 5736e3817b..89c768a34e 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -1509,7 +1509,7 @@ void MarkSweep::FinishPhase() { // Update the cumulative loggers. cumulative_timings_.Start(); - cumulative_timings_.AddNewLogger(timings_); + cumulative_timings_.AddLogger(timings_); cumulative_timings_.End(); // Clear all of the spaces' mark bitmaps. diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 0c1c6312a8..00f7e5b57f 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -148,7 +148,7 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max CHECK(large_object_space_ != NULL) << "Failed to create large object space"; AddDiscontinuousSpace(large_object_space_); - alloc_space_ = space::DlMallocSpace::Create("alloc space", + alloc_space_ = space::DlMallocSpace::Create(Runtime::Current()->IsZygote() ? "zygote space" : "alloc space", initial_size, growth_limit, capacity, requested_alloc_space_begin); @@ -524,25 +524,24 @@ bool Heap::IsHeapAddress(const mirror::Object* obj) { bool Heap::IsLiveObjectLocked(const mirror::Object* obj) { // Locks::heap_bitmap_lock_->AssertReaderHeld(Thread::Current()); - if (obj == NULL) { - return false; - } - if (UNLIKELY(!IsAligned<kObjectAlignment>(obj))) { + if (obj == NULL || UNLIKELY(!IsAligned<kObjectAlignment>(obj))) { return false; } - space::ContinuousSpace* cont_space = FindContinuousSpaceFromObject(obj, true); - if (cont_space != NULL) { - if (cont_space->GetLiveBitmap()->Test(obj)) { + space::ContinuousSpace* c_space = FindContinuousSpaceFromObject(obj, true); + space::DiscontinuousSpace* d_space = NULL; + if (c_space != NULL) { + if (c_space->GetLiveBitmap()->Test(obj)) { return true; } } else { - space::DiscontinuousSpace* disc_space = FindDiscontinuousSpaceFromObject(obj, true); - if (disc_space != NULL) { - if (disc_space->GetLiveObjects()->Test(obj)) { + d_space = FindDiscontinuousSpaceFromObject(obj, true); + if (d_space != NULL) { + if (d_space->GetLiveObjects()->Test(obj)) { return true; } } } + // This is covering the allocation/live stack swapping that is done without mutators suspended. for (size_t i = 0; i < 5; ++i) { if (allocation_stack_->Contains(const_cast<mirror::Object*>(obj)) || live_stack_->Contains(const_cast<mirror::Object*>(obj))) { @@ -550,6 +549,18 @@ bool Heap::IsLiveObjectLocked(const mirror::Object* obj) { } NanoSleep(MsToNs(10)); } + // We need to check the bitmaps again since there is a race where we mark something as live and + // then clear the stack containing it. + if (c_space != NULL) { + if (c_space->GetLiveBitmap()->Test(obj)) { + return true; + } + } else { + d_space = FindDiscontinuousSpaceFromObject(obj, true); + if (d_space != NULL && d_space->GetLiveObjects()->Test(obj)) { + return true; + } + } return false; } @@ -972,7 +983,7 @@ void Heap::PreZygoteFork() { // Turns the current alloc space into a Zygote space and obtain the new alloc space composed // of the remaining available heap memory. space::DlMallocSpace* zygote_space = alloc_space_; - alloc_space_ = zygote_space->CreateZygoteSpace(); + alloc_space_ = zygote_space->CreateZygoteSpace("alloc space"); alloc_space_->SetFootprintLimit(alloc_space_->Capacity()); // Change the GC retention policy of the zygote space to only collect when full. @@ -1131,7 +1142,7 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCaus << PrettySize(total_memory) << ", " << "paused " << pause_string.str() << " total " << PrettyDuration((duration / 1000) * 1000); if (VLOG_IS_ON(heap)) { - LOG(INFO) << Dumpable<base::NewTimingLogger>(collector->GetTimings()); + LOG(INFO) << Dumpable<base::TimingLogger>(collector->GetTimings()); } } @@ -1149,7 +1160,7 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCaus return gc_type; } -void Heap::UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::NewTimingLogger& timings, +void Heap::UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::TimingLogger& timings, collector::GcType gc_type) { if (gc_type == collector::kGcTypeSticky) { // Don't need to do anything for mod union table in this case since we are only scanning dirty @@ -1229,10 +1240,10 @@ class VerifyReferenceVisitor { if (bitmap != NULL && bitmap->Test(obj)) { LOG(ERROR) << "Object " << obj << " found in live bitmap"; } - if (alloc_stack->Contains(const_cast<mirror::Object*>(obj))) { + if (alloc_stack->ContainsSorted(const_cast<mirror::Object*>(obj))) { LOG(ERROR) << "Object " << obj << " found in allocation stack"; } - if (live_stack->Contains(const_cast<mirror::Object*>(obj))) { + if (live_stack->ContainsSorted(const_cast<mirror::Object*>(obj))) { LOG(ERROR) << "Object " << obj << " found in live stack"; } // Attempt to see if the card table missed the reference. @@ -1252,10 +1263,10 @@ class VerifyReferenceVisitor { } else { LOG(ERROR) << "Root references dead object " << ref << "\nRef type " << PrettyTypeOf(ref); } - if (alloc_stack->Contains(const_cast<mirror::Object*>(ref))) { + if (alloc_stack->ContainsSorted(const_cast<mirror::Object*>(ref))) { LOG(ERROR) << "Reference " << ref << " found in allocation stack!"; } - if (live_stack->Contains(const_cast<mirror::Object*>(ref))) { + if (live_stack->ContainsSorted(const_cast<mirror::Object*>(ref))) { LOG(ERROR) << "Reference " << ref << " found in live stack!"; } heap_->image_mod_union_table_->Dump(LOG(ERROR) << "Image mod-union table: "); @@ -1345,8 +1356,8 @@ class VerifyReferenceCardVisitor { // Card should be either kCardDirty if it got re-dirtied after we aged it, or // kCardDirty - 1 if it didnt get touched since we aged it. accounting::ObjectStack* live_stack = heap_->live_stack_.get(); - if (live_stack->Contains(const_cast<mirror::Object*>(ref))) { - if (live_stack->Contains(const_cast<mirror::Object*>(obj))) { + if (live_stack->ContainsSorted(const_cast<mirror::Object*>(ref))) { + if (live_stack->ContainsSorted(const_cast<mirror::Object*>(obj))) { LOG(ERROR) << "Object " << obj << " found in live stack"; } if (heap_->GetLiveBitmap()->Test(obj)) { @@ -1441,7 +1452,7 @@ void Heap::SwapStacks() { } } -void Heap::ProcessCards(base::NewTimingLogger& timings) { +void Heap::ProcessCards(base::TimingLogger& timings) { // Clear cards and keep track of cards cleared in the mod-union table. typedef std::vector<space::ContinuousSpace*>::iterator It; for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) { @@ -1934,5 +1945,27 @@ void Heap::RegisterNativeFree(int bytes) { } while (!native_bytes_allocated_.compare_and_swap(expected_size, new_size)); } +int64_t Heap::GetTotalMemory() const { + int64_t ret = 0; + typedef std::vector<space::ContinuousSpace*>::const_iterator It; + for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) { + space::ContinuousSpace* space = *it; + if (space->IsImageSpace()) { + // Currently don't include the image space. + } else if (space->IsDlMallocSpace()) { + // Zygote or alloc space + ret += space->AsDlMallocSpace()->GetFootprint(); + } + } + typedef std::vector<space::DiscontinuousSpace*>::const_iterator It2; + for (It2 it = discontinuous_spaces_.begin(), end = discontinuous_spaces_.end(); it != end; ++it) { + space::DiscontinuousSpace* space = *it; + if (space->IsLargeObjectSpace()) { + ret += space->AsLargeObjectSpace()->GetBytesAllocated(); + } + } + return ret; +} + } // namespace gc } // namespace art diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 20512b8d0b..7615f981dd 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -330,11 +330,7 @@ class Heap { // Implements java.lang.Runtime.totalMemory, returning the amount of memory consumed by an // application. - int64_t GetTotalMemory() const { - // TODO: we use the footprint limit here which is conservative wrt number of pages really used. - // We could implement a more accurate count across all spaces. - return max_allowed_footprint_; - } + int64_t GetTotalMemory() const; // Implements java.lang.Runtime.freeMemory. int64_t GetFreeMemory() const { @@ -382,7 +378,7 @@ class Heap { EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); // Update and mark mod union table based on gc type. - void UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::NewTimingLogger& timings, + void UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::TimingLogger& timings, collector::GcType gc_type) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); @@ -475,7 +471,7 @@ class Heap { void SwapStacks(); // Clear cards and update the mod union table. - void ProcessCards(base::NewTimingLogger& timings); + void ProcessCards(base::TimingLogger& timings); // All-known continuous spaces, where objects lie within fixed bounds. std::vector<space::ContinuousSpace*> continuous_spaces_; diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc index ee88edaaae..de4917fcee 100644 --- a/runtime/gc/space/dlmalloc_space.cc +++ b/runtime/gc/space/dlmalloc_space.cc @@ -286,7 +286,7 @@ void DlMallocSpace::SetGrowthLimit(size_t growth_limit) { } } -DlMallocSpace* DlMallocSpace::CreateZygoteSpace() { +DlMallocSpace* DlMallocSpace::CreateZygoteSpace(const char* alloc_space_name) { end_ = reinterpret_cast<byte*>(RoundUp(reinterpret_cast<uintptr_t>(end_), kPageSize)); DCHECK(IsAligned<accounting::CardTable::kCardSize>(begin_)); DCHECK(IsAligned<accounting::CardTable::kCardSize>(end_)); @@ -316,20 +316,19 @@ DlMallocSpace* DlMallocSpace::CreateZygoteSpace() { VLOG(heap) << "Size " << GetMemMap()->Size(); VLOG(heap) << "GrowthLimit " << PrettySize(growth_limit); VLOG(heap) << "Capacity " << PrettySize(capacity); - UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(GetName(), End(), capacity, PROT_READ | PROT_WRITE)); + UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(alloc_space_name, End(), capacity, PROT_READ | PROT_WRITE)); void* mspace = CreateMallocSpace(end_, starting_size, initial_size); // Protect memory beyond the initial size. byte* end = mem_map->Begin() + starting_size; if (capacity - initial_size > 0) { - CHECK_MEMORY_CALL(mprotect, (end, capacity - initial_size, PROT_NONE), name_.c_str()); + CHECK_MEMORY_CALL(mprotect, (end, capacity - initial_size, PROT_NONE), alloc_space_name); } DlMallocSpace* alloc_space = - new DlMallocSpace(name_, mem_map.release(), mspace, end_, end, growth_limit); + new DlMallocSpace(alloc_space_name, mem_map.release(), mspace, end_, end, growth_limit); live_bitmap_->SetHeapLimit(reinterpret_cast<uintptr_t>(End())); CHECK_EQ(live_bitmap_->HeapLimit(), reinterpret_cast<uintptr_t>(End())); mark_bitmap_->SetHeapLimit(reinterpret_cast<uintptr_t>(End())); CHECK_EQ(mark_bitmap_->HeapLimit(), reinterpret_cast<uintptr_t>(End())); - name_ += "-zygote-transformed"; VLOG(heap) << "zygote space creation done"; return alloc_space; } @@ -449,6 +448,11 @@ void DlMallocSpace::Walk(void(*callback)(void *start, void *end, size_t num_byte callback(NULL, NULL, 0, arg); // Indicate end of a space. } +size_t DlMallocSpace::GetFootprint() { + MutexLock mu(Thread::Current(), lock_); + return mspace_footprint(mspace_); +} + size_t DlMallocSpace::GetFootprintLimit() { MutexLock mu(Thread::Current(), lock_); return mspace_footprint_limit(mspace_); diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h index 8a4314c716..c15d0babcc 100644 --- a/runtime/gc/space/dlmalloc_space.h +++ b/runtime/gc/space/dlmalloc_space.h @@ -73,6 +73,10 @@ class DlMallocSpace : public MemMapSpace, public AllocSpace { // in use, indicated by num_bytes equaling zero. void Walk(WalkCallback callback, void* arg); + // Returns the number of bytes that the space has currently obtained from the system. This is + // greater or equal to the amount of live data in the space. + size_t GetFootprint(); + // Returns the number of bytes that the heap is allowed to obtain from the system via MoreCore. size_t GetFootprintLimit(); @@ -113,7 +117,7 @@ class DlMallocSpace : public MemMapSpace, public AllocSpace { void SwapBitmaps(); // Turn ourself into a zygote space and return a new alloc space which has our unused memory. - DlMallocSpace* CreateZygoteSpace(); + DlMallocSpace* CreateZygoteSpace(const char* alloc_space_name); uint64_t GetBytesAllocated() const { return num_bytes_allocated_; diff --git a/runtime/gc/space/space_test.cc b/runtime/gc/space/space_test.cc index 08ae894e58..3003140e5d 100644 --- a/runtime/gc/space/space_test.cc +++ b/runtime/gc/space/space_test.cc @@ -123,7 +123,7 @@ TEST_F(SpaceTest, ZygoteSpace) { // Make sure that the zygote space isn't directly at the start of the space. space->Alloc(self, 1U * MB); - space = space->CreateZygoteSpace(); + space = space->CreateZygoteSpace("alloc space"); // Make space findable to the heap, will also delete space when runtime is cleaned up AddContinuousSpace(space); diff --git a/runtime/image_test.cc b/runtime/image_test.cc index 75eead4d8f..22bed2e3d2 100644 --- a/runtime/image_test.cc +++ b/runtime/image_test.cc @@ -44,7 +44,8 @@ TEST_F(ImageTest, WriteRead) { { jobject class_loader = NULL; ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - TimingLogger timings("ImageTest::WriteRead", false); + base::TimingLogger timings("ImageTest::WriteRead", false, false); + timings.StartSplit("CompileAll"); compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings); ScopedObjectAccess soa(Thread::Current()); diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index e99fbd8d53..c0b85f41fd 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -30,7 +30,7 @@ #include "mirror/object-inl.h" #include "nth_caller_visitor.h" #if !defined(ART_USE_PORTABLE_COMPILER) -#include "oat/runtime/oat_support_entrypoints.h" +#include "entrypoints/quick/quick_entrypoints.h" #endif #include "object_utils.h" #include "os.h" diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index 30c7a46204..ef4b95c037 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -24,6 +24,7 @@ #include "dex_file-inl.h" #include "dex_instruction-inl.h" #include "dex_instruction.h" +#include "entrypoints/entrypoint_utils.h" #include "gc/accounting/card_table-inl.h" #include "invoke_arg_array_builder.h" #include "nth_caller_visitor.h" @@ -35,7 +36,6 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "object_utils.h" -#include "runtime_support.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change.h" #include "thread.h" @@ -408,11 +408,11 @@ static void DoMonitorExit(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS { // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template // specialization. template<InvokeType type, bool is_range, bool do_access_check> -static void DoInvoke(Thread* self, ShadowFrame& shadow_frame, +static bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, JValue* result) NO_THREAD_SAFETY_ANALYSIS; template<InvokeType type, bool is_range, bool do_access_check> -static void DoInvoke(Thread* self, ShadowFrame& shadow_frame, +static bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, JValue* result) { uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c(); @@ -422,7 +422,11 @@ static void DoInvoke(Thread* self, ShadowFrame& shadow_frame, if (UNLIKELY(method == NULL)) { CHECK(self->IsExceptionPending()); result->SetJ(0); - return; + return false; + } else if (UNLIKELY(method->IsAbstract())) { + ThrowAbstractMethodError(method); + result->SetJ(0); + return false; } MethodHelper mh(method); @@ -432,9 +436,6 @@ static void DoInvoke(Thread* self, ShadowFrame& shadow_frame, if (LIKELY(code_item != NULL)) { num_regs = code_item->registers_size_; num_ins = code_item->ins_size_; - } else if (method->IsAbstract()) { - ThrowAbstractMethodError(method); - return; } else { DCHECK(method->IsNative() || method->IsProxyMethod()); num_regs = num_ins = AbstractMethod::NumArgRegisters(mh.GetShorty()); @@ -486,17 +487,18 @@ static void DoInvoke(Thread* self, ShadowFrame& shadow_frame, } else { UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, num_regs - num_ins); } + return !self->IsExceptionPending(); } // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template // specialization. template<bool is_range> -static void DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, +static bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, JValue* result) NO_THREAD_SAFETY_ANALYSIS; template<bool is_range> -static void DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, +static bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, JValue* result) { uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c(); Object* receiver = shadow_frame.GetVRegReference(vregC); @@ -504,26 +506,28 @@ static void DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, // We lost the reference to the method index so we cannot get a more // precised exception message. ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow()); - return; + return false; } uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); + // TODO: use ObjectArray<T>::GetWithoutChecks ? AbstractMethod* method = receiver->GetClass()->GetVTable()->Get(vtable_idx); if (UNLIKELY(method == NULL)) { CHECK(self->IsExceptionPending()); result->SetJ(0); - return; + return false; + } else if (UNLIKELY(method->IsAbstract())) { + ThrowAbstractMethodError(method); + result->SetJ(0); + return false; } - MethodHelper mh(method); + MethodHelper mh(method); const DexFile::CodeItem* code_item = mh.GetCodeItem(); uint16_t num_regs; uint16_t num_ins; if (code_item != NULL) { num_regs = code_item->registers_size_; num_ins = code_item->ins_size_; - } else if (method->IsAbstract()) { - ThrowAbstractMethodError(method); - return; } else { DCHECK(method->IsNative() || method->IsProxyMethod()); num_regs = num_ins = AbstractMethod::NumArgRegisters(mh.GetShorty()); @@ -576,6 +580,7 @@ static void DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, } else { UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, num_regs - num_ins); } + return !self->IsExceptionPending(); } // We use template functions to optimize compiler inlining process. Otherwise, @@ -587,12 +592,12 @@ static void DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template // specialization. template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check> -static void DoFieldGet(Thread* self, ShadowFrame& shadow_frame, +static bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst) NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE; template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check> -static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame, +static inline bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst) { bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead); uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c(); @@ -601,7 +606,7 @@ static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame, do_access_check); if (UNLIKELY(f == NULL)) { CHECK(self->IsExceptionPending()); - return; + return false; } Object* obj; if (is_static) { @@ -610,7 +615,7 @@ static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame, obj = shadow_frame.GetVRegReference(inst->VRegB_22c()); if (UNLIKELY(obj == NULL)) { ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(), f, true); - return; + return false; } } uint32_t vregA = is_static ? inst->VRegA_21c() : inst->VRegA_22c(); @@ -639,24 +644,25 @@ static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame, default: LOG(FATAL) << "Unreachable: " << field_type; } + return true; } // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template // specialization. template<Primitive::Type field_type> -static void DoIGetQuick(Thread* self, ShadowFrame& shadow_frame, +static bool DoIGetQuick(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst) NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE; template<Primitive::Type field_type> -static inline void DoIGetQuick(Thread* self, ShadowFrame& shadow_frame, +static inline bool DoIGetQuick(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst) { Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c()); if (UNLIKELY(obj == NULL)) { // We lost the reference to the field index so we cannot get a more // precised exception message. ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow()); - return; + return false; } MemberOffset field_offset(inst->VRegC_22c()); const bool is_volatile = false; // iget-x-quick only on non volatile fields. @@ -674,17 +680,18 @@ static inline void DoIGetQuick(Thread* self, ShadowFrame& shadow_frame, default: LOG(FATAL) << "Unreachable: " << field_type; } + return true; } // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template // specialization. template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check> -static void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, +static bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst) NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE; template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check> -static inline void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, +static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst) { bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite); uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c(); @@ -693,7 +700,7 @@ static inline void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, do_access_check); if (UNLIKELY(f == NULL)) { CHECK(self->IsExceptionPending()); - return; + return false; } Object* obj; if (is_static) { @@ -703,7 +710,7 @@ static inline void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, if (UNLIKELY(obj == NULL)) { ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(), f, false); - return; + return false; } } uint32_t vregA = is_static ? inst->VRegA_21c() : inst->VRegA_22c(); @@ -732,24 +739,25 @@ static inline void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, default: LOG(FATAL) << "Unreachable: " << field_type; } + return true; } // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template // specialization. template<Primitive::Type field_type> -static void DoIPutQuick(Thread* self, ShadowFrame& shadow_frame, +static bool DoIPutQuick(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst) NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE; template<Primitive::Type field_type> -static inline void DoIPutQuick(Thread* self, ShadowFrame& shadow_frame, +static inline bool DoIPutQuick(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst) { Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c()); if (UNLIKELY(obj == NULL)) { // We lost the reference to the field index so we cannot get a more // precised exception message. ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow()); - return; + return false; } MemberOffset field_offset(inst->VRegC_22c()); const bool is_volatile = false; // iput-x-quick only on non volatile fields. @@ -767,6 +775,7 @@ static inline void DoIPutQuick(Thread* self, ShadowFrame& shadow_frame, default: LOG(FATAL) << "Unreachable: " << field_type; } + return true; } static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx) @@ -783,52 +792,64 @@ static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t str return mh.ResolveString(string_idx); } -static inline void DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg, +static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg, int32_t dividend, int32_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(divisor == 0)) { ThrowArithmeticExceptionDivideByZero(); - } else if (UNLIKELY(dividend == kMinInt && divisor == -1)) { + return false; + } + if (UNLIKELY(dividend == kMinInt && divisor == -1)) { shadow_frame.SetVReg(result_reg, kMinInt); } else { shadow_frame.SetVReg(result_reg, dividend / divisor); } + return true; } -static inline void DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg, +static inline bool DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg, int32_t dividend, int32_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(divisor == 0)) { ThrowArithmeticExceptionDivideByZero(); - } else if (UNLIKELY(dividend == kMinInt && divisor == -1)) { + return false; + } + if (UNLIKELY(dividend == kMinInt && divisor == -1)) { shadow_frame.SetVReg(result_reg, 0); } else { shadow_frame.SetVReg(result_reg, dividend % divisor); } + return true; } -static inline void DoLongDivide(ShadowFrame& shadow_frame, size_t result_reg, +static inline bool DoLongDivide(ShadowFrame& shadow_frame, size_t result_reg, int64_t dividend, int64_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(divisor == 0)) { ThrowArithmeticExceptionDivideByZero(); - } else if (UNLIKELY(dividend == kMinLong && divisor == -1)) { + return false; + } + if (UNLIKELY(dividend == kMinLong && divisor == -1)) { shadow_frame.SetVRegLong(result_reg, kMinLong); } else { shadow_frame.SetVRegLong(result_reg, dividend / divisor); } + return true; } -static inline void DoLongRemainder(ShadowFrame& shadow_frame, size_t result_reg, +static inline bool DoLongRemainder(ShadowFrame& shadow_frame, size_t result_reg, int64_t dividend, int64_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(divisor == 0)) { ThrowArithmeticExceptionDivideByZero(); - } else if (UNLIKELY(dividend == kMinLong && divisor == -1)) { + return false; + } + if (UNLIKELY(dividend == kMinLong && divisor == -1)) { shadow_frame.SetVRegLong(result_reg, 0); } else { shadow_frame.SetVRegLong(result_reg, dividend % divisor); } + return true; } // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template @@ -954,7 +975,9 @@ static inline const Instruction* FindNextInstructionFollowingException(Thread* s self->VerifyStack(); ThrowLocation throw_location; mirror::Throwable* exception = self->GetException(&throw_location); - uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception->GetClass(), dex_pc); + bool clear_exception; + uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception->GetClass(), dex_pc, + &clear_exception); if (found_dex_pc == DexFile::kDexNoIndex) { instrumentation->MethodUnwindEvent(self, this_object_ref.get(), shadow_frame.GetMethod(), dex_pc); @@ -963,6 +986,9 @@ static inline const Instruction* FindNextInstructionFollowingException(Thread* s instrumentation->ExceptionCaughtEvent(self, throw_location, shadow_frame.GetMethod(), found_dex_pc, exception); + if (clear_exception) { + self->ClearException(); + } return Instruction::At(insns + found_dex_pc); } } @@ -975,13 +1001,9 @@ static inline const Instruction* FindNextInstructionFollowingException(Thread* s return JValue(); /* Handled in caller. */ \ } -#define POSSIBLY_HANDLE_PENDING_EXCEPTION(next_function) \ - if (UNLIKELY(self->IsExceptionPending())) { \ - inst = FindNextInstructionFollowingException(self, shadow_frame, inst->GetDexPc(insns), insns, \ - this_object_ref, instrumentation); \ - if (inst == NULL) { \ - return JValue(); /* Handled in caller. */ \ - } \ +#define POSSIBLY_HANDLE_PENDING_EXCEPTION(is_exception_pending, next_function) \ + if (UNLIKELY(is_exception_pending)) { \ + HANDLE_PENDING_EXCEPTION(); \ } else { \ inst = inst->next_function(); \ } @@ -1013,28 +1035,29 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte return JValue(); } self->VerifyStack(); - instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); - const uint16_t* const insns = code_item->insns_; + instrumentation::Instrumentation* const instrumentation = Runtime::Current()->GetInstrumentation(); // As the 'this' object won't change during the execution of current code, we // want to cache it in local variables. Nevertheless, in order to let the // garbage collector access it, we store it into sirt references. SirtRef<Object> this_object_ref(self, shadow_frame.GetThisObject(code_item->ins_size_)); - const Instruction* inst = Instruction::At(insns + shadow_frame.GetDexPC()); - if (inst->GetDexPc(insns) == 0) { // We are entering the method as opposed to deoptimizing.. + uint32_t dex_pc = shadow_frame.GetDexPC(); + if (LIKELY(dex_pc == 0)) { // We are entering the method as opposed to deoptimizing.. if (UNLIKELY(instrumentation->HasMethodEntryListeners())) { instrumentation->MethodEnterEvent(self, this_object_ref.get(), shadow_frame.GetMethod(), 0); } } + const uint16_t* const insns = code_item->insns_; + const Instruction* inst = Instruction::At(insns + dex_pc); while (true) { + dex_pc = inst->GetDexPc(insns); + shadow_frame.SetDexPC(dex_pc); if (UNLIKELY(self->TestAllFlags())) { CheckSuspend(self); } - const uint32_t dex_pc = inst->GetDexPc(insns); - shadow_frame.SetDexPC(dex_pc); - if (instrumentation->HasDexPcListeners()) { + if (UNLIKELY(instrumentation->HasDexPcListeners())) { instrumentation->DexPcMovedEvent(self, this_object_ref.get(), shadow_frame.GetMethod(), dex_pc); } @@ -1200,8 +1223,8 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::CONST_4: { PREAMBLE(); - uint32_t dst = inst->VRegA_11n(); - int32_t val = inst->VRegB_11n(); + uint4_t dst = inst->VRegA_11n(); + int4_t val = inst->VRegB_11n(); shadow_frame.SetVReg(dst, val); if (val == 0) { shadow_frame.SetVRegReference(dst, NULL); @@ -1211,8 +1234,8 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::CONST_16: { PREAMBLE(); - uint32_t dst = inst->VRegA_21s(); - int32_t val = inst->VRegB_21s(); + uint8_t dst = inst->VRegA_21s(); + int16_t val = inst->VRegB_21s(); shadow_frame.SetVReg(dst, val); if (val == 0) { shadow_frame.SetVRegReference(dst, NULL); @@ -1222,7 +1245,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::CONST: { PREAMBLE(); - uint32_t dst = inst->VRegA_31i(); + uint8_t dst = inst->VRegA_31i(); int32_t val = inst->VRegB_31i(); shadow_frame.SetVReg(dst, val); if (val == 0) { @@ -1233,7 +1256,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::CONST_HIGH16: { PREAMBLE(); - uint32_t dst = inst->VRegA_21h(); + uint8_t dst = inst->VRegA_21h(); int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16); shadow_frame.SetVReg(dst, val); if (val == 0) { @@ -1304,7 +1327,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte HANDLE_PENDING_EXCEPTION(); } else { DoMonitorEnter(self, obj); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_1xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx); } break; } @@ -1316,7 +1339,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte HANDLE_PENDING_EXCEPTION(); } else { DoMonitorExit(self, obj); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_1xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx); } break; } @@ -1391,22 +1414,14 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte PREAMBLE(); bool success = DoFilledNewArray<false, do_access_check>(inst, shadow_frame, self, &result_register); - if (LIKELY(success)) { - inst = inst->Next_3xx(); - } else { - HANDLE_PENDING_EXCEPTION(); - } + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::FILLED_NEW_ARRAY_RANGE: { PREAMBLE(); bool success = DoFilledNewArray<true, do_access_check>(inst, shadow_frame, self, &result_register); - if (LIKELY(success)) { - inst = inst->Next_3xx(); - } else { - HANDLE_PENDING_EXCEPTION(); - } + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; } case Instruction::FILL_ARRAY_DATA: { @@ -1934,236 +1949,282 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } break; } - case Instruction::IGET_BOOLEAN: + case Instruction::IGET_BOOLEAN: { PREAMBLE(); - DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IGET_BYTE: + } + case Instruction::IGET_BYTE: { PREAMBLE(); - DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IGET_CHAR: + } + case Instruction::IGET_CHAR: { PREAMBLE(); - DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IGET_SHORT: + } + case Instruction::IGET_SHORT: { PREAMBLE(); - DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IGET: + } + case Instruction::IGET: { PREAMBLE(); - DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IGET_WIDE: + } + case Instruction::IGET_WIDE: { PREAMBLE(); - DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IGET_OBJECT: + } + case Instruction::IGET_OBJECT: { PREAMBLE(); - DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IGET_QUICK: + } + case Instruction::IGET_QUICK: { PREAMBLE(); - DoIGetQuick<Primitive::kPrimInt>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIGetQuick<Primitive::kPrimInt>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IGET_WIDE_QUICK: + } + case Instruction::IGET_WIDE_QUICK: { PREAMBLE(); - DoIGetQuick<Primitive::kPrimLong>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIGetQuick<Primitive::kPrimLong>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IGET_OBJECT_QUICK: + } + case Instruction::IGET_OBJECT_QUICK: { PREAMBLE(); - DoIGetQuick<Primitive::kPrimNot>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIGetQuick<Primitive::kPrimNot>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SGET_BOOLEAN: + } + case Instruction::SGET_BOOLEAN: { PREAMBLE(); - DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SGET_BYTE: + } + case Instruction::SGET_BYTE: { PREAMBLE(); - DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SGET_CHAR: + } + case Instruction::SGET_CHAR: { PREAMBLE(); - DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SGET_SHORT: + } + case Instruction::SGET_SHORT: { PREAMBLE(); - DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SGET: + } + case Instruction::SGET: { PREAMBLE(); - DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SGET_WIDE: + } + case Instruction::SGET_WIDE: { PREAMBLE(); - DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SGET_OBJECT: + } + case Instruction::SGET_OBJECT: { PREAMBLE(); - DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IPUT_BOOLEAN: + } + case Instruction::IPUT_BOOLEAN: { PREAMBLE(); - DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IPUT_BYTE: + } + case Instruction::IPUT_BYTE: { PREAMBLE(); - DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IPUT_CHAR: + } + case Instruction::IPUT_CHAR: { PREAMBLE(); - DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IPUT_SHORT: + } + case Instruction::IPUT_SHORT: { PREAMBLE(); - DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IPUT: + } + case Instruction::IPUT: { PREAMBLE(); - DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IPUT_WIDE: + } + case Instruction::IPUT_WIDE: { PREAMBLE(); - DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IPUT_OBJECT: + } + case Instruction::IPUT_OBJECT: { PREAMBLE(); - DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IPUT_QUICK: + } + case Instruction::IPUT_QUICK: { PREAMBLE(); - DoIPutQuick<Primitive::kPrimInt>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIPutQuick<Primitive::kPrimInt>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IPUT_WIDE_QUICK: + } + case Instruction::IPUT_WIDE_QUICK: { PREAMBLE(); - DoIPutQuick<Primitive::kPrimLong>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIPutQuick<Primitive::kPrimLong>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::IPUT_OBJECT_QUICK: + } + case Instruction::IPUT_OBJECT_QUICK: { PREAMBLE(); - DoIPutQuick<Primitive::kPrimNot>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIPutQuick<Primitive::kPrimNot>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SPUT_BOOLEAN: + } + case Instruction::SPUT_BOOLEAN: { PREAMBLE(); - DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SPUT_BYTE: + } + case Instruction::SPUT_BYTE: { PREAMBLE(); - DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SPUT_CHAR: + } + case Instruction::SPUT_CHAR: { PREAMBLE(); - DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SPUT_SHORT: + } + case Instruction::SPUT_SHORT: { PREAMBLE(); - DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SPUT: + } + case Instruction::SPUT: { PREAMBLE(); - DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SPUT_WIDE: + } + case Instruction::SPUT_WIDE: { PREAMBLE(); - DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::SPUT_OBJECT: + } + case Instruction::SPUT_OBJECT: { PREAMBLE(); - DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::INVOKE_VIRTUAL: + } + case Instruction::INVOKE_VIRTUAL: { PREAMBLE(); - DoInvoke<kVirtual, false, do_access_check>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvoke<kVirtual, false, do_access_check>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; - case Instruction::INVOKE_VIRTUAL_RANGE: + } + case Instruction::INVOKE_VIRTUAL_RANGE: { PREAMBLE(); - DoInvoke<kVirtual, true, do_access_check>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvoke<kVirtual, true, do_access_check>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; - case Instruction::INVOKE_SUPER: + } + case Instruction::INVOKE_SUPER: { PREAMBLE(); - DoInvoke<kSuper, false, do_access_check>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvoke<kSuper, false, do_access_check>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; - case Instruction::INVOKE_SUPER_RANGE: + } + case Instruction::INVOKE_SUPER_RANGE: { PREAMBLE(); - DoInvoke<kSuper, true, do_access_check>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvoke<kSuper, true, do_access_check>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; - case Instruction::INVOKE_DIRECT: + } + case Instruction::INVOKE_DIRECT: { PREAMBLE(); - DoInvoke<kDirect, false, do_access_check>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvoke<kDirect, false, do_access_check>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; - case Instruction::INVOKE_DIRECT_RANGE: + } + case Instruction::INVOKE_DIRECT_RANGE: { PREAMBLE(); - DoInvoke<kDirect, true, do_access_check>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvoke<kDirect, true, do_access_check>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; - case Instruction::INVOKE_INTERFACE: + } + case Instruction::INVOKE_INTERFACE: { PREAMBLE(); - DoInvoke<kInterface, false, do_access_check>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvoke<kInterface, false, do_access_check>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; - case Instruction::INVOKE_INTERFACE_RANGE: + } + case Instruction::INVOKE_INTERFACE_RANGE: { PREAMBLE(); - DoInvoke<kInterface, true, do_access_check>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvoke<kInterface, true, do_access_check>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; - case Instruction::INVOKE_STATIC: + } + case Instruction::INVOKE_STATIC: { PREAMBLE(); - DoInvoke<kStatic, false, do_access_check>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvoke<kStatic, false, do_access_check>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; - case Instruction::INVOKE_STATIC_RANGE: + } + case Instruction::INVOKE_STATIC_RANGE: { PREAMBLE(); - DoInvoke<kStatic, true, do_access_check>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvoke<kStatic, true, do_access_check>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; - case Instruction::INVOKE_VIRTUAL_QUICK: + } + case Instruction::INVOKE_VIRTUAL_QUICK: { PREAMBLE(); - DoInvokeVirtualQuick<false>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvokeVirtualQuick<false>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; - case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: + } + case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: { PREAMBLE(); - DoInvokeVirtualQuick<true>(self, shadow_frame, inst, &result_register); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx); + bool success = DoInvokeVirtualQuick<true>(self, shadow_frame, inst, &result_register); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx); break; + } case Instruction::NEG_INT: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_12x(), -shadow_frame.GetVReg(inst->VRegB_12x())); @@ -2341,20 +2402,22 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte shadow_frame.GetVReg(inst->VRegC_23x())); inst = inst->Next_2xx(); break; - case Instruction::DIV_INT: + case Instruction::DIV_INT: { PREAMBLE(); - DoIntDivide(shadow_frame, inst->VRegA_23x(), - shadow_frame.GetVReg(inst->VRegB_23x()), - shadow_frame.GetVReg(inst->VRegC_23x())); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIntDivide(shadow_frame, inst->VRegA_23x(), + shadow_frame.GetVReg(inst->VRegB_23x()), + shadow_frame.GetVReg(inst->VRegC_23x())); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::REM_INT: + } + case Instruction::REM_INT: { PREAMBLE(); - DoIntRemainder(shadow_frame, inst->VRegA_23x(), - shadow_frame.GetVReg(inst->VRegB_23x()), - shadow_frame.GetVReg(inst->VRegC_23x())); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIntRemainder(shadow_frame, inst->VRegA_23x(), + shadow_frame.GetVReg(inst->VRegB_23x()), + shadow_frame.GetVReg(inst->VRegC_23x())); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; + } case Instruction::SHL_INT: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_23x(), @@ -2423,14 +2486,14 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte DoLongDivide(shadow_frame, inst->VRegA_23x(), shadow_frame.GetVRegLong(inst->VRegB_23x()), shadow_frame.GetVRegLong(inst->VRegC_23x())); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx); break; case Instruction::REM_LONG: PREAMBLE(); DoLongRemainder(shadow_frame, inst->VRegA_23x(), shadow_frame.GetVRegLong(inst->VRegB_23x()), shadow_frame.GetVRegLong(inst->VRegC_23x())); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx); break; case Instruction::AND_LONG: PREAMBLE(); @@ -2546,7 +2609,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte break; case Instruction::ADD_INT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVReg(vregA, shadow_frame.GetVReg(vregA) + shadow_frame.GetVReg(inst->VRegB_12x())); @@ -2555,7 +2618,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::SUB_INT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVReg(vregA, shadow_frame.GetVReg(vregA) - shadow_frame.GetVReg(inst->VRegB_12x())); @@ -2564,7 +2627,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::MUL_INT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVReg(vregA, shadow_frame.GetVReg(vregA) * shadow_frame.GetVReg(inst->VRegB_12x())); @@ -2573,23 +2636,23 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::DIV_INT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); - DoIntDivide(shadow_frame, vregA, shadow_frame.GetVReg(vregA), - shadow_frame.GetVReg(inst->VRegB_12x())); - inst = inst->Next_1xx(); + uint4_t vregA = inst->VRegA_12x(); + bool success = DoIntDivide(shadow_frame, vregA, shadow_frame.GetVReg(vregA), + shadow_frame.GetVReg(inst->VRegB_12x())); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_1xx); break; } case Instruction::REM_INT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); - DoIntRemainder(shadow_frame, vregA, shadow_frame.GetVReg(vregA), - shadow_frame.GetVReg(inst->VRegB_12x())); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_1xx); + uint4_t vregA = inst->VRegA_12x(); + bool success = DoIntRemainder(shadow_frame, vregA, shadow_frame.GetVReg(vregA), + shadow_frame.GetVReg(inst->VRegB_12x())); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_1xx); break; } case Instruction::SHL_INT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVReg(vregA, shadow_frame.GetVReg(vregA) << (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x1f)); @@ -2598,7 +2661,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::SHR_INT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVReg(vregA, shadow_frame.GetVReg(vregA) >> (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x1f)); @@ -2607,7 +2670,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::USHR_INT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVReg(vregA, static_cast<uint32_t>(shadow_frame.GetVReg(vregA)) >> (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x1f)); @@ -2616,7 +2679,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::AND_INT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVReg(vregA, shadow_frame.GetVReg(vregA) & shadow_frame.GetVReg(inst->VRegB_12x())); @@ -2625,7 +2688,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::OR_INT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVReg(vregA, shadow_frame.GetVReg(vregA) | shadow_frame.GetVReg(inst->VRegB_12x())); @@ -2634,7 +2697,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::XOR_INT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVReg(vregA, shadow_frame.GetVReg(vregA) ^ shadow_frame.GetVReg(inst->VRegB_12x())); @@ -2643,7 +2706,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::ADD_LONG_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegLong(vregA, shadow_frame.GetVRegLong(vregA) + shadow_frame.GetVRegLong(inst->VRegB_12x())); @@ -2652,7 +2715,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::SUB_LONG_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegLong(vregA, shadow_frame.GetVRegLong(vregA) - shadow_frame.GetVRegLong(inst->VRegB_12x())); @@ -2661,7 +2724,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::MUL_LONG_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegLong(vregA, shadow_frame.GetVRegLong(vregA) * shadow_frame.GetVRegLong(inst->VRegB_12x())); @@ -2670,23 +2733,23 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::DIV_LONG_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); DoLongDivide(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA), shadow_frame.GetVRegLong(inst->VRegB_12x())); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_1xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx); break; } case Instruction::REM_LONG_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); DoLongRemainder(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA), shadow_frame.GetVRegLong(inst->VRegB_12x())); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_1xx); + POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx); break; } case Instruction::AND_LONG_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegLong(vregA, shadow_frame.GetVRegLong(vregA) & shadow_frame.GetVRegLong(inst->VRegB_12x())); @@ -2695,7 +2758,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::OR_LONG_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegLong(vregA, shadow_frame.GetVRegLong(vregA) | shadow_frame.GetVRegLong(inst->VRegB_12x())); @@ -2704,7 +2767,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::XOR_LONG_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegLong(vregA, shadow_frame.GetVRegLong(vregA) ^ shadow_frame.GetVRegLong(inst->VRegB_12x())); @@ -2713,7 +2776,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::SHL_LONG_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegLong(vregA, shadow_frame.GetVRegLong(vregA) << (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x3f)); @@ -2722,7 +2785,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::SHR_LONG_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegLong(vregA, shadow_frame.GetVRegLong(vregA) >> (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x3f)); @@ -2731,7 +2794,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::USHR_LONG_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegLong(vregA, static_cast<uint64_t>(shadow_frame.GetVRegLong(vregA)) >> (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x3f)); @@ -2740,7 +2803,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::ADD_FLOAT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegFloat(vregA, shadow_frame.GetVRegFloat(vregA) + shadow_frame.GetVRegFloat(inst->VRegB_12x())); @@ -2749,7 +2812,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::SUB_FLOAT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegFloat(vregA, shadow_frame.GetVRegFloat(vregA) - shadow_frame.GetVRegFloat(inst->VRegB_12x())); @@ -2758,7 +2821,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::MUL_FLOAT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegFloat(vregA, shadow_frame.GetVRegFloat(vregA) * shadow_frame.GetVRegFloat(inst->VRegB_12x())); @@ -2767,7 +2830,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::DIV_FLOAT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegFloat(vregA, shadow_frame.GetVRegFloat(vregA) / shadow_frame.GetVRegFloat(inst->VRegB_12x())); @@ -2776,7 +2839,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::REM_FLOAT_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegFloat(vregA, fmodf(shadow_frame.GetVRegFloat(vregA), shadow_frame.GetVRegFloat(inst->VRegB_12x()))); @@ -2785,7 +2848,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::ADD_DOUBLE_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegDouble(vregA, shadow_frame.GetVRegDouble(vregA) + shadow_frame.GetVRegDouble(inst->VRegB_12x())); @@ -2794,7 +2857,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::SUB_DOUBLE_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegDouble(vregA, shadow_frame.GetVRegDouble(vregA) - shadow_frame.GetVRegDouble(inst->VRegB_12x())); @@ -2803,7 +2866,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::MUL_DOUBLE_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegDouble(vregA, shadow_frame.GetVRegDouble(vregA) * shadow_frame.GetVRegDouble(inst->VRegB_12x())); @@ -2812,7 +2875,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::DIV_DOUBLE_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegDouble(vregA, shadow_frame.GetVRegDouble(vregA) / shadow_frame.GetVRegDouble(inst->VRegB_12x())); @@ -2821,7 +2884,7 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } case Instruction::REM_DOUBLE_2ADDR: { PREAMBLE(); - uint32_t vregA = inst->VRegA_12x(); + uint4_t vregA = inst->VRegA_12x(); shadow_frame.SetVRegDouble(vregA, fmod(shadow_frame.GetVRegDouble(vregA), shadow_frame.GetVRegDouble(inst->VRegB_12x()))); @@ -2849,18 +2912,20 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte inst->VRegC_22s()); inst = inst->Next_2xx(); break; - case Instruction::DIV_INT_LIT16: + case Instruction::DIV_INT_LIT16: { PREAMBLE(); - DoIntDivide(shadow_frame, inst->VRegA_22s(), - shadow_frame.GetVReg(inst->VRegB_22s()), inst->VRegC_22s()); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIntDivide(shadow_frame, inst->VRegA_22s(), + shadow_frame.GetVReg(inst->VRegB_22s()), inst->VRegC_22s()); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::REM_INT_LIT16: + } + case Instruction::REM_INT_LIT16: { PREAMBLE(); - DoIntRemainder(shadow_frame, inst->VRegA_22s(), - shadow_frame.GetVReg(inst->VRegB_22s()), inst->VRegC_22s()); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIntRemainder(shadow_frame, inst->VRegA_22s(), + shadow_frame.GetVReg(inst->VRegB_22s()), inst->VRegC_22s()); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; + } case Instruction::AND_INT_LIT16: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_22s(), @@ -2903,18 +2968,20 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte inst->VRegC_22b()); inst = inst->Next_2xx(); break; - case Instruction::DIV_INT_LIT8: + case Instruction::DIV_INT_LIT8: { PREAMBLE(); - DoIntDivide(shadow_frame, inst->VRegA_22b(), - shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIntDivide(shadow_frame, inst->VRegA_22b(), + shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; - case Instruction::REM_INT_LIT8: + } + case Instruction::REM_INT_LIT8: { PREAMBLE(); - DoIntRemainder(shadow_frame, inst->VRegA_22b(), - shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()); - POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx); + bool success = DoIntRemainder(shadow_frame, inst->VRegA_22b(), + shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()); + POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx); break; + } case Instruction::AND_INT_LIT8: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_22b(), diff --git a/runtime/mirror/abstract_method-inl.h b/runtime/mirror/abstract_method-inl.h index 2df1367637..d235e3eed8 100644 --- a/runtime/mirror/abstract_method-inl.h +++ b/runtime/mirror/abstract_method-inl.h @@ -20,9 +20,9 @@ #include "abstract_method.h" #include "dex_file.h" +#include "entrypoints/entrypoint_utils.h" #include "object_array.h" #include "runtime.h" -#include "runtime_support.h" namespace art { namespace mirror { diff --git a/runtime/mirror/abstract_method.cc b/runtime/mirror/abstract_method.cc index 58ef5f7bc8..4d7f99e076 100644 --- a/runtime/mirror/abstract_method.cc +++ b/runtime/mirror/abstract_method.cc @@ -20,6 +20,7 @@ #include "base/stringpiece.h" #include "class-inl.h" #include "dex_file-inl.h" +#include "dex_instruction.h" #include "gc/accounting/card_table-inl.h" #include "interpreter/interpreter.h" #include "jni_internal.h" @@ -225,28 +226,37 @@ uintptr_t AbstractMethod::ToNativePc(const uint32_t dex_pc) const { return 0; } -uint32_t AbstractMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc) const { +uint32_t AbstractMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc, + bool* has_no_move_exception) const { MethodHelper mh(this); const DexFile::CodeItem* code_item = mh.GetCodeItem(); - // Iterate over the catch handlers associated with dex_pc + // Default to handler not found. + uint32_t found_dex_pc = DexFile::kDexNoIndex; + // Iterate over the catch handlers associated with dex_pc. for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) { uint16_t iter_type_idx = it.GetHandlerTypeIndex(); // Catch all case if (iter_type_idx == DexFile::kDexNoIndex16) { - return it.GetHandlerAddress(); + found_dex_pc = it.GetHandlerAddress(); + break; } // Does this catch exception type apply? Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx); if (iter_exception_type == NULL) { // The verifier should take care of resolving all exception classes early LOG(WARNING) << "Unresolved exception class when finding catch block: " - << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx); + << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx); } else if (iter_exception_type->IsAssignableFrom(exception_type)) { - return it.GetHandlerAddress(); + found_dex_pc = it.GetHandlerAddress(); + break; } } - // Handler not found - return DexFile::kDexNoIndex; + if (found_dex_pc != DexFile::kDexNoIndex) { + const Instruction* first_catch_instr = + Instruction::At(&mh.GetCodeItem()->insns_[found_dex_pc]); + *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION); + } + return found_dex_pc; } void AbstractMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, diff --git a/runtime/mirror/abstract_method.h b/runtime/mirror/abstract_method.h index bbebecebb4..2e6e262451 100644 --- a/runtime/mirror/abstract_method.h +++ b/runtime/mirror/abstract_method.h @@ -407,8 +407,10 @@ class MANAGED AbstractMethod : public Object { uintptr_t ToFirstNativeSafepointPc(const uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Find the catch block for the given exception type and dex_pc - uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc) const + // Find the catch block for the given exception type and dex_pc. When a catch block is found, + // indicates whether the found catch block is responsible for clearing the exception or whether + // a move-exception instruction is present. + uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc, bool* has_no_move_exception) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static void SetClasses(Class* java_lang_reflect_Constructor, Class* java_lang_reflect_Method); diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h index b195a87fc0..db6132df59 100644 --- a/runtime/mirror/array.h +++ b/runtime/mirror/array.h @@ -72,7 +72,7 @@ class MANAGED Array : public Object { bool IsValidIndex(int32_t index) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (UNLIKELY(index < 0 || index >= GetLength())) { + if (UNLIKELY(static_cast<uint32_t>(index) >= static_cast<uint32_t>(GetLength()))) { ThrowArrayIndexOutOfBoundsException(index); return false; } diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 53a1df95a6..540ff9f68e 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -26,6 +26,7 @@ #include "class_linker-inl.h" #include "common_test.h" #include "dex_file.h" +#include "entrypoints/entrypoint_utils.h" #include "field-inl.h" #include "gc/accounting/card_table-inl.h" #include "gc/heap.h" @@ -33,7 +34,6 @@ #include "abstract_method-inl.h" #include "object-inl.h" #include "object_array-inl.h" -#include "runtime_support.h" #include "sirt_ref.h" #include "UniquePtr.h" diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index 60624c2704..e3ec3bcbb0 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -20,6 +20,9 @@ #include "class_linker.h" #include "common_throws.h" #include "debugger.h" +#include "gc/space/dlmalloc_space.h" +#include "gc/space/large_object_space.h" +#include "gc/space/space-inl.h" #include "hprof/hprof.h" #include "jni_internal.h" #include "mirror/class.h" @@ -234,6 +237,69 @@ static jlong VMDebug_countInstancesOfClass(JNIEnv* env, jclass, jclass javaClass return count; } +// 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 +// as PSS, private/shared dirty/shared data are available via +// /proc/<pid>/smaps. +static void VMDebug_getHeapSpaceStats(JNIEnv* env, jclass, jlongArray data) { + jlong* arr = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(data, 0)); + if (arr == NULL || env->GetArrayLength(data) < 9) { + return; + } + + size_t allocSize = 0; + size_t allocUsed = 0; + size_t zygoteSize = 0; + size_t zygoteUsed = 0; + size_t largeObjectsSize = 0; + size_t largeObjectsUsed = 0; + + gc::Heap* heap = Runtime::Current()->GetHeap(); + const std::vector<gc::space::ContinuousSpace*>& continuous_spaces = heap->GetContinuousSpaces(); + const std::vector<gc::space::DiscontinuousSpace*>& discontinuous_spaces = heap->GetDiscontinuousSpaces(); + typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It; + for (It it = continuous_spaces.begin(), end = continuous_spaces.end(); it != end; ++it) { + gc::space::ContinuousSpace* space = *it; + if (space->IsImageSpace()) { + // Currently don't include the image space. + } else if (space->IsZygoteSpace()) { + gc::space::DlMallocSpace* dlmalloc_space = space->AsDlMallocSpace(); + zygoteSize += dlmalloc_space->GetFootprint(); + zygoteUsed += dlmalloc_space->GetBytesAllocated(); + } else { + // This is the alloc space. + gc::space::DlMallocSpace* dlmalloc_space = space->AsDlMallocSpace(); + allocSize += dlmalloc_space->GetFootprint(); + allocUsed += dlmalloc_space->GetBytesAllocated(); + } + } + typedef std::vector<gc::space::DiscontinuousSpace*>::const_iterator It2; + for (It2 it = discontinuous_spaces.begin(), end = discontinuous_spaces.end(); it != end; ++it) { + gc::space::DiscontinuousSpace* space = *it; + if (space->IsLargeObjectSpace()) { + largeObjectsSize += space->AsLargeObjectSpace()->GetBytesAllocated(); + largeObjectsUsed += largeObjectsSize; + } + } + + size_t allocFree = allocSize - allocUsed; + size_t zygoteFree = zygoteSize - zygoteUsed; + size_t largeObjectsFree = largeObjectsSize - largeObjectsUsed; + + int j = 0; + arr[j++] = allocSize; + arr[j++] = allocUsed; + arr[j++] = allocFree; + arr[j++] = zygoteSize; + arr[j++] = zygoteUsed; + arr[j++] = zygoteFree; + arr[j++] = largeObjectsSize; + arr[j++] = largeObjectsUsed; + arr[j++] = largeObjectsFree; + env->ReleasePrimitiveArrayCritical(data, arr, 0); +} + static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"), NATIVE_METHOD(VMDebug, crash, "()V"), @@ -241,6 +307,7 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMDebug, dumpHprofDataDdms, "()V"), NATIVE_METHOD(VMDebug, dumpReferenceTables, "()V"), NATIVE_METHOD(VMDebug, getAllocCount, "(I)I"), + NATIVE_METHOD(VMDebug, getHeapSpaceStats, "([J)V"), NATIVE_METHOD(VMDebug, getInstructionCount, "([I)V"), NATIVE_METHOD(VMDebug, getLoadedClassCount, "()I"), NATIVE_METHOD(VMDebug, getVmFeatureList, "()[Ljava/lang/String;"), diff --git a/runtime/oat_test.cc b/runtime/oat_test.cc index ebb228e111..5d0dca9e4c 100644 --- a/runtime/oat_test.cc +++ b/runtime/oat_test.cc @@ -74,10 +74,11 @@ TEST_F(OatTest, WriteRead) { #else CompilerBackend compiler_backend = kQuick; #endif - compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, NULL, 2, true)); + InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86; + compiler_driver_.reset(new CompilerDriver(compiler_backend, insn_set, false, NULL, 2, true)); jobject class_loader = NULL; if (compile) { - TimingLogger timings("OatTest::WriteRead", false); + base::TimingLogger timings("OatTest::WriteRead", false, false); compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings); } @@ -96,7 +97,7 @@ TEST_F(OatTest, WriteRead) { ASSERT_TRUE(success); if (compile) { // OatWriter strips the code, regenerate to compare - TimingLogger timings("CommonTest::WriteRead", false); + base::TimingLogger timings("CommonTest::WriteRead", false, false); compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings); } UniquePtr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), NULL, false)); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 0c13ad23ed..485c636b1c 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -28,11 +28,11 @@ #include <limits> #include <vector> +#include "arch/arm/registers_arm.h" +#include "arch/mips/registers_mips.h" +#include "arch/x86/registers_x86.h" #include "atomic.h" #include "class_linker.h" -#include "constants_arm.h" -#include "constants_mips.h" -#include "constants_x86.h" #include "debugger.h" #include "gc/accounting/card_table-inl.h" #include "gc/heap.h" @@ -134,10 +134,10 @@ Runtime::~Runtime() { delete java_vm_; Thread::Shutdown(); QuasiAtomic::Shutdown(); + verifier::MethodVerifier::Shutdown(); // TODO: acquire a static mutex on Runtime to avoid racing. CHECK(instance_ == NULL || instance_ == this); instance_ = NULL; - verifier::MethodVerifier::Shutdown(); } struct AbortState { diff --git a/runtime/runtime_support_llvm.cc b/runtime/runtime_support_llvm.cc deleted file mode 100644 index 9d83f9e49e..0000000000 --- a/runtime/runtime_support_llvm.cc +++ /dev/null @@ -1,925 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "runtime_support_llvm.h" - -#include "ScopedLocalRef.h" -#include "asm_support.h" -#include "class_linker.h" -#include "class_linker-inl.h" -#include "dex_file-inl.h" -#include "dex_instruction.h" -#include "mirror/abstract_method-inl.h" -#include "mirror/class-inl.h" -#include "mirror/dex_cache-inl.h" -#include "mirror/field-inl.h" -#include "mirror/object.h" -#include "mirror/object-inl.h" -#include "mirror/object_array-inl.h" -#include "nth_caller_visitor.h" -#include "object_utils.h" -#include "reflection.h" -#include "runtime_support.h" -#include "runtime_support_llvm_func_list.h" -#include "scoped_thread_state_change.h" -#include "thread.h" -#include "thread_list.h" -#include "verifier/dex_gc_map.h" -#include "verifier/method_verifier.h" -#include "well_known_classes.h" - -#include <algorithm> -#include <math.h> -#include <stdarg.h> -#include <stdint.h> -#include <stdlib.h> - -namespace art { - -using ::art::mirror::AbstractMethod; - -class ShadowFrameCopyVisitor : public StackVisitor { - public: - explicit ShadowFrameCopyVisitor(Thread* self) : StackVisitor(self, NULL), prev_frame_(NULL), - top_frame_(NULL) {} - - bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (IsShadowFrame()) { - ShadowFrame* cur_frame = GetCurrentShadowFrame(); - size_t num_regs = cur_frame->NumberOfVRegs(); - AbstractMethod* method = cur_frame->GetMethod(); - uint32_t dex_pc = cur_frame->GetDexPC(); - ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, method, dex_pc); - - const uint8_t* gc_map = method->GetNativeGcMap(); - uint32_t gc_map_length = static_cast<uint32_t>((gc_map[0] << 24) | - (gc_map[1] << 16) | - (gc_map[2] << 8) | - (gc_map[3] << 0)); - verifier::DexPcToReferenceMap dex_gc_map(gc_map + 4, gc_map_length); - const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc); - for (size_t reg = 0; reg < num_regs; ++reg) { - if (TestBitmap(reg, reg_bitmap)) { - new_frame->SetVRegReference(reg, cur_frame->GetVRegReference(reg)); - } else { - new_frame->SetVReg(reg, cur_frame->GetVReg(reg)); - } - } - - if (prev_frame_ != NULL) { - prev_frame_->SetLink(new_frame); - } else { - top_frame_ = new_frame; - } - prev_frame_ = new_frame; - } - return true; - } - - ShadowFrame* GetShadowFrameCopy() { - return top_frame_; - } - - private: - static bool TestBitmap(int reg, const uint8_t* reg_vector) { - return ((reg_vector[reg / 8] >> (reg % 8)) & 0x01) != 0; - } - - ShadowFrame* prev_frame_; - ShadowFrame* top_frame_; -}; - -} // namespace art - -extern "C" { -using ::art::CatchHandlerIterator; -using ::art::DexFile; -using ::art::FindFieldFast; -using ::art::FindMethodFast; -using ::art::InstanceObjectRead; -using ::art::InstanceObjectWrite; -using ::art::InstancePrimitiveRead; -using ::art::InstancePrimitiveWrite; -using ::art::Instruction; -using ::art::InvokeType; -using ::art::JNIEnvExt; -using ::art::JValue; -using ::art::Locks; -using ::art::MethodHelper; -using ::art::PrettyClass; -using ::art::PrettyMethod; -using ::art::Primitive; -using ::art::ResolveStringFromCode; -using ::art::Runtime; -using ::art::ScopedJniEnvLocalRefState; -using ::art::ScopedObjectAccessUnchecked; -using ::art::ShadowFrame; -using ::art::ShadowFrameCopyVisitor; -using ::art::StaticObjectRead; -using ::art::StaticObjectWrite; -using ::art::StaticPrimitiveRead; -using ::art::StaticPrimitiveWrite; -using ::art::Thread; -using ::art::Thread; -using ::art::ThrowArithmeticExceptionDivideByZero; -using ::art::ThrowArrayIndexOutOfBoundsException; -using ::art::ThrowArrayStoreException; -using ::art::ThrowClassCastException; -using ::art::ThrowLocation; -using ::art::ThrowNoSuchMethodError; -using ::art::ThrowNullPointerException; -using ::art::ThrowNullPointerExceptionFromDexPC; -using ::art::ThrowStackOverflowError; -using ::art::kDirect; -using ::art::kInterface; -using ::art::kNative; -using ::art::kStatic; -using ::art::kSuper; -using ::art::kVirtual; -using ::art::mirror::AbstractMethod; -using ::art::mirror::Array; -using ::art::mirror::Class; -using ::art::mirror::Field; -using ::art::mirror::Object; -using ::art::mirror::Throwable; - -//---------------------------------------------------------------------------- -// Thread -//---------------------------------------------------------------------------- - -Thread* art_portable_get_current_thread_from_code() { -#if defined(__arm__) || defined(__i386__) - LOG(FATAL) << "UNREACHABLE"; -#endif - return Thread::Current(); -} - -void* art_portable_set_current_thread_from_code(void* thread_object_addr) { - // Hijacked to set r9 on ARM. - LOG(FATAL) << "UNREACHABLE"; - return NULL; -} - -void art_portable_lock_object_from_code(Object* obj, Thread* thread) - EXCLUSIVE_LOCK_FUNCTION(monitor_lock_) { - DCHECK(obj != NULL); // Assumed to have been checked before entry - obj->MonitorEnter(thread); // May block - DCHECK(thread->HoldsLock(obj)); - // Only possible exception is NPE and is handled before entry - DCHECK(!thread->IsExceptionPending()); -} - -void art_portable_unlock_object_from_code(Object* obj, Thread* thread) - UNLOCK_FUNCTION(monitor_lock_) { - DCHECK(obj != NULL); // Assumed to have been checked before entry - // MonitorExit may throw exception - obj->MonitorExit(thread); -} - -void art_portable_test_suspend_from_code(Thread* self) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CheckSuspend(self); - if (Runtime::Current()->GetInstrumentation()->ShouldPortableCodeDeoptimize()) { - // Save out the shadow frame to the heap - ShadowFrameCopyVisitor visitor(self); - visitor.WalkStack(true); - self->SetDeoptimizationShadowFrame(visitor.GetShadowFrameCopy()); - self->SetDeoptimizationReturnValue(JValue()); - self->SetException(ThrowLocation(), reinterpret_cast<Throwable*>(-1)); - } -} - -ShadowFrame* art_portable_push_shadow_frame_from_code(Thread* thread, - ShadowFrame* new_shadow_frame, - AbstractMethod* method, - uint32_t num_vregs) { - ShadowFrame* old_frame = thread->PushShadowFrame(new_shadow_frame); - new_shadow_frame->SetMethod(method); - new_shadow_frame->SetNumberOfVRegs(num_vregs); - return old_frame; -} - -void art_portable_pop_shadow_frame_from_code(void*) { - LOG(FATAL) << "Implemented by IRBuilder."; -} - -void art_portable_mark_gc_card_from_code(void *, void*) { - LOG(FATAL) << "Implemented by IRBuilder."; -} - -//---------------------------------------------------------------------------- -// Exception -//---------------------------------------------------------------------------- - -bool art_portable_is_exception_pending_from_code() { - LOG(FATAL) << "Implemented by IRBuilder."; - return false; -} - -void art_portable_throw_div_zero_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - ThrowArithmeticExceptionDivideByZero(); -} - -void art_portable_throw_array_bounds_from_code(int32_t index, int32_t length) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - ThrowArrayIndexOutOfBoundsException(index, length); -} - -void art_portable_throw_no_such_method_from_code(int32_t method_idx) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - ThrowNoSuchMethodError(method_idx); -} - -void art_portable_throw_null_pointer_exception_from_code(uint32_t dex_pc) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - // TODO: remove dex_pc argument from caller. - UNUSED(dex_pc); - Thread* self = Thread::Current(); - ThrowLocation throw_location = self->GetCurrentLocationForThrow(); - ThrowNullPointerExceptionFromDexPC(throw_location); -} - -void art_portable_throw_stack_overflow_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - ThrowStackOverflowError(Thread::Current()); -} - -void art_portable_throw_exception_from_code(Throwable* exception) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Thread* self = Thread::Current(); - ThrowLocation throw_location = self->GetCurrentLocationForThrow(); - if (exception == NULL) { - ThrowNullPointerException(NULL, "throw with null exception"); - } else { - self->SetException(throw_location, exception); - } -} - -void* art_portable_get_and_clear_exception(Thread* self) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(self->IsExceptionPending()); - // TODO: make this inline. - Throwable* exception = self->GetException(NULL); - self->ClearException(); - return exception; -} - -int32_t art_portable_find_catch_block_from_code(AbstractMethod* current_method, - uint32_t ti_offset) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Thread* self = Thread::Current(); // TODO: make an argument. - ThrowLocation throw_location; - Throwable* exception = self->GetException(&throw_location); - // Check for special deoptimization exception. - if (UNLIKELY(reinterpret_cast<int32_t>(exception) == -1)) { - return -1; - } - Class* exception_type = exception->GetClass(); - MethodHelper mh(current_method); - const DexFile::CodeItem* code_item = mh.GetCodeItem(); - DCHECK_LT(ti_offset, code_item->tries_size_); - const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item, ti_offset); - - int iter_index = 0; - int result = -1; - uint32_t catch_dex_pc = -1; - // Iterate over the catch handlers associated with dex_pc - for (CatchHandlerIterator it(*code_item, *try_item); it.HasNext(); it.Next()) { - uint16_t iter_type_idx = it.GetHandlerTypeIndex(); - // Catch all case - if (iter_type_idx == DexFile::kDexNoIndex16) { - catch_dex_pc = it.GetHandlerAddress(); - result = iter_index; - break; - } - // Does this catch exception type apply? - Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx); - if (UNLIKELY(iter_exception_type == NULL)) { - // TODO: check, the verifier (class linker?) should take care of resolving all exception - // classes early. - LOG(WARNING) << "Unresolved exception class when finding catch block: " - << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx); - } else if (iter_exception_type->IsAssignableFrom(exception_type)) { - catch_dex_pc = it.GetHandlerAddress(); - result = iter_index; - break; - } - ++iter_index; - } - if (result != -1) { - // Handler found. - Runtime::Current()->GetInstrumentation()->ExceptionCaughtEvent(self, - throw_location, - current_method, - catch_dex_pc, - exception); - } - return result; -} - - -//---------------------------------------------------------------------------- -// Object Space -//---------------------------------------------------------------------------- - -Object* art_portable_alloc_object_from_code(uint32_t type_idx, AbstractMethod* referrer, Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return AllocObjectFromCode(type_idx, referrer, thread, false); -} - -Object* art_portable_alloc_object_from_code_with_access_check(uint32_t type_idx, - AbstractMethod* referrer, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return AllocObjectFromCode(type_idx, referrer, thread, true); -} - -Object* art_portable_alloc_array_from_code(uint32_t type_idx, - AbstractMethod* referrer, - uint32_t length, - Thread* self) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return AllocArrayFromCode(type_idx, referrer, length, self, false); -} - -Object* art_portable_alloc_array_from_code_with_access_check(uint32_t type_idx, - AbstractMethod* referrer, - uint32_t length, - Thread* self) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return AllocArrayFromCode(type_idx, referrer, length, self, true); -} - -Object* art_portable_check_and_alloc_array_from_code(uint32_t type_idx, - AbstractMethod* referrer, - uint32_t length, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, false); -} - -Object* art_portable_check_and_alloc_array_from_code_with_access_check(uint32_t type_idx, - AbstractMethod* referrer, - uint32_t length, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, true); -} - -static AbstractMethod* FindMethodHelper(uint32_t method_idx, - Object* this_object, - AbstractMethod* caller_method, - bool access_check, - InvokeType type, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - AbstractMethod* method = FindMethodFast(method_idx, - this_object, - caller_method, - access_check, - type); - if (UNLIKELY(method == NULL)) { - method = FindMethodFromCode(method_idx, this_object, caller_method, - thread, access_check, type); - if (UNLIKELY(method == NULL)) { - CHECK(thread->IsExceptionPending()); - return 0; // failure - } - } - DCHECK(!thread->IsExceptionPending()); - const void* code = method->GetEntryPointFromCompiledCode(); - - // When we return, the caller will branch to this address, so it had better not be 0! - if (UNLIKELY(code == NULL)) { - MethodHelper mh(method); - LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method) - << " location: " << mh.GetDexFile().GetLocation(); - } - return method; -} - -Object* art_portable_find_static_method_from_code_with_access_check(uint32_t method_idx, - Object* this_object, - AbstractMethod* referrer, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return FindMethodHelper(method_idx, this_object, referrer, true, kStatic, thread); -} - -Object* art_portable_find_direct_method_from_code_with_access_check(uint32_t method_idx, - Object* this_object, - AbstractMethod* referrer, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return FindMethodHelper(method_idx, this_object, referrer, true, kDirect, thread); -} - -Object* art_portable_find_virtual_method_from_code_with_access_check(uint32_t method_idx, - Object* this_object, - AbstractMethod* referrer, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return FindMethodHelper(method_idx, this_object, referrer, true, kVirtual, thread); -} - -Object* art_portable_find_super_method_from_code_with_access_check(uint32_t method_idx, - Object* this_object, - AbstractMethod* referrer, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return FindMethodHelper(method_idx, this_object, referrer, true, kSuper, thread); -} - -Object* art_portable_find_interface_method_from_code_with_access_check(uint32_t method_idx, - Object* this_object, - AbstractMethod* referrer, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return FindMethodHelper(method_idx, this_object, referrer, true, kInterface, thread); -} - -Object* art_portable_find_interface_method_from_code(uint32_t method_idx, - Object* this_object, - AbstractMethod* referrer, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return FindMethodHelper(method_idx, this_object, referrer, false, kInterface, thread); -} - -Object* art_portable_initialize_static_storage_from_code(uint32_t type_idx, - AbstractMethod* referrer, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return ResolveVerifyAndClinit(type_idx, referrer, thread, true, false); -} - -Object* art_portable_initialize_type_from_code(uint32_t type_idx, - AbstractMethod* referrer, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return ResolveVerifyAndClinit(type_idx, referrer, thread, false, false); -} - -Object* art_portable_initialize_type_and_verify_access_from_code(uint32_t type_idx, - AbstractMethod* referrer, - Thread* thread) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - // Called when caller isn't guaranteed to have access to a type and the dex cache may be - // unpopulated - return ResolveVerifyAndClinit(type_idx, referrer, thread, false, true); -} - -Object* art_portable_resolve_string_from_code(AbstractMethod* referrer, uint32_t string_idx) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return ResolveStringFromCode(referrer, string_idx); -} - -int32_t art_portable_set32_static_from_code(uint32_t field_idx, - AbstractMethod* referrer, - int32_t new_value) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, - referrer, - StaticPrimitiveWrite, - sizeof(uint32_t)); - if (LIKELY(field != NULL)) { - field->Set32(field->GetDeclaringClass(), new_value); - return 0; - } - field = FindFieldFromCode(field_idx, - referrer, - Thread::Current(), - StaticPrimitiveWrite, - sizeof(uint32_t), - true); - if (LIKELY(field != NULL)) { - field->Set32(field->GetDeclaringClass(), new_value); - return 0; - } - return -1; -} - -int32_t art_portable_set64_static_from_code(uint32_t field_idx, - AbstractMethod* referrer, - int64_t new_value) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint64_t)); - if (LIKELY(field != NULL)) { - field->Set64(field->GetDeclaringClass(), new_value); - return 0; - } - field = FindFieldFromCode(field_idx, - referrer, - Thread::Current(), - StaticPrimitiveWrite, - sizeof(uint64_t), - true); - if (LIKELY(field != NULL)) { - field->Set64(field->GetDeclaringClass(), new_value); - return 0; - } - return -1; -} - -int32_t art_portable_set_obj_static_from_code(uint32_t field_idx, - AbstractMethod* referrer, - Object* new_value) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, referrer, StaticObjectWrite, sizeof(Object*)); - if (LIKELY(field != NULL)) { - field->SetObj(field->GetDeclaringClass(), new_value); - return 0; - } - field = FindFieldFromCode(field_idx, referrer, Thread::Current(), - StaticObjectWrite, sizeof(Object*), true); - if (LIKELY(field != NULL)) { - field->SetObj(field->GetDeclaringClass(), new_value); - return 0; - } - return -1; -} - -int32_t art_portable_get32_static_from_code(uint32_t field_idx, AbstractMethod* referrer) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint32_t)); - if (LIKELY(field != NULL)) { - return field->Get32(field->GetDeclaringClass()); - } - field = FindFieldFromCode(field_idx, referrer, Thread::Current(), - StaticPrimitiveRead, sizeof(uint32_t), true); - if (LIKELY(field != NULL)) { - return field->Get32(field->GetDeclaringClass()); - } - return 0; -} - -int64_t art_portable_get64_static_from_code(uint32_t field_idx, AbstractMethod* referrer) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint64_t)); - if (LIKELY(field != NULL)) { - return field->Get64(field->GetDeclaringClass()); - } - field = FindFieldFromCode(field_idx, referrer, Thread::Current(), - StaticPrimitiveRead, sizeof(uint64_t), true); - if (LIKELY(field != NULL)) { - return field->Get64(field->GetDeclaringClass()); - } - return 0; -} - -Object* art_portable_get_obj_static_from_code(uint32_t field_idx, AbstractMethod* referrer) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, referrer, StaticObjectRead, sizeof(Object*)); - if (LIKELY(field != NULL)) { - return field->GetObj(field->GetDeclaringClass()); - } - field = FindFieldFromCode(field_idx, referrer, Thread::Current(), - StaticObjectRead, sizeof(Object*), true); - if (LIKELY(field != NULL)) { - return field->GetObj(field->GetDeclaringClass()); - } - return 0; -} - -int32_t art_portable_set32_instance_from_code(uint32_t field_idx, AbstractMethod* referrer, - Object* obj, uint32_t new_value) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint32_t)); - if (LIKELY(field != NULL)) { - field->Set32(obj, new_value); - return 0; - } - field = FindFieldFromCode(field_idx, referrer, Thread::Current(), - InstancePrimitiveWrite, sizeof(uint32_t), true); - if (LIKELY(field != NULL)) { - field->Set32(obj, new_value); - return 0; - } - return -1; -} - -int32_t art_portable_set64_instance_from_code(uint32_t field_idx, AbstractMethod* referrer, - Object* obj, int64_t new_value) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint64_t)); - if (LIKELY(field != NULL)) { - field->Set64(obj, new_value); - return 0; - } - field = FindFieldFromCode(field_idx, referrer, Thread::Current(), - InstancePrimitiveWrite, sizeof(uint64_t), true); - if (LIKELY(field != NULL)) { - field->Set64(obj, new_value); - return 0; - } - return -1; -} - -int32_t art_portable_set_obj_instance_from_code(uint32_t field_idx, AbstractMethod* referrer, - Object* obj, Object* new_value) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite, sizeof(Object*)); - if (LIKELY(field != NULL)) { - field->SetObj(obj, new_value); - return 0; - } - field = FindFieldFromCode(field_idx, referrer, Thread::Current(), - InstanceObjectWrite, sizeof(Object*), true); - if (LIKELY(field != NULL)) { - field->SetObj(obj, new_value); - return 0; - } - return -1; -} - -int32_t art_portable_get32_instance_from_code(uint32_t field_idx, AbstractMethod* referrer, Object* obj) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint32_t)); - if (LIKELY(field != NULL)) { - return field->Get32(obj); - } - field = FindFieldFromCode(field_idx, referrer, Thread::Current(), - InstancePrimitiveRead, sizeof(uint32_t), true); - if (LIKELY(field != NULL)) { - return field->Get32(obj); - } - return 0; -} - -int64_t art_portable_get64_instance_from_code(uint32_t field_idx, AbstractMethod* referrer, Object* obj) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint64_t)); - if (LIKELY(field != NULL)) { - return field->Get64(obj); - } - field = FindFieldFromCode(field_idx, referrer, Thread::Current(), - InstancePrimitiveRead, sizeof(uint64_t), true); - if (LIKELY(field != NULL)) { - return field->Get64(obj); - } - return 0; -} - -Object* art_portable_get_obj_instance_from_code(uint32_t field_idx, AbstractMethod* referrer, Object* obj) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Field* field = FindFieldFast(field_idx, referrer, InstanceObjectRead, sizeof(Object*)); - if (LIKELY(field != NULL)) { - return field->GetObj(obj); - } - field = FindFieldFromCode(field_idx, referrer, Thread::Current(), - InstanceObjectRead, sizeof(Object*), true); - if (LIKELY(field != NULL)) { - return field->GetObj(obj); - } - return 0; -} - -void art_portable_fill_array_data_from_code(AbstractMethod* method, uint32_t dex_pc, - Array* array, uint32_t payload_offset) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - // Test: Is array equal to null? (Guard NullPointerException) - if (UNLIKELY(array == NULL)) { - art_portable_throw_null_pointer_exception_from_code(dex_pc); - return; - } - - // Find the payload from the CodeItem - MethodHelper mh(method); - const DexFile::CodeItem* code_item = mh.GetCodeItem(); - - DCHECK_GT(code_item->insns_size_in_code_units_, payload_offset); - - const Instruction::ArrayDataPayload* payload = - reinterpret_cast<const Instruction::ArrayDataPayload*>( - code_item->insns_ + payload_offset); - - DCHECK_EQ(payload->ident, - static_cast<uint16_t>(Instruction::kArrayDataSignature)); - - // Test: Is array big enough? - uint32_t array_len = static_cast<uint32_t>(array->GetLength()); - if (UNLIKELY(array_len < payload->element_count)) { - int32_t last_index = payload->element_count - 1; - art_portable_throw_array_bounds_from_code(array_len, last_index); - return; - } - - // Copy the data - size_t size = payload->element_width * payload->element_count; - memcpy(array->GetRawData(payload->element_width), payload->data, size); -} - - - -//---------------------------------------------------------------------------- -// Type checking, in the nature of casting -//---------------------------------------------------------------------------- - -int32_t art_portable_is_assignable_from_code(const Class* dest_type, const Class* src_type) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(dest_type != NULL); - DCHECK(src_type != NULL); - return dest_type->IsAssignableFrom(src_type) ? 1 : 0; -} - -void art_portable_check_cast_from_code(const Class* dest_type, const Class* src_type) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(dest_type->IsClass()) << PrettyClass(dest_type); - DCHECK(src_type->IsClass()) << PrettyClass(src_type); - if (UNLIKELY(!dest_type->IsAssignableFrom(src_type))) { - ThrowClassCastException(dest_type, src_type); - } -} - -void art_portable_check_put_array_element_from_code(const Object* element, - const Object* array) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (element == NULL) { - return; - } - DCHECK(array != NULL); - Class* array_class = array->GetClass(); - DCHECK(array_class != NULL); - Class* component_type = array_class->GetComponentType(); - Class* element_class = element->GetClass(); - if (UNLIKELY(!component_type->IsAssignableFrom(element_class))) { - ThrowArrayStoreException(element_class, array_class); - } - return; -} - -//---------------------------------------------------------------------------- -// JNI -//---------------------------------------------------------------------------- - -// Called on entry to JNI, transition out of Runnable and release share of mutator_lock_. -uint32_t art_portable_jni_method_start(Thread* self) - UNLOCK_FUNCTION(GlobalSynchronizatio::mutator_lock_) { - JNIEnvExt* env = self->GetJniEnv(); - uint32_t saved_local_ref_cookie = env->local_ref_cookie; - env->local_ref_cookie = env->locals.GetSegmentState(); - self->TransitionFromRunnableToSuspended(kNative); - return saved_local_ref_cookie; -} - -uint32_t art_portable_jni_method_start_synchronized(jobject to_lock, Thread* self) - UNLOCK_FUNCTION(Locks::mutator_lock_) { - self->DecodeJObject(to_lock)->MonitorEnter(self); - return art_portable_jni_method_start(self); -} - -static inline void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self) { - JNIEnvExt* env = self->GetJniEnv(); - env->locals.SetSegmentState(env->local_ref_cookie); - env->local_ref_cookie = saved_local_ref_cookie; -} - -void art_portable_jni_method_end(uint32_t saved_local_ref_cookie, Thread* self) - SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { - self->TransitionFromSuspendedToRunnable(); - PopLocalReferences(saved_local_ref_cookie, self); -} - - -void art_portable_jni_method_end_synchronized(uint32_t saved_local_ref_cookie, - jobject locked, - Thread* self) - SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { - self->TransitionFromSuspendedToRunnable(); - UnlockJniSynchronizedMethod(locked, self); // Must decode before pop. - PopLocalReferences(saved_local_ref_cookie, self); -} - -Object* art_portable_jni_method_end_with_reference(jobject result, - uint32_t saved_local_ref_cookie, - Thread* self) - SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { - self->TransitionFromSuspendedToRunnable(); - Object* o = self->DecodeJObject(result); // Must decode before pop. - PopLocalReferences(saved_local_ref_cookie, self); - // Process result. - if (UNLIKELY(self->GetJniEnv()->check_jni)) { - if (self->IsExceptionPending()) { - return NULL; - } - CheckReferenceResult(o, self); - } - return o; -} - -Object* art_portable_jni_method_end_with_reference_synchronized(jobject result, - uint32_t saved_local_ref_cookie, - jobject locked, - Thread* self) - SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { - self->TransitionFromSuspendedToRunnable(); - UnlockJniSynchronizedMethod(locked, self); // Must decode before pop. - Object* o = self->DecodeJObject(result); - PopLocalReferences(saved_local_ref_cookie, self); - // Process result. - if (UNLIKELY(self->GetJniEnv()->check_jni)) { - if (self->IsExceptionPending()) { - return NULL; - } - CheckReferenceResult(o, self); - } - return o; -} - -// Handler for invocation on proxy methods. Create a boxed argument array and invoke the invocation -// handler which is a field within the proxy object receiver. The var args encode the arguments -// with the last argument being a pointer to a JValue to store the result in. -void art_portable_proxy_invoke_handler_from_code(AbstractMethod* proxy_method, ...) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - va_list ap; - va_start(ap, proxy_method); - - Object* receiver = va_arg(ap, Object*); - Thread* self = va_arg(ap, Thread*); - MethodHelper proxy_mh(proxy_method); - - // Ensure we don't get thread suspension until the object arguments are safely in jobjects. - const char* old_cause = - self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments"); - self->VerifyStack(); - - // Start new JNI local reference state. - JNIEnvExt* env = self->GetJniEnv(); - ScopedObjectAccessUnchecked soa(env); - ScopedJniEnvLocalRefState env_state(env); - - // Create local ref. copies of the receiver. - jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver); - - // Convert proxy method into expected interface method. - AbstractMethod* interface_method = proxy_method->FindOverriddenMethod(); - DCHECK(interface_method != NULL); - DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method); - jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method); - - // Record arguments and turn Object* arguments into jobject to survive GC. - std::vector<jvalue> args; - const size_t num_params = proxy_mh.NumArgs(); - for (size_t i = 1; i < num_params; ++i) { - jvalue val; - switch (proxy_mh.GetParamPrimitiveType(i)) { - case Primitive::kPrimNot: - val.l = soa.AddLocalReference<jobject>(va_arg(ap, Object*)); - break; - case Primitive::kPrimBoolean: // Fall-through. - case Primitive::kPrimByte: // Fall-through. - case Primitive::kPrimChar: // Fall-through. - case Primitive::kPrimShort: // Fall-through. - case Primitive::kPrimInt: // Fall-through. - val.i = va_arg(ap, jint); - break; - case Primitive::kPrimFloat: - // TODO: should this be jdouble? Floats aren't passed to var arg routines. - val.i = va_arg(ap, jint); - break; - case Primitive::kPrimDouble: - val.d = (va_arg(ap, jdouble)); - break; - case Primitive::kPrimLong: - val.j = (va_arg(ap, jlong)); - break; - case Primitive::kPrimVoid: - LOG(FATAL) << "UNREACHABLE"; - val.j = 0; - break; - } - args.push_back(val); - } - self->EndAssertNoThreadSuspension(old_cause); - JValue* result_location = NULL; - const char* shorty = proxy_mh.GetShorty(); - if (shorty[0] != 'V') { - result_location = va_arg(ap, JValue*); - } - va_end(ap); - JValue result = InvokeProxyInvocationHandler(soa, shorty, rcvr_jobj, interface_method_jobj, args); - if (result_location != NULL) { - *result_location = result; - } -} - -//---------------------------------------------------------------------------- -// Memory barrier -//---------------------------------------------------------------------------- - -void art_portable_constructor_barrier() { - LOG(FATAL) << "Implemented by IRBuilder."; -} -} // extern "C" diff --git a/runtime/stack.cc b/runtime/stack.cc index 286a2a6a5e..aeb15f09bd 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -16,7 +16,6 @@ #include "stack.h" -#include "oat/runtime/context.h" #include "mirror/abstract_method-inl.h" #include "mirror/class-inl.h" #include "mirror/object.h" diff --git a/runtime/stack.h b/runtime/stack.h index 0b94f27c4b..de93846112 100644 --- a/runtime/stack.h +++ b/runtime/stack.h @@ -20,7 +20,7 @@ #include "dex_file.h" #include "instrumentation.h" #include "base/macros.h" -#include "oat/runtime/context.h" +#include "arch/context.h" #include <stdint.h> #include <string> diff --git a/runtime/thread.cc b/runtime/thread.cc index 0b3a5b4959..97a1410892 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -30,6 +30,7 @@ #include <iostream> #include <list> +#include "arch/context.h" #include "base/mutex.h" #include "class_linker.h" #include "class_linker-inl.h" @@ -37,6 +38,7 @@ #include "cutils/atomic-inline.h" #include "debugger.h" #include "dex_file-inl.h" +#include "entrypoints/entrypoint_utils.h" #include "gc_map.h" #include "gc/accounting/card_table-inl.h" #include "gc/heap.h" @@ -50,11 +52,9 @@ #include "mirror/object_array-inl.h" #include "mirror/stack_trace_element.h" #include "monitor.h" -#include "oat/runtime/context.h" #include "object_utils.h" #include "reflection.h" #include "runtime.h" -#include "runtime_support.h" #include "scoped_thread_state_change.h" #include "ScopedLocalRef.h" #include "ScopedUtfChars.h" @@ -86,16 +86,23 @@ static void UnimplementedEntryPoint() { } #endif +void InitEntryPoints(QuickEntryPoints* qpoints, PortableEntryPoints* ppoints); + void Thread::InitFunctionPointers() { #if !defined(__APPLE__) // The Mac GCC is too old to accept this code. // Insert a placeholder so we can easily tell if we call an unimplemented entry point. - uintptr_t* begin = reinterpret_cast<uintptr_t*>(&entrypoints_); - uintptr_t* end = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(begin) + sizeof(entrypoints_)); + uintptr_t* begin = reinterpret_cast<uintptr_t*>(&quick_entrypoints_); + uintptr_t* end = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(begin) + sizeof(quick_entrypoints_)); + for (uintptr_t* it = begin; it != end; ++it) { + *it = reinterpret_cast<uintptr_t>(UnimplementedEntryPoint); + } + begin = reinterpret_cast<uintptr_t*>(&portable_entrypoints_); + end = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(begin) + sizeof(portable_entrypoints_)); for (uintptr_t* it = begin; it != end; ++it) { *it = reinterpret_cast<uintptr_t>(UnimplementedEntryPoint); } #endif - InitEntryPoints(&entrypoints_); + InitEntryPoints(&quick_entrypoints_, &portable_entrypoints_); } void Thread::SetDeoptimizationShadowFrame(ShadowFrame* sf) { @@ -1582,86 +1589,87 @@ struct EntryPointInfo { uint32_t offset; const char* name; }; -#define ENTRY_POINT_INFO(x) { ENTRYPOINT_OFFSET(x), #x } +#define QUICK_ENTRY_POINT_INFO(x) { QUICK_ENTRYPOINT_OFFSET(x), #x } +#define PORTABLE_ENTRY_POINT_INFO(x) { PORTABLE_ENTRYPOINT_OFFSET(x), #x } static const EntryPointInfo gThreadEntryPointInfo[] = { - ENTRY_POINT_INFO(pAllocArrayFromCode), - ENTRY_POINT_INFO(pAllocArrayFromCodeWithAccessCheck), - ENTRY_POINT_INFO(pAllocObjectFromCode), - ENTRY_POINT_INFO(pAllocObjectFromCodeWithAccessCheck), - ENTRY_POINT_INFO(pCheckAndAllocArrayFromCode), - ENTRY_POINT_INFO(pCheckAndAllocArrayFromCodeWithAccessCheck), - ENTRY_POINT_INFO(pInstanceofNonTrivialFromCode), - ENTRY_POINT_INFO(pCanPutArrayElementFromCode), - ENTRY_POINT_INFO(pCheckCastFromCode), - ENTRY_POINT_INFO(pInitializeStaticStorage), - ENTRY_POINT_INFO(pInitializeTypeAndVerifyAccessFromCode), - ENTRY_POINT_INFO(pInitializeTypeFromCode), - ENTRY_POINT_INFO(pResolveStringFromCode), - ENTRY_POINT_INFO(pSet32Instance), - ENTRY_POINT_INFO(pSet32Static), - ENTRY_POINT_INFO(pSet64Instance), - ENTRY_POINT_INFO(pSet64Static), - ENTRY_POINT_INFO(pSetObjInstance), - ENTRY_POINT_INFO(pSetObjStatic), - ENTRY_POINT_INFO(pGet32Instance), - ENTRY_POINT_INFO(pGet32Static), - ENTRY_POINT_INFO(pGet64Instance), - ENTRY_POINT_INFO(pGet64Static), - ENTRY_POINT_INFO(pGetObjInstance), - ENTRY_POINT_INFO(pGetObjStatic), - ENTRY_POINT_INFO(pHandleFillArrayDataFromCode), - ENTRY_POINT_INFO(pJniMethodStart), - ENTRY_POINT_INFO(pJniMethodStartSynchronized), - ENTRY_POINT_INFO(pJniMethodEnd), - ENTRY_POINT_INFO(pJniMethodEndSynchronized), - ENTRY_POINT_INFO(pJniMethodEndWithReference), - ENTRY_POINT_INFO(pJniMethodEndWithReferenceSynchronized), - ENTRY_POINT_INFO(pLockObjectFromCode), - ENTRY_POINT_INFO(pUnlockObjectFromCode), - ENTRY_POINT_INFO(pCmpgDouble), - ENTRY_POINT_INFO(pCmpgFloat), - ENTRY_POINT_INFO(pCmplDouble), - ENTRY_POINT_INFO(pCmplFloat), - ENTRY_POINT_INFO(pFmod), - ENTRY_POINT_INFO(pSqrt), - ENTRY_POINT_INFO(pL2d), - ENTRY_POINT_INFO(pFmodf), - ENTRY_POINT_INFO(pL2f), - ENTRY_POINT_INFO(pD2iz), - ENTRY_POINT_INFO(pF2iz), - ENTRY_POINT_INFO(pIdivmod), - ENTRY_POINT_INFO(pD2l), - ENTRY_POINT_INFO(pF2l), - ENTRY_POINT_INFO(pLdiv), - ENTRY_POINT_INFO(pLdivmod), - ENTRY_POINT_INFO(pLmul), - ENTRY_POINT_INFO(pShlLong), - ENTRY_POINT_INFO(pShrLong), - ENTRY_POINT_INFO(pUshrLong), - ENTRY_POINT_INFO(pInterpreterToInterpreterEntry), - ENTRY_POINT_INFO(pInterpreterToQuickEntry), - ENTRY_POINT_INFO(pIndexOf), - ENTRY_POINT_INFO(pMemcmp16), - ENTRY_POINT_INFO(pStringCompareTo), - ENTRY_POINT_INFO(pMemcpy), - ENTRY_POINT_INFO(pPortableResolutionTrampolineFromCode), - ENTRY_POINT_INFO(pQuickResolutionTrampolineFromCode), - ENTRY_POINT_INFO(pInvokeDirectTrampolineWithAccessCheck), - ENTRY_POINT_INFO(pInvokeInterfaceTrampoline), - ENTRY_POINT_INFO(pInvokeInterfaceTrampolineWithAccessCheck), - ENTRY_POINT_INFO(pInvokeStaticTrampolineWithAccessCheck), - ENTRY_POINT_INFO(pInvokeSuperTrampolineWithAccessCheck), - ENTRY_POINT_INFO(pInvokeVirtualTrampolineWithAccessCheck), - ENTRY_POINT_INFO(pCheckSuspendFromCode), - ENTRY_POINT_INFO(pTestSuspendFromCode), - ENTRY_POINT_INFO(pDeliverException), - ENTRY_POINT_INFO(pThrowArrayBoundsFromCode), - ENTRY_POINT_INFO(pThrowDivZeroFromCode), - ENTRY_POINT_INFO(pThrowNoSuchMethodFromCode), - ENTRY_POINT_INFO(pThrowNullPointerFromCode), - ENTRY_POINT_INFO(pThrowStackOverflowFromCode), + QUICK_ENTRY_POINT_INFO(pAllocArrayFromCode), + QUICK_ENTRY_POINT_INFO(pAllocArrayFromCodeWithAccessCheck), + QUICK_ENTRY_POINT_INFO(pAllocObjectFromCode), + QUICK_ENTRY_POINT_INFO(pAllocObjectFromCodeWithAccessCheck), + QUICK_ENTRY_POINT_INFO(pCheckAndAllocArrayFromCode), + QUICK_ENTRY_POINT_INFO(pCheckAndAllocArrayFromCodeWithAccessCheck), + QUICK_ENTRY_POINT_INFO(pInstanceofNonTrivialFromCode), + QUICK_ENTRY_POINT_INFO(pCanPutArrayElementFromCode), + QUICK_ENTRY_POINT_INFO(pCheckCastFromCode), + QUICK_ENTRY_POINT_INFO(pInitializeStaticStorage), + QUICK_ENTRY_POINT_INFO(pInitializeTypeAndVerifyAccessFromCode), + QUICK_ENTRY_POINT_INFO(pInitializeTypeFromCode), + QUICK_ENTRY_POINT_INFO(pResolveStringFromCode), + QUICK_ENTRY_POINT_INFO(pSet32Instance), + QUICK_ENTRY_POINT_INFO(pSet32Static), + QUICK_ENTRY_POINT_INFO(pSet64Instance), + QUICK_ENTRY_POINT_INFO(pSet64Static), + QUICK_ENTRY_POINT_INFO(pSetObjInstance), + QUICK_ENTRY_POINT_INFO(pSetObjStatic), + QUICK_ENTRY_POINT_INFO(pGet32Instance), + QUICK_ENTRY_POINT_INFO(pGet32Static), + QUICK_ENTRY_POINT_INFO(pGet64Instance), + QUICK_ENTRY_POINT_INFO(pGet64Static), + QUICK_ENTRY_POINT_INFO(pGetObjInstance), + QUICK_ENTRY_POINT_INFO(pGetObjStatic), + QUICK_ENTRY_POINT_INFO(pHandleFillArrayDataFromCode), + QUICK_ENTRY_POINT_INFO(pJniMethodStart), + QUICK_ENTRY_POINT_INFO(pJniMethodStartSynchronized), + QUICK_ENTRY_POINT_INFO(pJniMethodEnd), + QUICK_ENTRY_POINT_INFO(pJniMethodEndSynchronized), + QUICK_ENTRY_POINT_INFO(pJniMethodEndWithReference), + QUICK_ENTRY_POINT_INFO(pJniMethodEndWithReferenceSynchronized), + QUICK_ENTRY_POINT_INFO(pLockObjectFromCode), + QUICK_ENTRY_POINT_INFO(pUnlockObjectFromCode), + QUICK_ENTRY_POINT_INFO(pCmpgDouble), + QUICK_ENTRY_POINT_INFO(pCmpgFloat), + QUICK_ENTRY_POINT_INFO(pCmplDouble), + QUICK_ENTRY_POINT_INFO(pCmplFloat), + QUICK_ENTRY_POINT_INFO(pFmod), + QUICK_ENTRY_POINT_INFO(pSqrt), + QUICK_ENTRY_POINT_INFO(pL2d), + QUICK_ENTRY_POINT_INFO(pFmodf), + QUICK_ENTRY_POINT_INFO(pL2f), + QUICK_ENTRY_POINT_INFO(pD2iz), + QUICK_ENTRY_POINT_INFO(pF2iz), + QUICK_ENTRY_POINT_INFO(pIdivmod), + QUICK_ENTRY_POINT_INFO(pD2l), + QUICK_ENTRY_POINT_INFO(pF2l), + QUICK_ENTRY_POINT_INFO(pLdiv), + QUICK_ENTRY_POINT_INFO(pLdivmod), + QUICK_ENTRY_POINT_INFO(pLmul), + QUICK_ENTRY_POINT_INFO(pShlLong), + QUICK_ENTRY_POINT_INFO(pShrLong), + QUICK_ENTRY_POINT_INFO(pUshrLong), + QUICK_ENTRY_POINT_INFO(pInterpreterToInterpreterEntry), + QUICK_ENTRY_POINT_INFO(pInterpreterToQuickEntry), + QUICK_ENTRY_POINT_INFO(pIndexOf), + QUICK_ENTRY_POINT_INFO(pMemcmp16), + QUICK_ENTRY_POINT_INFO(pStringCompareTo), + QUICK_ENTRY_POINT_INFO(pMemcpy), + QUICK_ENTRY_POINT_INFO(pQuickResolutionTrampolineFromCode), + QUICK_ENTRY_POINT_INFO(pInvokeDirectTrampolineWithAccessCheck), + QUICK_ENTRY_POINT_INFO(pInvokeInterfaceTrampoline), + QUICK_ENTRY_POINT_INFO(pInvokeInterfaceTrampolineWithAccessCheck), + QUICK_ENTRY_POINT_INFO(pInvokeStaticTrampolineWithAccessCheck), + QUICK_ENTRY_POINT_INFO(pInvokeSuperTrampolineWithAccessCheck), + QUICK_ENTRY_POINT_INFO(pInvokeVirtualTrampolineWithAccessCheck), + QUICK_ENTRY_POINT_INFO(pCheckSuspendFromCode), + QUICK_ENTRY_POINT_INFO(pTestSuspendFromCode), + QUICK_ENTRY_POINT_INFO(pDeliverException), + QUICK_ENTRY_POINT_INFO(pThrowArrayBoundsFromCode), + QUICK_ENTRY_POINT_INFO(pThrowDivZeroFromCode), + QUICK_ENTRY_POINT_INFO(pThrowNoSuchMethodFromCode), + QUICK_ENTRY_POINT_INFO(pThrowNullPointerFromCode), + QUICK_ENTRY_POINT_INFO(pThrowStackOverflowFromCode), + PORTABLE_ENTRY_POINT_INFO(pPortableResolutionTrampolineFromCode), }; -#undef ENTRY_POINT_INFO +#undef QUICK_ENTRY_POINT_INFO void Thread::DumpThreadOffset(std::ostream& os, uint32_t offset, size_t size_of_pointers) { CHECK_EQ(size_of_pointers, 4U); // TODO: support 64-bit targets. @@ -1686,8 +1694,9 @@ void Thread::DumpThreadOffset(std::ostream& os, uint32_t offset, size_t size_of_ #undef DO_THREAD_OFFSET size_t entry_point_count = arraysize(gThreadEntryPointInfo); - CHECK_EQ(entry_point_count * size_of_pointers, sizeof(EntryPoints)); - uint32_t expected_offset = OFFSETOF_MEMBER(Thread, entrypoints_); + CHECK_EQ(entry_point_count * size_of_pointers, + sizeof(QuickEntryPoints) + sizeof(PortableEntryPoints)); + uint32_t expected_offset = OFFSETOF_MEMBER(Thread, quick_entrypoints_); for (size_t i = 0; i < entry_point_count; ++i) { CHECK_EQ(gThreadEntryPointInfo[i].offset, expected_offset) << gThreadEntryPointInfo[i].name; expected_offset += size_of_pointers; @@ -1709,7 +1718,7 @@ class CatchBlockStackVisitor : public StackVisitor { self_(self), exception_(exception), is_deoptimization_(is_deoptimization), to_find_(is_deoptimization ? NULL : exception->GetClass()), throw_location_(throw_location), handler_quick_frame_(NULL), handler_quick_frame_pc_(0), handler_dex_pc_(0), - native_method_count_(0), + native_method_count_(0), clear_exception_(false), method_tracing_active_(is_deoptimization || Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()), instrumentation_frames_to_pop_(0), top_shadow_frame_(NULL), prev_shadow_frame_(NULL) { @@ -1754,7 +1763,7 @@ class CatchBlockStackVisitor : public StackVisitor { dex_pc = GetDexPc(); } if (dex_pc != DexFile::kDexNoIndex) { - uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc); + uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc, &clear_exception_); if (found_dex_pc != DexFile::kDexNoIndex) { handler_dex_pc_ = found_dex_pc; handler_quick_frame_pc_ = method->ToNativePc(found_dex_pc); @@ -1820,8 +1829,13 @@ class CatchBlockStackVisitor : public StackVisitor { LOG(INFO) << "Handler: " << PrettyMethod(catch_method) << " (line: " << line_number << ")"; } } - // Put exception back in root set and clear throw location. - self_->SetException(ThrowLocation(), exception_); + if (clear_exception_) { + // Exception was cleared as part of delivery. + DCHECK(!self_->IsExceptionPending()); + } else { + // Put exception back in root set with clear throw location. + self_->SetException(ThrowLocation(), exception_); + } self_->EndAssertNoThreadSuspension(last_no_assert_suspension_cause_); // Do instrumentation events after allowing thread suspension again. instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); @@ -1864,6 +1878,8 @@ class CatchBlockStackVisitor : public StackVisitor { uint32_t handler_dex_pc_; // Number of native methods passed in crawl (equates to number of SIRTs to pop) uint32_t native_method_count_; + // Should the exception be cleared as the catch block has no move-exception? + bool clear_exception_; // Is method tracing active? const bool method_tracing_active_; // Support for nesting no thread suspension checks. diff --git a/runtime/thread.h b/runtime/thread.h index b9393a3052..ff0fe228c0 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -26,9 +26,10 @@ #include <string> #include "base/macros.h" +#include "entrypoints/portable/portable_entrypoints.h" +#include "entrypoints/quick/quick_entrypoints.h" #include "globals.h" #include "jvalue.h" -#include "oat/runtime/oat_support_entrypoints.h" #include "locks.h" #include "offsets.h" #include "root_visitor.h" @@ -773,9 +774,10 @@ class PACKED(4) Thread { Closure* checkpoint_function_; public: - // Runtime support function pointers + // Entrypoint function pointers // TODO: move this near the top, since changing its offset requires all oats to be recompiled! - EntryPoints entrypoints_; + QuickEntryPoints quick_entrypoints_; + PortableEntryPoints portable_entrypoints_; private: // How many times has our pthread key's destructor been called? diff --git a/runtime/trace.cc b/runtime/trace.cc index 177fd48f7d..2bce70f7c1 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -29,14 +29,14 @@ #include "mirror/dex_cache.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" -#if !defined(ART_USE_PORTABLE_COMPILER) -#include "oat/runtime/oat_support_entrypoints.h" -#endif #include "object_utils.h" #include "os.h" #include "scoped_thread_state_change.h" #include "thread.h" #include "thread_list.h" +#if !defined(ART_USE_PORTABLE_COMPILER) +#include "entrypoints/quick/quick_entrypoints.h" +#endif namespace art { diff --git a/runtime/verifier/instruction_flags.cc b/runtime/verifier/instruction_flags.cc index 358791ddf6..f76c226e90 100644 --- a/runtime/verifier/instruction_flags.cc +++ b/runtime/verifier/instruction_flags.cc @@ -22,16 +22,17 @@ namespace art { namespace verifier { std::string InstructionFlags::ToString() const { - char encoding[6]; + char encoding[7]; if (!IsOpcode()) { - strncpy(encoding, "XXXXX", sizeof(encoding)); + strncpy(encoding, "XXXXXX", sizeof(encoding)); } else { - strncpy(encoding, "-----", sizeof(encoding)); - if (IsInTry()) encoding[kInTry] = 'T'; - if (IsBranchTarget()) encoding[kBranchTarget] = 'B'; + strncpy(encoding, "------", sizeof(encoding)); + if (IsVisited()) encoding[kVisited] = 'V'; + if (IsChanged()) encoding[kChanged] = 'C'; + if (IsInTry()) encoding[kInTry] = 'T'; + if (IsBranchTarget()) encoding[kBranchTarget] = 'B'; if (IsCompileTimeInfoPoint()) encoding[kCompileTimeInfoPoint] = 'G'; - if (IsVisited()) encoding[kVisited] = 'V'; - if (IsChanged()) encoding[kChanged] = 'C'; + if (IsReturn()) encoding[kReturn] = 'R'; } return encoding; } diff --git a/runtime/verifier/instruction_flags.h b/runtime/verifier/instruction_flags.h index 9b2e595b9d..e50ba13932 100644 --- a/runtime/verifier/instruction_flags.h +++ b/runtime/verifier/instruction_flags.h @@ -93,6 +93,21 @@ class InstructionFlags { return IsVisited() || IsChanged(); } + void SetReturn() { + flags_ |= 1 << kReturn; + } + void ClearReturn() { + flags_ &= ~(1 << kReturn); + } + bool IsReturn() const { + return (flags_ & (1 << kReturn)) != 0; + } + + void SetCompileTimeInfoPointAndReturn() { + SetCompileTimeInfoPoint(); + SetReturn(); + } + std::string ToString() const; private: @@ -108,6 +123,8 @@ class InstructionFlags { kBranchTarget = 3, // Location of interest to the compiler for GC maps and verifier based method sharpening. kCompileTimeInfoPoint = 4, + // A return instruction. + kReturn = 5, }; // Size of instruction in code units. diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index acb6557d52..9f0d911aa5 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -102,7 +102,11 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const mirror::Class* kla error += dex_file.GetLocation(); return kHardFailure; } - return VerifyClass(&dex_file, kh.GetDexCache(), klass->GetClassLoader(), class_def_idx, error, allow_soft_failures); + return VerifyClass(&dex_file, + kh.GetDexCache(), + klass->GetClassLoader(), + class_def_idx, error, + allow_soft_failures); } MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, @@ -142,8 +146,15 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, // We couldn't resolve the method, but continue regardless. Thread::Current()->ClearException(); } - MethodVerifier::FailureKind result = VerifyMethod(method_idx, dex_file, dex_cache, class_loader, - class_def_idx, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), allow_soft_failures); + MethodVerifier::FailureKind result = VerifyMethod(method_idx, + dex_file, + dex_cache, + class_loader, + class_def_idx, + it.GetMethodCodeItem(), + method, + it.GetMemberAccessFlags(), + allow_soft_failures); if (result != kNoFailure) { if (result == kHardFailure) { hard_fail = true; @@ -177,8 +188,15 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, // We couldn't resolve the method, but continue regardless. Thread::Current()->ClearException(); } - MethodVerifier::FailureKind result = VerifyMethod(method_idx, dex_file, dex_cache, class_loader, - class_def_idx, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), allow_soft_failures); + MethodVerifier::FailureKind result = VerifyMethod(method_idx, + dex_file, + dex_cache, + class_loader, + class_def_idx, + it.GetMethodCodeItem(), + method, + it.GetMemberAccessFlags(), + allow_soft_failures); if (result != kNoFailure) { if (result == kHardFailure) { hard_fail = true; @@ -282,7 +300,9 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca new_instance_count_(0), monitor_enter_count_(0), can_load_classes_(can_load_classes), - allow_soft_failures_(allow_soft_failures) { + allow_soft_failures_(allow_soft_failures), + has_check_casts_(false), + has_virtual_or_interface_invokes_(false) { } void MethodVerifier::FindLocksAtDexPc(mirror::AbstractMethod* m, uint32_t dex_pc, @@ -470,6 +490,13 @@ bool MethodVerifier::ComputeWidthsAndCountOps() { new_instance_count++; } else if (opcode == Instruction::MONITOR_ENTER) { monitor_enter_count++; + } else if (opcode == Instruction::CHECK_CAST) { + has_check_casts_ = true; + } else if ((inst->Opcode() == Instruction::INVOKE_VIRTUAL) || + (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE) || + (inst->Opcode() == Instruction::INVOKE_INTERFACE) || + (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE)) { + has_virtual_or_interface_invokes_ = true; } size_t inst_size = inst->SizeInCodeUnits(); insn_flags_[dex_pc].SetLengthInCodeUnits(inst_size); @@ -506,7 +533,8 @@ bool MethodVerifier::ScanTryCatchBlocks() { return false; } if (!insn_flags_[start].IsOpcode()) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "'try' block starts inside an instruction (" << start << ")"; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "'try' block starts inside an instruction (" << start << ")"; return false; } for (uint32_t dex_pc = start; dex_pc < end; @@ -523,7 +551,8 @@ bool MethodVerifier::ScanTryCatchBlocks() { for (; iterator.HasNext(); iterator.Next()) { uint32_t dex_pc= iterator.GetHandlerAddress(); if (!insn_flags_[dex_pc].IsOpcode()) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "exception handler starts at bad address (" << dex_pc << ")"; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "exception handler starts at bad address (" << dex_pc << ")"; return false; } insn_flags_[dex_pc].SetBranchTarget(); @@ -560,8 +589,10 @@ bool MethodVerifier::VerifyInstructions() { /* Flag instructions that are garbage collection points */ // All invoke points are marked as "Throw" points already. // We are relying on this to also count all the invokes as interesting. - if (inst->IsBranch() || inst->IsSwitch() || inst->IsThrow() || inst->IsReturn()) { + if (inst->IsBranch() || inst->IsSwitch() || inst->IsThrow()) { insn_flags_[dex_pc].SetCompileTimeInfoPoint(); + } else if (inst->IsReturn()) { + insn_flags_[dex_pc].SetCompileTimeInfoPointAndReturn(); } dex_pc += inst->SizeInCodeUnits(); inst = inst->Next(); @@ -727,11 +758,13 @@ bool MethodVerifier::CheckNewArray(uint32_t idx) { } if (bracket_count == 0) { /* The given class must be an array type. */ - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "can't new-array class '" << descriptor << "' (not an array)"; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "can't new-array class '" << descriptor << "' (not an array)"; return false; } else if (bracket_count > 255) { /* It is illegal to create an array of more than 255 dimensions. */ - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "can't new-array class '" << descriptor << "' (exceeds limit)"; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "can't new-array class '" << descriptor << "' (exceeds limit)"; return false; } return true; @@ -749,7 +782,8 @@ bool MethodVerifier::CheckArrayData(uint32_t cur_offset) { if ((int32_t) cur_offset + array_data_offset < 0 || cur_offset + array_data_offset + 2 >= insn_count) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid array data start: at " << cur_offset - << ", data offset " << array_data_offset << ", count " << insn_count; + << ", data offset " << array_data_offset + << ", count " << insn_count; return false; } /* offset to array data table is a relative branch-style offset */ @@ -781,18 +815,22 @@ bool MethodVerifier::CheckBranchTarget(uint32_t cur_offset) { return false; } if (!selfOkay && offset == 0) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "branch offset of zero not allowed at" << reinterpret_cast<void*>(cur_offset); + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "branch offset of zero not allowed at" + << reinterpret_cast<void*>(cur_offset); return false; } // Check for 32-bit overflow. This isn't strictly necessary if we can depend on the runtime // to have identical "wrap-around" behavior, but it's unwise to depend on that. if (((int64_t) cur_offset + (int64_t) offset) != (int64_t) (cur_offset + offset)) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "branch target overflow " << reinterpret_cast<void*>(cur_offset) << " +" << offset; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "branch target overflow " + << reinterpret_cast<void*>(cur_offset) << " +" << offset; return false; } const uint32_t insn_count = code_item_->insns_size_in_code_units_; int32_t abs_offset = cur_offset + offset; - if (abs_offset < 0 || (uint32_t) abs_offset >= insn_count || !insn_flags_[abs_offset].IsOpcode()) { + if (abs_offset < 0 || + (uint32_t) abs_offset >= insn_count || + !insn_flags_[abs_offset].IsOpcode()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid branch target " << offset << " (-> " << reinterpret_cast<void*>(abs_offset) << ") at " << reinterpret_cast<void*>(cur_offset); @@ -848,7 +886,8 @@ bool MethodVerifier::CheckSwitchTargets(uint32_t cur_offset) { int32_t switch_offset = insns[1] | ((int32_t) insns[2]) << 16; if ((int32_t) cur_offset + switch_offset < 0 || cur_offset + switch_offset + 2 >= insn_count) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch start: at " << cur_offset - << ", switch offset " << switch_offset << ", count " << insn_count; + << ", switch offset " << switch_offset + << ", count " << insn_count; return false; } /* offset to switch table is a relative branch-style offset */ @@ -875,15 +914,16 @@ bool MethodVerifier::CheckSwitchTargets(uint32_t cur_offset) { } uint32_t table_size = targets_offset + switch_count * 2; if (switch_insns[0] != expected_signature) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << StringPrintf("wrong signature for switch table (%x, wanted %x)", - switch_insns[0], expected_signature); + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << StringPrintf("wrong signature for switch table (%x, wanted %x)", + switch_insns[0], expected_signature); return false; } /* make sure the end of the switch is in range */ if (cur_offset + switch_offset + table_size > (uint32_t) insn_count) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch end: at " << cur_offset << ", switch offset " - << switch_offset << ", end " - << (cur_offset + switch_offset + table_size) + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch end: at " << cur_offset + << ", switch offset " << switch_offset + << ", end " << (cur_offset + switch_offset + table_size) << ", count " << insn_count; return false; } @@ -906,10 +946,13 @@ bool MethodVerifier::CheckSwitchTargets(uint32_t cur_offset) { int32_t offset = (int32_t) switch_insns[targets_offset + targ * 2] | (int32_t) (switch_insns[targets_offset + targ * 2 + 1] << 16); int32_t abs_offset = cur_offset + offset; - if (abs_offset < 0 || abs_offset >= (int32_t) insn_count || !insn_flags_[abs_offset].IsOpcode()) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch target " << offset << " (-> " - << reinterpret_cast<void*>(abs_offset) << ") at " - << reinterpret_cast<void*>(cur_offset) << "[" << targ << "]"; + if (abs_offset < 0 || + abs_offset >= (int32_t) insn_count || + !insn_flags_[abs_offset].IsOpcode()) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch target " << offset + << " (-> " << reinterpret_cast<void*>(abs_offset) << ") at " + << reinterpret_cast<void*>(cur_offset) + << "[" << targ << "]"; return false; } insn_flags_[abs_offset].SetBranchTarget(); @@ -939,14 +982,15 @@ bool MethodVerifier::CheckVarArgRangeRegs(uint32_t vA, uint32_t vC) { // vA/vC are unsigned 8-bit/16-bit quantities for /range instructions, so there's no risk of // integer overflow when adding them here. if (vA + vC > registers_size) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid reg index " << vA << "+" << vC << " in range invoke (> " - << registers_size << ")"; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid reg index " << vA << "+" << vC + << " in range invoke (> " << registers_size << ")"; return false; } return true; } -static const std::vector<uint8_t>* CreateLengthPrefixedDexGcMap(const std::vector<uint8_t>& gc_map) { +static const std::vector<uint8_t>* CreateLengthPrefixedDexGcMap( + const std::vector<uint8_t>& gc_map) { std::vector<uint8_t>* length_prefixed_gc_map = new std::vector<uint8_t>; length_prefixed_gc_map->reserve(gc_map.size() + 4); length_prefixed_gc_map->push_back((gc_map.size() & 0xff000000) >> 24); @@ -974,7 +1018,11 @@ bool MethodVerifier::VerifyCodeFlow() { << " insns_size=" << insns_size << ")"; } /* Create and initialize table holding register status */ - reg_table_.Init(kTrackCompilerInterestPoints, insn_flags_.get(), insns_size, registers_size, this); + reg_table_.Init(kTrackCompilerInterestPoints, + insn_flags_.get(), + insns_size, + registers_size, + this); work_line_.reset(new RegisterLine(registers_size, this)); @@ -994,27 +1042,37 @@ bool MethodVerifier::VerifyCodeFlow() { return false; } - /* Generate a register map and add it to the method. */ - UniquePtr<const std::vector<uint8_t> > map(GenerateGcMap()); - if (map.get() == NULL) { - DCHECK_NE(failures_.size(), 0U); - return false; // Not a real failure, but a failure to encode - } - if (kIsDebugBuild) { - VerifyGcMap(*map); - } - MethodReference ref(dex_file_, dex_method_idx_); - const std::vector<uint8_t>* dex_gc_map = CreateLengthPrefixedDexGcMap(*(map.get())); - verifier::MethodVerifier::SetDexGcMap(ref, *dex_gc_map); + // Compute information for compiler. + if (Runtime::Current()->IsCompiler()) { + MethodReference ref(dex_file_, dex_method_idx_); + bool compile = IsCandidateForCompilation(code_item_, method_access_flags_); + if (compile) { + /* Generate a register map and add it to the method. */ + UniquePtr<const std::vector<uint8_t> > map(GenerateGcMap()); + if (map.get() == NULL) { + DCHECK_NE(failures_.size(), 0U); + return false; // Not a real failure, but a failure to encode + } + if (kIsDebugBuild) { + VerifyGcMap(*map); + } + const std::vector<uint8_t>* dex_gc_map = CreateLengthPrefixedDexGcMap(*(map.get())); + verifier::MethodVerifier::SetDexGcMap(ref, *dex_gc_map); + } - MethodVerifier::MethodSafeCastSet* method_to_safe_casts = GenerateSafeCastSet(); - if (method_to_safe_casts != NULL) { - SetSafeCastMap(ref, method_to_safe_casts); - } + if (has_check_casts_) { + MethodVerifier::MethodSafeCastSet* method_to_safe_casts = GenerateSafeCastSet(); + if (method_to_safe_casts != NULL) { + SetSafeCastMap(ref, method_to_safe_casts); + } + } - MethodVerifier::PcToConcreteMethodMap* pc_to_concrete_method = GenerateDevirtMap(); - if (pc_to_concrete_method != NULL) { - SetDevirtMap(ref, pc_to_concrete_method); + if (has_virtual_or_interface_invokes_) { + MethodVerifier::PcToConcreteMethodMap* pc_to_concrete_method = GenerateDevirtMap(); + if (pc_to_concrete_method != NULL) { + SetDevirtMap(ref, pc_to_concrete_method); + } + } } return true; } @@ -1154,13 +1212,15 @@ bool MethodVerifier::SetTypesFromSignature() { break; } default: - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected signature type char '" << descriptor << "'"; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected signature type char '" + << descriptor << "'"; return false; } cur_arg++; } if (cur_arg != expected_args) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected " << expected_args << " arguments, found " << cur_arg; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected " << expected_args + << " arguments, found " << cur_arg; return false; } const char* descriptor = dex_file_->GetReturnTypeDescriptor(proto_id); @@ -1294,12 +1354,14 @@ bool MethodVerifier::CodeFlowVerifyMethod() { if (dead_start < 0) dead_start = insn_idx; } else if (dead_start >= 0) { - LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start) << "-" << reinterpret_cast<void*>(insn_idx - 1); + LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start) + << "-" << reinterpret_cast<void*>(insn_idx - 1); dead_start = -1; } } if (dead_start >= 0) { - LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start) << "-" << reinterpret_cast<void*>(insn_idx - 1); + LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start) + << "-" << reinterpret_cast<void*>(insn_idx - 1); } // To dump the state of the verify after a method, do something like: // if (PrettyMethod(dex_method_idx_, *dex_file_) == @@ -1456,7 +1518,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { /* check the method signature */ const RegType& return_type = GetMethodReturnType(); if (!return_type.IsCategory1Types()) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected non-category 1 return type " << return_type; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected non-category 1 return type " + << return_type; } else { // Compilers may generate synthetic functions that write byte values into boolean fields. // Also, it may use integer values for boolean, byte, short, and character return types. @@ -1505,10 +1568,14 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { // Disallow returning uninitialized values and verify that the reference in vAA is an // instance of the "return_type" if (reg_type.IsUninitializedTypes()) { - Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "returning uninitialized object '" << reg_type << "'"; + Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "returning uninitialized object '" + << reg_type << "'"; } else if (!return_type.IsAssignableFrom(reg_type)) { - Fail(reg_type.IsUnresolvedTypes() ? VERIFY_ERROR_BAD_CLASS_SOFT : VERIFY_ERROR_BAD_CLASS_HARD) - << "returning '" << reg_type << "', but expected from declaration '" << return_type << "'"; + Fail(reg_type.IsUnresolvedTypes() ? + VERIFY_ERROR_BAD_CLASS_SOFT : + VERIFY_ERROR_BAD_CLASS_HARD) + << "returning '" << reg_type << "', but expected from declaration '" + << return_type << "'"; } } } @@ -1728,7 +1795,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { case Instruction::THROW: { const RegType& res_type = work_line_->GetRegisterType(inst->VRegA_11x()); if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(res_type)) { - Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "thrown class " << res_type << " not instanceof Throwable"; + Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "thrown class " << res_type + << " not instanceof Throwable"; } break; } @@ -1750,7 +1818,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { /* array_type can be null if the reg type is Zero */ if (!array_type.IsZero()) { if (!array_type.IsArrayTypes()) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with array type " << array_type; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with array type " + << array_type; } else { const RegType& component_type = reg_types_.GetComponentType(array_type, class_loader_); DCHECK(!component_type.IsConflict()); @@ -1790,8 +1859,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { mismatch = !reg_type1.IsIntegralTypes() || !reg_type2.IsIntegralTypes(); } if (mismatch) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to if-eq/if-ne (" << reg_type1 << "," << reg_type2 - << ") must both be references or integral"; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to if-eq/if-ne (" << reg_type1 << "," + << reg_type2 << ") must both be references or integral"; } break; } @@ -1811,7 +1880,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { case Instruction::IF_NEZ: { const RegType& reg_type = work_line_->GetRegisterType(inst->VRegA_21t()); if (!reg_type.IsReferenceTypes() && !reg_type.IsIntegralTypes()) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type << " unexpected as arg to if-eqz/if-nez"; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type + << " unexpected as arg to if-eqz/if-nez"; } // Find previous instruction - its existence is a precondition to peephole optimization. @@ -2133,7 +2203,10 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { case Instruction::INVOKE_STATIC: case Instruction::INVOKE_STATIC_RANGE: { bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE); - mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, METHOD_STATIC, is_range, false); + mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, + METHOD_STATIC, + is_range, + false); const char* descriptor; if (called_method == NULL) { uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); @@ -2155,7 +2228,10 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { case Instruction::INVOKE_INTERFACE: case Instruction::INVOKE_INTERFACE_RANGE: { bool is_range = (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE); - mirror::AbstractMethod* abs_method = VerifyInvocationArgs(inst, METHOD_INTERFACE, is_range, false); + mirror::AbstractMethod* abs_method = VerifyInvocationArgs(inst, + METHOD_INTERFACE, + is_range, + false); if (abs_method != NULL) { mirror::Class* called_interface = abs_method->GetDeclaringClass(); if (!called_interface->IsInterface() && !called_interface->IsObjectClass()) { @@ -2319,7 +2395,11 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { case Instruction::MUL_FLOAT: case Instruction::DIV_FLOAT: case Instruction::REM_FLOAT: - work_line_->CheckBinaryOp(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false); + work_line_->CheckBinaryOp(inst, + reg_types_.Float(), + reg_types_.Float(), + reg_types_.Float(), + false); break; case Instruction::ADD_DOUBLE: case Instruction::SUB_DOUBLE: @@ -2337,15 +2417,27 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { case Instruction::SHL_INT_2ADDR: case Instruction::SHR_INT_2ADDR: case Instruction::USHR_INT_2ADDR: - work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false); + work_line_->CheckBinaryOp2addr(inst, + reg_types_.Integer(), + reg_types_.Integer(), + reg_types_.Integer(), + false); break; case Instruction::AND_INT_2ADDR: case Instruction::OR_INT_2ADDR: case Instruction::XOR_INT_2ADDR: - work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true); + work_line_->CheckBinaryOp2addr(inst, + reg_types_.Integer(), + reg_types_.Integer(), + reg_types_.Integer(), + true); break; case Instruction::DIV_INT_2ADDR: - work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false); + work_line_->CheckBinaryOp2addr(inst, + reg_types_.Integer(), + reg_types_.Integer(), + reg_types_.Integer(), + false); break; case Instruction::ADD_LONG_2ADDR: case Instruction::SUB_LONG_2ADDR: @@ -2370,7 +2462,11 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { case Instruction::MUL_FLOAT_2ADDR: case Instruction::DIV_FLOAT_2ADDR: case Instruction::REM_FLOAT_2ADDR: - work_line_->CheckBinaryOp2addr(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false); + work_line_->CheckBinaryOp2addr(inst, + reg_types_.Float(), + reg_types_.Float(), + reg_types_.Float(), + false); break; case Instruction::ADD_DOUBLE_2ADDR: case Instruction::SUB_DOUBLE_2ADDR: @@ -2650,6 +2746,20 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { // Make workline consistent with fallthrough computed from peephole optimization. work_line_->CopyFromLine(fallthrough_line.get()); } + if (insn_flags_[next_insn_idx].IsReturn()) { + // For returns we only care about the operand to the return, all other registers are dead. + const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn_idx); + Instruction::Code opcode = ret_inst->Opcode(); + if ((opcode == Instruction::RETURN_VOID) || (opcode == Instruction::RETURN_VOID_BARRIER)) { + work_line_->MarkAllRegistersAsConflicts(); + } else { + if (opcode == Instruction::RETURN_WIDE) { + work_line_->MarkAllRegistersAsConflictsExceptWide(ret_inst->VRegA_11x()); + } else { + work_line_->MarkAllRegistersAsConflictsExcept(ret_inst->VRegA_11x()); + } + } + } RegisterLine* next_line = reg_table_.GetLine(next_insn_idx); if (next_line != NULL) { // Merge registers into what we have for the next instruction, @@ -3062,8 +3172,9 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instr for (size_t param_index = 0; param_index < params_size; param_index++) { if (actual_args >= expected_args) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invalid call to '" << PrettyMethod(res_method) - << "'. Expected " << expected_args << " arguments, processing argument " << actual_args - << " (where longs/doubles count twice)."; + << "'. Expected " << expected_args + << " arguments, processing argument " << actual_args + << " (where longs/doubles count twice)."; return NULL; } const char* descriptor = @@ -3216,7 +3327,8 @@ void MethodVerifier::VerifyAPut(const Instruction* inst, // The instruction agrees with the type of array, confirm the value to be stored does too // Note: we use the instruction type (rather than the component type) for aput-object as // incompatible classes will be caught at runtime as an array store exception - work_line_->VerifyRegisterType(inst->VRegA_23x(), is_primitive ? component_type : insn_type); + work_line_->VerifyRegisterType(inst->VRegA_23x(), + is_primitive ? component_type : insn_type); } } } @@ -3235,8 +3347,10 @@ mirror::Field* MethodVerifier::GetStaticField(int field_idx) { if (klass_type.IsUnresolvedTypes()) { return NULL; // Can't resolve Class so no more to do here, will do checking at runtime. } - mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_, field_idx, - dex_cache_, class_loader_); + mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_, + field_idx, + dex_cache_, + class_loader_); if (field == NULL) { LOG(INFO) << "Unable to resolve static field " << field_idx << " (" << dex_file_->GetFieldName(field_id) << ") in " @@ -3270,8 +3384,10 @@ mirror::Field* MethodVerifier::GetInstanceField(const RegType& obj_type, int fie if (klass_type.IsUnresolvedTypes()) { return NULL; // Can't resolve Class so no more to do here } - mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_, field_idx, - dex_cache_, class_loader_); + mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_, + field_idx, + dex_cache_, + class_loader_); if (field == NULL) { LOG(INFO) << "Unable to resolve instance field " << field_idx << " (" << dex_file_->GetFieldName(field_id) << ") in " @@ -3302,8 +3418,8 @@ mirror::Field* MethodVerifier::GetInstanceField(const RegType& obj_type, int fie // Field accesses through uninitialized references are only allowable for constructors where // the field is declared in this class Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "cannot access instance field " << PrettyField(field) - << " of a not fully initialized object within the context of " - << PrettyMethod(dex_method_idx_, *dex_file_); + << " of a not fully initialized object within the context" + << " of " << PrettyMethod(dex_method_idx_, *dex_file_); return NULL; } else if (!field_klass.IsAssignableFrom(obj_type)) { // Trying to access C1.field1 using reference of type C2, which is neither C1 or a sub-class @@ -3637,9 +3753,28 @@ bool MethodVerifier::UpdateRegisters(uint32_t next_insn, const RegisterLine* mer * there's nothing to "merge". Copy the registers over and mark it as changed. (This is the * only way a register can transition out of "unknown", so this is not just an optimization.) */ - target_line->CopyFromLine(merge_line); + if (!insn_flags_[next_insn].IsReturn()) { + target_line->CopyFromLine(merge_line); + } else { + // For returns we only care about the operand to the return, all other registers are dead. + // Initialize them as conflicts so they don't add to GC and deoptimization information. + const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn); + Instruction::Code opcode = ret_inst->Opcode(); + if ((opcode == Instruction::RETURN_VOID) || (opcode == Instruction::RETURN_VOID_BARRIER)) { + target_line->MarkAllRegistersAsConflicts(); + } else { + target_line->CopyFromLine(merge_line); + if (opcode == Instruction::RETURN_WIDE) { + target_line->MarkAllRegistersAsConflictsExceptWide(ret_inst->VRegA_11x()); + } else { + target_line->MarkAllRegistersAsConflictsExcept(ret_inst->VRegA_11x()); + } + } + } } else { - UniquePtr<RegisterLine> copy(gDebugVerify ? new RegisterLine(target_line->NumRegs(), this) : NULL); + UniquePtr<RegisterLine> copy(gDebugVerify ? + new RegisterLine(target_line->NumRegs(), this) : + NULL); if (gDebugVerify) { copy->CopyFromLine(target_line); } @@ -3676,7 +3811,8 @@ const RegType& MethodVerifier::GetMethodReturnType() { const RegType& MethodVerifier::GetDeclaringClass() { if (declaring_class_ == NULL) { const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_); - const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_)); + const char* descriptor + = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_)); if (mirror_method_ != NULL) { mirror::Class* klass = mirror_method_->GetDeclaringClass(); declaring_class_ = ®_types_.FromClass(descriptor, klass, @@ -3909,6 +4045,7 @@ void MethodVerifier::VerifyGcMap(const std::vector<uint8_t>& data) { } void MethodVerifier::SetDexGcMap(MethodReference ref, const std::vector<uint8_t>& gc_map) { + DCHECK(Runtime::Current()->IsCompiler()); { WriterMutexLock mu(Thread::Current(), *dex_gc_maps_lock_); DexGcMapTable::iterator it = dex_gc_maps_->find(ref); @@ -3923,6 +4060,7 @@ void MethodVerifier::SetDexGcMap(MethodReference ref, const std::vector<uint8_t> void MethodVerifier::SetSafeCastMap(MethodReference ref, const MethodSafeCastSet* cast_set) { + DCHECK(Runtime::Current()->IsCompiler()); MutexLock mu(Thread::Current(), *safecast_map_lock_); SafeCastMap::iterator it = safecast_map_->find(ref); if (it != safecast_map_->end()) { @@ -3931,10 +4069,11 @@ void MethodVerifier::SetSafeCastMap(MethodReference ref, const MethodSafeCastSe } safecast_map_->Put(ref, cast_set); - CHECK(safecast_map_->find(ref) != safecast_map_->end()); + DCHECK(safecast_map_->find(ref) != safecast_map_->end()); } bool MethodVerifier::IsSafeCast(MethodReference ref, uint32_t pc) { + DCHECK(Runtime::Current()->IsCompiler()); MutexLock mu(Thread::Current(), *safecast_map_lock_); SafeCastMap::const_iterator it = safecast_map_->find(ref); if (it == safecast_map_->end()) { @@ -3947,6 +4086,7 @@ bool MethodVerifier::IsSafeCast(MethodReference ref, uint32_t pc) { } const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(MethodReference ref) { + DCHECK(Runtime::Current()->IsCompiler()); ReaderMutexLock mu(Thread::Current(), *dex_gc_maps_lock_); DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref); if (it == dex_gc_maps_->end()) { @@ -3959,6 +4099,7 @@ const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(MethodReference ref) { void MethodVerifier::SetDevirtMap(MethodReference ref, const PcToConcreteMethodMap* devirt_map) { + DCHECK(Runtime::Current()->IsCompiler()); WriterMutexLock mu(Thread::Current(), *devirt_maps_lock_); DevirtualizationMapTable::iterator it = devirt_maps_->find(ref); if (it != devirt_maps_->end()) { @@ -3967,11 +4108,12 @@ void MethodVerifier::SetDevirtMap(MethodReference ref, } devirt_maps_->Put(ref, devirt_map); - CHECK(devirt_maps_->find(ref) != devirt_maps_->end()); + DCHECK(devirt_maps_->find(ref) != devirt_maps_->end()); } const MethodReference* MethodVerifier::GetDevirtMap(const MethodReference& ref, uint32_t dex_pc) { + DCHECK(Runtime::Current()->IsCompiler()); ReaderMutexLock mu(Thread::Current(), *devirt_maps_lock_); DevirtualizationMapTable::const_iterator it = devirt_maps_->find(ref); if (it == devirt_maps_->end()) { @@ -3979,7 +4121,8 @@ const MethodReference* MethodVerifier::GetDevirtMap(const MethodReference& ref, } // Look up the PC in the map, get the concrete method to execute and return its reference. - MethodVerifier::PcToConcreteMethodMap::const_iterator pc_to_concrete_method = it->second->find(dex_pc); + MethodVerifier::PcToConcreteMethodMap::const_iterator pc_to_concrete_method + = it->second->find(dex_pc); if (pc_to_concrete_method != it->second->end()) { return &(pc_to_concrete_method->second); } else { @@ -4031,6 +4174,24 @@ std::vector<int32_t> MethodVerifier::DescribeVRegs(uint32_t dex_pc) { return result; } +bool MethodVerifier::IsCandidateForCompilation(const DexFile::CodeItem* code_item, + const uint32_t access_flags) { + // Don't compile class initializers, ever. + if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) { + return false; + } + + const Runtime* runtime = Runtime::Current(); + if (runtime->IsSmallMode() && runtime->UseCompileTimeClassPath()) { + // In Small mode, we only compile small methods. + const uint32_t code_size = code_item->insns_size_in_code_units_; + return (code_size < runtime->GetSmallModeMethodDexSizeLimit()); + } else { + // In normal mode, we compile everything. + return true; + } +} + ReaderWriterMutex* MethodVerifier::dex_gc_maps_lock_ = NULL; MethodVerifier::DexGcMapTable* MethodVerifier::dex_gc_maps_ = NULL; @@ -4044,65 +4205,79 @@ Mutex* MethodVerifier::rejected_classes_lock_ = NULL; MethodVerifier::RejectedClassesTable* MethodVerifier::rejected_classes_ = NULL; void MethodVerifier::Init() { - dex_gc_maps_lock_ = new ReaderWriterMutex("verifier GC maps lock"); - Thread* self = Thread::Current(); - { - WriterMutexLock mu(self, *dex_gc_maps_lock_); - dex_gc_maps_ = new MethodVerifier::DexGcMapTable; - } + if (Runtime::Current()->IsCompiler()) { + dex_gc_maps_lock_ = new ReaderWriterMutex("verifier GC maps lock"); + Thread* self = Thread::Current(); + { + WriterMutexLock mu(self, *dex_gc_maps_lock_); + dex_gc_maps_ = new MethodVerifier::DexGcMapTable; + } - safecast_map_lock_ = new Mutex("verifier Cast Elision lock"); - { - MutexLock mu(self, *safecast_map_lock_); - safecast_map_ = new MethodVerifier::SafeCastMap(); - } + safecast_map_lock_ = new Mutex("verifier Cast Elision lock"); + { + MutexLock mu(self, *safecast_map_lock_); + safecast_map_ = new MethodVerifier::SafeCastMap(); + } - devirt_maps_lock_ = new ReaderWriterMutex("verifier Devirtualization lock"); + devirt_maps_lock_ = new ReaderWriterMutex("verifier Devirtualization lock"); - { - WriterMutexLock mu(self, *devirt_maps_lock_); - devirt_maps_ = new MethodVerifier::DevirtualizationMapTable(); - } + { + WriterMutexLock mu(self, *devirt_maps_lock_); + devirt_maps_ = new MethodVerifier::DevirtualizationMapTable(); + } - rejected_classes_lock_ = new Mutex("verifier rejected classes lock"); - { - MutexLock mu(self, *rejected_classes_lock_); - rejected_classes_ = new MethodVerifier::RejectedClassesTable; + rejected_classes_lock_ = new Mutex("verifier rejected classes lock"); + { + MutexLock mu(self, *rejected_classes_lock_); + rejected_classes_ = new MethodVerifier::RejectedClassesTable; + } } art::verifier::RegTypeCache::Init(); } void MethodVerifier::Shutdown() { - Thread* self = Thread::Current(); - { - WriterMutexLock mu(self, *dex_gc_maps_lock_); - STLDeleteValues(dex_gc_maps_); - delete dex_gc_maps_; - dex_gc_maps_ = NULL; - } - delete dex_gc_maps_lock_; - dex_gc_maps_lock_ = NULL; - - { - WriterMutexLock mu(self, *devirt_maps_lock_); - STLDeleteValues(devirt_maps_); - delete devirt_maps_; - devirt_maps_ = NULL; - } - delete devirt_maps_lock_; - devirt_maps_lock_ = NULL; + if (Runtime::Current()->IsCompiler()) { + Thread* self = Thread::Current(); + { + WriterMutexLock mu(self, *dex_gc_maps_lock_); + STLDeleteValues(dex_gc_maps_); + delete dex_gc_maps_; + dex_gc_maps_ = NULL; + } + delete dex_gc_maps_lock_; + dex_gc_maps_lock_ = NULL; + + { + MutexLock mu(self, *safecast_map_lock_); + STLDeleteValues(safecast_map_); + delete safecast_map_; + safecast_map_ = NULL; + } + delete safecast_map_lock_; + safecast_map_lock_ = NULL; + + { + WriterMutexLock mu(self, *devirt_maps_lock_); + STLDeleteValues(devirt_maps_); + delete devirt_maps_; + devirt_maps_ = NULL; + } + delete devirt_maps_lock_; + devirt_maps_lock_ = NULL; - { - MutexLock mu(self, *rejected_classes_lock_); - delete rejected_classes_; - rejected_classes_ = NULL; + { + MutexLock mu(self, *rejected_classes_lock_); + delete rejected_classes_; + rejected_classes_ = NULL; + } + delete rejected_classes_lock_; + rejected_classes_lock_ = NULL; } - delete rejected_classes_lock_; - rejected_classes_lock_ = NULL; verifier::RegTypeCache::ShutDown(); } void MethodVerifier::AddRejectedClass(ClassReference ref) { + DCHECK(Runtime::Current()->IsCompiler()); { MutexLock mu(Thread::Current(), *rejected_classes_lock_); rejected_classes_->insert(ref); @@ -4111,6 +4286,7 @@ void MethodVerifier::AddRejectedClass(ClassReference ref) { } bool MethodVerifier::IsClassRejected(ClassReference ref) { + DCHECK(Runtime::Current()->IsCompiler()); MutexLock mu(Thread::Current(), *rejected_classes_lock_); return (rejected_classes_->find(ref) != rejected_classes_->end()); } diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index e1bcbb19e5..3f98a00adc 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -237,6 +237,9 @@ class MethodVerifier { // Describe VRegs at the given dex pc. std::vector<int32_t> DescribeVRegs(uint32_t dex_pc); + static bool IsCandidateForCompilation(const DexFile::CodeItem* code_item, + const uint32_t access_flags); + private: // Adds the given string to the beginning of the last failure message. void PrependToLastFailMessage(std::string); @@ -654,7 +657,7 @@ class MethodVerifier { LOCKS_EXCLUDED(devirt_maps_lock_); typedef std::set<ClassReference> RejectedClassesTable; static Mutex* rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - static RejectedClassesTable* rejected_classes_; + static RejectedClassesTable* rejected_classes_ GUARDED_BY(rejected_classes_lock_); static void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_); @@ -717,6 +720,13 @@ class MethodVerifier { // Converts soft failures to hard failures when false. Only false when the compiler isn't // running and the verifier is called from the class linker. const bool allow_soft_failures_; + + // Indicates if the method being verified contains at least one check-cast instruction. + bool has_check_casts_; + + // Indicates if the method being verified contains at least one invoke-virtual/range + // or invoke-interface/range. + bool has_virtual_or_interface_invokes_; }; std::ostream& operator<<(std::ostream& os, const MethodVerifier::FailureKind& rhs); diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc index d2abaac6f7..7965c0641e 100644 --- a/runtime/verifier/register_line.cc +++ b/runtime/verifier/register_line.cc @@ -167,7 +167,7 @@ void RegisterLine::MarkRefsAsInitialized(const RegType& uninit_type) { DCHECK(uninit_type.IsUninitializedTypes()); const RegType& init_type = verifier_->GetRegTypeCache()->FromUninitialized(uninit_type); size_t changed = 0; - for (size_t i = 0; i < num_regs_; i++) { + for (uint32_t i = 0; i < num_regs_; i++) { if (GetRegisterType(i).Equals(uninit_type)) { line_[i] = init_type.GetId(); changed++; @@ -176,6 +176,31 @@ void RegisterLine::MarkRefsAsInitialized(const RegType& uninit_type) { DCHECK_GT(changed, 0u); } +void RegisterLine::MarkAllRegistersAsConflicts() { + uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId(); + for (uint32_t i = 0; i < num_regs_; i++) { + line_[i] = conflict_type_id; + } +} + +void RegisterLine::MarkAllRegistersAsConflictsExcept(uint32_t vsrc) { + uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId(); + for (uint32_t i = 0; i < num_regs_; i++) { + if (i != vsrc) { + line_[i] = conflict_type_id; + } + } +} + +void RegisterLine::MarkAllRegistersAsConflictsExceptWide(uint32_t vsrc) { + uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId(); + for (uint32_t i = 0; i < num_regs_; i++) { + if ((i != vsrc) && (i != (vsrc + 1))) { + line_[i] = conflict_type_id; + } + } +} + std::string RegisterLine::Dump() const { std::string result; for (size_t i = 0; i < num_regs_; i++) { diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h index cde7b9b0be..f3808776f2 100644 --- a/runtime/verifier/register_line.h +++ b/runtime/verifier/register_line.h @@ -141,6 +141,13 @@ class RegisterLine { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); /* + * Update all registers to be Conflict except vsrc. + */ + void MarkAllRegistersAsConflicts(); + void MarkAllRegistersAsConflictsExcept(uint32_t vsrc); + void MarkAllRegistersAsConflictsExceptWide(uint32_t vsrc); + + /* * Check constraints on constructor return. Specifically, make sure that the "this" argument got * initialized. * The "this" argument to <init> uses code offset kUninitThisArgAddr, which puts it at the start diff --git a/test/ReferenceMap/stack_walk_refmap_jni.cc b/test/ReferenceMap/stack_walk_refmap_jni.cc index 10ca5638d0..3b5d80d981 100644 --- a/test/ReferenceMap/stack_walk_refmap_jni.cc +++ b/test/ReferenceMap/stack_walk_refmap_jni.cc @@ -103,7 +103,9 @@ struct ReferenceMap2Visitor : public StackVisitor { // 0024: move-object v3, v2 // 0025: goto 0013 // Detaled dex instructions for ReferenceMap.java are at the end of this function. - CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1); // v8: this, v3: y, v2: y, v1: x + // CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1); // v8: this, v3: y, v2: y, v1: x + // We eliminate the non-live registers at a return, so only v3 is live: + CHECK_REGS_CONTAIN_REFS(3); // v3: y ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x18U))); CHECK(ref_bitmap); @@ -188,7 +190,7 @@ struct ReferenceMap2Visitor : public StackVisitor { // 0:[Unknown],1:[Reference: java.lang.Object[]],2:[Zero],3:[Reference: java.lang.Object],4:[32-bit Constant: 2],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap], // |0010: +invoke-virtual-quick {v8, v7}, [000c] // vtable #000c -// 0:[Conflict],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Reference: java.lang.Object],4:[32-bit Constant: 2],5:[Conflict],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap], +// 0:[Conflict],1:[Conflict],2:[Conflict],3:[Reference: java.lang.Object],4:[Conflict],5:[Conflict],6:[Conflict],7:[Conflict],8:[Conflict], // |0013: return-object v3 // |0014: move-exception v0 |