Merge "ART: Do not recursively abort when visiting locks in a bad state"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index dd9f414..de0e3bd 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -117,7 +117,6 @@
   runtime/monitor_pool_test.cc \
   runtime/monitor_test.cc \
   runtime/parsed_options_test.cc \
-  runtime/proxy_test.cc \
   runtime/reference_table_test.cc \
   runtime/thread_pool_test.cc \
   runtime/transaction_test.cc \
@@ -128,6 +127,7 @@
 
 COMPILER_GTEST_COMMON_SRC_FILES := \
   runtime/jni_internal_test.cc \
+  runtime/proxy_test.cc \
   runtime/reflection_test.cc \
   compiler/dex/global_value_numbering_test.cc \
   compiler/dex/local_value_numbering_test.cc \
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index f2a8d84..f9a78be 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -148,16 +148,18 @@
                                const size_t frame_size_in_bytes,
                                const uint32_t core_spill_mask,
                                const uint32_t fp_spill_mask,
+                               SrcMap* src_mapping_table,
                                const std::vector<uint8_t>& mapping_table,
                                const std::vector<uint8_t>& vmap_table,
                                const std::vector<uint8_t>& native_gc_map,
                                const std::vector<uint8_t>* cfi_info)
     : CompiledCode(driver, instruction_set, quick_code), frame_size_in_bytes_(frame_size_in_bytes),
       core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
-  mapping_table_(driver->DeduplicateMappingTable(mapping_table)),
-  vmap_table_(driver->DeduplicateVMapTable(vmap_table)),
-  gc_map_(driver->DeduplicateGCMap(native_gc_map)),
-  cfi_info_(driver->DeduplicateCFIInfo(cfi_info)) {
+      src_mapping_table_(driver->DeduplicateSrcMappingTable(src_mapping_table->Arrange())),
+      mapping_table_(driver->DeduplicateMappingTable(mapping_table)),
+      vmap_table_(driver->DeduplicateVMapTable(vmap_table)),
+      gc_map_(driver->DeduplicateGCMap(native_gc_map)),
+      cfi_info_(driver->DeduplicateCFIInfo(cfi_info)) {
 }
 
 CompiledMethod::CompiledMethod(CompilerDriver* driver,
@@ -170,6 +172,7 @@
     : CompiledCode(driver, instruction_set, code),
       frame_size_in_bytes_(frame_size_in_bytes),
       core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
+      src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())),
       mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())),
       vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())),
       gc_map_(driver->DeduplicateGCMap(std::vector<uint8_t>())),
@@ -182,19 +185,22 @@
                                const std::string& symbol)
     : CompiledCode(driver, instruction_set, code, symbol),
       frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0),
-      fp_spill_mask_(0), gc_map_(driver->DeduplicateGCMap(gc_map)) {
-  mapping_table_ = driver->DeduplicateMappingTable(std::vector<uint8_t>());
-  vmap_table_ = driver->DeduplicateVMapTable(std::vector<uint8_t>());
+      fp_spill_mask_(0),
+      src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())),
+      mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())),
+      vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())),
+      gc_map_(driver->DeduplicateGCMap(gc_map)) {
 }
 
 CompiledMethod::CompiledMethod(CompilerDriver* driver, InstructionSet instruction_set,
                                const std::string& code, const std::string& symbol)
     : CompiledCode(driver, instruction_set, code, symbol),
       frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0),
-      fp_spill_mask_(0) {
-  mapping_table_ = driver->DeduplicateMappingTable(std::vector<uint8_t>());
-  vmap_table_ = driver->DeduplicateVMapTable(std::vector<uint8_t>());
-  gc_map_ = driver->DeduplicateGCMap(std::vector<uint8_t>());
+      fp_spill_mask_(0),
+      src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())),
+      mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())),
+      vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())),
+      gc_map_(driver->DeduplicateGCMap(std::vector<uint8_t>())) {
 }
 
 }  // namespace art
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index c98d06a..d02cbff 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -100,7 +100,97 @@
   std::vector<uint32_t> oatdata_offsets_to_compiled_code_offset_;
 };
 
-class CompiledMethod : public CompiledCode {
+class SrcMapElem {
+ public:
+  uint32_t from_;
+  int32_t to_;
+
+  bool operator<(const SrcMapElem& sme) const {
+    uint64_t lhs = (static_cast<uint64_t>(from_) << 32) + to_;
+    uint64_t rhs = (static_cast<uint64_t>(sme.from_) << 32) + sme.to_;
+    return lhs < rhs;
+  }
+
+  operator uint8_t() const {
+    return static_cast<uint8_t>(from_ + to_);
+  }
+};
+
+class SrcMap FINAL : public std::vector<SrcMapElem> {
+ public:
+  struct CompareByTo {
+    bool operator()(const SrcMapElem& lhs, const SrcMapElem& rhs) {
+      return lhs.to_ < rhs.to_;
+    }
+  };
+
+  struct CompareByFrom {
+    bool operator()(const SrcMapElem& lhs, const SrcMapElem& rhs) {
+      return lhs.from_ < rhs.from_;
+    }
+  };
+
+  void SortByTo() {
+    std::sort(begin(), end(), CompareByTo());
+  }
+
+  void SortByFrom() {
+    std::sort(begin(), end(), CompareByFrom());
+  }
+
+  const_iterator FindByTo(int32_t to) const {
+    return std::lower_bound(begin(), end(), SrcMapElem({0, to}), CompareByTo());
+  }
+
+  SrcMap& Arrange() {
+    SortByTo();
+
+    // Remove duplicate pairs.
+    if (!empty()) {
+      SrcMap tmp;
+      tmp.swap(*this);
+      iterator it = tmp.begin();
+      iterator prev = it;
+      it++;
+      push_back(*prev);
+      for (; it != tmp.end(); it++) {
+        if (prev->from_ != it->from_ || prev->to_ != it->to_) {
+          push_back(*(prev = it));
+        }
+      }
+    }
+    return *this;
+  }
+
+  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 (size_t 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_;
+    }
+  }
+};
+
+class CompiledMethod FINAL : public CompiledCode {
  public:
   // Constructs a CompiledMethod for the non-LLVM compilers.
   CompiledMethod(CompilerDriver* driver,
@@ -109,6 +199,7 @@
                  const size_t frame_size_in_bytes,
                  const uint32_t core_spill_mask,
                  const uint32_t fp_spill_mask,
+                 SrcMap* src_mapping_table,
                  const std::vector<uint8_t>& mapping_table,
                  const std::vector<uint8_t>& vmap_table,
                  const std::vector<uint8_t>& native_gc_map,
@@ -145,6 +236,11 @@
     return fp_spill_mask_;
   }
 
+  const SrcMap& GetSrcMappingTable() const {
+    DCHECK(src_mapping_table_ != nullptr);
+    return *src_mapping_table_;
+  }
+
   const std::vector<uint8_t>& GetMappingTable() const {
     DCHECK(mapping_table_ != nullptr);
     return *mapping_table_;
@@ -171,6 +267,8 @@
   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
+  SrcMap* 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.
   std::vector<uint8_t>* mapping_table_;
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index be79b63..ebebe70 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -15,6 +15,7 @@
  */
 
 #include "dex/compiler_internals.h"
+#include "driver/compiler_options.h"
 #include "dex_file-inl.h"
 #include "gc_map.h"
 #include "gc_map_builder.h"
@@ -648,15 +649,19 @@
 
 
 void Mir2Lir::CreateMappingTables() {
+  bool generate_src_map = cu_->compiler_driver->GetCompilerOptions().GetIncludeDebugSymbols();
+
   uint32_t pc2dex_data_size = 0u;
   uint32_t pc2dex_entries = 0u;
   uint32_t pc2dex_offset = 0u;
   uint32_t pc2dex_dalvik_offset = 0u;
+  uint32_t pc2dex_src_entries = 0u;
   uint32_t dex2pc_data_size = 0u;
   uint32_t dex2pc_entries = 0u;
   uint32_t dex2pc_offset = 0u;
   uint32_t dex2pc_dalvik_offset = 0u;
   for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
+    pc2dex_src_entries++;
     if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
       pc2dex_entries += 1;
       DCHECK(pc2dex_offset <= tgt_lir->offset);
@@ -677,6 +682,10 @@
     }
   }
 
+  if (generate_src_map) {
+    src_mapping_table_.reserve(pc2dex_src_entries);
+  }
+
   uint32_t total_entries = pc2dex_entries + dex2pc_entries;
   uint32_t hdr_data_size = UnsignedLeb128Size(total_entries) + UnsignedLeb128Size(pc2dex_entries);
   uint32_t data_size = hdr_data_size + pc2dex_data_size + dex2pc_data_size;
@@ -692,6 +701,10 @@
   dex2pc_offset = 0u;
   dex2pc_dalvik_offset = 0u;
   for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; 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 (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
       DCHECK(pc2dex_offset <= tgt_lir->offset);
       write_pos = EncodeUnsignedLeb128(write_pos, tgt_lir->offset - pc2dex_offset);
@@ -1088,7 +1101,7 @@
   std::unique_ptr<std::vector<uint8_t>> cfi_info(ReturnFrameDescriptionEntry());
   CompiledMethod* result =
       new CompiledMethod(cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_,
-                         core_spill_mask_, fp_spill_mask_, encoded_mapping_table_,
+                         core_spill_mask_, fp_spill_mask_, &src_mapping_table_, encoded_mapping_table_,
                          vmap_encoder.GetData(), native_gc_map_, cfi_info.get());
   return result;
 }
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 4b8f794..573bd91 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1715,6 +1715,8 @@
      */
     int live_sreg_;
     CodeBuffer code_buffer_;
+    // The source mapping table data (pc -> dex). More entries than in encoded_mapping_table_
+    SrcMap src_mapping_table_;
     // The encoding mapping table data (dex -> pc offset and pc offset -> dex) with a size prefix.
     std::vector<uint8_t> encoded_mapping_table_;
     ArenaVector<uint32_t> core_vmap_table_;
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index 93b7999..6173163 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -263,8 +263,10 @@
 
   { kX86Cmc, kNullary, NO_OPERAND, { 0, 0, 0xF5, 0, 0, 0, 0, 0, false }, "Cmc", "" },
   { kX86Shld32RRI,  kRegRegImmStore, IS_TERTIARY_OP | REG_DEF0_USE01  | SETS_CCODES,            { 0,    0, 0x0F, 0xA4, 0, 0, 0, 1, false }, "Shld32RRI", "!0r,!1r,!2d" },
+  { kX86Shld32RRC,  kShiftRegRegCl,  IS_TERTIARY_OP | REG_DEF0_USE01  | REG_USEC | SETS_CCODES, { 0,    0, 0x0F, 0xA5, 0, 0, 0, 0, false }, "Shld32RRC", "!0r,!1r,cl" },
   { kX86Shld32MRI,  kMemRegImm,      IS_QUAD_OP | REG_USE02 | IS_LOAD | IS_STORE | SETS_CCODES, { 0,    0, 0x0F, 0xA4, 0, 0, 0, 1, false }, "Shld32MRI", "[!0r+!1d],!2r,!3d" },
   { kX86Shrd32RRI,  kRegRegImmStore, IS_TERTIARY_OP | REG_DEF0_USE01  | SETS_CCODES,            { 0,    0, 0x0F, 0xAC, 0, 0, 0, 1, false }, "Shrd32RRI", "!0r,!1r,!2d" },
+  { kX86Shrd32RRC,  kShiftRegRegCl,  IS_TERTIARY_OP | REG_DEF0_USE01  | REG_USEC | SETS_CCODES, { 0,    0, 0x0F, 0xAD, 0, 0, 0, 0, false }, "Shrd32RRC", "!0r,!1r,cl" },
   { kX86Shrd32MRI,  kMemRegImm,      IS_QUAD_OP | REG_USE02 | IS_LOAD | IS_STORE | SETS_CCODES, { 0,    0, 0x0F, 0xAC, 0, 0, 0, 1, false }, "Shrd32MRI", "[!0r+!1d],!2r,!3d" },
   { kX86Shld64RRI,  kRegRegImmStore, IS_TERTIARY_OP | REG_DEF0_USE01  | SETS_CCODES,            { REX_W,    0, 0x0F, 0xA4, 0, 0, 0, 1, false }, "Shld64RRI", "!0r,!1r,!2d" },
   { kX86Shld64MRI,  kMemRegImm,      IS_QUAD_OP | REG_USE02 | IS_LOAD | IS_STORE | SETS_CCODES, { REX_W,    0, 0x0F, 0xA4, 0, 0, 0, 1, false }, "Shld64MRI", "[!0r+!1d],!2r,!3d" },
@@ -591,6 +593,7 @@
     case kShiftRegCl: return true;
     case kRegCond: return true;
     case kRegRegCond: return true;
+    case kShiftRegRegCl: return true;
     case kJmp:
       switch (entry->opcode) {
         case kX86JmpR: return true;
@@ -768,6 +771,9 @@
       DCHECK_EQ(rs_rCX.GetRegNum(), RegStorage::RegNum(lir->operands[4]));
       return ComputeSize(entry, lir->operands[4], lir->operands[1], lir->operands[0],
                          lir->operands[3]);
+    case kShiftRegRegCl:  // lir operands - 0: reg1, 1: reg2, 2: cl
+      DCHECK_EQ(rs_rCX.GetRegNum(), RegStorage::RegNum(lir->operands[2]));
+      return ComputeSize(entry, lir->operands[0], NO_REG, lir->operands[1], 0);
     case kRegCond:  // lir operands - 0: reg, 1: cond
       return ComputeSize(entry, NO_REG, NO_REG, lir->operands[0], 0);
     case kMemCond:  // lir operands - 0: base, 1: disp, 2: cond
@@ -1336,6 +1342,19 @@
   DCHECK_EQ(0, entry->skeleton.immediate_bytes);
 }
 
+void X86Mir2Lir::EmitShiftRegRegCl(const X86EncodingMap* entry, int32_t raw_reg1, int32_t raw_reg2, int32_t raw_cl) {
+  DCHECK_EQ(false, entry->skeleton.r8_form);
+  DCHECK_EQ(rs_rCX.GetRegNum(), RegStorage::RegNum(raw_cl));
+  EmitPrefixAndOpcode(entry, raw_reg1, NO_REG, raw_reg2);
+  uint8_t low_reg1 = LowRegisterBits(raw_reg1);
+  uint8_t low_reg2 = LowRegisterBits(raw_reg2);
+  uint8_t modrm = (3 << 6) | (low_reg1 << 3) | low_reg2;
+  code_buffer_.push_back(modrm);
+  DCHECK_EQ(0, entry->skeleton.modrm_opcode);
+  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
+}
+
 void X86Mir2Lir::EmitShiftMemImm(const X86EncodingMap* entry, int32_t raw_base, int32_t disp,
                                  int32_t imm) {
   DCHECK_EQ(false, entry->skeleton.r8_form);
@@ -1829,6 +1848,9 @@
       case kShiftMemCl:  // lir operands - 0: base, 1:displacement, 2: cl
         EmitShiftMemCl(entry, lir->operands[0], lir->operands[1], lir->operands[2]);
         break;
+      case kShiftRegRegCl:  // lir operands - 0: reg1, 1: reg2, 2: cl
+        EmitShiftRegRegCl(entry, lir->operands[1], lir->operands[0], lir->operands[2]);
+        break;
       case kRegCond:  // lir operands - 0: reg, 1: condition
         EmitRegCond(entry, lir->operands[0], lir->operands[1]);
         break;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 1f5b350..7d1e20e 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -457,6 +457,8 @@
   void EmitShiftRegImm(const X86EncodingMap* entry, int32_t raw_reg, int32_t imm);
   void EmitShiftRegCl(const X86EncodingMap* entry, int32_t raw_reg, int32_t raw_cl);
   void EmitShiftMemCl(const X86EncodingMap* entry, int32_t raw_base, int32_t disp, int32_t raw_cl);
+  void EmitShiftRegRegCl(const X86EncodingMap* entry, int32_t raw_reg1, int32_t raw_reg2,
+                         int32_t raw_cl);
   void EmitShiftMemImm(const X86EncodingMap* entry, int32_t raw_base, int32_t disp, int32_t imm);
   void EmitRegCond(const X86EncodingMap* entry, int32_t raw_reg, int32_t cc);
   void EmitMemCond(const X86EncodingMap* entry, int32_t raw_base, int32_t disp, int32_t cc);
@@ -478,8 +480,10 @@
   void GenConstWide(RegLocation rl_dest, int64_t value);
   void GenMultiplyVectorSignedByte(BasicBlock *bb, MIR *mir);
   void GenShiftByteVector(BasicBlock *bb, MIR *mir);
-  void AndMaskVectorRegister(RegStorage rs_src1, uint32_t m1, uint32_t m2, uint32_t m3, uint32_t m4);
-  void MaskVectorRegister(X86OpCode opcode, RegStorage rs_src1, uint32_t m1, uint32_t m2, uint32_t m3, uint32_t m4);
+  void AndMaskVectorRegister(RegStorage rs_src1, uint32_t m1, uint32_t m2, uint32_t m3,
+                             uint32_t m4);
+  void MaskVectorRegister(X86OpCode opcode, RegStorage rs_src1, uint32_t m1, uint32_t m2,
+                          uint32_t m3, uint32_t m4);
   void AppendOpcodeWithConst(X86OpCode opcode, int reg, MIR* mir);
 
   static bool ProvidesFullMemoryBarrier(X86OpCode opcode);
@@ -551,7 +555,8 @@
   void GenMoveVector(BasicBlock *bb, MIR *mir);
 
   /*
-   * @brief Packed multiply of units in two vector registers: vB = vB .* @note vC using vA to know the type of the vector.
+   * @brief Packed multiply of units in two vector registers: vB = vB .* @note vC using vA to know
+   * the type of the vector.
    * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
@@ -561,7 +566,8 @@
   void GenMultiplyVector(BasicBlock *bb, MIR *mir);
 
   /*
-   * @brief Packed addition of units in two vector registers: vB = vB .+ vC using vA to know the type of the vector.
+   * @brief Packed addition of units in two vector registers: vB = vB .+ vC using vA to know the
+   * type of the vector.
    * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
@@ -571,7 +577,8 @@
   void GenAddVector(BasicBlock *bb, MIR *mir);
 
   /*
-   * @brief Packed subtraction of units in two vector registers: vB = vB .- vC using vA to know the type of the vector.
+   * @brief Packed subtraction of units in two vector registers: vB = vB .- vC using vA to know the
+   * type of the vector.
    * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
@@ -581,7 +588,8 @@
   void GenSubtractVector(BasicBlock *bb, MIR *mir);
 
   /*
-   * @brief Packed shift left of units in two vector registers: vB = vB .<< vC using vA to know the type of the vector.
+   * @brief Packed shift left of units in two vector registers: vB = vB .<< vC using vA to know the
+   * type of the vector.
    * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
@@ -591,7 +599,8 @@
   void GenShiftLeftVector(BasicBlock *bb, MIR *mir);
 
   /*
-   * @brief Packed signed shift right of units in two vector registers: vB = vB .>> vC using vA to know the type of the vector.
+   * @brief Packed signed shift right of units in two vector registers: vB = vB .>> vC using vA to
+   * know the type of the vector.
    * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
@@ -601,7 +610,8 @@
   void GenSignedShiftRightVector(BasicBlock *bb, MIR *mir);
 
   /*
-   * @brief Packed unsigned shift right of units in two vector registers: vB = vB .>>> vC using vA to know the type of the vector.
+   * @brief Packed unsigned shift right of units in two vector registers: vB = vB .>>> vC using vA
+   * to know the type of the vector.
    * @param bb The basic block in which the MIR is from..
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
@@ -611,7 +621,8 @@
   void GenUnsignedShiftRightVector(BasicBlock *bb, MIR *mir);
 
   /*
-   * @brief Packed bitwise and of units in two vector registers: vB = vB .& vC using vA to know the type of the vector.
+   * @brief Packed bitwise and of units in two vector registers: vB = vB .& vC using vA to know the
+   * type of the vector.
    * @note vA: TypeSize
    * @note vB: destination and source
    * @note vC: source
@@ -619,7 +630,8 @@
   void GenAndVector(BasicBlock *bb, MIR *mir);
 
   /*
-   * @brief Packed bitwise or of units in two vector registers: vB = vB .| vC using vA to know the type of the vector.
+   * @brief Packed bitwise or of units in two vector registers: vB = vB .| vC using vA to know the
+   * type of the vector.
    * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
@@ -629,7 +641,8 @@
   void GenOrVector(BasicBlock *bb, MIR *mir);
 
   /*
-   * @brief Packed bitwise xor of units in two vector registers: vB = vB .^ vC using vA to know the type of the vector.
+   * @brief Packed bitwise xor of units in two vector registers: vB = vB .^ vC using vA to know the
+   * type of the vector.
    * @param bb The basic block in which the MIR is from.
    * @param mir The MIR whose opcode is kMirConstVector.
    * @note vA: TypeSize
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index afa2ae2..cc51538 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -793,8 +793,115 @@
 bool X86Mir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
   DCHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64);
 
-  if (is_long && cu_->instruction_set == kX86) {
-    return false;
+  if (is_long && !cu_->target64) {
+   /*
+    * We want to implement the following algorithm
+    * mov eax, low part of arg1
+    * mov edx, high part of arg1
+    * mov ebx, low part of arg2
+    * mov ecx, high part of arg2
+    * mov edi, eax
+    * sub edi, ebx
+    * mov edi, edx
+    * sbb edi, ecx
+    * is_min ? "cmovgel eax, ebx" : "cmovll eax, ebx"
+    * is_min ? "cmovgel edx, ecx" : "cmovll edx, ecx"
+    *
+    * The algorithm above needs 5 registers: a pair for the first operand
+    * (which later will be used as result), a pair for the second operand
+    * and a temp register (e.g. 'edi') for intermediate calculations.
+    * Ideally we have 6 GP caller-save registers in 32-bit mode. They are:
+    * 'eax', 'ebx', 'ecx', 'edx', 'esi' and 'edi'. So there should be
+    * always enough registers to operate on. Practically, there is a pair
+    * of registers 'edi' and 'esi' which holds promoted values and
+    * sometimes should be treated as 'callee save'. If one of the operands
+    * is in the promoted registers then we have enough register to
+    * operate on. Otherwise there is lack of resources and we have to
+    * save 'edi' before calculations and restore after.
+    */
+
+    RegLocation rl_src1 = info->args[0];
+    RegLocation rl_src2 = info->args[2];
+    RegLocation rl_dest = InlineTargetWide(info);
+    int res_vreg, src1_vreg, src2_vreg;
+
+    /*
+     * If the result register is the same as the second element, then we
+     * need to be careful. The reason is that the first copy will
+     * inadvertently clobber the second element with the first one thus
+     * yielding the wrong result. Thus we do a swap in that case.
+     */
+    res_vreg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
+    src2_vreg = mir_graph_->SRegToVReg(rl_src2.s_reg_low);
+    if (res_vreg == src2_vreg) {
+      std::swap(rl_src1, rl_src2);
+    }
+
+    rl_src1 = LoadValueWide(rl_src1, kCoreReg);
+    RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+
+    // Pick the first integer as min/max.
+    OpRegCopyWide(rl_result.reg, rl_src1.reg);
+
+    /*
+     * If the integers are both in the same register, then there is
+     * nothing else to do because they are equal and we have already
+     * moved one into the result.
+     */
+    src1_vreg = mir_graph_->SRegToVReg(rl_src1.s_reg_low);
+    src2_vreg = mir_graph_->SRegToVReg(rl_src2.s_reg_low);
+    if (src1_vreg == src2_vreg) {
+      StoreValueWide(rl_dest, rl_result);
+      return true;
+    }
+
+    // Free registers to make some room for the second operand.
+    // But don't try to free ourselves or promoted registers.
+    if (res_vreg != src1_vreg &&
+        IsTemp(rl_src1.reg.GetLow()) && IsTemp(rl_src1.reg.GetHigh())) {
+      FreeTemp(rl_src1.reg);
+    }
+    rl_src2 = LoadValueWide(rl_src2, kCoreReg);
+
+    // Do we have a free register for intermediate calculations?
+    RegStorage tmp = AllocTemp(false);
+    if (tmp == RegStorage::InvalidReg()) {
+       /*
+        * No, will use 'edi'.
+        *
+        * As mentioned above we have 4 temporary and 2 promotable
+        * caller-save registers. Therefore, we assume that a free
+        * register can be allocated only if 'esi' and 'edi' are
+        * already used as operands. If number of promotable registers
+        * increases from 2 to 4 then our assumption fails and operand
+        * data is corrupted.
+        * Let's DCHECK it.
+        */
+       DCHECK(IsTemp(rl_src2.reg.GetLow()) &&
+              IsTemp(rl_src2.reg.GetHigh()) &&
+              IsTemp(rl_result.reg.GetLow()) &&
+              IsTemp(rl_result.reg.GetHigh()));
+       tmp = rs_rDI;
+       NewLIR1(kX86Push32R, tmp.GetReg());
+    }
+
+    // Now we are ready to do calculations.
+    OpRegReg(kOpMov, tmp, rl_result.reg.GetLow());
+    OpRegReg(kOpSub, tmp, rl_src2.reg.GetLow());
+    OpRegReg(kOpMov, tmp, rl_result.reg.GetHigh());
+    OpRegReg(kOpSbc, tmp, rl_src2.reg.GetHigh());
+
+    // Let's put pop 'edi' here to break a bit the dependency chain.
+    if (tmp == rs_rDI) {
+      NewLIR1(kX86Pop32R, tmp.GetReg());
+    }
+
+    // Conditionally move the other integer into the destination register.
+    ConditionCode cc = is_min ? kCondGe : kCondLt;
+    OpCondRegReg(kOpCmov, cc, rl_result.reg.GetLow(), rl_src2.reg.GetLow());
+    OpCondRegReg(kOpCmov, cc, rl_result.reg.GetHigh(), rl_src2.reg.GetHigh());
+    StoreValueWide(rl_dest, rl_result);
+    return true;
   }
 
   // Get the two arguments to the invoke and place them in GP registers.
@@ -3033,7 +3140,53 @@
 void X86Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
                         RegLocation rl_src1, RegLocation rl_shift) {
   if (!cu_->target64) {
-    Mir2Lir::GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
+    // Long shift operations in 32-bit. Use shld or shrd to create a 32-bit register filled from
+    // the other half, shift the other half, if the shift amount is less than 32 we're done,
+    // otherwise move one register to the other and place zero or sign bits in the other.
+    LIR* branch;
+    FlushAllRegs();
+    LockCallTemps();
+    LoadValueDirectFixed(rl_shift, rs_rCX);
+    RegStorage r_tmp = RegStorage::MakeRegPair(rs_rAX, rs_rDX);
+    LoadValueDirectWideFixed(rl_src1, r_tmp);
+    switch (opcode) {
+      case Instruction::SHL_LONG:
+      case Instruction::SHL_LONG_2ADDR:
+        NewLIR3(kX86Shld32RRC, r_tmp.GetHighReg(), r_tmp.GetLowReg(), rs_rCX.GetReg());
+        NewLIR2(kX86Sal32RC, r_tmp.GetLowReg(), rs_rCX.GetReg());
+        NewLIR2(kX86Test8RI, rs_rCX.GetReg(), 32);
+        branch = NewLIR2(kX86Jcc8, 0, kX86CondZ);
+        OpRegCopy(r_tmp.GetHigh(), r_tmp.GetLow());
+        LoadConstant(r_tmp.GetLow(), 0);
+        branch->target = NewLIR0(kPseudoTargetLabel);
+        break;
+      case Instruction::SHR_LONG:
+      case Instruction::SHR_LONG_2ADDR:
+        NewLIR3(kX86Shrd32RRC, r_tmp.GetLowReg(), r_tmp.GetHighReg(), rs_rCX.GetReg());
+        NewLIR2(kX86Sar32RC, r_tmp.GetHighReg(), rs_rCX.GetReg());
+        NewLIR2(kX86Test8RI, rs_rCX.GetReg(), 32);
+        branch = NewLIR2(kX86Jcc8, 0, kX86CondZ);
+        OpRegCopy(r_tmp.GetLow(), r_tmp.GetHigh());
+        NewLIR2(kX86Sar32RI, r_tmp.GetHighReg(), 31);
+        branch->target = NewLIR0(kPseudoTargetLabel);
+        break;
+      case Instruction::USHR_LONG:
+      case Instruction::USHR_LONG_2ADDR:
+        NewLIR3(kX86Shrd32RRC, r_tmp.GetLowReg(), r_tmp.GetHighReg(),
+               rs_rCX.GetReg());
+        NewLIR2(kX86Shr32RC, r_tmp.GetHighReg(), rs_rCX.GetReg());
+        NewLIR2(kX86Test8RI, rs_rCX.GetReg(), 32);
+        branch = NewLIR2(kX86Jcc8, 0, kX86CondZ);
+        OpRegCopy(r_tmp.GetLow(), r_tmp.GetHigh());
+        LoadConstant(r_tmp.GetHigh(), 0);
+        branch->target = NewLIR0(kPseudoTargetLabel);
+        break;
+      default:
+        LOG(FATAL) << "Unexpected case: " << opcode;
+        return;
+    }
+    RegLocation rl_result = LocCReturnWide();
+    StoreValueWide(rl_dest, rl_result);
     return;
   }
 
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 95941e0..f4bb40c 100755
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -760,10 +760,7 @@
 RegisterClass X86Mir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
   // X86_64 can handle any size.
   if (cu_->target64) {
-    if (size == kReference) {
-      return kRefReg;
-    }
-    return kCoreReg;
+    return RegClassBySize(size);
   }
 
   if (UNLIKELY(is_volatile)) {
@@ -1439,8 +1436,8 @@
   // Generate the FDE for the method.
   DCHECK_NE(data_offset_, 0U);
 
-  WriteFDEHeader(cfi_info);
-  WriteFDEAddressRange(cfi_info, data_offset_);
+  WriteFDEHeader(cfi_info, cu_->target64);
+  WriteFDEAddressRange(cfi_info, data_offset_, cu_->target64);
 
   // The instructions in the FDE.
   if (stack_decrement_ != nullptr) {
@@ -1500,7 +1497,7 @@
   }
 
   PadCFI(cfi_info);
-  WriteCFILength(cfi_info);
+  WriteCFILength(cfi_info, cu_->target64);
 
   return cfi_info;
 }
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 500c6b8..9620cd1 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -484,8 +484,10 @@
 #undef BinaryShiftOpcode
   kX86Cmc,
   kX86Shld32RRI,
+  kX86Shld32RRC,
   kX86Shld32MRI,
   kX86Shrd32RRI,
+  kX86Shrd32RRC,
   kX86Shrd32MRI,
   kX86Shld64RRI,
   kX86Shld64MRI,
@@ -675,6 +677,7 @@
   kMemRegImm,                               // MRI instruction kinds.
   kShiftRegImm, kShiftMemImm, kShiftArrayImm,  // Shift opcode with immediate.
   kShiftRegCl, kShiftMemCl, kShiftArrayCl,     // Shift opcode with register CL.
+  kShiftRegRegCl,
   // kRegRegReg, kRegRegMem, kRegRegArray,    // RRR, RRM, RRA instruction kinds.
   kRegCond, kMemCond, kArrayCond,          // R, M, A instruction kinds following by a condition.
   kRegRegCond,                             // RR instruction kind followed by a condition.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 645fc1c..3915381 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -354,6 +354,7 @@
       compiler_get_method_code_addr_(NULL),
       support_boot_image_fixup_(instruction_set != kMips),
       dedupe_code_("dedupe code"),
+      dedupe_src_mapping_table_("dedupe source mapping table"),
       dedupe_mapping_table_("dedupe mapping table"),
       dedupe_vmap_table_("dedupe vmap table"),
       dedupe_gc_map_("dedupe gc map"),
@@ -390,6 +391,10 @@
   return dedupe_code_.Add(Thread::Current(), code);
 }
 
