diff options
-rw-r--r-- | compiler/dex/quick/x86/call_x86.cc | 24 | ||||
-rw-r--r-- | compiler/dex/quick/x86/codegen_x86.h | 12 | ||||
-rwxr-xr-x | compiler/dex/quick/x86/int_x86.cc | 35 | ||||
-rwxr-xr-x | compiler/dex/quick/x86/target_x86.cc | 16 | ||||
-rw-r--r-- | compiler/oat_writer.cc | 41 | ||||
-rw-r--r-- | compiler/oat_writer.h | 2 |
6 files changed, 107 insertions, 23 deletions
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc index e81228a..bf7c157 100644 --- a/compiler/dex/quick/x86/call_x86.cc +++ b/compiler/dex/quick/x86/call_x86.cc @@ -25,6 +25,7 @@ #include "gc/accounting/card_table.h" #include "mirror/art_method.h" #include "mirror/object_array-inl.h" +#include "utils/dex_cache_arrays_layout-inl.h" #include "x86_lir.h" namespace art { @@ -322,13 +323,13 @@ void X86Mir2Lir::GenImplicitNullCheck(RegStorage reg, int opt_flags) { * Bit of a hack here - in the absence of a real scheduling pass, * emit the next instruction in static & direct invoke sequences. */ -static int X86NextSDCallInsn(CompilationUnit* cu, CallInfo* info, - int state, const MethodReference& target_method, - uint32_t, - uintptr_t direct_code, uintptr_t direct_method, - InvokeType type) { +int X86Mir2Lir::X86NextSDCallInsn(CompilationUnit* cu, CallInfo* info, + int state, const MethodReference& target_method, + uint32_t, + uintptr_t direct_code, uintptr_t direct_method, + InvokeType type) { UNUSED(info, direct_code); - Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get()); + X86Mir2Lir* cg = static_cast<X86Mir2Lir*>(cu->cg.get()); if (direct_method != 0) { switch (state) { case 0: // Get the current Method* [sets kArg0] @@ -346,6 +347,17 @@ static int X86NextSDCallInsn(CompilationUnit* cu, CallInfo* info, default: return -1; } + } else if (cg->CanUseOpPcRelDexCacheArrayLoad()) { + switch (state) { + case 0: { + CHECK_EQ(cu->dex_file, target_method.dex_file); + size_t offset = cg->dex_cache_arrays_layout_.MethodOffset(target_method.dex_method_index); + cg->OpPcRelDexCacheArrayLoad(cu->dex_file, offset, cg->TargetReg(kArg0, kRef)); + break; + } + default: + return -1; + } } else { RegStorage arg0_ref = cg->TargetReg(kArg0, kRef); switch (state) { diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index 040a8c4..758684e 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -104,6 +104,9 @@ class X86Mir2Lir : 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; + void GenImplicitNullCheck(RegStorage reg, int opt_flags) OVERRIDE; // Required for target - register utilities. @@ -952,6 +955,9 @@ class X86Mir2Lir : public Mir2Lir { // Instructions needing patching with PC relative code addresses. ArenaVector<LIR*> call_method_insns_; + // Instructions needing patching with PC relative code addresses. + ArenaVector<LIR*> dex_cache_access_insns_; + // Prologue decrement of stack pointer. LIR* stack_decrement_; @@ -992,6 +998,12 @@ class X86Mir2Lir : public Mir2Lir { void SwapBits(RegStorage result_reg, int shift, int32_t value); void SwapBits64(RegStorage result_reg, int shift, int64_t value); + static int X86NextSDCallInsn(CompilationUnit* cu, CallInfo* info, + int state, const MethodReference& target_method, + uint32_t, + uintptr_t direct_code, uintptr_t direct_method, + InvokeType type); + static const X86EncodingMap EncodingMap[kX86Last]; friend std::ostream& operator<<(std::ostream& os, const X86OpCode& rhs); diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc index 4eb626c..5def5c8 100755 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -1324,14 +1324,16 @@ bool X86Mir2Lir::GenInlinedReverseBits(CallInfo* info, OpSize size) { return true; } +// When we don't know the proper offset for the value, pick one that will force +// 4 byte offset. We will fix this up in the assembler or linker later to have +// the right value. +static constexpr int kDummy32BitOffset = 256; + void X86Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) { if (cu_->target64) { // We can do this directly using RIP addressing. - // We don't know the proper offset for the value, so pick one that will force - // 4 byte offset. We will fix this up in the assembler later to have the right - // value. ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral); - LIR* res = NewLIR3(kX86Mov32RM, reg.GetReg(), kRIPReg, 256); + LIR* res = NewLIR3(kX86Mov32RM, reg.GetReg(), kRIPReg, kDummy32BitOffset); res->target = target; res->flags.fixup = kFixupLoad; return; @@ -1349,15 +1351,32 @@ void X86Mir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) { store_method_addr_used_ = true; // Load the proper value from the literal area. - // We don't know the proper offset for the value, so pick one that will force - // 4 byte offset. We will fix this up in the assembler later to have the right - // value. ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral); - LIR* res = NewLIR3(kX86Mov32RM, reg.GetReg(), reg.GetReg(), 256); + LIR* res = NewLIR3(kX86Mov32RM, reg.GetReg(), reg.GetReg(), kDummy32BitOffset); res->target = target; res->flags.fixup = kFixupLoad; } +bool X86Mir2Lir::CanUseOpPcRelDexCacheArrayLoad() const { + // TODO: Implement for 32-bit. + return cu_->target64 && dex_cache_arrays_layout_.Valid(); +} + +void X86Mir2Lir::OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset, + RegStorage r_dest) { + if (cu_->target64) { + LIR* mov = NewLIR3(kX86Mov32RM, r_dest.GetReg(), kRIPReg, kDummy32BitOffset); + mov->flags.fixup = kFixupLabel; + mov->operands[3] = WrapPointer(dex_file); + mov->operands[4] = offset; + dex_cache_access_insns_.push_back(mov); + } else { + // TODO: Implement for 32-bit. + LOG(FATAL) << "Unimplemented."; + UNREACHABLE(); + } +} + LIR* X86Mir2Lir::OpVldm(RegStorage r_base, int count) { UNUSED(r_base, count); LOG(FATAL) << "Unexpected use of OpVldm for x86"; diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index f128eb7..cad82a1 100755 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -829,6 +829,7 @@ X86Mir2Lir::X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* method_address_insns_(arena->Adapter()), class_type_address_insns_(arena->Adapter()), call_method_insns_(arena->Adapter()), + dex_cache_access_insns_(arena->Adapter()), stack_decrement_(nullptr), stack_increment_(nullptr), const_vectors_(nullptr) { method_address_insns_.reserve(100); @@ -1058,6 +1059,9 @@ void X86Mir2Lir::InstallLiteralPools() { } } + patches_.reserve(method_address_insns_.size() + class_type_address_insns_.size() + + call_method_insns_.size() + dex_cache_access_insns_.size()); + // Handle the fixups for methods. for (LIR* p : method_address_insns_) { DCHECK_EQ(p->opcode, kX86Mov32RI); @@ -1084,7 +1088,6 @@ void X86Mir2Lir::InstallLiteralPools() { } // And now the PC-relative calls to methods. - patches_.reserve(call_method_insns_.size()); for (LIR* p : call_method_insns_) { DCHECK_EQ(p->opcode, kX86CallI); uint32_t target_method_idx = p->operands[1]; @@ -1096,6 +1099,17 @@ void X86Mir2Lir::InstallLiteralPools() { target_dex_file, target_method_idx)); } + // PC-relative references to dex cache arrays. + for (LIR* p : dex_cache_access_insns_) { + DCHECK(p->opcode == kX86Mov32RM); + const DexFile* dex_file = UnwrapPointer<DexFile>(p->operands[3]); + uint32_t offset = p->operands[4]; + // The offset to patch is the last 4 bytes of the instruction. + int patch_offset = p->offset + p->flags.size - 4; + DCHECK(!p->flags.is_nop); + patches_.push_back(LinkerPatch::DexCacheArrayPatch(patch_offset, dex_file, p->offset, offset)); + } + // And do the normal processing. Mir2Lir::InstallLiteralPools(); } diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 04f0db6..2c3f982 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -105,9 +105,9 @@ class OatWriter::NoRelativePatcher FINAL : public RelativePatcher { DISALLOW_COPY_AND_ASSIGN(NoRelativePatcher); }; -class OatWriter::X86RelativePatcher FINAL : public RelativePatcher { +class OatWriter::X86BaseRelativePatcher : public RelativePatcher { public: - X86RelativePatcher() { } + X86BaseRelativePatcher() { } uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method ATTRIBUTE_UNUSED) OVERRIDE { @@ -129,19 +129,42 @@ class OatWriter::X86RelativePatcher FINAL : public RelativePatcher { reinterpret_cast<unaligned_int32_t*>(&(*code)[literal_offset])[0] = displacement; } + protected: + // PC displacement from patch location; the base address of x86/x86-64 relative + // calls and x86-64 RIP-relative addressing is the PC of the next instruction and + // the patch location is 4 bytes earlier. + static constexpr int32_t kPcDisplacement = 4; + + private: + DISALLOW_COPY_AND_ASSIGN(X86BaseRelativePatcher); +}; + +class OatWriter::X86RelativePatcher FINAL : public X86BaseRelativePatcher { + public: + X86RelativePatcher() { } + 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; +class OatWriter::X86_64RelativePatcher FINAL : public X86BaseRelativePatcher { + public: + X86_64RelativePatcher() { } + + virtual void PatchDexCacheReference(std::vector<uint8_t>* code, const LinkerPatch& patch, + uint32_t patch_offset, uint32_t target_offset) { + DCHECK_LE(patch.LiteralOffset() + 4u, code->size()); + // Unsigned arithmetic with its well-defined overflow behavior is just fine here. + uint32_t displacement = target_offset - patch_offset; + displacement -= kPcDisplacement; // The base PC is at the end of the 4-byte patch. - DISALLOW_COPY_AND_ASSIGN(X86RelativePatcher); + typedef __attribute__((__aligned__(1))) int32_t unaligned_int32_t; + reinterpret_cast<unaligned_int32_t*>(&(*code)[patch.LiteralOffset()])[0] = displacement; + } }; class OatWriter::ArmBaseRelativePatcher : public RelativePatcher { @@ -706,9 +729,11 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, switch (compiler_driver_->GetInstructionSet()) { case kX86: - case kX86_64: relative_patcher_.reset(new X86RelativePatcher); break; + case kX86_64: + relative_patcher_.reset(new X86_64RelativePatcher); + break; case kArm: // Fall through: we generate Thumb2 code for "arm". case kThumb2: diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 676d628..8951634 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -329,7 +329,9 @@ class OatWriter { class RelativePatcher; class NoRelativePatcher; + class X86BaseRelativePatcher; class X86RelativePatcher; + class X86_64RelativePatcher; class ArmBaseRelativePatcher; class Thumb2RelativePatcher; class Arm64RelativePatcher; |