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(&current_method_thunks_, thunks_code_offset, adrp);
+      SetInsn(&current_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(&current_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(&current_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(&current_method_thunks_, thunks_code_offset, adrp);
-        SetInsn(&current_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(&current_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);