+SrcMap* CompilerDriver::DeduplicateSrcMappingTable(const SrcMap& src_map) {
+  return dedupe_src_mapping_table_.Add(Thread::Current(), src_map);
+}
+
 std::vector<uint8_t>* CompilerDriver::DeduplicateMappingTable(const std::vector<uint8_t>& code) {
   return dedupe_mapping_table_.Add(Thread::Current(), code);
 }
@@ -1524,7 +1529,13 @@
     return true;
   }
 
-  return SkipClassCheckClassPath(descriptor, dex_file, dex_files);
+  if (dex_files.size() > 1) {
+    // Multi-dex compilation, only take first class.
+    return SkipClassCheckClassPath(descriptor, dex_file, dex_files);
+  } else {
+    // Single dex, take everything.
+    return false;
+  }
 }
 
 // A fast version of SkipClass above if the class pointer is available
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 233c4f8..d8f318b 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -601,6 +601,7 @@
       LOCKS_EXCLUDED(compiled_classes_lock_);
 
   std::vector<uint8_t>* DeduplicateCode(const std::vector<uint8_t>& code);
+  SrcMap* DeduplicateSrcMappingTable(const SrcMap& src_map);
   std::vector<uint8_t>* DeduplicateMappingTable(const std::vector<uint8_t>& code);
   std::vector<uint8_t>* DeduplicateVMapTable(const std::vector<uint8_t>& code);
   std::vector<uint8_t>* DeduplicateGCMap(const std::vector<uint8_t>& code);
@@ -770,14 +771,15 @@
   bool support_boot_image_fixup_;
 
   // DeDuplication data structures, these own the corresponding byte arrays.
+  template <typename ByteArray>
   class DedupeHashFunc {
    public:
-    size_t operator()(const std::vector<uint8_t>& array) const {
+    size_t operator()(const ByteArray& array) const {
       // For small arrays compute a hash using every byte.
       static const size_t kSmallArrayThreshold = 16;
       size_t hash = 0x811c9dc5;
       if (array.size() <= kSmallArrayThreshold) {
-        for (uint8_t b : array) {
+        for (auto b : array) {
           hash = (hash * 16777619) ^ b;
         }
       } else {
@@ -803,11 +805,13 @@
       return hash;
     }
   };
-  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_code_;
-  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_mapping_table_;
-  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_vmap_table_;
-  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_gc_map_;
-  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_cfi_info_;
+
+  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_code_;
+  DedupeSet<SrcMap, size_t, DedupeHashFunc<SrcMap>, 4> dedupe_src_mapping_table_;
+  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_mapping_table_;
+  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_vmap_table_;
+  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_gc_map_;
+  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_cfi_info_;
 
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
 };
diff --git a/compiler/elf_fixup.cc b/compiler/elf_fixup.cc
index 60f76ef..bbfbc6e 100644
--- a/compiler/elf_fixup.cc
+++ b/compiler/elf_fixup.cc
@@ -38,28 +38,32 @@
   Elf32_Off base_address = oat_data_begin - oatdata_address;
 
   if (!FixupDynamic(*elf_file.get(), base_address)) {
-      LOG(WARNING) << "Failed fo fixup .dynamic in " << file->GetPath();
-      return false;
+    LOG(WARNING) << "Failed to fixup .dynamic in " << file->GetPath();
+    return false;
   }
   if (!FixupSectionHeaders(*elf_file.get(), base_address)) {
-      LOG(WARNING) << "Failed fo fixup section headers in " << file->GetPath();
-      return false;
+    LOG(WARNING) << "Failed to fixup section headers in " << file->GetPath();
+    return false;
   }
   if (!FixupProgramHeaders(*elf_file.get(), base_address)) {
-      LOG(WARNING) << "Failed fo fixup program headers in " << file->GetPath();
-      return false;
+    LOG(WARNING) << "Failed to fixup program headers in " << file->GetPath();
+    return false;
   }
   if (!FixupSymbols(*elf_file.get(), base_address, true)) {
-      LOG(WARNING) << "Failed fo fixup .dynsym in " << file->GetPath();
-      return false;
+    LOG(WARNING) << "Failed to fixup .dynsym in " << file->GetPath();
+    return false;
   }
   if (!FixupSymbols(*elf_file.get(), base_address, false)) {
-      LOG(WARNING) << "Failed fo fixup .symtab in " << file->GetPath();
-      return false;
+    LOG(WARNING) << "Failed to fixup .symtab in " << file->GetPath();
+    return false;
   }
   if (!FixupRelocations(*elf_file.get(), base_address)) {
-      LOG(WARNING) << "Failed fo fixup .rel.dyn in " << file->GetPath();
-      return false;
+    LOG(WARNING) << "Failed to fixup .rel.dyn in " << file->GetPath();
+    return false;
+  }
+  if (!elf_file->FixupDebugSections(base_address)) {
+    LOG(WARNING) << "Failed to fixup debug sections in " << file->GetPath();
+    return false;
   }
   return true;
 }
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index bb5f7e0..e45eb61 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -16,11 +16,14 @@
 
 #include "elf_writer_quick.h"
 
+#include <unordered_map>
+
 #include "base/logging.h"
 #include "base/unix_file/fd_file.h"
 #include "buffered_output_stream.h"
 #include "driver/compiler_driver.h"
 #include "dwarf.h"
+#include "elf_file.h"
 #include "elf_utils.h"
 #include "file_output_stream.h"
 #include "globals.h"
@@ -39,6 +42,30 @@
   return ((binding) << 4) + ((type) & 0xf);
 }
 
+static void PushByte(std::vector<uint8_t>* buf, int data) {
+  buf->push_back(data & 0xff);
+}
+
+static uint32_t PushStr(std::vector<uint8_t>* buf, const char* str, const char* def = nullptr) {
+  if (str == nullptr) {
+    str = def;
+  }
+
+  uint32_t offset = buf->size();
+  for (size_t i = 0; str[i] != '\0'; ++i) {
+    buf->push_back(str[i]);
+  }
+  buf->push_back('\0');
+  return offset;
+}
+
+static uint32_t PushStr(std::vector<uint8_t>* buf, const std::string &str) {
+  uint32_t offset = buf->size();
+  buf->insert(buf->end(), str.begin(), str.end());
+  buf->push_back('\0');
+  return offset;
+}
+
 static void UpdateWord(std::vector<uint8_t>* buf, int offset, int data) {
   (*buf)[offset+0] = data;
   (*buf)[offset+1] = data >> 8;
@@ -51,7 +78,7 @@
   buf->push_back((data >> 8) & 0xff);
 }
 
