Merge "Fix race with Heap::ClampGrowthLimit and GC"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 1a4c30c..f834a38 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -193,6 +193,9 @@
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 904f117..eaea031 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -79,6 +79,13 @@
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 1849e7e..03370db 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -142,7 +142,6 @@
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 @@
} 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 2386914..7497b17 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -94,20 +94,12 @@
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 @@
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() {
+ void push_back(const SrcMapElem& elem) {
if (!empty()) {
- std::sort(begin(), end());
- resize(std::unique(begin(), end()) - begin());
- shrink_to_fit();
+ // 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;
+ }
}
- return *this;
+ std::vector<SrcMapElem, Allocator>::push_back(elem);
}
- void DeltaFormat(const SrcMapElem& start, uint32_t highest_pc) {
- // Convert from abs values to deltas.
- 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;
- }
- }
- 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_;
+ // 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 @@
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 39725de..0acdd42 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -99,14 +99,16 @@
// 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 3e69878..c5ac4c1 100644
--- a/compiler/dex/quick/arm/assemble_arm.cc
+++ b/compiler/dex/quick/arm/assemble_arm.cc
@@ -1083,7 +1083,9 @@
#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 3081c9e..e6158c3 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -372,7 +372,6 @@
* 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 @@
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 a59deb5..2f1ae66 100644
--- a/compiler/dex/quick/arm64/assemble_arm64.cc
+++ b/compiler/dex/quick/arm64/assemble_arm64.cc
@@ -686,7 +686,9 @@
#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 3316945..6b47bba 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -312,8 +312,6 @@
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 @@
*/
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 509d448..483a5d0 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -203,12 +203,17 @@
/* 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 @@
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 @@
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 @@
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 de66b35..c932df6 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -275,7 +275,6 @@
*/
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 @@
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 0b480a0..ed8e21e 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -1250,10 +1250,14 @@
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 e81228a..fd23692 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 @@
stack_decrement_ = OpRegImm(kOpSub, rs_rSP, frame_size_ -
GetInstructionSetPointerSize(cu_->instruction_set));
- NewLIR0(kPseudoMethodEntry);
/* Spill core callee saves */
SpillCoreRegs();
SpillFPRegs();
@@ -259,7 +259,6 @@
LockTemp(rs_rX86_RET0);
LockTemp(rs_rX86_RET1);
- NewLIR0(kPseudoMethodExit);
UnSpillCoreRegs();
UnSpillFPRegs();
/* Remove frame except for return address */
@@ -322,13 +321,13 @@
* 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 @@
default:
return -1;
}
+ } else if (cg->CanUseOpPcRelDexCacheArrayLoad()) {
+ switch (state) {
+ case 0: {
+ CHECK_EQ(cu->dex_file, target_method.dex_file);
+ size_t offset = cg->dex_cache_arrays_layout_.MethodOffset(target_method.dex_method_index);
+ cg->OpPcRelDexCacheArrayLoad(cu->dex_file, offset, cg->TargetReg(kArg0, kRef));
+ break;
+ }
+ default:
+ return -1;
+ }
} else {
RegStorage arg0_ref = cg->TargetReg(kArg0, kRef);
switch (state) {
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 040a8c4..758684e 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -104,6 +104,9 @@
/// @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 @@
// 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 @@
void SwapBits(RegStorage result_reg, int shift, int32_t value);
void SwapBits64(RegStorage result_reg, int shift, int64_t value);
+ static int X86NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
+ int state, const MethodReference& target_method,
+ uint32_t,
+ uintptr_t direct_code, uintptr_t direct_method,
+ InvokeType type);
+
static const X86EncodingMap EncodingMap[kX86Last];
friend std::ostream& operator<<(std::ostream& os, const X86OpCode& rhs);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 4eb626c..5def5c8 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1324,14 +1324,16 @@
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 @@
store_method_addr_used_ = true;
// Load the proper value from the literal area.
- // We don't know the proper offset for the value, so pick one that will force
- // 4 byte offset. We will fix this up in the assembler later to have the right
- // value.
ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
- LIR* res = NewLIR3(kX86Mov32RM, reg.GetReg(), reg.GetReg(), 256);
+ LIR* res = NewLIR3(kX86Mov32RM, reg.GetReg(), reg.GetReg(), kDummy32BitOffset);
res->target = target;
res->flags.fixup = kFixupLoad;
}
+bool X86Mir2Lir::CanUseOpPcRelDexCacheArrayLoad() const {
+ // TODO: Implement for 32-bit.
+ return cu_->target64 && dex_cache_arrays_layout_.Valid();
+}
+
+void X86Mir2Lir::OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset,
+ RegStorage r_dest) {
+ if (cu_->target64) {
+ LIR* mov = NewLIR3(kX86Mov32RM, r_dest.GetReg(), kRIPReg, kDummy32BitOffset);
+ mov->flags.fixup = kFixupLabel;
+ mov->operands[3] = WrapPointer(dex_file);
+ mov->operands[4] = offset;
+ dex_cache_access_insns_.push_back(mov);
+ } else {
+ // TODO: Implement for 32-bit.
+ LOG(FATAL) << "Unimplemented.";
+ UNREACHABLE();
+ }
+}
+
LIR* X86Mir2Lir::OpVldm(RegStorage r_base, int count) {
UNUSED(r_base, count);
LOG(FATAL) << "Unexpected use of OpVldm for x86";
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index f128eb7..cad82a1 100755
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -829,6 +829,7 @@
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 @@
}
}
+ 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 @@
}
// 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 @@
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 e436f52..fc00c92 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -42,6 +42,11 @@
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 d06ec27..f7ea385 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -53,6 +53,7 @@
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 ca5ec66..a92ce69 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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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;
- 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
- }
+ 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;
}
- 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);
+ dwarf::DebugLineOpCodeWriter<> opcodes(use_64bit_addresses, code_factor_bits_);
+ opcodes.SetAddress(text_section_offset + cunit_low_pc);
+ if (isa != -1) {
+ opcodes.SetISA(isa);
+ }
+ DefaultSrcMap dex2line_map;
+ for (size_t i = 0; i < method_infos.size(); i++) {
+ const OatWriter::DebugInfo& method_info = method_infos[i];
- // 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);
+ // Addresses in the line table should be unique and increasing.
+ if (method_info.deduped_) {
+ continue;
+ }
- 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;
+ // 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);
- 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_);
+ // 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;
}
- pc2java_map.clear();
+
+ // 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;
+ }
+ }
+ 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 @@
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 0000000..2eae2a8
--- /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 0000000..35a8b8e
--- /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 0000000..4267743
--- /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 0000000..5611303
--- /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 0000000..abdfd6d
--- /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 0000000..b61b3d8
--- /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 0000000..b2a1da5
--- /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 0000000..71f38b4
--- /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 0000000..7a78254
--- /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 0000000..9efcf60
--- /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 0000000..246cf11
--- /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 0000000..0c881f0
--- /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 0000000..ea3472d
--- /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 0000000..1f38cf2
--- /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 0000000..c18a743
--- /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 0000000..598f3ac
--- /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 0000000..af687b4
--- /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 0000000..9d9529c
--- /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 04f0db6..19013cf 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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
}
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 @@
#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 @@
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 676d628..c472000 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 @@
~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 @@
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 @@
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 dde5407..c0e7f47 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -471,7 +471,7 @@
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 7daa5f1..b491f47 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 @@
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 3490bcf..bc5cf9b 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1665,7 +1665,6 @@
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 @@
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 @@
};
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 @@
// 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 @@
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 46545b8..81896ab 100644
--- a/test/421-large-frame/src/Main.java
+++ b/test/421-large-frame/src/Main.java
@@ -28,8 +28,6 @@
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 @@
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 0000000..e69de29
--- /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 0000000..6074505
--- /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 0000000..cd42561
--- /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 452278a..5a5f725 100644
--- a/test/Android.libnativebridgetest.mk
+++ b/test/Android.libnativebridgetest.mk
@@ -60,7 +60,7 @@
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 726a7a8f..7251ec5 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java
@@ -27,7 +27,7 @@
@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 611270b..7d226e8 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java
@@ -27,7 +27,7 @@
@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 bebf27c..36e39c2 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java
@@ -27,7 +27,7 @@
@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 a534866..0ea166b 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java
@@ -27,7 +27,7 @@
@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 4a68bde..7e4a2f6 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java
@@ -28,7 +28,7 @@
@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 9579b76..995cba2 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java
@@ -27,7 +27,7 @@
@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);