diff options
53 files changed, 4462 insertions, 3028 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 1a4c30c20d..f834a38fcc 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -193,6 +193,9 @@ COMPILER_GTEST_COMMON_SRC_FILES := \ compiler/elf_writer_test.cc \ compiler/image_test.cc \ compiler/jni/jni_compiler_test.cc \ + compiler/linker/arm/relative_patcher_thumb2_test.cc \ + compiler/linker/x86/relative_patcher_x86_test.cc \ + compiler/linker/x86_64/relative_patcher_x86_64_test.cc \ compiler/oat_test.cc \ compiler/optimizing/bounds_check_elimination_test.cc \ compiler/optimizing/codegen_test.cc \ diff --git a/compiler/Android.mk b/compiler/Android.mk index 904f117a5a..eaea031b62 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -79,6 +79,13 @@ LIBART_COMPILER_SRC_FILES := \ driver/compiler_driver.cc \ driver/compiler_options.cc \ driver/dex_compilation_unit.cc \ + linker/relative_patcher.cc \ + linker/arm/relative_patcher_arm_base.cc \ + linker/arm/relative_patcher_thumb2.cc \ + linker/arm64/relative_patcher_arm64.cc \ + linker/x86/relative_patcher_x86_base.cc \ + linker/x86/relative_patcher_x86.cc \ + linker/x86_64/relative_patcher_x86_64.cc \ jit/jit_compiler.cc \ jni/quick/arm/calling_convention_arm.cc \ jni/quick/arm64/calling_convention_arm64.cc \ diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc index 1849e7ef64..03370db6c0 100644 --- a/compiler/compiled_method.cc +++ b/compiler/compiled_method.cc @@ -142,7 +142,6 @@ CompiledMethod::CompiledMethod(CompilerDriver* driver, if (src_mapping_table == nullptr) { src_mapping_table_ = new SwapSrcMap(driver->GetSwapSpaceAllocator()); } else { - src_mapping_table->Arrange(); src_mapping_table_ = new SwapSrcMap(src_mapping_table->begin(), src_mapping_table->end(), driver->GetSwapSpaceAllocator()); } @@ -159,7 +158,7 @@ CompiledMethod::CompiledMethod(CompilerDriver* driver, } else { src_mapping_table_ = src_mapping_table == nullptr ? driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>()) : - driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>(src_mapping_table->Arrange())); + driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>(*src_mapping_table)); mapping_table_ = mapping_table.empty() ? nullptr : driver->DeduplicateMappingTable(mapping_table); vmap_table_ = driver->DeduplicateVMapTable(vmap_table); diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index 23869140ae..7497b175fc 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -94,20 +94,12 @@ class SrcMapElem { uint32_t from_; int32_t to_; - explicit operator int64_t() const { - return (static_cast<int64_t>(to_) << 32) | from_; - } - - bool operator<(const SrcMapElem& sme) const { - return int64_t(*this) < int64_t(sme); - } - - bool operator==(const SrcMapElem& sme) const { - return int64_t(*this) == int64_t(sme); - } - - explicit operator uint8_t() const { - return static_cast<uint8_t>(from_ + to_); + // Lexicographical compare. + bool operator<(const SrcMapElem& other) const { + if (from_ != other.from_) { + return from_ < other.from_; + } + return to_ < other.to_; } }; @@ -129,49 +121,33 @@ class SrcMap FINAL : public std::vector<SrcMapElem, Allocator> { SrcMap(InputIt first, InputIt last, const Allocator& alloc) : std::vector<SrcMapElem, Allocator>(first, last, alloc) {} - void SortByFrom() { - std::sort(begin(), end(), [] (const SrcMapElem& lhs, const SrcMapElem& rhs) -> bool { - return lhs.from_ < rhs.from_; - }); - } - - const_iterator FindByTo(int32_t to) const { - return std::lower_bound(begin(), end(), SrcMapElem({0, to})); - } - - SrcMap& Arrange() { - if (!empty()) { - std::sort(begin(), end()); - resize(std::unique(begin(), end()) - begin()); - shrink_to_fit(); - } - return *this; - } - - void DeltaFormat(const SrcMapElem& start, uint32_t highest_pc) { - // Convert from abs values to deltas. + void push_back(const SrcMapElem& elem) { if (!empty()) { - SortByFrom(); - - // TODO: one PC can be mapped to several Java src lines. - // do we want such a one-to-many correspondence? - - // get rid of the highest values - size_t i = size() - 1; - for (; i > 0 ; i--) { - if ((*this)[i].from_ < highest_pc) { - break; - } + // Check that the addresses are inserted in sorted order. + DCHECK_GE(elem.from_, this->back().from_); + // If two consequitive entries map to the same value, ignore the later. + // E.g. for map {{0, 1}, {4, 1}, {8, 2}}, all values in [0,8) map to 1. + if (elem.to_ == this->back().to_) { + return; } - this->resize(i + 1); - - for (i = size(); --i >= 1; ) { - (*this)[i].from_ -= (*this)[i-1].from_; - (*this)[i].to_ -= (*this)[i-1].to_; - } - DCHECK((*this)[0].from_ >= start.from_); - (*this)[0].from_ -= start.from_; - (*this)[0].to_ -= start.to_; + } + std::vector<SrcMapElem, Allocator>::push_back(elem); + } + + // Returns true and the corresponding "to" value if the mapping is found. + // Oterwise returns false and 0. + std::pair<bool, int32_t> Find(uint32_t from) const { + // Finds first mapping such that lb.from_ >= from. + auto lb = std::lower_bound(begin(), end(), SrcMapElem {from, INT32_MIN}); + if (lb != end() && lb->from_ == from) { + // Found exact match. + return std::make_pair(true, lb->to_); + } else if (lb != begin()) { + // The previous mapping is still in effect. + return std::make_pair(true, (--lb)->to_); + } else { + // Not found because 'from' is smaller than first entry in the map. + return std::make_pair(false, 0); } } }; @@ -428,7 +404,7 @@ class CompiledMethod FINAL : public CompiledCode { const uint32_t core_spill_mask_; // For quick code, a bit mask describing spilled FPR callee-save registers. const uint32_t fp_spill_mask_; - // For quick code, a set of pairs (PC, Line) mapping from native PC offset to Java line + // For quick code, a set of pairs (PC, DEX) mapping from native PC offset to DEX offset. SwapSrcMap* src_mapping_table_; // For quick code, a uleb128 encoded map from native PC offset to dex PC aswell as dex PC to // native PC offset. Size prefixed. diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h index 39725dee38..0acdd422df 100644 --- a/compiler/dex/compiler_enums.h +++ b/compiler/dex/compiler_enums.h @@ -99,14 +99,16 @@ std::ostream& operator<<(std::ostream& os, const BBType& code); // Shared pseudo opcodes - must be < 0. enum LIRPseudoOpcode { - kPseudoExportedPC = -16, - kPseudoSafepointPC = -15, - kPseudoIntrinsicRetry = -14, - kPseudoSuspendTarget = -13, - kPseudoThrowTarget = -12, - kPseudoCaseLabel = -11, - kPseudoMethodEntry = -10, - kPseudoMethodExit = -9, + kPseudoPrologueBegin = -18, + kPseudoPrologueEnd = -17, + kPseudoEpilogueBegin = -16, + kPseudoEpilogueEnd = -15, + kPseudoExportedPC = -14, + kPseudoSafepointPC = -13, + kPseudoIntrinsicRetry = -12, + kPseudoSuspendTarget = -11, + kPseudoThrowTarget = -10, + kPseudoCaseLabel = -9, kPseudoBarrier = -8, kPseudoEntryBlock = -7, kPseudoExitBlock = -6, diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc index 3e69878846..c5ac4c1508 100644 --- a/compiler/dex/quick/arm/assemble_arm.cc +++ b/compiler/dex/quick/arm/assemble_arm.cc @@ -1083,7 +1083,9 @@ void ArmMir2Lir::InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir) { #define PADDING_MOV_R5_R5 0x1C2D uint8_t* ArmMir2Lir::EncodeLIRs(uint8_t* write_pos, LIR* lir) { + uint8_t* const write_buffer = write_pos; for (; lir != NULL; lir = NEXT_LIR(lir)) { + lir->offset = (write_pos - write_buffer); if (!lir->flags.is_nop) { int opcode = lir->opcode; if (IsPseudoLirOp(opcode)) { diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index 3081c9e752..e6158c3200 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -372,7 +372,6 @@ void ArmMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) { * a leaf *and* our frame size < fudge factor. */ bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !FrameNeedsStackCheck(frame_size_, kArm); - NewLIR0(kPseudoMethodEntry); const size_t kStackOverflowReservedUsableBytes = GetStackOverflowReservedBytes(kArm); bool large_frame = (static_cast<size_t>(frame_size_) > kStackOverflowReservedUsableBytes); bool generate_explicit_stack_overflow_check = large_frame || @@ -507,7 +506,6 @@ void ArmMir2Lir::GenExitSequence() { LockTemp(rs_r0); LockTemp(rs_r1); - NewLIR0(kPseudoMethodExit); OpRegImm(kOpAdd, rs_rARM_SP, frame_size_ - (spill_count * 4)); /* Need to restore any FP callee saves? */ if (num_fp_spills_) { diff --git a/compiler/dex/quick/arm64/assemble_arm64.cc b/compiler/dex/quick/arm64/assemble_arm64.cc index a59deb5db7..2f1ae66bfc 100644 --- a/compiler/dex/quick/arm64/assemble_arm64.cc +++ b/compiler/dex/quick/arm64/assemble_arm64.cc @@ -686,7 +686,9 @@ void Arm64Mir2Lir::InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir) #define PADDING_NOP (UINT32_C(0xd503201f)) uint8_t* Arm64Mir2Lir::EncodeLIRs(uint8_t* write_pos, LIR* lir) { + uint8_t* const write_buffer = write_pos; for (; lir != nullptr; lir = NEXT_LIR(lir)) { + lir->offset = (write_pos - write_buffer); bool opcode_is_wide = IS_WIDE(lir->opcode); A64Opcode opcode = UNWIDE(lir->opcode); diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc index 3316945ed1..6b47bba884 100644 --- a/compiler/dex/quick/arm64/call_arm64.cc +++ b/compiler/dex/quick/arm64/call_arm64.cc @@ -312,8 +312,6 @@ void Arm64Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !FrameNeedsStackCheck(frame_size_, kArm64); - NewLIR0(kPseudoMethodEntry); - const size_t kStackOverflowReservedUsableBytes = GetStackOverflowReservedBytes(kArm64); const bool large_frame = static_cast<size_t>(frame_size_) > kStackOverflowReservedUsableBytes; bool generate_explicit_stack_overflow_check = large_frame || @@ -401,9 +399,6 @@ void Arm64Mir2Lir::GenExitSequence() { */ LockTemp(rs_x0); LockTemp(rs_x1); - - NewLIR0(kPseudoMethodExit); - UnspillRegs(rs_sp, core_spill_mask_, fp_spill_mask_, frame_size_); // Finally return. diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 509d4487ad..483a5d06cc 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -203,12 +203,17 @@ void Mir2Lir::DumpLIRInsn(LIR* lir, unsigned char* base_addr) { /* Handle pseudo-ops individually, and all regular insns as a group */ switch (lir->opcode) { - case kPseudoMethodEntry: - LOG(INFO) << "-------- method entry " - << PrettyMethod(cu_->method_idx, *cu_->dex_file); + case kPseudoPrologueBegin: + LOG(INFO) << "-------- PrologueBegin"; break; - case kPseudoMethodExit: - LOG(INFO) << "-------- Method_Exit"; + case kPseudoPrologueEnd: + LOG(INFO) << "-------- PrologueEnd"; + break; + case kPseudoEpilogueBegin: + LOG(INFO) << "-------- EpilogueBegin"; + break; + case kPseudoEpilogueEnd: + LOG(INFO) << "-------- EpilogueEnd"; break; case kPseudoBarrier: LOG(INFO) << "-------- BARRIER"; @@ -267,8 +272,9 @@ void Mir2Lir::DumpLIRInsn(LIR* lir, unsigned char* base_addr) { lir, base_addr)); std::string op_operands(BuildInsnString(GetTargetInstFmt(lir->opcode), lir, base_addr)); - LOG(INFO) << StringPrintf("%5p: %-9s%s%s", + LOG(INFO) << StringPrintf("%5p|0x%02x: %-9s%s%s", base_addr + offset, + lir->dalvik_offset, op_name.c_str(), op_operands.c_str(), lir->flags.is_nop ? "(nop)" : ""); } @@ -713,14 +719,17 @@ void Mir2Lir::CreateMappingTables() { DCHECK_EQ(static_cast<size_t>(write_pos - &encoded_mapping_table_[0]), hdr_data_size); uint8_t* write_pos2 = write_pos + pc2dex_data_size; + bool is_in_prologue_or_epilogue = false; pc2dex_offset = 0u; pc2dex_dalvik_offset = 0u; dex2pc_offset = 0u; dex2pc_dalvik_offset = 0u; for (LIR* tgt_lir = first_lir_insn_; tgt_lir != nullptr; tgt_lir = NEXT_LIR(tgt_lir)) { - if (generate_src_map && !tgt_lir->flags.is_nop) { - src_mapping_table_.push_back(SrcMapElem({tgt_lir->offset, - static_cast<int32_t>(tgt_lir->dalvik_offset)})); + if (generate_src_map && !tgt_lir->flags.is_nop && tgt_lir->opcode >= 0) { + if (!is_in_prologue_or_epilogue) { + src_mapping_table_.push_back(SrcMapElem({tgt_lir->offset, + static_cast<int32_t>(tgt_lir->dalvik_offset)})); + } } if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) { DCHECK(pc2dex_offset <= tgt_lir->offset); @@ -738,6 +747,12 @@ void Mir2Lir::CreateMappingTables() { dex2pc_offset = tgt_lir->offset; dex2pc_dalvik_offset = tgt_lir->dalvik_offset; } + if (tgt_lir->opcode == kPseudoPrologueBegin || tgt_lir->opcode == kPseudoEpilogueBegin) { + is_in_prologue_or_epilogue = true; + } + if (tgt_lir->opcode == kPseudoPrologueEnd || tgt_lir->opcode == kPseudoEpilogueEnd) { + is_in_prologue_or_epilogue = false; + } } DCHECK_EQ(static_cast<size_t>(write_pos - &encoded_mapping_table_[0]), hdr_data_size + pc2dex_data_size); diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc index de66b35418..c932df6dc9 100644 --- a/compiler/dex/quick/mips/call_mips.cc +++ b/compiler/dex/quick/mips/call_mips.cc @@ -275,7 +275,6 @@ void MipsMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) */ skip_overflow_check = mir_graph_->MethodIsLeaf() && !FrameNeedsStackCheck(frame_size_, target); - NewLIR0(kPseudoMethodEntry); RegStorage check_reg = AllocPtrSizeTemp(); RegStorage new_sp = AllocPtrSizeTemp(); const RegStorage rs_sp = TargetPtrReg(kSp); @@ -345,7 +344,6 @@ void MipsMir2Lir::GenExitSequence() { LockTemp(TargetPtrReg(kRet0)); LockTemp(TargetPtrReg(kRet1)); - NewLIR0(kPseudoMethodExit); UnSpillCoreRegs(); OpReg(kOpBx, TargetPtrReg(kLr)); } diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index 0b480a09c6..ed8e21e817 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -1250,10 +1250,14 @@ bool Mir2Lir::MethodBlockCodeGen(BasicBlock* bb) { if (bb->block_type == kEntryBlock) { ResetRegPool(); int start_vreg = mir_graph_->GetFirstInVR(); + AppendLIR(NewLIR0(kPseudoPrologueBegin)); GenEntrySequence(&mir_graph_->reg_location_[start_vreg], mir_graph_->GetMethodLoc()); + AppendLIR(NewLIR0(kPseudoPrologueEnd)); } else if (bb->block_type == kExitBlock) { ResetRegPool(); + AppendLIR(NewLIR0(kPseudoEpilogueBegin)); GenExitSequence(); + AppendLIR(NewLIR0(kPseudoEpilogueEnd)); } for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc index e81228a5e9..fd23692d24 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 { @@ -186,7 +187,6 @@ void X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) { stack_decrement_ = OpRegImm(kOpSub, rs_rSP, frame_size_ - GetInstructionSetPointerSize(cu_->instruction_set)); - NewLIR0(kPseudoMethodEntry); /* Spill core callee saves */ SpillCoreRegs(); SpillFPRegs(); @@ -259,7 +259,6 @@ void X86Mir2Lir::GenExitSequence() { LockTemp(rs_rX86_RET0); LockTemp(rs_rX86_RET1); - NewLIR0(kPseudoMethodExit); UnSpillCoreRegs(); UnSpillFPRegs(); /* Remove frame except for return address */ @@ -322,13 +321,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 +345,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 040a8c4bef..758684e835 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 4eb626c14f..5def5c8bb0 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 f128eb78a3..cad82a183e 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/driver/compiler_options.cc b/compiler/driver/compiler_options.cc index e436f52db3..fc00c926b2 100644 --- a/compiler/driver/compiler_options.cc +++ b/compiler/driver/compiler_options.cc @@ -42,6 +42,11 @@ CompilerOptions::CompilerOptions() init_failure_output_(nullptr) { } +CompilerOptions::~CompilerOptions() { + // The destructor looks empty but it destroys a PassManagerOptions object. We keep it here + // because we don't want to include the PassManagerOptions definition from the header file. +} + CompilerOptions::CompilerOptions(CompilerFilter compiler_filter, size_t huge_method_threshold, size_t large_method_threshold, diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index d06ec278ab..f7ea385e19 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -53,6 +53,7 @@ class CompilerOptions FINAL { static const bool kDefaultIncludePatchInformation = false; CompilerOptions(); + ~CompilerOptions(); CompilerOptions(CompilerFilter compiler_filter, size_t huge_method_threshold, diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index ca5ec66381..a92ce69c6d 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -25,6 +25,8 @@ #include "driver/compiler_driver.h" #include "driver/compiler_options.h" #include "dwarf.h" +#include "dwarf/debug_frame_writer.h" +#include "dwarf/debug_line_writer.h" #include "elf_builder.h" #include "elf_file.h" #include "elf_utils.h" @@ -275,96 +277,8 @@ bool ElfWriterQuick<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn, return builder->Write(); } -class LineTableGenerator FINAL : public Leb128Encoder { - public: - LineTableGenerator(int line_base, int line_range, int opcode_base, - std::vector<uint8_t>* data, uintptr_t current_address, - size_t current_line) - : Leb128Encoder(data), line_base_(line_base), line_range_(line_range), - opcode_base_(opcode_base), current_address_(current_address), - current_line_(current_line), current_file_index_(0) {} - - void PutDelta(unsigned delta_addr, int delta_line) { - current_line_ += delta_line; - current_address_ += delta_addr; - - if (delta_line >= line_base_ && delta_line < line_base_ + line_range_) { - unsigned special_opcode = (delta_line - line_base_) + - (line_range_ * delta_addr) + opcode_base_; - if (special_opcode <= 255) { - PushByte(data_, special_opcode); - return; - } - } - - // generate standart opcode for address advance - if (delta_addr != 0) { - PushByte(data_, DW_LNS_advance_pc); - PushBackUnsigned(delta_addr); - } - - // generate standart opcode for line delta - if (delta_line != 0) { - PushByte(data_, DW_LNS_advance_line); - PushBackSigned(delta_line); - } - - // generate standart opcode for new LTN entry - PushByte(data_, DW_LNS_copy); - } - - void SetAddr(uintptr_t addr) { - if (current_address_ == addr) { - return; - } - - current_address_ = addr; - - PushByte(data_, 0); // extended opcode: - PushByte(data_, 1 + 4); // length: opcode_size + address_size - PushByte(data_, DW_LNE_set_address); - Push32(data_, addr); - } - - void SetLine(unsigned line) { - int delta_line = line - current_line_; - if (delta_line) { - current_line_ = line; - PushByte(data_, DW_LNS_advance_line); - PushBackSigned(delta_line); - } - } - - void SetFile(unsigned file_index) { - if (current_file_index_ != file_index) { - current_file_index_ = file_index; - PushByte(data_, DW_LNS_set_file); - PushBackUnsigned(file_index); - } - } - - void EndSequence() { - // End of Line Table Program - // 0(=ext), 1(len), DW_LNE_end_sequence - PushByte(data_, 0); - PushByte(data_, 1); - PushByte(data_, DW_LNE_end_sequence); - } - - private: - const int line_base_; - const int line_range_; - const int opcode_base_; - uintptr_t current_address_; - size_t current_line_; - unsigned current_file_index_; - - DISALLOW_COPY_AND_ASSIGN(LineTableGenerator); -}; - // TODO: rewriting it using DexFile::DecodeDebugInfo needs unneeded stuff. -static void GetLineInfoForJava(const uint8_t* dbgstream, const SwapSrcMap& pc2dex, - DefaultSrcMap* result, uint32_t start_pc = 0) { +static void GetLineInfoForJava(const uint8_t* dbgstream, DefaultSrcMap* dex2line) { if (dbgstream == nullptr) { return; } @@ -419,12 +333,7 @@ static void GetLineInfoForJava(const uint8_t* dbgstream, const SwapSrcMap& pc2de adjopcode = opcode - DexFile::DBG_FIRST_SPECIAL; dex_offset += adjopcode / DexFile::DBG_LINE_RANGE; java_line += DexFile::DBG_LINE_BASE + (adjopcode % DexFile::DBG_LINE_RANGE); - - for (SwapSrcMap::const_iterator found = pc2dex.FindByTo(dex_offset); - found != pc2dex.end() && found->to_ == static_cast<int32_t>(dex_offset); - found++) { - result->push_back({found->from_ + start_pc, static_cast<int32_t>(java_line)}); - } + dex2line->push_back({dex_offset, static_cast<int32_t>(java_line)}); break; } } @@ -443,71 +352,78 @@ static void FillInCFIInformation(OatWriter* oat_writer, std::vector<uint8_t>* dbg_str, std::vector<uint8_t>* dbg_line, uint32_t text_section_offset) { - const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetCFIMethodInfo(); + const std::vector<OatWriter::DebugInfo>& method_infos = oat_writer->GetCFIMethodInfo(); uint32_t producer_str_offset = PushStr(dbg_str, "Android dex2oat"); + constexpr bool use_64bit_addresses = false; + // Create the debug_abbrev section with boilerplate information. // We only care about low_pc and high_pc right now for the compilation // unit and methods. // Tag 1: Compilation unit: DW_TAG_compile_unit. PushByte(dbg_abbrev, 1); - PushByte(dbg_abbrev, DW_TAG_compile_unit); + PushByte(dbg_abbrev, dwarf::DW_TAG_compile_unit); // There are children (the methods). - PushByte(dbg_abbrev, DW_CHILDREN_yes); + PushByte(dbg_abbrev, dwarf::DW_CHILDREN_yes); // DW_AT_producer DW_FORM_data1. // REVIEW: we can get rid of dbg_str section if // DW_FORM_string (immediate string) was used everywhere instead of // DW_FORM_strp (ref to string from .debug_str section). // DW_FORM_strp makes sense only if we reuse the strings. - PushByte(dbg_abbrev, DW_AT_producer); - PushByte(dbg_abbrev, DW_FORM_strp); + PushByte(dbg_abbrev, dwarf::DW_AT_producer); + PushByte(dbg_abbrev, dwarf::DW_FORM_strp); // DW_LANG_Java DW_FORM_data1. - PushByte(dbg_abbrev, DW_AT_language); - PushByte(dbg_abbrev, DW_FORM_data1); + PushByte(dbg_abbrev, dwarf::DW_AT_language); + PushByte(dbg_abbrev, dwarf::DW_FORM_data1); // DW_AT_low_pc DW_FORM_addr. - PushByte(dbg_abbrev, DW_AT_low_pc); - PushByte(dbg_abbrev, DW_FORM_addr); + PushByte(dbg_abbrev, dwarf::DW_AT_low_pc); + PushByte(dbg_abbrev, dwarf::DW_FORM_addr); // DW_AT_high_pc DW_FORM_addr. - PushByte(dbg_abbrev, DW_AT_high_pc); - PushByte(dbg_abbrev, DW_FORM_addr); + PushByte(dbg_abbrev, dwarf::DW_AT_high_pc); + PushByte(dbg_abbrev, dwarf::DW_FORM_addr); if (dbg_line != nullptr) { // DW_AT_stmt_list DW_FORM_sec_offset. - PushByte(dbg_abbrev, DW_AT_stmt_list); - PushByte(dbg_abbrev, DW_FORM_sec_offset); + PushByte(dbg_abbrev, dwarf::DW_AT_stmt_list); + PushByte(dbg_abbrev, dwarf::DW_FORM_data4); } // End of DW_TAG_compile_unit. - PushHalf(dbg_abbrev, 0); + PushByte(dbg_abbrev, 0); // DW_AT. + PushByte(dbg_abbrev, 0); // DW_FORM. // Tag 2: Compilation unit: DW_TAG_subprogram. PushByte(dbg_abbrev, 2); - PushByte(dbg_abbrev, DW_TAG_subprogram); + PushByte(dbg_abbrev, dwarf::DW_TAG_subprogram); // There are no children. - PushByte(dbg_abbrev, DW_CHILDREN_no); + PushByte(dbg_abbrev, dwarf::DW_CHILDREN_no); // Name of the method. - PushByte(dbg_abbrev, DW_AT_name); - PushByte(dbg_abbrev, DW_FORM_strp); + PushByte(dbg_abbrev, dwarf::DW_AT_name); + PushByte(dbg_abbrev, dwarf::DW_FORM_strp); // DW_AT_low_pc DW_FORM_addr. - PushByte(dbg_abbrev, DW_AT_low_pc); - PushByte(dbg_abbrev, DW_FORM_addr); + PushByte(dbg_abbrev, dwarf::DW_AT_low_pc); + PushByte(dbg_abbrev, dwarf::DW_FORM_addr); // DW_AT_high_pc DW_FORM_addr. - PushByte(dbg_abbrev, DW_AT_high_pc); - PushByte(dbg_abbrev, DW_FORM_addr); + PushByte(dbg_abbrev, dwarf::DW_AT_high_pc); + PushByte(dbg_abbrev, dwarf::DW_FORM_addr); // End of DW_TAG_subprogram. - PushHalf(dbg_abbrev, 0); + PushByte(dbg_abbrev, 0); // DW_AT. + PushByte(dbg_abbrev, 0); // DW_FORM. + + // End of abbrevs for compilation unit + PushByte(dbg_abbrev, 0); // Start the debug_info section with the header information // 'unit_length' will be filled in later. @@ -520,8 +436,8 @@ static void FillInCFIInformation(OatWriter* oat_writer, // Offset into .debug_abbrev section (always 0). Push32(dbg_info, 0); - // Address size: 4. - PushByte(dbg_info, 4); + // Address size: 4 or 8. + PushByte(dbg_info, use_64bit_addresses ? 8 : 4); // Start the description for the compilation unit. // This uses tag 1. @@ -531,31 +447,34 @@ static void FillInCFIInformation(OatWriter* oat_writer, Push32(dbg_info, producer_str_offset); // The language is Java. - PushByte(dbg_info, DW_LANG_Java); + PushByte(dbg_info, dwarf::DW_LANG_Java); // low_pc and high_pc. - uint32_t cunit_low_pc = 0 - 1; + uint32_t cunit_low_pc = static_cast<uint32_t>(-1); uint32_t cunit_high_pc = 0; - int cunit_low_pc_pos = dbg_info->size(); - Push32(dbg_info, 0); - Push32(dbg_info, 0); + for (auto method_info : method_infos) { + cunit_low_pc = std::min(cunit_low_pc, method_info.low_pc_); + cunit_high_pc = std::max(cunit_high_pc, method_info.high_pc_); + } + Push32(dbg_info, cunit_low_pc + text_section_offset); + Push32(dbg_info, cunit_high_pc + text_section_offset); - if (dbg_line == nullptr) { - for (size_t i = 0; i < method_info.size(); ++i) { - const OatWriter::DebugInfo &dbg = method_info[i]; + if (dbg_line != nullptr) { + // Line number table offset. + Push32(dbg_info, dbg_line->size()); + } - cunit_low_pc = std::min(cunit_low_pc, dbg.low_pc_); - cunit_high_pc = std::max(cunit_high_pc, dbg.high_pc_); + for (auto method_info : method_infos) { + // Start a new TAG: subroutine (2). + PushByte(dbg_info, 2); - // Start a new TAG: subroutine (2). - PushByte(dbg_info, 2); + // Enter name, low_pc, high_pc. + Push32(dbg_info, PushStr(dbg_str, method_info.method_name_)); + Push32(dbg_info, method_info.low_pc_ + text_section_offset); + Push32(dbg_info, method_info.high_pc_ + text_section_offset); + } - // Enter name, low_pc, high_pc. - Push32(dbg_info, PushStr(dbg_str, dbg.method_name_)); - Push32(dbg_info, dbg.low_pc_ + text_section_offset); - Push32(dbg_info, dbg.high_pc_ + text_section_offset); - } - } else { + if (dbg_line != nullptr) { // TODO: in gdb info functions <regexp> - reports Java functions, but // source file is <unknown> because .debug_line is formed as one // compilation unit. To fix this it is possible to generate @@ -563,110 +482,135 @@ static void FillInCFIInformation(OatWriter* oat_writer, // Each of the these compilation units can have several non-adjacent // method ranges. - // Line number table offset - Push32(dbg_info, dbg_line->size()); + std::vector<dwarf::DebugLineWriter<>::FileEntry> files; + std::unordered_map<std::string, size_t> files_map; + std::vector<std::string> directories; + std::unordered_map<std::string, size_t> directories_map; + + int code_factor_bits_ = 0; + int isa = -1; + switch (oat_writer->GetOatHeader().GetInstructionSet()) { + case kThumb2: + code_factor_bits_ = 1; // 16-bit instuctions + isa = 1; // DW_ISA_ARM_thumb. + break; + case kArm: + code_factor_bits_ = 2; // 32-bit instructions + isa = 2; // DW_ISA_ARM_arm. + break; + case kArm64: + case kMips: + case kMips64: + code_factor_bits_ = 2; // 32-bit instructions + break; + case kNone: + case kX86: + case kX86_64: + break; + } - size_t lnt_length = dbg_line->size(); - Push32(dbg_line, 0); - - PushHalf(dbg_line, 4); // LNT Version DWARF v4 => 4 - - size_t lnt_hdr_length = dbg_line->size(); - Push32(dbg_line, 0); // TODO: 64-bit uses 8-byte here - - PushByte(dbg_line, 1); // minimum_instruction_length (ubyte) - PushByte(dbg_line, 1); // maximum_operations_per_instruction (ubyte) = always 1 - PushByte(dbg_line, 1); // default_is_stmt (ubyte) - - const int8_t LINE_BASE = -5; - PushByte(dbg_line, LINE_BASE); // line_base (sbyte) - - const uint8_t LINE_RANGE = 14; - PushByte(dbg_line, LINE_RANGE); // line_range (ubyte) - - const uint8_t OPCODE_BASE = 13; - PushByte(dbg_line, OPCODE_BASE); // opcode_base (ubyte) - - // Standard_opcode_lengths (array of ubyte). - PushByte(dbg_line, 0); PushByte(dbg_line, 1); PushByte(dbg_line, 1); - PushByte(dbg_line, 1); PushByte(dbg_line, 1); PushByte(dbg_line, 0); - PushByte(dbg_line, 0); PushByte(dbg_line, 0); PushByte(dbg_line, 1); - PushByte(dbg_line, 0); PushByte(dbg_line, 0); PushByte(dbg_line, 1); - - PushByte(dbg_line, 0); // include_directories (sequence of path names) = EMPTY - - // File_names (sequence of file entries). - std::unordered_map<const char*, size_t> files; - for (size_t i = 0; i < method_info.size(); ++i) { - const OatWriter::DebugInfo &dbg = method_info[i]; - // TODO: add package directory to the file name - const char* file_name = dbg.src_file_name_ == nullptr ? "null" : dbg.src_file_name_; - auto found = files.find(file_name); - if (found == files.end()) { - size_t file_index = 1 + files.size(); - files[file_name] = file_index; - PushStr(dbg_line, file_name); - PushByte(dbg_line, 0); // include directory index = LEB128(0) - no directory - PushByte(dbg_line, 0); // modification time = LEB128(0) - NA - PushByte(dbg_line, 0); // file length = LEB128(0) - NA - } + dwarf::DebugLineOpCodeWriter<> opcodes(use_64bit_addresses, code_factor_bits_); + opcodes.SetAddress(text_section_offset + cunit_low_pc); + if (isa != -1) { + opcodes.SetISA(isa); } - PushByte(dbg_line, 0); // End of file_names. - - // Set lnt header length. - UpdateWord(dbg_line, lnt_hdr_length, dbg_line->size() - lnt_hdr_length - 4); - - // Generate Line Number Program code, one long program for all methods. - LineTableGenerator line_table_generator(LINE_BASE, LINE_RANGE, OPCODE_BASE, - dbg_line, 0, 1); - - DefaultSrcMap pc2java_map; - for (size_t i = 0; i < method_info.size(); ++i) { - const OatWriter::DebugInfo &dbg = method_info[i]; - const char* file_name = (dbg.src_file_name_ == nullptr) ? "null" : dbg.src_file_name_; - size_t file_index = files[file_name]; - DCHECK_NE(file_index, 0U) << file_name; - - cunit_low_pc = std::min(cunit_low_pc, dbg.low_pc_); - cunit_high_pc = std::max(cunit_high_pc, dbg.high_pc_); - - // Start a new TAG: subroutine (2). - PushByte(dbg_info, 2); - - // Enter name, low_pc, high_pc. - Push32(dbg_info, PushStr(dbg_str, dbg.method_name_)); - Push32(dbg_info, dbg.low_pc_ + text_section_offset); - Push32(dbg_info, dbg.high_pc_ + text_section_offset); - - GetLineInfoForJava(dbg.dbgstream_, dbg.compiled_method_->GetSrcMappingTable(), - &pc2java_map, dbg.low_pc_); - pc2java_map.DeltaFormat({dbg.low_pc_, 1}, dbg.high_pc_); - if (!pc2java_map.empty()) { - line_table_generator.SetFile(file_index); - line_table_generator.SetAddr(dbg.low_pc_ + text_section_offset); - line_table_generator.SetLine(1); - for (auto& src_map_elem : pc2java_map) { - line_table_generator.PutDelta(src_map_elem.from_, src_map_elem.to_); + DefaultSrcMap dex2line_map; + for (size_t i = 0; i < method_infos.size(); i++) { + const OatWriter::DebugInfo& method_info = method_infos[i]; + + // Addresses in the line table should be unique and increasing. + if (method_info.deduped_) { + continue; + } + + // Get and deduplicate directory and filename. + int file_index = 0; // 0 - primary source file of the compilation. + if (method_info.src_file_name_ != nullptr) { + std::string file_name(method_info.src_file_name_); + size_t file_name_slash = file_name.find_last_of('/'); + std::string class_name(method_info.class_descriptor_); + size_t class_name_slash = class_name.find_last_of('/'); + std::string full_path(file_name); + + // Guess directory from package name. + int directory_index = 0; // 0 - current directory of the compilation. + if (file_name_slash == std::string::npos && // Just filename. + class_name.front() == 'L' && // Type descriptor for a class. + class_name_slash != std::string::npos) { // Has package name. + std::string package_name = class_name.substr(1, class_name_slash - 1); + auto it = directories_map.find(package_name); + if (it == directories_map.end()) { + directory_index = 1 + directories.size(); + directories_map.emplace(package_name, directory_index); + directories.push_back(package_name); + } else { + directory_index = it->second; + } + full_path = package_name + "/" + file_name; + } + + // Add file entry. + auto it2 = files_map.find(full_path); + if (it2 == files_map.end()) { + file_index = 1 + files.size(); + files_map.emplace(full_path, file_index); + files.push_back(dwarf::DebugLineWriter<>::FileEntry { + file_name, + directory_index, + 0, // Modification time - NA. + 0, // File size - NA. + }); + } else { + file_index = it2->second; } - pc2java_map.clear(); + } + opcodes.SetFile(file_index); + + // Generate mapping opcodes from PC to Java lines. + dex2line_map.clear(); + GetLineInfoForJava(method_info.dbgstream_, &dex2line_map); + uint32_t low_pc = text_section_offset + method_info.low_pc_; + if (file_index != 0 && !dex2line_map.empty()) { + bool first = true; + for (SrcMapElem pc2dex : method_info.compiled_method_->GetSrcMappingTable()) { + uint32_t pc = pc2dex.from_; + int dex = pc2dex.to_; + auto dex2line = dex2line_map.Find(static_cast<uint32_t>(dex)); + if (dex2line.first) { + int line = dex2line.second; + if (first) { + first = false; + if (pc > 0) { + // Assume that any preceding code is prologue. + int first_line = dex2line_map.front().to_; + // Prologue is not a sensible place for a breakpoint. + opcodes.NegateStmt(); + opcodes.AddRow(low_pc, first_line); + opcodes.NegateStmt(); + opcodes.SetPrologueEnd(); + } + opcodes.AddRow(low_pc + pc, line); + } else if (line != opcodes.CurrentLine()) { + opcodes.AddRow(low_pc + pc, line); + } + } + } + } else { + // line 0 - instruction cannot be attributed to any source line. + opcodes.AddRow(low_pc, 0); } } - // End Sequence should have the highest address set. - line_table_generator.SetAddr(cunit_high_pc + text_section_offset); - line_table_generator.EndSequence(); + opcodes.AdvancePC(text_section_offset + cunit_high_pc); + opcodes.EndSequence(); - // set lnt length - UpdateWord(dbg_line, lnt_length, dbg_line->size() - lnt_length - 4); + dwarf::DebugLineWriter<> dbg_line_writer(dbg_line); + dbg_line_writer.WriteTable(directories, files, opcodes); } - // One byte terminator + // One byte terminator. PushByte(dbg_info, 0); - // Fill in cunit's low_pc and high_pc. - UpdateWord(dbg_info, cunit_low_pc_pos, cunit_low_pc + text_section_offset); - UpdateWord(dbg_info, cunit_low_pc_pos + 4, cunit_high_pc + text_section_offset); - // We have now walked all the methods. Fill in lengths. UpdateWord(dbg_info, cunit_length, dbg_info->size() - cunit_length - 4); } @@ -690,8 +634,11 @@ static void WriteDebugSymbols(const CompilerDriver* compiler_driver, ElfSymtabBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Sym, Elf_Shdr>* symtab = builder->GetSymtabBuilder(); for (auto it = method_info.begin(); it != method_info.end(); ++it) { - symtab->AddSymbol(it->method_name_, &builder->GetTextBuilder(), it->low_pc_, true, - it->high_pc_ - it->low_pc_, STB_GLOBAL, STT_FUNC); + uint32_t low_pc = it->low_pc_; + // Add in code delta, e.g., thumb bit 0 for Thumb2 code. + low_pc += it->compiled_method_->CodeDelta(); + symtab->AddSymbol(it->method_name_, &builder->GetTextBuilder(), low_pc, + true, it->high_pc_ - it->low_pc_, STB_GLOBAL, STT_FUNC); // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2 // instructions, so that disassembler tools can correctly disassemble. diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc new file mode 100644 index 0000000000..2eae2a8001 --- /dev/null +++ b/compiler/linker/arm/relative_patcher_arm_base.cc @@ -0,0 +1,181 @@ +/* + * 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. + */ + +#include "linker/arm/relative_patcher_arm_base.h" + +#include "compiled_method.h" +#include "oat.h" +#include "output_stream.h" + +namespace art { +namespace linker { + +uint32_t ArmBaseRelativePatcher::ReserveSpace(uint32_t offset, + const CompiledMethod* compiled_method, + MethodReference method_ref) { + return ReserveSpaceInternal(offset, compiled_method, method_ref, 0u); +} + +uint32_t ArmBaseRelativePatcher::WriteThunks(OutputStream* out, uint32_t offset) { + if (current_thunk_to_write_ == thunk_locations_.size()) { + return offset; + } + uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_); + if (UNLIKELY(aligned_offset == thunk_locations_[current_thunk_to_write_])) { + ++current_thunk_to_write_; + uint32_t aligned_code_delta = aligned_offset - offset; + if (aligned_code_delta != 0u && !WriteCodeAlignment(out, aligned_code_delta)) { + return 0u; + } + if (UNLIKELY(!WriteRelCallThunk(out, ArrayRef<const uint8_t>(thunk_code_)))) { + return 0u; + } + uint32_t thunk_end_offset = aligned_offset + thunk_code_.size(); + // Align after writing chunk, see the ReserveSpace() above. + offset = CompiledMethod::AlignCode(thunk_end_offset, instruction_set_); + aligned_code_delta = offset - thunk_end_offset; + if (aligned_code_delta != 0u && !WriteCodeAlignment(out, aligned_code_delta)) { + return 0u; + } + } + return offset; +} + +ArmBaseRelativePatcher::ArmBaseRelativePatcher(RelativePatcherTargetProvider* provider, + InstructionSet instruction_set, + std::vector<uint8_t> thunk_code, + uint32_t max_positive_displacement, + uint32_t max_negative_displacement) + : provider_(provider), instruction_set_(instruction_set), thunk_code_(thunk_code), + max_positive_displacement_(max_positive_displacement), + max_negative_displacement_(max_negative_displacement), + thunk_locations_(), current_thunk_to_write_(0u), unprocessed_patches_() { +} + +uint32_t ArmBaseRelativePatcher::ReserveSpaceInternal(uint32_t offset, + const CompiledMethod* compiled_method, + MethodReference method_ref, + uint32_t max_extra_space) { + // NOTE: The final thunk can be reserved from InitCodeMethodVisitor::EndClass() while it + // may be written early by WriteCodeMethodVisitor::VisitMethod() for a deduplicated chunk + // of code. To avoid any alignment discrepancies for the final chunk, we always align the + // offset after reserving of writing any chunk. + if (UNLIKELY(compiled_method == nullptr)) { + uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_); + DCHECK(method_ref.dex_file == nullptr && method_ref.dex_method_index == 0u); + bool needs_thunk = ReserveSpaceProcessPatches(aligned_offset, method_ref, aligned_offset); + if (needs_thunk) { + thunk_locations_.push_back(aligned_offset); + offset = CompiledMethod::AlignCode(aligned_offset + thunk_code_.size(), instruction_set_); + } + return offset; + } + DCHECK(compiled_method->GetQuickCode() != nullptr); + uint32_t quick_code_size = compiled_method->GetQuickCode()->size(); + uint32_t quick_code_offset = compiled_method->AlignCode(offset) + sizeof(OatQuickMethodHeader); + uint32_t next_aligned_offset = compiled_method->AlignCode(quick_code_offset + quick_code_size); + // Adjust for extra space required by the subclass. + next_aligned_offset = compiled_method->AlignCode(next_aligned_offset + max_extra_space); + // TODO: ignore unprocessed patches targeting this method if they can reach quick_code_offset. + // We need the MethodReference for that. + if (!unprocessed_patches_.empty() && + next_aligned_offset - unprocessed_patches_.front().second > max_positive_displacement_) { + bool needs_thunk = ReserveSpaceProcessPatches(quick_code_offset, method_ref, + next_aligned_offset); + if (needs_thunk) { + // A single thunk will cover all pending patches. + unprocessed_patches_.clear(); + uint32_t thunk_location = compiled_method->AlignCode(offset); + thunk_locations_.push_back(thunk_location); + offset = CompiledMethod::AlignCode(thunk_location + thunk_code_.size(), instruction_set_); + } + } + for (const LinkerPatch& patch : compiled_method->GetPatches()) { + if (patch.Type() == kLinkerPatchCallRelative) { + unprocessed_patches_.emplace_back(patch.TargetMethod(), + quick_code_offset + patch.LiteralOffset()); + } + } + return offset; +} + +uint32_t ArmBaseRelativePatcher::CalculateDisplacement(uint32_t patch_offset, + uint32_t target_offset) { + // Unsigned arithmetic with its well-defined overflow behavior is just fine here. + uint32_t displacement = target_offset - patch_offset; + // NOTE: With unsigned arithmetic we do mean to use && rather than || below. + if (displacement > max_positive_displacement_ && displacement < -max_negative_displacement_) { + // Unwritten thunks have higher offsets, check if it's within range. + DCHECK(current_thunk_to_write_ == thunk_locations_.size() || + thunk_locations_[current_thunk_to_write_] > patch_offset); + if (current_thunk_to_write_ != thunk_locations_.size() && + thunk_locations_[current_thunk_to_write_] - patch_offset < max_positive_displacement_) { + displacement = thunk_locations_[current_thunk_to_write_] - patch_offset; + } else { + // We must have a previous thunk then. + DCHECK_NE(current_thunk_to_write_, 0u); + DCHECK_LT(thunk_locations_[current_thunk_to_write_ - 1], patch_offset); + displacement = thunk_locations_[current_thunk_to_write_ - 1] - patch_offset; + DCHECK(displacement >= -max_negative_displacement_); + } + } + return displacement; +} + +bool ArmBaseRelativePatcher::ReserveSpaceProcessPatches(uint32_t quick_code_offset, + MethodReference method_ref, + uint32_t next_aligned_offset) { + // Process as many patches as possible, stop only on unresolved targets or calls too far back. + while (!unprocessed_patches_.empty()) { + MethodReference patch_ref = unprocessed_patches_.front().first; + uint32_t patch_offset = unprocessed_patches_.front().second; + DCHECK(thunk_locations_.empty() || thunk_locations_.back() <= patch_offset); + if (patch_ref.dex_file == method_ref.dex_file && + patch_ref.dex_method_index == method_ref.dex_method_index) { + DCHECK_GT(quick_code_offset, patch_offset); + if (quick_code_offset - patch_offset > max_positive_displacement_) { + return true; + } + } else { + auto result = provider_->FindMethodOffset(patch_ref); + if (!result.first) { + // If still unresolved, check if we have a thunk within range. + if (thunk_locations_.empty() || + patch_offset - thunk_locations_.back() > max_negative_displacement_) { + return next_aligned_offset - patch_offset > max_positive_displacement_; + } + } else { + uint32_t target_offset = result.second - CompiledCode::CodeDelta(instruction_set_); + if (target_offset >= patch_offset) { + DCHECK_LE(target_offset - patch_offset, max_positive_displacement_); + } else { + // When calling back, check if we have a thunk that's closer than the actual target. + if (!thunk_locations_.empty()) { + target_offset = std::max(target_offset, thunk_locations_.back()); + } + if (patch_offset - target_offset > max_negative_displacement_) { + return true; + } + } + } + } + unprocessed_patches_.pop_front(); + } + return false; +} + +} // namespace linker +} // namespace art diff --git a/compiler/linker/arm/relative_patcher_arm_base.h b/compiler/linker/arm/relative_patcher_arm_base.h new file mode 100644 index 0000000000..35a8b8e5f0 --- /dev/null +++ b/compiler/linker/arm/relative_patcher_arm_base.h @@ -0,0 +1,67 @@ +/* + * 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_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_ +#define ART_COMPILER_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_ + +#include <deque> + +#include "linker/relative_patcher.h" +#include "method_reference.h" + +namespace art { +namespace linker { + +class ArmBaseRelativePatcher : public RelativePatcher { + public: + uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method, + MethodReference method_ref) OVERRIDE; + uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE; + + protected: + ArmBaseRelativePatcher(RelativePatcherTargetProvider* provider, + InstructionSet instruction_set, std::vector<uint8_t> thunk_code, + uint32_t max_positive_displacement, uint32_t max_negative_displacement); + + uint32_t ReserveSpaceInternal(uint32_t offset, const CompiledMethod* compiled_method, + MethodReference method_ref, uint32_t max_extra_space); + uint32_t CalculateDisplacement(uint32_t patch_offset, uint32_t target_offset); + + private: + bool ReserveSpaceProcessPatches(uint32_t quick_code_offset, MethodReference method_ref, + uint32_t next_aligned_offset); + + RelativePatcherTargetProvider* const provider_; + const InstructionSet instruction_set_; + const std::vector<uint8_t> thunk_code_; + const uint32_t max_positive_displacement_; + const uint32_t max_negative_displacement_; + std::vector<uint32_t> thunk_locations_; + size_t current_thunk_to_write_; + + // ReserveSpace() tracks unprocessed patches. + typedef std::pair<MethodReference, uint32_t> UnprocessedPatch; + std::deque<UnprocessedPatch> unprocessed_patches_; + + friend class Thumb2RelativePatcherTest; + + DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativePatcher); +}; + +} // namespace linker +} // namespace art + +#endif // ART_COMPILER_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_ diff --git a/compiler/linker/arm/relative_patcher_thumb2.cc b/compiler/linker/arm/relative_patcher_thumb2.cc new file mode 100644 index 0000000000..4267743097 --- /dev/null +++ b/compiler/linker/arm/relative_patcher_thumb2.cc @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#include "linker/arm/relative_patcher_thumb2.h" + +#include "compiled_method.h" +#include "mirror/art_method.h" +#include "utils/arm/assembler_thumb2.h" + +namespace art { +namespace linker { + +Thumb2RelativePatcher::Thumb2RelativePatcher(RelativePatcherTargetProvider* provider) + : ArmBaseRelativePatcher(provider, kThumb2, CompileThunkCode(), + kMaxPositiveDisplacement, kMaxNegativeDisplacement) { +} + +void Thumb2RelativePatcher::PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, + uint32_t patch_offset, uint32_t target_offset) { + DCHECK_LE(literal_offset + 4u, code->size()); + DCHECK_EQ(literal_offset & 1u, 0u); + DCHECK_EQ(patch_offset & 1u, 0u); + DCHECK_EQ(target_offset & 1u, 1u); // Thumb2 mode bit. + uint32_t displacement = CalculateDisplacement(patch_offset, target_offset & ~1u); + displacement -= kPcDisplacement; // The base PC is at the end of the 4-byte patch. + DCHECK_EQ(displacement & 1u, 0u); + DCHECK((displacement >> 24) == 0u || (displacement >> 24) == 255u); // 25-bit signed. + uint32_t signbit = (displacement >> 31) & 0x1; + uint32_t i1 = (displacement >> 23) & 0x1; + uint32_t i2 = (displacement >> 22) & 0x1; + uint32_t imm10 = (displacement >> 12) & 0x03ff; + uint32_t imm11 = (displacement >> 1) & 0x07ff; + uint32_t j1 = i1 ^ (signbit ^ 1); + uint32_t j2 = i2 ^ (signbit ^ 1); + uint32_t value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) | imm11; + value |= 0xf000d000; // BL + + uint8_t* addr = &(*code)[literal_offset]; + // Check that we're just overwriting an existing BL. + DCHECK_EQ(addr[1] & 0xf8, 0xf0); + DCHECK_EQ(addr[3] & 0xd0, 0xd0); + // Write the new BL. + addr[0] = (value >> 16) & 0xff; + addr[1] = (value >> 24) & 0xff; + addr[2] = (value >> 0) & 0xff; + addr[3] = (value >> 8) & 0xff; +} + +void Thumb2RelativePatcher::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."; +} + +std::vector<uint8_t> Thumb2RelativePatcher::CompileThunkCode() { + // The thunk just uses the entry point in the ArtMethod. This works even for calls + // to the generic JNI and interpreter trampolines. + arm::Thumb2Assembler assembler; + assembler.LoadFromOffset( + arm::kLoadWord, arm::PC, arm::R0, + mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value()); + assembler.bkpt(0); + std::vector<uint8_t> thunk_code(assembler.CodeSize()); + MemoryRegion code(thunk_code.data(), thunk_code.size()); + assembler.FinalizeInstructions(code); + return thunk_code; +} + +} // namespace linker +} // namespace art diff --git a/compiler/linker/arm/relative_patcher_thumb2.h b/compiler/linker/arm/relative_patcher_thumb2.h new file mode 100644 index 0000000000..561130305e --- /dev/null +++ b/compiler/linker/arm/relative_patcher_thumb2.h @@ -0,0 +1,52 @@ +/* + * 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_LINKER_ARM_RELATIVE_PATCHER_THUMB2_H_ +#define ART_COMPILER_LINKER_ARM_RELATIVE_PATCHER_THUMB2_H_ + +#include "linker/arm/relative_patcher_arm_base.h" + +namespace art { +namespace linker { + +class Thumb2RelativePatcher FINAL : public ArmBaseRelativePatcher { + public: + explicit Thumb2RelativePatcher(RelativePatcherTargetProvider* provider); + + void PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, + uint32_t patch_offset, uint32_t target_offset) OVERRIDE; + void PatchDexCacheReference(std::vector<uint8_t>* code, const LinkerPatch& patch, + uint32_t patch_offset, uint32_t target_offset) OVERRIDE; + + private: + static std::vector<uint8_t> CompileThunkCode(); + + // PC displacement from patch location; Thumb2 PC is always at instruction address + 4. + static constexpr int32_t kPcDisplacement = 4; + + // Maximum positive and negative displacement measured from the patch location. + // (Signed 25 bit displacement with the last bit 0 has range [-2^24, 2^24-2] measured from + // the Thumb2 PC pointing right after the BL, i.e. 4 bytes later than the patch location.) + static constexpr uint32_t kMaxPositiveDisplacement = (1u << 24) - 2 + kPcDisplacement; + static constexpr uint32_t kMaxNegativeDisplacement = (1u << 24) - kPcDisplacement; + + DISALLOW_COPY_AND_ASSIGN(Thumb2RelativePatcher); +}; + +} // namespace linker +} // namespace art + +#endif // ART_COMPILER_LINKER_ARM_RELATIVE_PATCHER_THUMB2_H_ diff --git a/compiler/linker/arm/relative_patcher_thumb2_test.cc b/compiler/linker/arm/relative_patcher_thumb2_test.cc new file mode 100644 index 0000000000..abdfd6d64b --- /dev/null +++ b/compiler/linker/arm/relative_patcher_thumb2_test.cc @@ -0,0 +1,289 @@ +/* + * 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. + */ + +#include "linker/relative_patcher_test.h" +#include "linker/arm/relative_patcher_thumb2.h" + +namespace art { +namespace linker { + +class Thumb2RelativePatcherTest : public RelativePatcherTest { + public: + Thumb2RelativePatcherTest() : RelativePatcherTest(kThumb2, "default") { } + + protected: + static const uint8_t kCallRawCode[]; + static const ArrayRef<const uint8_t> kCallCode; + static const uint8_t kNopRawCode[]; + static const ArrayRef<const uint8_t> kNopCode; + + // Branches within range [-256, 256) can be created from these by adding the low 8 bits. + static constexpr uint32_t kBlPlus0 = 0xf000f800; + static constexpr uint32_t kBlMinus256 = 0xf7ffff00; + + // Special BL values. + static constexpr uint32_t kBlPlusMax = 0xf3ffd7ff; + static constexpr uint32_t kBlMinusMax = 0xf400d000; + + bool Create2MethodsWithGap(const ArrayRef<const uint8_t>& method1_code, + const ArrayRef<LinkerPatch>& method1_patches, + const ArrayRef<const uint8_t>& method3_code, + const ArrayRef<LinkerPatch>& method3_patches, + uint32_t distance_without_thunks) { + CHECK_EQ(distance_without_thunks % kArmAlignment, 0u); + const uint32_t method1_offset = + CompiledCode::AlignCode(kTrampolineSize, kThumb2) + sizeof(OatQuickMethodHeader); + AddCompiledMethod(MethodRef(1u), method1_code, ArrayRef<LinkerPatch>(method1_patches)); + + // We want to put the method3 at a very precise offset. + const uint32_t method3_offset = method1_offset + distance_without_thunks; + CHECK(IsAligned<kArmAlignment>(method3_offset - sizeof(OatQuickMethodHeader))); + + // Calculate size of method2 so that we put method3 at the correct place. + const uint32_t method2_offset = + CompiledCode::AlignCode(method1_offset + method1_code.size(), kThumb2) + + sizeof(OatQuickMethodHeader); + const uint32_t method2_size = (method3_offset - sizeof(OatQuickMethodHeader) - method2_offset); + std::vector<uint8_t> method2_raw_code(method2_size); + ArrayRef<const uint8_t> method2_code(method2_raw_code); + AddCompiledMethod(MethodRef(2u), method2_code, ArrayRef<LinkerPatch>()); + + AddCompiledMethod(MethodRef(3u), method3_code, method3_patches); + + Link(); + + // Check assumptions. + CHECK_EQ(GetMethodOffset(1), method1_offset); + CHECK_EQ(GetMethodOffset(2), method2_offset); + auto result3 = method_offset_map_.FindMethodOffset(MethodRef(3)); + CHECK(result3.first); + // There may be a thunk before method2. + if (result3.second == method3_offset + 1 /* thumb mode */) { + return false; // No thunk. + } else { + uint32_t aligned_thunk_size = CompiledCode::AlignCode(ThunkSize(), kThumb2); + CHECK_EQ(result3.second, method3_offset + aligned_thunk_size + 1 /* thumb mode */); + return true; // Thunk present. + } + } + + uint32_t GetMethodOffset(uint32_t method_idx) { + auto result = method_offset_map_.FindMethodOffset(MethodRef(method_idx)); + CHECK(result.first); + CHECK_NE(result.second & 1u, 0u); + return result.second - 1 /* thumb mode */; + } + + uint32_t ThunkSize() { + return static_cast<Thumb2RelativePatcher*>(patcher_.get())->thunk_code_.size(); + } + + bool CheckThunk(uint32_t thunk_offset) { + Thumb2RelativePatcher* patcher = static_cast<Thumb2RelativePatcher*>(patcher_.get()); + ArrayRef<const uint8_t> expected_code(patcher->thunk_code_); + if (output_.size() < thunk_offset + expected_code.size()) { + LOG(ERROR) << "output_.size() == " << output_.size() << " < " + << "thunk_offset + expected_code.size() == " << (thunk_offset + expected_code.size()); + return false; + } + ArrayRef<const uint8_t> linked_code(&output_[thunk_offset], expected_code.size()); + if (linked_code == expected_code) { + return true; + } + // Log failure info. + DumpDiff(expected_code, linked_code); + return false; + } + + std::vector<uint8_t> GenNopsAndBl(size_t num_nops, uint32_t bl) { + std::vector<uint8_t> result; + result.reserve(num_nops * 2u + 4u); + for (size_t i = 0; i != num_nops; ++i) { + result.push_back(0x00); + result.push_back(0xbf); + } + result.push_back(static_cast<uint8_t>(bl >> 16)); + result.push_back(static_cast<uint8_t>(bl >> 24)); + result.push_back(static_cast<uint8_t>(bl)); + result.push_back(static_cast<uint8_t>(bl >> 8)); + return result; + } +}; + +const uint8_t Thumb2RelativePatcherTest::kCallRawCode[] = { + 0x00, 0xf0, 0x00, 0xf8 +}; + +const ArrayRef<const uint8_t> Thumb2RelativePatcherTest::kCallCode(kCallRawCode); + +const uint8_t Thumb2RelativePatcherTest::kNopRawCode[] = { + 0x00, 0xbf +}; + +const ArrayRef<const uint8_t> Thumb2RelativePatcherTest::kNopCode(kNopRawCode); + +TEST_F(Thumb2RelativePatcherTest, CallSelf) { + LinkerPatch patches[] = { + LinkerPatch::RelativeCodePatch(0u, nullptr, 1u), + }; + AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<LinkerPatch>(patches)); + Link(); + + static const uint8_t expected_code[] = { + 0xff, 0xf7, 0xfe, 0xff + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); +} + +TEST_F(Thumb2RelativePatcherTest, CallOther) { + LinkerPatch method1_patches[] = { + LinkerPatch::RelativeCodePatch(0u, nullptr, 2u), + }; + AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<LinkerPatch>(method1_patches)); + LinkerPatch method2_patches[] = { + LinkerPatch::RelativeCodePatch(0u, nullptr, 1u), + }; + AddCompiledMethod(MethodRef(2u), kCallCode, ArrayRef<LinkerPatch>(method2_patches)); + Link(); + + uint32_t method1_offset = GetMethodOffset(1u); + uint32_t method2_offset = GetMethodOffset(2u); + uint32_t diff_after = method2_offset - (method1_offset + 4u /* PC adjustment */); + ASSERT_EQ(diff_after & 1u, 0u); + ASSERT_LT(diff_after >> 1, 1u << 8); // Simple encoding, (diff_after >> 1) fits into 8 bits. + static const uint8_t method1_expected_code[] = { + 0x00, 0xf0, static_cast<uint8_t>(diff_after >> 1), 0xf8 + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(method1_expected_code))); + uint32_t diff_before = method1_offset - (method2_offset + 4u /* PC adjustment */); + ASSERT_EQ(diff_before & 1u, 0u); + ASSERT_GE(diff_before, -1u << 9); // Simple encoding, -256 <= (diff >> 1) < 0. + auto method2_expected_code = GenNopsAndBl(0u, kBlMinus256 | ((diff_before >> 1) & 0xffu)); + EXPECT_TRUE(CheckLinkedMethod(MethodRef(2u), ArrayRef<const uint8_t>(method2_expected_code))); +} + +TEST_F(Thumb2RelativePatcherTest, CallTrampoline) { + LinkerPatch patches[] = { + LinkerPatch::RelativeCodePatch(0u, nullptr, 2u), + }; + AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<LinkerPatch>(patches)); + Link(); + + uint32_t method1_offset = GetMethodOffset(1u); + uint32_t diff = kTrampolineOffset - (method1_offset + 4u); + ASSERT_EQ(diff & 1u, 0u); + ASSERT_GE(diff, -1u << 9); // Simple encoding, -256 <= (diff >> 1) < 0 (checked as unsigned). + auto expected_code = GenNopsAndBl(0u, kBlMinus256 | ((diff >> 1) & 0xffu)); + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); +} + +TEST_F(Thumb2RelativePatcherTest, CallOtherAlmostTooFarAfter) { + auto method1_raw_code = GenNopsAndBl(3u, kBlPlus0); + constexpr uint32_t bl_offset_in_method1 = 3u * 2u; // After NOPs. + ArrayRef<const uint8_t> method1_code(method1_raw_code); + ASSERT_EQ(bl_offset_in_method1 + 4u, method1_code.size()); + LinkerPatch method1_patches[] = { + LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, 3u), + }; + + constexpr uint32_t max_positive_disp = 16 * MB - 2u + 4u /* PC adjustment */; + bool thunk_in_gap = Create2MethodsWithGap(method1_code, method1_patches, + kNopCode, ArrayRef<LinkerPatch>(), + bl_offset_in_method1 + max_positive_disp); + ASSERT_FALSE(thunk_in_gap); // There should be no thunk. + + // Check linked code. + auto expected_code = GenNopsAndBl(3u, kBlPlusMax); + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); +} + +TEST_F(Thumb2RelativePatcherTest, CallOtherAlmostTooFarBefore) { + auto method3_raw_code = GenNopsAndBl(2u, kBlPlus0); + constexpr uint32_t bl_offset_in_method3 = 2u * 2u; // After NOPs. + ArrayRef<const uint8_t> method3_code(method3_raw_code); + ASSERT_EQ(bl_offset_in_method3 + 4u, method3_code.size()); + LinkerPatch method3_patches[] = { + LinkerPatch::RelativeCodePatch(bl_offset_in_method3, nullptr, 1u), + }; + + constexpr uint32_t just_over_max_negative_disp = 16 * MB - 4u /* PC adjustment */; + bool thunk_in_gap = Create2MethodsWithGap(kNopCode, ArrayRef<LinkerPatch>(), + method3_code, method3_patches, + just_over_max_negative_disp - bl_offset_in_method3); + ASSERT_FALSE(thunk_in_gap); // There should be no thunk. + + // Check linked code. + auto expected_code = GenNopsAndBl(2u, kBlMinusMax); + EXPECT_TRUE(CheckLinkedMethod(MethodRef(3u), ArrayRef<const uint8_t>(expected_code))); +} + +TEST_F(Thumb2RelativePatcherTest, CallOtherJustTooFarAfter) { + auto method1_raw_code = GenNopsAndBl(2u, kBlPlus0); + constexpr uint32_t bl_offset_in_method1 = 2u * 2u; // After NOPs. + ArrayRef<const uint8_t> method1_code(method1_raw_code); + ASSERT_EQ(bl_offset_in_method1 + 4u, method1_code.size()); + LinkerPatch method1_patches[] = { + LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, 3u), + }; + + constexpr uint32_t just_over_max_positive_disp = 16 * MB + 4u /* PC adjustment */; + bool thunk_in_gap = Create2MethodsWithGap(method1_code, method1_patches, + kNopCode, ArrayRef<LinkerPatch>(), + bl_offset_in_method1 + just_over_max_positive_disp); + ASSERT_TRUE(thunk_in_gap); + + uint32_t method1_offset = GetMethodOffset(1u); + uint32_t method3_offset = GetMethodOffset(3u); + uint32_t method3_header_offset = method3_offset - sizeof(OatQuickMethodHeader); + ASSERT_TRUE(IsAligned<kArmAlignment>(method3_header_offset)); + uint32_t thunk_offset = method3_header_offset - CompiledCode::AlignCode(ThunkSize(), kThumb2); + ASSERT_TRUE(IsAligned<kArmAlignment>(thunk_offset)); + uint32_t diff = thunk_offset - (method1_offset + bl_offset_in_method1 + 4u /* PC adjustment */); + ASSERT_EQ(diff & 1u, 0u); + ASSERT_GE(diff, 16 * MB - (1u << 9)); // Simple encoding, unknown bits fit into the low 8 bits. + auto expected_code = GenNopsAndBl(2u, 0xf3ffd700 | ((diff >> 1) & 0xffu)); + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); + CheckThunk(thunk_offset); +} + +TEST_F(Thumb2RelativePatcherTest, CallOtherJustTooFarBefore) { + auto method3_raw_code = GenNopsAndBl(3u, kBlPlus0); + constexpr uint32_t bl_offset_in_method3 = 3u * 2u; // After NOPs. + ArrayRef<const uint8_t> method3_code(method3_raw_code); + ASSERT_EQ(bl_offset_in_method3 + 4u, method3_code.size()); + LinkerPatch method3_patches[] = { + LinkerPatch::RelativeCodePatch(bl_offset_in_method3, nullptr, 1u), + }; + + constexpr uint32_t just_over_max_negative_disp = 16 * MB + 2 - 4u /* PC adjustment */; + bool thunk_in_gap = Create2MethodsWithGap(kNopCode, ArrayRef<LinkerPatch>(), + method3_code, method3_patches, + just_over_max_negative_disp - bl_offset_in_method3); + ASSERT_FALSE(thunk_in_gap); // There should be a thunk but it should be after the method2. + + // Check linked code. + uint32_t method3_offset = GetMethodOffset(3u); + uint32_t thunk_offset = CompiledCode::AlignCode(method3_offset + method3_code.size(), kThumb2); + uint32_t diff = thunk_offset - (method3_offset + bl_offset_in_method3 + 4u /* PC adjustment */); + ASSERT_EQ(diff & 1u, 0u); + ASSERT_LT(diff >> 1, 1u << 8); // Simple encoding, (diff >> 1) fits into 8 bits. + auto expected_code = GenNopsAndBl(3u, kBlPlus0 | ((diff >> 1) & 0xffu)); + EXPECT_TRUE(CheckLinkedMethod(MethodRef(3u), ArrayRef<const uint8_t>(expected_code))); + EXPECT_TRUE(CheckThunk(thunk_offset)); +} + +} // namespace linker +} // namespace art diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc new file mode 100644 index 0000000000..b61b3d8e44 --- /dev/null +++ b/compiler/linker/arm64/relative_patcher_arm64.cc @@ -0,0 +1,285 @@ +/* + * 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. + */ + +#include "linker/arm64/relative_patcher_arm64.h" + +#include "arch/arm64/instruction_set_features_arm64.h" +#include "compiled_method.h" +#include "driver/compiler_driver.h" +#include "mirror/art_method.h" +#include "utils/arm64/assembler_arm64.h" +#include "oat.h" +#include "output_stream.h" + +namespace art { +namespace linker { + +Arm64RelativePatcher::Arm64RelativePatcher(RelativePatcherTargetProvider* provider, + const Arm64InstructionSetFeatures* features) + : ArmBaseRelativePatcher(provider, kArm64, CompileThunkCode(), + kMaxPositiveDisplacement, kMaxNegativeDisplacement), + fix_cortex_a53_843419_(features->NeedFixCortexA53_843419()), + reserved_adrp_thunks_(0u), + processed_adrp_thunks_(0u) { + if (fix_cortex_a53_843419_) { + adrp_thunk_locations_.reserve(16u); + current_method_thunks_.reserve(16u * kAdrpThunkSize); + } +} + +uint32_t Arm64RelativePatcher::ReserveSpace(uint32_t offset, + const CompiledMethod* compiled_method, + MethodReference method_ref) { + if (!fix_cortex_a53_843419_) { + DCHECK(adrp_thunk_locations_.empty()); + return ReserveSpaceInternal(offset, compiled_method, method_ref, 0u); + } + + // Add thunks for previous method if any. + if (reserved_adrp_thunks_ != adrp_thunk_locations_.size()) { + size_t num_adrp_thunks = adrp_thunk_locations_.size() - reserved_adrp_thunks_; + offset = CompiledMethod::AlignCode(offset, kArm64) + kAdrpThunkSize * num_adrp_thunks; + reserved_adrp_thunks_ = adrp_thunk_locations_.size(); + } + + // Count the number of ADRP insns as the upper bound on the number of thunks needed + // and use it to reserve space for other linker patches. + size_t num_adrp = 0u; + if (LIKELY(compiled_method != nullptr)) { + for (const LinkerPatch& patch : compiled_method->GetPatches()) { + if (patch.Type() == kLinkerPatchDexCacheArray && + patch.LiteralOffset() == patch.PcInsnOffset()) { // ADRP patch + ++num_adrp; + } + } + } + offset = ReserveSpaceInternal(offset, compiled_method, method_ref, kAdrpThunkSize * num_adrp); + if (num_adrp == 0u) { + return offset; + } + + // Now that we have the actual offset where the code will be placed, locate the ADRP insns + // that actually require the thunk. + uint32_t quick_code_offset = compiled_method->AlignCode(offset) + sizeof(OatQuickMethodHeader); + ArrayRef<const uint8_t> code(*compiled_method->GetQuickCode()); + uint32_t thunk_offset = compiled_method->AlignCode(quick_code_offset + code.size()); + DCHECK(compiled_method != nullptr); + for (const LinkerPatch& patch : compiled_method->GetPatches()) { + if (patch.Type() == kLinkerPatchDexCacheArray && + patch.LiteralOffset() == patch.PcInsnOffset()) { // ADRP patch + uint32_t patch_offset = quick_code_offset + patch.LiteralOffset(); + if (NeedsErratum843419Thunk(code, patch.LiteralOffset(), patch_offset)) { + adrp_thunk_locations_.emplace_back(patch_offset, thunk_offset); + thunk_offset += kAdrpThunkSize; + } + } + } + return offset; +} + +uint32_t Arm64RelativePatcher::WriteThunks(OutputStream* out, uint32_t offset) { + if (fix_cortex_a53_843419_) { + if (!current_method_thunks_.empty()) { + uint32_t aligned_offset = CompiledMethod::AlignCode(offset, kArm64); + if (kIsDebugBuild) { + CHECK(IsAligned<kAdrpThunkSize>(current_method_thunks_.size())); + size_t num_thunks = current_method_thunks_.size() / kAdrpThunkSize; + CHECK_LE(num_thunks, processed_adrp_thunks_); + for (size_t i = 0u; i != num_thunks; ++i) { + const auto& entry = adrp_thunk_locations_[processed_adrp_thunks_ - num_thunks + i]; + CHECK_EQ(entry.second, aligned_offset + i * kAdrpThunkSize); + } + } + uint32_t aligned_code_delta = aligned_offset - offset; + if (aligned_code_delta != 0u && !WriteCodeAlignment(out, aligned_code_delta)) { + return 0u; + } + if (!WriteMiscThunk(out, ArrayRef<const uint8_t>(current_method_thunks_))) { + return 0u; + } + offset = aligned_offset + current_method_thunks_.size(); + current_method_thunks_.clear(); + } + } + return ArmBaseRelativePatcher::WriteThunks(out, offset); +} + +void Arm64RelativePatcher::PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, + uint32_t patch_offset, uint32_t target_offset) { + DCHECK_LE(literal_offset + 4u, code->size()); + DCHECK_EQ(literal_offset & 3u, 0u); + DCHECK_EQ(patch_offset & 3u, 0u); + DCHECK_EQ(target_offset & 3u, 0u); + 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 insn = (displacement & 0x0fffffffu) >> 2; + insn |= 0x94000000; // BL + + // Check that we're just overwriting an existing BL. + DCHECK_EQ(GetInsn(code, literal_offset) & 0xfc000000u, 0x94000000u); + // Write the new BL. + SetInsn(code, literal_offset, insn); +} + +void Arm64RelativePatcher::PatchDexCacheReference(std::vector<uint8_t>* code, + const LinkerPatch& patch, + uint32_t patch_offset, + uint32_t target_offset) { + 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; + if (fix_cortex_a53_843419_ && processed_adrp_thunks_ != adrp_thunk_locations_.size() && + adrp_thunk_locations_[processed_adrp_thunks_].first == patch_offset) { + DCHECK(NeedsErratum843419Thunk(ArrayRef<const uint8_t>(*code), + literal_offset, patch_offset)); + uint32_t thunk_offset = adrp_thunk_locations_[processed_adrp_thunks_].second; + uint32_t adrp_disp = target_offset - (thunk_offset & ~0xfffu); + uint32_t adrp = PatchAdrp(insn, adrp_disp); + + uint32_t out_disp = thunk_offset - patch_offset; + DCHECK_EQ(out_disp & 3u, 0u); + DCHECK((out_disp >> 27) == 0u || (out_disp >> 27) == 31u); // 28-bit signed. + insn = (out_disp & 0x0fffffffu) >> 2; + insn |= 0x14000000; // B <thunk> + + uint32_t back_disp = -out_disp; + DCHECK_EQ(back_disp & 3u, 0u); + DCHECK((back_disp >> 27) == 0u || (back_disp >> 27) == 31u); // 28-bit signed. + uint32_t b_back = (back_disp & 0x0fffffffu) >> 2; + b_back |= 0x14000000; // B <back> + size_t thunks_code_offset = current_method_thunks_.size(); + current_method_thunks_.resize(thunks_code_offset + kAdrpThunkSize); + SetInsn(¤t_method_thunks_, thunks_code_offset, adrp); + SetInsn(¤t_method_thunks_, thunks_code_offset + 4u, b_back); + static_assert(kAdrpThunkSize == 2 * 4u, "thunk has 2 instructions"); + + processed_adrp_thunks_ += 1u; + } else { + insn = PatchAdrp(insn, disp); + } + // Write the new ADRP (or B to the erratum 843419 thunk). + SetInsn(code, literal_offset, insn); + } else { + DCHECK_EQ(insn & 0xfffffc00, 0xb9400000); // LDR 32-bit with imm12 == 0 (unset). + if (kIsDebugBuild) { + uint32_t adrp = GetInsn(code, pc_insn_offset); + if ((adrp & 0x9f000000u) != 0x90000000u) { + CHECK(fix_cortex_a53_843419_); + CHECK_EQ(adrp & 0xfc000000u, 0x14000000u); // B <thunk> + CHECK(IsAligned<kAdrpThunkSize>(current_method_thunks_.size())); + size_t num_thunks = current_method_thunks_.size() / kAdrpThunkSize; + CHECK_LE(num_thunks, processed_adrp_thunks_); + uint32_t b_offset = patch_offset - literal_offset + pc_insn_offset; + for (size_t i = processed_adrp_thunks_ - num_thunks; ; ++i) { + CHECK_NE(i, processed_adrp_thunks_); + if (adrp_thunk_locations_[i].first == b_offset) { + size_t idx = num_thunks - (processed_adrp_thunks_ - i); + adrp = GetInsn(¤t_method_thunks_, idx * kAdrpThunkSize); + break; + } + } + } + CHECK_EQ(adrp & 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); + } +} + +std::vector<uint8_t> Arm64RelativePatcher::CompileThunkCode() { + // The thunk just uses the entry point in the ArtMethod. This works even for calls + // to the generic JNI and interpreter trampolines. + arm64::Arm64Assembler assembler; + Offset offset(mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kArm64PointerSize).Int32Value()); + assembler.JumpTo(ManagedRegister(arm64::X0), offset, ManagedRegister(arm64::IP0)); + // Ensure we emit the literal pool. + assembler.EmitSlowPaths(); + std::vector<uint8_t> thunk_code(assembler.CodeSize()); + MemoryRegion code(thunk_code.data(), thunk_code.size()); + assembler.FinalizeInstructions(code); + return thunk_code; +} + +uint32_t Arm64RelativePatcher::PatchAdrp(uint32_t adrp, uint32_t disp) { + return (adrp & 0x9f00001fu) | // Clear offset bits, keep ADRP with destination reg. + // Bottom 12 bits are ignored, the next 2 lowest bits are encoded in bits 29-30. + ((disp & 0x00003000u) << (29 - 12)) | + // The next 16 bits are encoded in bits 5-22. + ((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. This is encoded in bit 23. + ((disp & 0x80000000u) >> (31 - 23)); +} + +bool Arm64RelativePatcher::NeedsErratum843419Thunk(ArrayRef<const uint8_t> code, + uint32_t literal_offset, + uint32_t patch_offset) { + DCHECK_EQ(patch_offset & 0x3u, 0u); + if ((patch_offset & 0xff8) == 0xff8) { // ...ff8 or ...ffc + uint32_t adrp = GetInsn(code, literal_offset); + DCHECK_EQ(adrp & 0xff000000, 0x90000000); + // TODO: Improve the check. For now, we're just checking if the next insn is + // the LDR using the result of the ADRP, otherwise we implement the workaround. + uint32_t next_insn = GetInsn(code, literal_offset + 4u); + bool ok = (next_insn & 0xffc00000) == 0xb9400000 && // LDR <Wt>, [<Xn>, #pimm] + (((next_insn >> 5) ^ adrp) & 0x1f) == 0; // <Xn> == ADRP destination reg + return !ok; + } + return false; +} + +void Arm64RelativePatcher::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; +} + +uint32_t Arm64RelativePatcher::GetInsn(ArrayRef<const uint8_t> code, uint32_t offset) { + DCHECK_LE(offset + 4u, code.size()); + DCHECK_EQ(offset & 3u, 0u); + const 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); +} + +template <typename Alloc> +uint32_t Arm64RelativePatcher::GetInsn(std::vector<uint8_t, Alloc>* code, uint32_t offset) { + return GetInsn(ArrayRef<const uint8_t>(*code), offset); +} + +} // namespace linker +} // namespace art diff --git a/compiler/linker/arm64/relative_patcher_arm64.h b/compiler/linker/arm64/relative_patcher_arm64.h new file mode 100644 index 0000000000..b2a1da50d3 --- /dev/null +++ b/compiler/linker/arm64/relative_patcher_arm64.h @@ -0,0 +1,73 @@ +/* + * 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_LINKER_ARM64_RELATIVE_PATCHER_ARM64_H_ +#define ART_COMPILER_LINKER_ARM64_RELATIVE_PATCHER_ARM64_H_ + +#include "linker/arm/relative_patcher_arm_base.h" +#include "utils/array_ref.h" + +namespace art { +namespace linker { + +class Arm64RelativePatcher FINAL : public ArmBaseRelativePatcher { + public: + Arm64RelativePatcher(RelativePatcherTargetProvider* provider, + const Arm64InstructionSetFeatures* features); + + uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method, + MethodReference method_ref) OVERRIDE; + uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE; + void PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, + uint32_t patch_offset, uint32_t target_offset) OVERRIDE; + void PatchDexCacheReference(std::vector<uint8_t>* code, const LinkerPatch& patch, + uint32_t patch_offset, uint32_t target_offset) OVERRIDE; + + private: + static std::vector<uint8_t> CompileThunkCode(); + static uint32_t PatchAdrp(uint32_t adrp, uint32_t disp); + + static bool NeedsErratum843419Thunk(ArrayRef<const uint8_t> code, uint32_t literal_offset, + uint32_t patch_offset); + void SetInsn(std::vector<uint8_t>* code, uint32_t offset, uint32_t value); + static uint32_t GetInsn(ArrayRef<const uint8_t> code, uint32_t offset); + + template <typename Alloc> + static uint32_t GetInsn(std::vector<uint8_t, Alloc>* code, uint32_t offset); + + // 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); + + // The ADRP thunk for erratum 843419 is 2 instructions, i.e. 8 bytes. + static constexpr uint32_t kAdrpThunkSize = 8u; + + const bool fix_cortex_a53_843419_; + // Map original patch_offset to thunk offset. + std::vector<std::pair<uint32_t, uint32_t>> adrp_thunk_locations_; + size_t reserved_adrp_thunks_; + size_t processed_adrp_thunks_; + std::vector<uint8_t> current_method_thunks_; + + DISALLOW_COPY_AND_ASSIGN(Arm64RelativePatcher); +}; + +} // namespace linker +} // namespace art + +#endif // ART_COMPILER_LINKER_ARM64_RELATIVE_PATCHER_ARM64_H_ diff --git a/compiler/linker/relative_patcher.cc b/compiler/linker/relative_patcher.cc new file mode 100644 index 0000000000..71f38b408a --- /dev/null +++ b/compiler/linker/relative_patcher.cc @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#include "linker/relative_patcher.h" + +#include "linker/arm/relative_patcher_thumb2.h" +#include "linker/arm64/relative_patcher_arm64.h" +#include "linker/x86/relative_patcher_x86.h" +#include "linker/x86_64/relative_patcher_x86_64.h" +#include "output_stream.h" + +namespace art { +namespace linker { + +std::unique_ptr<RelativePatcher> RelativePatcher::Create( + InstructionSet instruction_set, const InstructionSetFeatures* features, + RelativePatcherTargetProvider* provider) { + class RelativePatcherNone FINAL : public RelativePatcher { + public: + RelativePatcherNone() { } + + uint32_t ReserveSpace(uint32_t offset, + const CompiledMethod* compiled_method ATTRIBUTE_UNUSED, + MethodReference method_ref ATTRIBUTE_UNUSED) OVERRIDE { + return offset; // No space reserved; no patches expected. + } + + uint32_t WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, uint32_t offset) OVERRIDE { + return offset; // No thunks added; no patches expected. + } + + 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(RelativePatcherNone); + }; + + switch (instruction_set) { + case kX86: + return std::unique_ptr<RelativePatcher>(new X86RelativePatcher()); + break; + case kX86_64: + return std::unique_ptr<RelativePatcher>(new X86_64RelativePatcher()); + break; + case kArm: + // Fall through: we generate Thumb2 code for "arm". + case kThumb2: + return std::unique_ptr<RelativePatcher>(new Thumb2RelativePatcher(provider)); + break; + case kArm64: + return std::unique_ptr<RelativePatcher>( + new Arm64RelativePatcher(provider, features->AsArm64InstructionSetFeatures())); + break; + default: + return std::unique_ptr<RelativePatcher>(new RelativePatcherNone); + break; + } +} + +bool RelativePatcher::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) { + static const uint8_t kPadding[] = { + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u + }; + DCHECK_LE(aligned_code_delta, sizeof(kPadding)); + if (UNLIKELY(!out->WriteFully(kPadding, aligned_code_delta))) { + return false; + } + size_code_alignment_ += aligned_code_delta; + return true; +} + +bool RelativePatcher::WriteRelCallThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk) { + if (UNLIKELY(!out->WriteFully(thunk.data(), thunk.size()))) { + return false; + } + size_relative_call_thunks_ += thunk.size(); + return true; +} + +bool RelativePatcher::WriteMiscThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk) { + if (UNLIKELY(!out->WriteFully(thunk.data(), thunk.size()))) { + return false; + } + size_misc_thunks_ += thunk.size(); + return true; +} + +} // namespace linker +} // namespace art diff --git a/compiler/linker/relative_patcher.h b/compiler/linker/relative_patcher.h new file mode 100644 index 0000000000..7a78254787 --- /dev/null +++ b/compiler/linker/relative_patcher.h @@ -0,0 +1,124 @@ +/* + * 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_LINKER_RELATIVE_PATCHER_H_ +#define ART_COMPILER_LINKER_RELATIVE_PATCHER_H_ + +#include <vector> + +#include "arch/instruction_set.h" +#include "arch/instruction_set_features.h" +#include "base/macros.h" +#include "method_reference.h" +#include "utils/array_ref.h" + +namespace art { + +class CompiledMethod; +class LinkerPatch; +class OutputStream; + +namespace linker { + +/** + * @class RelativePatcherTargetProvider + * @brief Interface for providing method offsets for relative call targets. + */ +class RelativePatcherTargetProvider { + public: + /** + * Find the offset of the target method of a relative call if known. + * + * The process of assigning target method offsets includes calls to the relative patcher's + * ReserveSpace() which in turn can use FindMethodOffset() to determine if a method already + * has an offset assigned and, if so, what's that offset. If the offset has not yet been + * assigned or if it's too far for the particular architecture's relative call, + * ReserveSpace() may need to allocate space for a special dispatch thunk. + * + * @param ref the target method of the relative call. + * @return true in the first element of the pair if the method was found, false otherwise; + * if found, the second element specifies the offset. + */ + virtual std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) = 0; + + protected: + virtual ~RelativePatcherTargetProvider() { } +}; + +/** + * @class RelativePatcher + * @brief Interface for architecture-specific link-time patching of PC-relative references. + */ +class RelativePatcher { + public: + static std::unique_ptr<RelativePatcher> Create( + InstructionSet instruction_set, const InstructionSetFeatures* features, + RelativePatcherTargetProvider* provider); + + virtual ~RelativePatcher() { } + + uint32_t CodeAlignmentSize() const { + return size_code_alignment_; + } + + uint32_t RelativeCallThunksSize() const { + return size_relative_call_thunks_; + } + + uint32_t MiscThunksSize() const { + return size_misc_thunks_; + } + + // Reserve space for relative call thunks if needed, return adjusted offset. After all methods + // of a class have been processed it's called one last time with compiled_method == nullptr. + virtual uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method, + MethodReference method_ref) = 0; + + // Write relative call thunks if needed, return adjusted offset. + virtual uint32_t WriteThunks(OutputStream* out, uint32_t offset) = 0; + + // 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 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: + RelativePatcher() + : size_code_alignment_(0u), + size_relative_call_thunks_(0u), + size_misc_thunks_(0u) { + } + + bool WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta); + bool WriteRelCallThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk); + bool WriteMiscThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk); + + private: + uint32_t size_code_alignment_; + uint32_t size_relative_call_thunks_; + uint32_t size_misc_thunks_; + + DISALLOW_COPY_AND_ASSIGN(RelativePatcher); +}; + +} // namespace linker +} // namespace art + +#endif // ART_COMPILER_LINKER_RELATIVE_PATCHER_H_ diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h new file mode 100644 index 0000000000..9efcf6082b --- /dev/null +++ b/compiler/linker/relative_patcher_test.h @@ -0,0 +1,243 @@ +/* + * 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_LINKER_RELATIVE_PATCHER_TEST_H_ +#define ART_COMPILER_LINKER_RELATIVE_PATCHER_TEST_H_ + +#include "arch/instruction_set.h" +#include "arch/instruction_set_features.h" +#include "base/macros.h" +#include "compiled_method.h" +#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 "globals.h" +#include "gtest/gtest.h" +#include "linker/relative_patcher.h" +#include "method_reference.h" +#include "oat.h" +#include "utils/array_ref.h" +#include "vector_output_stream.h" + +namespace art { +namespace linker { + +// Base class providing infrastructure for architecture-specific tests. +class RelativePatcherTest : public testing::Test { + protected: + RelativePatcherTest(InstructionSet instruction_set, const std::string& variant) + : compiler_options_(), + verification_results_(&compiler_options_), + inliner_map_(), + driver_(&compiler_options_, &verification_results_, &inliner_map_, + Compiler::kQuick, instruction_set, nullptr, + false, nullptr, nullptr, 1u, + false, false, "", nullptr, -1, ""), + error_msg_(), + instruction_set_(instruction_set), + features_(InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg_)), + method_offset_map_(), + patcher_(RelativePatcher::Create(instruction_set, features_.get(), &method_offset_map_)), + dex_cache_arrays_begin_(0u), + compiled_method_refs_(), + compiled_methods_(), + patched_code_(), + output_(), + out_("test output stream", &output_) { + CHECK(error_msg_.empty()) << instruction_set << "/" << variant; + patched_code_.reserve(16 * KB); + } + + MethodReference MethodRef(uint32_t method_idx) { + CHECK_NE(method_idx, 0u); + return MethodReference(nullptr, method_idx); + } + + void AddCompiledMethod(MethodReference method_ref, + const ArrayRef<const uint8_t>& code, + const ArrayRef<LinkerPatch>& patches) { + compiled_method_refs_.push_back(method_ref); + compiled_methods_.emplace_back(new CompiledMethod( + &driver_, instruction_set_, code, + 0u, 0u, 0u, nullptr, ArrayRef<const uint8_t>(), ArrayRef<const uint8_t>(), + ArrayRef<const uint8_t>(), ArrayRef<const uint8_t>(), + patches)); + } + + void Link() { + // Reserve space. + static_assert(kTrampolineOffset == 0u, "Unexpected trampoline offset."); + uint32_t offset = kTrampolineSize; + size_t idx = 0u; + for (auto& compiled_method : compiled_methods_) { + offset = patcher_->ReserveSpace(offset, compiled_method.get(), compiled_method_refs_[idx]); + + uint32_t aligned_offset = compiled_method->AlignCode(offset); + uint32_t aligned_code_delta = aligned_offset - offset; + offset += aligned_code_delta; + + offset += sizeof(OatQuickMethodHeader); + uint32_t quick_code_offset = offset + compiled_method->CodeDelta(); + const auto& code = *compiled_method->GetQuickCode(); + offset += code.size(); + + method_offset_map_.map.Put(compiled_method_refs_[idx], quick_code_offset); + ++idx; + } + offset = patcher_->ReserveSpace(offset, nullptr, MethodReference(nullptr, 0u)); + uint32_t output_size = offset; + output_.reserve(output_size); + + // Write data. + DCHECK(output_.empty()); + uint8_t dummy_trampoline[kTrampolineSize]; + memset(dummy_trampoline, 0, sizeof(dummy_trampoline)); + out_.WriteFully(dummy_trampoline, kTrampolineSize); + offset = kTrampolineSize; + static const uint8_t kPadding[] = { + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u + }; + uint8_t dummy_header[sizeof(OatQuickMethodHeader)]; + memset(dummy_header, 0, sizeof(dummy_header)); + for (auto& compiled_method : compiled_methods_) { + offset = patcher_->WriteThunks(&out_, offset); + + uint32_t aligned_offset = compiled_method->AlignCode(offset); + uint32_t aligned_code_delta = aligned_offset - offset; + CHECK_LE(aligned_code_delta, sizeof(kPadding)); + out_.WriteFully(kPadding, aligned_code_delta); + offset += aligned_code_delta; + + out_.WriteFully(dummy_header, sizeof(OatQuickMethodHeader)); + offset += sizeof(OatQuickMethodHeader); + ArrayRef<const uint8_t> code(*compiled_method->GetQuickCode()); + if (!compiled_method->GetPatches().empty()) { + patched_code_.assign(code.begin(), code.end()); + code = ArrayRef<const uint8_t>(patched_code_); + for (const LinkerPatch& patch : compiled_method->GetPatches()) { + if (patch.Type() == kLinkerPatchCallRelative) { + auto result = method_offset_map_.FindMethodOffset(patch.TargetMethod()); + uint32_t target_offset = + result.first ? result.second : kTrampolineOffset + compiled_method->CodeDelta(); + patcher_->PatchCall(&patched_code_, patch.LiteralOffset(), + offset + patch.LiteralOffset(), target_offset); + } else if (patch.Type() == kLinkerPatchDexCacheArray) { + uint32_t target_offset = dex_cache_arrays_begin_ + patch.TargetDexCacheElementOffset(); + patcher_->PatchDexCacheReference(&patched_code_, patch, + offset + patch.LiteralOffset(), target_offset); + } else { + LOG(FATAL) << "Bad patch type."; + } + } + } + out_.WriteFully(&code[0], code.size()); + offset += code.size(); + } + offset = patcher_->WriteThunks(&out_, offset); + CHECK_EQ(offset, output_size); + CHECK_EQ(output_.size(), output_size); + } + + bool CheckLinkedMethod(MethodReference method_ref, const ArrayRef<const uint8_t>& expected_code) { + // Sanity check: original code size must match linked_code.size(). + size_t idx = 0u; + for (auto ref : compiled_method_refs_) { + if (ref.dex_file == method_ref.dex_file && + ref.dex_method_index == method_ref.dex_method_index) { + break; + } + ++idx; + } + CHECK_NE(idx, compiled_method_refs_.size()); + CHECK_EQ(compiled_methods_[idx]->GetQuickCode()->size(), expected_code.size()); + + auto result = method_offset_map_.FindMethodOffset(method_ref); + CHECK(result.first); // Must have been linked. + size_t offset = result.second - compiled_methods_[idx]->CodeDelta(); + CHECK_LT(offset, output_.size()); + CHECK_LE(offset + expected_code.size(), output_.size()); + ArrayRef<const uint8_t> linked_code(&output_[offset], expected_code.size()); + if (linked_code == expected_code) { + return true; + } + // Log failure info. + DumpDiff(expected_code, linked_code); + return false; + } + + void DumpDiff(const ArrayRef<const uint8_t>& expected_code, + const ArrayRef<const uint8_t>& linked_code) { + std::ostringstream expected_hex; + std::ostringstream linked_hex; + std::ostringstream diff_indicator; + static const char digits[] = "0123456789abcdef"; + bool found_diff = false; + for (size_t i = 0; i != expected_code.size(); ++i) { + expected_hex << " " << digits[expected_code[i] >> 4] << digits[expected_code[i] & 0xf]; + linked_hex << " " << digits[linked_code[i] >> 4] << digits[linked_code[i] & 0xf]; + diff_indicator << " "; + if (!found_diff) { + found_diff = (expected_code[i] != linked_code[i]); + diff_indicator << (found_diff ? "^^" : " "); + } + } + CHECK(found_diff); + LOG(ERROR) << "diff expected_code linked_code"; + LOG(ERROR) << "<" << expected_hex.str(); + LOG(ERROR) << ">" << linked_hex.str(); + LOG(ERROR) << " " << diff_indicator.str(); + } + + // Map method reference to assinged offset. + // Wrap the map in a class implementing linker::RelativePatcherTargetProvider. + class MethodOffsetMap FINAL : public linker::RelativePatcherTargetProvider { + public: + std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) OVERRIDE { + auto it = map.find(ref); + if (it == map.end()) { + return std::pair<bool, uint32_t>(false, 0u); + } else { + return std::pair<bool, uint32_t>(true, it->second); + } + } + SafeMap<MethodReference, uint32_t, MethodReferenceComparator> map; + }; + + static const uint32_t kTrampolineSize = 4u; + static const uint32_t kTrampolineOffset = 0u; + + CompilerOptions compiler_options_; + VerificationResults verification_results_; + DexFileToMethodInlinerMap inliner_map_; + CompilerDriver driver_; // Needed for constructing CompiledMethod. + std::string error_msg_; + InstructionSet instruction_set_; + std::unique_ptr<const InstructionSetFeatures> features_; + MethodOffsetMap method_offset_map_; + std::unique_ptr<RelativePatcher> patcher_; + uint32_t dex_cache_arrays_begin_; + std::vector<MethodReference> compiled_method_refs_; + std::vector<std::unique_ptr<CompiledMethod>> compiled_methods_; + std::vector<uint8_t> patched_code_; + std::vector<uint8_t> output_; + VectorOutputStream out_; +}; + +} // namespace linker +} // namespace art + +#endif // ART_COMPILER_LINKER_RELATIVE_PATCHER_TEST_H_ diff --git a/compiler/linker/x86/relative_patcher_x86.cc b/compiler/linker/x86/relative_patcher_x86.cc new file mode 100644 index 0000000000..246cf11dae --- /dev/null +++ b/compiler/linker/x86/relative_patcher_x86.cc @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include "linker/x86/relative_patcher_x86.h" + +namespace art { +namespace linker { + +void X86RelativePatcher::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."; +} + +} // namespace linker +} // namespace art diff --git a/compiler/linker/x86/relative_patcher_x86.h b/compiler/linker/x86/relative_patcher_x86.h new file mode 100644 index 0000000000..0c881f00ba --- /dev/null +++ b/compiler/linker/x86/relative_patcher_x86.h @@ -0,0 +1,36 @@ +/* + * 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_LINKER_X86_RELATIVE_PATCHER_X86_H_ +#define ART_COMPILER_LINKER_X86_RELATIVE_PATCHER_X86_H_ + +#include "linker/x86/relative_patcher_x86_base.h" + +namespace art { +namespace linker { + +class X86RelativePatcher FINAL : public X86BaseRelativePatcher { + public: + X86RelativePatcher() { } + + void PatchDexCacheReference(std::vector<uint8_t>* code, const LinkerPatch& patch, + uint32_t patch_offset, uint32_t target_offset) OVERRIDE; +}; + +} // namespace linker +} // namespace art + +#endif // ART_COMPILER_LINKER_X86_RELATIVE_PATCHER_X86_H_ diff --git a/compiler/linker/x86/relative_patcher_x86_base.cc b/compiler/linker/x86/relative_patcher_x86_base.cc new file mode 100644 index 0000000000..ea3472d232 --- /dev/null +++ b/compiler/linker/x86/relative_patcher_x86_base.cc @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#include "linker/x86/relative_patcher_x86_base.h" + +namespace art { +namespace linker { + +uint32_t X86BaseRelativePatcher::ReserveSpace( + uint32_t offset, + const CompiledMethod* compiled_method ATTRIBUTE_UNUSED, + MethodReference method_ref ATTRIBUTE_UNUSED) { + return offset; // No space reserved; no limit on relative call distance. +} + +uint32_t X86BaseRelativePatcher::WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, uint32_t offset) { + return offset; // No thunks added; no limit on relative call distance. +} + +void X86BaseRelativePatcher::PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, + uint32_t patch_offset, uint32_t target_offset) { + 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; + displacement -= kPcDisplacement; // The base PC is at the end of the 4-byte patch. + + typedef __attribute__((__aligned__(1))) int32_t unaligned_int32_t; + reinterpret_cast<unaligned_int32_t*>(&(*code)[literal_offset])[0] = displacement; +} + +} // namespace linker +} // namespace art diff --git a/compiler/linker/x86/relative_patcher_x86_base.h b/compiler/linker/x86/relative_patcher_x86_base.h new file mode 100644 index 0000000000..1f38cf2996 --- /dev/null +++ b/compiler/linker/x86/relative_patcher_x86_base.h @@ -0,0 +1,49 @@ +/* + * 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_LINKER_X86_RELATIVE_PATCHER_X86_BASE_H_ +#define ART_COMPILER_LINKER_X86_RELATIVE_PATCHER_X86_BASE_H_ + +#include "linker/relative_patcher.h" + +namespace art { +namespace linker { + +class X86BaseRelativePatcher : public RelativePatcher { + public: + uint32_t ReserveSpace(uint32_t offset, + const CompiledMethod* compiled_method, + MethodReference method_ref) OVERRIDE; + uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE; + void PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset, + uint32_t patch_offset, uint32_t target_offset) OVERRIDE; + + protected: + X86BaseRelativePatcher() { } + + // 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); +}; + +} // namespace linker +} // namespace art + +#endif // ART_COMPILER_LINKER_X86_RELATIVE_PATCHER_X86_BASE_H_ diff --git a/compiler/linker/x86/relative_patcher_x86_test.cc b/compiler/linker/x86/relative_patcher_x86_test.cc new file mode 100644 index 0000000000..c18a743b6b --- /dev/null +++ b/compiler/linker/x86/relative_patcher_x86_test.cc @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#include "linker/relative_patcher_test.h" +#include "linker/x86/relative_patcher_x86.h" + +namespace art { +namespace linker { + +class X86RelativePatcherTest : public RelativePatcherTest { + public: + X86RelativePatcherTest() : RelativePatcherTest(kX86, "default") { } + + protected: + static const uint8_t kCallRawCode[]; + static const ArrayRef<const uint8_t> kCallCode; + + uint32_t GetMethodOffset(uint32_t method_idx) { + auto result = method_offset_map_.FindMethodOffset(MethodRef(method_idx)); + CHECK(result.first); + return result.second; + } +}; + +const uint8_t X86RelativePatcherTest::kCallRawCode[] = { + 0xe8, 0x00, 0x01, 0x00, 0x00 +}; + +const ArrayRef<const uint8_t> X86RelativePatcherTest::kCallCode(kCallRawCode); + +TEST_F(X86RelativePatcherTest, CallSelf) { + LinkerPatch patches[] = { + LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 1u), + }; + AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<LinkerPatch>(patches)); + Link(); + + static const uint8_t expected_code[] = { + 0xe8, 0xfb, 0xff, 0xff, 0xff + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); +} + +TEST_F(X86RelativePatcherTest, CallOther) { + LinkerPatch method1_patches[] = { + LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 2u), + }; + AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<LinkerPatch>(method1_patches)); + LinkerPatch method2_patches[] = { + LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 1u), + }; + AddCompiledMethod(MethodRef(2u), kCallCode, ArrayRef<LinkerPatch>(method2_patches)); + Link(); + + uint32_t method1_offset = GetMethodOffset(1u); + uint32_t method2_offset = GetMethodOffset(2u); + uint32_t diff_after = method2_offset - (method1_offset + kCallCode.size() /* PC adjustment */); + static const uint8_t method1_expected_code[] = { + 0xe8, + static_cast<uint8_t>(diff_after), static_cast<uint8_t>(diff_after >> 8), + static_cast<uint8_t>(diff_after >> 16), static_cast<uint8_t>(diff_after >> 24) + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(method1_expected_code))); + uint32_t diff_before = method1_offset - (method2_offset + kCallCode.size() /* PC adjustment */); + static const uint8_t method2_expected_code[] = { + 0xe8, + static_cast<uint8_t>(diff_before), static_cast<uint8_t>(diff_before >> 8), + static_cast<uint8_t>(diff_before >> 16), static_cast<uint8_t>(diff_before >> 24) + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(2u), ArrayRef<const uint8_t>(method2_expected_code))); +} + +TEST_F(X86RelativePatcherTest, CallTrampoline) { + LinkerPatch patches[] = { + LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 2u), + }; + AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<LinkerPatch>(patches)); + Link(); + + auto result = method_offset_map_.FindMethodOffset(MethodRef(1)); + ASSERT_TRUE(result.first); + uint32_t diff = kTrampolineOffset - (result.second + kCallCode.size()); + static const uint8_t expected_code[] = { + 0xe8, + static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), + static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24) + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); +} + +} // namespace linker +} // namespace art diff --git a/compiler/linker/x86_64/relative_patcher_x86_64.cc b/compiler/linker/x86_64/relative_patcher_x86_64.cc new file mode 100644 index 0000000000..598f3ac4a8 --- /dev/null +++ b/compiler/linker/x86_64/relative_patcher_x86_64.cc @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#include "linker/x86_64/relative_patcher_x86_64.h" + +#include "compiled_method.h" + +namespace art { +namespace linker { + +void X86_64RelativePatcher::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. + + typedef __attribute__((__aligned__(1))) int32_t unaligned_int32_t; + reinterpret_cast<unaligned_int32_t*>(&(*code)[patch.LiteralOffset()])[0] = displacement; +} + +} // namespace linker +} // namespace art diff --git a/compiler/linker/x86_64/relative_patcher_x86_64.h b/compiler/linker/x86_64/relative_patcher_x86_64.h new file mode 100644 index 0000000000..af687b4a2f --- /dev/null +++ b/compiler/linker/x86_64/relative_patcher_x86_64.h @@ -0,0 +1,36 @@ +/* + * 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_LINKER_X86_64_RELATIVE_PATCHER_X86_64_H_ +#define ART_COMPILER_LINKER_X86_64_RELATIVE_PATCHER_X86_64_H_ + +#include "linker/x86/relative_patcher_x86_base.h" + +namespace art { +namespace linker { + +class X86_64RelativePatcher FINAL : public X86BaseRelativePatcher { + public: + X86_64RelativePatcher() { } + + void PatchDexCacheReference(std::vector<uint8_t>* code, const LinkerPatch& patch, + uint32_t patch_offset, uint32_t target_offset) OVERRIDE; +}; + +} // namespace linker +} // namespace art + +#endif // ART_COMPILER_LINKER_X86_64_RELATIVE_PATCHER_X86_64_H_ diff --git a/compiler/linker/x86_64/relative_patcher_x86_64_test.cc b/compiler/linker/x86_64/relative_patcher_x86_64_test.cc new file mode 100644 index 0000000000..9d9529ced7 --- /dev/null +++ b/compiler/linker/x86_64/relative_patcher_x86_64_test.cc @@ -0,0 +1,136 @@ +/* + * 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. + */ + +#include "linker/relative_patcher_test.h" +#include "linker/x86_64/relative_patcher_x86_64.h" + +namespace art { +namespace linker { + +class X86_64RelativePatcherTest : public RelativePatcherTest { + public: + X86_64RelativePatcherTest() : RelativePatcherTest(kX86_64, "default") { } + + protected: + static const uint8_t kCallRawCode[]; + static const ArrayRef<const uint8_t> kCallCode; + static const uint8_t kDexCacheLoadRawCode[]; + static const ArrayRef<const uint8_t> kDexCacheLoadCode; + + uint32_t GetMethodOffset(uint32_t method_idx) { + auto result = method_offset_map_.FindMethodOffset(MethodRef(method_idx)); + CHECK(result.first); + return result.second; + } +}; + +const uint8_t X86_64RelativePatcherTest::kCallRawCode[] = { + 0xe8, 0x00, 0x01, 0x00, 0x00 +}; + +const ArrayRef<const uint8_t> X86_64RelativePatcherTest::kCallCode(kCallRawCode); + +const uint8_t X86_64RelativePatcherTest::kDexCacheLoadRawCode[] = { + 0x8b, 0x05, // mov eax, [rip + <offset>] + 0x00, 0x01, 0x00, 0x00 +}; + +const ArrayRef<const uint8_t> X86_64RelativePatcherTest::kDexCacheLoadCode( + kDexCacheLoadRawCode); + +TEST_F(X86_64RelativePatcherTest, CallSelf) { + LinkerPatch patches[] = { + LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 1u), + }; + AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<LinkerPatch>(patches)); + Link(); + + static const uint8_t expected_code[] = { + 0xe8, 0xfb, 0xff, 0xff, 0xff + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); +} + +TEST_F(X86_64RelativePatcherTest, CallOther) { + LinkerPatch method1_patches[] = { + LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 2u), + }; + AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<LinkerPatch>(method1_patches)); + LinkerPatch method2_patches[] = { + LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 1u), + }; + AddCompiledMethod(MethodRef(2u), kCallCode, ArrayRef<LinkerPatch>(method2_patches)); + Link(); + + uint32_t method1_offset = GetMethodOffset(1u); + uint32_t method2_offset = GetMethodOffset(2u); + uint32_t diff_after = method2_offset - (method1_offset + kCallCode.size() /* PC adjustment */); + static const uint8_t method1_expected_code[] = { + 0xe8, + static_cast<uint8_t>(diff_after), static_cast<uint8_t>(diff_after >> 8), + static_cast<uint8_t>(diff_after >> 16), static_cast<uint8_t>(diff_after >> 24) + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(method1_expected_code))); + uint32_t diff_before = method1_offset - (method2_offset + kCallCode.size() /* PC adjustment */); + static const uint8_t method2_expected_code[] = { + 0xe8, + static_cast<uint8_t>(diff_before), static_cast<uint8_t>(diff_before >> 8), + static_cast<uint8_t>(diff_before >> 16), static_cast<uint8_t>(diff_before >> 24) + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(2u), ArrayRef<const uint8_t>(method2_expected_code))); +} + +TEST_F(X86_64RelativePatcherTest, CallTrampoline) { + LinkerPatch patches[] = { + LinkerPatch::RelativeCodePatch(kCallCode.size() - 4u, nullptr, 2u), + }; + AddCompiledMethod(MethodRef(1u), kCallCode, ArrayRef<LinkerPatch>(patches)); + Link(); + + auto result = method_offset_map_.FindMethodOffset(MethodRef(1u)); + ASSERT_TRUE(result.first); + uint32_t diff = kTrampolineOffset - (result.second + kCallCode.size()); + static const uint8_t expected_code[] = { + 0xe8, + static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), + static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24) + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); +} + +TEST_F(X86_64RelativePatcherTest, DexCacheReference) { + dex_cache_arrays_begin_ = 0x12345678; + constexpr size_t kElementOffset = 0x1234; + LinkerPatch patches[] = { + LinkerPatch::DexCacheArrayPatch(kDexCacheLoadCode.size() - 4u, nullptr, 0u, kElementOffset), + }; + AddCompiledMethod(MethodRef(1u), kDexCacheLoadCode, ArrayRef<LinkerPatch>(patches)); + Link(); + + auto result = method_offset_map_.FindMethodOffset(MethodRef(1u)); + ASSERT_TRUE(result.first); + uint32_t diff = + dex_cache_arrays_begin_ + kElementOffset - (result.second + kDexCacheLoadCode.size()); + static const uint8_t expected_code[] = { + 0x8b, 0x05, + static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), + static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24) + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code))); +} + +} // namespace linker +} // namespace art diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 04f0db6572..19013cf7a1 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -32,6 +32,7 @@ #include "driver/compiler_options.h" #include "gc/space/space.h" #include "image_writer.h" +#include "linker/relative_patcher.h" #include "mirror/art_method-inl.h" #include "mirror/array.h" #include "mirror/class_loader.h" @@ -41,609 +42,10 @@ #include "safe_map.h" #include "scoped_thread_state_change.h" #include "handle_scope-inl.h" -#include "utils/arm/assembler_thumb2.h" -#include "utils/arm64/assembler_arm64.h" #include "verifier/method_verifier.h" namespace art { -class OatWriter::RelativePatcher { - public: - virtual ~RelativePatcher() { } - - // Reserve space for relative call thunks if needed, return adjusted offset. After all methods - // of a class have been processed it's called one last time with compiled_method == nullptr. - virtual uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method) = 0; - - // Write relative call thunks if needed, return adjusted offset. - virtual uint32_t WriteThunks(OutputStream* out, uint32_t offset) = 0; - - // 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 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: - RelativePatcher() { } - - private: - DISALLOW_COPY_AND_ASSIGN(RelativePatcher); -}; - -class OatWriter::NoRelativePatcher FINAL : public RelativePatcher { - public: - NoRelativePatcher() { } - - uint32_t ReserveSpace(uint32_t offset, - const CompiledMethod* compiled_method ATTRIBUTE_UNUSED) OVERRIDE { - return offset; // No space reserved; no patches expected. - } - - uint32_t WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, uint32_t offset) OVERRIDE { - return offset; // No thunks added; no patches expected. - } - - 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(NoRelativePatcher); -}; - -class OatWriter::X86RelativePatcher FINAL : public RelativePatcher { - public: - X86RelativePatcher() { } - - uint32_t ReserveSpace(uint32_t offset, - const CompiledMethod* compiled_method ATTRIBUTE_UNUSED) OVERRIDE { - return offset; // No space reserved; no limit on relative call distance. - } - - uint32_t WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, uint32_t offset) OVERRIDE { - return offset; // No thunks added; no limit on relative call distance. - } - - 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; - displacement -= kPcDisplacement; // The base PC is at the end of the 4-byte patch. - - typedef __attribute__((__aligned__(1))) int32_t unaligned_int32_t; - 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(X86RelativePatcher); -}; - -class OatWriter::ArmBaseRelativePatcher : public RelativePatcher { - public: - 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), - max_positive_displacement_(max_positive_displacement), - max_negative_displacement_(max_negative_displacement), - thunk_locations_(), current_thunk_to_write_(0u), unprocessed_patches_() { - } - - uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method) OVERRIDE { - return ReserveSpaceInternal(offset, compiled_method, 0u); - } - - uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE { - if (current_thunk_to_write_ == thunk_locations_.size()) { - return offset; - } - uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_); - if (UNLIKELY(aligned_offset == thunk_locations_[current_thunk_to_write_])) { - ++current_thunk_to_write_; - uint32_t aligned_code_delta = aligned_offset - offset; - if (aligned_code_delta != 0u && !writer_->WriteCodeAlignment(out, aligned_code_delta)) { - return 0u; - } - if (!out->WriteFully(thunk_code_.data(), thunk_code_.size())) { - return 0u; - } - writer_->size_relative_call_thunks_ += thunk_code_.size(); - uint32_t thunk_end_offset = aligned_offset + thunk_code_.size(); - // Align after writing chunk, see the ReserveSpace() above. - offset = CompiledMethod::AlignCode(thunk_end_offset, instruction_set_); - aligned_code_delta = offset - thunk_end_offset; - if (aligned_code_delta != 0u && !writer_->WriteCodeAlignment(out, aligned_code_delta)) { - return 0u; - } - } - return offset; - } - - protected: - uint32_t ReserveSpaceInternal(uint32_t offset, const CompiledMethod* compiled_method, - uint32_t max_extra_space) { - // NOTE: The final thunk can be reserved from InitCodeMethodVisitor::EndClass() while it - // may be written early by WriteCodeMethodVisitor::VisitMethod() for a deduplicated chunk - // of code. To avoid any alignment discrepancies for the final chunk, we always align the - // offset after reserving of writing any chunk. - if (UNLIKELY(compiled_method == nullptr)) { - uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_); - bool needs_thunk = ReserveSpaceProcessPatches(aligned_offset); - if (needs_thunk) { - thunk_locations_.push_back(aligned_offset); - offset = CompiledMethod::AlignCode(aligned_offset + thunk_code_.size(), instruction_set_); - } - return offset; - } - DCHECK(compiled_method->GetQuickCode() != nullptr); - uint32_t quick_code_size = compiled_method->GetQuickCode()->size(); - uint32_t quick_code_offset = compiled_method->AlignCode(offset) + sizeof(OatQuickMethodHeader); - uint32_t next_aligned_offset = compiled_method->AlignCode(quick_code_offset + quick_code_size); - // Adjust for extra space required by the subclass. - next_aligned_offset = compiled_method->AlignCode(next_aligned_offset + max_extra_space); - if (!unprocessed_patches_.empty() && - next_aligned_offset - unprocessed_patches_.front().second > max_positive_displacement_) { - bool needs_thunk = ReserveSpaceProcessPatches(next_aligned_offset); - if (needs_thunk) { - // A single thunk will cover all pending patches. - unprocessed_patches_.clear(); - uint32_t thunk_location = compiled_method->AlignCode(offset); - thunk_locations_.push_back(thunk_location); - offset = CompiledMethod::AlignCode(thunk_location + thunk_code_.size(), instruction_set_); - } - } - for (const LinkerPatch& patch : compiled_method->GetPatches()) { - if (patch.Type() == kLinkerPatchCallRelative) { - unprocessed_patches_.emplace_back(patch.TargetMethod(), - quick_code_offset + patch.LiteralOffset()); - } - } - return offset; - } - - uint32_t CalculateDisplacement(uint32_t patch_offset, uint32_t target_offset) { - // Unsigned arithmetic with its well-defined overflow behavior is just fine here. - uint32_t displacement = target_offset - patch_offset; - // NOTE: With unsigned arithmetic we do mean to use && rather than || below. - if (displacement > max_positive_displacement_ && displacement < -max_negative_displacement_) { - // Unwritten thunks have higher offsets, check if it's within range. - DCHECK(current_thunk_to_write_ == thunk_locations_.size() || - thunk_locations_[current_thunk_to_write_] > patch_offset); - if (current_thunk_to_write_ != thunk_locations_.size() && - thunk_locations_[current_thunk_to_write_] - patch_offset < max_positive_displacement_) { - displacement = thunk_locations_[current_thunk_to_write_] - patch_offset; - } else { - // We must have a previous thunk then. - DCHECK_NE(current_thunk_to_write_, 0u); - DCHECK_LT(thunk_locations_[current_thunk_to_write_ - 1], patch_offset); - displacement = thunk_locations_[current_thunk_to_write_ - 1] - patch_offset; - DCHECK(displacement >= -max_negative_displacement_); - } - } - return displacement; - } - - OatWriter* Writer() const { - return writer_; - } - - private: - bool ReserveSpaceProcessPatches(uint32_t next_aligned_offset) { - // Process as many patches as possible, stop only on unresolved targets or calls too far back. - while (!unprocessed_patches_.empty()) { - uint32_t patch_offset = unprocessed_patches_.front().second; - auto it = writer_->method_offset_map_.find(unprocessed_patches_.front().first); - if (it == writer_->method_offset_map_.end()) { - // If still unresolved, check if we have a thunk within range. - DCHECK(thunk_locations_.empty() || thunk_locations_.back() <= patch_offset); - if (thunk_locations_.empty() || - patch_offset - thunk_locations_.back() > max_negative_displacement_) { - return next_aligned_offset - patch_offset > max_positive_displacement_; - } - } else if (it->second >= patch_offset) { - DCHECK_LE(it->second - patch_offset, max_positive_displacement_); - } else { - // When calling back, check if we have a thunk that's closer than the actual target. - uint32_t target_offset = (thunk_locations_.empty() || it->second > thunk_locations_.back()) - ? it->second - : thunk_locations_.back(); - DCHECK_GT(patch_offset, target_offset); - if (patch_offset - target_offset > max_negative_displacement_) { - return true; - } - } - unprocessed_patches_.pop_front(); - } - return false; - } - - OatWriter* const writer_; - const InstructionSet instruction_set_; - const std::vector<uint8_t> thunk_code_; - const uint32_t max_positive_displacement_; - const uint32_t max_negative_displacement_; - std::vector<uint32_t> thunk_locations_; - size_t current_thunk_to_write_; - - // ReserveSpace() tracks unprocessed patches. - typedef std::pair<MethodReference, uint32_t> UnprocessedPatch; - std::deque<UnprocessedPatch> unprocessed_patches_; - - DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativePatcher); -}; - -class OatWriter::Thumb2RelativePatcher FINAL : public ArmBaseRelativePatcher { - public: - explicit Thumb2RelativePatcher(OatWriter* writer) - : ArmBaseRelativePatcher(writer, kThumb2, CompileThunkCode(), - kMaxPositiveDisplacement, kMaxNegativeDisplacement) { - } - - 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); - DCHECK_EQ(target_offset & 1u, 1u); // Thumb2 mode bit. - uint32_t displacement = CalculateDisplacement(patch_offset, target_offset & ~1u); - displacement -= kPcDisplacement; // The base PC is at the end of the 4-byte patch. - DCHECK_EQ(displacement & 1u, 0u); - DCHECK((displacement >> 24) == 0u || (displacement >> 24) == 255u); // 25-bit signed. - uint32_t signbit = (displacement >> 31) & 0x1; - uint32_t i1 = (displacement >> 23) & 0x1; - uint32_t i2 = (displacement >> 22) & 0x1; - uint32_t imm10 = (displacement >> 12) & 0x03ff; - uint32_t imm11 = (displacement >> 1) & 0x07ff; - uint32_t j1 = i1 ^ (signbit ^ 1); - uint32_t j2 = i2 ^ (signbit ^ 1); - uint32_t value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) | imm11; - value |= 0xf000d000; // BL - - uint8_t* addr = &(*code)[literal_offset]; - // Check that we're just overwriting an existing BL. - DCHECK_EQ(addr[1] & 0xf8, 0xf0); - DCHECK_EQ(addr[3] & 0xd0, 0xd0); - // Write the new BL. - addr[0] = (value >> 16) & 0xff; - addr[1] = (value >> 24) & 0xff; - addr[2] = (value >> 0) & 0xff; - 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 - // to the generic JNI and interpreter trampolines. - arm::Thumb2Assembler assembler; - assembler.LoadFromOffset( - arm::kLoadWord, arm::PC, arm::R0, - mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value()); - assembler.bkpt(0); - std::vector<uint8_t> thunk_code(assembler.CodeSize()); - MemoryRegion code(thunk_code.data(), thunk_code.size()); - assembler.FinalizeInstructions(code); - return thunk_code; - } - - // PC displacement from patch location; Thumb2 PC is always at instruction address + 4. - static constexpr int32_t kPcDisplacement = 4; - - // Maximum positive and negative displacement measured from the patch location. - // (Signed 25 bit displacement with the last bit 0 has range [-2^24, 2^24-2] measured from - // the Thumb2 PC pointing right after the BL, i.e. 4 bytes later than the patch location.) - static constexpr uint32_t kMaxPositiveDisplacement = (1u << 24) - 2 + kPcDisplacement; - static constexpr uint32_t kMaxNegativeDisplacement = (1u << 24) - kPcDisplacement; - - DISALLOW_COPY_AND_ASSIGN(Thumb2RelativePatcher); -}; - -class OatWriter::Arm64RelativePatcher FINAL : public ArmBaseRelativePatcher { - public: - explicit Arm64RelativePatcher(OatWriter* writer) - : ArmBaseRelativePatcher(writer, kArm64, CompileThunkCode(), - kMaxPositiveDisplacement, kMaxNegativeDisplacement), - fix_cortex_a53_843419_(writer->compiler_driver_->GetInstructionSetFeatures() - ->AsArm64InstructionSetFeatures()->NeedFixCortexA53_835769()), - reserved_adrp_thunks_(0u), - processed_adrp_thunks_(0u) { - if (fix_cortex_a53_843419_) { - adrp_thunk_locations_.reserve(16u); - current_method_thunks_.reserve(16u * kAdrpThunkSize); - } - } - - uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method) OVERRIDE { - if (!fix_cortex_a53_843419_) { - DCHECK(adrp_thunk_locations_.empty()); - return ReserveSpaceInternal(offset, compiled_method, 0u); - } - - // Add thunks for previous method if any. - if (reserved_adrp_thunks_ != adrp_thunk_locations_.size()) { - size_t num_adrp_thunks = adrp_thunk_locations_.size() - reserved_adrp_thunks_; - offset = CompiledMethod::AlignCode(offset, kArm64) + kAdrpThunkSize * num_adrp_thunks; - reserved_adrp_thunks_ = adrp_thunk_locations_.size(); - } - - // Count the number of ADRP insns as the upper bound on the number of thunks needed - // and use it to reserve space for other linker patches. - size_t num_adrp = 0u; - if (LIKELY(compiled_method != nullptr)) { - for (const LinkerPatch& patch : compiled_method->GetPatches()) { - if (patch.Type() == kLinkerPatchDexCacheArray && - patch.LiteralOffset() == patch.PcInsnOffset()) { // ADRP patch - ++num_adrp; - } - } - } - offset = ReserveSpaceInternal(offset, compiled_method, kAdrpThunkSize * num_adrp); - if (num_adrp == 0u) { - return offset; - } - - // Now that we have the actual offset where the code will be placed, locate the ADRP insns - // that actually require the thunk. - uint32_t quick_code_offset = compiled_method->AlignCode(offset) + sizeof(OatQuickMethodHeader); - ArrayRef<const uint8_t> code(*compiled_method->GetQuickCode()); - uint32_t thunk_offset = compiled_method->AlignCode(quick_code_offset + code.size()); - DCHECK(compiled_method != nullptr); - for (const LinkerPatch& patch : compiled_method->GetPatches()) { - if (patch.Type() == kLinkerPatchDexCacheArray && - patch.LiteralOffset() == patch.PcInsnOffset()) { // ADRP patch - uint32_t patch_offset = quick_code_offset + patch.LiteralOffset(); - if (NeedsErratum843419Thunk(code, patch.LiteralOffset(), patch_offset)) { - adrp_thunk_locations_.emplace_back(patch_offset, thunk_offset); - thunk_offset += kAdrpThunkSize; - } - } - } - return offset; - } - - uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE { - if (fix_cortex_a53_843419_) { - if (!current_method_thunks_.empty()) { - uint32_t aligned_offset = CompiledMethod::AlignCode(offset, kArm64); - if (kIsDebugBuild) { - CHECK(IsAligned<kAdrpThunkSize>(current_method_thunks_.size())); - size_t num_thunks = current_method_thunks_.size() / kAdrpThunkSize; - CHECK_LE(num_thunks, processed_adrp_thunks_); - for (size_t i = 0u; i != num_thunks; ++i) { - const auto& entry = adrp_thunk_locations_[processed_adrp_thunks_ - num_thunks + i]; - CHECK_EQ(entry.second, aligned_offset + i * kAdrpThunkSize); - } - } - uint32_t aligned_code_delta = aligned_offset - offset; - if (aligned_code_delta != 0u && !Writer()->WriteCodeAlignment(out, aligned_code_delta)) { - return 0u; - } - if (!out->WriteFully(¤t_method_thunks_[0], current_method_thunks_.size())) { - return 0u; - } - Writer()->size_misc_thunks_ += current_method_thunks_.size(); - offset = aligned_offset + current_method_thunks_.size(); - current_method_thunks_.clear(); - } - } - return ArmBaseRelativePatcher::WriteThunks(out, offset); - } - - 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); - DCHECK_EQ(target_offset & 3u, 0u); - 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 insn = (displacement & 0x0fffffffu) >> 2; - insn |= 0x94000000; // BL - - // Check that we're just overwriting an existing BL. - DCHECK_EQ(GetInsn(code, literal_offset) & 0xfc000000u, 0x94000000u); - // Write the new BL. - 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; - if (fix_cortex_a53_843419_ && processed_adrp_thunks_ != adrp_thunk_locations_.size() && - adrp_thunk_locations_[processed_adrp_thunks_].first == patch_offset) { - DCHECK(NeedsErratum843419Thunk(ArrayRef<const uint8_t>(*code), - literal_offset, patch_offset)); - uint32_t thunk_offset = adrp_thunk_locations_[processed_adrp_thunks_].second; - uint32_t adrp_disp = target_offset - (thunk_offset & ~0xfffu); - uint32_t adrp = PatchAdrp(insn, adrp_disp); - - uint32_t out_disp = thunk_offset - patch_offset; - DCHECK_EQ(out_disp & 3u, 0u); - DCHECK((out_disp >> 27) == 0u || (out_disp >> 27) == 31u); // 28-bit signed. - insn = (out_disp & 0x0fffffffu) >> 2; - insn |= 0x14000000; // B <thunk> - - uint32_t back_disp = -out_disp; - DCHECK_EQ(back_disp & 3u, 0u); - DCHECK((back_disp >> 27) == 0u || (back_disp >> 27) == 31u); // 28-bit signed. - uint32_t b_back = (back_disp & 0x0fffffffu) >> 2; - b_back |= 0x14000000; // B <back> - size_t thunks_code_offset = current_method_thunks_.size(); - current_method_thunks_.resize(thunks_code_offset + kAdrpThunkSize); - SetInsn(¤t_method_thunks_, thunks_code_offset, adrp); - SetInsn(¤t_method_thunks_, thunks_code_offset + 4u, b_back); - static_assert(kAdrpThunkSize == 2 * 4u, "thunk has 2 instructions"); - - processed_adrp_thunks_ += 1u; - } else { - insn = PatchAdrp(insn, disp); - } - // Write the new ADRP (or B to the erratum 843419 thunk). - SetInsn(code, literal_offset, insn); - } else { - DCHECK_EQ(insn & 0xfffffc00, 0xb9400000); // LDR 32-bit with imm12 == 0 (unset). - if (kIsDebugBuild) { - uint32_t adrp = GetInsn(code, pc_insn_offset); - if ((adrp & 0x9f000000u) != 0x90000000u) { - CHECK(fix_cortex_a53_843419_); - CHECK_EQ(adrp & 0xfc000000u, 0x14000000u); // B <thunk> - CHECK(IsAligned<kAdrpThunkSize>(current_method_thunks_.size())); - size_t num_thunks = current_method_thunks_.size() / kAdrpThunkSize; - CHECK_LE(num_thunks, processed_adrp_thunks_); - uint32_t b_offset = patch_offset - literal_offset + pc_insn_offset; - for (size_t i = processed_adrp_thunks_ - num_thunks; ; ++i) { - CHECK_NE(i, processed_adrp_thunks_); - if (adrp_thunk_locations_[i].first == b_offset) { - size_t idx = num_thunks - (processed_adrp_thunks_ - i); - adrp = GetInsn(¤t_method_thunks_, idx * kAdrpThunkSize); - break; - } - } - } - CHECK_EQ(adrp & 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: - static uint32_t PatchAdrp(uint32_t adrp, uint32_t disp) { - return (adrp & 0x9f00001fu) | // Clear offset bits, keep ADRP with destination reg. - // Bottom 12 bits are ignored, the next 2 lowest bits are encoded in bits 29-30. - ((disp & 0x00003000u) << (29 - 12)) | - // The next 16 bits are encoded in bits 5-22. - ((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. This is encoded in bit 23. - ((disp & 0x80000000u) >> (31 - 23)); - } - - static std::vector<uint8_t> CompileThunkCode() { - // The thunk just uses the entry point in the ArtMethod. This works even for calls - // to the generic JNI and interpreter trampolines. - arm64::Arm64Assembler assembler; - Offset offset(mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( - kArm64PointerSize).Int32Value()); - assembler.JumpTo(ManagedRegister(arm64::X0), offset, ManagedRegister(arm64::IP0)); - // Ensure we emit the literal pool. - assembler.EmitSlowPaths(); - std::vector<uint8_t> thunk_code(assembler.CodeSize()); - MemoryRegion code(thunk_code.data(), thunk_code.size()); - assembler.FinalizeInstructions(code); - return thunk_code; - } - - static bool NeedsErratum843419Thunk(ArrayRef<const uint8_t> code, uint32_t literal_offset, - uint32_t patch_offset) { - DCHECK_EQ(patch_offset & 0x3u, 0u); - if ((patch_offset & 0xff8) == 0xff8) { // ...ff8 or ...ffc - uint32_t adrp = GetInsn(code, literal_offset); - DCHECK_EQ(adrp & 0xff000000, 0x90000000); - // TODO: Improve the check. For now, we're just checking if the next insn is - // the LDR using the result of the ADRP, otherwise we implement the workaround. - uint32_t next_insn = GetInsn(code, literal_offset + 4u); - bool ok = (next_insn & 0xffc00000) == 0xb9400000 && // LDR <Wt>, [<Xn>, #pimm] - (((next_insn >> 5) ^ adrp) & 0x1f) == 0; // <Xn> == ADRP destination reg - return !ok; - } - return false; - } - - static uint32_t GetInsn(ArrayRef<const uint8_t> code, uint32_t offset) { - DCHECK_LE(offset + 4u, code.size()); - DCHECK_EQ(offset & 3u, 0u); - const 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); - } - - template <typename Alloc> - static uint32_t GetInsn(std::vector<uint8_t, Alloc>* code, uint32_t offset) { - return GetInsn(ArrayRef<const uint8_t>(*code), offset); - } - - 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); - - // The ADRP thunk for erratum 843419 is 2 instructions, i.e. 8 bytes. - static constexpr uint32_t kAdrpThunkSize = 8u; - - const bool fix_cortex_a53_843419_; - // Map original patch_offset to thunk offset. - std::vector<std::pair<uint32_t, uint32_t>> adrp_thunk_locations_; - size_t reserved_adrp_thunks_; - size_t processed_adrp_thunks_; - std::vector<uint8_t> current_method_thunks_; - - DISALLOW_COPY_AND_ASSIGN(Arm64RelativePatcher); -}; - #define DCHECK_OFFSET() \ DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \ << "file_offset=" << file_offset << " relative_offset=" << relative_offset @@ -704,23 +106,10 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, method_offset_map_() { CHECK(key_value_store != nullptr); - switch (compiler_driver_->GetInstructionSet()) { - case kX86: - case kX86_64: - relative_patcher_.reset(new X86RelativePatcher); - break; - case kArm: - // Fall through: we generate Thumb2 code for "arm". - case kThumb2: - relative_patcher_.reset(new Thumb2RelativePatcher(this)); - break; - case kArm64: - relative_patcher_.reset(new Arm64RelativePatcher(this)); - break; - default: - relative_patcher_.reset(new NoRelativePatcher); - break; - } + InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); + const InstructionSetFeatures* features = compiler_driver_->GetInstructionSetFeatures(); + relative_patcher_ = linker::RelativePatcher::Create(instruction_set, features, + &method_offset_map_); size_t offset; { @@ -968,7 +357,8 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { bool EndClass() { OatDexMethodVisitor::EndClass(); if (oat_class_index_ == writer_->oat_classes_.size()) { - offset_ = writer_->relative_patcher_->ReserveSpace(offset_, nullptr); + offset_ = writer_->relative_patcher_->ReserveSpace(offset_, nullptr, + MethodReference(nullptr, 0u)); } return true; } @@ -995,7 +385,8 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { quick_code_offset = lb->second; deduped = true; } else { - offset_ = writer_->relative_patcher_->ReserveSpace(offset_, compiled_method); + offset_ = writer_->relative_patcher_->ReserveSpace( + offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex())); offset_ = compiled_method->AlignCode(offset_); DCHECK_ALIGNED_PARAM(offset_, GetInstructionSetAlignment(compiled_method->GetInstructionSet())); @@ -1004,15 +395,15 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { } MethodReference method_ref(dex_file_, it.GetMemberIndex()); - auto method_lb = writer_->method_offset_map_.lower_bound(method_ref); - if (method_lb != writer_->method_offset_map_.end() && - !writer_->method_offset_map_.key_comp()(method_ref, method_lb->first)) { + auto method_lb = writer_->method_offset_map_.map.lower_bound(method_ref); + if (method_lb != writer_->method_offset_map_.map.end() && + !writer_->method_offset_map_.map.key_comp()(method_ref, method_lb->first)) { // TODO: Should this be a hard failure? LOG(WARNING) << "Multiple definitions of " << PrettyMethod(method_ref.dex_method_index, *method_ref.dex_file) << ((method_lb->second != quick_code_offset) ? "; OFFSET MISMATCH" : ""); } else { - writer_->method_offset_map_.PutBefore(method_lb, method_ref, quick_code_offset); + writer_->method_offset_map_.map.PutBefore(method_lb, method_ref, quick_code_offset); } // Update quick method header. @@ -1069,10 +460,12 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { } const uint32_t quick_code_start = quick_code_offset - - writer_->oat_header_->GetExecutableOffset(); + writer_->oat_header_->GetExecutableOffset() - thumb_offset; const DexFile::CodeItem *code_item = it.GetMethodCodeItem(); - writer_->method_info_.push_back(DebugInfo(name, - dex_file_->GetSourceFile(dex_file_->GetClassDef(class_def_index_)), + const DexFile::ClassDef& class_def = dex_file_->GetClassDef(class_def_index_); + writer_->method_info_.push_back(DebugInfo(name, deduped, + dex_file_->GetClassDescriptor(class_def), + dex_file_->GetSourceFile(class_def), quick_code_start, quick_code_start + code_size, code_item == nullptr ? nullptr : dex_file_->GetDebugInfoStream(code_item), compiled_method)); @@ -1399,9 +792,9 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } uint32_t GetTargetOffset(const LinkerPatch& patch) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - auto target_it = writer_->method_offset_map_.find(patch.TargetMethod()); + auto target_it = writer_->method_offset_map_.map.find(patch.TargetMethod()); uint32_t target_offset = - (target_it != writer_->method_offset_map_.end()) ? target_it->second : 0u; + (target_it != writer_->method_offset_map_.map.end()) ? target_it->second : 0u; // If there's no compiled code, point to the correct trampoline. if (UNLIKELY(target_offset == 0)) { mirror::ArtMethod* target = GetTargetMethod(patch); @@ -1940,6 +1333,10 @@ size_t OatWriter::WriteCodeDexFiles(OutputStream* out, #undef VISIT + size_code_alignment_ += relative_patcher_->CodeAlignmentSize(); + size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize(); + size_misc_thunks_ += relative_patcher_->MiscThunksSize(); + return relative_offset; } @@ -1955,6 +1352,15 @@ bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delt return true; } +std::pair<bool, uint32_t> OatWriter::MethodOffsetMap::FindMethodOffset(MethodReference ref) { + auto it = map.find(ref); + if (it == map.end()) { + return std::pair<bool, uint32_t>(false, 0u); + } else { + return std::pair<bool, uint32_t>(true, it->second); + } +} + OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) { offset_ = offset; const std::string& location(dex_file.GetLocation()); diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 676d628450..c472000f37 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -21,6 +21,7 @@ #include <cstddef> #include <memory> +#include "linker/relative_patcher.h" // For linker::RelativePatcherTargetProvider. #include "mem_map.h" #include "method_reference.h" #include "oat.h" @@ -114,14 +115,18 @@ class OatWriter { ~OatWriter(); struct DebugInfo { - DebugInfo(const std::string& method_name, const char* src_file_name, - uint32_t low_pc, uint32_t high_pc, const uint8_t* dbgstream, - CompiledMethod* compiled_method) - : method_name_(method_name), src_file_name_(src_file_name), - low_pc_(low_pc), high_pc_(high_pc), dbgstream_(dbgstream), - compiled_method_(compiled_method) { + DebugInfo(const std::string& method_name, bool deduped, + const char* class_descriptor, const char* src_file_name, + uint32_t low_pc, uint32_t high_pc, + const uint8_t* dbgstream, CompiledMethod* compiled_method) + : method_name_(method_name), deduped_(deduped), + class_descriptor_(class_descriptor), src_file_name_(src_file_name), + low_pc_(low_pc), high_pc_(high_pc), + dbgstream_(dbgstream), compiled_method_(compiled_method) { } std::string method_name_; // Note: this name is a pretty-printed name. + bool deduped_; + const char* class_descriptor_; const char* src_file_name_; uint32_t low_pc_; uint32_t high_pc_; @@ -133,6 +138,10 @@ class OatWriter { return method_info_; } + const CompilerDriver* GetCompilerDriver() { + return compiler_driver_; + } + private: // The DataAccess classes are helper classes that provide access to members related to // a given map, i.e. GC map, mapping table or vmap table. By abstracting these away @@ -327,19 +336,19 @@ class OatWriter { uint32_t size_oat_class_method_bitmaps_; uint32_t size_oat_class_method_offsets_; - class RelativePatcher; - class NoRelativePatcher; - class X86RelativePatcher; - class ArmBaseRelativePatcher; - class Thumb2RelativePatcher; - class Arm64RelativePatcher; - - std::unique_ptr<RelativePatcher> relative_patcher_; + std::unique_ptr<linker::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_; + // Map method reference to assigned offset. + // Wrap the map in a class implementing linker::RelativePatcherTargetProvider. + class MethodOffsetMap FINAL : public linker::RelativePatcherTargetProvider { + public: + std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) OVERRIDE; + SafeMap<MethodReference, uint32_t, MethodReferenceComparator> map; + }; + MethodOffsetMap method_offset_map_; DISALLOW_COPY_AND_ASSIGN(OatWriter); }; diff --git a/runtime/Android.mk b/runtime/Android.mk index dde5407e12..c0e7f47c90 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -471,7 +471,7 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT else # host LOCAL_SHARED_LIBRARIES += libziparchive-host # For ashmem_create_region. - LOCAL_STATIC_LIBRARIES += libcutils + LOCAL_SHARED_LIBRARIES += libcutils endif LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk LOCAL_ADDITIONAL_DEPENDENCIES += $$(LOCAL_PATH)/Android.mk diff --git a/runtime/dwarf.h b/runtime/dwarf.h index 7daa5f1485..b491f4767c 100644 --- a/runtime/dwarf.h +++ b/runtime/dwarf.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_DWARF_H_ namespace art { +namespace dwarf { // Based on the Dwarf 4 specification at dwarfstd.com and issues marked // for inclusion in Dwarf 5 on same. Values not specified in the Dwarf 4 @@ -657,6 +658,7 @@ enum CallFrameInstruction : uint8_t { DW_CFA_hi_user = 0x3f }; +} // namespace dwarf } // namespace art #endif // ART_RUNTIME_DWARF_H_ diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index 3490bcf862..bc5cf9b1ff 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -1665,7 +1665,6 @@ struct PACKED(1) DebugLineHeader { uint16_t version_; uint32_t header_length_; // TODO 32-bit specific size uint8_t minimum_instruction_lenght_; - uint8_t maximum_operations_per_instruction_; uint8_t default_is_stmt_; int8_t line_base_; uint8_t line_range_; @@ -1691,7 +1690,7 @@ struct PACKED(1) DebugLineHeader { return length_field + length; } else if (!IsStandardOpcode(op)) { return op + 1; - } else if (*op == DW_LNS_fixed_advance_pc) { + } else if (*op == dwarf::DW_LNS_fixed_advance_pc) { return op + 1 + sizeof(uint16_t); } else { uint8_t num_args = GetStandardOpcodeLengths()[*op - 1]; @@ -1774,8 +1773,8 @@ class DebugLineInstructionIterator FINAL { }; static bool FixupDebugLine(off_t base_offset_delta, DebugLineInstructionIterator* iter) { - while (iter->Next()) { - if (iter->IsExtendedOpcode() && iter->GetOpcode() == DW_LNE_set_address) { + for (; iter->GetInstruction(); iter->Next()) { + if (iter->IsExtendedOpcode() && iter->GetOpcode() == dwarf::DW_LNE_set_address) { *reinterpret_cast<uint32_t*>(iter->GetArguments()) += base_offset_delta; } } @@ -1792,39 +1791,39 @@ struct PACKED(1) DebugInfoHeader { // Returns -1 if it is variable length, which we will just disallow for now. static int32_t FormLength(uint32_t att) { switch (att) { - case DW_FORM_data1: - case DW_FORM_flag: - case DW_FORM_flag_present: - case DW_FORM_ref1: + case dwarf::DW_FORM_data1: + case dwarf::DW_FORM_flag: + case dwarf::DW_FORM_flag_present: + case dwarf::DW_FORM_ref1: return 1; - case DW_FORM_data2: - case DW_FORM_ref2: + case dwarf::DW_FORM_data2: + case dwarf::DW_FORM_ref2: return 2; - case DW_FORM_addr: // TODO 32-bit only - case DW_FORM_ref_addr: // TODO 32-bit only - case DW_FORM_sec_offset: // TODO 32-bit only - case DW_FORM_strp: // TODO 32-bit only - case DW_FORM_data4: - case DW_FORM_ref4: + case dwarf::DW_FORM_addr: // TODO 32-bit only + case dwarf::DW_FORM_ref_addr: // TODO 32-bit only + case dwarf::DW_FORM_sec_offset: // TODO 32-bit only + case dwarf::DW_FORM_strp: // TODO 32-bit only + case dwarf::DW_FORM_data4: + case dwarf::DW_FORM_ref4: return 4; - case DW_FORM_data8: - case DW_FORM_ref8: - case DW_FORM_ref_sig8: + case dwarf::DW_FORM_data8: + case dwarf::DW_FORM_ref8: + case dwarf::DW_FORM_ref_sig8: return 8; - case DW_FORM_block: - case DW_FORM_block1: - case DW_FORM_block2: - case DW_FORM_block4: - case DW_FORM_exprloc: - case DW_FORM_indirect: - case DW_FORM_ref_udata: - case DW_FORM_sdata: - case DW_FORM_string: - case DW_FORM_udata: + case dwarf::DW_FORM_block: + case dwarf::DW_FORM_block1: + case dwarf::DW_FORM_block2: + case dwarf::DW_FORM_block4: + case dwarf::DW_FORM_exprloc: + case dwarf::DW_FORM_indirect: + case dwarf::DW_FORM_ref_udata: + case dwarf::DW_FORM_sdata: + case dwarf::DW_FORM_string: + case dwarf::DW_FORM_udata: default: return -1; } @@ -2047,13 +2046,13 @@ class DebugInfoIterator { static bool FixupDebugInfo(off_t base_address_delta, DebugInfoIterator* iter) { do { - if (iter->GetCurrentTag()->GetAttrSize(DW_AT_low_pc) != sizeof(int32_t) || - iter->GetCurrentTag()->GetAttrSize(DW_AT_high_pc) != sizeof(int32_t)) { + if (iter->GetCurrentTag()->GetAttrSize(dwarf::DW_AT_low_pc) != sizeof(int32_t) || + iter->GetCurrentTag()->GetAttrSize(dwarf::DW_AT_high_pc) != sizeof(int32_t)) { LOG(ERROR) << "DWARF information with 64 bit pointers is not supported yet."; return false; } - uint32_t* PC_low = reinterpret_cast<uint32_t*>(iter->GetPointerToField(DW_AT_low_pc)); - uint32_t* PC_high = reinterpret_cast<uint32_t*>(iter->GetPointerToField(DW_AT_high_pc)); + uint32_t* PC_low = reinterpret_cast<uint32_t*>(iter->GetPointerToField(dwarf::DW_AT_low_pc)); + uint32_t* PC_high = reinterpret_cast<uint32_t*>(iter->GetPointerToField(dwarf::DW_AT_high_pc)); if (PC_low != nullptr && PC_high != nullptr) { *PC_low += base_address_delta; *PC_high += base_address_delta; diff --git a/test/421-large-frame/src/Main.java b/test/421-large-frame/src/Main.java index 46545b8dc9..81896abbd8 100644 --- a/test/421-large-frame/src/Main.java +++ b/test/421-large-frame/src/Main.java @@ -28,8 +28,6 @@ public class Main { long dummy = 0L; // Sum[i = 0..499](i) = 499 * 500 / 2 = 124750L. assertEquals(124750L, $opt$LargeFrame(dummy)); - // Sum[i = 0..999](i) = 999 * 1000 / 2 = 499500L. - assertEquals(499500L, HugeFrame(dummy)); } static long $opt$LargeFrame(long dummy) { @@ -1042,2013 +1040,4 @@ public class Main { return l499; } } - - // This method cannot be optimized because of its huge size. - static long HugeFrame(long dummy) { - long l0 = 0L + dummy; - long l1 = 1L + dummy; - long l2 = 2L + dummy; - long l3 = 3L + dummy; - long l4 = 4L + dummy; - long l5 = 5L + dummy; - long l6 = 6L + dummy; - long l7 = 7L + dummy; - long l8 = 8L + dummy; - long l9 = 9L + dummy; - long l10 = 10L + dummy; - long l11 = 11L + dummy; - long l12 = 12L + dummy; - long l13 = 13L + dummy; - long l14 = 14L + dummy; - long l15 = 15L + dummy; - long l16 = 16L + dummy; - long l17 = 17L + dummy; - long l18 = 18L + dummy; - long l19 = 19L + dummy; - long l20 = 20L + dummy; - long l21 = 21L + dummy; - long l22 = 22L + dummy; - long l23 = 23L + dummy; - long l24 = 24L + dummy; - long l25 = 25L + dummy; - long l26 = 26L + dummy; - long l27 = 27L + dummy; - long l28 = 28L + dummy; - long l29 = 29L + dummy; - long l30 = 30L + dummy; - long l31 = 31L + dummy; - long l32 = 32L + dummy; - long l33 = 33L + dummy; - long l34 = 34L + dummy; - long l35 = 35L + dummy; - long l36 = 36L + dummy; - long l37 = 37L + dummy; - long l38 = 38L + dummy; - long l39 = 39L + dummy; - long l40 = 40L + dummy; - long l41 = 41L + dummy; - long l42 = 42L + dummy; - long l43 = 43L + dummy; - long l44 = 44L + dummy; - long l45 = 45L + dummy; - long l46 = 46L + dummy; - long l47 = 47L + dummy; - long l48 = 48L + dummy; - long l49 = 49L + dummy; - long l50 = 50L + dummy; - long l51 = 51L + dummy; - long l52 = 52L + dummy; - long l53 = 53L + dummy; - long l54 = 54L + dummy; - long l55 = 55L + dummy; - long l56 = 56L + dummy; - long l57 = 57L + dummy; - long l58 = 58L + dummy; - long l59 = 59L + dummy; - long l60 = 60L + dummy; - long l61 = 61L + dummy; - long l62 = 62L + dummy; - long l63 = 63L + dummy; - long l64 = 64L + dummy; - long l65 = 65L + dummy; - long l66 = 66L + dummy; - long l67 = 67L + dummy; - long l68 = 68L + dummy; - long l69 = 69L + dummy; - long l70 = 70L + dummy; - long l71 = 71L + dummy; - long l72 = 72L + dummy; - long l73 = 73L + dummy; - long l74 = 74L + dummy; - long l75 = 75L + dummy; - long l76 = 76L + dummy; - long l77 = 77L + dummy; - long l78 = 78L + dummy; - long l79 = 79L + dummy; - long l80 = 80L + dummy; - long l81 = 81L + dummy; - long l82 = 82L + dummy; - long l83 = 83L + dummy; - long l84 = 84L + dummy; - long l85 = 85L + dummy; - long l86 = 86L + dummy; - long l87 = 87L + dummy; - long l88 = 88L + dummy; - long l89 = 89L + dummy; - long l90 = 90L + dummy; - long l91 = 91L + dummy; - long l92 = 92L + dummy; - long l93 = 93L + dummy; - long l94 = 94L + dummy; - long l95 = 95L + dummy; - long l96 = 96L + dummy; - long l97 = 97L + dummy; - long l98 = 98L + dummy; - long l99 = 99L + dummy; - long l100 = 100L + dummy; - long l101 = 101L + dummy; - long l102 = 102L + dummy; - long l103 = 103L + dummy; - long l104 = 104L + dummy; - long l105 = 105L + dummy; - long l106 = 106L + dummy; - long l107 = 107L + dummy; - long l108 = 108L + dummy; - long l109 = 109L + dummy; - long l110 = 110L + dummy; - long l111 = 111L + dummy; - long l112 = 112L + dummy; - long l113 = 113L + dummy; - long l114 = 114L + dummy; - long l115 = 115L + dummy; - long l116 = 116L + dummy; - long l117 = 117L + dummy; - long l118 = 118L + dummy; - long l119 = 119L + dummy; - long l120 = 120L + dummy; - long l121 = 121L + dummy; - long l122 = 122L + dummy; - long l123 = 123L + dummy; - long l124 = 124L + dummy; - long l125 = 125L + dummy; - long l126 = 126L + dummy; - long l127 = 127L + dummy; - long l128 = 128L + dummy; - long l129 = 129L + dummy; - long l130 = 130L + dummy; - long l131 = 131L + dummy; - long l132 = 132L + dummy; - long l133 = 133L + dummy; - long l134 = 134L + dummy; - long l135 = 135L + dummy; - long l136 = 136L + dummy; - long l137 = 137L + dummy; - long l138 = 138L + dummy; - long l139 = 139L + dummy; - long l140 = 140L + dummy; - long l141 = 141L + dummy; - long l142 = 142L + dummy; - long l143 = 143L + dummy; - long l144 = 144L + dummy; - long l145 = 145L + dummy; - long l146 = 146L + dummy; - long l147 = 147L + dummy; - long l148 = 148L + dummy; - long l149 = 149L + dummy; - long l150 = 150L + dummy; - long l151 = 151L + dummy; - long l152 = 152L + dummy; - long l153 = 153L + dummy; - long l154 = 154L + dummy; - long l155 = 155L + dummy; - long l156 = 156L + dummy; - long l157 = 157L + dummy; - long l158 = 158L + dummy; - long l159 = 159L + dummy; - long l160 = 160L + dummy; - long l161 = 161L + dummy; - long l162 = 162L + dummy; - long l163 = 163L + dummy; - long l164 = 164L + dummy; - long l165 = 165L + dummy; - long l166 = 166L + dummy; - long l167 = 167L + dummy; - long l168 = 168L + dummy; - long l169 = 169L + dummy; - long l170 = 170L + dummy; - long l171 = 171L + dummy; - long l172 = 172L + dummy; - long l173 = 173L + dummy; - long l174 = 174L + dummy; - long l175 = 175L + dummy; - long l176 = 176L + dummy; - long l177 = 177L + dummy; - long l178 = 178L + dummy; - long l179 = 179L + dummy; - long l180 = 180L + dummy; - long l181 = 181L + dummy; - long l182 = 182L + dummy; - long l183 = 183L + dummy; - long l184 = 184L + dummy; - long l185 = 185L + dummy; - long l186 = 186L + dummy; - long l187 = 187L + dummy; - long l188 = 188L + dummy; - long l189 = 189L + dummy; - long l190 = 190L + dummy; - long l191 = 191L + dummy; - long l192 = 192L + dummy; - long l193 = 193L + dummy; - long l194 = 194L + dummy; - long l195 = 195L + dummy; - long l196 = 196L + dummy; - long l197 = 197L + dummy; - long l198 = 198L + dummy; - long l199 = 199L + dummy; - long l200 = 200L + dummy; - long l201 = 201L + dummy; - long l202 = 202L + dummy; - long l203 = 203L + dummy; - long l204 = 204L + dummy; - long l205 = 205L + dummy; - long l206 = 206L + dummy; - long l207 = 207L + dummy; - long l208 = 208L + dummy; - long l209 = 209L + dummy; - long l210 = 210L + dummy; - long l211 = 211L + dummy; - long l212 = 212L + dummy; - long l213 = 213L + dummy; - long l214 = 214L + dummy; - long l215 = 215L + dummy; - long l216 = 216L + dummy; - long l217 = 217L + dummy; - long l218 = 218L + dummy; - long l219 = 219L + dummy; - long l220 = 220L + dummy; - long l221 = 221L + dummy; - long l222 = 222L + dummy; - long l223 = 223L + dummy; - long l224 = 224L + dummy; - long l225 = 225L + dummy; - long l226 = 226L + dummy; - long l227 = 227L + dummy; - long l228 = 228L + dummy; - long l229 = 229L + dummy; - long l230 = 230L + dummy; - long l231 = 231L + dummy; - long l232 = 232L + dummy; - long l233 = 233L + dummy; - long l234 = 234L + dummy; - long l235 = 235L + dummy; - long l236 = 236L + dummy; - long l237 = 237L + dummy; - long l238 = 238L + dummy; - long l239 = 239L + dummy; - long l240 = 240L + dummy; - long l241 = 241L + dummy; - long l242 = 242L + dummy; - long l243 = 243L + dummy; - long l244 = 244L + dummy; - long l245 = 245L + dummy; - long l246 = 246L + dummy; - long l247 = 247L + dummy; - long l248 = 248L + dummy; - long l249 = 249L + dummy; - long l250 = 250L + dummy; - long l251 = 251L + dummy; - long l252 = 252L + dummy; - long l253 = 253L + dummy; - long l254 = 254L + dummy; - long l255 = 255L + dummy; - long l256 = 256L + dummy; - long l257 = 257L + dummy; - long l258 = 258L + dummy; - long l259 = 259L + dummy; - long l260 = 260L + dummy; - long l261 = 261L + dummy; - long l262 = 262L + dummy; - long l263 = 263L + dummy; - long l264 = 264L + dummy; - long l265 = 265L + dummy; - long l266 = 266L + dummy; - long l267 = 267L + dummy; - long l268 = 268L + dummy; - long l269 = 269L + dummy; - long l270 = 270L + dummy; - long l271 = 271L + dummy; - long l272 = 272L + dummy; - long l273 = 273L + dummy; - long l274 = 274L + dummy; - long l275 = 275L + dummy; - long l276 = 276L + dummy; - long l277 = 277L + dummy; - long l278 = 278L + dummy; - long l279 = 279L + dummy; - long l280 = 280L + dummy; - long l281 = 281L + dummy; - long l282 = 282L + dummy; - long l283 = 283L + dummy; - long l284 = 284L + dummy; - long l285 = 285L + dummy; - long l286 = 286L + dummy; - long l287 = 287L + dummy; - long l288 = 288L + dummy; - long l289 = 289L + dummy; - long l290 = 290L + dummy; - long l291 = 291L + dummy; - long l292 = 292L + dummy; - long l293 = 293L + dummy; - long l294 = 294L + dummy; - long l295 = 295L + dummy; - long l296 = 296L + dummy; - long l297 = 297L + dummy; - long l298 = 298L + dummy; - long l299 = 299L + dummy; - long l300 = 300L + dummy; - long l301 = 301L + dummy; - long l302 = 302L + dummy; - long l303 = 303L + dummy; - long l304 = 304L + dummy; - long l305 = 305L + dummy; - long l306 = 306L + dummy; - long l307 = 307L + dummy; - long l308 = 308L + dummy; - long l309 = 309L + dummy; - long l310 = 310L + dummy; - long l311 = 311L + dummy; - long l312 = 312L + dummy; - long l313 = 313L + dummy; - long l314 = 314L + dummy; - long l315 = 315L + dummy; - long l316 = 316L + dummy; - long l317 = 317L + dummy; - long l318 = 318L + dummy; - long l319 = 319L + dummy; - long l320 = 320L + dummy; - long l321 = 321L + dummy; - long l322 = 322L + dummy; - long l323 = 323L + dummy; - long l324 = 324L + dummy; - long l325 = 325L + dummy; - long l326 = 326L + dummy; - long l327 = 327L + dummy; - long l328 = 328L + dummy; - long l329 = 329L + dummy; - long l330 = 330L + dummy; - long l331 = 331L + dummy; - long l332 = 332L + dummy; - long l333 = 333L + dummy; - long l334 = 334L + dummy; - long l335 = 335L + dummy; - long l336 = 336L + dummy; - long l337 = 337L + dummy; - long l338 = 338L + dummy; - long l339 = 339L + dummy; - long l340 = 340L + dummy; - long l341 = 341L + dummy; - long l342 = 342L + dummy; - long l343 = 343L + dummy; - long l344 = 344L + dummy; - long l345 = 345L + dummy; - long l346 = 346L + dummy; - long l347 = 347L + dummy; - long l348 = 348L + dummy; - long l349 = 349L + dummy; - long l350 = 350L + dummy; - long l351 = 351L + dummy; - long l352 = 352L + dummy; - long l353 = 353L + dummy; - long l354 = 354L + dummy; - long l355 = 355L + dummy; - long l356 = 356L + dummy; - long l357 = 357L + dummy; - long l358 = 358L + dummy; - long l359 = 359L + dummy; - long l360 = 360L + dummy; - long l361 = 361L + dummy; - long l362 = 362L + dummy; - long l363 = 363L + dummy; - long l364 = 364L + dummy; - long l365 = 365L + dummy; - long l366 = 366L + dummy; - long l367 = 367L + dummy; - long l368 = 368L + dummy; - long l369 = 369L + dummy; - long l370 = 370L + dummy; - long l371 = 371L + dummy; - long l372 = 372L + dummy; - long l373 = 373L + dummy; - long l374 = 374L + dummy; - long l375 = 375L + dummy; - long l376 = 376L + dummy; - long l377 = 377L + dummy; - long l378 = 378L + dummy; - long l379 = 379L + dummy; - long l380 = 380L + dummy; - long l381 = 381L + dummy; - long l382 = 382L + dummy; - long l383 = 383L + dummy; - long l384 = 384L + dummy; - long l385 = 385L + dummy; - long l386 = 386L + dummy; - long l387 = 387L + dummy; - long l388 = 388L + dummy; - long l389 = 389L + dummy; - long l390 = 390L + dummy; - long l391 = 391L + dummy; - long l392 = 392L + dummy; - long l393 = 393L + dummy; - long l394 = 394L + dummy; - long l395 = 395L + dummy; - long l396 = 396L + dummy; - long l397 = 397L + dummy; - long l398 = 398L + dummy; - long l399 = 399L + dummy; - long l400 = 400L + dummy; - long l401 = 401L + dummy; - long l402 = 402L + dummy; - long l403 = 403L + dummy; - long l404 = 404L + dummy; - long l405 = 405L + dummy; - long l406 = 406L + dummy; - long l407 = 407L + dummy; - long l408 = 408L + dummy; - long l409 = 409L + dummy; - long l410 = 410L + dummy; - long l411 = 411L + dummy; - long l412 = 412L + dummy; - long l413 = 413L + dummy; - long l414 = 414L + dummy; - long l415 = 415L + dummy; - long l416 = 416L + dummy; - long l417 = 417L + dummy; - long l418 = 418L + dummy; - long l419 = 419L + dummy; - long l420 = 420L + dummy; - long l421 = 421L + dummy; - long l422 = 422L + dummy; - long l423 = 423L + dummy; - long l424 = 424L + dummy; - long l425 = 425L + dummy; - long l426 = 426L + dummy; - long l427 = 427L + dummy; - long l428 = 428L + dummy; - long l429 = 429L + dummy; - long l430 = 430L + dummy; - long l431 = 431L + dummy; - long l432 = 432L + dummy; - long l433 = 433L + dummy; - long l434 = 434L + dummy; - long l435 = 435L + dummy; - long l436 = 436L + dummy; - long l437 = 437L + dummy; - long l438 = 438L + dummy; - long l439 = 439L + dummy; - long l440 = 440L + dummy; - long l441 = 441L + dummy; - long l442 = 442L + dummy; - long l443 = 443L + dummy; - long l444 = 444L + dummy; - long l445 = 445L + dummy; - long l446 = 446L + dummy; - long l447 = 447L + dummy; - long l448 = 448L + dummy; - long l449 = 449L + dummy; - long l450 = 450L + dummy; - long l451 = 451L + dummy; - long l452 = 452L + dummy; - long l453 = 453L + dummy; - long l454 = 454L + dummy; - long l455 = 455L + dummy; - long l456 = 456L + dummy; - long l457 = 457L + dummy; - long l458 = 458L + dummy; - long l459 = 459L + dummy; - long l460 = 460L + dummy; - long l461 = 461L + dummy; - long l462 = 462L + dummy; - long l463 = 463L + dummy; - long l464 = 464L + dummy; - long l465 = 465L + dummy; - long l466 = 466L + dummy; - long l467 = 467L + dummy; - long l468 = 468L + dummy; - long l469 = 469L + dummy; - long l470 = 470L + dummy; - long l471 = 471L + dummy; - long l472 = 472L + dummy; - long l473 = 473L + dummy; - long l474 = 474L + dummy; - long l475 = 475L + dummy; - long l476 = 476L + dummy; - long l477 = 477L + dummy; - long l478 = 478L + dummy; - long l479 = 479L + dummy; - long l480 = 480L + dummy; - long l481 = 481L + dummy; - long l482 = 482L + dummy; - long l483 = 483L + dummy; - long l484 = 484L + dummy; - long l485 = 485L + dummy; - long l486 = 486L + dummy; - long l487 = 487L + dummy; - long l488 = 488L + dummy; - long l489 = 489L + dummy; - long l490 = 490L + dummy; - long l491 = 491L + dummy; - long l492 = 492L + dummy; - long l493 = 493L + dummy; - long l494 = 494L + dummy; - long l495 = 495L + dummy; - long l496 = 496L + dummy; - long l497 = 497L + dummy; - long l498 = 498L + dummy; - long l499 = 499L + dummy; - long l500 = 500L + dummy; - long l501 = 501L + dummy; - long l502 = 502L + dummy; - long l503 = 503L + dummy; - long l504 = 504L + dummy; - long l505 = 505L + dummy; - long l506 = 506L + dummy; - long l507 = 507L + dummy; - long l508 = 508L + dummy; - long l509 = 509L + dummy; - long l510 = 510L + dummy; - long l511 = 511L + dummy; - long l512 = 512L + dummy; - long l513 = 513L + dummy; - long l514 = 514L + dummy; - long l515 = 515L + dummy; - long l516 = 516L + dummy; - long l517 = 517L + dummy; - long l518 = 518L + dummy; - long l519 = 519L + dummy; - long l520 = 520L + dummy; - long l521 = 521L + dummy; - long l522 = 522L + dummy; - long l523 = 523L + dummy; - long l524 = 524L + dummy; - long l525 = 525L + dummy; - long l526 = 526L + dummy; - long l527 = 527L + dummy; - long l528 = 528L + dummy; - long l529 = 529L + dummy; - long l530 = 530L + dummy; - long l531 = 531L + dummy; - long l532 = 532L + dummy; - long l533 = 533L + dummy; - long l534 = 534L + dummy; - long l535 = 535L + dummy; - long l536 = 536L + dummy; - long l537 = 537L + dummy; - long l538 = 538L + dummy; - long l539 = 539L + dummy; - long l540 = 540L + dummy; - long l541 = 541L + dummy; - long l542 = 542L + dummy; - long l543 = 543L + dummy; - long l544 = 544L + dummy; - long l545 = 545L + dummy; - long l546 = 546L + dummy; - long l547 = 547L + dummy; - long l548 = 548L + dummy; - long l549 = 549L + dummy; - long l550 = 550L + dummy; - long l551 = 551L + dummy; - long l552 = 552L + dummy; - long l553 = 553L + dummy; - long l554 = 554L + dummy; - long l555 = 555L + dummy; - long l556 = 556L + dummy; - long l557 = 557L + dummy; - long l558 = 558L + dummy; - long l559 = 559L + dummy; - long l560 = 560L + dummy; - long l561 = 561L + dummy; - long l562 = 562L + dummy; - long l563 = 563L + dummy; - long l564 = 564L + dummy; - long l565 = 565L + dummy; - long l566 = 566L + dummy; - long l567 = 567L + dummy; - long l568 = 568L + dummy; - long l569 = 569L + dummy; - long l570 = 570L + dummy; - long l571 = 571L + dummy; - long l572 = 572L + dummy; - long l573 = 573L + dummy; - long l574 = 574L + dummy; - long l575 = 575L + dummy; - long l576 = 576L + dummy; - long l577 = 577L + dummy; - long l578 = 578L + dummy; - long l579 = 579L + dummy; - long l580 = 580L + dummy; - long l581 = 581L + dummy; - long l582 = 582L + dummy; - long l583 = 583L + dummy; - long l584 = 584L + dummy; - long l585 = 585L + dummy; - long l586 = 586L + dummy; - long l587 = 587L + dummy; - long l588 = 588L + dummy; - long l589 = 589L + dummy; - long l590 = 590L + dummy; - long l591 = 591L + dummy; - long l592 = 592L + dummy; - long l593 = 593L + dummy; - long l594 = 594L + dummy; - long l595 = 595L + dummy; - long l596 = 596L + dummy; - long l597 = 597L + dummy; - long l598 = 598L + dummy; - long l599 = 599L + dummy; - long l600 = 600L + dummy; - long l601 = 601L + dummy; - long l602 = 602L + dummy; - long l603 = 603L + dummy; - long l604 = 604L + dummy; - long l605 = 605L + dummy; - long l606 = 606L + dummy; - long l607 = 607L + dummy; - long l608 = 608L + dummy; - long l609 = 609L + dummy; - long l610 = 610L + dummy; - long l611 = 611L + dummy; - long l612 = 612L + dummy; - long l613 = 613L + dummy; - long l614 = 614L + dummy; - long l615 = 615L + dummy; - long l616 = 616L + dummy; - long l617 = 617L + dummy; - long l618 = 618L + dummy; - long l619 = 619L + dummy; - long l620 = 620L + dummy; - long l621 = 621L + dummy; - long l622 = 622L + dummy; - long l623 = 623L + dummy; - long l624 = 624L + dummy; - long l625 = 625L + dummy; - long l626 = 626L + dummy; - long l627 = 627L + dummy; - long l628 = 628L + dummy; - long l629 = 629L + dummy; - long l630 = 630L + dummy; - long l631 = 631L + dummy; - long l632 = 632L + dummy; - long l633 = 633L + dummy; - long l634 = 634L + dummy; - long l635 = 635L + dummy; - long l636 = 636L + dummy; - long l637 = 637L + dummy; - long l638 = 638L + dummy; - long l639 = 639L + dummy; - long l640 = 640L + dummy; - long l641 = 641L + dummy; - long l642 = 642L + dummy; - long l643 = 643L + dummy; - long l644 = 644L + dummy; - long l645 = 645L + dummy; - long l646 = 646L + dummy; - long l647 = 647L + dummy; - long l648 = 648L + dummy; - long l649 = 649L + dummy; - long l650 = 650L + dummy; - long l651 = 651L + dummy; - long l652 = 652L + dummy; - long l653 = 653L + dummy; - long l654 = 654L + dummy; - long l655 = 655L + dummy; - long l656 = 656L + dummy; - long l657 = 657L + dummy; - long l658 = 658L + dummy; - long l659 = 659L + dummy; - long l660 = 660L + dummy; - long l661 = 661L + dummy; - long l662 = 662L + dummy; - long l663 = 663L + dummy; - long l664 = 664L + dummy; - long l665 = 665L + dummy; - long l666 = 666L + dummy; - long l667 = 667L + dummy; - long l668 = 668L + dummy; - long l669 = 669L + dummy; - long l670 = 670L + dummy; - long l671 = 671L + dummy; - long l672 = 672L + dummy; - long l673 = 673L + dummy; - long l674 = 674L + dummy; - long l675 = 675L + dummy; - long l676 = 676L + dummy; - long l677 = 677L + dummy; - long l678 = 678L + dummy; - long l679 = 679L + dummy; - long l680 = 680L + dummy; - long l681 = 681L + dummy; - long l682 = 682L + dummy; - long l683 = 683L + dummy; - long l684 = 684L + dummy; - long l685 = 685L + dummy; - long l686 = 686L + dummy; - long l687 = 687L + dummy; - long l688 = 688L + dummy; - long l689 = 689L + dummy; - long l690 = 690L + dummy; - long l691 = 691L + dummy; - long l692 = 692L + dummy; - long l693 = 693L + dummy; - long l694 = 694L + dummy; - long l695 = 695L + dummy; - long l696 = 696L + dummy; - long l697 = 697L + dummy; - long l698 = 698L + dummy; - long l699 = 699L + dummy; - long l700 = 700L + dummy; - long l701 = 701L + dummy; - long l702 = 702L + dummy; - long l703 = 703L + dummy; - long l704 = 704L + dummy; - long l705 = 705L + dummy; - long l706 = 706L + dummy; - long l707 = 707L + dummy; - long l708 = 708L + dummy; - long l709 = 709L + dummy; - long l710 = 710L + dummy; - long l711 = 711L + dummy; - long l712 = 712L + dummy; - long l713 = 713L + dummy; - long l714 = 714L + dummy; - long l715 = 715L + dummy; - long l716 = 716L + dummy; - long l717 = 717L + dummy; - long l718 = 718L + dummy; - long l719 = 719L + dummy; - long l720 = 720L + dummy; - long l721 = 721L + dummy; - long l722 = 722L + dummy; - long l723 = 723L + dummy; - long l724 = 724L + dummy; - long l725 = 725L + dummy; - long l726 = 726L + dummy; - long l727 = 727L + dummy; - long l728 = 728L + dummy; - long l729 = 729L + dummy; - long l730 = 730L + dummy; - long l731 = 731L + dummy; - long l732 = 732L + dummy; - long l733 = 733L + dummy; - long l734 = 734L + dummy; - long l735 = 735L + dummy; - long l736 = 736L + dummy; - long l737 = 737L + dummy; - long l738 = 738L + dummy; - long l739 = 739L + dummy; - long l740 = 740L + dummy; - long l741 = 741L + dummy; - long l742 = 742L + dummy; - long l743 = 743L + dummy; - long l744 = 744L + dummy; - long l745 = 745L + dummy; - long l746 = 746L + dummy; - long l747 = 747L + dummy; - long l748 = 748L + dummy; - long l749 = 749L + dummy; - long l750 = 750L + dummy; - long l751 = 751L + dummy; - long l752 = 752L + dummy; - long l753 = 753L + dummy; - long l754 = 754L + dummy; - long l755 = 755L + dummy; - long l756 = 756L + dummy; - long l757 = 757L + dummy; - long l758 = 758L + dummy; - long l759 = 759L + dummy; - long l760 = 760L + dummy; - long l761 = 761L + dummy; - long l762 = 762L + dummy; - long l763 = 763L + dummy; - long l764 = 764L + dummy; - long l765 = 765L + dummy; - long l766 = 766L + dummy; - long l767 = 767L + dummy; - long l768 = 768L + dummy; - long l769 = 769L + dummy; - long l770 = 770L + dummy; - long l771 = 771L + dummy; - long l772 = 772L + dummy; - long l773 = 773L + dummy; - long l774 = 774L + dummy; - long l775 = 775L + dummy; - long l776 = 776L + dummy; - long l777 = 777L + dummy; - long l778 = 778L + dummy; - long l779 = 779L + dummy; - long l780 = 780L + dummy; - long l781 = 781L + dummy; - long l782 = 782L + dummy; - long l783 = 783L + dummy; - long l784 = 784L + dummy; - long l785 = 785L + dummy; - long l786 = 786L + dummy; - long l787 = 787L + dummy; - long l788 = 788L + dummy; - long l789 = 789L + dummy; - long l790 = 790L + dummy; - long l791 = 791L + dummy; - long l792 = 792L + dummy; - long l793 = 793L + dummy; - long l794 = 794L + dummy; - long l795 = 795L + dummy; - long l796 = 796L + dummy; - long l797 = 797L + dummy; - long l798 = 798L + dummy; - long l799 = 799L + dummy; - long l800 = 800L + dummy; - long l801 = 801L + dummy; - long l802 = 802L + dummy; - long l803 = 803L + dummy; - long l804 = 804L + dummy; - long l805 = 805L + dummy; - long l806 = 806L + dummy; - long l807 = 807L + dummy; - long l808 = 808L + dummy; - long l809 = 809L + dummy; - long l810 = 810L + dummy; - long l811 = 811L + dummy; - long l812 = 812L + dummy; - long l813 = 813L + dummy; - long l814 = 814L + dummy; - long l815 = 815L + dummy; - long l816 = 816L + dummy; - long l817 = 817L + dummy; - long l818 = 818L + dummy; - long l819 = 819L + dummy; - long l820 = 820L + dummy; - long l821 = 821L + dummy; - long l822 = 822L + dummy; - long l823 = 823L + dummy; - long l824 = 824L + dummy; - long l825 = 825L + dummy; - long l826 = 826L + dummy; - long l827 = 827L + dummy; - long l828 = 828L + dummy; - long l829 = 829L + dummy; - long l830 = 830L + dummy; - long l831 = 831L + dummy; - long l832 = 832L + dummy; - long l833 = 833L + dummy; - long l834 = 834L + dummy; - long l835 = 835L + dummy; - long l836 = 836L + dummy; - long l837 = 837L + dummy; - long l838 = 838L + dummy; - long l839 = 839L + dummy; - long l840 = 840L + dummy; - long l841 = 841L + dummy; - long l842 = 842L + dummy; - long l843 = 843L + dummy; - long l844 = 844L + dummy; - long l845 = 845L + dummy; - long l846 = 846L + dummy; - long l847 = 847L + dummy; - long l848 = 848L + dummy; - long l849 = 849L + dummy; - long l850 = 850L + dummy; - long l851 = 851L + dummy; - long l852 = 852L + dummy; - long l853 = 853L + dummy; - long l854 = 854L + dummy; - long l855 = 855L + dummy; - long l856 = 856L + dummy; - long l857 = 857L + dummy; - long l858 = 858L + dummy; - long l859 = 859L + dummy; - long l860 = 860L + dummy; - long l861 = 861L + dummy; - long l862 = 862L + dummy; - long l863 = 863L + dummy; - long l864 = 864L + dummy; - long l865 = 865L + dummy; - long l866 = 866L + dummy; - long l867 = 867L + dummy; - long l868 = 868L + dummy; - long l869 = 869L + dummy; - long l870 = 870L + dummy; - long l871 = 871L + dummy; - long l872 = 872L + dummy; - long l873 = 873L + dummy; - long l874 = 874L + dummy; - long l875 = 875L + dummy; - long l876 = 876L + dummy; - long l877 = 877L + dummy; - long l878 = 878L + dummy; - long l879 = 879L + dummy; - long l880 = 880L + dummy; - long l881 = 881L + dummy; - long l882 = 882L + dummy; - long l883 = 883L + dummy; - long l884 = 884L + dummy; - long l885 = 885L + dummy; - long l886 = 886L + dummy; - long l887 = 887L + dummy; - long l888 = 888L + dummy; - long l889 = 889L + dummy; - long l890 = 890L + dummy; - long l891 = 891L + dummy; - long l892 = 892L + dummy; - long l893 = 893L + dummy; - long l894 = 894L + dummy; - long l895 = 895L + dummy; - long l896 = 896L + dummy; - long l897 = 897L + dummy; - long l898 = 898L + dummy; - long l899 = 899L + dummy; - long l900 = 900L + dummy; - long l901 = 901L + dummy; - long l902 = 902L + dummy; - long l903 = 903L + dummy; - long l904 = 904L + dummy; - long l905 = 905L + dummy; - long l906 = 906L + dummy; - long l907 = 907L + dummy; - long l908 = 908L + dummy; - long l909 = 909L + dummy; - long l910 = 910L + dummy; - long l911 = 911L + dummy; - long l912 = 912L + dummy; - long l913 = 913L + dummy; - long l914 = 914L + dummy; - long l915 = 915L + dummy; - long l916 = 916L + dummy; - long l917 = 917L + dummy; - long l918 = 918L + dummy; - long l919 = 919L + dummy; - long l920 = 920L + dummy; - long l921 = 921L + dummy; - long l922 = 922L + dummy; - long l923 = 923L + dummy; - long l924 = 924L + dummy; - long l925 = 925L + dummy; - long l926 = 926L + dummy; - long l927 = 927L + dummy; - long l928 = 928L + dummy; - long l929 = 929L + dummy; - long l930 = 930L + dummy; - long l931 = 931L + dummy; - long l932 = 932L + dummy; - long l933 = 933L + dummy; - long l934 = 934L + dummy; - long l935 = 935L + dummy; - long l936 = 936L + dummy; - long l937 = 937L + dummy; - long l938 = 938L + dummy; - long l939 = 939L + dummy; - long l940 = 940L + dummy; - long l941 = 941L + dummy; - long l942 = 942L + dummy; - long l943 = 943L + dummy; - long l944 = 944L + dummy; - long l945 = 945L + dummy; - long l946 = 946L + dummy; - long l947 = 947L + dummy; - long l948 = 948L + dummy; - long l949 = 949L + dummy; - long l950 = 950L + dummy; - long l951 = 951L + dummy; - long l952 = 952L + dummy; - long l953 = 953L + dummy; - long l954 = 954L + dummy; - long l955 = 955L + dummy; - long l956 = 956L + dummy; - long l957 = 957L + dummy; - long l958 = 958L + dummy; - long l959 = 959L + dummy; - long l960 = 960L + dummy; - long l961 = 961L + dummy; - long l962 = 962L + dummy; - long l963 = 963L + dummy; - long l964 = 964L + dummy; - long l965 = 965L + dummy; - long l966 = 966L + dummy; - long l967 = 967L + dummy; - long l968 = 968L + dummy; - long l969 = 969L + dummy; - long l970 = 970L + dummy; - long l971 = 971L + dummy; - long l972 = 972L + dummy; - long l973 = 973L + dummy; - long l974 = 974L + dummy; - long l975 = 975L + dummy; - long l976 = 976L + dummy; - long l977 = 977L + dummy; - long l978 = 978L + dummy; - long l979 = 979L + dummy; - long l980 = 980L + dummy; - long l981 = 981L + dummy; - long l982 = 982L + dummy; - long l983 = 983L + dummy; - long l984 = 984L + dummy; - long l985 = 985L + dummy; - long l986 = 986L + dummy; - long l987 = 987L + dummy; - long l988 = 988L + dummy; - long l989 = 989L + dummy; - long l990 = 990L + dummy; - long l991 = 991L + dummy; - long l992 = 992L + dummy; - long l993 = 993L + dummy; - long l994 = 994L + dummy; - long l995 = 995L + dummy; - long l996 = 996L + dummy; - long l997 = 997L + dummy; - long l998 = 998L + dummy; - long l999 = 999L + dummy; - l1 += l0; - l2 += l1; - l3 += l2; - l4 += l3; - l5 += l4; - l6 += l5; - l7 += l6; - l8 += l7; - l9 += l8; - l10 += l9; - l11 += l10; - l12 += l11; - l13 += l12; - l14 += l13; - l15 += l14; - l16 += l15; - l17 += l16; - l18 += l17; - l19 += l18; - l20 += l19; - l21 += l20; - l22 += l21; - l23 += l22; - l24 += l23; - l25 += l24; - l26 += l25; - l27 += l26; - l28 += l27; - l29 += l28; - l30 += l29; - l31 += l30; - l32 += l31; - l33 += l32; - l34 += l33; - l35 += l34; - l36 += l35; - l37 += l36; - l38 += l37; - l39 += l38; - l40 += l39; - l41 += l40; - l42 += l41; - l43 += l42; - l44 += l43; - l45 += l44; - l46 += l45; - l47 += l46; - l48 += l47; - l49 += l48; - l50 += l49; - l51 += l50; - l52 += l51; - l53 += l52; - l54 += l53; - l55 += l54; - l56 += l55; - l57 += l56; - l58 += l57; - l59 += l58; - l60 += l59; - l61 += l60; - l62 += l61; - l63 += l62; - l64 += l63; - l65 += l64; - l66 += l65; - l67 += l66; - l68 += l67; - l69 += l68; - l70 += l69; - l71 += l70; - l72 += l71; - l73 += l72; - l74 += l73; - l75 += l74; - l76 += l75; - l77 += l76; - l78 += l77; - l79 += l78; - l80 += l79; - l81 += l80; - l82 += l81; - l83 += l82; - l84 += l83; - l85 += l84; - l86 += l85; - l87 += l86; - l88 += l87; - l89 += l88; - l90 += l89; - l91 += l90; - l92 += l91; - l93 += l92; - l94 += l93; - l95 += l94; - l96 += l95; - l97 += l96; - l98 += l97; - l99 += l98; - l100 += l99; - l101 += l100; - l102 += l101; - l103 += l102; - l104 += l103; - l105 += l104; - l106 += l105; - l107 += l106; - l108 += l107; - l109 += l108; - l110 += l109; - l111 += l110; - l112 += l111; - l113 += l112; - l114 += l113; - l115 += l114; - l116 += l115; - l117 += l116; - l118 += l117; - l119 += l118; - l120 += l119; - l121 += l120; - l122 += l121; - l123 += l122; - l124 += l123; - l125 += l124; - l126 += l125; - l127 += l126; - l128 += l127; - l129 += l128; - l130 += l129; - l131 += l130; - l132 += l131; - l133 += l132; - l134 += l133; - l135 += l134; - l136 += l135; - l137 += l136; - l138 += l137; - l139 += l138; - l140 += l139; - l141 += l140; - l142 += l141; - l143 += l142; - l144 += l143; - l145 += l144; - l146 += l145; - l147 += l146; - l148 += l147; - l149 += l148; - l150 += l149; - l151 += l150; - l152 += l151; - l153 += l152; - l154 += l153; - l155 += l154; - l156 += l155; - l157 += l156; - l158 += l157; - l159 += l158; - l160 += l159; - l161 += l160; - l162 += l161; - l163 += l162; - l164 += l163; - l165 += l164; - l166 += l165; - l167 += l166; - l168 += l167; - l169 += l168; - l170 += l169; - l171 += l170; - l172 += l171; - l173 += l172; - l174 += l173; - l175 += l174; - l176 += l175; - l177 += l176; - l178 += l177; - l179 += l178; - l180 += l179; - l181 += l180; - l182 += l181; - l183 += l182; - l184 += l183; - l185 += l184; - l186 += l185; - l187 += l186; - l188 += l187; - l189 += l188; - l190 += l189; - l191 += l190; - l192 += l191; - l193 += l192; - l194 += l193; - l195 += l194; - l196 += l195; - l197 += l196; - l198 += l197; - l199 += l198; - l200 += l199; - l201 += l200; - l202 += l201; - l203 += l202; - l204 += l203; - l205 += l204; - l206 += l205; - l207 += l206; - l208 += l207; - l209 += l208; - l210 += l209; - l211 += l210; - l212 += l211; - l213 += l212; - l214 += l213; - l215 += l214; - l216 += l215; - l217 += l216; - l218 += l217; - l219 += l218; - l220 += l219; - l221 += l220; - l222 += l221; - l223 += l222; - l224 += l223; - l225 += l224; - l226 += l225; - l227 += l226; - l228 += l227; - l229 += l228; - l230 += l229; - l231 += l230; - l232 += l231; - l233 += l232; - l234 += l233; - l235 += l234; - l236 += l235; - l237 += l236; - l238 += l237; - l239 += l238; - l240 += l239; - l241 += l240; - l242 += l241; - l243 += l242; - l244 += l243; - l245 += l244; - l246 += l245; - l247 += l246; - l248 += l247; - l249 += l248; - l250 += l249; - l251 += l250; - l252 += l251; - l253 += l252; - l254 += l253; - l255 += l254; - l256 += l255; - l257 += l256; - l258 += l257; - l259 += l258; - l260 += l259; - l261 += l260; - l262 += l261; - l263 += l262; - l264 += l263; - l265 += l264; - l266 += l265; - l267 += l266; - l268 += l267; - l269 += l268; - l270 += l269; - l271 += l270; - l272 += l271; - l273 += l272; - l274 += l273; - l275 += l274; - l276 += l275; - l277 += l276; - l278 += l277; - l279 += l278; - l280 += l279; - l281 += l280; - l282 += l281; - l283 += l282; - l284 += l283; - l285 += l284; - l286 += l285; - l287 += l286; - l288 += l287; - l289 += l288; - l290 += l289; - l291 += l290; - l292 += l291; - l293 += l292; - l294 += l293; - l295 += l294; - l296 += l295; - l297 += l296; - l298 += l297; - l299 += l298; - l300 += l299; - l301 += l300; - l302 += l301; - l303 += l302; - l304 += l303; - l305 += l304; - l306 += l305; - l307 += l306; - l308 += l307; - l309 += l308; - l310 += l309; - l311 += l310; - l312 += l311; - l313 += l312; - l314 += l313; - l315 += l314; - l316 += l315; - l317 += l316; - l318 += l317; - l319 += l318; - l320 += l319; - l321 += l320; - l322 += l321; - l323 += l322; - l324 += l323; - l325 += l324; - l326 += l325; - l327 += l326; - l328 += l327; - l329 += l328; - l330 += l329; - l331 += l330; - l332 += l331; - l333 += l332; - l334 += l333; - l335 += l334; - l336 += l335; - l337 += l336; - l338 += l337; - l339 += l338; - l340 += l339; - l341 += l340; - l342 += l341; - l343 += l342; - l344 += l343; - l345 += l344; - l346 += l345; - l347 += l346; - l348 += l347; - l349 += l348; - l350 += l349; - l351 += l350; - l352 += l351; - l353 += l352; - l354 += l353; - l355 += l354; - l356 += l355; - l357 += l356; - l358 += l357; - l359 += l358; - l360 += l359; - l361 += l360; - l362 += l361; - l363 += l362; - l364 += l363; - l365 += l364; - l366 += l365; - l367 += l366; - l368 += l367; - l369 += l368; - l370 += l369; - l371 += l370; - l372 += l371; - l373 += l372; - l374 += l373; - l375 += l374; - l376 += l375; - l377 += l376; - l378 += l377; - l379 += l378; - l380 += l379; - l381 += l380; - l382 += l381; - l383 += l382; - l384 += l383; - l385 += l384; - l386 += l385; - l387 += l386; - l388 += l387; - l389 += l388; - l390 += l389; - l391 += l390; - l392 += l391; - l393 += l392; - l394 += l393; - l395 += l394; - l396 += l395; - l397 += l396; - l398 += l397; - l399 += l398; - l400 += l399; - l401 += l400; - l402 += l401; - l403 += l402; - l404 += l403; - l405 += l404; - l406 += l405; - l407 += l406; - l408 += l407; - l409 += l408; - l410 += l409; - l411 += l410; - l412 += l411; - l413 += l412; - l414 += l413; - l415 += l414; - l416 += l415; - l417 += l416; - l418 += l417; - l419 += l418; - l420 += l419; - l421 += l420; - l422 += l421; - l423 += l422; - l424 += l423; - l425 += l424; - l426 += l425; - l427 += l426; - l428 += l427; - l429 += l428; - l430 += l429; - l431 += l430; - l432 += l431; - l433 += l432; - l434 += l433; - l435 += l434; - l436 += l435; - l437 += l436; - l438 += l437; - l439 += l438; - l440 += l439; - l441 += l440; - l442 += l441; - l443 += l442; - l444 += l443; - l445 += l444; - l446 += l445; - l447 += l446; - l448 += l447; - l449 += l448; - l450 += l449; - l451 += l450; - l452 += l451; - l453 += l452; - l454 += l453; - l455 += l454; - l456 += l455; - l457 += l456; - l458 += l457; - l459 += l458; - l460 += l459; - l461 += l460; - l462 += l461; - l463 += l462; - l464 += l463; - l465 += l464; - l466 += l465; - l467 += l466; - l468 += l467; - l469 += l468; - l470 += l469; - l471 += l470; - l472 += l471; - l473 += l472; - l474 += l473; - l475 += l474; - l476 += l475; - l477 += l476; - l478 += l477; - l479 += l478; - l480 += l479; - l481 += l480; - l482 += l481; - l483 += l482; - l484 += l483; - l485 += l484; - l486 += l485; - l487 += l486; - l488 += l487; - l489 += l488; - l490 += l489; - l491 += l490; - l492 += l491; - l493 += l492; - l494 += l493; - l495 += l494; - l496 += l495; - l497 += l496; - l498 += l497; - l499 += l498; - l500 += l499; - l501 += l500; - l502 += l501; - l503 += l502; - l504 += l503; - l505 += l504; - l506 += l505; - l507 += l506; - l508 += l507; - l509 += l508; - l510 += l509; - l511 += l510; - l512 += l511; - l513 += l512; - l514 += l513; - l515 += l514; - l516 += l515; - l517 += l516; - l518 += l517; - l519 += l518; - l520 += l519; - l521 += l520; - l522 += l521; - l523 += l522; - l524 += l523; - l525 += l524; - l526 += l525; - l527 += l526; - l528 += l527; - l529 += l528; - l530 += l529; - l531 += l530; - l532 += l531; - l533 += l532; - l534 += l533; - l535 += l534; - l536 += l535; - l537 += l536; - l538 += l537; - l539 += l538; - l540 += l539; - l541 += l540; - l542 += l541; - l543 += l542; - l544 += l543; - l545 += l544; - l546 += l545; - l547 += l546; - l548 += l547; - l549 += l548; - l550 += l549; - l551 += l550; - l552 += l551; - l553 += l552; - l554 += l553; - l555 += l554; - l556 += l555; - l557 += l556; - l558 += l557; - l559 += l558; - l560 += l559; - l561 += l560; - l562 += l561; - l563 += l562; - l564 += l563; - l565 += l564; - l566 += l565; - l567 += l566; - l568 += l567; - l569 += l568; - l570 += l569; - l571 += l570; - l572 += l571; - l573 += l572; - l574 += l573; - l575 += l574; - l576 += l575; - l577 += l576; - l578 += l577; - l579 += l578; - l580 += l579; - l581 += l580; - l582 += l581; - l583 += l582; - l584 += l583; - l585 += l584; - l586 += l585; - l587 += l586; - l588 += l587; - l589 += l588; - l590 += l589; - l591 += l590; - l592 += l591; - l593 += l592; - l594 += l593; - l595 += l594; - l596 += l595; - l597 += l596; - l598 += l597; - l599 += l598; - l600 += l599; - l601 += l600; - l602 += l601; - l603 += l602; - l604 += l603; - l605 += l604; - l606 += l605; - l607 += l606; - l608 += l607; - l609 += l608; - l610 += l609; - l611 += l610; - l612 += l611; - l613 += l612; - l614 += l613; - l615 += l614; - l616 += l615; - l617 += l616; - l618 += l617; - l619 += l618; - l620 += l619; - l621 += l620; - l622 += l621; - l623 += l622; - l624 += l623; - l625 += l624; - l626 += l625; - l627 += l626; - l628 += l627; - l629 += l628; - l630 += l629; - l631 += l630; - l632 += l631; - l633 += l632; - l634 += l633; - l635 += l634; - l636 += l635; - l637 += l636; - l638 += l637; - l639 += l638; - l640 += l639; - l641 += l640; - l642 += l641; - l643 += l642; - l644 += l643; - l645 += l644; - l646 += l645; - l647 += l646; - l648 += l647; - l649 += l648; - l650 += l649; - l651 += l650; - l652 += l651; - l653 += l652; - l654 += l653; - l655 += l654; - l656 += l655; - l657 += l656; - l658 += l657; - l659 += l658; - l660 += l659; - l661 += l660; - l662 += l661; - l663 += l662; - l664 += l663; - l665 += l664; - l666 += l665; - l667 += l666; - l668 += l667; - l669 += l668; - l670 += l669; - l671 += l670; - l672 += l671; - l673 += l672; - l674 += l673; - l675 += l674; - l676 += l675; - l677 += l676; - l678 += l677; - l679 += l678; - l680 += l679; - l681 += l680; - l682 += l681; - l683 += l682; - l684 += l683; - l685 += l684; - l686 += l685; - l687 += l686; - l688 += l687; - l689 += l688; - l690 += l689; - l691 += l690; - l692 += l691; - l693 += l692; - l694 += l693; - l695 += l694; - l696 += l695; - l697 += l696; - l698 += l697; - l699 += l698; - l700 += l699; - l701 += l700; - l702 += l701; - l703 += l702; - l704 += l703; - l705 += l704; - l706 += l705; - l707 += l706; - l708 += l707; - l709 += l708; - l710 += l709; - l711 += l710; - l712 += l711; - l713 += l712; - l714 += l713; - l715 += l714; - l716 += l715; - l717 += l716; - l718 += l717; - l719 += l718; - l720 += l719; - l721 += l720; - l722 += l721; - l723 += l722; - l724 += l723; - l725 += l724; - l726 += l725; - l727 += l726; - l728 += l727; - l729 += l728; - l730 += l729; - l731 += l730; - l732 += l731; - l733 += l732; - l734 += l733; - l735 += l734; - l736 += l735; - l737 += l736; - l738 += l737; - l739 += l738; - l740 += l739; - l741 += l740; - l742 += l741; - l743 += l742; - l744 += l743; - l745 += l744; - l746 += l745; - l747 += l746; - l748 += l747; - l749 += l748; - l750 += l749; - l751 += l750; - l752 += l751; - l753 += l752; - l754 += l753; - l755 += l754; - l756 += l755; - l757 += l756; - l758 += l757; - l759 += l758; - l760 += l759; - l761 += l760; - l762 += l761; - l763 += l762; - l764 += l763; - l765 += l764; - l766 += l765; - l767 += l766; - l768 += l767; - l769 += l768; - l770 += l769; - l771 += l770; - l772 += l771; - l773 += l772; - l774 += l773; - l775 += l774; - l776 += l775; - l777 += l776; - l778 += l777; - l779 += l778; - l780 += l779; - l781 += l780; - l782 += l781; - l783 += l782; - l784 += l783; - l785 += l784; - l786 += l785; - l787 += l786; - l788 += l787; - l789 += l788; - l790 += l789; - l791 += l790; - l792 += l791; - l793 += l792; - l794 += l793; - l795 += l794; - l796 += l795; - l797 += l796; - l798 += l797; - l799 += l798; - l800 += l799; - l801 += l800; - l802 += l801; - l803 += l802; - l804 += l803; - l805 += l804; - l806 += l805; - l807 += l806; - l808 += l807; - l809 += l808; - l810 += l809; - l811 += l810; - l812 += l811; - l813 += l812; - l814 += l813; - l815 += l814; - l816 += l815; - l817 += l816; - l818 += l817; - l819 += l818; - l820 += l819; - l821 += l820; - l822 += l821; - l823 += l822; - l824 += l823; - l825 += l824; - l826 += l825; - l827 += l826; - l828 += l827; - l829 += l828; - l830 += l829; - l831 += l830; - l832 += l831; - l833 += l832; - l834 += l833; - l835 += l834; - l836 += l835; - l837 += l836; - l838 += l837; - l839 += l838; - l840 += l839; - l841 += l840; - l842 += l841; - l843 += l842; - l844 += l843; - l845 += l844; - l846 += l845; - l847 += l846; - l848 += l847; - l849 += l848; - l850 += l849; - l851 += l850; - l852 += l851; - l853 += l852; - l854 += l853; - l855 += l854; - l856 += l855; - l857 += l856; - l858 += l857; - l859 += l858; - l860 += l859; - l861 += l860; - l862 += l861; - l863 += l862; - l864 += l863; - l865 += l864; - l866 += l865; - l867 += l866; - l868 += l867; - l869 += l868; - l870 += l869; - l871 += l870; - l872 += l871; - l873 += l872; - l874 += l873; - l875 += l874; - l876 += l875; - l877 += l876; - l878 += l877; - l879 += l878; - l880 += l879; - l881 += l880; - l882 += l881; - l883 += l882; - l884 += l883; - l885 += l884; - l886 += l885; - l887 += l886; - l888 += l887; - l889 += l888; - l890 += l889; - l891 += l890; - l892 += l891; - l893 += l892; - l894 += l893; - l895 += l894; - l896 += l895; - l897 += l896; - l898 += l897; - l899 += l898; - l900 += l899; - l901 += l900; - l902 += l901; - l903 += l902; - l904 += l903; - l905 += l904; - l906 += l905; - l907 += l906; - l908 += l907; - l909 += l908; - l910 += l909; - l911 += l910; - l912 += l911; - l913 += l912; - l914 += l913; - l915 += l914; - l916 += l915; - l917 += l916; - l918 += l917; - l919 += l918; - l920 += l919; - l921 += l920; - l922 += l921; - l923 += l922; - l924 += l923; - l925 += l924; - l926 += l925; - l927 += l926; - l928 += l927; - l929 += l928; - l930 += l929; - l931 += l930; - l932 += l931; - l933 += l932; - l934 += l933; - l935 += l934; - l936 += l935; - l937 += l936; - l938 += l937; - l939 += l938; - l940 += l939; - l941 += l940; - l942 += l941; - l943 += l942; - l944 += l943; - l945 += l944; - l946 += l945; - l947 += l946; - l948 += l947; - l949 += l948; - l950 += l949; - l951 += l950; - l952 += l951; - l953 += l952; - l954 += l953; - l955 += l954; - l956 += l955; - l957 += l956; - l958 += l957; - l959 += l958; - l960 += l959; - l961 += l960; - l962 += l961; - l963 += l962; - l964 += l963; - l965 += l964; - l966 += l965; - l967 += l966; - l968 += l967; - l969 += l968; - l970 += l969; - l971 += l970; - l972 += l971; - l973 += l972; - l974 += l973; - l975 += l974; - l976 += l975; - l977 += l976; - l978 += l977; - l979 += l978; - l980 += l979; - l981 += l980; - l982 += l981; - l983 += l982; - l984 += l983; - l985 += l984; - l986 += l985; - l987 += l986; - l988 += l987; - l989 += l988; - l990 += l989; - l991 += l990; - l992 += l991; - l993 += l992; - l994 += l993; - l995 += l994; - l996 += l995; - l997 += l996; - l998 += l997; - l999 += l998; - // Create a branch to beat the large method check. - if (l998 == l999) { - return l998; - } else { - return l999; - } - } } diff --git a/test/470-huge-method/expected.txt b/test/470-huge-method/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/470-huge-method/expected.txt diff --git a/test/470-huge-method/info.txt b/test/470-huge-method/info.txt new file mode 100644 index 0000000000..6074505a60 --- /dev/null +++ b/test/470-huge-method/info.txt @@ -0,0 +1 @@ +Test for huge method. diff --git a/test/470-huge-method/src/Main.java b/test/470-huge-method/src/Main.java new file mode 100644 index 0000000000..cd42561f7b --- /dev/null +++ b/test/470-huge-method/src/Main.java @@ -0,0 +1,2033 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + + public static void assertEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void main(String[] args) { + // Sum[i = 0..999](i) = 999 * 1000 / 2 = 499500L. + assertEquals(499500L, HugeMethod()); + } + + // We're not compiling this method because we consider it huge. + static long HugeMethod() { + long l0 = 0; + long l1 = 1; + long l2 = 2; + long l3 = 3; + long l4 = 4; + long l5 = 5; + long l6 = 6; + long l7 = 7; + long l8 = 8; + long l9 = 9; + long l10 = 10; + long l11 = 11; + long l12 = 12; + long l13 = 13; + long l14 = 14; + long l15 = 15; + long l16 = 16; + long l17 = 17; + long l18 = 18; + long l19 = 19; + long l20 = 20; + long l21 = 21; + long l22 = 22; + long l23 = 23; + long l24 = 24; + long l25 = 25; + long l26 = 26; + long l27 = 27; + long l28 = 28; + long l29 = 29; + long l30 = 30; + long l31 = 31; + long l32 = 32; + long l33 = 33; + long l34 = 34; + long l35 = 35; + long l36 = 36; + long l37 = 37; + long l38 = 38; + long l39 = 39; + long l40 = 40; + long l41 = 41; + long l42 = 42; + long l43 = 43; + long l44 = 44; + long l45 = 45; + long l46 = 46; + long l47 = 47; + long l48 = 48; + long l49 = 49; + long l50 = 50; + long l51 = 51; + long l52 = 52; + long l53 = 53; + long l54 = 54; + long l55 = 55; + long l56 = 56; + long l57 = 57; + long l58 = 58; + long l59 = 59; + long l60 = 60; + long l61 = 61; + long l62 = 62; + long l63 = 63; + long l64 = 64; + long l65 = 65; + long l66 = 66; + long l67 = 67; + long l68 = 68; + long l69 = 69; + long l70 = 70; + long l71 = 71; + long l72 = 72; + long l73 = 73; + long l74 = 74; + long l75 = 75; + long l76 = 76; + long l77 = 77; + long l78 = 78; + long l79 = 79; + long l80 = 80; + long l81 = 81; + long l82 = 82; + long l83 = 83; + long l84 = 84; + long l85 = 85; + long l86 = 86; + long l87 = 87; + long l88 = 88; + long l89 = 89; + long l90 = 90; + long l91 = 91; + long l92 = 92; + long l93 = 93; + long l94 = 94; + long l95 = 95; + long l96 = 96; + long l97 = 97; + long l98 = 98; + long l99 = 99; + long l100 = 100; + long l101 = 101; + long l102 = 102; + long l103 = 103; + long l104 = 104; + long l105 = 105; + long l106 = 106; + long l107 = 107; + long l108 = 108; + long l109 = 109; + long l110 = 110; + long l111 = 111; + long l112 = 112; + long l113 = 113; + long l114 = 114; + long l115 = 115; + long l116 = 116; + long l117 = 117; + long l118 = 118; + long l119 = 119; + long l120 = 120; + long l121 = 121; + long l122 = 122; + long l123 = 123; + long l124 = 124; + long l125 = 125; + long l126 = 126; + long l127 = 127; + long l128 = 128; + long l129 = 129; + long l130 = 130; + long l131 = 131; + long l132 = 132; + long l133 = 133; + long l134 = 134; + long l135 = 135; + long l136 = 136; + long l137 = 137; + long l138 = 138; + long l139 = 139; + long l140 = 140; + long l141 = 141; + long l142 = 142; + long l143 = 143; + long l144 = 144; + long l145 = 145; + long l146 = 146; + long l147 = 147; + long l148 = 148; + long l149 = 149; + long l150 = 150; + long l151 = 151; + long l152 = 152; + long l153 = 153; + long l154 = 154; + long l155 = 155; + long l156 = 156; + long l157 = 157; + long l158 = 158; + long l159 = 159; + long l160 = 160; + long l161 = 161; + long l162 = 162; + long l163 = 163; + long l164 = 164; + long l165 = 165; + long l166 = 166; + long l167 = 167; + long l168 = 168; + long l169 = 169; + long l170 = 170; + long l171 = 171; + long l172 = 172; + long l173 = 173; + long l174 = 174; + long l175 = 175; + long l176 = 176; + long l177 = 177; + long l178 = 178; + long l179 = 179; + long l180 = 180; + long l181 = 181; + long l182 = 182; + long l183 = 183; + long l184 = 184; + long l185 = 185; + long l186 = 186; + long l187 = 187; + long l188 = 188; + long l189 = 189; + long l190 = 190; + long l191 = 191; + long l192 = 192; + long l193 = 193; + long l194 = 194; + long l195 = 195; + long l196 = 196; + long l197 = 197; + long l198 = 198; + long l199 = 199; + long l200 = 200; + long l201 = 201; + long l202 = 202; + long l203 = 203; + long l204 = 204; + long l205 = 205; + long l206 = 206; + long l207 = 207; + long l208 = 208; + long l209 = 209; + long l210 = 210; + long l211 = 211; + long l212 = 212; + long l213 = 213; + long l214 = 214; + long l215 = 215; + long l216 = 216; + long l217 = 217; + long l218 = 218; + long l219 = 219; + long l220 = 220; + long l221 = 221; + long l222 = 222; + long l223 = 223; + long l224 = 224; + long l225 = 225; + long l226 = 226; + long l227 = 227; + long l228 = 228; + long l229 = 229; + long l230 = 230; + long l231 = 231; + long l232 = 232; + long l233 = 233; + long l234 = 234; + long l235 = 235; + long l236 = 236; + long l237 = 237; + long l238 = 238; + long l239 = 239; + long l240 = 240; + long l241 = 241; + long l242 = 242; + long l243 = 243; + long l244 = 244; + long l245 = 245; + long l246 = 246; + long l247 = 247; + long l248 = 248; + long l249 = 249; + long l250 = 250; + long l251 = 251; + long l252 = 252; + long l253 = 253; + long l254 = 254; + long l255 = 255; + long l256 = 256; + long l257 = 257; + long l258 = 258; + long l259 = 259; + long l260 = 260; + long l261 = 261; + long l262 = 262; + long l263 = 263; + long l264 = 264; + long l265 = 265; + long l266 = 266; + long l267 = 267; + long l268 = 268; + long l269 = 269; + long l270 = 270; + long l271 = 271; + long l272 = 272; + long l273 = 273; + long l274 = 274; + long l275 = 275; + long l276 = 276; + long l277 = 277; + long l278 = 278; + long l279 = 279; + long l280 = 280; + long l281 = 281; + long l282 = 282; + long l283 = 283; + long l284 = 284; + long l285 = 285; + long l286 = 286; + long l287 = 287; + long l288 = 288; + long l289 = 289; + long l290 = 290; + long l291 = 291; + long l292 = 292; + long l293 = 293; + long l294 = 294; + long l295 = 295; + long l296 = 296; + long l297 = 297; + long l298 = 298; + long l299 = 299; + long l300 = 300; + long l301 = 301; + long l302 = 302; + long l303 = 303; + long l304 = 304; + long l305 = 305; + long l306 = 306; + long l307 = 307; + long l308 = 308; + long l309 = 309; + long l310 = 310; + long l311 = 311; + long l312 = 312; + long l313 = 313; + long l314 = 314; + long l315 = 315; + long l316 = 316; + long l317 = 317; + long l318 = 318; + long l319 = 319; + long l320 = 320; + long l321 = 321; + long l322 = 322; + long l323 = 323; + long l324 = 324; + long l325 = 325; + long l326 = 326; + long l327 = 327; + long l328 = 328; + long l329 = 329; + long l330 = 330; + long l331 = 331; + long l332 = 332; + long l333 = 333; + long l334 = 334; + long l335 = 335; + long l336 = 336; + long l337 = 337; + long l338 = 338; + long l339 = 339; + long l340 = 340; + long l341 = 341; + long l342 = 342; + long l343 = 343; + long l344 = 344; + long l345 = 345; + long l346 = 346; + long l347 = 347; + long l348 = 348; + long l349 = 349; + long l350 = 350; + long l351 = 351; + long l352 = 352; + long l353 = 353; + long l354 = 354; + long l355 = 355; + long l356 = 356; + long l357 = 357; + long l358 = 358; + long l359 = 359; + long l360 = 360; + long l361 = 361; + long l362 = 362; + long l363 = 363; + long l364 = 364; + long l365 = 365; + long l366 = 366; + long l367 = 367; + long l368 = 368; + long l369 = 369; + long l370 = 370; + long l371 = 371; + long l372 = 372; + long l373 = 373; + long l374 = 374; + long l375 = 375; + long l376 = 376; + long l377 = 377; + long l378 = 378; + long l379 = 379; + long l380 = 380; + long l381 = 381; + long l382 = 382; + long l383 = 383; + long l384 = 384; + long l385 = 385; + long l386 = 386; + long l387 = 387; + long l388 = 388; + long l389 = 389; + long l390 = 390; + long l391 = 391; + long l392 = 392; + long l393 = 393; + long l394 = 394; + long l395 = 395; + long l396 = 396; + long l397 = 397; + long l398 = 398; + long l399 = 399; + long l400 = 400; + long l401 = 401; + long l402 = 402; + long l403 = 403; + long l404 = 404; + long l405 = 405; + long l406 = 406; + long l407 = 407; + long l408 = 408; + long l409 = 409; + long l410 = 410; + long l411 = 411; + long l412 = 412; + long l413 = 413; + long l414 = 414; + long l415 = 415; + long l416 = 416; + long l417 = 417; + long l418 = 418; + long l419 = 419; + long l420 = 420; + long l421 = 421; + long l422 = 422; + long l423 = 423; + long l424 = 424; + long l425 = 425; + long l426 = 426; + long l427 = 427; + long l428 = 428; + long l429 = 429; + long l430 = 430; + long l431 = 431; + long l432 = 432; + long l433 = 433; + long l434 = 434; + long l435 = 435; + long l436 = 436; + long l437 = 437; + long l438 = 438; + long l439 = 439; + long l440 = 440; + long l441 = 441; + long l442 = 442; + long l443 = 443; + long l444 = 444; + long l445 = 445; + long l446 = 446; + long l447 = 447; + long l448 = 448; + long l449 = 449; + long l450 = 450; + long l451 = 451; + long l452 = 452; + long l453 = 453; + long l454 = 454; + long l455 = 455; + long l456 = 456; + long l457 = 457; + long l458 = 458; + long l459 = 459; + long l460 = 460; + long l461 = 461; + long l462 = 462; + long l463 = 463; + long l464 = 464; + long l465 = 465; + long l466 = 466; + long l467 = 467; + long l468 = 468; + long l469 = 469; + long l470 = 470; + long l471 = 471; + long l472 = 472; + long l473 = 473; + long l474 = 474; + long l475 = 475; + long l476 = 476; + long l477 = 477; + long l478 = 478; + long l479 = 479; + long l480 = 480; + long l481 = 481; + long l482 = 482; + long l483 = 483; + long l484 = 484; + long l485 = 485; + long l486 = 486; + long l487 = 487; + long l488 = 488; + long l489 = 489; + long l490 = 490; + long l491 = 491; + long l492 = 492; + long l493 = 493; + long l494 = 494; + long l495 = 495; + long l496 = 496; + long l497 = 497; + long l498 = 498; + long l499 = 499; + long l500 = 500; + long l501 = 501; + long l502 = 502; + long l503 = 503; + long l504 = 504; + long l505 = 505; + long l506 = 506; + long l507 = 507; + long l508 = 508; + long l509 = 509; + long l510 = 510; + long l511 = 511; + long l512 = 512; + long l513 = 513; + long l514 = 514; + long l515 = 515; + long l516 = 516; + long l517 = 517; + long l518 = 518; + long l519 = 519; + long l520 = 520; + long l521 = 521; + long l522 = 522; + long l523 = 523; + long l524 = 524; + long l525 = 525; + long l526 = 526; + long l527 = 527; + long l528 = 528; + long l529 = 529; + long l530 = 530; + long l531 = 531; + long l532 = 532; + long l533 = 533; + long l534 = 534; + long l535 = 535; + long l536 = 536; + long l537 = 537; + long l538 = 538; + long l539 = 539; + long l540 = 540; + long l541 = 541; + long l542 = 542; + long l543 = 543; + long l544 = 544; + long l545 = 545; + long l546 = 546; + long l547 = 547; + long l548 = 548; + long l549 = 549; + long l550 = 550; + long l551 = 551; + long l552 = 552; + long l553 = 553; + long l554 = 554; + long l555 = 555; + long l556 = 556; + long l557 = 557; + long l558 = 558; + long l559 = 559; + long l560 = 560; + long l561 = 561; + long l562 = 562; + long l563 = 563; + long l564 = 564; + long l565 = 565; + long l566 = 566; + long l567 = 567; + long l568 = 568; + long l569 = 569; + long l570 = 570; + long l571 = 571; + long l572 = 572; + long l573 = 573; + long l574 = 574; + long l575 = 575; + long l576 = 576; + long l577 = 577; + long l578 = 578; + long l579 = 579; + long l580 = 580; + long l581 = 581; + long l582 = 582; + long l583 = 583; + long l584 = 584; + long l585 = 585; + long l586 = 586; + long l587 = 587; + long l588 = 588; + long l589 = 589; + long l590 = 590; + long l591 = 591; + long l592 = 592; + long l593 = 593; + long l594 = 594; + long l595 = 595; + long l596 = 596; + long l597 = 597; + long l598 = 598; + long l599 = 599; + long l600 = 600; + long l601 = 601; + long l602 = 602; + long l603 = 603; + long l604 = 604; + long l605 = 605; + long l606 = 606; + long l607 = 607; + long l608 = 608; + long l609 = 609; + long l610 = 610; + long l611 = 611; + long l612 = 612; + long l613 = 613; + long l614 = 614; + long l615 = 615; + long l616 = 616; + long l617 = 617; + long l618 = 618; + long l619 = 619; + long l620 = 620; + long l621 = 621; + long l622 = 622; + long l623 = 623; + long l624 = 624; + long l625 = 625; + long l626 = 626; + long l627 = 627; + long l628 = 628; + long l629 = 629; + long l630 = 630; + long l631 = 631; + long l632 = 632; + long l633 = 633; + long l634 = 634; + long l635 = 635; + long l636 = 636; + long l637 = 637; + long l638 = 638; + long l639 = 639; + long l640 = 640; + long l641 = 641; + long l642 = 642; + long l643 = 643; + long l644 = 644; + long l645 = 645; + long l646 = 646; + long l647 = 647; + long l648 = 648; + long l649 = 649; + long l650 = 650; + long l651 = 651; + long l652 = 652; + long l653 = 653; + long l654 = 654; + long l655 = 655; + long l656 = 656; + long l657 = 657; + long l658 = 658; + long l659 = 659; + long l660 = 660; + long l661 = 661; + long l662 = 662; + long l663 = 663; + long l664 = 664; + long l665 = 665; + long l666 = 666; + long l667 = 667; + long l668 = 668; + long l669 = 669; + long l670 = 670; + long l671 = 671; + long l672 = 672; + long l673 = 673; + long l674 = 674; + long l675 = 675; + long l676 = 676; + long l677 = 677; + long l678 = 678; + long l679 = 679; + long l680 = 680; + long l681 = 681; + long l682 = 682; + long l683 = 683; + long l684 = 684; + long l685 = 685; + long l686 = 686; + long l687 = 687; + long l688 = 688; + long l689 = 689; + long l690 = 690; + long l691 = 691; + long l692 = 692; + long l693 = 693; + long l694 = 694; + long l695 = 695; + long l696 = 696; + long l697 = 697; + long l698 = 698; + long l699 = 699; + long l700 = 700; + long l701 = 701; + long l702 = 702; + long l703 = 703; + long l704 = 704; + long l705 = 705; + long l706 = 706; + long l707 = 707; + long l708 = 708; + long l709 = 709; + long l710 = 710; + long l711 = 711; + long l712 = 712; + long l713 = 713; + long l714 = 714; + long l715 = 715; + long l716 = 716; + long l717 = 717; + long l718 = 718; + long l719 = 719; + long l720 = 720; + long l721 = 721; + long l722 = 722; + long l723 = 723; + long l724 = 724; + long l725 = 725; + long l726 = 726; + long l727 = 727; + long l728 = 728; + long l729 = 729; + long l730 = 730; + long l731 = 731; + long l732 = 732; + long l733 = 733; + long l734 = 734; + long l735 = 735; + long l736 = 736; + long l737 = 737; + long l738 = 738; + long l739 = 739; + long l740 = 740; + long l741 = 741; + long l742 = 742; + long l743 = 743; + long l744 = 744; + long l745 = 745; + long l746 = 746; + long l747 = 747; + long l748 = 748; + long l749 = 749; + long l750 = 750; + long l751 = 751; + long l752 = 752; + long l753 = 753; + long l754 = 754; + long l755 = 755; + long l756 = 756; + long l757 = 757; + long l758 = 758; + long l759 = 759; + long l760 = 760; + long l761 = 761; + long l762 = 762; + long l763 = 763; + long l764 = 764; + long l765 = 765; + long l766 = 766; + long l767 = 767; + long l768 = 768; + long l769 = 769; + long l770 = 770; + long l771 = 771; + long l772 = 772; + long l773 = 773; + long l774 = 774; + long l775 = 775; + long l776 = 776; + long l777 = 777; + long l778 = 778; + long l779 = 779; + long l780 = 780; + long l781 = 781; + long l782 = 782; + long l783 = 783; + long l784 = 784; + long l785 = 785; + long l786 = 786; + long l787 = 787; + long l788 = 788; + long l789 = 789; + long l790 = 790; + long l791 = 791; + long l792 = 792; + long l793 = 793; + long l794 = 794; + long l795 = 795; + long l796 = 796; + long l797 = 797; + long l798 = 798; + long l799 = 799; + long l800 = 800; + long l801 = 801; + long l802 = 802; + long l803 = 803; + long l804 = 804; + long l805 = 805; + long l806 = 806; + long l807 = 807; + long l808 = 808; + long l809 = 809; + long l810 = 810; + long l811 = 811; + long l812 = 812; + long l813 = 813; + long l814 = 814; + long l815 = 815; + long l816 = 816; + long l817 = 817; + long l818 = 818; + long l819 = 819; + long l820 = 820; + long l821 = 821; + long l822 = 822; + long l823 = 823; + long l824 = 824; + long l825 = 825; + long l826 = 826; + long l827 = 827; + long l828 = 828; + long l829 = 829; + long l830 = 830; + long l831 = 831; + long l832 = 832; + long l833 = 833; + long l834 = 834; + long l835 = 835; + long l836 = 836; + long l837 = 837; + long l838 = 838; + long l839 = 839; + long l840 = 840; + long l841 = 841; + long l842 = 842; + long l843 = 843; + long l844 = 844; + long l845 = 845; + long l846 = 846; + long l847 = 847; + long l848 = 848; + long l849 = 849; + long l850 = 850; + long l851 = 851; + long l852 = 852; + long l853 = 853; + long l854 = 854; + long l855 = 855; + long l856 = 856; + long l857 = 857; + long l858 = 858; + long l859 = 859; + long l860 = 860; + long l861 = 861; + long l862 = 862; + long l863 = 863; + long l864 = 864; + long l865 = 865; + long l866 = 866; + long l867 = 867; + long l868 = 868; + long l869 = 869; + long l870 = 870; + long l871 = 871; + long l872 = 872; + long l873 = 873; + long l874 = 874; + long l875 = 875; + long l876 = 876; + long l877 = 877; + long l878 = 878; + long l879 = 879; + long l880 = 880; + long l881 = 881; + long l882 = 882; + long l883 = 883; + long l884 = 884; + long l885 = 885; + long l886 = 886; + long l887 = 887; + long l888 = 888; + long l889 = 889; + long l890 = 890; + long l891 = 891; + long l892 = 892; + long l893 = 893; + long l894 = 894; + long l895 = 895; + long l896 = 896; + long l897 = 897; + long l898 = 898; + long l899 = 899; + long l900 = 900; + long l901 = 901; + long l902 = 902; + long l903 = 903; + long l904 = 904; + long l905 = 905; + long l906 = 906; + long l907 = 907; + long l908 = 908; + long l909 = 909; + long l910 = 910; + long l911 = 911; + long l912 = 912; + long l913 = 913; + long l914 = 914; + long l915 = 915; + long l916 = 916; + long l917 = 917; + long l918 = 918; + long l919 = 919; + long l920 = 920; + long l921 = 921; + long l922 = 922; + long l923 = 923; + long l924 = 924; + long l925 = 925; + long l926 = 926; + long l927 = 927; + long l928 = 928; + long l929 = 929; + long l930 = 930; + long l931 = 931; + long l932 = 932; + long l933 = 933; + long l934 = 934; + long l935 = 935; + long l936 = 936; + long l937 = 937; + long l938 = 938; + long l939 = 939; + long l940 = 940; + long l941 = 941; + long l942 = 942; + long l943 = 943; + long l944 = 944; + long l945 = 945; + long l946 = 946; + long l947 = 947; + long l948 = 948; + long l949 = 949; + long l950 = 950; + long l951 = 951; + long l952 = 952; + long l953 = 953; + long l954 = 954; + long l955 = 955; + long l956 = 956; + long l957 = 957; + long l958 = 958; + long l959 = 959; + long l960 = 960; + long l961 = 961; + long l962 = 962; + long l963 = 963; + long l964 = 964; + long l965 = 965; + long l966 = 966; + long l967 = 967; + long l968 = 968; + long l969 = 969; + long l970 = 970; + long l971 = 971; + long l972 = 972; + long l973 = 973; + long l974 = 974; + long l975 = 975; + long l976 = 976; + long l977 = 977; + long l978 = 978; + long l979 = 979; + long l980 = 980; + long l981 = 981; + long l982 = 982; + long l983 = 983; + long l984 = 984; + long l985 = 985; + long l986 = 986; + long l987 = 987; + long l988 = 988; + long l989 = 989; + long l990 = 990; + long l991 = 991; + long l992 = 992; + long l993 = 993; + long l994 = 994; + long l995 = 995; + long l996 = 996; + long l997 = 997; + long l998 = 998; + long l999 = 999; + l1 += l0; + l2 += l1; + l3 += l2; + l4 += l3; + l5 += l4; + l6 += l5; + l7 += l6; + l8 += l7; + l9 += l8; + l10 += l9; + l11 += l10; + l12 += l11; + l13 += l12; + l14 += l13; + l15 += l14; + l16 += l15; + l17 += l16; + l18 += l17; + l19 += l18; + l20 += l19; + l21 += l20; + l22 += l21; + l23 += l22; + l24 += l23; + l25 += l24; + l26 += l25; + l27 += l26; + l28 += l27; + l29 += l28; + l30 += l29; + l31 += l30; + l32 += l31; + l33 += l32; + l34 += l33; + l35 += l34; + l36 += l35; + l37 += l36; + l38 += l37; + l39 += l38; + l40 += l39; + l41 += l40; + l42 += l41; + l43 += l42; + l44 += l43; + l45 += l44; + l46 += l45; + l47 += l46; + l48 += l47; + l49 += l48; + l50 += l49; + l51 += l50; + l52 += l51; + l53 += l52; + l54 += l53; + l55 += l54; + l56 += l55; + l57 += l56; + l58 += l57; + l59 += l58; + l60 += l59; + l61 += l60; + l62 += l61; + l63 += l62; + l64 += l63; + l65 += l64; + l66 += l65; + l67 += l66; + l68 += l67; + l69 += l68; + l70 += l69; + l71 += l70; + l72 += l71; + l73 += l72; + l74 += l73; + l75 += l74; + l76 += l75; + l77 += l76; + l78 += l77; + l79 += l78; + l80 += l79; + l81 += l80; + l82 += l81; + l83 += l82; + l84 += l83; + l85 += l84; + l86 += l85; + l87 += l86; + l88 += l87; + l89 += l88; + l90 += l89; + l91 += l90; + l92 += l91; + l93 += l92; + l94 += l93; + l95 += l94; + l96 += l95; + l97 += l96; + l98 += l97; + l99 += l98; + l100 += l99; + l101 += l100; + l102 += l101; + l103 += l102; + l104 += l103; + l105 += l104; + l106 += l105; + l107 += l106; + l108 += l107; + l109 += l108; + l110 += l109; + l111 += l110; + l112 += l111; + l113 += l112; + l114 += l113; + l115 += l114; + l116 += l115; + l117 += l116; + l118 += l117; + l119 += l118; + l120 += l119; + l121 += l120; + l122 += l121; + l123 += l122; + l124 += l123; + l125 += l124; + l126 += l125; + l127 += l126; + l128 += l127; + l129 += l128; + l130 += l129; + l131 += l130; + l132 += l131; + l133 += l132; + l134 += l133; + l135 += l134; + l136 += l135; + l137 += l136; + l138 += l137; + l139 += l138; + l140 += l139; + l141 += l140; + l142 += l141; + l143 += l142; + l144 += l143; + l145 += l144; + l146 += l145; + l147 += l146; + l148 += l147; + l149 += l148; + l150 += l149; + l151 += l150; + l152 += l151; + l153 += l152; + l154 += l153; + l155 += l154; + l156 += l155; + l157 += l156; + l158 += l157; + l159 += l158; + l160 += l159; + l161 += l160; + l162 += l161; + l163 += l162; + l164 += l163; + l165 += l164; + l166 += l165; + l167 += l166; + l168 += l167; + l169 += l168; + l170 += l169; + l171 += l170; + l172 += l171; + l173 += l172; + l174 += l173; + l175 += l174; + l176 += l175; + l177 += l176; + l178 += l177; + l179 += l178; + l180 += l179; + l181 += l180; + l182 += l181; + l183 += l182; + l184 += l183; + l185 += l184; + l186 += l185; + l187 += l186; + l188 += l187; + l189 += l188; + l190 += l189; + l191 += l190; + l192 += l191; + l193 += l192; + l194 += l193; + l195 += l194; + l196 += l195; + l197 += l196; + l198 += l197; + l199 += l198; + l200 += l199; + l201 += l200; + l202 += l201; + l203 += l202; + l204 += l203; + l205 += l204; + l206 += l205; + l207 += l206; + l208 += l207; + l209 += l208; + l210 += l209; + l211 += l210; + l212 += l211; + l213 += l212; + l214 += l213; + l215 += l214; + l216 += l215; + l217 += l216; + l218 += l217; + l219 += l218; + l220 += l219; + l221 += l220; + l222 += l221; + l223 += l222; + l224 += l223; + l225 += l224; + l226 += l225; + l227 += l226; + l228 += l227; + l229 += l228; + l230 += l229; + l231 += l230; + l232 += l231; + l233 += l232; + l234 += l233; + l235 += l234; + l236 += l235; + l237 += l236; + l238 += l237; + l239 += l238; + l240 += l239; + l241 += l240; + l242 += l241; + l243 += l242; + l244 += l243; + l245 += l244; + l246 += l245; + l247 += l246; + l248 += l247; + l249 += l248; + l250 += l249; + l251 += l250; + l252 += l251; + l253 += l252; + l254 += l253; + l255 += l254; + l256 += l255; + l257 += l256; + l258 += l257; + l259 += l258; + l260 += l259; + l261 += l260; + l262 += l261; + l263 += l262; + l264 += l263; + l265 += l264; + l266 += l265; + l267 += l266; + l268 += l267; + l269 += l268; + l270 += l269; + l271 += l270; + l272 += l271; + l273 += l272; + l274 += l273; + l275 += l274; + l276 += l275; + l277 += l276; + l278 += l277; + l279 += l278; + l280 += l279; + l281 += l280; + l282 += l281; + l283 += l282; + l284 += l283; + l285 += l284; + l286 += l285; + l287 += l286; + l288 += l287; + l289 += l288; + l290 += l289; + l291 += l290; + l292 += l291; + l293 += l292; + l294 += l293; + l295 += l294; + l296 += l295; + l297 += l296; + l298 += l297; + l299 += l298; + l300 += l299; + l301 += l300; + l302 += l301; + l303 += l302; + l304 += l303; + l305 += l304; + l306 += l305; + l307 += l306; + l308 += l307; + l309 += l308; + l310 += l309; + l311 += l310; + l312 += l311; + l313 += l312; + l314 += l313; + l315 += l314; + l316 += l315; + l317 += l316; + l318 += l317; + l319 += l318; + l320 += l319; + l321 += l320; + l322 += l321; + l323 += l322; + l324 += l323; + l325 += l324; + l326 += l325; + l327 += l326; + l328 += l327; + l329 += l328; + l330 += l329; + l331 += l330; + l332 += l331; + l333 += l332; + l334 += l333; + l335 += l334; + l336 += l335; + l337 += l336; + l338 += l337; + l339 += l338; + l340 += l339; + l341 += l340; + l342 += l341; + l343 += l342; + l344 += l343; + l345 += l344; + l346 += l345; + l347 += l346; + l348 += l347; + l349 += l348; + l350 += l349; + l351 += l350; + l352 += l351; + l353 += l352; + l354 += l353; + l355 += l354; + l356 += l355; + l357 += l356; + l358 += l357; + l359 += l358; + l360 += l359; + l361 += l360; + l362 += l361; + l363 += l362; + l364 += l363; + l365 += l364; + l366 += l365; + l367 += l366; + l368 += l367; + l369 += l368; + l370 += l369; + l371 += l370; + l372 += l371; + l373 += l372; + l374 += l373; + l375 += l374; + l376 += l375; + l377 += l376; + l378 += l377; + l379 += l378; + l380 += l379; + l381 += l380; + l382 += l381; + l383 += l382; + l384 += l383; + l385 += l384; + l386 += l385; + l387 += l386; + l388 += l387; + l389 += l388; + l390 += l389; + l391 += l390; + l392 += l391; + l393 += l392; + l394 += l393; + l395 += l394; + l396 += l395; + l397 += l396; + l398 += l397; + l399 += l398; + l400 += l399; + l401 += l400; + l402 += l401; + l403 += l402; + l404 += l403; + l405 += l404; + l406 += l405; + l407 += l406; + l408 += l407; + l409 += l408; + l410 += l409; + l411 += l410; + l412 += l411; + l413 += l412; + l414 += l413; + l415 += l414; + l416 += l415; + l417 += l416; + l418 += l417; + l419 += l418; + l420 += l419; + l421 += l420; + l422 += l421; + l423 += l422; + l424 += l423; + l425 += l424; + l426 += l425; + l427 += l426; + l428 += l427; + l429 += l428; + l430 += l429; + l431 += l430; + l432 += l431; + l433 += l432; + l434 += l433; + l435 += l434; + l436 += l435; + l437 += l436; + l438 += l437; + l439 += l438; + l440 += l439; + l441 += l440; + l442 += l441; + l443 += l442; + l444 += l443; + l445 += l444; + l446 += l445; + l447 += l446; + l448 += l447; + l449 += l448; + l450 += l449; + l451 += l450; + l452 += l451; + l453 += l452; + l454 += l453; + l455 += l454; + l456 += l455; + l457 += l456; + l458 += l457; + l459 += l458; + l460 += l459; + l461 += l460; + l462 += l461; + l463 += l462; + l464 += l463; + l465 += l464; + l466 += l465; + l467 += l466; + l468 += l467; + l469 += l468; + l470 += l469; + l471 += l470; + l472 += l471; + l473 += l472; + l474 += l473; + l475 += l474; + l476 += l475; + l477 += l476; + l478 += l477; + l479 += l478; + l480 += l479; + l481 += l480; + l482 += l481; + l483 += l482; + l484 += l483; + l485 += l484; + l486 += l485; + l487 += l486; + l488 += l487; + l489 += l488; + l490 += l489; + l491 += l490; + l492 += l491; + l493 += l492; + l494 += l493; + l495 += l494; + l496 += l495; + l497 += l496; + l498 += l497; + l499 += l498; + l500 += l499; + l501 += l500; + l502 += l501; + l503 += l502; + l504 += l503; + l505 += l504; + l506 += l505; + l507 += l506; + l508 += l507; + l509 += l508; + l510 += l509; + l511 += l510; + l512 += l511; + l513 += l512; + l514 += l513; + l515 += l514; + l516 += l515; + l517 += l516; + l518 += l517; + l519 += l518; + l520 += l519; + l521 += l520; + l522 += l521; + l523 += l522; + l524 += l523; + l525 += l524; + l526 += l525; + l527 += l526; + l528 += l527; + l529 += l528; + l530 += l529; + l531 += l530; + l532 += l531; + l533 += l532; + l534 += l533; + l535 += l534; + l536 += l535; + l537 += l536; + l538 += l537; + l539 += l538; + l540 += l539; + l541 += l540; + l542 += l541; + l543 += l542; + l544 += l543; + l545 += l544; + l546 += l545; + l547 += l546; + l548 += l547; + l549 += l548; + l550 += l549; + l551 += l550; + l552 += l551; + l553 += l552; + l554 += l553; + l555 += l554; + l556 += l555; + l557 += l556; + l558 += l557; + l559 += l558; + l560 += l559; + l561 += l560; + l562 += l561; + l563 += l562; + l564 += l563; + l565 += l564; + l566 += l565; + l567 += l566; + l568 += l567; + l569 += l568; + l570 += l569; + l571 += l570; + l572 += l571; + l573 += l572; + l574 += l573; + l575 += l574; + l576 += l575; + l577 += l576; + l578 += l577; + l579 += l578; + l580 += l579; + l581 += l580; + l582 += l581; + l583 += l582; + l584 += l583; + l585 += l584; + l586 += l585; + l587 += l586; + l588 += l587; + l589 += l588; + l590 += l589; + l591 += l590; + l592 += l591; + l593 += l592; + l594 += l593; + l595 += l594; + l596 += l595; + l597 += l596; + l598 += l597; + l599 += l598; + l600 += l599; + l601 += l600; + l602 += l601; + l603 += l602; + l604 += l603; + l605 += l604; + l606 += l605; + l607 += l606; + l608 += l607; + l609 += l608; + l610 += l609; + l611 += l610; + l612 += l611; + l613 += l612; + l614 += l613; + l615 += l614; + l616 += l615; + l617 += l616; + l618 += l617; + l619 += l618; + l620 += l619; + l621 += l620; + l622 += l621; + l623 += l622; + l624 += l623; + l625 += l624; + l626 += l625; + l627 += l626; + l628 += l627; + l629 += l628; + l630 += l629; + l631 += l630; + l632 += l631; + l633 += l632; + l634 += l633; + l635 += l634; + l636 += l635; + l637 += l636; + l638 += l637; + l639 += l638; + l640 += l639; + l641 += l640; + l642 += l641; + l643 += l642; + l644 += l643; + l645 += l644; + l646 += l645; + l647 += l646; + l648 += l647; + l649 += l648; + l650 += l649; + l651 += l650; + l652 += l651; + l653 += l652; + l654 += l653; + l655 += l654; + l656 += l655; + l657 += l656; + l658 += l657; + l659 += l658; + l660 += l659; + l661 += l660; + l662 += l661; + l663 += l662; + l664 += l663; + l665 += l664; + l666 += l665; + l667 += l666; + l668 += l667; + l669 += l668; + l670 += l669; + l671 += l670; + l672 += l671; + l673 += l672; + l674 += l673; + l675 += l674; + l676 += l675; + l677 += l676; + l678 += l677; + l679 += l678; + l680 += l679; + l681 += l680; + l682 += l681; + l683 += l682; + l684 += l683; + l685 += l684; + l686 += l685; + l687 += l686; + l688 += l687; + l689 += l688; + l690 += l689; + l691 += l690; + l692 += l691; + l693 += l692; + l694 += l693; + l695 += l694; + l696 += l695; + l697 += l696; + l698 += l697; + l699 += l698; + l700 += l699; + l701 += l700; + l702 += l701; + l703 += l702; + l704 += l703; + l705 += l704; + l706 += l705; + l707 += l706; + l708 += l707; + l709 += l708; + l710 += l709; + l711 += l710; + l712 += l711; + l713 += l712; + l714 += l713; + l715 += l714; + l716 += l715; + l717 += l716; + l718 += l717; + l719 += l718; + l720 += l719; + l721 += l720; + l722 += l721; + l723 += l722; + l724 += l723; + l725 += l724; + l726 += l725; + l727 += l726; + l728 += l727; + l729 += l728; + l730 += l729; + l731 += l730; + l732 += l731; + l733 += l732; + l734 += l733; + l735 += l734; + l736 += l735; + l737 += l736; + l738 += l737; + l739 += l738; + l740 += l739; + l741 += l740; + l742 += l741; + l743 += l742; + l744 += l743; + l745 += l744; + l746 += l745; + l747 += l746; + l748 += l747; + l749 += l748; + l750 += l749; + l751 += l750; + l752 += l751; + l753 += l752; + l754 += l753; + l755 += l754; + l756 += l755; + l757 += l756; + l758 += l757; + l759 += l758; + l760 += l759; + l761 += l760; + l762 += l761; + l763 += l762; + l764 += l763; + l765 += l764; + l766 += l765; + l767 += l766; + l768 += l767; + l769 += l768; + l770 += l769; + l771 += l770; + l772 += l771; + l773 += l772; + l774 += l773; + l775 += l774; + l776 += l775; + l777 += l776; + l778 += l777; + l779 += l778; + l780 += l779; + l781 += l780; + l782 += l781; + l783 += l782; + l784 += l783; + l785 += l784; + l786 += l785; + l787 += l786; + l788 += l787; + l789 += l788; + l790 += l789; + l791 += l790; + l792 += l791; + l793 += l792; + l794 += l793; + l795 += l794; + l796 += l795; + l797 += l796; + l798 += l797; + l799 += l798; + l800 += l799; + l801 += l800; + l802 += l801; + l803 += l802; + l804 += l803; + l805 += l804; + l806 += l805; + l807 += l806; + l808 += l807; + l809 += l808; + l810 += l809; + l811 += l810; + l812 += l811; + l813 += l812; + l814 += l813; + l815 += l814; + l816 += l815; + l817 += l816; + l818 += l817; + l819 += l818; + l820 += l819; + l821 += l820; + l822 += l821; + l823 += l822; + l824 += l823; + l825 += l824; + l826 += l825; + l827 += l826; + l828 += l827; + l829 += l828; + l830 += l829; + l831 += l830; + l832 += l831; + l833 += l832; + l834 += l833; + l835 += l834; + l836 += l835; + l837 += l836; + l838 += l837; + l839 += l838; + l840 += l839; + l841 += l840; + l842 += l841; + l843 += l842; + l844 += l843; + l845 += l844; + l846 += l845; + l847 += l846; + l848 += l847; + l849 += l848; + l850 += l849; + l851 += l850; + l852 += l851; + l853 += l852; + l854 += l853; + l855 += l854; + l856 += l855; + l857 += l856; + l858 += l857; + l859 += l858; + l860 += l859; + l861 += l860; + l862 += l861; + l863 += l862; + l864 += l863; + l865 += l864; + l866 += l865; + l867 += l866; + l868 += l867; + l869 += l868; + l870 += l869; + l871 += l870; + l872 += l871; + l873 += l872; + l874 += l873; + l875 += l874; + l876 += l875; + l877 += l876; + l878 += l877; + l879 += l878; + l880 += l879; + l881 += l880; + l882 += l881; + l883 += l882; + l884 += l883; + l885 += l884; + l886 += l885; + l887 += l886; + l888 += l887; + l889 += l888; + l890 += l889; + l891 += l890; + l892 += l891; + l893 += l892; + l894 += l893; + l895 += l894; + l896 += l895; + l897 += l896; + l898 += l897; + l899 += l898; + l900 += l899; + l901 += l900; + l902 += l901; + l903 += l902; + l904 += l903; + l905 += l904; + l906 += l905; + l907 += l906; + l908 += l907; + l909 += l908; + l910 += l909; + l911 += l910; + l912 += l911; + l913 += l912; + l914 += l913; + l915 += l914; + l916 += l915; + l917 += l916; + l918 += l917; + l919 += l918; + l920 += l919; + l921 += l920; + l922 += l921; + l923 += l922; + l924 += l923; + l925 += l924; + l926 += l925; + l927 += l926; + l928 += l927; + l929 += l928; + l930 += l929; + l931 += l930; + l932 += l931; + l933 += l932; + l934 += l933; + l935 += l934; + l936 += l935; + l937 += l936; + l938 += l937; + l939 += l938; + l940 += l939; + l941 += l940; + l942 += l941; + l943 += l942; + l944 += l943; + l945 += l944; + l946 += l945; + l947 += l946; + l948 += l947; + l949 += l948; + l950 += l949; + l951 += l950; + l952 += l951; + l953 += l952; + l954 += l953; + l955 += l954; + l956 += l955; + l957 += l956; + l958 += l957; + l959 += l958; + l960 += l959; + l961 += l960; + l962 += l961; + l963 += l962; + l964 += l963; + l965 += l964; + l966 += l965; + l967 += l966; + l968 += l967; + l969 += l968; + l970 += l969; + l971 += l970; + l972 += l971; + l973 += l972; + l974 += l973; + l975 += l974; + l976 += l975; + l977 += l976; + l978 += l977; + l979 += l978; + l980 += l979; + l981 += l980; + l982 += l981; + l983 += l982; + l984 += l983; + l985 += l984; + l986 += l985; + l987 += l986; + l988 += l987; + l989 += l988; + l990 += l989; + l991 += l990; + l992 += l991; + l993 += l992; + l994 += l993; + l995 += l994; + l996 += l995; + l997 += l996; + l998 += l997; + l999 += l998; + return l999; + } +} diff --git a/test/Android.libnativebridgetest.mk b/test/Android.libnativebridgetest.mk index 452278ac11..5a5f72584f 100644 --- a/test/Android.libnativebridgetest.mk +++ b/test/Android.libnativebridgetest.mk @@ -60,7 +60,7 @@ define build-libnativebridgetest else # host LOCAL_CLANG := $(ART_HOST_CLANG) LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS) - LOCAL_STATIC_LIBRARIES := libcutils + LOCAL_SHARED_LIBRARIES := libcutils LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -ldl -lpthread ifeq ($(HOST_OS),linux) LOCAL_LDLIBS += -lrt diff --git a/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java index 726a7a8fe3..7251ec5535 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java @@ -27,7 +27,7 @@ public class Arm64QuickBackendExecutor extends Executor { @Override public void execute(String programName) { StringBuilder commandBuilder = new StringBuilder(); - commandBuilder.append("dalvikvm64 "); + commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Quick "); if (device.noBootImageAvailable()) { commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate "); } diff --git a/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java index 611270b67e..7d226e89a3 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java @@ -27,7 +27,7 @@ public class ArmQuickBackendExecutor extends Executor { @Override public void execute(String programName) { StringBuilder commandBuilder = new StringBuilder(); - commandBuilder.append("dalvikvm32 "); + commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Quick "); if (device.noBootImageAvailable()) { commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate "); } diff --git a/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java index bebf27c51e..36e39c27e1 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java @@ -27,7 +27,7 @@ public class Mips64QuickBackendExecutor extends Executor { @Override public void execute(String programName) { StringBuilder commandBuilder = new StringBuilder(); - commandBuilder.append("dalvikvm64 "); + commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Quick "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); diff --git a/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java index a534866777..0ea166ba68 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java @@ -27,7 +27,7 @@ public class MipsQuickBackendExecutor extends Executor { @Override public void execute(String programName) { StringBuilder commandBuilder = new StringBuilder(); - commandBuilder.append("dalvikvm32 "); + commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Quick "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java index 4a68bdebaa..7e4a2f6976 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java @@ -28,7 +28,7 @@ public class X86QuickBackendExecutor extends Executor { @Override public void execute(String programName) { StringBuilder commandBuilder = new StringBuilder(); - commandBuilder.append("dalvikvm32 "); + commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Quick "); if (Options.executeOnHost) { commandBuilder.append(device.getHostExecutionFlags()).append(" "); } diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java index 9579b76521..995cba2ac8 100644 --- a/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java +++ b/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java @@ -27,7 +27,7 @@ public class X86_64QuickBackendExecutor extends Executor { @Override public void execute(String programName) { StringBuilder commandBuilder = new StringBuilder(); - commandBuilder.append("dalvikvm64 "); + commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Quick "); commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" "); commandBuilder.append(executeClass); executionResult = executeCommandWithTimeout(commandBuilder.toString(), true); |