-bool ElfWriterQuick::ElfBuilder::Write() {
+bool ElfWriterQuick::ElfBuilder::Init() {
   // The basic layout of the elf file. Order may be different in final output.
   // +-------------------------+
   // | Elf32_Ehdr              |
@@ -120,16 +147,19 @@
   // | .debug_str\0            |  (Optional)
   // | .debug_info\0           |  (Optional)
   // | .eh_frame\0             |  (Optional)
+  // | .debug_line\0           |  (Optional)
   // | .debug_abbrev\0         |  (Optional)
   // +-------------------------+  (Optional)
-  // | .debug_str              |  (Optional)
-  // +-------------------------+  (Optional)
   // | .debug_info             |  (Optional)
   // +-------------------------+  (Optional)
+  // | .debug_abbrev           |  (Optional)
+  // +-------------------------+  (Optional)
   // | .eh_frame               |  (Optional)
   // +-------------------------+  (Optional)
-  // | .debug_abbrev           |  (Optional)
-  // +-------------------------+
+  // | .debug_line             |  (Optional)
+  // +-------------------------+  (Optional)
+  // | .debug_str              |  (Optional)
+  // +-------------------------+  (Optional)
   // | Elf32_Shdr NULL         |
   // | Elf32_Shdr .dynsym      |
   // | Elf32_Shdr .dynstr      |
@@ -138,173 +168,117 @@
   // | Elf32_Shdr .rodata      |
   // | Elf32_Shdr .dynamic     |
   // | Elf32_Shdr .shstrtab    |
-  // | Elf32_Shdr .debug_str   |  (Optional)
   // | Elf32_Shdr .debug_info  |  (Optional)
-  // | Elf32_Shdr .eh_frame    |  (Optional)
   // | Elf32_Shdr .debug_abbrev|  (Optional)
+  // | Elf32_Shdr .eh_frame    |  (Optional)
+  // | Elf32_Shdr .debug_line  |  (Optional)
+  // | Elf32_Shdr .debug_str   |  (Optional)
   // +-------------------------+
 
-
   if (fatal_error_) {
     return false;
   }
   // Step 1. Figure out all the offsets.
 
-  // What phdr is.
-  uint32_t phdr_offset = sizeof(Elf32_Ehdr);
-  const uint8_t PH_PHDR     = 0;
-  const uint8_t PH_LOAD_R__ = 1;
-  const uint8_t PH_LOAD_R_X = 2;
-  const uint8_t PH_LOAD_RW_ = 3;
-  const uint8_t PH_DYNAMIC  = 4;
-  const uint8_t PH_NUM      = 5;
-  uint32_t phdr_size = sizeof(Elf32_Phdr) * PH_NUM;
   if (debug_logging_) {
-    LOG(INFO) << "phdr_offset=" << phdr_offset << std::hex << " " << phdr_offset;
-    LOG(INFO) << "phdr_size=" << phdr_size << std::hex << " " << phdr_size;
+    LOG(INFO) << "phdr_offset=" << PHDR_OFFSET << std::hex << " " << PHDR_OFFSET;
+    LOG(INFO) << "phdr_size=" << PHDR_SIZE << std::hex << " " << PHDR_SIZE;
   }
-  Elf32_Phdr program_headers[PH_NUM];
-  memset(&program_headers, 0, sizeof(program_headers));
-  program_headers[PH_PHDR].p_type    = PT_PHDR;
-  program_headers[PH_PHDR].p_offset  = phdr_offset;
-  program_headers[PH_PHDR].p_vaddr   = phdr_offset;
-  program_headers[PH_PHDR].p_paddr   = phdr_offset;
-  program_headers[PH_PHDR].p_filesz  = sizeof(program_headers);
-  program_headers[PH_PHDR].p_memsz   = sizeof(program_headers);
-  program_headers[PH_PHDR].p_flags   = PF_R;
-  program_headers[PH_PHDR].p_align   = sizeof(Elf32_Word);
 
-  program_headers[PH_LOAD_R__].p_type    = PT_LOAD;
-  program_headers[PH_LOAD_R__].p_offset  = 0;
-  program_headers[PH_LOAD_R__].p_vaddr   = 0;
-  program_headers[PH_LOAD_R__].p_paddr   = 0;
-  program_headers[PH_LOAD_R__].p_flags   = PF_R;
+  memset(&program_headers_, 0, sizeof(program_headers_));
+  program_headers_[PH_PHDR].p_type    = PT_PHDR;
+  program_headers_[PH_PHDR].p_offset  = PHDR_OFFSET;
+  program_headers_[PH_PHDR].p_vaddr   = PHDR_OFFSET;
+  program_headers_[PH_PHDR].p_paddr   = PHDR_OFFSET;
+  program_headers_[PH_PHDR].p_filesz  = sizeof(program_headers_);
+  program_headers_[PH_PHDR].p_memsz   = sizeof(program_headers_);
+  program_headers_[PH_PHDR].p_flags   = PF_R;
+  program_headers_[PH_PHDR].p_align   = sizeof(Elf32_Word);
 
-  program_headers[PH_LOAD_R_X].p_type    = PT_LOAD;
-  program_headers[PH_LOAD_R_X].p_flags   = PF_R | PF_X;
+  program_headers_[PH_LOAD_R__].p_type    = PT_LOAD;
+  program_headers_[PH_LOAD_R__].p_offset  = 0;
+  program_headers_[PH_LOAD_R__].p_vaddr   = 0;
+  program_headers_[PH_LOAD_R__].p_paddr   = 0;
+  program_headers_[PH_LOAD_R__].p_flags   = PF_R;
 
-  program_headers[PH_LOAD_RW_].p_type    = PT_LOAD;
-  program_headers[PH_LOAD_RW_].p_flags   = PF_R | PF_W;
+  program_headers_[PH_LOAD_R_X].p_type    = PT_LOAD;
+  program_headers_[PH_LOAD_R_X].p_flags   = PF_R | PF_X;
 
-  program_headers[PH_DYNAMIC].p_type    = PT_DYNAMIC;
-  program_headers[PH_DYNAMIC].p_flags   = PF_R | PF_W;
+  program_headers_[PH_LOAD_RW_].p_type    = PT_LOAD;
+  program_headers_[PH_LOAD_RW_].p_flags   = PF_R | PF_W;
+
+  program_headers_[PH_DYNAMIC].p_type    = PT_DYNAMIC;
+  program_headers_[PH_DYNAMIC].p_flags   = PF_R | PF_W;
 
   // Get the dynstr string.
-  std::string dynstr(dynsym_builder_.GenerateStrtab());
+  dynstr_ = dynsym_builder_.GenerateStrtab();
 
   // Add the SONAME to the dynstr.
-  uint32_t dynstr_soname_offset = dynstr.size();
+  dynstr_soname_offset_ = dynstr_.size();
   std::string file_name(elf_file_->GetPath());
   size_t directory_separator_pos = file_name.rfind('/');
   if (directory_separator_pos != std::string::npos) {
     file_name = file_name.substr(directory_separator_pos + 1);
   }
-  dynstr += file_name;
-  dynstr += '\0';
+  dynstr_ += file_name;
+  dynstr_ += '\0';
   if (debug_logging_) {
-    LOG(INFO) << "dynstr size (bytes)   =" << dynstr.size()
-              << std::hex << " " << dynstr.size();
+    LOG(INFO) << "dynstr size (bytes)   =" << dynstr_.size()
+              << std::hex << " " << dynstr_.size();
     LOG(INFO) << "dynsym size (elements)=" << dynsym_builder_.GetSize()
               << std::hex << " " << dynsym_builder_.GetSize();
   }
 
-  // get the strtab
-  std::string strtab;
-  if (IncludingDebugSymbols()) {
-    strtab = symtab_builder_.GenerateStrtab();
-    if (debug_logging_) {
-      LOG(INFO) << "strtab size (bytes)    =" << strtab.size()
-                << std::hex << " " << strtab.size();
-      LOG(INFO) << "symtab size (elements) =" << symtab_builder_.GetSize()
-                << std::hex << " " << symtab_builder_.GetSize();
-    }
-  }
-
   // Get the section header string table.
-  std::vector<Elf32_Shdr*> section_ptrs;
-  std::string shstrtab;
-  shstrtab += '\0';
+  shstrtab_ += '\0';
 
   // Setup sym_undef
-  Elf32_Shdr null_hdr;
-  memset(&null_hdr, 0, sizeof(null_hdr));
-  null_hdr.sh_type = SHT_NULL;
-  null_hdr.sh_link = SHN_UNDEF;
-  section_ptrs.push_back(&null_hdr);
+  memset(&null_hdr_, 0, sizeof(null_hdr_));
+  null_hdr_.sh_type = SHT_NULL;
+  null_hdr_.sh_link = SHN_UNDEF;
+  section_ptrs_.push_back(&null_hdr_);
 
-  uint32_t section_index = 1;
+  section_index_ = 1;
 
   // setup .dynsym
-  section_ptrs.push_back(&dynsym_builder_.section_);
-  AssignSectionStr(&dynsym_builder_, &shstrtab);
-  dynsym_builder_.section_index_ = section_index++;
+  section_ptrs_.push_back(&dynsym_builder_.section_);
+  AssignSectionStr(&dynsym_builder_, &shstrtab_);
+  dynsym_builder_.section_index_ = section_index_++;
 
   // Setup .dynstr
-  section_ptrs.push_back(&dynsym_builder_.strtab_.section_);
-  AssignSectionStr(&dynsym_builder_.strtab_, &shstrtab);
-  dynsym_builder_.strtab_.section_index_ = section_index++;
+  section_ptrs_.push_back(&dynsym_builder_.strtab_.section_);
+  AssignSectionStr(&dynsym_builder_.strtab_, &shstrtab_);
+  dynsym_builder_.strtab_.section_index_ = section_index_++;
 
   // Setup .hash
-  section_ptrs.push_back(&hash_builder_.section_);
-  AssignSectionStr(&hash_builder_, &shstrtab);
-  hash_builder_.section_index_ = section_index++;
+  section_ptrs_.push_back(&hash_builder_.section_);
+  AssignSectionStr(&hash_builder_, &shstrtab_);
+  hash_builder_.section_index_ = section_index_++;
 
   // Setup .rodata
-  section_ptrs.push_back(&rodata_builder_.section_);
-  AssignSectionStr(&rodata_builder_, &shstrtab);
-  rodata_builder_.section_index_ = section_index++;
+  section_ptrs_.push_back(&rodata_builder_.section_);
+  AssignSectionStr(&rodata_builder_, &shstrtab_);
+  rodata_builder_.section_index_ = section_index_++;
 
   // Setup .text
-  section_ptrs.push_back(&text_builder_.section_);
-  AssignSectionStr(&text_builder_, &shstrtab);
-  text_builder_.section_index_ = section_index++;
+  section_ptrs_.push_back(&text_builder_.section_);
+  AssignSectionStr(&text_builder_, &shstrtab_);
+  text_builder_.section_index_ = section_index_++;
 
   // Setup .dynamic
-  section_ptrs.push_back(&dynamic_builder_.section_);
-  AssignSectionStr(&dynamic_builder_, &shstrtab);
-  dynamic_builder_.section_index_ = section_index++;
-
-  if (IncludingDebugSymbols()) {
-    // Setup .symtab
-    section_ptrs.push_back(&symtab_builder_.section_);
-    AssignSectionStr(&symtab_builder_, &shstrtab);
-    symtab_builder_.section_index_ = section_index++;
-
-    // Setup .strtab
-    section_ptrs.push_back(&symtab_builder_.strtab_.section_);
-    AssignSectionStr(&symtab_builder_.strtab_, &shstrtab);
-    symtab_builder_.strtab_.section_index_ = section_index++;
-  }
-  ElfRawSectionBuilder* it = other_builders_.data();
-  for (uint32_t cnt = 0; cnt < other_builders_.size(); ++it, ++cnt) {
-    // Setup all the other sections.
-    section_ptrs.push_back(&it->section_);
-    AssignSectionStr(it, &shstrtab);
-    it->section_index_ = section_index++;
-  }
-
-  // Setup shstrtab
-  section_ptrs.push_back(&shstrtab_builder_.section_);
-  AssignSectionStr(&shstrtab_builder_, &shstrtab);
-  shstrtab_builder_.section_index_ = section_index++;
-
-  if (debug_logging_) {
-    LOG(INFO) << ".shstrtab size    (bytes)   =" << shstrtab.size()
-              << std::hex << " " << shstrtab.size();
-    LOG(INFO) << "section list size (elements)=" << section_ptrs.size()
-              << std::hex << " " << section_ptrs.size();
-  }
+  section_ptrs_.push_back(&dynamic_builder_.section_);
+  AssignSectionStr(&dynamic_builder_, &shstrtab_);
+  dynamic_builder_.section_index_ = section_index_++;
 
   // Fill in the hash section.
-  std::vector<Elf32_Word> hash = dynsym_builder_.GenerateHashContents();
+  hash_ = dynsym_builder_.GenerateHashContents();
 
   if (debug_logging_) {
-    LOG(INFO) << ".hash size (bytes)=" << hash.size() * sizeof(Elf32_Word)
-              << std::hex << " " << hash.size() * sizeof(Elf32_Word);
+    LOG(INFO) << ".hash size (bytes)=" << hash_.size() * sizeof(Elf32_Word)
+              << std::hex << " " << hash_.size() * sizeof(Elf32_Word);
   }
 
-  Elf32_Word base_offset = sizeof(Elf32_Ehdr) + sizeof(program_headers);
-  std::vector<ElfFilePiece> pieces;
+  Elf32_Word base_offset = sizeof(Elf32_Ehdr) + sizeof(program_headers_);
 
   // Get the layout in the sections.
   //
@@ -318,14 +292,14 @@
   dynsym_builder_.strtab_.section_.sh_offset = NextOffset(dynsym_builder_.strtab_.section_,
                                                           dynsym_builder_.section_);
   dynsym_builder_.strtab_.section_.sh_addr = dynsym_builder_.strtab_.section_.sh_offset;
-  dynsym_builder_.strtab_.section_.sh_size = dynstr.size();
+  dynsym_builder_.strtab_.section_.sh_size = dynstr_.size();
   dynsym_builder_.strtab_.section_.sh_link = dynsym_builder_.strtab_.GetLink();
 
   // Get the layout of the hash section
   hash_builder_.section_.sh_offset = NextOffset(hash_builder_.section_,
                                                 dynsym_builder_.strtab_.section_);
   hash_builder_.section_.sh_addr = hash_builder_.section_.sh_offset;
-  hash_builder_.section_.sh_size = hash.size() * sizeof(Elf32_Word);
+  hash_builder_.section_.sh_size = hash_.size() * sizeof(Elf32_Word);
   hash_builder_.section_.sh_link = hash_builder_.GetLink();
 
   // Get the layout of the rodata section.
@@ -349,7 +323,70 @@
   dynamic_builder_.section_.sh_size = dynamic_builder_.GetSize() * sizeof(Elf32_Dyn);
   dynamic_builder_.section_.sh_link = dynamic_builder_.GetLink();
 
+  if (debug_logging_) {
+    LOG(INFO) << "dynsym off=" << dynsym_builder_.section_.sh_offset
+              << " dynsym size=" << dynsym_builder_.section_.sh_size;
+    LOG(INFO) << "dynstr off=" << dynsym_builder_.strtab_.section_.sh_offset
+              << " dynstr size=" << dynsym_builder_.strtab_.section_.sh_size;
+    LOG(INFO) << "hash off=" << hash_builder_.section_.sh_offset
+              << " hash size=" << hash_builder_.section_.sh_size;
+    LOG(INFO) << "rodata off=" << rodata_builder_.section_.sh_offset
+              << " rodata size=" << rodata_builder_.section_.sh_size;
+    LOG(INFO) << "text off=" << text_builder_.section_.sh_offset
+              << " text size=" << text_builder_.section_.sh_size;
+    LOG(INFO) << "dynamic off=" << dynamic_builder_.section_.sh_offset
+              << " dynamic size=" << dynamic_builder_.section_.sh_size;
+  }
+
+  return true;
+}
+
+bool ElfWriterQuick::ElfBuilder::Write() {
+  std::vector<ElfFilePiece> pieces;
   Elf32_Shdr prev = dynamic_builder_.section_;
+  std::string strtab;
+
+  if (IncludingDebugSymbols()) {
+    // Setup .symtab
+    section_ptrs_.push_back(&symtab_builder_.section_);
+    AssignSectionStr(&symtab_builder_, &shstrtab_);
+    symtab_builder_.section_index_ = section_index_++;
+
+    // Setup .strtab
+    section_ptrs_.push_back(&symtab_builder_.strtab_.section_);
+    AssignSectionStr(&symtab_builder_.strtab_, &shstrtab_);
+    symtab_builder_.strtab_.section_index_ = section_index_++;
+
+    strtab = symtab_builder_.GenerateStrtab();
+    if (debug_logging_) {
+      LOG(INFO) << "strtab size (bytes)    =" << strtab.size()
+                << std::hex << " " << strtab.size();
+      LOG(INFO) << "symtab size (elements) =" << symtab_builder_.GetSize()
+                << std::hex << " " << symtab_builder_.GetSize();
+    }
+  }
+
+  // Setup all the other sections.
+  for (ElfRawSectionBuilder *builder = other_builders_.data(),
+                            *end = builder + other_builders_.size();
+       builder != end; ++builder) {
+    section_ptrs_.push_back(&builder->section_);
+    AssignSectionStr(builder, &shstrtab_);
+    builder->section_index_ = section_index_++;
+  }
+
+  // Setup shstrtab
+  section_ptrs_.push_back(&shstrtab_builder_.section_);
+  AssignSectionStr(&shstrtab_builder_, &shstrtab_);
+  shstrtab_builder_.section_index_ = section_index_++;
+
+  if (debug_logging_) {
+    LOG(INFO) << ".shstrtab size    (bytes)   =" << shstrtab_.size()
+              << std::hex << " " << shstrtab_.size();
+    LOG(INFO) << "section list size (elements)=" << section_ptrs_.size()
+              << std::hex << " " << section_ptrs_.size();
+  }
+
   if (IncludingDebugSymbols()) {
     // Get the layout of the symtab section.
     symtab_builder_.section_.sh_offset = NextOffset(symtab_builder_.section_,
@@ -367,27 +404,14 @@
     symtab_builder_.strtab_.section_.sh_link = symtab_builder_.strtab_.GetLink();
 
     prev = symtab_builder_.strtab_.section_;
-  }
-  if (debug_logging_) {
-    LOG(INFO) << "dynsym off=" << dynsym_builder_.section_.sh_offset
-              << " dynsym size=" << dynsym_builder_.section_.sh_size;
-    LOG(INFO) << "dynstr off=" << dynsym_builder_.strtab_.section_.sh_offset
-              << " dynstr size=" << dynsym_builder_.strtab_.section_.sh_size;
-    LOG(INFO) << "hash off=" << hash_builder_.section_.sh_offset
-              << " hash size=" << hash_builder_.section_.sh_size;
-    LOG(INFO) << "rodata off=" << rodata_builder_.section_.sh_offset
-              << " rodata size=" << rodata_builder_.section_.sh_size;
-    LOG(INFO) << "text off=" << text_builder_.section_.sh_offset
-              << " text size=" << text_builder_.section_.sh_size;
-    LOG(INFO) << "dynamic off=" << dynamic_builder_.section_.sh_offset
-              << " dynamic size=" << dynamic_builder_.section_.sh_size;
-    if (IncludingDebugSymbols()) {
+    if (debug_logging_) {
       LOG(INFO) << "symtab off=" << symtab_builder_.section_.sh_offset
                 << " symtab size=" << symtab_builder_.section_.sh_size;
       LOG(INFO) << "strtab off=" << symtab_builder_.strtab_.section_.sh_offset
                 << " strtab size=" << symtab_builder_.strtab_.section_.sh_size;
     }
   }
+
   // Get the layout of the extra sections. (This will deal with the debug
   // sections if they are there)
   for (auto it = other_builders_.begin(); it != other_builders_.end(); ++it) {
@@ -403,10 +427,11 @@
                 << " " << it->name_ << " size=" << it->section_.sh_size;
     }
   }
+
   // Get the layout of the shstrtab section
   shstrtab_builder_.section_.sh_offset = NextOffset(shstrtab_builder_.section_, prev);
   shstrtab_builder_.section_.sh_addr = 0;
-  shstrtab_builder_.section_.sh_size = shstrtab.size();
+  shstrtab_builder_.section_.sh_size = shstrtab_.size();
   shstrtab_builder_.section_.sh_link = shstrtab_builder_.GetLink();
   if (debug_logging_) {
       LOG(INFO) << "shstrtab off=" << shstrtab_builder_.section_.sh_offset
@@ -430,58 +455,58 @@
   // Setup the dynamic section.
   // This will add the 2 values we cannot know until now time, namely the size
   // and the soname_offset.
-  std::vector<Elf32_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr.size(),
-                                                                dynstr_soname_offset);
+  std::vector<Elf32_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr_.size(),
+                                                                dynstr_soname_offset_);
   CHECK_EQ(dynamic.size() * sizeof(Elf32_Dyn), dynamic_builder_.section_.sh_size);
 
   // Finish setup of the program headers now that we know the layout of the
   // whole file.
   Elf32_Word load_r_size = rodata_builder_.section_.sh_offset + rodata_builder_.section_.sh_size;
-  program_headers[PH_LOAD_R__].p_filesz = load_r_size;
-  program_headers[PH_LOAD_R__].p_memsz =  load_r_size;
-  program_headers[PH_LOAD_R__].p_align =  rodata_builder_.section_.sh_addralign;
+  program_headers_[PH_LOAD_R__].p_filesz = load_r_size;
+  program_headers_[PH_LOAD_R__].p_memsz =  load_r_size;
+  program_headers_[PH_LOAD_R__].p_align =  rodata_builder_.section_.sh_addralign;
 
   Elf32_Word load_rx_size = text_builder_.section_.sh_size;
-  program_headers[PH_LOAD_R_X].p_offset = text_builder_.section_.sh_offset;
-  program_headers[PH_LOAD_R_X].p_vaddr  = text_builder_.section_.sh_offset;
-  program_headers[PH_LOAD_R_X].p_paddr  = text_builder_.section_.sh_offset;
-  program_headers[PH_LOAD_R_X].p_filesz = load_rx_size;
-  program_headers[PH_LOAD_R_X].p_memsz  = load_rx_size;
-  program_headers[PH_LOAD_R_X].p_align  = text_builder_.section_.sh_addralign;
+  program_headers_[PH_LOAD_R_X].p_offset = text_builder_.section_.sh_offset;
+  program_headers_[PH_LOAD_R_X].p_vaddr  = text_builder_.section_.sh_offset;
+  program_headers_[PH_LOAD_R_X].p_paddr  = text_builder_.section_.sh_offset;
+  program_headers_[PH_LOAD_R_X].p_filesz = load_rx_size;
+  program_headers_[PH_LOAD_R_X].p_memsz  = load_rx_size;
+  program_headers_[PH_LOAD_R_X].p_align  = text_builder_.section_.sh_addralign;
 
-  program_headers[PH_LOAD_RW_].p_offset = dynamic_builder_.section_.sh_offset;
-  program_headers[PH_LOAD_RW_].p_vaddr  = dynamic_builder_.section_.sh_offset;
-  program_headers[PH_LOAD_RW_].p_paddr  = dynamic_builder_.section_.sh_offset;
-  program_headers[PH_LOAD_RW_].p_filesz = dynamic_builder_.section_.sh_size;
-  program_headers[PH_LOAD_RW_].p_memsz  = dynamic_builder_.section_.sh_size;
-  program_headers[PH_LOAD_RW_].p_align  = dynamic_builder_.section_.sh_addralign;
+  program_headers_[PH_LOAD_RW_].p_offset = dynamic_builder_.section_.sh_offset;
+  program_headers_[PH_LOAD_RW_].p_vaddr  = dynamic_builder_.section_.sh_offset;
+  program_headers_[PH_LOAD_RW_].p_paddr  = dynamic_builder_.section_.sh_offset;
+  program_headers_[PH_LOAD_RW_].p_filesz = dynamic_builder_.section_.sh_size;
+  program_headers_[PH_LOAD_RW_].p_memsz  = dynamic_builder_.section_.sh_size;
+  program_headers_[PH_LOAD_RW_].p_align  = dynamic_builder_.section_.sh_addralign;
 
-  program_headers[PH_DYNAMIC].p_offset = dynamic_builder_.section_.sh_offset;
-  program_headers[PH_DYNAMIC].p_vaddr  = dynamic_builder_.section_.sh_offset;
-  program_headers[PH_DYNAMIC].p_paddr  = dynamic_builder_.section_.sh_offset;
-  program_headers[PH_DYNAMIC].p_filesz = dynamic_builder_.section_.sh_size;
-  program_headers[PH_DYNAMIC].p_memsz  = dynamic_builder_.section_.sh_size;
-  program_headers[PH_DYNAMIC].p_align  = dynamic_builder_.section_.sh_addralign;
+  program_headers_[PH_DYNAMIC].p_offset = dynamic_builder_.section_.sh_offset;
+  program_headers_[PH_DYNAMIC].p_vaddr  = dynamic_builder_.section_.sh_offset;
+  program_headers_[PH_DYNAMIC].p_paddr  = dynamic_builder_.section_.sh_offset;
+  program_headers_[PH_DYNAMIC].p_filesz = dynamic_builder_.section_.sh_size;
+  program_headers_[PH_DYNAMIC].p_memsz  = dynamic_builder_.section_.sh_size;
+  program_headers_[PH_DYNAMIC].p_align  = dynamic_builder_.section_.sh_addralign;
 
   // Finish setup of the Ehdr values.
-  elf_header_.e_phoff = phdr_offset;
+  elf_header_.e_phoff = PHDR_OFFSET;
   elf_header_.e_shoff = sections_offset;
   elf_header_.e_phnum = PH_NUM;
-  elf_header_.e_shnum = section_ptrs.size();
+  elf_header_.e_shnum = section_ptrs_.size();
   elf_header_.e_shstrndx = shstrtab_builder_.section_index_;
 
   // Add the rest of the pieces to the list.
   pieces.push_back(ElfFilePiece("Elf Header", 0, &elf_header_, sizeof(elf_header_)));
-  pieces.push_back(ElfFilePiece("Program headers", phdr_offset,
-                                &program_headers, sizeof(program_headers)));
+  pieces.push_back(ElfFilePiece("Program headers", PHDR_OFFSET,
+                                &program_headers_, sizeof(program_headers_)));
   pieces.push_back(ElfFilePiece(".dynamic", dynamic_builder_.section_.sh_offset,
                                 dynamic.data(), dynamic_builder_.section_.sh_size));
   pieces.push_back(ElfFilePiece(".dynsym", dynsym_builder_.section_.sh_offset,
                                 dynsym.data(), dynsym.size() * sizeof(Elf32_Sym)));
   pieces.push_back(ElfFilePiece(".dynstr", dynsym_builder_.strtab_.section_.sh_offset,
-                                dynstr.c_str(), dynstr.size()));
+                                dynstr_.c_str(), dynstr_.size()));
   pieces.push_back(ElfFilePiece(".hash", hash_builder_.section_.sh_offset,
-                                hash.data(), hash.size() * sizeof(Elf32_Word)));
+                                hash_.data(), hash_.size() * sizeof(Elf32_Word)));
   pieces.push_back(ElfFilePiece(".rodata", rodata_builder_.section_.sh_offset,
                                 nullptr, rodata_builder_.section_.sh_size));
   pieces.push_back(ElfFilePiece(".text", text_builder_.section_.sh_offset,
@@ -493,13 +518,13 @@
                                   strtab.c_str(), strtab.size()));
   }
   pieces.push_back(ElfFilePiece(".shstrtab", shstrtab_builder_.section_.sh_offset,
-                                &shstrtab[0], shstrtab.size()));
-  for (uint32_t i = 0; i < section_ptrs.size(); ++i) {
+                                &shstrtab_[0], shstrtab_.size()));
+  for (uint32_t i = 0; i < section_ptrs_.size(); ++i) {
     // Just add all the sections in induvidually since they are all over the
     // place on the heap/stack.
     Elf32_Word cur_off = sections_offset + i * sizeof(Elf32_Shdr);
     pieces.push_back(ElfFilePiece("section table piece", cur_off,
-                                  section_ptrs[i], sizeof(Elf32_Shdr)));
+                                  section_ptrs_[i], sizeof(Elf32_Shdr)));
   }
 
   if (!WriteOutFile(pieces)) {
@@ -664,7 +689,7 @@
   // Lets say the state is something like this.
   // +--------+       +--------+      +-----------+
   // | symtab |       | bucket |      |   chain   |
-  // |  nullptr  |       | 1      |      | STN_UNDEF |
+  // |  null  |       | 1      |      | STN_UNDEF |
   // | <sym1> |       | 4      |      | 2         |
   // | <sym2> |       |        |      | 5         |
   // | <sym3> |       |        |      | STN_UNDEF |
@@ -836,13 +861,24 @@
 }
 
 std::vector<uint8_t>* ConstructCIEFrameX86(bool is_x86_64) {
-  std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+  std::vector<uint8_t>* cfi_info = new std::vector<uint8_t>;
 
   // Length (will be filled in later in this routine).
-  PushWord(cfi_info, 0);
+  if (is_x86_64) {
+    PushWord(cfi_info, 0xffffffff);  // Indicates 64bit
+    PushWord(cfi_info, 0);
+    PushWord(cfi_info, 0);
+  } else {
+    PushWord(cfi_info, 0);
+  }
 
   // CIE id: always 0.
-  PushWord(cfi_info, 0);
+  if (is_x86_64) {
+    PushWord(cfi_info, 0);
+    PushWord(cfi_info, 0);
+  } else {
+    PushWord(cfi_info, 0);
+  }
 
   // Version: always 1.
   cfi_info->push_back(0x01);
@@ -874,8 +910,14 @@
   // Augmentation length: 1.
   cfi_info->push_back(1);
 
-  // Augmentation data: 0x03 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4).
-  cfi_info->push_back(0x03);
+  // Augmentation data.
+  if (is_x86_64) {
+    // 0x04 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata8).
+    cfi_info->push_back(0x04);
+  } else {
+    // 0x03 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4).
+    cfi_info->push_back(0x03);
+  }
 
   // Initial instructions.
   if (is_x86_64) {
@@ -905,11 +947,13 @@
   }
 
   // Set the length of the CIE inside the generated bytes.
-  uint32_t length = cfi_info->size() - 4;
-  (*cfi_info)[0] = length;
-  (*cfi_info)[1] = length >> 8;
-  (*cfi_info)[2] = length >> 16;
-  (*cfi_info)[3] = length >> 24;
+  if (is_x86_64) {
+    uint32_t length = cfi_info->size() - 12;
+    UpdateWord(cfi_info, 4, length);
+  } else {
+    uint32_t length = cfi_info->size() - 4;
+    UpdateWord(cfi_info, 0, length);
+  }
   return cfi_info;
 }
 
