diff options
Diffstat (limited to 'compiler/dex/quick/gen_common.cc')
-rw-r--r-- | compiler/dex/quick/gen_common.cc | 302 |
1 files changed, 130 insertions, 172 deletions
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 2bcaaca..1813e09 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -24,12 +24,14 @@ #include "dex/mir_graph.h" #include "dex/quick/arm/arm_lir.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "entrypoints/quick/quick_entrypoints.h" #include "mirror/array.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" #include "mirror/object_reference.h" #include "utils.h" +#include "utils/dex_cache_arrays_layout-inl.h" #include "verifier/method_verifier.h" namespace art { @@ -56,6 +58,42 @@ ALWAYS_INLINE static inline bool ForceSlowTypePath(CompilationUnit* cu) { return (cu->enable_debug & (1 << kDebugSlowTypePath)) != 0; } +void Mir2Lir::GenIfNullUseHelperImmMethod( + RegStorage r_result, QuickEntrypointEnum trampoline, int imm, RegStorage r_method) { + class CallHelperImmMethodSlowPath : public LIRSlowPath { + public: + CallHelperImmMethodSlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont, + QuickEntrypointEnum trampoline_in, int imm_in, + RegStorage r_method_in, RegStorage r_result_in) + : LIRSlowPath(m2l, fromfast, cont), trampoline_(trampoline_in), + imm_(imm_in), r_method_(r_method_in), r_result_(r_result_in) { + } + + void Compile() { + GenerateTargetLabel(); + if (r_method_.Valid()) { + m2l_->CallRuntimeHelperImmReg(trampoline_, imm_, r_method_, true); + } else { + m2l_->CallRuntimeHelperImmMethod(trampoline_, imm_, true); + } + m2l_->OpRegCopy(r_result_, m2l_->TargetReg(kRet0, kRef)); + m2l_->OpUnconditionalBranch(cont_); + } + + private: + QuickEntrypointEnum trampoline_; + const int imm_; + const RegStorage r_method_; + const RegStorage r_result_; + }; + + LIR* branch = OpCmpImmBranch(kCondEq, r_result, 0, NULL); + LIR* cont = NewLIR0(kPseudoTargetLabel); + + AddSlowPath(new (arena_) CallHelperImmMethodSlowPath(this, branch, cont, trampoline, imm, + r_method, r_result)); +} + /* * Generate a kPseudoBarrier marker to indicate the boundary of special * blocks. @@ -1022,64 +1060,41 @@ void Mir2Lir::GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl } void Mir2Lir::GenConstClass(uint32_t type_idx, RegLocation rl_dest) { - RegLocation rl_method = LoadCurrMethod(); - CheckRegLocation(rl_method); - RegStorage res_reg = AllocTempRef(); + RegLocation rl_result; if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file, type_idx)) { // Call out to helper which resolves type and verifies access. // Resolved type returned in kRet0. - CallRuntimeHelperImmReg(kQuickInitializeTypeAndVerifyAccess, type_idx, rl_method.reg, true); - RegLocation rl_result = GetReturn(kRefReg); - StoreValue(rl_dest, rl_result); + CallRuntimeHelperImmMethod(kQuickInitializeTypeAndVerifyAccess, type_idx, true); + rl_result = GetReturn(kRefReg); } else { - RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true); - // We're don't need access checks, load type from dex cache - int32_t dex_cache_offset = - mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(); - LoadRefDisp(rl_method.reg, dex_cache_offset, res_reg, kNotVolatile); - int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value(); - LoadRefDisp(res_reg, offset_of_type, rl_result.reg, kNotVolatile); + rl_result = EvalLoc(rl_dest, kRefReg, true); + // We don't need access checks, load type from dex cache + RegStorage r_method = RegStorage::InvalidReg(); + if (CanUseOpPcRelDexCacheArrayLoad()) { + size_t offset = dex_cache_arrays_layout_.TypeOffset(type_idx); + OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, rl_result.reg); + } else { + RegLocation rl_method = LoadCurrMethod(); + CheckRegLocation(rl_method); + r_method = rl_method.reg; + int32_t dex_cache_offset = + mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(); + RegStorage res_reg = AllocTempRef(); + LoadRefDisp(r_method, dex_cache_offset, res_reg, kNotVolatile); + int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value(); + LoadRefDisp(res_reg, offset_of_type, rl_result.reg, kNotVolatile); + FreeTemp(res_reg); + } if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx) || ForceSlowTypePath(cu_)) { // Slow path, at runtime test if type is null and if so initialize FlushAllRegs(); - LIR* branch = OpCmpImmBranch(kCondEq, rl_result.reg, 0, NULL); - LIR* cont = NewLIR0(kPseudoTargetLabel); - - // Object to generate the slow path for class resolution. - class SlowPath : public LIRSlowPath { - public: - SlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont_in, const int type_idx_in, - const RegLocation& rl_method_in, const RegLocation& rl_result_in) - : LIRSlowPath(m2l, fromfast, cont_in), - type_idx_(type_idx_in), rl_method_(rl_method_in), rl_result_(rl_result_in) { - } - - void Compile() { - GenerateTargetLabel(); - - m2l_->CallRuntimeHelperImmReg(kQuickInitializeType, type_idx_, rl_method_.reg, true); - m2l_->OpRegCopy(rl_result_.reg, m2l_->TargetReg(kRet0, kRef)); - m2l_->OpUnconditionalBranch(cont_); - } - - private: - const int type_idx_; - const RegLocation rl_method_; - const RegLocation rl_result_; - }; - - // Add to list for future. - AddSlowPath(new (arena_) SlowPath(this, branch, cont, type_idx, rl_method, rl_result)); - - StoreValue(rl_dest, rl_result); - } else { - // Fast path, we're done - just store result - StoreValue(rl_dest, rl_result); + GenIfNullUseHelperImmMethod(rl_result.reg, kQuickInitializeType, type_idx, r_method); } } + StoreValue(rl_dest, rl_result); } void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) { @@ -1092,64 +1107,42 @@ void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) { FlushAllRegs(); LockCallTemps(); // Using explicit registers - // If the Method* is already in a register, we can save a copy. - RegLocation rl_method = mir_graph_->GetMethodLoc(); - RegStorage r_method; - if (rl_method.location == kLocPhysReg) { - // A temp would conflict with register use below. - DCHECK(!IsTemp(rl_method.reg)); - r_method = rl_method.reg; - } else { - r_method = TargetReg(kArg2, kRef); - LoadCurrMethodDirect(r_method); - } - // Method to declaring class. - LoadRefDisp(r_method, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), - TargetReg(kArg0, kRef), kNotVolatile); - // Declaring class to dex cache strings. - LoadRefDisp(TargetReg(kArg0, kRef), mirror::Class::DexCacheStringsOffset().Int32Value(), - TargetReg(kArg0, kRef), kNotVolatile); - // Might call out to helper, which will return resolved string in kRet0 - LoadRefDisp(TargetReg(kArg0, kRef), offset_of_string, TargetReg(kRet0, kRef), kNotVolatile); - LIR* fromfast = OpCmpImmBranch(kCondEq, TargetReg(kRet0, kRef), 0, NULL); - LIR* cont = NewLIR0(kPseudoTargetLabel); - - { - // Object to generate the slow path for string resolution. - class SlowPath : public LIRSlowPath { - public: - SlowPath(Mir2Lir* m2l, LIR* fromfast_in, LIR* cont_in, RegStorage r_method_in, - int32_t string_idx_in) - : LIRSlowPath(m2l, fromfast_in, cont_in), - r_method_(r_method_in), string_idx_(string_idx_in) { - } - - void Compile() { - GenerateTargetLabel(); - m2l_->CallRuntimeHelperImmReg(kQuickResolveString, string_idx_, r_method_, true); - m2l_->OpUnconditionalBranch(cont_); - } - - private: - const RegStorage r_method_; - const int32_t string_idx_; - }; - - AddSlowPath(new (arena_) SlowPath(this, fromfast, cont, r_method, string_idx)); + RegStorage ret0 = TargetReg(kRet0, kRef); + RegStorage r_method = RegStorage::InvalidReg(); + if (CanUseOpPcRelDexCacheArrayLoad()) { + size_t offset = dex_cache_arrays_layout_.StringOffset(string_idx); + OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, ret0); + } else { + r_method = LoadCurrMethodWithHint(TargetReg(kArg1, kRef)); + // Method to declaring class. + RegStorage arg0 = TargetReg(kArg0, kRef); + LoadRefDisp(r_method, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), + arg0, kNotVolatile); + // Declaring class to dex cache strings. + LoadRefDisp(arg0, mirror::Class::DexCacheStringsOffset().Int32Value(), arg0, kNotVolatile); + + LoadRefDisp(arg0, offset_of_string, ret0, kNotVolatile); } + GenIfNullUseHelperImmMethod(ret0, kQuickResolveString, string_idx, r_method); GenBarrier(); StoreValue(rl_dest, GetReturn(kRefReg)); } else { - RegLocation rl_method = LoadCurrMethod(); - RegStorage res_reg = AllocTempRef(); RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true); - LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), res_reg, - kNotVolatile); - LoadRefDisp(res_reg, mirror::Class::DexCacheStringsOffset().Int32Value(), res_reg, - kNotVolatile); - LoadRefDisp(res_reg, offset_of_string, rl_result.reg, kNotVolatile); + if (CanUseOpPcRelDexCacheArrayLoad()) { + size_t offset = dex_cache_arrays_layout_.StringOffset(string_idx); + OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, rl_result.reg); + } else { + RegLocation rl_method = LoadCurrMethod(); + RegStorage res_reg = AllocTempRef(); + LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), res_reg, + kNotVolatile); + LoadRefDisp(res_reg, mirror::Class::DexCacheStringsOffset().Int32Value(), res_reg, + kNotVolatile); + LoadRefDisp(res_reg, offset_of_string, rl_result.reg, kNotVolatile); + FreeTemp(res_reg); + } StoreValue(rl_dest, rl_result); } } @@ -1224,14 +1217,20 @@ void Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, Re RegStorage check_class = AllocTypedTemp(false, kRefReg); RegStorage object_class = AllocTypedTemp(false, kRefReg); - LoadCurrMethodDirect(check_class); if (use_declaring_class) { - LoadRefDisp(check_class, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), check_class, + RegStorage r_method = LoadCurrMethodWithHint(check_class); + LoadRefDisp(r_method, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), check_class, + kNotVolatile); + LoadRefDisp(object.reg, mirror::Object::ClassOffset().Int32Value(), object_class, kNotVolatile); + } else if (CanUseOpPcRelDexCacheArrayLoad()) { + size_t offset = dex_cache_arrays_layout_.TypeOffset(type_idx); + OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, check_class); LoadRefDisp(object.reg, mirror::Object::ClassOffset().Int32Value(), object_class, kNotVolatile); } else { - LoadRefDisp(check_class, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), + RegStorage r_method = LoadCurrMethodWithHint(check_class); + LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), check_class, kNotVolatile); LoadRefDisp(object.reg, mirror::Object::ClassOffset().Int32Value(), object_class, kNotVolatile); @@ -1267,20 +1266,19 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know FlushAllRegs(); // May generate a call - use explicit registers LockCallTemps(); - RegStorage method_reg = TargetReg(kArg1, kRef); - LoadCurrMethodDirect(method_reg); // kArg1 <= current Method* RegStorage class_reg = TargetReg(kArg2, kRef); // kArg2 will hold the Class* RegStorage ref_reg = TargetReg(kArg0, kRef); // kArg0 will hold the ref. RegStorage ret_reg = GetReturn(kRefReg).reg; if (needs_access_check) { // Check we have access to type_idx and if not throw IllegalAccessError, // returns Class* in kArg0 - CallRuntimeHelperImm(kQuickInitializeTypeAndVerifyAccess, type_idx, true); + CallRuntimeHelperImmMethod(kQuickInitializeTypeAndVerifyAccess, type_idx, true); OpRegCopy(class_reg, ret_reg); // Align usage with fast path LoadValueDirectFixed(rl_src, ref_reg); // kArg0 <= ref } else if (use_declaring_class) { + RegStorage r_method = LoadCurrMethodWithHint(TargetReg(kArg1, kRef)); LoadValueDirectFixed(rl_src, ref_reg); // kArg0 <= ref - LoadRefDisp(method_reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), + LoadRefDisp(r_method, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg, kNotVolatile); } else { if (can_assume_type_is_in_dex_cache) { @@ -1288,42 +1286,23 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know LoadValueDirectFixed(rl_src, ref_reg); // kArg0 <= ref } - // Load dex cache entry into class_reg (kArg2) - LoadRefDisp(method_reg, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), - class_reg, kNotVolatile); - int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value(); - LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile); + RegStorage r_method = RegStorage::InvalidReg(); + if (CanUseOpPcRelDexCacheArrayLoad()) { + size_t offset = dex_cache_arrays_layout_.TypeOffset(type_idx); + OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, class_reg); + } else { + r_method = LoadCurrMethodWithHint(TargetReg(kArg1, kRef)); + // Load dex cache entry into class_reg (kArg2) + LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), + class_reg, kNotVolatile); + int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value(); + LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile); + } if (!can_assume_type_is_in_dex_cache) { - LIR* slow_path_branch = OpCmpImmBranch(kCondEq, class_reg, 0, NULL); - LIR* slow_path_target = NewLIR0(kPseudoTargetLabel); + GenIfNullUseHelperImmMethod(class_reg, kQuickInitializeType, type_idx, r_method); // Should load value here. LoadValueDirectFixed(rl_src, ref_reg); // kArg0 <= ref - - class InitTypeSlowPath : public Mir2Lir::LIRSlowPath { - public: - InitTypeSlowPath(Mir2Lir* m2l, LIR* branch, LIR* cont, uint32_t type_idx_in, - RegLocation rl_src_in) - : LIRSlowPath(m2l, branch, cont), type_idx_(type_idx_in), - rl_src_(rl_src_in) { - } - - void Compile() OVERRIDE { - GenerateTargetLabel(); - - m2l_->CallRuntimeHelperImm(kQuickInitializeType, type_idx_, true); - m2l_->OpRegCopy(m2l_->TargetReg(kArg2, kRef), - m2l_->TargetReg(kRet0, kRef)); // Align usage with fast path - m2l_->OpUnconditionalBranch(cont_); - } - - private: - uint32_t type_idx_; - RegLocation rl_src_; - }; - - AddSlowPath(new (arena_) InitTypeSlowPath(this, slow_path_branch, slow_path_target, - type_idx, rl_src)); } } /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */ @@ -1426,55 +1405,34 @@ void Mir2Lir::GenCheckCast(int opt_flags, uint32_t insn_idx, uint32_t type_idx, FlushAllRegs(); // May generate a call - use explicit registers LockCallTemps(); - RegStorage method_reg = TargetReg(kArg1, kRef); - LoadCurrMethodDirect(method_reg); // kArg1 <= current Method* RegStorage class_reg = TargetReg(kArg2, kRef); // kArg2 will hold the Class* if (needs_access_check) { // Check we have access to type_idx and if not throw IllegalAccessError, // returns Class* in kRet0 // InitializeTypeAndVerifyAccess(idx, method) - CallRuntimeHelperImm(kQuickInitializeTypeAndVerifyAccess, type_idx, true); + CallRuntimeHelperImmMethod(kQuickInitializeTypeAndVerifyAccess, type_idx, true); OpRegCopy(class_reg, TargetReg(kRet0, kRef)); // Align usage with fast path } else if (use_declaring_class) { + RegStorage method_reg = LoadCurrMethodWithHint(TargetReg(kArg1, kRef)); LoadRefDisp(method_reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg, kNotVolatile); } else { // Load dex cache entry into class_reg (kArg2) - LoadRefDisp(method_reg, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), - class_reg, kNotVolatile); - int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value(); - LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile); + RegStorage r_method = RegStorage::InvalidReg(); + if (CanUseOpPcRelDexCacheArrayLoad()) { + size_t offset = dex_cache_arrays_layout_.TypeOffset(type_idx); + OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, class_reg); + } else { + r_method = LoadCurrMethodWithHint(TargetReg(kArg1, kRef)); + + LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), + class_reg, kNotVolatile); + int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value(); + LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile); + } if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx)) { // Need to test presence of type in dex cache at runtime - LIR* hop_branch = OpCmpImmBranch(kCondEq, class_reg, 0, NULL); - LIR* cont = NewLIR0(kPseudoTargetLabel); - - // Slow path to initialize the type. Executed if the type is NULL. - class SlowPath : public LIRSlowPath { - public: - SlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont_in, const int type_idx_in, - const RegStorage class_reg_in) - : LIRSlowPath(m2l, fromfast, cont_in), - type_idx_(type_idx_in), class_reg_(class_reg_in) { - } - - void Compile() { - GenerateTargetLabel(); - - // Call out to helper, which will return resolved type in kArg0 - // InitializeTypeFromCode(idx, method) - m2l_->CallRuntimeHelperImmReg(kQuickInitializeType, type_idx_, - m2l_->TargetReg(kArg1, kRef), true); - m2l_->OpRegCopy(class_reg_, m2l_->TargetReg(kRet0, kRef)); // Align usage with fast path - m2l_->OpUnconditionalBranch(cont_); - } - - public: - const int type_idx_; - const RegStorage class_reg_; - }; - - AddSlowPath(new (arena_) SlowPath(this, hop_branch, cont, type_idx, class_reg)); + GenIfNullUseHelperImmMethod(class_reg, kQuickInitializeType, type_idx, r_method); } } // At this point, class_reg (kArg2) has class |