diff options
Diffstat (limited to 'compiler')
32 files changed, 828 insertions, 334 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index 09be437..dab28bc 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -24,6 +24,7 @@ #include "dex/quick/dex_file_to_method_inliner_map.h" #include "dex/verification_results.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "interpreter/interpreter.h" #include "mirror/art_method.h" #include "mirror/dex_cache.h" diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index d6a07f6..2386914 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -185,6 +185,7 @@ enum LinkerPatchType { kLinkerPatchCall, kLinkerPatchCallRelative, // NOTE: Actual patching is instruction_set-dependent. kLinkerPatchType, + kLinkerPatchDexCacheArray, // NOTE: Actual patching is instruction_set-dependent. }; class LinkerPatch { @@ -192,28 +193,44 @@ class LinkerPatch { static LinkerPatch MethodPatch(size_t literal_offset, const DexFile* target_dex_file, uint32_t target_method_idx) { - return LinkerPatch(literal_offset, kLinkerPatchMethod, - target_method_idx, target_dex_file); + LinkerPatch patch(literal_offset, kLinkerPatchMethod, target_dex_file); + patch.method_idx_ = target_method_idx; + return patch; } static LinkerPatch CodePatch(size_t literal_offset, const DexFile* target_dex_file, uint32_t target_method_idx) { - return LinkerPatch(literal_offset, kLinkerPatchCall, - target_method_idx, target_dex_file); + LinkerPatch patch(literal_offset, kLinkerPatchCall, target_dex_file); + patch.method_idx_ = target_method_idx; + return patch; } static LinkerPatch RelativeCodePatch(size_t literal_offset, const DexFile* target_dex_file, uint32_t target_method_idx) { - return LinkerPatch(literal_offset, kLinkerPatchCallRelative, - target_method_idx, target_dex_file); + LinkerPatch patch(literal_offset, kLinkerPatchCallRelative, target_dex_file); + patch.method_idx_ = target_method_idx; + return patch; } static LinkerPatch TypePatch(size_t literal_offset, const DexFile* target_dex_file, uint32_t target_type_idx) { - return LinkerPatch(literal_offset, kLinkerPatchType, target_type_idx, target_dex_file); + LinkerPatch patch(literal_offset, kLinkerPatchType, target_dex_file); + patch.type_idx_ = target_type_idx; + return patch; + } + + static LinkerPatch DexCacheArrayPatch(size_t literal_offset, + const DexFile* target_dex_file, + uint32_t pc_insn_offset, + size_t element_offset) { + DCHECK(IsUint<32>(element_offset)); + LinkerPatch patch(literal_offset, kLinkerPatchDexCacheArray, target_dex_file); + patch.pc_insn_offset_ = pc_insn_offset; + patch.element_offset_ = element_offset; + return patch; } LinkerPatch(const LinkerPatch& other) = default; @@ -227,10 +244,14 @@ class LinkerPatch { return patch_type_; } + bool IsPcRelative() const { + return Type() == kLinkerPatchCallRelative || Type() == kLinkerPatchDexCacheArray; + } + MethodReference TargetMethod() const { DCHECK(patch_type_ == kLinkerPatchMethod || patch_type_ == kLinkerPatchCall || patch_type_ == kLinkerPatchCallRelative); - return MethodReference(target_dex_file_, target_idx_); + return MethodReference(target_dex_file_, method_idx_); } const DexFile* TargetTypeDexFile() const { @@ -240,22 +261,52 @@ class LinkerPatch { uint32_t TargetTypeIndex() const { DCHECK(patch_type_ == kLinkerPatchType); - return target_idx_; + return type_idx_; + } + + const DexFile* TargetDexCacheDexFile() const { + DCHECK(patch_type_ == kLinkerPatchDexCacheArray); + return target_dex_file_; + } + + size_t TargetDexCacheElementOffset() const { + DCHECK(patch_type_ == kLinkerPatchDexCacheArray); + return element_offset_; + } + + uint32_t PcInsnOffset() const { + DCHECK(patch_type_ == kLinkerPatchDexCacheArray); + return pc_insn_offset_; } private: - LinkerPatch(size_t literal_offset, LinkerPatchType patch_type, - uint32_t target_idx, const DexFile* target_dex_file) - : literal_offset_(literal_offset), - patch_type_(patch_type), - target_idx_(target_idx), - target_dex_file_(target_dex_file) { + LinkerPatch(size_t literal_offset, LinkerPatchType patch_type, const DexFile* target_dex_file) + : target_dex_file_(target_dex_file), + literal_offset_(literal_offset), + patch_type_(patch_type) { + cmp1_ = 0u; + cmp2_ = 0u; + // The compiler rejects methods that are too big, so the compiled code + // of a single method really shouln't be anywhere close to 16MiB. + DCHECK(IsUint<24>(literal_offset)); } - size_t literal_offset_; - LinkerPatchType patch_type_; - uint32_t target_idx_; // Method index (Call/Method patches) or type index (Type patches). const DexFile* target_dex_file_; + uint32_t literal_offset_ : 24; // Method code size up to 16MiB. + LinkerPatchType patch_type_ : 8; + union { + uint32_t cmp1_; // Used for relational operators. + uint32_t method_idx_; // Method index for Call/Method patches. + uint32_t type_idx_; // Type index for Type patches. + uint32_t element_offset_; // Element offset in the dex cache arrays. + }; + union { + uint32_t cmp2_; // Used for relational operators. + // Literal offset of the insn loading PC (same as literal_offset if it's the same insn, + // may be different if the PC-relative addressing needs multiple insns). + uint32_t pc_insn_offset_; + static_assert(sizeof(pc_insn_offset_) == sizeof(cmp2_), "needed by relational operators"); + }; friend bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs); friend bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs); @@ -264,15 +315,17 @@ class LinkerPatch { inline bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs) { return lhs.literal_offset_ == rhs.literal_offset_ && lhs.patch_type_ == rhs.patch_type_ && - lhs.target_idx_ == rhs.target_idx_ && - lhs.target_dex_file_ == rhs.target_dex_file_; + lhs.target_dex_file_ == rhs.target_dex_file_ && + lhs.cmp1_ == rhs.cmp1_ && + lhs.cmp2_ == rhs.cmp2_; } inline bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs) { return (lhs.literal_offset_ != rhs.literal_offset_) ? lhs.literal_offset_ < rhs.literal_offset_ : (lhs.patch_type_ != rhs.patch_type_) ? lhs.patch_type_ < rhs.patch_type_ - : (lhs.target_idx_ != rhs.target_idx_) ? lhs.target_idx_ < rhs.target_idx_ - : lhs.target_dex_file_ < rhs.target_dex_file_; + : (lhs.target_dex_file_ != rhs.target_dex_file_) ? lhs.target_dex_file_ < rhs.target_dex_file_ + : (lhs.cmp1_ != rhs.cmp1_) ? lhs.cmp1_ < rhs.cmp1_ + : lhs.cmp2_ < rhs.cmp2_; } class CompiledMethod FINAL : public CompiledCode { diff --git a/compiler/dex/mir_field_info.cc b/compiler/dex/mir_field_info.cc index d2079a2..a9ab3bb 100644 --- a/compiler/dex/mir_field_info.cc +++ b/compiler/dex/mir_field_info.cc @@ -19,6 +19,7 @@ #include <string.h> #include "base/logging.h" +#include "dex/verified_method.h" #include "driver/compiler_driver.h" #include "driver/compiler_driver-inl.h" #include "mirror/class_loader.h" // Only to allow casts in Handle<ClassLoader>. diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index 3103f96..58f12c9 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -688,7 +688,7 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, DexOffse /* Parse a Dex method and insert it into the MIRGraph at the current insert point. */ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint16_t class_def_idx, + InvokeType invoke_type ATTRIBUTE_UNUSED, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file) { current_code_item_ = code_item; method_stack_.push_back(std::make_pair(current_method_, current_offset_)); @@ -726,13 +726,6 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_ null_block->hidden = true; entry_block_ = CreateNewBB(kEntryBlock); exit_block_ = CreateNewBB(kExitBlock); - // TODO: deprecate all "cu->" fields; move what's left to wherever CompilationUnit is allocated. - cu_->dex_file = &dex_file; - cu_->class_def_idx = class_def_idx; - cu_->method_idx = method_idx; - cu_->access_flags = access_flags; - cu_->invoke_type = invoke_type; - cu_->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); } else { UNIMPLEMENTED(FATAL) << "Nested inlining not implemented."; /* diff --git a/compiler/dex/mir_method_info.cc b/compiler/dex/mir_method_info.cc index 34fb1bf..831ad42 100644 --- a/compiler/dex/mir_method_info.cc +++ b/compiler/dex/mir_method_info.cc @@ -16,9 +16,11 @@ # include "mir_method_info.h" +#include "dex/verified_method.h" #include "driver/compiler_driver.h" #include "driver/dex_compilation_unit.h" #include "driver/compiler_driver-inl.h" +#include "driver/compiler_options.h" #include "mirror/class_loader.h" // Only to allow casts in Handle<ClassLoader>. #include "mirror/dex_cache.h" // Only to allow casts in Handle<DexCache>. #include "scoped_thread_state_change.h" diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index d46c25a..3081c9e 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -23,6 +23,7 @@ #include "dex/mir_graph.h" #include "dex/quick/mir_to_lir-inl.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "gc/accounting/card_table.h" #include "mirror/art_method.h" #include "mirror/object_array-inl.h" diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h index d15412a..f6fa938 100644 --- a/compiler/dex/quick/arm64/arm64_lir.h +++ b/compiler/dex/quick/arm64/arm64_lir.h @@ -236,6 +236,7 @@ enum A64Opcode { kA64Add4rrro, // add [00001011000] rm[20-16] imm_6[15-10] rn[9-5] rd[4-0]. kA64Add4RRre, // add [00001011001] rm[20-16] option[15-13] imm_3[12-10] rn[9-5] rd[4-0]. kA64Adr2xd, // adr [0] immlo[30-29] [10000] immhi[23-5] rd[4-0]. + kA64Adrp2xd, // adrp [1] immlo[30-29] [10000] immhi[23-5] rd[4-0]. kA64And3Rrl, // and [00010010] N[22] imm_r[21-16] imm_s[15-10] rn[9-5] rd[4-0]. kA64And4rrro, // and [00001010] shift[23-22] [N=0] rm[20-16] imm_6[15-10] rn[9-5] rd[4-0]. kA64Asr3rrd, // asr [0001001100] immr[21-16] imms[15-10] rn[9-5] rd[4-0]. diff --git a/compiler/dex/quick/arm64/assemble_arm64.cc b/compiler/dex/quick/arm64/assemble_arm64.cc index 329bb1e..a59deb5 100644 --- a/compiler/dex/quick/arm64/assemble_arm64.cc +++ b/compiler/dex/quick/arm64/assemble_arm64.cc @@ -131,6 +131,10 @@ const A64EncodingMap Arm64Mir2Lir::EncodingMap[kA64Last] = { kFmtRegX, 4, 0, kFmtImm21, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | NEEDS_FIXUP, "adr", "!0x, #!1d", kFixupAdr), + ENCODING_MAP(kA64Adrp2xd, NO_VARIANTS(0x90000000), + kFmtRegX, 4, 0, kFmtImm21, -1, -1, kFmtUnused, -1, -1, + kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0 | NEEDS_FIXUP, + "adrp", "!0x, #!1d", kFixupLabel), ENCODING_MAP(WIDE(kA64And3Rrl), SF_VARIANTS(0x12000000), kFmtRegROrSp, 4, 0, kFmtRegR, 9, 5, kFmtBitBlt, 22, 10, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc index 823cb60..3316945 100644 --- a/compiler/dex/quick/arm64/call_arm64.cc +++ b/compiler/dex/quick/arm64/call_arm64.cc @@ -23,10 +23,12 @@ #include "dex/mir_graph.h" #include "dex/quick/mir_to_lir-inl.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "gc/accounting/card_table.h" #include "entrypoints/quick/quick_entrypoints.h" #include "mirror/art_method.h" #include "mirror/object_array-inl.h" +#include "utils/dex_cache_arrays_layout-inl.h" namespace art { @@ -438,13 +440,13 @@ static bool Arm64UseRelativeCall(CompilationUnit* cu, const MethodReference& tar * Bit of a hack here - in the absence of a real scheduling pass, * emit the next instruction in static & direct invoke sequences. */ -static int Arm64NextSDCallInsn(CompilationUnit* cu, CallInfo* info, - int state, const MethodReference& target_method, - uint32_t unused_idx, - uintptr_t direct_code, uintptr_t direct_method, - InvokeType type) { +int Arm64Mir2Lir::Arm64NextSDCallInsn(CompilationUnit* cu, CallInfo* info, + int state, const MethodReference& target_method, + uint32_t unused_idx, + uintptr_t direct_code, uintptr_t direct_method, + InvokeType type) { UNUSED(info, unused_idx); - Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get()); + Arm64Mir2Lir* cg = static_cast<Arm64Mir2Lir*>(cu->cg.get()); if (direct_code != 0 && direct_method != 0) { switch (state) { case 0: // Get the current Method* [sets kArg0] @@ -465,17 +467,24 @@ static int Arm64NextSDCallInsn(CompilationUnit* cu, CallInfo* info, return -1; } } else { + bool use_pc_rel = cg->CanUseOpPcRelDexCacheArrayLoad(); RegStorage arg0_ref = cg->TargetReg(kArg0, kRef); switch (state) { case 0: // Get the current Method* [sets kArg0] // TUNING: we can save a reg copy if Method* has been promoted. - cg->LoadCurrMethodDirect(arg0_ref); - break; + if (!use_pc_rel) { + cg->LoadCurrMethodDirect(arg0_ref); + break; + } + ++state; + FALLTHROUGH_INTENDED; case 1: // Get method->dex_cache_resolved_methods_ - cg->LoadRefDisp(arg0_ref, - mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(), - arg0_ref, - kNotVolatile); + if (!use_pc_rel) { + cg->LoadRefDisp(arg0_ref, + mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(), + arg0_ref, + kNotVolatile); + } // Set up direct code if known. if (direct_code != 0) { if (direct_code != static_cast<uintptr_t>(-1)) { @@ -487,14 +496,23 @@ static int Arm64NextSDCallInsn(CompilationUnit* cu, CallInfo* info, cg->LoadCodeAddress(target_method, type, kInvokeTgt); } } - break; + if (!use_pc_rel || direct_code != 0) { + break; + } + ++state; + FALLTHROUGH_INTENDED; case 2: // Grab target method* CHECK_EQ(cu->dex_file, target_method.dex_file); - cg->LoadRefDisp(arg0_ref, - mirror::ObjectArray<mirror::Object>::OffsetOfElement( - target_method.dex_method_index).Int32Value(), - arg0_ref, - kNotVolatile); + if (!use_pc_rel) { + cg->LoadRefDisp(arg0_ref, + mirror::ObjectArray<mirror::Object>::OffsetOfElement( + target_method.dex_method_index).Int32Value(), + arg0_ref, + kNotVolatile); + } else { + size_t offset = cg->dex_cache_arrays_layout_.MethodOffset(target_method.dex_method_index); + cg->OpPcRelDexCacheArrayLoad(cu->dex_file, offset, arg0_ref); + } break; case 3: // Grab the code from the method* if (direct_code == 0) { diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h index 54fd46d..8184f02 100644 --- a/compiler/dex/quick/arm64/codegen_arm64.h +++ b/compiler/dex/quick/arm64/codegen_arm64.h @@ -78,6 +78,9 @@ class Arm64Mir2Lir FINAL : public Mir2Lir { /// @copydoc Mir2Lir::UnconditionallyMarkGCCard(RegStorage) void UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) OVERRIDE; + bool CanUseOpPcRelDexCacheArrayLoad() const OVERRIDE; + void OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset, RegStorage r_dest) OVERRIDE; + LIR* OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg, int offset, int check_value, LIR* target, LIR** compare) OVERRIDE; @@ -393,9 +396,16 @@ class Arm64Mir2Lir FINAL : public Mir2Lir { void GenDivRemLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2, bool is_div, int flags); + static int Arm64NextSDCallInsn(CompilationUnit* cu, CallInfo* info, + int state, const MethodReference& target_method, + uint32_t unused_idx, + uintptr_t direct_code, uintptr_t direct_method, + InvokeType type); + static const A64EncodingMap EncodingMap[kA64Last]; ArenaVector<LIR*> call_method_insns_; + ArenaVector<LIR*> dex_cache_access_insns_; int GenDalvikArgsBulkCopy(CallInfo* info, int first, int count) OVERRIDE; }; diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc index 2372ccc..e9b9b5d 100644 --- a/compiler/dex/quick/arm64/int_arm64.cc +++ b/compiler/dex/quick/arm64/int_arm64.cc @@ -18,6 +18,7 @@ #include "codegen_arm64.h" +#include "arch/arm64/instruction_set_features_arm64.h" #include "arch/instruction_set_features.h" #include "arm64_lir.h" #include "base/logging.h" @@ -943,6 +944,28 @@ void Arm64Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) { lir->target = target; } +bool Arm64Mir2Lir::CanUseOpPcRelDexCacheArrayLoad() const { + if (cu_->compiler_driver->GetInstructionSetFeatures()->AsArm64InstructionSetFeatures() + ->NeedFixCortexA53_843419()) { + // TODO: Implement link-time workaround in OatWriter so that we can use ADRP on Cortex-A53. + return false; + } + return dex_cache_arrays_layout_.Valid(); +} + +void Arm64Mir2Lir::OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset, + RegStorage r_dest) { + LIR* adrp = NewLIR2(kA64Adrp2xd, r_dest.GetReg(), 0); + adrp->operands[2] = WrapPointer(dex_file); + adrp->operands[3] = offset; + adrp->operands[4] = WrapPointer(adrp); + dex_cache_access_insns_.push_back(adrp); + LIR* ldr = LoadBaseDisp(r_dest, 0, r_dest, kReference, kNotVolatile); + ldr->operands[4] = adrp->operands[4]; + ldr->flags.fixup = kFixupLabel; + dex_cache_access_insns_.push_back(ldr); +} + LIR* Arm64Mir2Lir::OpVldm(RegStorage r_base, int count) { UNUSED(r_base, count); LOG(FATAL) << "Unexpected use of OpVldm for Arm64"; diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc index 09a34bf..c5c0dc5 100644 --- a/compiler/dex/quick/arm64/target_arm64.cc +++ b/compiler/dex/quick/arm64/target_arm64.cc @@ -606,7 +606,8 @@ RegisterClass Arm64Mir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volat Arm64Mir2Lir::Arm64Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena) : Mir2Lir(cu, mir_graph, arena), - call_method_insns_(arena->Adapter()) { + call_method_insns_(arena->Adapter()), + dex_cache_access_insns_(arena->Adapter()) { // Sanity check - make sure encoding map lines up. for (int i = 0; i < kA64Last; i++) { DCHECK_EQ(UNWIDE(Arm64Mir2Lir::EncodingMap[i].opcode), i) @@ -846,8 +847,9 @@ RegStorage Arm64Mir2Lir::InToRegStorageArm64Mapper::GetNextReg(ShortyArg arg) { } void Arm64Mir2Lir::InstallLiteralPools() { + patches_.reserve(call_method_insns_.size() + dex_cache_access_insns_.size()); + // PC-relative calls to methods. - patches_.reserve(call_method_insns_.size()); for (LIR* p : call_method_insns_) { DCHECK_EQ(p->opcode, kA64Bl1t); uint32_t target_method_idx = p->operands[1]; @@ -856,6 +858,18 @@ void Arm64Mir2Lir::InstallLiteralPools() { target_dex_file, target_method_idx)); } + // PC-relative references to dex cache arrays. + for (LIR* p : dex_cache_access_insns_) { + DCHECK(p->opcode == kA64Adrp2xd || p->opcode == kA64Ldr3rXD); + const LIR* adrp = UnwrapPointer<LIR>(p->operands[4]); + DCHECK_EQ(adrp->opcode, kA64Adrp2xd); + const DexFile* dex_file = UnwrapPointer<DexFile>(adrp->operands[2]); + uint32_t offset = adrp->operands[3]; + DCHECK(!p->flags.is_nop); + DCHECK(!adrp->flags.is_nop); + patches_.push_back(LinkerPatch::DexCacheArrayPatch(p->offset, dex_file, adrp->offset, offset)); + } + // And do the normal processing. Mir2Lir::InstallLiteralPools(); } diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index df72830..509d448 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -29,6 +29,7 @@ #include "dex/quick/dex_file_to_method_inliner_map.h" #include "dex/verification_results.h" #include "dex/verified_method.h" +#include "utils/dex_cache_arrays_layout-inl.h" #include "verifier/dex_gc_map.h" #include "verifier/method_verifier.h" #include "vmap_table.h" @@ -1053,6 +1054,7 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena mem_ref_type_(ResourceMask::kHeapRef), mask_cache_(arena), safepoints_(arena->Adapter()), + dex_cache_arrays_layout_(cu->compiler_driver->GetDexCacheArraysLayout(cu->dex_file)), in_to_reg_storage_mapping_(arena) { switch_tables_.reserve(4); fill_array_data_.reserve(4); @@ -1304,6 +1306,17 @@ void Mir2Lir::LoadClassType(const DexFile& dex_file, uint32_t type_idx, OpPcRelLoad(TargetReg(symbolic_reg, kRef), data_target); } +bool Mir2Lir::CanUseOpPcRelDexCacheArrayLoad() const { + return false; +} + +void Mir2Lir::OpPcRelDexCacheArrayLoad(const DexFile* dex_file ATTRIBUTE_UNUSED, + int offset ATTRIBUTE_UNUSED, + RegStorage r_dest ATTRIBUTE_UNUSED) { + LOG(FATAL) << "No generic implementation."; + UNREACHABLE(); +} + std::vector<uint8_t>* Mir2Lir::ReturnFrameDescriptionEntry() { // Default case is to do nothing. return nullptr; 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 diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 2d41ba1..e747239 100755 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -24,6 +24,7 @@ #include "dex/quick/dex_file_to_method_inliner_map.h" #include "dex_file-inl.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "entrypoints/quick/quick_entrypoints.h" #include "invoke_type.h" #include "mirror/array.h" diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc index b71691f..54e5742 100644 --- a/compiler/dex/quick/gen_loadstore.cc +++ b/compiler/dex/quick/gen_loadstore.cc @@ -340,6 +340,20 @@ void Mir2Lir::LoadCurrMethodDirect(RegStorage r_tgt) { LoadValueDirectFixed(mir_graph_->GetMethodLoc(), r_tgt); } +RegStorage Mir2Lir::LoadCurrMethodWithHint(RegStorage r_hint) { + // If the method is promoted to a register, return that register, otherwise load it to r_hint. + // (Replacement for LoadCurrMethod() usually used when LockCallTemps() is in effect.) + DCHECK(r_hint.Valid()); + RegLocation rl_method = mir_graph_->GetMethodLoc(); + if (rl_method.location == kLocPhysReg) { + DCHECK(!IsTemp(rl_method.reg)); + return rl_method.reg; + } else { + LoadCurrMethodDirect(r_hint); + return r_hint; + } +} + RegLocation Mir2Lir::LoadCurrMethod() { return LoadValue(mir_graph_->GetMethodLoc(), kRefReg); } diff --git a/compiler/dex/quick/local_optimizations.cc b/compiler/dex/quick/local_optimizations.cc index e573899..6cdf567 100644 --- a/compiler/dex/quick/local_optimizations.cc +++ b/compiler/dex/quick/local_optimizations.cc @@ -493,15 +493,14 @@ void Mir2Lir::ApplyLoadHoisting(LIR* head_lir, LIR* tail_lir) { /* Found a slot to hoist to */ if (slot >= 0) { LIR* cur_lir = prev_inst_list[slot]; - LIR* new_load_lir = - static_cast<LIR*>(arena_->Alloc(sizeof(LIR), kArenaAllocLIR)); - *new_load_lir = *this_lir; + LIR* prev_lir = PREV_LIR(this_lir); + UnlinkLIR(this_lir); /* * Insertion is guaranteed to succeed since check_lir * is never the first LIR on the list */ - InsertLIRBefore(cur_lir, new_load_lir); - NopLIR(this_lir); + InsertLIRBefore(cur_lir, this_lir); + this_lir = prev_lir; // Continue the loop with the next LIR. } } } diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index cca4e5a..bb8fbae 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -32,6 +32,7 @@ #include "leb128.h" #include "safe_map.h" #include "utils/array_ref.h" +#include "utils/dex_cache_arrays_layout.h" #include "utils/stack_checks.h" namespace art { @@ -956,6 +957,7 @@ class Mir2Lir { // Shared by all targets - implemented in gen_loadstore.cc. RegLocation LoadCurrMethod(); void LoadCurrMethodDirect(RegStorage r_tgt); + RegStorage LoadCurrMethodWithHint(RegStorage r_hint); virtual LIR* LoadConstant(RegStorage r_dest, int value); // Natural word size. LIR* LoadWordDisp(RegStorage r_base, int displacement, RegStorage r_dest) { @@ -1093,6 +1095,18 @@ class Mir2Lir { virtual void LoadClassType(const DexFile& dex_file, uint32_t type_idx, SpecialTargetRegister symbolic_reg); + // TODO: Support PC-relative dex cache array loads on all platforms and + // replace CanUseOpPcRelDexCacheArrayLoad() with dex_cache_arrays_layout_.Valid(). + virtual bool CanUseOpPcRelDexCacheArrayLoad() const; + + /* + * @brief Load an element of one of the dex cache arrays. + * @param dex_file the dex file associated with the target dex cache. + * @param offset the offset of the element in the fixed dex cache arrays' layout. + * @param r_dest the register where to load the element. + */ + virtual void OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset, RegStorage r_dest); + // Routines that work for the generic case, but may be overriden by target. /* * @brief Compare memory to immediate, and branch if condition true. @@ -1596,7 +1610,6 @@ class Mir2Lir { */ virtual bool GenSpecialCase(BasicBlock* bb, MIR* mir, const InlineMethod& special); - protected: void ClobberBody(RegisterInfo* p); void SetCurrentDexPc(DexOffset dexpc) { current_dalvik_offset_ = dexpc; @@ -1669,6 +1682,16 @@ class Mir2Lir { */ bool GenSpecialIdentity(MIR* mir, const InlineMethod& special); + /** + * @brief Generate code to check if result is null and, if it is, call helper to load it. + * @param r_result the result register. + * @param trampoline the helper to call in slow path. + * @param imm the immediate passed to the helper. + * @param r_method the register with ArtMethod* if available, otherwise RegStorage::Invalid(). + */ + void GenIfNullUseHelperImmMethod( + RegStorage r_result, QuickEntrypointEnum trampoline, int imm, RegStorage r_method); + void AddDivZeroCheckSlowPath(LIR* branch); // Copy arg0 and arg1 to kArg0 and kArg1 safely, possibly using @@ -1815,7 +1838,9 @@ class Mir2Lir { // Record the MIR that generated a given safepoint (nullptr for prologue safepoints). ArenaVector<std::pair<LIR*, MIR*>> safepoints_; - protected: + // The layout of the cu_->dex_file's dex cache arrays for PC-relative addressing. + const DexCacheArraysLayout dex_cache_arrays_layout_; + // ABI support class ShortyArg { public: diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc index 1673312..d4ad0c2 100644 --- a/compiler/dex/quick/quick_compiler.cc +++ b/compiler/dex/quick/quick_compiler.cc @@ -635,6 +635,12 @@ CompiledMethod* QuickCompiler::Compile(const DexFile::CodeItem* code_item, instruction_set = kThumb2; } CompilationUnit cu(runtime->GetArenaPool(), instruction_set, driver, class_linker); + cu.dex_file = &dex_file; + cu.class_def_idx = class_def_idx; + cu.method_idx = method_idx; + cu.access_flags = access_flags; + cu.invoke_type = invoke_type; + cu.shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); CHECK((cu.instruction_set == kThumb2) || (cu.instruction_set == kArm64) || diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc index abee872..e81228a 100644 --- a/compiler/dex/quick/x86/call_x86.cc +++ b/compiler/dex/quick/x86/call_x86.cc @@ -21,6 +21,7 @@ #include "base/logging.h" #include "dex/quick/mir_to_lir-inl.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "gc/accounting/card_table.h" #include "mirror/art_method.h" #include "mirror/object_array-inl.h" diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 100d49a..670efee 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -31,6 +31,7 @@ #include "base/timing_logger.h" #include "class_linker.h" #include "compiled_class.h" +#include "compiled_method.h" #include "compiler.h" #include "compiler_driver-inl.h" #include "dex_compilation_unit.h" @@ -62,6 +63,7 @@ #include "thread_pool.h" #include "trampolines/trampoline_compiler.h" #include "transaction.h" +#include "utils/dex_cache_arrays_layout-inl.h" #include "utils/swap_space.h" #include "verifier/method_verifier.h" #include "verifier/method_verifier-inl.h" @@ -1173,6 +1175,13 @@ uint32_t CompilerDriver::GetReferenceDisableFlagOffset() const { return klass->GetDisableIntrinsicFlagOffset().Uint32Value(); } +DexCacheArraysLayout CompilerDriver::GetDexCacheArraysLayout(const DexFile* dex_file) { + // Currently only image dex caches have fixed array layout. + return IsImage() && GetSupportBootImageFixup() + ? DexCacheArraysLayout(dex_file) + : DexCacheArraysLayout(); +} + void CompilerDriver::ProcessedInstanceField(bool resolved) { if (!resolved) { stats_->UnresolvedInstanceField(); @@ -2246,7 +2255,7 @@ void CompilerDriver::CompileMethod(Thread* self, const DexFile::CodeItem* code_i // Count non-relative linker patches. size_t non_relative_linker_patch_count = 0u; for (const LinkerPatch& patch : compiled_method->GetPatches()) { - if (patch.Type() != kLinkerPatchCallRelative) { + if (!patch.IsPcRelative()) { ++non_relative_linker_patch_count; } } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index b825293..efcaae4 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -26,11 +26,8 @@ #include "base/mutex.h" #include "base/timing_logger.h" #include "class_reference.h" -#include "compiled_method.h" #include "compiler.h" #include "dex_file.h" -#include "dex/verified_method.h" -#include "driver/compiler_options.h" #include "invoke_type.h" #include "method_reference.h" #include "mirror/class.h" // For mirror::Class::Status. @@ -39,7 +36,9 @@ #include "runtime.h" #include "safe_map.h" #include "thread_pool.h" +#include "utils/array_ref.h" #include "utils/dedupe_set.h" +#include "utils/dex_cache_arrays_layout.h" #include "utils/swap_space.h" #include "utils.h" @@ -54,6 +53,7 @@ class MethodVerifier; } // namespace verifier class CompiledClass; +class CompiledMethod; class CompilerOptions; class DexCompilationUnit; class DexFileToMethodInlinerMap; @@ -62,6 +62,9 @@ class InstructionSetFeatures; class OatWriter; class ParallelCompilationManager; class ScopedObjectAccess; +template <class Allocator> class SrcMap; +class SrcMapElem; +using SwapSrcMap = SrcMap<SwapAllocator<SrcMapElem>>; template<class T> class Handle; class TimingLogger; class VerificationResults; @@ -318,6 +321,10 @@ class CompilerDriver { bool IsMethodsClassInitialized(mirror::Class* referrer_class, mirror::ArtMethod* resolved_method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Get the layout of dex cache arrays for a dex file. Returns invalid layout if the + // dex cache arrays don't have a fixed layout. + DexCacheArraysLayout GetDexCacheArraysLayout(const DexFile* dex_file); + void ProcessedInstanceField(bool resolved); void ProcessedStaticField(bool resolved, bool local); void ProcessedInvoke(InvokeType invoke_type, int flags); diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index a822b24..ca5ec66 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -21,7 +21,9 @@ #include "base/logging.h" #include "base/unix_file/fd_file.h" #include "buffered_output_stream.h" +#include "compiled_method.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "dwarf.h" #include "elf_builder.h" #include "elf_file.h" diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index c1555aa..1ede228 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -19,6 +19,7 @@ #include <sys/stat.h> #include <memory> +#include <numeric> #include <vector> #include "base/logging.h" @@ -54,8 +55,7 @@ #include "runtime.h" #include "scoped_thread_state_change.h" #include "handle_scope-inl.h" - -#include <numeric> +#include "utils/dex_cache_arrays_layout-inl.h" using ::art::mirror::ArtField; using ::art::mirror::ArtMethod; @@ -238,7 +238,7 @@ void ImageWriter::AssignImageOffset(mirror::Object* object, ImageWriter::BinSlot DCHECK(object != nullptr); DCHECK_NE(image_objects_offset_begin_, 0u); - size_t previous_bin_sizes = GetBinSizeSum(bin_slot.GetBin()); // sum sizes in [0..bin#) + size_t previous_bin_sizes = bin_slot_previous_sizes_[bin_slot.GetBin()]; size_t new_offset = image_objects_offset_begin_ + previous_bin_sizes + bin_slot.GetIndex(); DCHECK_ALIGNED(new_offset, kObjectAlignment); @@ -293,6 +293,28 @@ void ImageWriter::SetImageBinSlot(mirror::Object* object, BinSlot bin_slot) { DCHECK(IsImageBinSlotAssigned(object)); } +void ImageWriter::PrepareDexCacheArraySlots() { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock()); + size_t dex_cache_count = class_linker->GetDexCacheCount(); + uint32_t size = 0u; + for (size_t idx = 0; idx < dex_cache_count; ++idx) { + DexCache* dex_cache = class_linker->GetDexCache(idx); + const DexFile* dex_file = dex_cache->GetDexFile(); + dex_cache_array_starts_.Put(dex_file, size); + DexCacheArraysLayout layout(dex_file); + DCHECK(layout.Valid()); + dex_cache_array_indexes_.Put(dex_cache->GetResolvedTypes(), size + layout.TypesOffset()); + dex_cache_array_indexes_.Put(dex_cache->GetResolvedMethods(), size + layout.MethodsOffset()); + dex_cache_array_indexes_.Put(dex_cache->GetResolvedFields(), size + layout.FieldsOffset()); + dex_cache_array_indexes_.Put(dex_cache->GetStrings(), size + layout.StringsOffset()); + size += layout.Size(); + } + // Set the slot size early to avoid DCHECK() failures in IsImageBinSlotAssigned() + // when AssignImageBinSlot() assigns their indexes out or order. + bin_slot_sizes_[kBinDexCacheArray] = size; +} + void ImageWriter::AssignImageBinSlot(mirror::Object* object) { DCHECK(object != nullptr); size_t object_size = object->SizeOf(); @@ -307,6 +329,7 @@ void ImageWriter::AssignImageBinSlot(mirror::Object* object) { // This means more pages will stay either clean or shared dirty (with zygote) and // the app will use less of its own (private) memory. Bin bin = kBinRegular; + size_t current_offset = 0u; if (kBinObjects) { // @@ -316,6 +339,12 @@ void ImageWriter::AssignImageBinSlot(mirror::Object* object) { // Memory analysis has determined that the following types of objects get dirtied // the most: // + // * Dex cache arrays are stored in a special bin. The arrays for each dex cache have + // a fixed layout which helps improve generated code (using PC-relative addressing), + // so we pre-calculate their offsets separately in PrepareDexCacheArraySlots(). + // Since these arrays are huge, most pages do not overlap other objects and it's not + // really important where they are for the clean/dirty separation. Due to their + // special PC-relative addressing, we arbitrarily keep them at the beginning. // * Class'es which are verified [their clinit runs only at runtime] // - classes in general [because their static fields get overwritten] // - initialized classes with all-final statics are unlikely to be ever dirty, @@ -376,13 +405,21 @@ void ImageWriter::AssignImageBinSlot(mirror::Object* object) { } } else if (object->GetClass<kVerifyNone>()->IsStringClass()) { bin = kBinString; // Strings are almost always immutable (except for object header). + } else if (object->IsObjectArray()) { + auto it = dex_cache_array_indexes_.find(object); + if (it != dex_cache_array_indexes_.end()) { + bin = kBinDexCacheArray; + current_offset = it->second; // Use prepared offset defined by the DexCacheLayout. + } // else bin = kBinRegular } // else bin = kBinRegular } - size_t current_offset = bin_slot_sizes_[bin]; // How many bytes the current bin is at (aligned). - // Move the current bin size up to accomodate the object we just assigned a bin slot. size_t offset_delta = RoundUp(object_size, kObjectAlignment); // 64-bit alignment - bin_slot_sizes_[bin] += offset_delta; + if (bin != kBinDexCacheArray) { + current_offset = bin_slot_sizes_[bin]; // How many bytes the current bin is at (aligned). + // Move the current bin size up to accomodate the object we just assigned a bin slot. + bin_slot_sizes_[bin] += offset_delta; + } BinSlot new_bin_slot(bin, current_offset); SetImageBinSlot(object, new_bin_slot); @@ -887,8 +924,17 @@ void ImageWriter::CalculateNewObjectOffsets() { // TODO: Image spaces only? DCHECK_LT(image_end_, image_->Size()); image_objects_offset_begin_ = image_end_; + // Prepare bin slots for dex cache arrays. + PrepareDexCacheArraySlots(); // Clear any pre-existing monitors which may have been in the monitor words, assign bin slots. heap->VisitObjects(WalkFieldsCallback, this); + // Calculate cumulative bin slot sizes. + size_t previous_sizes = 0u; + for (size_t i = 0; i != kBinSize; ++i) { + bin_slot_previous_sizes_[i] = previous_sizes; + previous_sizes += bin_slot_sizes_[i]; + } + DCHECK_EQ(previous_sizes, GetBinSizeSum()); // Transform each object's bin slot into an offset which will be used to do the final copy. heap->VisitObjects(UnbinObjectsIntoOffsetCallback, this); DCHECK(saved_hashes_map_.empty()); // All binslot hashes should've been put into vector by now. @@ -1187,8 +1233,8 @@ size_t ImageWriter::GetBinSizeSum(ImageWriter::Bin up_to) const { ImageWriter::BinSlot::BinSlot(uint32_t lockword) : lockword_(lockword) { // These values may need to get updated if more bins are added to the enum Bin - static_assert(kBinBits == 3, "wrong number of bin bits"); - static_assert(kBinShift == 29, "wrong number of shift"); + static_assert(kBinBits == 4, "wrong number of bin bits"); + static_assert(kBinShift == 28, "wrong number of shift"); static_assert(sizeof(BinSlot) == sizeof(LockWord), "BinSlot/LockWord must have equal sizes"); DCHECK_LT(GetBin(), kBinSize); diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 53f5ce4..71044f7 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -52,7 +52,8 @@ class ImageWriter FINAL { quick_imt_conflict_trampoline_offset_(0), quick_resolution_trampoline_offset_(0), quick_to_interpreter_bridge_offset_(0), compile_pic_(compile_pic), target_ptr_size_(InstructionSetPointerSize(compiler_driver_.GetInstructionSet())), - bin_slot_sizes_(), bin_slot_count_() { + bin_slot_sizes_(), bin_slot_previous_sizes_(), bin_slot_count_(), + string_data_array_(nullptr) { CHECK_NE(image_begin, 0U); } @@ -80,6 +81,14 @@ class ImageWriter FINAL { return reinterpret_cast<mirror::Object*>(image_begin_ + GetImageOffset(object)); } + mirror::HeapReference<mirror::Object>* GetDexCacheArrayElementImageAddress( + const DexFile* dex_file, uint32_t offset) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + auto it = dex_cache_array_starts_.find(dex_file); + DCHECK(it != dex_cache_array_starts_.end()); + return reinterpret_cast<mirror::HeapReference<mirror::Object>*>( + image_begin_ + RoundUp(sizeof(ImageHeader), kObjectAlignment) + it->second + offset); + } + uint8_t* GetOatFileBegin() const { return image_begin_ + RoundUp(image_end_, kPageSize); } @@ -101,6 +110,10 @@ class ImageWriter FINAL { // Classify different kinds of bins that objects end up getting packed into during image writing. enum Bin { + // Dex cache arrays have a special slot for PC-relative addressing. Since they are + // huge, and as such their dirtiness is not important for the clean/dirty separation, + // we arbitrarily keep them at the beginning. + kBinDexCacheArray, // Object arrays belonging to dex cache. // Likely-clean: kBinString, // [String] Almost always immutable (except for obj header). kBinArtMethodsManagedInitialized, // [ArtMethod] Not-native, and initialized. Unlikely to dirty @@ -113,7 +126,6 @@ class ImageWriter FINAL { kBinClassVerified, // Class verified, but initializers haven't been run kBinArtMethodNative, // Art method that is actually native kBinArtMethodNotInitialized, // Art method with a declaring class that wasn't initialized - // Don't care about other art methods since they don't dirty // Add more bins here if we add more segregation code. kBinSize, }; @@ -157,6 +169,7 @@ class ImageWriter FINAL { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); size_t GetImageOffset(mirror::Object* object) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void PrepareDexCacheArraySlots() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void AssignImageBinSlot(mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetImageBinSlot(mirror::Object* object, BinSlot bin_slot) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -282,6 +295,12 @@ class ImageWriter FINAL { // Memory mapped for generating the image. std::unique_ptr<MemMap> image_; + // Indexes for dex cache arrays (objects are inside of the image so that they don't move). + SafeMap<mirror::Object*, size_t> dex_cache_array_indexes_; + + // The start offsets of the dex cache arrays. + SafeMap<const DexFile*, size_t> dex_cache_array_starts_; + // Saved hashes (objects are inside of the image so that they don't move). std::vector<std::pair<mirror::Object*, uint32_t>> saved_hashes_; @@ -309,6 +328,7 @@ class ImageWriter FINAL { // Bin slot tracking for dirty object packing size_t bin_slot_sizes_[kBinSize]; // Number of bytes in a bin + size_t bin_slot_previous_sizes_[kBinSize]; // Number of bytes in previous bins. size_t bin_slot_count_[kBinSize]; // Number of objects in a bin void* string_data_array_; // The backing for the interned strings. diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index c426625..728da27 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -17,11 +17,14 @@ #include "arch/instruction_set_features.h" #include "class_linker.h" #include "common_compiler_test.h" +#include "compiled_method.h" #include "compiler.h" #include "dex/pass_manager.h" #include "dex/quick/dex_file_to_method_inliner_map.h" #include "dex/quick_compiler_callbacks.h" #include "dex/verification_results.h" +#include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "entrypoints/quick/quick_entrypoints.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index b3bb438..05599e1 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -24,8 +24,11 @@ #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "compiled_class.h" +#include "compiled_method.h" #include "dex_file-inl.h" #include "dex/verification_results.h" +#include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "gc/space/space.h" #include "image_writer.h" #include "mirror/art_method-inl.h" @@ -43,9 +46,9 @@ namespace art { -class OatWriter::RelativeCallPatcher { +class OatWriter::RelativePatcher { public: - virtual ~RelativeCallPatcher() { } + virtual ~RelativePatcher() { } // Reserve space for relative call thunks if needed, return adjusted offset. // After all methods have been processed it's call one last time with compiled_method == nullptr. @@ -56,19 +59,23 @@ class OatWriter::RelativeCallPatcher { // Patch method code. The input displacement is relative to the patched location, // the patcher may need to adjust it if the correct base is different. - virtual void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset, - uint32_t target_offset) = 0; + virtual void PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, + uint32_t patch_offset, uint32_t target_offset) = 0; + + // Patch a reference to a dex cache location. + virtual void PatchDexCacheReference(std::vector<uint8_t>* code, const LinkerPatch& patch, + uint32_t patch_offset, uint32_t target_offset) = 0; protected: - RelativeCallPatcher() { } + RelativePatcher() { } private: - DISALLOW_COPY_AND_ASSIGN(RelativeCallPatcher); + DISALLOW_COPY_AND_ASSIGN(RelativePatcher); }; -class OatWriter::NoRelativeCallPatcher FINAL : public RelativeCallPatcher { +class OatWriter::NoRelativePatcher FINAL : public RelativePatcher { public: - NoRelativeCallPatcher() { } + NoRelativePatcher() { } uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method ATTRIBUTE_UNUSED) OVERRIDE { @@ -79,19 +86,27 @@ class OatWriter::NoRelativeCallPatcher FINAL : public RelativeCallPatcher { return offset; // No thunks added; no patches expected. } - void Patch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED, uint32_t literal_offset ATTRIBUTE_UNUSED, - uint32_t patch_offset ATTRIBUTE_UNUSED, - uint32_t target_offset ATTRIBUTE_UNUSED) OVERRIDE { - LOG(FATAL) << "Unexpected relative patch."; + void PatchCall(std::vector<uint8_t>* code ATTRIBUTE_UNUSED, + uint32_t literal_offset ATTRIBUTE_UNUSED, + uint32_t patch_offset ATTRIBUTE_UNUSED, + uint32_t target_offset ATTRIBUTE_UNUSED) OVERRIDE { + LOG(FATAL) << "Unexpected relative call patch."; + } + + virtual void PatchDexCacheReference(std::vector<uint8_t>* code ATTRIBUTE_UNUSED, + const LinkerPatch& patch ATTRIBUTE_UNUSED, + uint32_t patch_offset ATTRIBUTE_UNUSED, + uint32_t target_offset ATTRIBUTE_UNUSED) { + LOG(FATAL) << "Unexpected relative dex cache array patch."; } private: - DISALLOW_COPY_AND_ASSIGN(NoRelativeCallPatcher); + DISALLOW_COPY_AND_ASSIGN(NoRelativePatcher); }; -class OatWriter::X86RelativeCallPatcher FINAL : public RelativeCallPatcher { +class OatWriter::X86RelativePatcher FINAL : public RelativePatcher { public: - X86RelativeCallPatcher() { } + X86RelativePatcher() { } uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method ATTRIBUTE_UNUSED) OVERRIDE { @@ -102,8 +117,8 @@ class OatWriter::X86RelativeCallPatcher FINAL : public RelativeCallPatcher { return offset; // No thunks added; no limit on relative call distance. } - void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset, - uint32_t target_offset) OVERRIDE { + void PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, + uint32_t patch_offset, uint32_t target_offset) OVERRIDE { DCHECK_LE(literal_offset + 4u, code->size()); // Unsigned arithmetic with its well-defined overflow behavior is just fine here. uint32_t displacement = target_offset - patch_offset; @@ -113,17 +128,24 @@ class OatWriter::X86RelativeCallPatcher FINAL : public RelativeCallPatcher { reinterpret_cast<unaligned_int32_t*>(&(*code)[literal_offset])[0] = displacement; } + virtual void PatchDexCacheReference(std::vector<uint8_t>* code ATTRIBUTE_UNUSED, + const LinkerPatch& patch ATTRIBUTE_UNUSED, + uint32_t patch_offset ATTRIBUTE_UNUSED, + uint32_t target_offset ATTRIBUTE_UNUSED) { + LOG(FATAL) << "Unexpected relative dex cache array patch."; + } + private: // PC displacement from patch location; x86 PC for relative calls points to the next // instruction and the patch location is 4 bytes earlier. static constexpr int32_t kPcDisplacement = 4; - DISALLOW_COPY_AND_ASSIGN(X86RelativeCallPatcher); + DISALLOW_COPY_AND_ASSIGN(X86RelativePatcher); }; -class OatWriter::ArmBaseRelativeCallPatcher : public RelativeCallPatcher { +class OatWriter::ArmBaseRelativePatcher : public RelativePatcher { public: - ArmBaseRelativeCallPatcher(OatWriter* writer, + ArmBaseRelativePatcher(OatWriter* writer, InstructionSet instruction_set, std::vector<uint8_t> thunk_code, uint32_t max_positive_displacement, uint32_t max_negative_displacement) : writer_(writer), instruction_set_(instruction_set), thunk_code_(thunk_code), @@ -261,18 +283,18 @@ class OatWriter::ArmBaseRelativeCallPatcher : public RelativeCallPatcher { typedef std::pair<MethodReference, uint32_t> UnprocessedPatch; std::deque<UnprocessedPatch> unprocessed_patches_; - DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativeCallPatcher); + DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativePatcher); }; -class OatWriter::Thumb2RelativeCallPatcher FINAL : public ArmBaseRelativeCallPatcher { +class OatWriter::Thumb2RelativePatcher FINAL : public ArmBaseRelativePatcher { public: - explicit Thumb2RelativeCallPatcher(OatWriter* writer) - : ArmBaseRelativeCallPatcher(writer, kThumb2, CompileThunkCode(), + explicit Thumb2RelativePatcher(OatWriter* writer) + : ArmBaseRelativePatcher(writer, kThumb2, CompileThunkCode(), kMaxPositiveDisplacement, kMaxNegativeDisplacement) { } - void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset, - uint32_t target_offset) OVERRIDE { + void PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, + uint32_t patch_offset, uint32_t target_offset) OVERRIDE { DCHECK_LE(literal_offset + 4u, code->size()); DCHECK_EQ(literal_offset & 1u, 0u); DCHECK_EQ(patch_offset & 1u, 0u); @@ -302,6 +324,13 @@ class OatWriter::Thumb2RelativeCallPatcher FINAL : public ArmBaseRelativeCallPat addr[3] = (value >> 8) & 0xff; } + virtual void PatchDexCacheReference(std::vector<uint8_t>* code ATTRIBUTE_UNUSED, + const LinkerPatch& patch ATTRIBUTE_UNUSED, + uint32_t patch_offset ATTRIBUTE_UNUSED, + uint32_t target_offset ATTRIBUTE_UNUSED) { + LOG(FATAL) << "Unexpected relative dex cache array patch."; + } + private: static std::vector<uint8_t> CompileThunkCode() { // The thunk just uses the entry point in the ArtMethod. This works even for calls @@ -326,18 +355,18 @@ class OatWriter::Thumb2RelativeCallPatcher FINAL : public ArmBaseRelativeCallPat static constexpr uint32_t kMaxPositiveDisplacement = (1u << 24) - 2 + kPcDisplacement; static constexpr uint32_t kMaxNegativeDisplacement = (1u << 24) - kPcDisplacement; - DISALLOW_COPY_AND_ASSIGN(Thumb2RelativeCallPatcher); + DISALLOW_COPY_AND_ASSIGN(Thumb2RelativePatcher); }; -class OatWriter::Arm64RelativeCallPatcher FINAL : public ArmBaseRelativeCallPatcher { +class OatWriter::Arm64RelativePatcher FINAL : public ArmBaseRelativePatcher { public: - explicit Arm64RelativeCallPatcher(OatWriter* writer) - : ArmBaseRelativeCallPatcher(writer, kArm64, CompileThunkCode(), + explicit Arm64RelativePatcher(OatWriter* writer) + : ArmBaseRelativePatcher(writer, kArm64, CompileThunkCode(), kMaxPositiveDisplacement, kMaxNegativeDisplacement) { } - void Patch(std::vector<uint8_t>* code, uint32_t literal_offset, uint32_t patch_offset, - uint32_t target_offset) OVERRIDE { + void PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, + uint32_t patch_offset, uint32_t target_offset) OVERRIDE { DCHECK_LE(literal_offset + 4u, code->size()); DCHECK_EQ(literal_offset & 3u, 0u); DCHECK_EQ(patch_offset & 3u, 0u); @@ -345,17 +374,48 @@ class OatWriter::Arm64RelativeCallPatcher FINAL : public ArmBaseRelativeCallPatc uint32_t displacement = CalculateDisplacement(patch_offset, target_offset & ~1u); DCHECK_EQ(displacement & 3u, 0u); DCHECK((displacement >> 27) == 0u || (displacement >> 27) == 31u); // 28-bit signed. - uint32_t value = (displacement & 0x0fffffffu) >> 2; - value |= 0x94000000; // BL + uint32_t insn = (displacement & 0x0fffffffu) >> 2; + insn |= 0x94000000; // BL - uint8_t* addr = &(*code)[literal_offset]; // Check that we're just overwriting an existing BL. - DCHECK_EQ(addr[3] & 0xfc, 0x94); + DCHECK_EQ(GetInsn(code, literal_offset) & 0xfc000000u, 0x94000000u); // Write the new BL. - addr[0] = (value >> 0) & 0xff; - addr[1] = (value >> 8) & 0xff; - addr[2] = (value >> 16) & 0xff; - addr[3] = (value >> 24) & 0xff; + SetInsn(code, literal_offset, insn); + } + + virtual void PatchDexCacheReference(std::vector<uint8_t>* code ATTRIBUTE_UNUSED, + const LinkerPatch& patch ATTRIBUTE_UNUSED, + uint32_t patch_offset ATTRIBUTE_UNUSED, + uint32_t target_offset ATTRIBUTE_UNUSED) { + DCHECK_EQ(patch_offset & 3u, 0u); + DCHECK_EQ(target_offset & 3u, 0u); + uint32_t literal_offset = patch.LiteralOffset(); + uint32_t insn = GetInsn(code, literal_offset); + uint32_t pc_insn_offset = patch.PcInsnOffset(); + uint32_t disp = target_offset - ((patch_offset - literal_offset + pc_insn_offset) & ~0xfffu); + if (literal_offset == pc_insn_offset) { + // Check it's an ADRP with imm == 0 (unset). + DCHECK_EQ((insn & 0xffffffe0u), 0x90000000u) + << literal_offset << ", " << pc_insn_offset << ", 0x" << std::hex << insn; + insn = (insn & 0x9f00001fu) | + ((disp & 0x00003000u) << (29 - 12)) | + ((disp & 0xffffc000u) >> (12 + 2 - 5)) | + // Since the target_offset is based on the beginning of the oat file and the + // image space precedes the oat file, the target_offset into image space will + // be negative yet passed as uint32_t. Therefore we limit the displacement + // to +-2GiB (rather than the maximim +-4GiB) and determine the sign bit from + // the highest bit of the displacement. + ((disp & 0x80000000u) >> (31 - 23)); + // Write the new ADRP. + SetInsn(code, literal_offset, insn); + } else { + DCHECK_EQ(insn & 0xfffffc00, 0xb9400000); // LDR 32-bit with imm12 == 0 (unset). + DCHECK_EQ(GetInsn(code, pc_insn_offset) & 0x9f00001fu, // Check that pc_insn_offset points + 0x90000000 | ((insn >> 5) & 0x1fu)); // to ADRP with matching register. + uint32_t imm12 = (disp & 0xfffu) >> 2; + insn = (insn & ~(0xfffu << 10)) | (imm12 << 10); + SetInsn(code, literal_offset, insn); + } } private: @@ -374,13 +434,34 @@ class OatWriter::Arm64RelativeCallPatcher FINAL : public ArmBaseRelativeCallPatc return thunk_code; } + uint32_t GetInsn(std::vector<uint8_t>* code, uint32_t offset) { + DCHECK_LE(offset + 4u, code->size()); + DCHECK_EQ(offset & 3u, 0u); + uint8_t* addr = &(*code)[offset]; + return + (static_cast<uint32_t>(addr[0]) << 0) + + (static_cast<uint32_t>(addr[1]) << 8) + + (static_cast<uint32_t>(addr[2]) << 16)+ + (static_cast<uint32_t>(addr[3]) << 24); + } + + void SetInsn(std::vector<uint8_t>* code, uint32_t offset, uint32_t value) { + DCHECK_LE(offset + 4u, code->size()); + DCHECK_EQ(offset & 3u, 0u); + uint8_t* addr = &(*code)[offset]; + addr[0] = (value >> 0) & 0xff; + addr[1] = (value >> 8) & 0xff; + addr[2] = (value >> 16) & 0xff; + addr[3] = (value >> 24) & 0xff; + } + // Maximum positive and negative displacement measured from the patch location. // (Signed 28 bit displacement with the last bit 0 has range [-2^27, 2^27-4] measured from // the ARM64 PC pointing to the BL.) static constexpr uint32_t kMaxPositiveDisplacement = (1u << 27) - 4u; static constexpr uint32_t kMaxNegativeDisplacement = (1u << 27); - DISALLOW_COPY_AND_ASSIGN(Arm64RelativeCallPatcher); + DISALLOW_COPY_AND_ASSIGN(Arm64RelativePatcher); }; #define DCHECK_OFFSET() \ @@ -445,18 +526,18 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, switch (compiler_driver_->GetInstructionSet()) { case kX86: case kX86_64: - relative_call_patcher_.reset(new X86RelativeCallPatcher); + relative_patcher_.reset(new X86RelativePatcher); break; case kArm: // Fall through: we generate Thumb2 code for "arm". case kThumb2: - relative_call_patcher_.reset(new Thumb2RelativeCallPatcher(this)); + relative_patcher_.reset(new Thumb2RelativePatcher(this)); break; case kArm64: - relative_call_patcher_.reset(new Arm64RelativeCallPatcher(this)); + relative_patcher_.reset(new Arm64RelativePatcher(this)); break; default: - relative_call_patcher_.reset(new NoRelativeCallPatcher); + relative_patcher_.reset(new NoRelativePatcher); break; } @@ -706,7 +787,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { bool EndClass() { OatDexMethodVisitor::EndClass(); if (oat_class_index_ == writer_->oat_classes_.size()) { - offset_ = writer_->relative_call_patcher_->ReserveSpace(offset_, nullptr); + offset_ = writer_->relative_patcher_->ReserveSpace(offset_, nullptr); } return true; } @@ -722,7 +803,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { const SwapVector<uint8_t>* quick_code = compiled_method->GetQuickCode(); CHECK(quick_code != nullptr); - offset_ = writer_->relative_call_patcher_->ReserveSpace(offset_, compiled_method); + offset_ = writer_->relative_patcher_->ReserveSpace(offset_, compiled_method); offset_ = compiled_method->AlignCode(offset_); DCHECK_ALIGNED_PARAM(offset_, GetInstructionSetAlignment(compiled_method->GetInstructionSet())); @@ -790,7 +871,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { if (!compiled_method->GetPatches().empty()) { uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset(); for (const LinkerPatch& patch : compiled_method->GetPatches()) { - if (patch.Type() != kLinkerPatchCallRelative) { + if (!patch.IsPcRelative()) { writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset()); } } @@ -851,6 +932,37 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { } private: + struct CodeOffsetsKeyComparator { + bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const { + if (lhs->GetQuickCode() != rhs->GetQuickCode()) { + return lhs->GetQuickCode() < rhs->GetQuickCode(); + } + // If the code is the same, all other fields are likely to be the same as well. + if (UNLIKELY(lhs->GetMappingTable() != rhs->GetMappingTable())) { + return lhs->GetMappingTable() < rhs->GetMappingTable(); + } + if (UNLIKELY(lhs->GetVmapTable() != rhs->GetVmapTable())) { + return lhs->GetVmapTable() < rhs->GetVmapTable(); + } + if (UNLIKELY(lhs->GetGcMap() != rhs->GetGcMap())) { + return lhs->GetGcMap() < rhs->GetGcMap(); + } + const auto& lhs_patches = lhs->GetPatches(); + const auto& rhs_patches = rhs->GetPatches(); + if (UNLIKELY(lhs_patches.size() != rhs_patches.size())) { + return lhs_patches.size() < rhs_patches.size(); + } + auto rit = rhs_patches.begin(); + for (const LinkerPatch& lpatch : lhs_patches) { + if (UNLIKELY(!(lpatch == *rit))) { + return lpatch < *rit; + } + ++rit; + } + return false; + } + }; + // Deduplication is already done on a pointer basis by the compiler driver, // so we can simply compare the pointers to find out if things are duplicated. SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_; @@ -978,7 +1090,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { bool result = OatDexMethodVisitor::EndClass(); if (oat_class_index_ == writer_->oat_classes_.size()) { DCHECK(result); // OatDexMethodVisitor::EndClass() never fails. - offset_ = writer_->relative_call_patcher_->WriteThunks(out_, offset_); + offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_); if (UNLIKELY(offset_ == 0u)) { PLOG(ERROR) << "Failed to write final relative call thunks"; result = false; @@ -1001,7 +1113,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { // Need a wrapper if we create a copy for patching. ArrayRef<const uint8_t> wrapped(*quick_code); - offset_ = writer_->relative_call_patcher_->WriteThunks(out, offset_); + offset_ = writer_->relative_patcher_->WriteThunks(out, offset_); if (offset_ == 0u) { ReportWriteFailure("relative call thunk", it); return false; @@ -1039,15 +1151,21 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { DCHECK_OFFSET_(); if (!compiled_method->GetPatches().empty()) { - patched_code_ = std::vector<uint8_t>(quick_code->begin(), quick_code->end()); + patched_code_.assign(quick_code->begin(), quick_code->end()); wrapped = ArrayRef<const uint8_t>(patched_code_); for (const LinkerPatch& patch : compiled_method->GetPatches()) { if (patch.Type() == kLinkerPatchCallRelative) { // NOTE: Relative calls across oat files are not supported. uint32_t target_offset = GetTargetOffset(patch); uint32_t literal_offset = patch.LiteralOffset(); - writer_->relative_call_patcher_->Patch(&patched_code_, literal_offset, + writer_->relative_patcher_->PatchCall(&patched_code_, literal_offset, offset_ + literal_offset, target_offset); + } else if (patch.Type() == kLinkerPatchDexCacheArray) { + uint32_t target_offset = GetDexCacheOffset(patch); + uint32_t literal_offset = patch.LiteralOffset(); + writer_->relative_patcher_->PatchDexCacheReference(&patched_code_, patch, + offset_ + literal_offset, + target_offset); } else if (patch.Type() == kLinkerPatchCall) { uint32_t target_offset = GetTargetOffset(patch); PatchCodeAddress(&patched_code_, patch.LiteralOffset(), target_offset); @@ -1134,6 +1252,18 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { return type; } + uint32_t GetDexCacheOffset(const LinkerPatch& patch) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (writer_->image_writer_ != nullptr) { + auto* element = writer_->image_writer_->GetDexCacheArrayElementImageAddress( + patch.TargetDexCacheDexFile(), patch.TargetDexCacheElementOffset()); + const uint8_t* oat_data = writer_->image_writer_->GetOatFileBegin() + file_offset_; + return reinterpret_cast<const uint8_t*>(element) - oat_data; + } else { + LOG(FATAL) << "Unimplemented."; + UNREACHABLE(); + } + } + void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // NOTE: Direct method pointers across oat files don't use linker patches. However, direct diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index fd2ccae..cbf768f 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -21,7 +21,6 @@ #include <cstddef> #include <memory> -#include "driver/compiler_driver.h" #include "mem_map.h" #include "method_reference.h" #include "oat.h" @@ -32,8 +31,10 @@ namespace art { class BitVector; class CompiledMethod; +class CompilerDriver; class ImageWriter; class OutputStream; +class TimingLogger; // OatHeader variable length with count of D OatDexFiles // @@ -325,51 +326,20 @@ class OatWriter { uint32_t size_oat_class_method_bitmaps_; uint32_t size_oat_class_method_offsets_; - class RelativeCallPatcher; - class NoRelativeCallPatcher; - class X86RelativeCallPatcher; - class ArmBaseRelativeCallPatcher; - class Thumb2RelativeCallPatcher; - class Arm64RelativeCallPatcher; + class RelativePatcher; + class NoRelativePatcher; + class X86RelativePatcher; + class ArmBaseRelativePatcher; + class Thumb2RelativePatcher; + class Arm64RelativePatcher; - std::unique_ptr<RelativeCallPatcher> relative_call_patcher_; + std::unique_ptr<RelativePatcher> relative_patcher_; // The locations of absolute patches relative to the start of the executable section. std::vector<uintptr_t> absolute_patch_locations_; SafeMap<MethodReference, uint32_t, MethodReferenceComparator> method_offset_map_; - struct CodeOffsetsKeyComparator { - bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const { - if (lhs->GetQuickCode() != rhs->GetQuickCode()) { - return lhs->GetQuickCode() < rhs->GetQuickCode(); - } - // If the code is the same, all other fields are likely to be the same as well. - if (UNLIKELY(lhs->GetMappingTable() != rhs->GetMappingTable())) { - return lhs->GetMappingTable() < rhs->GetMappingTable(); - } - if (UNLIKELY(lhs->GetVmapTable() != rhs->GetVmapTable())) { - return lhs->GetVmapTable() < rhs->GetVmapTable(); - } - if (UNLIKELY(lhs->GetGcMap() != rhs->GetGcMap())) { - return lhs->GetGcMap() < rhs->GetGcMap(); - } - const auto& lhs_patches = lhs->GetPatches(); - const auto& rhs_patches = rhs->GetPatches(); - if (UNLIKELY(lhs_patches.size() != rhs_patches.size())) { - return lhs_patches.size() < rhs_patches.size(); - } - auto rit = rhs_patches.begin(); - for (const LinkerPatch& lpatch : lhs_patches) { - if (UNLIKELY(!(lpatch == *rit))) { - return lpatch < *rit; - } - ++rit; - } - return false; - } - }; - DISALLOW_COPY_AND_ASSIGN(OatWriter); }; diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 2cdd5af..2da3176 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -23,6 +23,7 @@ #include "dex_instruction.h" #include "dex_instruction-inl.h" #include "driver/compiler_driver-inl.h" +#include "driver/compiler_options.h" #include "mirror/art_field.h" #include "mirror/art_field-inl.h" #include "mirror/class_loader.h" diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 5ce73ba..c0df02b 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -26,11 +26,13 @@ #include "bounds_check_elimination.h" #include "builder.h" #include "code_generator.h" +#include "compiled_method.h" #include "compiler.h" #include "constant_folding.h" #include "dead_code_elimination.h" #include "dex/quick/dex_file_to_method_inliner_map.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "driver/dex_compilation_unit.h" #include "elf_writer_quick.h" #include "graph_visualizer.h" diff --git a/compiler/utils/dex_cache_arrays_layout-inl.h b/compiler/utils/dex_cache_arrays_layout-inl.h new file mode 100644 index 0000000..7d02ce3 --- /dev/null +++ b/compiler/utils/dex_cache_arrays_layout-inl.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_UTILS_DEX_CACHE_ARRAYS_LAYOUT_INL_H_ +#define ART_COMPILER_UTILS_DEX_CACHE_ARRAYS_LAYOUT_INL_H_ + +#include "dex_cache_arrays_layout.h" + +#include "base/logging.h" +#include "globals.h" +#include "mirror/array-inl.h" +#include "primitive.h" +#include "utils.h" + +namespace mirror { +class ArtField; +class ArtMethod; +class Class; +class String; +} // namespace mirror + +namespace art { + +inline DexCacheArraysLayout::DexCacheArraysLayout(const DexFile* dex_file) + : /* types_offset_ is always 0u */ + methods_offset_(types_offset_ + ArraySize<mirror::Class>(dex_file->NumTypeIds())), + strings_offset_(methods_offset_ + ArraySize<mirror::ArtMethod>(dex_file->NumMethodIds())), + fields_offset_(strings_offset_ + ArraySize<mirror::String>(dex_file->NumStringIds())), + size_(fields_offset_ + ArraySize<mirror::ArtField>(dex_file->NumFieldIds())) { +} + +inline size_t DexCacheArraysLayout::TypeOffset(uint32_t type_idx) const { + return types_offset_ + ElementOffset<mirror::Class>(type_idx); +} + +inline size_t DexCacheArraysLayout::MethodOffset(uint32_t method_idx) const { + return methods_offset_ + ElementOffset<mirror::ArtMethod>(method_idx); +} + +inline size_t DexCacheArraysLayout::StringOffset(uint32_t string_idx) const { + return strings_offset_ + ElementOffset<mirror::String>(string_idx); +} + +inline size_t DexCacheArraysLayout::FieldOffset(uint32_t field_idx) const { + return fields_offset_ + ElementOffset<mirror::ArtField>(field_idx); +} + +template <typename MirrorType> +inline size_t DexCacheArraysLayout::ElementOffset(uint32_t idx) { + return mirror::Array::DataOffset(sizeof(mirror::HeapReference<MirrorType>)).Uint32Value() + + sizeof(mirror::HeapReference<MirrorType>) * idx; +} + +template <typename MirrorType> +inline size_t DexCacheArraysLayout::ArraySize(uint32_t num_elements) { + size_t array_size = mirror::ComputeArraySize( + num_elements, ComponentSizeShiftWidth<sizeof(mirror::HeapReference<MirrorType>)>()); + DCHECK_NE(array_size, 0u); // No overflow expected for dex cache arrays. + return RoundUp(array_size, kObjectAlignment); +} + +} // namespace art + +#endif // ART_COMPILER_UTILS_DEX_CACHE_ARRAYS_LAYOUT_INL_H_ diff --git a/compiler/utils/dex_cache_arrays_layout.h b/compiler/utils/dex_cache_arrays_layout.h new file mode 100644 index 0000000..b461256 --- /dev/null +++ b/compiler/utils/dex_cache_arrays_layout.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_UTILS_DEX_CACHE_ARRAYS_LAYOUT_H_ +#define ART_COMPILER_UTILS_DEX_CACHE_ARRAYS_LAYOUT_H_ + +namespace art { + +/** + * @class DexCacheArraysLayout + * @details This class provides the layout information for the type, method, field and + * string arrays for a DexCache with a fixed arrays' layout (such as in the boot image), + */ +class DexCacheArraysLayout { + public: + // Construct an invalid layout. + DexCacheArraysLayout() + : /* types_offset_ is always 0u */ + methods_offset_(0u), + strings_offset_(0u), + fields_offset_(0u), + size_(0u) { + } + + // Construct a layout for a particular dex file. + explicit DexCacheArraysLayout(const DexFile* dex_file); + + bool Valid() const { + return Size() != 0u; + } + + size_t Size() const { + return size_; + } + + size_t TypesOffset() const { + return types_offset_; + } + + size_t TypeOffset(uint32_t type_idx) const; + + size_t MethodsOffset() const { + return methods_offset_; + } + + size_t MethodOffset(uint32_t method_idx) const; + + size_t StringsOffset() const { + return strings_offset_; + } + + size_t StringOffset(uint32_t string_idx) const; + + size_t FieldsOffset() const { + return fields_offset_; + } + + size_t FieldOffset(uint32_t field_idx) const; + + private: + static constexpr size_t types_offset_ = 0u; + const size_t methods_offset_; + const size_t strings_offset_; + const size_t fields_offset_; + const size_t size_; + + template <typename MirrorType> + static size_t ElementOffset(uint32_t idx); + + template <typename MirrorType> + static size_t ArraySize(uint32_t num_elements); +}; + +} // namespace art + +#endif // ART_COMPILER_UTILS_DEX_CACHE_ARRAYS_LAYOUT_H_ |