@@ -940,8 +984,12 @@
                      compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols(),
                      debug);
 
+  if (!builder.Init()) {
+    return false;
+  }
+
   if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
-    WriteDebugSymbols(builder, oat_writer);
+    WriteDebugSymbols(&builder, oat_writer);
   }
 
   if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation()) {
@@ -954,15 +1002,17 @@
   return builder.Write();
 }
 
-void ElfWriterQuick::WriteDebugSymbols(ElfBuilder& builder, OatWriter* oat_writer) {
+void ElfWriterQuick::WriteDebugSymbols(ElfBuilder* builder, OatWriter* oat_writer) {
   std::unique_ptr<std::vector<uint8_t>> cfi_info(
       ConstructCIEFrame(compiler_driver_->GetInstructionSet()));
 
+  Elf32_Addr text_section_address = builder->text_builder_.section_.sh_addr;
+
   // Iterate over the compiled methods.
   const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetCFIMethodInfo();
-  ElfSymtabBuilder* symtab = &builder.symtab_builder_;
+  ElfSymtabBuilder* symtab = &builder->symtab_builder_;
   for (auto it = method_info.begin(); it != method_info.end(); ++it) {
-    symtab->AddSymbol(it->method_name_, &builder.text_builder_, it->low_pc_, true,
+    symtab->AddSymbol(it->method_name_, &builder->text_builder_, it->low_pc_, true,
                       it->high_pc_ - it->low_pc_, STB_GLOBAL, STT_FUNC);
 
     // Include CFI for compiled method, if possible.
@@ -976,96 +1026,314 @@
         int cur_offset = cfi_info->size();
         cfi_info->insert(cfi_info->end(), fde->begin(), fde->end());
 
-        // Set the 'CIE_pointer' field to cur_offset+4.
-        uint32_t CIE_pointer = cur_offset + 4;
-        uint32_t offset_to_update = cur_offset + sizeof(uint32_t);
-        (*cfi_info)[offset_to_update+0] = CIE_pointer;
-        (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8;
-        (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16;
-        (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24;
+        bool is_64bit = *(reinterpret_cast<const uint32_t*>(fde->data())) == 0xffffffff;
 
-        // Set the 'initial_location' field to address the start of the method.
-        offset_to_update = cur_offset + 2*sizeof(uint32_t);
-        const uint32_t quick_code_start = it->low_pc_;
-        (*cfi_info)[offset_to_update+0] = quick_code_start;
-        (*cfi_info)[offset_to_update+1] = quick_code_start >> 8;
-        (*cfi_info)[offset_to_update+2] = quick_code_start >> 16;
-        (*cfi_info)[offset_to_update+3] = quick_code_start >> 24;
+        // Set the 'CIE_pointer' field.
+        uint64_t CIE_pointer = cur_offset + (is_64bit ? 12 : 4);
+        uint64_t offset_to_update = CIE_pointer;
+        if (is_64bit) {
+          (*cfi_info)[offset_to_update+0] = CIE_pointer;
+          (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8;
+          (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16;
+          (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24;
+          (*cfi_info)[offset_to_update+4] = CIE_pointer >> 32;
+          (*cfi_info)[offset_to_update+5] = CIE_pointer >> 40;
+          (*cfi_info)[offset_to_update+6] = CIE_pointer >> 48;
+          (*cfi_info)[offset_to_update+7] = CIE_pointer >> 56;
+        } else {
+          (*cfi_info)[offset_to_update+0] = CIE_pointer;
+          (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8;
+          (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16;
+          (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24;
+        }
+
+        // Set the 'initial_location' field.
+        offset_to_update += is_64bit ? 8 : 4;
+        if (is_64bit) {
+          const uint64_t quick_code_start = it->low_pc_ + text_section_address;
+          (*cfi_info)[offset_to_update+0] = quick_code_start;
+          (*cfi_info)[offset_to_update+1] = quick_code_start >> 8;
+          (*cfi_info)[offset_to_update+2] = quick_code_start >> 16;
+          (*cfi_info)[offset_to_update+3] = quick_code_start >> 24;
+          (*cfi_info)[offset_to_update+4] = quick_code_start >> 32;
+          (*cfi_info)[offset_to_update+5] = quick_code_start >> 40;
+          (*cfi_info)[offset_to_update+6] = quick_code_start >> 48;
+          (*cfi_info)[offset_to_update+7] = quick_code_start >> 56;
+        } else {
+          const uint32_t quick_code_start = it->low_pc_ + text_section_address;
+          (*cfi_info)[offset_to_update+0] = quick_code_start;
+          (*cfi_info)[offset_to_update+1] = quick_code_start >> 8;
+          (*cfi_info)[offset_to_update+2] = quick_code_start >> 16;
+          (*cfi_info)[offset_to_update+3] = quick_code_start >> 24;
+        }
       }
     }
   }
 
-  if (cfi_info.get() != nullptr) {
-    // Now lay down the Elf sections.
-    ElfRawSectionBuilder debug_info(".debug_info",   SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-    ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-    ElfRawSectionBuilder debug_str(".debug_str",    SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-    ElfRawSectionBuilder eh_frame(".eh_frame",  SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
-    eh_frame.SetBuffer(std::move(*cfi_info.get()));
+  bool hasCFI = (cfi_info.get() != nullptr);
+  bool hasLineInfo = false;
+  for (auto& dbg_info : oat_writer->GetCFIMethodInfo()) {
+    if (dbg_info.dbgstream_ != nullptr &&
+        !dbg_info.compiled_method_->GetSrcMappingTable().empty()) {
+      hasLineInfo = true;
+      break;
+    }
+  }
 
-    FillInCFIInformation(oat_writer, debug_info.GetBuffer(), debug_abbrev.GetBuffer(),
-                         debug_str.GetBuffer());
-    builder.RegisterRawSection(debug_info);
-    builder.RegisterRawSection(debug_abbrev);
-    builder.RegisterRawSection(eh_frame);
-    builder.RegisterRawSection(debug_str);
+  if (hasLineInfo || hasCFI) {
+    ElfRawSectionBuilder debug_info(".debug_info",     SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+    ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+    ElfRawSectionBuilder debug_str(".debug_str",       SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+    ElfRawSectionBuilder debug_line(".debug_line",     SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+
+    FillInCFIInformation(oat_writer, debug_info.GetBuffer(),
+                         debug_abbrev.GetBuffer(), debug_str.GetBuffer(),
+                         hasLineInfo ? debug_line.GetBuffer() : nullptr,
+                         text_section_address);
+
+    builder->RegisterRawSection(debug_info);
+    builder->RegisterRawSection(debug_abbrev);
+
+    if (hasCFI) {
+      ElfRawSectionBuilder eh_frame(".eh_frame",  SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
+      eh_frame.SetBuffer(std::move(*cfi_info.get()));
+      builder->RegisterRawSection(eh_frame);
+    }
+
+    if (hasLineInfo) {
+      builder->RegisterRawSection(debug_line);
+    }
+
+    builder->RegisterRawSection(debug_str);
+  }
+}
+
+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) {}
+
+  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);
+    PushWord(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) {
+    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_;
+
+  DISALLOW_COPY_AND_ASSIGN(LineTableGenerator);
+};
+
+// TODO: rewriting it using DexFile::DecodeDebugInfo needs unneeded stuff.
+static void GetLineInfoForJava(const uint8_t* dbgstream, const SrcMap& pc2dex,
+                               SrcMap* result, uint32_t start_pc = 0) {
+  if (dbgstream == nullptr) {
+    return;
+  }
+
+  int adjopcode;
+  uint32_t dex_offset = 0;
+  uint32_t java_line = DecodeUnsignedLeb128(&dbgstream);
+
+  // skip parameters
+  for (uint32_t param_count = DecodeUnsignedLeb128(&dbgstream); param_count != 0; --param_count) {
+    DecodeUnsignedLeb128(&dbgstream);
+  }
+
+  for (bool is_end = false; is_end == false; ) {
+    uint8_t opcode = *dbgstream;
+    dbgstream++;
+    switch (opcode) {
+    case DexFile::DBG_END_SEQUENCE:
+      is_end = true;
+      break;
+
+    case DexFile::DBG_ADVANCE_PC:
+      dex_offset += DecodeUnsignedLeb128(&dbgstream);
+      break;
+
+    case DexFile::DBG_ADVANCE_LINE:
+      java_line += DecodeSignedLeb128(&dbgstream);
+      break;
+
+    case DexFile::DBG_START_LOCAL:
+    case DexFile::DBG_START_LOCAL_EXTENDED:
+      DecodeUnsignedLeb128(&dbgstream);
+      DecodeUnsignedLeb128(&dbgstream);
+      DecodeUnsignedLeb128(&dbgstream);
+
+      if (opcode == DexFile::DBG_START_LOCAL_EXTENDED) {
+        DecodeUnsignedLeb128(&dbgstream);
+      }
+      break;
+
+    case DexFile::DBG_END_LOCAL:
+    case DexFile::DBG_RESTART_LOCAL:
+      DecodeUnsignedLeb128(&dbgstream);
+      break;
+
+    case DexFile::DBG_SET_PROLOGUE_END:
+    case DexFile::DBG_SET_EPILOGUE_BEGIN:
+    case DexFile::DBG_SET_FILE:
+      break;
+
+    default:
+      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 (SrcMap::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)});
+      }
+      break;
+    }
   }
 }
 
 void ElfWriterQuick::FillInCFIInformation(OatWriter* oat_writer,
                                           std::vector<uint8_t>* dbg_info,
                                           std::vector<uint8_t>* dbg_abbrev,
-                                          std::vector<uint8_t>* dbg_str) {
+                                          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();
+
+  uint32_t producer_str_offset = PushStr(dbg_str, "Android dex2oat");
+
   // 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.
-  dbg_abbrev->push_back(1);
-  dbg_abbrev->push_back(DW_TAG_compile_unit);
+  PushByte(dbg_abbrev, 1);
+  PushByte(dbg_abbrev, DW_TAG_compile_unit);
 
   // There are children (the methods).
-  dbg_abbrev->push_back(DW_CHILDREN_yes);
+  PushByte(dbg_abbrev, 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);
 
   // DW_LANG_Java DW_FORM_data1.
-  dbg_abbrev->push_back(DW_AT_language);
-  dbg_abbrev->push_back(DW_FORM_data1);
+  PushByte(dbg_abbrev, DW_AT_language);
+  PushByte(dbg_abbrev, DW_FORM_data1);
 
   // DW_AT_low_pc DW_FORM_addr.
-  dbg_abbrev->push_back(DW_AT_low_pc);
-  dbg_abbrev->push_back(DW_FORM_addr);
+  PushByte(dbg_abbrev, DW_AT_low_pc);
+  PushByte(dbg_abbrev, DW_FORM_addr);
 
   // DW_AT_high_pc DW_FORM_addr.
-  dbg_abbrev->push_back(DW_AT_high_pc);
-  dbg_abbrev->push_back(DW_FORM_addr);
+  PushByte(dbg_abbrev, DW_AT_high_pc);
+  PushByte(dbg_abbrev, 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);
+  }
 
   // End of DW_TAG_compile_unit.
   PushHalf(dbg_abbrev, 0);
 
   // Tag 2: Compilation unit: DW_TAG_subprogram.
-  dbg_abbrev->push_back(2);
-  dbg_abbrev->push_back(DW_TAG_subprogram);
+  PushByte(dbg_abbrev, 2);
+  PushByte(dbg_abbrev, DW_TAG_subprogram);
 
   // There are no children.
-  dbg_abbrev->push_back(DW_CHILDREN_no);
+  PushByte(dbg_abbrev, DW_CHILDREN_no);
 
   // Name of the method.
-  dbg_abbrev->push_back(DW_AT_name);
-  dbg_abbrev->push_back(DW_FORM_strp);
+  PushByte(dbg_abbrev, DW_AT_name);
+  PushByte(dbg_abbrev, DW_FORM_strp);
 
   // DW_AT_low_pc DW_FORM_addr.
-  dbg_abbrev->push_back(DW_AT_low_pc);
-  dbg_abbrev->push_back(DW_FORM_addr);
+  PushByte(dbg_abbrev, DW_AT_low_pc);
+  PushByte(dbg_abbrev, DW_FORM_addr);
 
   // DW_AT_high_pc DW_FORM_addr.
-  dbg_abbrev->push_back(DW_AT_high_pc);
-  dbg_abbrev->push_back(DW_FORM_addr);
+  PushByte(dbg_abbrev, DW_AT_high_pc);
+  PushByte(dbg_abbrev, DW_FORM_addr);
 
   // End of DW_TAG_subprogram.
   PushHalf(dbg_abbrev, 0);
 
   // Start the debug_info section with the header information
   // 'unit_length' will be filled in later.
+  int cunit_length = dbg_info->size();
   PushWord(dbg_info, 0);
 
   // 'version' - 3.
@@ -1075,55 +1343,153 @@
   PushWord(dbg_info, 0);
 
   // Address size: 4.
-  dbg_info->push_back(4);
+  PushByte(dbg_info, 4);
 
   // Start the description for the compilation unit.
   // This uses tag 1.
-  dbg_info->push_back(1);
+  PushByte(dbg_info, 1);
+
+  // The producer is Android dex2oat.
+  PushWord(dbg_info, producer_str_offset);
 
   // The language is Java.
-  dbg_info->push_back(DW_LANG_Java);
+  PushByte(dbg_info, DW_LANG_Java);
 
-  // Leave space for low_pc and high_pc.
-  int low_pc_offset = dbg_info->size();
+  // low_pc and high_pc.
+  uint32_t cunit_low_pc = 0 - 1;
+  uint32_t cunit_high_pc = 0;
+  int cunit_low_pc_pos = dbg_info->size();
   PushWord(dbg_info, 0);
   PushWord(dbg_info, 0);
 
-  // Walk through the information in the method table, and enter into dbg_info.
-  const std::vector<OatWriter::DebugInfo>& dbg = oat_writer->GetCFIMethodInfo();
-  uint32_t low_pc = 0xFFFFFFFFU;
-  uint32_t high_pc = 0;
+  if (dbg_line == nullptr) {
+    for (size_t i = 0; i < method_info.size(); ++i) {
+      const OatWriter::DebugInfo &dbg = method_info[i];
 
-  for (uint32_t i = 0; i < dbg.size(); i++) {
-    const OatWriter::DebugInfo& info = dbg[i];
-    if (info.low_pc_ < low_pc) {
-      low_pc = info.low_pc_;
+      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.
+      PushWord(dbg_info, PushStr(dbg_str, dbg.method_name_));
+      PushWord(dbg_info, dbg.low_pc_ + text_section_offset);
+      PushWord(dbg_info, dbg.high_pc_ + text_section_offset);
     }
-    if (info.high_pc_ > high_pc) {
-      high_pc = info.high_pc_;
+  } else {
+    // 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
+    // a separate compilation unit for every distinct Java source.
+    // Each of the these compilation units can have several non-adjacent
+    // method ranges.
+
+    // Line number table offset
+    PushWord(dbg_info, dbg_line->size());
+
+    size_t lnt_length = dbg_line->size();
+    PushWord(dbg_line, 0);
+
+    PushHalf(dbg_line, 4);  // LNT Version DWARF v4 => 4
+
+    size_t lnt_hdr_length = dbg_line->size();
+    PushWord(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
+      }
+    }
+    PushByte(dbg_line, 0);  // End of file_names.
+
+    // Set lnt header length.
+    UpdateWord(dbg_line, lnt_hdr_length, dbg_line->size() - lnt_hdr_length - 4);
+
+    // Generate Line Number Program code, one long program for all methods.
+    LineTableGenerator line_table_generator(LINE_BASE, LINE_RANGE, OPCODE_BASE,
+                                            dbg_line, 0, 1);
+
+    SrcMap pc2java_map;
+    for (size_t i = 0; i < method_info.size(); ++i) {
+      const OatWriter::DebugInfo &dbg = method_info[i];
+      const char* file_name = (dbg.src_file_name_ == nullptr) ? "null" : dbg.src_file_name_;
+      size_t file_index = files[file_name];
+      DCHECK_NE(file_index, 0U) << file_name;
+
+      cunit_low_pc = std::min(cunit_low_pc, dbg.low_pc_);
+      cunit_high_pc = std::max(cunit_high_pc, dbg.high_pc_);
+
+      // Start a new TAG: subroutine (2).
+      PushByte(dbg_info, 2);
+
+      // Enter name, low_pc, high_pc.
+      PushWord(dbg_info, PushStr(dbg_str, dbg.method_name_));
+      PushWord(dbg_info, dbg.low_pc_ + text_section_offset);
+      PushWord(dbg_info, dbg.high_pc_ + text_section_offset);
+
+      pc2java_map.clear();
+      GetLineInfoForJava(dbg.dbgstream_, dbg.compiled_method_->GetSrcMappingTable(),
+                         &pc2java_map, dbg.low_pc_);
+      pc2java_map.DeltaFormat({dbg.low_pc_, 1}, dbg.high_pc_);
+
+      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_);
+      }
     }
 
-    // Start a new TAG: subroutine (2).
-    dbg_info->push_back(2);
+    // End Sequence should have the highest address set.
+    line_table_generator.SetAddr(cunit_high_pc + text_section_offset);
+    line_table_generator.EndSequence();
 
-    // Enter the name into the string table (and NUL terminate).
-    uint32_t str_offset = dbg_str->size();
-    dbg_str->insert(dbg_str->end(), info.method_name_.begin(), info.method_name_.end());
-    dbg_str->push_back('\0');
-
-    // Enter name, low_pc, high_pc.
-    PushWord(dbg_info, str_offset);
-    PushWord(dbg_info, info.low_pc_);
-    PushWord(dbg_info, info.high_pc_);
+    // set lnt length
+    UpdateWord(dbg_line, lnt_length, dbg_line->size() - lnt_length - 4);
   }
 
   // One byte terminator
-  dbg_info->push_back(0);
+  PushByte(dbg_info, 0);
 
-  // We have now walked all the methods.  Fill in lengths and low/high PCs.
-  UpdateWord(dbg_info, 0, dbg_info->size() - 4);
-  UpdateWord(dbg_info, low_pc_offset, low_pc);
-  UpdateWord(dbg_info, low_pc_offset + 4, high_pc);
+  // 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);
 }
 
 }  // namespace art
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index 8cfe550..c7ef872 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -48,7 +48,7 @@
   ~ElfWriterQuick() {}
 
   class ElfBuilder;
-  void WriteDebugSymbols(ElfBuilder& builder, OatWriter* oat_writer);
+  void WriteDebugSymbols(ElfBuilder* builder, OatWriter* oat_writer);
   void ReservePatchSpace(std::vector<uint8_t>* buffer, bool debug);
 
   class ElfSectionBuilder {
@@ -237,6 +237,7 @@
     }
     ~ElfBuilder() {}
 
+    bool Init();
     bool Write();
 
     // Adds the given raw section to the builder. This will copy it. The caller
@@ -253,8 +254,29 @@
 
     bool fatal_error_ = false;
 
+    // What phdr is.
+    static const uint32_t PHDR_OFFSET = sizeof(Elf32_Ehdr);
+    enum : uint8_t {
+      PH_PHDR     = 0,
+      PH_LOAD_R__ = 1,
+      PH_LOAD_R_X = 2,
+      PH_LOAD_RW_ = 3,
+      PH_DYNAMIC  = 4,
+      PH_NUM      = 5,
+    };
+    static const uint32_t PHDR_SIZE = sizeof(Elf32_Phdr) * PH_NUM;
+    Elf32_Phdr program_headers_[PH_NUM];
+
     Elf32_Ehdr elf_header_;
 
+    Elf32_Shdr null_hdr_;
+    std::string shstrtab_;
+    uint32_t section_index_;
+    std::string dynstr_;
+    uint32_t dynstr_soname_offset_;
+    std::vector<Elf32_Shdr*> section_ptrs_;
+    std::vector<Elf32_Word> hash_;
+
    public:
     ElfOatSectionBuilder text_builder_;
     ElfOatSectionBuilder rodata_builder_;
@@ -316,7 +338,8 @@
    * @param dbg_str Debug strings.
    */
   void FillInCFIInformation(OatWriter* oat_writer, std::vector<uint8_t>* dbg_info,
-                            std::vector<uint8_t>* dbg_abbrev, std::vector<uint8_t>* dbg_str);
+                            std::vector<uint8_t>* dbg_abbrev, std::vector<uint8_t>* dbg_str,
+                            std::vector<uint8_t>* dbg_line, uint32_t text_section_offset);
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick);
 };
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 1ba5d32..0fb1575 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -411,10 +411,12 @@
 
           const uint32_t quick_code_start = quick_code_offset -
               writer_->oat_header_->GetExecutableOffset();
+          const DexFile::CodeItem *code_item = it.GetMethodCodeItem();
           writer_->method_info_.push_back(DebugInfo(name,
-                                                    quick_code_start,
-                                                    quick_code_start + code_size,
-                                                    compiled_method));
+                dex_file_->GetSourceFile(dex_file_->GetClassDef(class_def_index_)),
+                quick_code_start, quick_code_start + code_size,
+                code_item == nullptr ? nullptr : dex_file_->GetDebugInfoStream(code_item),
+                compiled_method));
         }
       }
 
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index ef5fd6b..11f8bff 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -98,14 +98,18 @@
   ~OatWriter();
 
   struct DebugInfo {
-    DebugInfo(const std::string& method_name, uint32_t low_pc, uint32_t high_pc,
+    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), low_pc_(low_pc), high_pc_(high_pc),
+      : method_name_(method_name), 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.
+    const char* src_file_name_;
     uint32_t    low_pc_;
     uint32_t    high_pc_;
+    const uint8_t* dbgstream_;
     CompiledMethod* compiled_method_;
   };
 
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index bd8c27e..7269fff 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -19,6 +19,7 @@
 #include "code_generator_arm.h"
 #include "code_generator_x86.h"
 #include "code_generator_x86_64.h"
+#include "compiled_method.h"
 #include "dex/verified_method.h"
 #include "driver/dex_compilation_unit.h"
 #include "gc_map_builder.h"
@@ -297,7 +298,7 @@
   }
 }
 
-void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data) const {
+void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_map) const {
   uint32_t pc2dex_data_size = 0u;
   uint32_t pc2dex_entries = pc_infos_.Size();
   uint32_t pc2dex_offset = 0u;
@@ -305,6 +306,10 @@
   uint32_t dex2pc_data_size = 0u;
   uint32_t dex2pc_entries = 0u;
 
+  if (src_map != nullptr) {
+    src_map->reserve(pc2dex_entries);
+  }
+
   // We currently only have pc2dex entries.
   for (size_t i = 0; i < pc2dex_entries; i++) {
     struct PcInfo pc_info = pc_infos_.Get(i);
@@ -312,6 +317,9 @@
     pc2dex_data_size += SignedLeb128Size(pc_info.dex_pc - pc2dex_dalvik_offset);
     pc2dex_offset = pc_info.native_pc;
     pc2dex_dalvik_offset = pc_info.dex_pc;
+    if (src_map != nullptr) {
+      src_map->push_back(SrcMapElem({pc2dex_offset, pc2dex_dalvik_offset}));
+    }
   }
 
   uint32_t total_entries = pc2dex_entries + dex2pc_entries;
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index b31c3a3..24e0277 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -32,6 +32,7 @@
 
 class CodeGenerator;
 class DexCompilationUnit;
+class SrcMap;
 
 class CodeAllocator {
  public:
@@ -126,7 +127,7 @@
 
   void GenerateSlowPaths();
 
-  void BuildMappingTable(std::vector<uint8_t>* vector) const;
+  void BuildMappingTable(std::vector<uint8_t>* vector, SrcMap* src_map) const;
   void BuildVMapTable(std::vector<uint8_t>* vector) const;
   void BuildNativeGCMap(
       std::vector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const;
@@ -142,6 +143,7 @@
  protected:
   CodeGenerator(HGraph* graph, size_t number_of_registers)
       : frame_size_(kUninitializedFrameSize),
+        core_spill_mask_(-1),
         graph_(graph),
         block_labels_(graph->GetArena(), 0),
         pc_infos_(graph->GetArena(), 32),
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 8a5077b..fce6ab0 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -161,7 +161,10 @@
   }
 
   std::vector<uint8_t> mapping_table;
-  codegen->BuildMappingTable(&mapping_table);
+  SrcMap src_mapping_table;
+  codegen->BuildMappingTable(&mapping_table,
+          GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ?
+               &src_mapping_table : nullptr);
   std::vector<uint8_t> vmap_table;
   codegen->BuildVMapTable(&vmap_table);
   std::vector<uint8_t> gc_map;
@@ -173,6 +176,7 @@
                             codegen->GetFrameSize(),
                             codegen->GetCoreSpillMask(),
                             0, /* FPR spill mask, unused */
+                            &src_mapping_table,
                             mapping_table,
                             vmap_table,
                             gc_map,
diff --git a/compiler/utils/dwarf_cfi.cc b/compiler/utils/dwarf_cfi.cc
index b3d1a47..83e5f5a 100644
--- a/compiler/utils/dwarf_cfi.cc
+++ b/compiler/utils/dwarf_cfi.cc
@@ -65,44 +65,86 @@
   buf->push_back(0x0b);
 }
 
-void WriteFDEHeader(std::vector<uint8_t>* buf) {
+void WriteFDEHeader(std::vector<uint8_t>* buf, bool is_64bit) {
   // 'length' (filled in by other functions).
-  PushWord(buf, 0);
+  if (is_64bit) {
+    PushWord(buf, 0xffffffff);  // Indicates 64bit
+    PushWord(buf, 0);
+    PushWord(buf, 0);
+  } else {
+    PushWord(buf, 0);
+  }
 
   // 'CIE_pointer' (filled in by linker).
-  PushWord(buf, 0);
+  if (is_64bit) {
+    PushWord(buf, 0);
+    PushWord(buf, 0);
+  } else {
+    PushWord(buf, 0);
+  }
 
   // 'initial_location' (filled in by linker).
-  PushWord(buf, 0);
+  if (is_64bit) {
+    PushWord(buf, 0);
+    PushWord(buf, 0);
+  } else {
+    PushWord(buf, 0);
+  }
 
   // 'address_range' (filled in by other functions).
-  PushWord(buf, 0);
+  if (is_64bit) {
+    PushWord(buf, 0);
+    PushWord(buf, 0);
+  } else {
+    PushWord(buf, 0);
+  }
 
   // Augmentation length: 0
   buf->push_back(0);
 }
 
-void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint32_t data) {
-  const int kOffsetOfAddressRange = 12;
-  CHECK(buf->size() >= kOffsetOfAddressRange + sizeof(uint32_t));
+void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint64_t data, bool is_64bit) {
+  const size_t kOffsetOfAddressRange = is_64bit? 28 : 12;
+  CHECK(buf->size() >= kOffsetOfAddressRange + (is_64bit? 8 : 4));
 
   uint8_t *p = buf->data() + kOffsetOfAddressRange;
-  p[0] = data;
-  p[1] = data >> 8;
-  p[2] = data >> 16;
-  p[3] = data >> 24;
+  if (is_64bit) {
+    p[0] = data;
+    p[1] = data >> 8;
+    p[2] = data >> 16;
+    p[3] = data >> 24;
+    p[4] = data >> 32;
+    p[5] = data >> 40;
+    p[6] = data >> 48;
+    p[7] = data >> 56;
+  } else {
+    p[0] = data;
+    p[1] = data >> 8;
+    p[2] = data >> 16;
+    p[3] = data >> 24;
+  }
 }
 
-void WriteCFILength(std::vector<uint8_t>* buf) {
-  uint32_t length = buf->size() - 4;
+void WriteCFILength(std::vector<uint8_t>* buf, bool is_64bit) {
+  uint64_t length = is_64bit ? buf->size() - 12 : buf->size() - 4;
   DCHECK_EQ((length & 0x3), 0U);
-  DCHECK_GT(length, 4U);
 
-  uint8_t *p = buf->data();
-  p[0] = length;
-  p[1] = length >> 8;
-  p[2] = length >> 16;
-  p[3] = length >> 24;
+  uint8_t *p = is_64bit? buf->data() + 4 : buf->data();
+  if (is_64bit) {
+    p[0] = length;
+    p[1] = length >> 8;
+    p[2] = length >> 16;
+    p[3] = length >> 24;
+    p[4] = length >> 32;
+    p[5] = length >> 40;
+    p[6] = length >> 48;
+    p[7] = length >> 56;
+  } else {
+    p[0] = length;
+    p[1] = length >> 8;
+    p[2] = length >> 16;
+    p[3] = length >> 24;
+  }
 }
 
 void PadCFI(std::vector<uint8_t>* buf) {
diff --git a/compiler/utils/dwarf_cfi.h b/compiler/utils/dwarf_cfi.h
index e5acc0e..0c8b151 100644
--- a/compiler/utils/dwarf_cfi.h
+++ b/compiler/utils/dwarf_cfi.h
@@ -66,20 +66,24 @@
 /**
  * @brief Write FDE header into an FDE buffer
  * @param buf FDE buffer.
+ * @param is_64bit If FDE is for 64bit application.
  */
-void WriteFDEHeader(std::vector<uint8_t>* buf);
+void WriteFDEHeader(std::vector<uint8_t>* buf, bool is_64bit);
 
 /**
  * @brief Set 'address_range' field of an FDE buffer
  * @param buf FDE buffer.
+ * @param data Data value.
+ * @param is_64bit If FDE is for 64bit application.
  */
-void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint32_t data);
+void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint64_t data, bool is_64bit);
 
 /**
  * @brief Set 'length' field of an FDE buffer
  * @param buf FDE buffer.
+ * @param is_64bit If FDE is for 64bit application.
  */
-void WriteCFILength(std::vector<uint8_t>* buf);
+void WriteCFILength(std::vector<uint8_t>* buf, bool is_64bit);
 
 /**
  * @brief Pad an FDE buffer with 0 until its size is a multiple of 4
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 48edb15..2c9bc28 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1409,13 +1409,13 @@
 }
 
 void X86Assembler::InitializeFrameDescriptionEntry() {
-  WriteFDEHeader(&cfi_info_);
+  WriteFDEHeader(&cfi_info_, false /* is_64bit */);
 }
 
 void X86Assembler::FinalizeFrameDescriptionEntry() {
-  WriteFDEAddressRange(&cfi_info_, buffer_.Size());
+  WriteFDEAddressRange(&cfi_info_, buffer_.Size(), false /* is_64bit */);
   PadCFI(&cfi_info_);
-  WriteCFILength(&cfi_info_);
+  WriteCFILength(&cfi_info_, false /* is_64bit */);
 }
 
 constexpr size_t kFramePointerSize = 4;
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 62b72c2..1e2884a 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1716,13 +1716,13 @@
 }
 
 void X86_64Assembler::InitializeFrameDescriptionEntry() {
-  WriteFDEHeader(&cfi_info_);
+  WriteFDEHeader(&cfi_info_, true /* is_64bit */);
 }
 
 void X86_64Assembler::FinalizeFrameDescriptionEntry() {
-  WriteFDEAddressRange(&cfi_info_, buffer_.Size());
+  WriteFDEAddressRange(&cfi_info_, buffer_.Size(), true /* is_64bit */);
   PadCFI(&cfi_info_);
-  WriteCFILength(&cfi_info_);
+  WriteCFILength(&cfi_info_, true /* is_64bit */);
 }
 
 constexpr size_t kFramePointerSize = 8;
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 0ca8962..0bf758e 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -702,12 +702,24 @@
         load = true;
         immediate_bytes = 1;
         break;
+      case 0xA5:
+        opcode << "shld";
+        has_modrm = true;
+        load = true;
+        cx = true;
+        break;
       case 0xAC:
         opcode << "shrd";
         has_modrm = true;
         load = true;
         immediate_bytes = 1;
         break;
+      case 0xAD:
+        opcode << "shrd";
+        has_modrm = true;
+        load = true;
+        cx = true;
+        break;
       case 0xAE:
         if (prefix[0] == 0xF3) {
           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index eed20da..72ad9a5 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -569,6 +569,11 @@
     }
   }
 
+  t.NewTiming("Fixup Debug Sections");
+  if (!oat_file_->FixupDebugSections(delta_)) {
+    return false;
+  }
+
   return true;
 }
 
diff --git a/runtime/Android.mk b/runtime/Android.mk
index f55d3fb..1f2f86e 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -106,7 +106,7 @@
   mirror/string.cc \
   mirror/throwable.cc \
   monitor.cc \
-  native_bridge.cc \
+  native_bridge_art_interface.cc \
   native/dalvik_system_DexFile.cc \
   native/dalvik_system_VMDebug.cc \
   native/dalvik_system_VMRuntime.cc \
@@ -417,7 +417,7 @@
   LOCAL_C_INCLUDES += $$(ART_C_INCLUDES)
   LOCAL_C_INCLUDES += art/sigchainlib
 
-  LOCAL_SHARED_LIBRARIES += liblog libnativehelper
+  LOCAL_SHARED_LIBRARIES += liblog libnativehelper libnativebridge
   include external/libcxx/libcxx.mk
   LOCAL_SHARED_LIBRARIES += libbacktrace_libc++
   ifeq ($$(art_target_or_host),target)
diff --git a/runtime/arch/mips/asm_support_mips.h b/runtime/arch/mips/asm_support_mips.h
index 4db5ea6..6add93b 100644
--- a/runtime/arch/mips/asm_support_mips.h
+++ b/runtime/arch/mips/asm_support_mips.h
@@ -22,9 +22,9 @@
 // Offset of field Thread::tls32_.state_and_flags verified in InitCpu
 #define THREAD_FLAGS_OFFSET 0
 // Offset of field Thread::tlsPtr_.card_table verified in InitCpu
-#define THREAD_CARD_TABLE_OFFSET 112
+#define THREAD_CARD_TABLE_OFFSET 120
 // Offset of field Thread::tlsPtr_.exception verified in InitCpu
-#define THREAD_EXCEPTION_OFFSET 116
+#define THREAD_EXCEPTION_OFFSET 124
 
 #define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 64
 #define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 64
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index c143c5d..65a48f6 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -66,7 +66,7 @@
 #if defined(__APPLE__) && defined(__x86_64__)
 // mac symbols have a prefix of _ on x86_64
 extern "C" void _art_quick_throw_null_pointer_exception();
-extern "C" void _art_quick_throw_stack_overflow_from_signal();
+extern "C" void _art_quick_throw_stack_overflow();
 extern "C" void _art_quick_test_suspend();
 #define EXT_SYM(sym) _ ## sym
 #else
@@ -395,7 +395,7 @@
   // the previous frame.
 
   // Now arrange for the signal handler to return to art_quick_throw_stack_overflow.
-  uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow);
+  uc->CTX_EIP = reinterpret_cast<uintptr_t>(EXT_SYM(art_quick_throw_stack_overflow));
 
   return true;
 }
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 91cd11b..3ab4ef8 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2022,21 +2022,20 @@
   return mirror::Class::ComputeClassSize(false, 0, num_32, num_64, num_ref);
 }
 
-bool ClassLinker::FindOatClass(const DexFile& dex_file,
-                               uint16_t class_def_idx,
-                               OatFile::OatClass* oat_class) {
-  DCHECK(oat_class != nullptr);
+OatFile::OatClass ClassLinker::FindOatClass(const DexFile& dex_file, uint16_t class_def_idx,
+                                            bool* found) {
   DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16);
   const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
   if (oat_file == nullptr) {
-    return false;
+    *found = false;
+    return OatFile::OatClass::Invalid();
   }
   uint dex_location_checksum = dex_file.GetLocationChecksum();
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(),
                                                                     &dex_location_checksum);
   CHECK(oat_dex_file != NULL) << dex_file.GetLocation();
-  *oat_class = oat_dex_file->GetOatClass(class_def_idx);
-  return true;
+  *found = true;
+  return oat_dex_file->GetOatClass(class_def_idx);
 }
 
 static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx,
@@ -2073,8 +2072,7 @@
   return 0;
 }
 
-bool ClassLinker::FindOatMethodFor(mirror::ArtMethod* method, OatFile::OatMethod* oat_method) {
-  DCHECK(oat_method != nullptr);
+const OatFile::OatMethod ClassLinker::FindOatMethodFor(mirror::ArtMethod* method, bool* found) {
   // Although we overwrite the trampoline of non-static methods, we may get here via the resolution
   // method for direct methods (or virtual methods made direct).
   mirror::Class* declaring_class = method->GetDeclaringClass();
@@ -2101,15 +2099,14 @@
             GetOatMethodIndexFromMethodIndex(*declaring_class->GetDexCache()->GetDexFile(),
                                              method->GetDeclaringClass()->GetDexClassDefIndex(),
                                              method->GetDexMethodIndex()));
-  OatFile::OatClass oat_class;
-  if (!FindOatClass(*declaring_class->GetDexCache()->GetDexFile(),
-                    declaring_class->GetDexClassDefIndex(),
-                    &oat_class)) {
-    return false;
+  OatFile::OatClass oat_class = FindOatClass(*declaring_class->GetDexCache()->GetDexFile(),
+                                             declaring_class->GetDexClassDefIndex(),
+                                             found);
+  if (!found) {
+    return OatFile::OatMethod::Invalid();
   }
-
-  *oat_method = oat_class.GetOatMethod(oat_method_index);
-  return true;
+  *found = true;
+  return oat_class.GetOatMethod(oat_method_index);
 }
 
 // Special case to get oat code without overwriting a trampoline.
@@ -2118,9 +2115,10 @@
   if (method->IsProxyMethod()) {
     return GetQuickProxyInvokeHandler();
   }
-  OatFile::OatMethod oat_method;
+  bool found;
+  OatFile::OatMethod oat_method = FindOatMethodFor(method, &found);
   const void* result = nullptr;
-  if (FindOatMethodFor(method, &oat_method)) {
+  if (found) {
     result = oat_method.GetQuickCode();
   }
 
@@ -2146,10 +2144,11 @@
   if (method->IsProxyMethod()) {
     return GetPortableProxyInvokeHandler();
   }
-  OatFile::OatMethod oat_method;
+  bool found;
+  OatFile::OatMethod oat_method = FindOatMethodFor(method, &found);
   const void* result = nullptr;
   const void* quick_code = nullptr;
-  if (FindOatMethodFor(method, &oat_method)) {
+  if (found) {
     result = oat_method.GetPortableCode();
     quick_code = oat_method.GetQuickCode();
   }
@@ -2170,8 +2169,9 @@
 
 const void* ClassLinker::GetQuickOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx,
                                             uint32_t method_idx) {
-  OatFile::OatClass oat_class;
-  if (!FindOatClass(dex_file, class_def_idx, &oat_class)) {
+  bool found;
+  OatFile::OatClass oat_class = FindOatClass(dex_file, class_def_idx, &found);
+  if (!found) {
     return nullptr;
   }
   uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx);
@@ -2180,8 +2180,9 @@
 
 const void* ClassLinker::GetPortableOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx,
                                                uint32_t method_idx) {
-  OatFile::OatClass oat_class;
-  if (!FindOatClass(dex_file, class_def_idx, &oat_class)) {
+  bool found;
+  OatFile::OatClass oat_class = FindOatClass(dex_file, class_def_idx, &found);
+  if (!found) {
     return nullptr;
   }
   uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx);
@@ -2234,8 +2235,9 @@
   while (it.HasNextInstanceField()) {
     it.Next();
   }
-  OatFile::OatClass oat_class;
-  bool has_oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(), &oat_class);
+  bool has_oat_class;
+  OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(),
+                                             &has_oat_class);
   // Link the code of methods skipped by LinkCode.
   for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) {
     mirror::ArtMethod* method = klass->GetDirectMethod(method_index);
@@ -2386,12 +2388,16 @@
     return;  // no fields or methods - for example a marker interface
   }
 
-  OatFile::OatClass oat_class;
-  if (Runtime::Current()->IsStarted()
-      && !Runtime::Current()->UseCompileTimeClassPath()
-      && FindOatClass(dex_file, klass->GetDexClassDefIndex(), &oat_class)) {
-    LoadClassMembers(dex_file, class_data, klass, class_loader, &oat_class);
-  } else {
+
+  bool has_oat_class = false;
+  if (Runtime::Current()->IsStarted() && !Runtime::Current()->UseCompileTimeClassPath()) {
+    OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(),
+                                               &has_oat_class);
+    if (has_oat_class) {
+      LoadClassMembers(dex_file, class_data, klass, class_loader, &oat_class);
+    }
+  }
+  if (!has_oat_class) {
     LoadClassMembers(dex_file, class_data, klass, class_loader, nullptr);
   }
 }
@@ -3561,19 +3567,13 @@
       proxy_class->GetDirectMethods();
   CHECK_EQ(proxy_direct_methods->GetLength(), 16);
   mirror::ArtMethod* proxy_constructor = proxy_direct_methods->Get(2);
+  // Clone the existing constructor of Proxy (our constructor would just invoke it so steal its
+  // code_ too)
   mirror::ArtMethod* constructor = down_cast<mirror::ArtMethod*>(proxy_constructor->Clone(self));
   if (constructor == nullptr) {
     CHECK(self->IsExceptionPending());  // OOME.
     return nullptr;
   }
-  // Make the proxy constructor's code always point to the uninstrumented code. This avoids
-  // getting a method enter event for the proxy constructor as the proxy constructor doesn't
-  // have an activation.
-  bool have_portable_code;
-  constructor->SetEntryPointFromQuickCompiledCode(GetQuickOatCodeFor(proxy_constructor));
-  constructor->SetEntryPointFromPortableCompiledCode(GetPortableOatCodeFor(proxy_constructor,
-                                                                           &have_portable_code));
-
   // Make this constructor public and fix the class to be our Proxy version
   constructor->SetAccessFlags((constructor->GetAccessFlags() & ~kAccProtected) | kAccPublic);
   constructor->SetDeclaringClass(klass.Get());
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 6fc0f0e..d2c9b40 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -392,7 +392,7 @@
   }
 
  private:
-  bool FindOatMethodFor(mirror::ArtMethod* method, OatFile::OatMethod* oat_method)
+  const OatFile::OatMethod FindOatMethodFor(mirror::ArtMethod* method, bool* found)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   OatFile& GetImageOatFile(gc::space::ImageSpace* space)
@@ -461,9 +461,9 @@
 
   void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Finds the associated oat class for a dex_file and descriptor. Returns whether the class
-  // was found, and sets the data in oat_class.
-  bool FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, OatFile::OatClass* oat_class)
+  // Finds the associated oat class for a dex_file and descriptor. Returns an invalid OatClass on
+  // error and sets found to false.
+  OatFile::OatClass FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index ab4a2bb..eed6f71 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -285,19 +285,6 @@
   return StringPrintf("%s/framework/%s.jar", GetAndroidRoot(), jar_prefix.c_str());
 }
 
-std::string CommonRuntimeTest::GetLibCoreOatFileName() {
-  return GetOatFileName("core");
-}
-
-std::string CommonRuntimeTest::GetOatFileName(const std::string& oat_prefix) {
-  if (IsHost()) {
-    const char* host_dir = getenv("ANDROID_HOST_OUT");
-    CHECK(host_dir != nullptr);
-    return StringPrintf("%s/framework/%s.art", host_dir, oat_prefix.c_str());
-  }
-  return StringPrintf("%s/framework/%s.art", GetAndroidRoot(), oat_prefix.c_str());
-}
-
 std::string CommonRuntimeTest::GetTestAndroidRoot() {
   if (IsHost()) {
     const char* host_dir = getenv("ANDROID_HOST_OUT");
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index ddb6c81..1ca6eb3 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -97,12 +97,6 @@
   // Gets the path of the specified dex file for host or target.
   std::string GetDexFileName(const std::string& jar_prefix);
 
-  // Gets the path of the libcore oat file.
-  std::string GetLibCoreOatFileName();
-
-  // Gets the path of the specified oat file for host or target.
-  std::string GetOatFileName(const std::string& oat_prefix);
-
   std::string GetTestAndroidRoot();
 
   std::vector<const DexFile*> OpenTestDexFiles(const char* name)
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 6179b5e..566ce03 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1020,7 +1020,7 @@
   return nullptr;
 }
 
-struct PACKED(1) FDE {
+struct PACKED(1) FDE32 {
   uint32_t raw_length_;
   uint32_t GetLength() {
     return raw_length_ + sizeof(raw_length_);
@@ -1031,25 +1031,186 @@
   uint8_t instructions[0];
 };
 
-static FDE* NextFDE(FDE* frame) {
+static FDE32* NextFDE(FDE32* frame) {
   byte* fde_bytes = reinterpret_cast<byte*>(frame);
   fde_bytes += frame->GetLength();
-  return reinterpret_cast<FDE*>(fde_bytes);
+  return reinterpret_cast<FDE32*>(fde_bytes);
 }
 
-static bool IsFDE(FDE* frame) {
+static bool IsFDE(FDE32* frame) {
   return frame->CIE_pointer != 0;
 }
 
-// TODO This only works for 32-bit Elf Files.
-static bool FixupEHFrame(uintptr_t text_start, byte* eh_frame, size_t eh_frame_size) {
-  FDE* last_frame = reinterpret_cast<FDE*>(eh_frame + eh_frame_size);
-  FDE* frame = NextFDE(reinterpret_cast<FDE*>(eh_frame));
-  for (; frame < last_frame; frame = NextFDE(frame)) {
-    if (!IsFDE(frame)) {
+struct PACKED(1) FDE64 {
+  uint32_t raw_length_;
+  uint64_t extended_length_;
+  uint64_t GetLength() {
+    return extended_length_ + sizeof(raw_length_) + sizeof(extended_length_);
+  }
+  uint64_t CIE_pointer;
+  uint64_t initial_location;
+  uint64_t address_range;
+  uint8_t instructions[0];
+};
+
+static FDE64* NextFDE(FDE64* frame) {
+  byte* fde_bytes = reinterpret_cast<byte*>(frame);
+  fde_bytes += frame->GetLength();
+  return reinterpret_cast<FDE64*>(fde_bytes);
+}
+
+static bool IsFDE(FDE64* frame) {
+  return frame->CIE_pointer != 0;
+}
+
+static bool FixupEHFrame(off_t base_address_delta,
+                           byte* eh_frame, size_t eh_frame_size) {
+  if (*(reinterpret_cast<uint32_t*>(eh_frame)) == 0xffffffff) {
+    FDE64* last_frame = reinterpret_cast<FDE64*>(eh_frame + eh_frame_size);
+    FDE64* frame = NextFDE(reinterpret_cast<FDE64*>(eh_frame));
+    for (; frame < last_frame; frame = NextFDE(frame)) {
+      if (!IsFDE(frame)) {
+        return false;
+      }
+      frame->initial_location += base_address_delta;
+    }
+    return true;
+  } else {
+    FDE32* last_frame = reinterpret_cast<FDE32*>(eh_frame + eh_frame_size);
+    FDE32* frame = NextFDE(reinterpret_cast<FDE32*>(eh_frame));
+    for (; frame < last_frame; frame = NextFDE(frame)) {
+      if (!IsFDE(frame)) {
+        return false;
+      }
+      frame->initial_location += base_address_delta;
+    }
+    return true;
+  }
+}
+
+static uint8_t* NextLeb128(uint8_t* current) {
+  DecodeUnsignedLeb128(const_cast<const uint8_t**>(&current));
+  return current;
+}
+
+struct PACKED(1) DebugLineHeader {
+  uint32_t unit_length_;  // TODO 32-bit specific size
+  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_;
+  uint8_t opcode_base_;
+  uint8_t remaining_[0];
+
+  bool IsStandardOpcode(const uint8_t* op) const {
+    return *op != 0 && *op < opcode_base_;
+  }
+
+  bool IsExtendedOpcode(const uint8_t* op) const {
+    return *op == 0;
+  }
+
+  const uint8_t* GetStandardOpcodeLengths() const {
+    return remaining_;
+  }
+
+  uint8_t* GetNextOpcode(uint8_t* op) const {
+    if (IsExtendedOpcode(op)) {
+      uint8_t* length_field = op + 1;
+      uint32_t length = DecodeUnsignedLeb128(const_cast<const uint8_t**>(&length_field));
+      return length_field + length;
+    } else if (!IsStandardOpcode(op)) {
+      return op + 1;
+    } else if (*op == DW_LNS_fixed_advance_pc) {
+      return op + 1 + sizeof(uint16_t);
+    } else {
+      uint8_t num_args = GetStandardOpcodeLengths()[*op - 1];
+      op += 1;
+      for (int i = 0; i < num_args; i++) {
+        op = NextLeb128(op);
+      }
+      return op;
+    }
+  }
+
+  uint8_t* GetDebugLineData() const {
+    const uint8_t* hdr_start =
+        reinterpret_cast<const uint8_t*>(&header_length_) + sizeof(header_length_);
+    return const_cast<uint8_t*>(hdr_start + header_length_);
+  }
+};
+
+class DebugLineInstructionIterator {
+ public:
+  static DebugLineInstructionIterator* Create(DebugLineHeader* header, size_t section_size) {
+    std::unique_ptr<DebugLineInstructionIterator> line_iter(
+        new DebugLineInstructionIterator(header, section_size));
+    if (line_iter.get() == nullptr) {
+      return nullptr;
+    } else {
+      return line_iter.release();
+    }
+  }
+
+  ~DebugLineInstructionIterator() {}
+
+  bool Next() {
+    if (current_instruction_ == nullptr) {
       return false;
     }
-    frame->initial_location += text_start;
+    current_instruction_ = header_->GetNextOpcode(current_instruction_);
+    if (current_instruction_ >= last_instruction_) {
+      current_instruction_ = nullptr;
+      return false;
+    } else {
+      return true;
+    }
+  }
+
+  uint8_t* GetInstruction() {
+    return current_instruction_;
+  }
+
+  bool IsExtendedOpcode() {
+    return header_->IsExtendedOpcode(current_instruction_);
+  }
+
+  uint8_t GetOpcode() {
+    if (!IsExtendedOpcode()) {
+      return *current_instruction_;
+    } else {
+      uint8_t* len_ptr = current_instruction_ + 1;
+      return *NextLeb128(len_ptr);
+    }
+  }
+
+  uint8_t* GetArguments() {
+    if (!IsExtendedOpcode()) {
+      return current_instruction_ + 1;
+    } else {
+      uint8_t* len_ptr = current_instruction_ + 1;
+      return NextLeb128(len_ptr) + 1;
+    }
+  }
+
+ private:
+  DebugLineInstructionIterator(DebugLineHeader* header, size_t size)
+    : header_(header), last_instruction_(reinterpret_cast<uint8_t*>(header) + size),
+      current_instruction_(header->GetDebugLineData()) {}
+
+  DebugLineHeader* header_;
+  uint8_t* last_instruction_;
+  uint8_t* current_instruction_;
+};
+
+static bool FixupDebugLine(off_t base_offset_delta, DebugLineInstructionIterator* iter) {
+  while (iter->Next()) {
+    if (iter->IsExtendedOpcode() && iter->GetOpcode() == DW_LNE_set_address) {
+      *reinterpret_cast<uint32_t*>(iter->GetArguments()) += base_offset_delta;
+    }
   }
   return true;
 }
@@ -1189,20 +1350,29 @@
  public:
   ~DebugAbbrev() {}
   static DebugAbbrev* Create(const byte* dbg_abbrev, size_t dbg_abbrev_size) {
-    std::unique_ptr<DebugAbbrev> abbrev(new DebugAbbrev);
-    const byte* last = dbg_abbrev + dbg_abbrev_size;
-    while (dbg_abbrev < last) {
-      std::unique_ptr<DebugTag> tag(DebugTag::Create(&dbg_abbrev));
-      if (tag.get() == nullptr) {
-        return nullptr;
-      } else {
-        abbrev->tags_.insert(std::pair<uint32_t, uint32_t>(tag->index_, abbrev->tag_list_.size()));
-        abbrev->tag_list_.push_back(std::move(tag));
-      }
+    std::unique_ptr<DebugAbbrev> abbrev(new DebugAbbrev(dbg_abbrev, dbg_abbrev + dbg_abbrev_size));
+    if (!abbrev->ReadAtOffset(0)) {
+      return nullptr;
     }
     return abbrev.release();
   }
 
+  bool ReadAtOffset(uint32_t abbrev_offset) {
+    tags_.clear();
+    tag_list_.clear();
+    const byte* dbg_abbrev = begin_ + abbrev_offset;
+    while (dbg_abbrev < end_ && *dbg_abbrev != 0) {
+      std::unique_ptr<DebugTag> tag(DebugTag::Create(&dbg_abbrev));
+      if (tag.get() == nullptr) {
+        return false;
+      } else {
+        tags_.insert(std::pair<uint32_t, uint32_t>(tag->index_, tag_list_.size()));
+        tag_list_.push_back(std::move(tag));
+      }
+    }
+    return true;
+  }
+
   DebugTag* ReadTag(const byte* entry) {
     uint32_t tag_num = DecodeUnsignedLeb128(&entry);
     auto it = tags_.find(tag_num);
@@ -1215,7 +1385,9 @@
   }
 
  private:
-  DebugAbbrev() {}
+  DebugAbbrev(const byte* begin, const byte* end) : begin_(begin), end_(end) {}
+  const byte* begin_;
+  const byte* end_;
   std::map<uint32_t, uint32_t> tags_;
   std::vector<std::unique_ptr<DebugTag>> tag_list_;
 };
@@ -1239,11 +1411,21 @@
     if (current_entry_ == nullptr || current_tag_ == nullptr) {
       return false;
     }
+    bool reread_abbrev = false;
     current_entry_ += current_tag_->GetSize();
+    if (reinterpret_cast<DebugInfoHeader*>(current_entry_) >= next_cu_) {
+      current_cu_ = next_cu_;
+      next_cu_ = GetNextCu(current_cu_);
+      current_entry_ = reinterpret_cast<byte*>(current_cu_) + sizeof(DebugInfoHeader);
+      reread_abbrev = true;
+    }
     if (current_entry_ >= last_entry_) {
       current_entry_ = nullptr;
       return false;
     }
+    if (reread_abbrev) {
+      abbrev_->ReadAtOffset(current_cu_->debug_abbrev_offset);
+    }
     current_tag_ = abbrev_->ReadTag(current_entry_);
     if (current_tag_ == nullptr) {
       current_entry_ = nullptr;
@@ -1271,49 +1453,91 @@
   }
 
  private:
+  static DebugInfoHeader* GetNextCu(DebugInfoHeader* hdr) {
+    byte* hdr_byte = reinterpret_cast<byte*>(hdr);
+    return reinterpret_cast<DebugInfoHeader*>(hdr_byte + sizeof(uint32_t) + hdr->unit_length);
+  }
+
   DebugInfoIterator(DebugInfoHeader* header, size_t frame_size, DebugAbbrev* abbrev)
       : abbrev_(abbrev),
+        current_cu_(header),
+        next_cu_(GetNextCu(header)),
         last_entry_(reinterpret_cast<byte*>(header) + frame_size),
         current_entry_(reinterpret_cast<byte*>(header) + sizeof(DebugInfoHeader)),
         current_tag_(abbrev_->ReadTag(current_entry_)) {}
   DebugAbbrev* abbrev_;
+  DebugInfoHeader* current_cu_;
+  DebugInfoHeader* next_cu_;
   byte* last_entry_;
   byte* current_entry_;
   DebugTag* current_tag_;
 };
 
-static bool FixupDebugInfo(uint32_t text_start, DebugInfoIterator* iter) {
+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)) {
+      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));
     if (PC_low != nullptr && PC_high != nullptr) {
-      *PC_low  += text_start;
-      *PC_high += text_start;
+      *PC_low  += base_address_delta;
+      *PC_high += base_address_delta;
     }
   } while (iter->next());
   return true;
 }
 
-static bool FixupDebugSections(const byte* dbg_abbrev, size_t dbg_abbrev_size,
-                               uintptr_t text_start,
-                               byte* dbg_info, size_t dbg_info_size,
-                               byte* eh_frame, size_t eh_frame_size) {
-  std::unique_ptr<DebugAbbrev> abbrev(DebugAbbrev::Create(dbg_abbrev, dbg_abbrev_size));
+bool ElfFile::FixupDebugSections(off_t base_address_delta) {
+  const Elf32_Shdr* debug_info = FindSectionByName(".debug_info");
+  const Elf32_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev");
+  const Elf32_Shdr* eh_frame = FindSectionByName(".eh_frame");
+  const Elf32_Shdr* debug_str = FindSectionByName(".debug_str");
+  const Elf32_Shdr* debug_line = FindSectionByName(".debug_line");
+  const Elf32_Shdr* strtab_sec = FindSectionByName(".strtab");
+  const Elf32_Shdr* symtab_sec = FindSectionByName(".symtab");
+
+  if (debug_info == nullptr || debug_abbrev == nullptr ||
+      debug_str == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) {
+    // Release version of ART does not generate debug info.
+    return true;
+  }
+  if (base_address_delta == 0) {
+    return true;
+  }
+  if (eh_frame != nullptr &&
+      !FixupEHFrame(base_address_delta, Begin() + eh_frame->sh_offset, eh_frame->sh_size)) {
+    return false;
+  }
+
+  std::unique_ptr<DebugAbbrev> abbrev(DebugAbbrev::Create(Begin() + debug_abbrev->sh_offset,
+                                                          debug_abbrev->sh_size));
   if (abbrev.get() == nullptr) {
     return false;
   }
-  std::unique_ptr<DebugInfoIterator> iter(
-      DebugInfoIterator::Create(reinterpret_cast<DebugInfoHeader*>(dbg_info),
-                                dbg_info_size, abbrev.get()));
-  if (iter.get() == nullptr) {
+  DebugInfoHeader* info_header =
+      reinterpret_cast<DebugInfoHeader*>(Begin() + debug_info->sh_offset);
+  std::unique_ptr<DebugInfoIterator> info_iter(DebugInfoIterator::Create(info_header,
+                                                                         debug_info->sh_size,
+                                                                         abbrev.get()));
+  if (info_iter.get() == nullptr) {
     return false;
   }
-  return FixupDebugInfo(text_start, iter.get())
-      && FixupEHFrame(text_start, eh_frame, eh_frame_size);
+  if (debug_line != nullptr) {
+    DebugLineHeader* line_header =
+        reinterpret_cast<DebugLineHeader*>(Begin() + debug_line->sh_offset);
+    std::unique_ptr<DebugLineInstructionIterator> line_iter(
+        DebugLineInstructionIterator::Create(line_header, debug_line->sh_size));
+    if (line_iter.get() == nullptr) {
+      return false;
+    }
+    if (!FixupDebugLine(base_address_delta, line_iter.get())) {
+      return false;
+    }
+  }
+  return FixupDebugInfo(base_address_delta, info_iter.get());
 }
 
 void ElfFile::GdbJITSupport() {
@@ -1331,19 +1555,13 @@
   }
   ElfFile& all = *all_ptr;
 
-  // Do we have interesting sections?
-  const Elf32_Shdr* debug_info = all.FindSectionByName(".debug_info");
-  const Elf32_Shdr* debug_abbrev = all.FindSectionByName(".debug_abbrev");
+  // We need the eh_frame for gdb but debug info might be present without it.
   const Elf32_Shdr* eh_frame = all.FindSectionByName(".eh_frame");
-  const Elf32_Shdr* debug_str = all.FindSectionByName(".debug_str");
-  const Elf32_Shdr* strtab_sec = all.FindSectionByName(".strtab");
-  const Elf32_Shdr* symtab_sec = all.FindSectionByName(".symtab");
-  Elf32_Shdr* text_sec = all.FindSectionByName(".text");
-  if (debug_info == nullptr || debug_abbrev == nullptr || eh_frame == nullptr ||
-      debug_str == nullptr || text_sec == nullptr || strtab_sec == nullptr ||
-      symtab_sec == nullptr) {
+  if (eh_frame == nullptr) {
     return;
   }
+
+  // Do we have interesting sections?
   // We need to add in a strtab and symtab to the image.
   // all is MAP_PRIVATE so it can be written to freely.
   // We also already have strtab and symtab so we are fine there.
@@ -1354,13 +1572,9 @@
   elf_hdr.e_phentsize = 0;
   elf_hdr.e_type = ET_EXEC;
 
-  text_sec->sh_type = SHT_NOBITS;
-  text_sec->sh_offset = 0;
-
-  if (!FixupDebugSections(
-        all.Begin() + debug_abbrev->sh_offset, debug_abbrev->sh_size, text_sec->sh_addr,
-        all.Begin() + debug_info->sh_offset, debug_info->sh_size,
-        all.Begin() + eh_frame->sh_offset, eh_frame->sh_size)) {
+  // Since base_address_ is 0 if we are actually loaded at a known address (i.e. this is boot.oat)
+  // and the actual address stuff starts at in regular files this is good.
+  if (!all.FixupDebugSections(reinterpret_cast<intptr_t>(base_address_))) {
     LOG(ERROR) << "Failed to load GDB data";
     return;
   }
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index a966bd9..1922911 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -128,6 +128,8 @@
   // executable is true at run time, false at compile time.
   bool Load(bool executable, std::string* error_msg);
 
+  bool FixupDebugSections(off_t base_address_delta);
+
  private:
   ElfFile(File* file, bool writable, bool program_header_only);
 
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index ae42284..9c6f8c4 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -121,6 +121,13 @@
     // Do not change stubs for these methods.
     return;
   }
+  std::string temp;
+  // Note that the Proxy class itself is not a proxy class.
+  if (strcmp(method->GetDeclaringClass()->GetDescriptor(&temp), "Ljava/lang/reflect/Proxy;") == 0 &&
+      method->IsConstructor()) {
+    // Do not stub Proxy.<init>.
+    return;
+  }
   const void* new_portable_code;
   const void* new_quick_code;
   bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_;
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 9eab3fd..e085ac2 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -25,7 +25,7 @@
 #include "mirror/art_method.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
-#include "native_bridge.h"
+#include "nativebridge/native_bridge.h"
 #include "java_vm_ext.h"
 #include "parsed_options.h"
 #include "ScopedLocalRef.h"
@@ -135,7 +135,7 @@
     CHECK(NeedsNativeBridge());
 
     uint32_t len = 0;
-    return NativeBridgeGetTrampoline(handle_, symbol_name.c_str(), shorty, len);
+    return android::NativeBridgeGetTrampoline(handle_, symbol_name.c_str(), shorty, len);
   }
 
  private:
@@ -645,8 +645,8 @@
   void* handle = dlopen(path_str, RTLD_LAZY);
   bool needs_native_bridge = false;
   if (handle == nullptr) {
-    if (NativeBridgeIsSupported(path_str)) {
-      handle = NativeBridgeLoadLibrary(path_str, RTLD_LAZY);
+    if (android::NativeBridgeIsSupported(path_str)) {
+      handle = android::NativeBridgeLoadLibrary(path_str, RTLD_LAZY);
       needs_native_bridge = true;
     }
   }
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index b7d485e..1c870cd 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -43,7 +43,6 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/string-inl.h"
 #include "mirror/throwable.h"
-#include "native_bridge.h"
 #include "parsed_options.h"
 #include "reflection.h"
 #include "runtime.h"
diff --git a/runtime/leb128.h b/runtime/leb128.h
index 89de16e..dfb42b8 100644
--- a/runtime/leb128.h
+++ b/runtime/leb128.h
@@ -137,25 +137,26 @@
   return dest;
 }
 
-// An encoder with an API similar to vector<uint32_t> where the data is captured in ULEB128 format.
-class Leb128EncodingVector {
+// An encoder that pushed uint32_t data onto the given std::vector.
+class Leb128Encoder {
  public:
-  Leb128EncodingVector() {
+  explicit Leb128Encoder(std::vector<uint8_t>* data) : data_(data) {
+    DCHECK(data != nullptr);
   }
 
   void Reserve(uint32_t size) {
-    data_.reserve(size);
+    data_->reserve(size);
   }
 
   void PushBackUnsigned(uint32_t value) {
     uint8_t out = value & 0x7f;
     value >>= 7;
     while (value != 0) {
-      data_.push_back(out | 0x80);
+      data_->push_back(out | 0x80);
       out = value & 0x7f;
       value >>= 7;
     }
-    data_.push_back(out);
+    data_->push_back(out);
   }
 
   template<typename It>
@@ -169,12 +170,12 @@
     uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
     uint8_t out = value & 0x7f;
     while (extra_bits != 0u) {
-      data_.push_back(out | 0x80);
+      data_->push_back(out | 0x80);
       value >>= 7;
       out = value & 0x7f;
       extra_bits >>= 7;
     }
-    data_.push_back(out);
+    data_->push_back(out);
   }
 
   template<typename It>
@@ -185,12 +186,23 @@
   }
 
   const std::vector<uint8_t>& GetData() const {
-    return data_;
+    return *data_;
+  }
+
+ protected:
+  std::vector<uint8_t>* const data_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Leb128Encoder);
+};
+
+// An encoder with an API similar to vector<uint32_t> where the data is captured in ULEB128 format.
+class Leb128EncodingVector FINAL : private std::vector<uint8_t>, public Leb128Encoder {
+ public:
+  Leb128EncodingVector() : Leb128Encoder(this) {
   }
 
  private:
-  std::vector<uint8_t> data_;
-
   DISALLOW_COPY_AND_ASSIGN(Leb128EncodingVector);
 };
 
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 3543654..a1177d6 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -162,7 +162,8 @@
         break;
       }
       case LockWord::kThinLocked: {
-        // Inflate the thin lock to a monitor and stick the hash code inside of the monitor.
+        // Inflate the thin lock to a monitor and stick the hash code inside of the monitor. May
+        // fail spuriously.
         Thread* self = Thread::Current();
         StackHandleScope<1> hs(self);
         Handle<mirror::Object> h_this(hs.NewHandle(current_this));
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 7118af1..5dd16ef 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -176,10 +176,6 @@
   // Deflated monitors have a null object.
 }
 
-/*
- * Links a thread into a monitor's wait set.  The monitor lock must be
- * held by the caller of this routine.
- */
 void Monitor::AppendToWaitSet(Thread* thread) {
   DCHECK(owner_ == Thread::Current());
   DCHECK(thread != NULL);
@@ -197,10 +193,6 @@
   t->SetWaitNext(thread);
 }
 
-/*
- * Unlinks a thread from a monitor's wait set.  The monitor lock must
- * be held by the caller of this routine.
- */
 void Monitor::RemoveFromWaitSet(Thread *thread) {
   DCHECK(owner_ == Thread::Current());
   DCHECK(thread != NULL);
@@ -395,29 +387,6 @@
   return true;
 }
 
-/*
- * Wait on a monitor until timeout, interrupt, or notification.  Used for
- * Object.wait() and (somewhat indirectly) Thread.sleep() and Thread.join().
- *
- * If another thread calls Thread.interrupt(), we throw InterruptedException
- * and return immediately if one of the following are true:
- *  - blocked in wait(), wait(long), or wait(long, int) methods of Object
- *  - blocked in join(), join(long), or join(long, int) methods of Thread
- *  - blocked in sleep(long), or sleep(long, int) methods of Thread
- * Otherwise, we set the "interrupted" flag.
- *
- * Checks to make sure that "ns" is in the range 0-999999
- * (i.e. fractions of a millisecond) and throws the appropriate
- * exception if it isn't.
- *
- * The spec allows "spurious wakeups", and recommends that all code using
- * Object.wait() do so in a loop.  This appears to derive from concerns
- * about pthread_cond_wait() on multiprocessor systems.  Some commentary
- * on the web casts doubt on whether these can/should occur.
- *
- * Since we're allowed to wake up "early", we clamp extremely long durations
- * to return at the end of the 32-bit time epoch.
- */
 void Monitor::Wait(Thread* self, int64_t ms, int32_t ns,
                    bool interruptShouldThrow, ThreadState why) {
   DCHECK(self != NULL);
@@ -641,11 +610,6 @@
   return true;
 }
 
-/*
- * Changes the shape of a monitor from thin to fat, preserving the internal lock state. The calling
- * thread must own the lock or the owner must be suspended. There's a race with other threads
- * inflating the lock and so the caller should read the monitor following the call.
- */
 void Monitor::Inflate(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code) {
   DCHECK(self != nullptr);
   DCHECK(obj != nullptr);
@@ -823,38 +787,37 @@
   }
 }
 
-/*
- * Object.wait().  Also called for class init.
- */
 void Monitor::Wait(Thread* self, mirror::Object *obj, int64_t ms, int32_t ns,
                    bool interruptShouldThrow, ThreadState why) {
   DCHECK(self != nullptr);
   DCHECK(obj != nullptr);
   LockWord lock_word = obj->GetLockWord(true);
-  switch (lock_word.GetState()) {
-    case LockWord::kHashCode:
-      // Fall-through.
-    case LockWord::kUnlocked:
-      ThrowIllegalMonitorStateExceptionF("object not locked by thread before wait()");
-      return;  // Failure.
-    case LockWord::kThinLocked: {
-      uint32_t thread_id = self->GetThreadId();
-      uint32_t owner_thread_id = lock_word.ThinLockOwner();
-      if (owner_thread_id != thread_id) {
+  while (lock_word.GetState() != LockWord::kFatLocked) {
+    switch (lock_word.GetState()) {
+      case LockWord::kHashCode:
+        // Fall-through.
+      case LockWord::kUnlocked:
         ThrowIllegalMonitorStateExceptionF("object not locked by thread before wait()");
         return;  // Failure.
-      } else {
-        // We own the lock, inflate to enqueue ourself on the Monitor.
-        Inflate(self, self, obj, 0);
-        lock_word = obj->GetLockWord(true);
+      case LockWord::kThinLocked: {
+        uint32_t thread_id = self->GetThreadId();
+        uint32_t owner_thread_id = lock_word.ThinLockOwner();
+        if (owner_thread_id != thread_id) {
+          ThrowIllegalMonitorStateExceptionF("object not locked by thread before wait()");
+          return;  // Failure.
+        } else {
+          // We own the lock, inflate to enqueue ourself on the Monitor. May fail spuriously so
+          // re-load.
+          Inflate(self, self, obj, 0);
+          lock_word = obj->GetLockWord(true);
+        }
+        break;
       }
-      break;
-    }
-    case LockWord::kFatLocked:
-      break;  // Already set for a wait.
-    default: {
-      LOG(FATAL) << "Invalid monitor state " << lock_word.GetState();
-      return;
+      case LockWord::kFatLocked:  // Unreachable given the loop condition above. Fall-through.
+      default: {
+        LOG(FATAL) << "Invalid monitor state " << lock_word.GetState();
+        return;
+      }
     }
   }
   Monitor* mon = lock_word.FatLockMonitor();
diff --git a/runtime/monitor.h b/runtime/monitor.h
index e8321eb..efa83c7 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -74,6 +74,8 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DoNotify(self, obj, true);
   }
+
+  // Object.wait().  Also called for class init.
   static void Wait(Thread* self, mirror::Object* obj, int64_t ms, int32_t ns,
                    bool interruptShouldThrow, ThreadState why)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -119,6 +121,7 @@
     return monitor_id_;
   }
 
+  // Inflate the lock on obj. May fail to inflate for spurious reasons, always re-check.
   static void InflateThinLocked(Thread* self, Handle<mirror::Object> obj, LockWord lock_word,
                                 uint32_t hash_code) NO_THREAD_SAFETY_ANALYSIS;
 
@@ -137,9 +140,18 @@
       LOCKS_EXCLUDED(monitor_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Links a thread into a monitor's wait set.  The monitor lock must be held by the caller of this
+  // routine.
   void AppendToWaitSet(Thread* thread) EXCLUSIVE_LOCKS_REQUIRED(monitor_lock_);
+
+  // Unlinks a thread from a monitor's wait set.  The monitor lock must be held by the caller of
+  // this routine.
   void RemoveFromWaitSet(Thread* thread) EXCLUSIVE_LOCKS_REQUIRED(monitor_lock_);
 
+  // Changes the shape of a monitor from thin to fat, preserving the internal lock state. The
+  // calling thread must own the lock or the owner must be suspended. There's a race with other
+  // threads inflating the lock, installing hash codes and spurious failures. The caller should
+  // re-read the lock word following the call.
   static void Inflate(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -170,6 +182,25 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 
+  // Wait on a monitor until timeout, interrupt, or notification.  Used for Object.wait() and
+  // (somewhat indirectly) Thread.sleep() and Thread.join().
+  //
+  // If another thread calls Thread.interrupt(), we throw InterruptedException and return
+  // immediately if one of the following are true:
+  //  - blocked in wait(), wait(long), or wait(long, int) methods of Object
+  //  - blocked in join(), join(long), or join(long, int) methods of Thread
+  //  - blocked in sleep(long), or sleep(long, int) methods of Thread
+  // Otherwise, we set the "interrupted" flag.
+  //
+  // Checks to make sure that "ns" is in the range 0-999999 (i.e. fractions of a millisecond) and
+  // throws the appropriate exception if it isn't.
+  //
+  // The spec allows "spurious wakeups", and recommends that all code using Object.wait() do so in
+  // a loop.  This appears to derive from concerns about pthread_cond_wait() on multiprocessor
+  // systems.  Some commentary on the web casts doubt on whether these can/should occur.
+  //
+  // Since we're allowed to wake up "early", we clamp extremely long durations to return at the end
+  // of the 32-bit time epoch.
   void Wait(Thread* self, int64_t msec, int32_t nsec, bool interruptShouldThrow, ThreadState why)
       LOCKS_EXCLUDED(monitor_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/native_bridge.cc b/runtime/native_bridge.cc
deleted file mode 100644
index d0b516b..0000000
--- a/runtime/native_bridge.cc
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * 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.
- */
-
-#include "native_bridge.h"
-
-#include <dlfcn.h>
-#include <stdio.h>
-#include "jni.h"
-
-#include "base/mutex.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
-#include "ScopedLocalRef.h"
-#include "thread.h"
-
-#ifdef HAVE_ANDROID_OS
-#include "cutils/properties.h"
-#endif
-
-
-namespace art {
-
-// The symbol name exposed by native-bridge with the type of NativeBridgeCallbacks.
-static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf";
-
-// The library name we are supposed to load.
-static std::string native_bridge_library_string = "";
-
-// Whether a native bridge is available (loaded and ready).
-static bool available = false;
-// Whether we have already initialized (or tried to).
-static bool initialized = false;
-
-struct NativeBridgeCallbacks;
-static NativeBridgeCallbacks* callbacks = nullptr;
-
-// ART interfaces to native-bridge.
-struct NativeBridgeArtCallbacks {
-  // Get shorty of a Java method. The shorty is supposed to be persistent in memory.
-  //
-  // Parameters:
-  //   env [IN] pointer to JNIenv.
-  //   mid [IN] Java methodID.
-  // Returns:
-  //   short descriptor for method.
-  const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
-
-  // Get number of native methods for specified class.
-  //
-  // Parameters:
-  //   env [IN] pointer to JNIenv.
-  //   clazz [IN] Java class object.
-  // Returns:
-  //   number of native methods.
-  uint32_t (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
-
-  // Get at most 'method_count' native methods for specified class 'clazz'. Results are outputed
-  // via 'methods' [OUT]. The signature pointer in JNINativeMethod is reused as the method shorty.
-  //
-  // Parameters:
-  //   env [IN] pointer to JNIenv.
-  //   clazz [IN] Java class object.
-  //   methods [OUT] array of method with the name, shorty, and fnPtr.
-  //   method_count [IN] max number of elements in methods.
-  // Returns:
-  //   number of method it actually wrote to methods.
-  uint32_t (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
-                               uint32_t method_count);
-};
-
-// Native-bridge interfaces to ART
-struct NativeBridgeCallbacks {
-  // Initialize native-bridge. Native-bridge's internal implementation must ensure MT safety and
-  // that the native-bridge is initialized only once. Thus it is OK to call this interface for an
-  // already initialized native-bridge.
-  //
-  // Parameters:
-  //   art_cbs [IN] the pointer to NativeBridgeArtCallbacks.
-  // Returns:
-  //   true iff initialization was successful.
-  bool (*initialize)(NativeBridgeArtCallbacks* art_cbs);
-
-  // Load a shared library that is supported by the native-bridge.
-  //
-  // Parameters:
-  //   libpath [IN] path to the shared library
-  //   flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
-  // Returns:
-  //   The opaque handle of the shared library if sucessful, otherwise NULL
-  void* (*loadLibrary)(const char* libpath, int flag);
-
-  // Get a native-bridge trampoline for specified native method. The trampoline has same
-  // sigature as the native method.
-  //
-  // Parameters:
-  //   handle [IN] the handle returned from loadLibrary
-  //   shorty [IN] short descriptor of native method
-  //   len [IN] length of shorty
-  // Returns:
-  //   address of trampoline if successful, otherwise NULL
-  void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
-
-  // Check whether native library is valid and is for an ABI that is supported by native-bridge.
-  //
-  // Parameters:
-  //   libpath [IN] path to the shared library
-  // Returns:
-  //   TRUE if library is supported by native-bridge, FALSE otherwise
-  bool (*isSupported)(const char* libpath);
-};
-
-static const char* GetMethodShorty(JNIEnv* env, jmethodID mid) {
-  ScopedObjectAccess soa(env);
-  StackHandleScope<1> scope(soa.Self());
-  mirror::ArtMethod* m = soa.DecodeMethod(mid);
-  MethodHelper mh(scope.NewHandle(m));
-  return mh.GetShorty();
-}
-
-static uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) {
-  if (clazz == nullptr)
-    return 0;
-
-  ScopedObjectAccess soa(env);
-  mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
-
-  uint32_t native_method_count = 0;
-  for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
-    mirror::ArtMethod* m = c->GetDirectMethod(i);
-    if (m->IsNative()) {
-      native_method_count++;
-    }
-  }
-  for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
-    mirror::ArtMethod* m = c->GetVirtualMethod(i);
-    if (m->IsNative()) {
-      native_method_count++;
-    }
-  }
-  return native_method_count;
-}
-
-static uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
-                               uint32_t method_count) {
-  if ((clazz == nullptr) || (methods == nullptr)) {
-    return 0;
-  }
-  ScopedObjectAccess soa(env);
-  mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
-
-  uint32_t count = 0;
-  for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
-    mirror::ArtMethod* m = c->GetDirectMethod(i);
-    if (m->IsNative()) {
-      if (count < method_count) {
-        methods[count].name = m->GetName();
-        methods[count].signature = m->GetShorty();
-        methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
-        count++;
-      } else {
-        LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
-      }
-    }
-  }
-  for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
-    mirror::ArtMethod* m = c->GetVirtualMethod(i);
-    if (m->IsNative()) {
-      if (count < method_count) {
-        methods[count].name = m->GetName();
-        methods[count].signature = m->GetShorty();
-        methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
-        count++;
-      } else {
-        LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
-      }
-    }
-  }
-  return count;
-}
-
-static NativeBridgeArtCallbacks NativeBridgeArtItf = {
-  GetMethodShorty,
-  GetNativeMethodCount,
-  GetNativeMethods
-};
-
-void SetNativeBridgeLibraryString(const std::string& nb_library_string) {
-  // This is called when the runtime starts and nothing is working concurrently
-  // so we don't need a lock here.
-
-  native_bridge_library_string = nb_library_string;
-
-  if (native_bridge_library_string.empty()) {
-    initialized = true;
-    available = false;
-  }
-}
-
-static bool NativeBridgeInitialize() {
-  // TODO: Missing annotalysis static lock ordering of DEFAULT_MUTEX_ACQUIRED, place lock into
-  // global order or remove.
-  static Mutex lock("native bridge lock");
-  MutexLock mu(Thread::Current(), lock);
-
-  if (initialized) {
-    // Somebody did it before.
-    return available;
-  }
-
-  available = false;
-
-  void* handle = dlopen(native_bridge_library_string.c_str(), RTLD_LAZY);
-  if (handle != nullptr) {
-    callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
-                                                               kNativeBridgeInterfaceSymbol));
-
-    if (callbacks != nullptr) {
-      available = callbacks->initialize(&NativeBridgeArtItf);
-    }
-
-    if (!available) {
-      dlclose(handle);
-    }
-  }
-
-  initialized = true;
-
-  return available;
-}
-
-void* NativeBridgeLoadLibrary(const char* libpath, int flag) {
-  if (NativeBridgeInitialize()) {
-    return callbacks->loadLibrary(libpath, flag);
-  }
-  return nullptr;
-}
-
-void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty,
-                                  uint32_t len) {
-  if (NativeBridgeInitialize()) {
-    return callbacks->getTrampoline(handle, name, shorty, len);
-  }
-  return nullptr;
-}
-
-bool NativeBridgeIsSupported(const char* libpath) {
-  if (NativeBridgeInitialize()) {
-    return callbacks->isSupported(libpath);
-  }
-  return false;
-}
-
-};  // namespace art
diff --git a/runtime/native_bridge.h b/runtime/native_bridge.h
deleted file mode 100644
index be647fc..0000000
--- a/runtime/native_bridge.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ART_RUNTIME_NATIVE_BRIDGE_H_
-#define ART_RUNTIME_NATIVE_BRIDGE_H_
-
-#include <string>
-
-namespace art {
-
-// Initialize the native bridge, if any. Should be called by Runtime::Init(). An empty string
-// signals that we do not want to load a native bridge.
-void SetNativeBridgeLibraryString(const std::string& native_bridge_library_string);
-
-// Load a shared library that is supported by the native-bridge.
-void* NativeBridgeLoadLibrary(const char* libpath, int flag);
-
-// Get a native-bridge trampoline for specified native method.
-void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
-
-// True if native library is valid and is for an ABI that is supported by native-bridge.
-bool NativeBridgeIsSupported(const char* libpath);
-
-};  // namespace art
-
-#endif  // ART_RUNTIME_NATIVE_BRIDGE_H_
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
new file mode 100644
index 0000000..453c92f
--- /dev/null
+++ b/runtime/native_bridge_art_interface.cc
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#include "native_bridge_art_interface.h"
+
+#include "mirror/art_method-inl.h"
+#include "mirror/class-inl.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+
+const char* GetMethodShorty(JNIEnv* env, jmethodID mid) {
+  ScopedObjectAccess soa(env);
+  StackHandleScope<1> scope(soa.Self());
+  mirror::ArtMethod* m = soa.DecodeMethod(mid);
+  MethodHelper mh(scope.NewHandle(m));
+  return mh.GetShorty();
+}
+
+uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) {
+  if (clazz == nullptr)
+    return 0;
+
+  ScopedObjectAccess soa(env);
+  mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
+
+  uint32_t native_method_count = 0;
+  for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
+    mirror::ArtMethod* m = c->GetDirectMethod(i);
+    if (m->IsNative()) {
+      native_method_count++;
+    }
+  }
+  for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
+    mirror::ArtMethod* m = c->GetVirtualMethod(i);
+    if (m->IsNative()) {
+      native_method_count++;
+    }
+  }
+  return native_method_count;
+}
+
+uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
+                          uint32_t method_count) {
+  if ((clazz == nullptr) || (methods == nullptr)) {
+    return 0;
+  }
+  ScopedObjectAccess soa(env);
+  mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
+
+  uint32_t count = 0;
+  for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
+    mirror::ArtMethod* m = c->GetDirectMethod(i);
+    if (m->IsNative()) {
+      if (count < method_count) {
+        methods[count].name = m->GetName();
+        methods[count].signature = m->GetShorty();
+        methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
+        count++;
+      } else {
+        LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
+      }
+    }
+  }
+  for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
+    mirror::ArtMethod* m = c->GetVirtualMethod(i);
+    if (m->IsNative()) {
+      if (count < method_count) {
+        methods[count].name = m->GetName();
+        methods[count].signature = m->GetShorty();
+        methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
+        count++;
+      } else {
+        LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
+      }
+    }
+  }
+  return count;
+}
+
+};  // namespace art
diff --git a/runtime/native_bridge_art_interface.h b/runtime/native_bridge_art_interface.h
new file mode 100644
index 0000000..08735c8
--- /dev/null
+++ b/runtime/native_bridge_art_interface.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_NATIVE_BRIDGE_ART_INTERFACE_H_
+#define ART_RUNTIME_NATIVE_BRIDGE_ART_INTERFACE_H_
+
+#include <jni.h>
+#include <stdint.h>
+
+namespace art {
+
+const char* GetMethodShorty(JNIEnv* env, jmethodID mid);
+
+uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz);
+
+uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
+                          uint32_t method_count);
+
+};  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_BRIDGE_ART_INTERFACE_H_
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 971daf8..b74b10f 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -460,15 +460,17 @@
   uint32_t bitmap_size = 0;
   const byte* bitmap_pointer = nullptr;
   const byte* methods_pointer = nullptr;
-  if (type == kOatClassSomeCompiled) {
-    bitmap_size = static_cast<uint32_t>(*reinterpret_cast<const uint32_t*>(after_type_pointer));
-    bitmap_pointer = after_type_pointer + sizeof(bitmap_size);
-    CHECK_LE(bitmap_pointer, oat_file_->End()) << oat_file_->GetLocation();
-    methods_pointer = bitmap_pointer + bitmap_size;
-  } else {
-    methods_pointer = after_type_pointer;
+  if (type != kOatClassNoneCompiled) {
+    if (type == kOatClassSomeCompiled) {
+      bitmap_size = static_cast<uint32_t>(*reinterpret_cast<const uint32_t*>(after_type_pointer));
+      bitmap_pointer = after_type_pointer + sizeof(bitmap_size);
+      CHECK_LE(bitmap_pointer, oat_file_->End()) << oat_file_->GetLocation();
+      methods_pointer = bitmap_pointer + bitmap_size;
+    } else {
+      methods_pointer = after_type_pointer;
+    }
+    CHECK_LE(methods_pointer, oat_file_->End()) << oat_file_->GetLocation();
   }
-  CHECK_LE(methods_pointer, oat_file_->End()) << oat_file_->GetLocation();
 
   return OatClass(oat_file_,
                   status,
@@ -486,22 +488,23 @@
                             const OatMethodOffsets* methods_pointer)
     : oat_file_(oat_file), status_(status), type_(type),
       bitmap_(bitmap_pointer), methods_pointer_(methods_pointer) {
-    CHECK(methods_pointer != nullptr);
     switch (type_) {
       case kOatClassAllCompiled: {
         CHECK_EQ(0U, bitmap_size);
         CHECK(bitmap_pointer == nullptr);
+        CHECK(methods_pointer != nullptr);
         break;
       }
       case kOatClassSomeCompiled: {
         CHECK_NE(0U, bitmap_size);
         CHECK(bitmap_pointer != nullptr);
+        CHECK(methods_pointer != nullptr);
         break;
       }
       case kOatClassNoneCompiled: {
         CHECK_EQ(0U, bitmap_size);
         CHECK(bitmap_pointer == nullptr);
-        methods_pointer_ = nullptr;
+        CHECK(methods_pointer_ == nullptr);
         break;
       }
       case kOatClassMax: {
@@ -536,16 +539,6 @@
       oat_method_offsets.gc_map_offset_);
 }
 
-OatFile::OatMethod::OatMethod(const byte* base,
-                              const uint32_t code_offset,
-                              const uint32_t gc_map_offset)
-  : begin_(base),
-    code_offset_(code_offset),
-    native_gc_map_offset_(gc_map_offset) {
-}
-
-OatFile::OatMethod::~OatMethod() {}
-
 
 uint32_t OatFile::OatMethod::GetQuickCodeSize() const {
   uintptr_t code = reinterpret_cast<uintptr_t>(GetQuickCode());
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 810eccb..508bfc2 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -126,14 +126,19 @@
     const uint8_t* GetMappingTable() const;
     const uint8_t* GetVmapTable() const;
 
-    ~OatMethod();
-
     // Create an OatMethod with offsets relative to the given base address
-    OatMethod(const byte* base,
-              const uint32_t code_offset,
-              const uint32_t gc_map_offset);
+    OatMethod(const byte* base, const uint32_t code_offset, const uint32_t gc_map_offset)
+      : begin_(base),
+        code_offset_(code_offset),
+        native_gc_map_offset_(gc_map_offset) {
+    }
+    ~OatMethod() {}
 
-    OatMethod() {}
+    // A representation of an invalid OatMethod, used when an OatMethod or OatClass can't be found.
+    // See ClassLinker::FindOatMethodFor.
+    static const OatMethod Invalid() {
+      return OatMethod(nullptr, -1, -1);
+    }
 
    private:
     template<class T>
@@ -144,10 +149,10 @@
       return reinterpret_cast<T>(begin_ + offset);
     }
 
-    const byte* begin_;
+    const byte* const begin_;
 
-    uint32_t code_offset_;
-    uint32_t native_gc_map_offset_;
+    const uint32_t code_offset_;
+    const uint32_t native_gc_map_offset_;
 
     friend class OatClass;
   };
@@ -168,7 +173,12 @@
     // methods are not included.
     const OatMethod GetOatMethod(uint32_t method_index) const;
 
-    OatClass() {}
+    // A representation of an invalid OatClass, used when an OatClass can't be found.
+    // See ClassLinker::FindOatClass.
+    static OatClass Invalid() {
+      return OatClass(nullptr, mirror::Class::kStatusError, kOatClassNoneCompiled, 0, nullptr,
+                      nullptr);
+    }
 
    private:
     OatClass(const OatFile* oat_file,
@@ -178,15 +188,15 @@
              const uint32_t* bitmap_pointer,
              const OatMethodOffsets* methods_pointer);
 
-    const OatFile* oat_file_;
+    const OatFile* const oat_file_;
 
-    mirror::Class::Status status_;
+    const mirror::Class::Status status_;
 
-    OatClassType type_;
+    const OatClassType type_;
 
-    const uint32_t* bitmap_;
+    const uint32_t* const bitmap_;
 
-    const OatMethodOffsets* methods_pointer_;
+    const OatMethodOffsets* const methods_pointer_;
 
     friend class OatDexFile;
   };
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 27f7765..a023ff1 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -609,7 +609,7 @@
         return false;
       }
     } else if (StartsWith(option, "-XX:NativeBridge=")) {
-      if (!ParseStringAfterChar(option, '=', &native_bridge_library_string_)) {
+      if (!ParseStringAfterChar(option, '=', &native_bridge_library_path_)) {
         return false;
       }
     } else if (StartsWith(option, "-ea") ||
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index aa2c557..1afd610 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -46,7 +46,7 @@
   bool check_jni_;
   bool force_copy_;
   std::string jni_trace_;
-  std::string native_bridge_library_string_;
+  std::string native_bridge_library_path_;
   CompilerCallbacks* compiler_callbacks_;
   bool is_zygote_;
   bool must_relocate_;
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index 5af26b0..d977ce9 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -17,14 +17,14 @@
 #include <jni.h>
 #include <vector>
 
-#include "common_runtime_test.h"
+#include "common_compiler_test.h"
 #include "field_helper.h"
 #include "mirror/art_field-inl.h"
 #include "scoped_thread_state_change.h"
 
 namespace art {
 
-class ProxyTest : public CommonRuntimeTest {
+class ProxyTest : public CommonCompilerTest {
  public:
   // Generate a proxy class with the given name and interfaces. This is a simplification from what
   // libcore does to fit to our test needs. We do not check for duplicated interfaces or methods and
@@ -103,12 +103,6 @@
     soa.Self()->AssertNoPendingException();
     return proxyClass;
   }
-
- protected:
-  void SetUpRuntimeOptions(RuntimeOptions *options) OVERRIDE {
-    options->push_back(std::make_pair(StringPrintf("-Ximage:%s", GetLibCoreOatFileName().c_str()),
-                                      nullptr));
-  }
 };
 
 // Creates a proxy class and check ClassHelper works correctly.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index d3957c1..05003cb 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -63,7 +63,7 @@
 #include "mirror/stack_trace_element.h"
 #include "mirror/throwable.h"
 #include "monitor.h"
-#include "native_bridge.h"
+#include "native_bridge_art_interface.h"
 #include "parsed_options.h"
 #include "oat_file.h"
 #include "quick/quick_method_frame_info.h"
@@ -143,7 +143,8 @@
       target_sdk_version_(0),
       implicit_null_checks_(false),
       implicit_so_checks_(false),
-      implicit_suspend_checks_(false) {
+      implicit_suspend_checks_(false),
+      native_bridge_art_callbacks_({GetMethodShorty, GetNativeMethodCount, GetNativeMethods}) {
 }
 
 Runtime::~Runtime() {
@@ -708,8 +709,11 @@
   self->ClearException();
 
   // Look for a native bridge.
-  SetNativeBridgeLibraryString(options->native_bridge_library_string_);
-
+  native_bridge_library_path_ = options->native_bridge_library_path_;
+  if (!native_bridge_library_path_.empty()) {
+    android::SetupNativeBridge(native_bridge_library_path_.c_str(), &native_bridge_art_callbacks_);
+    VLOG(startup) << "Runtime::Setup native bridge library: " << native_bridge_library_path_;
+  }
   VLOG(startup) << "Runtime::Init exiting";
   return true;
 }
diff --git a/runtime/runtime.h b/runtime/runtime.h
index e76280a..34ccdcb 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -31,6 +31,7 @@
 #include "instrumentation.h"
 #include "instruction_set.h"
 #include "jobject_comparator.h"
+#include "nativebridge/native_bridge.h"
 #include "object_callbacks.h"
 #include "offsets.h"
 #include "profiler_options.h"
@@ -616,6 +617,25 @@
   bool implicit_so_checks_;         // StackOverflow checks are implicit.
   bool implicit_suspend_checks_;    // Thread suspension checks are implicit.
 
+  // The path to the native bridge library. If this is not empty the native bridge will be
+  // initialized and loaded from the pointed path.
+  //
+  // The native bridge allows running native code compiled for a foreign ISA. The way it works is,
+  // if standard dlopen fails to load native library associated with native activity, it calls to
+  // the native bridge to load it and then gets the trampoline for the entry to native activity.
+  std::string native_bridge_library_path_;
+
+  // Native bridge library runtime callbacks. They represent the runtime interface to native bridge.
+  //
+  // The interface is expected to expose the following methods:
+  // getMethodShorty(): in the case of native method calling JNI native function CallXXXXMethodY(),
+  //   native bridge calls back to VM for the shorty of the method so that it can prepare based on
+  //   host calling convention.
+  // getNativeMethodCount() and getNativeMethods(): in case of JNI function UnregisterNatives(),
+  //   native bridge can call back to get all native methods of specified class so that all
+  //   corresponding trampolines can be destroyed.
+  android::NativeBridgeRuntimeCallbacks native_bridge_art_callbacks_;
+
   DISALLOW_COPY_AND_ASSIGN(Runtime);
 };
 
diff --git a/runtime/utils.cc b/runtime/utils.cc
index b845f50..b55977b 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1372,21 +1372,11 @@
 }
 
 void EncodeUnsignedLeb128(uint32_t data, std::vector<uint8_t>* dst) {
-  size_t encoded_size = UnsignedLeb128Size(data);
-  size_t cur_index = dst->size();
-  dst->resize(dst->size() + encoded_size);
-  uint8_t* write_pos = &((*dst)[cur_index]);
-  uint8_t* write_pos_after = EncodeUnsignedLeb128(write_pos, data);
-  DCHECK_EQ(static_cast<size_t>(write_pos_after - write_pos), encoded_size);
+  Leb128Encoder(dst).PushBackUnsigned(data);
 }
 
 void EncodeSignedLeb128(int32_t data, std::vector<uint8_t>* dst) {
-  size_t encoded_size = SignedLeb128Size(data);
-  size_t cur_index = dst->size();
-  dst->resize(dst->size() + encoded_size);
-  uint8_t* write_pos = &((*dst)[cur_index]);
-  uint8_t* write_pos_after = EncodeSignedLeb128(write_pos, data);
-  DCHECK_EQ(static_cast<size_t>(write_pos_after - write_pos), encoded_size);
+  Leb128Encoder(dst).PushBackSigned(data);
 }
 
 void PushWord(std::vector<uint8_t>* buf, int data) {
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index c02f310..63bfc44 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -123,7 +123,7 @@
 
   // Resist the urge to delete the space. <: is a bigraph sequence.
   std::unique_ptr< ::ZipEntry> zip_entry(new ::ZipEntry);
-  const int32_t error = FindEntry(handle_, name, zip_entry.get());
+  const int32_t error = FindEntry(handle_, ZipEntryName(name), zip_entry.get());
   if (error) {
     *error_msg = std::string(ErrorCodeString(error));
     return nullptr;
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index 268f0be..3acc643 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -22,27 +22,9 @@
 
 #include "jni.h"
 #include "stdio.h"
-#include "string.h"
 #include "unistd.h"
 
-#include "native_bridge.h"
-
-
-// Native bridge interfaces...
-
-struct NativeBridgeArtCallbacks {
-  const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
-  uint32_t (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
-  uint32_t (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
-                               uint32_t method_count);
-};
-
-struct NativeBridgeCallbacks {
-  bool (*initialize)(NativeBridgeArtCallbacks* art_cbs);
-  void* (*loadLibrary)(const char* libpath, int flag);
-  void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
-  bool (*isSupported)(const char* libpath);
-};
+#include "nativebridge/native_bridge.h"
 
 struct NativeBridgeMethod {
   const char* name;
@@ -53,7 +35,7 @@
 };
 
 static NativeBridgeMethod* find_native_bridge_method(const char *name);
-static NativeBridgeArtCallbacks* gNativeBridgeArtCallbacks;
+static const android::NativeBridgeRuntimeCallbacks* gNativeBridgeArtCallbacks;
 
 static jint trampoline_JNI_OnLoad(JavaVM* vm, void* reserved) {
   JNIEnv* env = nullptr;
@@ -225,7 +207,7 @@
 }
 
 // NativeBridgeCallbacks implementations
-extern "C" bool native_bridge_initialize(NativeBridgeArtCallbacks* art_cbs) {
+extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* art_cbs) {
   if (art_cbs != nullptr) {
     gNativeBridgeArtCallbacks = art_cbs;
     printf("Native bridge initialized.\n");
@@ -281,7 +263,9 @@
   return strcmp(libpath, "libjavacore.so") != 0;
 }
 
-NativeBridgeCallbacks NativeBridgeItf {
+// "NativeBridgeItf" is effectively an API (it is the name of the symbol that will be loaded
+// by the native bridge library).
+android::NativeBridgeCallbacks NativeBridgeItf {
   .initialize = &native_bridge_initialize,
   .loadLibrary = &native_bridge_loadLibrary,
   .getTrampoline = &native_bridge_getTrampoline,
diff --git a/test/run-test b/test/run-test
index 496f7d1..b8e40d9 100755
--- a/test/run-test
+++ b/test/run-test
@@ -206,6 +206,14 @@
         break
     fi
 done
+
+# tmp_dir may be relative, resolve.
+#
+# Cannot use realpath, as it does not exist on Mac.
+# Cannot us a simple "cd", as the path might not be created yet.
+# Use -m option of readlink: canonicalizes, but allows non-existing components.
+tmp_dir="`cd $oldwd ; readlink -m $tmp_dir`"
+
 mkdir -p $tmp_dir
 
 if [ "$basic_verify" = "true" ]; then