Merge "Add D/CHECK_CONSTEXPR macros for use in constexpr context."
diff --git a/build/Android.common.mk b/build/Android.common.mk
index a14b951..09f34b3 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -34,8 +34,8 @@
 #
 ART_BUILD_TARGET_NDEBUG ?= true
 ART_BUILD_TARGET_DEBUG ?= true
-ART_BUILD_HOST_NDEBUG ?= $(WITH_HOST_DALVIK)
-ART_BUILD_HOST_DEBUG ?= $(WITH_HOST_DALVIK)
+ART_BUILD_HOST_NDEBUG ?= true
+ART_BUILD_HOST_DEBUG ?= true
 
 ifeq ($(HOST_PREFER_32_BIT),true)
 ART_HOST_ARCH := $(HOST_2ND_ARCH)
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 407269b..1bb1d56 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -250,11 +250,9 @@
   $(foreach file,$(RUNTIME_GTEST_TARGET_SRC_FILES), $(eval $(call build-art-test,target,$(file),,)))
   $(foreach file,$(COMPILER_GTEST_TARGET_SRC_FILES), $(eval $(call build-art-test,target,$(file),art/compiler,libartd-compiler)))
 endif
-ifeq ($(WITH_HOST_DALVIK),true)
-  ifeq ($(ART_BUILD_HOST),true)
-    $(foreach file,$(RUNTIME_GTEST_HOST_SRC_FILES), $(eval $(call build-art-test,host,$(file),,)))
-    $(foreach file,$(COMPILER_GTEST_HOST_SRC_FILES), $(eval $(call build-art-test,host,$(file),art/compiler,libartd-compiler)))
-  endif
+ifeq ($(ART_BUILD_HOST),true)
+  $(foreach file,$(RUNTIME_GTEST_HOST_SRC_FILES), $(eval $(call build-art-test,host,$(file),,)))
+  $(foreach file,$(COMPILER_GTEST_HOST_SRC_FILES), $(eval $(call build-art-test,host,$(file),art/compiler,libartd-compiler)))
 endif
 
 # Used outside the art project to get a list of the current tests
diff --git a/build/Android.libarttest.mk b/build/Android.libarttest.mk
index b4c99b5..76e5af0 100644
--- a/build/Android.libarttest.mk
+++ b/build/Android.libarttest.mk
@@ -74,8 +74,6 @@
 ifeq ($(ART_BUILD_TARGET),true)
   $(eval $(call build-libarttest,target))
 endif
-ifeq ($(WITH_HOST_DALVIK),true)
-  ifeq ($(ART_BUILD_HOST),true)
-    $(eval $(call build-libarttest,host))
-  endif
+ifeq ($(ART_BUILD_HOST),true)
+  $(eval $(call build-libarttest,host))
 endif
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index bf07ecc..fbb7eb3 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -74,7 +74,6 @@
 endif # ART_BUILD_HOST
 
 # If we aren't building the host toolchain, skip building the target core.art.
-ifeq ($(WITH_HOST_DALVIK),true)
 ifeq ($(ART_BUILD_TARGET),true)
 include $(CLEAR_VARS)
 LOCAL_MODULE := core.art
@@ -84,4 +83,3 @@
 LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_CORE_IMG_OUT)
 include $(BUILD_PHONY_PACKAGE)
 endif # ART_BUILD_TARGET
-endif # WITH_HOST_DALVIK
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 3cf7368..9a868fc 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -273,14 +273,12 @@
 
 endef
 
-ifeq ($(WITH_HOST_DALVIK),true)
-  # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
-  ifeq ($(ART_BUILD_NDEBUG),true)
-    $(eval $(call build-libart-compiler,host,ndebug))
-  endif
-  ifeq ($(ART_BUILD_DEBUG),true)
-    $(eval $(call build-libart-compiler,host,debug))
-  endif
+# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
+ifeq ($(ART_BUILD_NDEBUG),true)
+  $(eval $(call build-libart-compiler,host,ndebug))
+endif
+ifeq ($(ART_BUILD_DEBUG),true)
+  $(eval $(call build-libart-compiler,host,debug))
 endif
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
   $(eval $(call build-libart-compiler,target,ndebug))
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 1460ce6..4b2bc4a 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -346,7 +346,7 @@
           if (mir->next != NULL) {
             MIR* mir_next = mir->next;
             // Make sure result of cmp is used by next insn and nowhere else
-            if (IsInstructionIfCcZ(mir->next->dalvikInsn.opcode) &&
+            if (IsInstructionIfCcZ(mir_next->dalvikInsn.opcode) &&
                 (mir->ssa_rep->defs[0] == mir_next->ssa_rep->uses[0]) &&
                 (GetSSAUseCount(mir->ssa_rep->defs[0]) == 1)) {
               mir_next->meta.ccode = ConditionCodeForIfCcZ(mir_next->dalvikInsn.opcode);
@@ -374,12 +374,16 @@
                 default: LOG(ERROR) << "Unexpected opcode: " << opcode;
               }
               mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
+              // Copy the SSA information that is relevant.
               mir_next->ssa_rep->num_uses = mir->ssa_rep->num_uses;
               mir_next->ssa_rep->uses = mir->ssa_rep->uses;
               mir_next->ssa_rep->fp_use = mir->ssa_rep->fp_use;
               mir_next->ssa_rep->num_defs = 0;
               mir->ssa_rep->num_uses = 0;
               mir->ssa_rep->num_defs = 0;
+              // Copy in the decoded instruction information for potential SSA re-creation.
+              mir_next->dalvikInsn.vA = mir->dalvikInsn.vB;
+              mir_next->dalvikInsn.vB = mir->dalvikInsn.vC;
             }
           }
           break;
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 8093fd7..a050a05 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1095,6 +1095,55 @@
 
 void X86Mir2Lir::GenMulLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1,
                             RegLocation rl_src2) {
+  if (Gen64Bit()) {
+    if (rl_src1.is_const) {
+      std::swap(rl_src1, rl_src2);
+    }
+    // Are we multiplying by a constant?
+    if (rl_src2.is_const) {
+      int64_t val = mir_graph_->ConstantValueWide(rl_src2);
+      if (val == 0) {
+        RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
+        OpRegReg(kOpXor, rl_result.reg, rl_result.reg);
+        StoreValueWide(rl_dest, rl_result);
+        return;
+      } else if (val == 1) {
+        StoreValueWide(rl_dest, rl_src1);
+        return;
+      } else if (val == 2) {
+        GenAddLong(Instruction::ADD_LONG, rl_dest, rl_src1, rl_src1);
+        return;
+      } else if (IsPowerOfTwo(val)) {
+        int shift_amount = LowestSetBit(val);
+        if (!BadOverlap(rl_src1, rl_dest)) {
+          rl_src1 = LoadValueWide(rl_src1, kCoreReg);
+          RegLocation rl_result = GenShiftImmOpLong(Instruction::SHL_LONG, rl_dest,
+                                                    rl_src1, shift_amount);
+          StoreValueWide(rl_dest, rl_result);
+          return;
+        }
+      }
+    }
+    rl_src1 = LoadValueWide(rl_src1, kCoreReg);
+    rl_src2 = LoadValueWide(rl_src2, kCoreReg);
+    RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
+    if (rl_result.reg.GetReg() == rl_src1.reg.GetReg() &&
+        rl_result.reg.GetReg() == rl_src2.reg.GetReg()) {
+      NewLIR2(kX86Imul64RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
+    } else if (rl_result.reg.GetReg() != rl_src1.reg.GetReg() &&
+               rl_result.reg.GetReg() == rl_src2.reg.GetReg()) {
+      NewLIR2(kX86Imul64RR, rl_result.reg.GetReg(), rl_src1.reg.GetReg());
+    } else if (rl_result.reg.GetReg() == rl_src1.reg.GetReg() &&
+               rl_result.reg.GetReg() != rl_src2.reg.GetReg()) {
+      NewLIR2(kX86Imul64RR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
+    } else {
+      OpRegCopy(rl_result.reg, rl_src1.reg);
+      NewLIR2(kX86Imul64RR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
+    }
+    StoreValueWide(rl_dest, rl_result);
+    return;
+  }
+
   if (rl_src1.is_const) {
     std::swap(rl_src1, rl_src2);
   }
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 09f2eae..cb66e48 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -29,21 +29,16 @@
 
 namespace art {
 
-bool ElfWriterQuick::Create(File* elf_file,
-                            OatWriter* oat_writer,
-                            const std::vector<const DexFile*>& dex_files,
-                            const std::string& android_root,
-                            bool is_host,
-                            const CompilerDriver& driver) {
-  ElfWriterQuick elf_writer(driver, elf_file);
-  return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
+static constexpr Elf32_Word NextOffset(const Elf32_Shdr& cur, const Elf32_Shdr& prev) {
+  return RoundUp(prev.sh_size + prev.sh_offset, cur.sh_addralign);
 }
 
-bool ElfWriterQuick::Write(OatWriter* oat_writer,
-                           const std::vector<const DexFile*>& dex_files_unused,
-                           const std::string& android_root_unused,
-                           bool is_host_unused) {
-  const bool debug = false;
+static uint8_t MakeStInfo(uint8_t binding, uint8_t type) {
+  return ((binding) << 4) + ((type) & 0xf);
+}
+
+bool ElfWriterQuick::ElfBuilder::Write() {
+  // The basic layout of the elf file. Order may be different in final output.
   // +-------------------------+
   // | Elf32_Ehdr              |
   // +-------------------------+
@@ -67,12 +62,14 @@
   // | boot.oat\0              |
   // +-------------------------+
   // | .hash                   |
-  // | Elf32_Word nbucket = 1  |
-  // | Elf32_Word nchain  = 3  |
-  // | Elf32_Word bucket[0] = 0|
-  // | Elf32_Word chain[0]  = 1|
-  // | Elf32_Word chain[1]  = 2|
-  // | Elf32_Word chain[2]  = 3|
+  // | Elf32_Word nbucket = b  |
+  // | Elf32_Word nchain  = c  |
+  // | Elf32_Word bucket[0]    |
+  // |         ...             |
+  // | Elf32_Word bucket[b - 1]|
+  // | Elf32_Word chain[0]     |
+  // |         ...             |
+  // | Elf32_Word chain[c - 1] |
   // +-------------------------+
   // | .rodata                 |
   // | oatdata..oatexec-4      |
@@ -88,6 +85,12 @@
   // | Elf32_Dyn DT_STRTAB     |
   // | Elf32_Dyn DT_STRSZ      |
   // | Elf32_Dyn DT_NULL       |
+  // +-------------------------+  (Optional)
+  // | .strtab                 |  (Optional)
+  // | program symbol names    |  (Optional)
+  // +-------------------------+  (Optional)
+  // | .symtab                 |  (Optional)
+  // | program symbols         |  (Optional)
   // +-------------------------+
   // | .shstrtab               |
   // | \0                      |
@@ -98,7 +101,20 @@
   // | .rodata\0               |
   // | .text\0                 |
   // | .shstrtab\0             |
-  // | .debug_frame\0          |
+  // | .symtab\0               |  (Optional)
+  // | .strtab\0               |  (Optional)
+  // | .debug_str\0            |  (Optional)
+  // | .debug_info\0           |  (Optional)
+  // | .debug_frame\0          |  (Optional)
+  // | .debug_abbrev\0         |  (Optional)
+  // +-------------------------+  (Optional)
+  // | .debug_str              |  (Optional)
+  // +-------------------------+  (Optional)
+  // | .debug_info             |  (Optional)
+  // +-------------------------+  (Optional)
+  // | .debug_frame            |  (Optional)
+  // +-------------------------+  (Optional)
+  // | .debug_abbrev           |  (Optional)
   // +-------------------------+
   // | Elf32_Shdr NULL         |
   // | Elf32_Shdr .dynsym      |
@@ -108,20 +124,20 @@
   // | Elf32_Shdr .rodata      |
   // | Elf32_Shdr .dynamic     |
   // | Elf32_Shdr .shstrtab    |
+  // | Elf32_Shdr .debug_str   |  (Optional)
   // | Elf32_Shdr .debug_info  |  (Optional)
-  // | Elf32_Shdr .debug_abbrev|  (Optional)
   // | Elf32_Shdr .debug_frame |  (Optional)
+  // | Elf32_Shdr .debug_abbrev|  (Optional)
   // +-------------------------+
 
-  // phase 1: computing offsets
-  uint32_t expected_offset = 0;
 
-  // Elf32_Ehdr
-  expected_offset += sizeof(Elf32_Ehdr);
+  if (fatal_error_) {
+    return false;
+  }
+  // Step 1. Figure out all the offsets.
 
-  // PHDR
-  uint32_t phdr_alignment = sizeof(Elf32_Word);
-  uint32_t phdr_offset = expected_offset;
+  // 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;
@@ -129,41 +145,40 @@
   const uint8_t PH_DYNAMIC  = 4;
   const uint8_t PH_NUM      = 5;
   uint32_t phdr_size = sizeof(Elf32_Phdr) * PH_NUM;
-  expected_offset += phdr_size;
-  if (debug) {
+  if (debug_logging_) {
     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);
 
-  // .dynsym
-  uint32_t dynsym_alignment = sizeof(Elf32_Word);
-  uint32_t dynsym_offset = expected_offset = RoundUp(expected_offset, dynsym_alignment);
-  const uint8_t SYM_UNDEF       = 0;  // aka STN_UNDEF
-  const uint8_t SYM_OATDATA     = 1;
-  const uint8_t SYM_OATEXEC     = 2;
-  const uint8_t SYM_OATLASTWORD = 3;
-  const uint8_t SYM_NUM         = 4;
-  uint32_t dynsym_size = sizeof(Elf32_Sym) * SYM_NUM;
-  expected_offset += dynsym_size;
-  if (debug) {
-    LOG(INFO) << "dynsym_offset=" << dynsym_offset << std::hex << " " << dynsym_offset;
-    LOG(INFO) << "dynsym_size=" << dynsym_size << std::hex << " " << dynsym_size;
-  }
+  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;
 
-  // .dynstr
-  uint32_t dynstr_alignment = 1;
-  uint32_t dynstr_offset = expected_offset = RoundUp(expected_offset, dynstr_alignment);
-  std::string dynstr;
-  dynstr += '\0';
-  uint32_t dynstr_oatdata_offset = dynstr.size();
-  dynstr += "oatdata";
-  dynstr += '\0';
-  uint32_t dynstr_oatexec_offset = dynstr.size();
-  dynstr += "oatexec";
-  dynstr += '\0';
-  uint32_t dynstr_oatlastword_offset = dynstr.size();
-  dynstr += "oatlastword";
-  dynstr += '\0';
+  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_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());
+
+  // Add the SONAME to the dynstr.
   uint32_t dynstr_soname_offset = dynstr.size();
   std::string file_name(elf_file_->GetPath());
   size_t directory_separator_pos = file_name.rfind('/');
@@ -172,672 +187,651 @@
   }
   dynstr += file_name;
   dynstr += '\0';
-  uint32_t dynstr_size = dynstr.size();
-  expected_offset += dynstr_size;
-  if (debug) {
-    LOG(INFO) << "dynstr_offset=" << dynstr_offset << std::hex << " " << dynstr_offset;
-    LOG(INFO) << "dynstr_size=" << dynstr_size << std::hex << " " << dynstr_size;
+  if (debug_logging_) {
+    LOG(INFO) << "dynstr size (bytes)   =" << dynstr.size()
+              << std::hex << " " << dynstr.size();
+    LOG(INFO) << "dynsym size (elements)=" << dynsym_builder_.GetSize()
+              << std::hex << " " << dynsym_builder_.GetSize();
   }
 
-  // .hash
-  uint32_t hash_alignment = sizeof(Elf32_Word);  // Even for 64-bit
-  uint32_t hash_offset = expected_offset = RoundUp(expected_offset, hash_alignment);
-  const uint8_t HASH_NBUCKET = 0;
-  const uint8_t HASH_NCHAIN  = 1;
-  const uint8_t HASH_BUCKET0 = 2;
-  const uint8_t HASH_NUM     = HASH_BUCKET0 + 1 + SYM_NUM;
-  uint32_t hash_size = sizeof(Elf32_Word) * HASH_NUM;
-  expected_offset += hash_size;
-  if (debug) {
-    LOG(INFO) << "hash_offset=" << hash_offset << std::hex << " " << hash_offset;
-    LOG(INFO) << "hash_size=" << hash_size << std::hex << " " << hash_size;
+  // 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();
+    }
   }
 
-  // .rodata
-  uint32_t oat_data_alignment = kPageSize;
-  uint32_t oat_data_offset = expected_offset = RoundUp(expected_offset, oat_data_alignment);
-  const OatHeader& oat_header = oat_writer->GetOatHeader();
-  CHECK(oat_header.IsValid());
-  uint32_t oat_data_size = oat_header.GetExecutableOffset();
-  expected_offset += oat_data_size;
-  if (debug) {
-    LOG(INFO) << "oat_data_offset=" << oat_data_offset << std::hex << " " << oat_data_offset;
-    LOG(INFO) << "oat_data_size=" << oat_data_size << std::hex << " " << oat_data_size;
-  }
-
-  // .text
-  uint32_t oat_exec_alignment = kPageSize;
-  CHECK_ALIGNED(expected_offset, kPageSize);
-  uint32_t oat_exec_offset = expected_offset = RoundUp(expected_offset, oat_exec_alignment);
-  uint32_t oat_exec_size = oat_writer->GetSize() - oat_data_size;
-  expected_offset += oat_exec_size;
-  CHECK_EQ(oat_data_offset + oat_writer->GetSize(), expected_offset);
-  if (debug) {
-    LOG(INFO) << "oat_exec_offset=" << oat_exec_offset << std::hex << " " << oat_exec_offset;
-    LOG(INFO) << "oat_exec_size=" << oat_exec_size << std::hex << " " << oat_exec_size;
-  }
-
-  // .dynamic
-  // alignment would naturally be sizeof(Elf32_Word), but we want this in a new segment
-  uint32_t dynamic_alignment = kPageSize;
-  uint32_t dynamic_offset = expected_offset = RoundUp(expected_offset, dynamic_alignment);
-  const uint8_t DH_SONAME = 0;
-  const uint8_t DH_HASH   = 1;
-  const uint8_t DH_SYMTAB = 2;
-  const uint8_t DH_SYMENT = 3;
-  const uint8_t DH_STRTAB = 4;
-  const uint8_t DH_STRSZ  = 5;
-  const uint8_t DH_NULL   = 6;
-  const uint8_t DH_NUM    = 7;
-  uint32_t dynamic_size = sizeof(Elf32_Dyn) * DH_NUM;
-  expected_offset += dynamic_size;
-  if (debug) {
-    LOG(INFO) << "dynamic_offset=" << dynamic_offset << std::hex << " " << dynamic_offset;
-    LOG(INFO) << "dynamic_size=" << dynamic_size << std::hex << " " << dynamic_size;
-  }
-
-  // .shstrtab
-  uint32_t shstrtab_alignment = 1;
-  uint32_t shstrtab_offset = expected_offset = RoundUp(expected_offset, shstrtab_alignment);
+  // Get the section header string table.
+  std::vector<Elf32_Shdr*> section_ptrs;
   std::string shstrtab;
   shstrtab += '\0';
-  uint32_t shstrtab_dynamic_offset = shstrtab.size();
-  CHECK_EQ(1U, shstrtab_dynamic_offset);
-  shstrtab += ".dynamic";
-  shstrtab += '\0';
-  uint32_t shstrtab_dynsym_offset = shstrtab.size();
-  shstrtab += ".dynsym";
-  shstrtab += '\0';
-  uint32_t shstrtab_dynstr_offset = shstrtab.size();
-  shstrtab += ".dynstr";
-  shstrtab += '\0';
-  uint32_t shstrtab_hash_offset = shstrtab.size();
-  shstrtab += ".hash";
-  shstrtab += '\0';
-  uint32_t shstrtab_rodata_offset = shstrtab.size();
-  shstrtab += ".rodata";
-  shstrtab += '\0';
-  uint32_t shstrtab_text_offset = shstrtab.size();
-  shstrtab += ".text";
-  shstrtab += '\0';
-  uint32_t shstrtab_shstrtab_offset = shstrtab.size();
-  shstrtab += ".shstrtab";
-  shstrtab += '\0';
-  uint32_t shstrtab_debug_info_offset = shstrtab.size();
-  shstrtab += ".debug_info";
-  shstrtab += '\0';
-  uint32_t shstrtab_debug_abbrev_offset = shstrtab.size();
-  shstrtab += ".debug_abbrev";
-  shstrtab += '\0';
-  uint32_t shstrtab_debug_str_offset = shstrtab.size();
-  shstrtab += ".debug_str";
-  shstrtab += '\0';
-  uint32_t shstrtab_debug_frame_offset = shstrtab.size();
-  shstrtab += ".debug_frame";
-  shstrtab += '\0';
-  uint32_t shstrtab_size = shstrtab.size();
-  expected_offset += shstrtab_size;
-  if (debug) {
-    LOG(INFO) << "shstrtab_offset=" << shstrtab_offset << std::hex << " " << shstrtab_offset;
-    LOG(INFO) << "shstrtab_size=" << shstrtab_size << std::hex << " " << shstrtab_size;
+
+  // 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);
+
+  uint32_t section_index = 1;
+
+  // setup .dynsym
+  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++;
+
+  // Setup .hash
+  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++;
+
+  // Setup .text
+  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++;
   }
 
-  // Create debug informatin, if we have it.
-  bool generateDebugInformation = compiler_driver_->GetCallFrameInformation() != nullptr;
-  std::vector<uint8_t> dbg_info;
-  std::vector<uint8_t> dbg_abbrev;
-  std::vector<uint8_t> dbg_str;
-  if (generateDebugInformation) {
-    FillInCFIInformation(oat_writer, &dbg_info, &dbg_abbrev, &dbg_str);
+  // 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();
   }
 
-  uint32_t shdbg_info_alignment = 1;
-  uint32_t shdbg_info_offset = expected_offset;
-  uint32_t shdbg_info_size = dbg_info.size();
-  expected_offset += shdbg_info_size;
-  if (debug) {
-    LOG(INFO) << "shdbg_info_offset=" << shdbg_info_offset << std::hex << " " << shdbg_info_offset;
-    LOG(INFO) << "shdbg_info_size=" << shdbg_info_size << std::hex << " " << shdbg_info_size;
+  // Fill in the hash section.
+  std::vector<Elf32_Word> hash = dynsym_builder_.GenerateHashContents();
+
+  if (debug_logging_) {
+    LOG(INFO) << ".hash size (bytes)=" << hash.size() * sizeof(Elf32_Word)
+              << std::hex << " " << hash.size() * sizeof(Elf32_Word);
   }
 
-  uint32_t shdbg_abbrev_alignment = 1;
-  uint32_t shdbg_abbrev_offset = expected_offset;
-  uint32_t shdbg_abbrev_size = dbg_abbrev.size();
-  expected_offset += shdbg_abbrev_size;
-  if (debug) {
-    LOG(INFO) << "shdbg_abbrev_offset=" << shdbg_abbrev_offset << std::hex << " " << shdbg_abbrev_offset;
-    LOG(INFO) << "shdbg_abbrev_size=" << shdbg_abbrev_size << std::hex << " " << shdbg_abbrev_size;
+  Elf32_Word base_offset = sizeof(Elf32_Ehdr) + sizeof(program_headers);
+  std::vector<ElfFilePiece> pieces;
+
+  // Get the layout in the sections.
+  //
+  // Get the layout of the dynsym section.
+  dynsym_builder_.section_.sh_offset = RoundUp(base_offset, dynsym_builder_.section_.sh_addralign);
+  dynsym_builder_.section_.sh_addr = dynsym_builder_.section_.sh_offset;
+  dynsym_builder_.section_.sh_size = dynsym_builder_.GetSize() * sizeof(Elf32_Sym);
+  dynsym_builder_.section_.sh_link = dynsym_builder_.GetLink();
+
+  // Get the layout of the dynstr section.
+  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_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_link = hash_builder_.GetLink();
+
+  // Get the layout of the rodata section.
+  rodata_builder_.section_.sh_offset = NextOffset(rodata_builder_.section_,
+                                                  hash_builder_.section_);
+  rodata_builder_.section_.sh_addr = rodata_builder_.section_.sh_offset;
+  rodata_builder_.section_.sh_size = rodata_builder_.size_;
+  rodata_builder_.section_.sh_link = rodata_builder_.GetLink();
+
+  // Get the layout of the text section.
+  text_builder_.section_.sh_offset = NextOffset(text_builder_.section_, rodata_builder_.section_);
+  text_builder_.section_.sh_addr = text_builder_.section_.sh_offset;
+  text_builder_.section_.sh_size = text_builder_.size_;
+  text_builder_.section_.sh_link = text_builder_.GetLink();
+  CHECK_ALIGNED(rodata_builder_.section_.sh_offset + rodata_builder_.section_.sh_size, kPageSize);
+
+  // Get the layout of the dynamic section.
+  dynamic_builder_.section_.sh_offset = NextOffset(dynamic_builder_.section_,
+                                                   text_builder_.section_);
+  dynamic_builder_.section_.sh_addr = dynamic_builder_.section_.sh_offset;
+  dynamic_builder_.section_.sh_size = dynamic_builder_.GetSize() * sizeof(Elf32_Dyn);
+  dynamic_builder_.section_.sh_link = dynamic_builder_.GetLink();
+
+  Elf32_Shdr prev = dynamic_builder_.section_;
+  if (IncludingDebugSymbols()) {
+    // Get the layout of the symtab section.
+    symtab_builder_.section_.sh_offset = NextOffset(symtab_builder_.section_,
+                                                    dynamic_builder_.section_);
+    symtab_builder_.section_.sh_addr = 0;
+    // Add to leave space for the null symbol.
+    symtab_builder_.section_.sh_size = symtab_builder_.GetSize() * sizeof(Elf32_Sym);
+    symtab_builder_.section_.sh_link = symtab_builder_.GetLink();
+
+    // Get the layout of the dynstr section.
+    symtab_builder_.strtab_.section_.sh_offset = NextOffset(symtab_builder_.strtab_.section_,
+                                                            symtab_builder_.section_);
+    symtab_builder_.strtab_.section_.sh_addr = 0;
+    symtab_builder_.strtab_.section_.sh_size = strtab.size();
+    symtab_builder_.strtab_.section_.sh_link = symtab_builder_.strtab_.GetLink();
+
+    prev = symtab_builder_.strtab_.section_;
   }
-
-  uint32_t shdbg_frm_alignment = 4;
-  uint32_t shdbg_frm_offset = expected_offset = RoundUp(expected_offset, shdbg_frm_alignment);
-  uint32_t shdbg_frm_size =
-    generateDebugInformation ? compiler_driver_->GetCallFrameInformation()->size() : 0;
-  expected_offset += shdbg_frm_size;
-  if (debug) {
-    LOG(INFO) << "shdbg_frm_offset=" << shdbg_frm_offset << std::hex << " " << shdbg_frm_offset;
-    LOG(INFO) << "shdbg_frm_size=" << shdbg_frm_size << std::hex << " " << shdbg_frm_size;
-  }
-
-  uint32_t shdbg_str_alignment = 1;
-  uint32_t shdbg_str_offset = expected_offset;
-  uint32_t shdbg_str_size = dbg_str.size();
-  expected_offset += shdbg_str_size;
-  if (debug) {
-    LOG(INFO) << "shdbg_str_offset=" << shdbg_str_offset << std::hex << " " << shdbg_str_offset;
-    LOG(INFO) << "shdbg_str_size=" << shdbg_str_size << std::hex << " " << shdbg_str_size;
-  }
-
-  // section headers (after all sections)
-  uint32_t shdr_alignment = sizeof(Elf32_Word);
-  uint32_t shdr_offset = expected_offset = RoundUp(expected_offset, shdr_alignment);
-  const uint8_t SH_NULL     = 0;
-  const uint8_t SH_DYNSYM   = 1;
-  const uint8_t SH_DYNSTR   = 2;
-  const uint8_t SH_HASH     = 3;
-  const uint8_t SH_RODATA   = 4;
-  const uint8_t SH_TEXT     = 5;
-  const uint8_t SH_DYNAMIC  = 6;
-  const uint8_t SH_SHSTRTAB = 7;
-  const uint8_t SH_DBG_INFO = 8;
-  const uint8_t SH_DBG_ABRV = 9;
-  const uint8_t SH_DBG_FRM  = 10;
-  const uint8_t SH_DBG_STR  = 11;
-  const uint8_t SH_NUM      = generateDebugInformation ? 12 : 8;
-  uint32_t shdr_size = sizeof(Elf32_Shdr) * SH_NUM;
-  expected_offset += shdr_size;
-  if (debug) {
-    LOG(INFO) << "shdr_offset=" << shdr_offset << std::hex << " " << shdr_offset;
-    LOG(INFO) << "shdr_size=" << shdr_size << std::hex << " " << shdr_size;
-  }
-
-  // phase 2: initializing data
-
-  // Elf32_Ehdr
-  Elf32_Ehdr elf_header;
-  memset(&elf_header, 0, sizeof(elf_header));
-  elf_header.e_ident[EI_MAG0]       = ELFMAG0;
-  elf_header.e_ident[EI_MAG1]       = ELFMAG1;
-  elf_header.e_ident[EI_MAG2]       = ELFMAG2;
-  elf_header.e_ident[EI_MAG3]       = ELFMAG3;
-  elf_header.e_ident[EI_CLASS]      = ELFCLASS32;
-  elf_header.e_ident[EI_DATA]       = ELFDATA2LSB;
-  elf_header.e_ident[EI_VERSION]    = EV_CURRENT;
-  elf_header.e_ident[EI_OSABI]      = ELFOSABI_LINUX;
-  elf_header.e_ident[EI_ABIVERSION] = 0;
-  elf_header.e_type = ET_DYN;
-  switch (compiler_driver_->GetInstructionSet()) {
-    case kArm:
-      // Fall through.
-    case kThumb2: {
-      elf_header.e_machine = EM_ARM;
-      elf_header.e_flags = EF_ARM_EABI_VER5;
-      break;
-    }
-    case kArm64: {
-      elf_header.e_machine = EM_AARCH64;
-      elf_header.e_flags = 0;
-      break;
-    }
-    case kX86: {
-      elf_header.e_machine = EM_386;
-      elf_header.e_flags = 0;
-      break;
-    }
-    case kX86_64: {
-      elf_header.e_machine = EM_X86_64;
-      elf_header.e_flags = 0;
-      break;
-    }
-    case kMips: {
-      elf_header.e_machine = EM_MIPS;
-      elf_header.e_flags = (EF_MIPS_NOREORDER |
-                            EF_MIPS_PIC       |
-                            EF_MIPS_CPIC      |
-                            EF_MIPS_ABI_O32   |
-                            EF_MIPS_ARCH_32R2);
-      break;
-    }
-    default: {
-      LOG(FATAL) << "Unknown instruction set: " << compiler_driver_->GetInstructionSet();
-      break;
+  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()) {
+      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;
     }
   }
-  elf_header.e_version = 1;
-  elf_header.e_entry = 0;
-  elf_header.e_phoff = phdr_offset;
-  elf_header.e_shoff = shdr_offset;
-  elf_header.e_ehsize = sizeof(Elf32_Ehdr);
-  elf_header.e_phentsize = sizeof(Elf32_Phdr);
-  elf_header.e_phnum = PH_NUM;
-  elf_header.e_shentsize = sizeof(Elf32_Shdr);
-  elf_header.e_shnum = SH_NUM;
-  elf_header.e_shstrndx = SH_SHSTRTAB;
-
-  // PHDR
-  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   = phdr_alignment;
-
-  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_filesz  = oat_data_offset + oat_data_size;
-  program_headers[PH_LOAD_R__].p_memsz   = oat_data_offset + oat_data_size;
-  program_headers[PH_LOAD_R__].p_flags   = PF_R;
-  program_headers[PH_LOAD_R__].p_align   = oat_data_alignment;
-
-  program_headers[PH_LOAD_R_X].p_type    = PT_LOAD;
-  program_headers[PH_LOAD_R_X].p_offset  = oat_exec_offset;
-  program_headers[PH_LOAD_R_X].p_vaddr   = oat_exec_offset;
-  program_headers[PH_LOAD_R_X].p_paddr   = oat_exec_offset;
-  program_headers[PH_LOAD_R_X].p_filesz  = oat_exec_size;
-  program_headers[PH_LOAD_R_X].p_memsz   = oat_exec_size;
-  program_headers[PH_LOAD_R_X].p_flags   = PF_R | PF_X;
-  program_headers[PH_LOAD_R_X].p_align   = oat_exec_alignment;
-
-  // TODO: PF_W for DYNAMIC is considered processor specific, do we need it?
-  program_headers[PH_LOAD_RW_].p_type    = PT_LOAD;
-  program_headers[PH_LOAD_RW_].p_offset  = dynamic_offset;
-  program_headers[PH_LOAD_RW_].p_vaddr   = dynamic_offset;
-  program_headers[PH_LOAD_RW_].p_paddr   = dynamic_offset;
-  program_headers[PH_LOAD_RW_].p_filesz  = dynamic_size;
-  program_headers[PH_LOAD_RW_].p_memsz   = dynamic_size;
-  program_headers[PH_LOAD_RW_].p_flags   = PF_R | PF_W;
-  program_headers[PH_LOAD_RW_].p_align   = dynamic_alignment;
-
-  // TODO: PF_W for DYNAMIC is considered processor specific, do we need it?
-  program_headers[PH_DYNAMIC].p_type    = PT_DYNAMIC;
-  program_headers[PH_DYNAMIC].p_offset  = dynamic_offset;
-  program_headers[PH_DYNAMIC].p_vaddr   = dynamic_offset;
-  program_headers[PH_DYNAMIC].p_paddr   = dynamic_offset;
-  program_headers[PH_DYNAMIC].p_filesz  = dynamic_size;
-  program_headers[PH_DYNAMIC].p_memsz   = dynamic_size;
-  program_headers[PH_DYNAMIC].p_flags   = PF_R | PF_W;
-  program_headers[PH_DYNAMIC].p_align   = dynamic_alignment;
-
-  // .dynsym
-  Elf32_Sym dynsym[SYM_NUM];
-  memset(&dynsym, 0, sizeof(dynsym));
-
-  dynsym[SYM_UNDEF].st_name  = 0;
-  dynsym[SYM_UNDEF].st_value = 0;
-  dynsym[SYM_UNDEF].st_size  = 0;
-  dynsym[SYM_UNDEF].st_info  = 0;
-  dynsym[SYM_UNDEF].st_other = 0;
-  dynsym[SYM_UNDEF].st_shndx = 0;
-
-  dynsym[SYM_OATDATA].st_name  = dynstr_oatdata_offset;
-  dynsym[SYM_OATDATA].st_value = oat_data_offset;
-  dynsym[SYM_OATDATA].st_size  = oat_data_size;
-  SetBindingAndType(&dynsym[SYM_OATDATA], STB_GLOBAL, STT_OBJECT);
-  dynsym[SYM_OATDATA].st_other = STV_DEFAULT;
-  dynsym[SYM_OATDATA].st_shndx = SH_RODATA;
-
-  dynsym[SYM_OATEXEC].st_name  = dynstr_oatexec_offset;
-  dynsym[SYM_OATEXEC].st_value = oat_exec_offset;
-  dynsym[SYM_OATEXEC].st_size  = oat_exec_size;
-  SetBindingAndType(&dynsym[SYM_OATEXEC], STB_GLOBAL, STT_OBJECT);
-  dynsym[SYM_OATEXEC].st_other = STV_DEFAULT;
-  dynsym[SYM_OATEXEC].st_shndx = SH_TEXT;
-
-  dynsym[SYM_OATLASTWORD].st_name  = dynstr_oatlastword_offset;
-  dynsym[SYM_OATLASTWORD].st_value = oat_exec_offset + oat_exec_size - 4;
-  dynsym[SYM_OATLASTWORD].st_size  = 4;
-  SetBindingAndType(&dynsym[SYM_OATLASTWORD], STB_GLOBAL, STT_OBJECT);
-  dynsym[SYM_OATLASTWORD].st_other = STV_DEFAULT;
-  dynsym[SYM_OATLASTWORD].st_shndx = SH_TEXT;
-
-  // .dynstr initialized above as dynstr
-
-  // .hash
-  Elf32_Word hash[HASH_NUM];  // Note this is Elf32_Word even on 64-bit
-  hash[HASH_NBUCKET] = 1;
-  hash[HASH_NCHAIN]  = SYM_NUM;
-  hash[HASH_BUCKET0] = SYM_OATDATA;
-  hash[HASH_BUCKET0 + 1 + SYM_UNDEF]       = SYM_UNDEF;
-  hash[HASH_BUCKET0 + 1 + SYM_OATDATA]     = SYM_OATEXEC;
-  hash[HASH_BUCKET0 + 1 + SYM_OATEXEC]     = SYM_OATLASTWORD;
-  hash[HASH_BUCKET0 + 1 + SYM_OATLASTWORD] = SYM_UNDEF;
-
-  // .rodata and .text content come from oat_contents
-
-  // .dynamic
-  Elf32_Dyn dynamic_headers[DH_NUM];
-  memset(&dynamic_headers, 0, sizeof(dynamic_headers));
-
-  dynamic_headers[DH_SONAME].d_tag = DT_SONAME;
-  dynamic_headers[DH_SONAME].d_un.d_val = dynstr_soname_offset;
-
-  dynamic_headers[DH_HASH].d_tag = DT_HASH;
-  dynamic_headers[DH_HASH].d_un.d_ptr = hash_offset;
-
-  dynamic_headers[DH_SYMTAB].d_tag = DT_SYMTAB;
-  dynamic_headers[DH_SYMTAB].d_un.d_ptr = dynsym_offset;
-
-  dynamic_headers[DH_SYMENT].d_tag = DT_SYMENT;
-  dynamic_headers[DH_SYMENT].d_un.d_val = sizeof(Elf32_Sym);
-
-  dynamic_headers[DH_STRTAB].d_tag = DT_STRTAB;
-  dynamic_headers[DH_STRTAB].d_un.d_ptr = dynstr_offset;
-
-  dynamic_headers[DH_STRSZ].d_tag = DT_STRSZ;
-  dynamic_headers[DH_STRSZ].d_un.d_val = dynstr_size;
-
-  dynamic_headers[DH_NULL].d_tag = DT_NULL;
-  dynamic_headers[DH_NULL].d_un.d_val = 0;
-
-  // .shstrtab initialized above as shstrtab
-
-  // section headers (after all sections)
-  Elf32_Shdr section_headers[SH_NUM];
-  memset(&section_headers, 0, sizeof(section_headers));
-
-  section_headers[SH_NULL].sh_name      = 0;
-  section_headers[SH_NULL].sh_type      = SHT_NULL;
-  section_headers[SH_NULL].sh_flags     = 0;
-  section_headers[SH_NULL].sh_addr      = 0;
-  section_headers[SH_NULL].sh_offset    = 0;
-  section_headers[SH_NULL].sh_size      = 0;
-  section_headers[SH_NULL].sh_link      = 0;
-  section_headers[SH_NULL].sh_info      = 0;
-  section_headers[SH_NULL].sh_addralign = 0;
-  section_headers[SH_NULL].sh_entsize   = 0;
-
-  section_headers[SH_DYNSYM].sh_name      = shstrtab_dynsym_offset;
-  section_headers[SH_DYNSYM].sh_type      = SHT_DYNSYM;
-  section_headers[SH_DYNSYM].sh_flags     = SHF_ALLOC;
-  section_headers[SH_DYNSYM].sh_addr      = dynsym_offset;
-  section_headers[SH_DYNSYM].sh_offset    = dynsym_offset;
-  section_headers[SH_DYNSYM].sh_size      = dynsym_size;
-  section_headers[SH_DYNSYM].sh_link      = SH_DYNSTR;
-  section_headers[SH_DYNSYM].sh_info      = 1;  // 1 because we have not STB_LOCAL symbols
-  section_headers[SH_DYNSYM].sh_addralign = dynsym_alignment;
-  section_headers[SH_DYNSYM].sh_entsize   = sizeof(Elf32_Sym);
-
-  section_headers[SH_DYNSTR].sh_name      = shstrtab_dynstr_offset;
-  section_headers[SH_DYNSTR].sh_type      = SHT_STRTAB;
-  section_headers[SH_DYNSTR].sh_flags     = SHF_ALLOC;
-  section_headers[SH_DYNSTR].sh_addr      = dynstr_offset;
-  section_headers[SH_DYNSTR].sh_offset    = dynstr_offset;
-  section_headers[SH_DYNSTR].sh_size      = dynstr_size;
-  section_headers[SH_DYNSTR].sh_link      = 0;
-  section_headers[SH_DYNSTR].sh_info      = 0;
-  section_headers[SH_DYNSTR].sh_addralign = dynstr_alignment;
-  section_headers[SH_DYNSTR].sh_entsize   = 0;
-
-  section_headers[SH_HASH].sh_name      = shstrtab_hash_offset;
-  section_headers[SH_HASH].sh_type      = SHT_HASH;
-  section_headers[SH_HASH].sh_flags     = SHF_ALLOC;
-  section_headers[SH_HASH].sh_addr      = hash_offset;
-  section_headers[SH_HASH].sh_offset    = hash_offset;
-  section_headers[SH_HASH].sh_size      = hash_size;
-  section_headers[SH_HASH].sh_link      = SH_DYNSYM;
-  section_headers[SH_HASH].sh_info      = 0;
-  section_headers[SH_HASH].sh_addralign = hash_alignment;
-  section_headers[SH_HASH].sh_entsize   = sizeof(Elf32_Word);  // This is Elf32_Word even on 64-bit
-
-  section_headers[SH_RODATA].sh_name      = shstrtab_rodata_offset;
-  section_headers[SH_RODATA].sh_type      = SHT_PROGBITS;
-  section_headers[SH_RODATA].sh_flags     = SHF_ALLOC;
-  section_headers[SH_RODATA].sh_addr      = oat_data_offset;
-  section_headers[SH_RODATA].sh_offset    = oat_data_offset;
-  section_headers[SH_RODATA].sh_size      = oat_data_size;
-  section_headers[SH_RODATA].sh_link      = 0;
-  section_headers[SH_RODATA].sh_info      = 0;
-  section_headers[SH_RODATA].sh_addralign = oat_data_alignment;
-  section_headers[SH_RODATA].sh_entsize   = 0;
-
-  section_headers[SH_TEXT].sh_name      = shstrtab_text_offset;
-  section_headers[SH_TEXT].sh_type      = SHT_PROGBITS;
-  section_headers[SH_TEXT].sh_flags     = SHF_ALLOC | SHF_EXECINSTR;
-  section_headers[SH_TEXT].sh_addr      = oat_exec_offset;
-  section_headers[SH_TEXT].sh_offset    = oat_exec_offset;
-  section_headers[SH_TEXT].sh_size      = oat_exec_size;
-  section_headers[SH_TEXT].sh_link      = 0;
-  section_headers[SH_TEXT].sh_info      = 0;
-  section_headers[SH_TEXT].sh_addralign = oat_exec_alignment;
-  section_headers[SH_TEXT].sh_entsize   = 0;
-
-  // TODO: SHF_WRITE for .dynamic is considered processor specific, do we need it?
-  section_headers[SH_DYNAMIC].sh_name      = shstrtab_dynamic_offset;
-  section_headers[SH_DYNAMIC].sh_type      = SHT_DYNAMIC;
-  section_headers[SH_DYNAMIC].sh_flags     = SHF_WRITE | SHF_ALLOC;
-  section_headers[SH_DYNAMIC].sh_addr      = dynamic_offset;
-  section_headers[SH_DYNAMIC].sh_offset    = dynamic_offset;
-  section_headers[SH_DYNAMIC].sh_size      = dynamic_size;
-  section_headers[SH_DYNAMIC].sh_link      = SH_DYNSTR;
-  section_headers[SH_DYNAMIC].sh_info      = 0;
-  section_headers[SH_DYNAMIC].sh_addralign = dynamic_alignment;
-  section_headers[SH_DYNAMIC].sh_entsize   = sizeof(Elf32_Dyn);
-
-  section_headers[SH_SHSTRTAB].sh_name      = shstrtab_shstrtab_offset;
-  section_headers[SH_SHSTRTAB].sh_type      = SHT_STRTAB;
-  section_headers[SH_SHSTRTAB].sh_flags     = 0;
-  section_headers[SH_SHSTRTAB].sh_addr      = shstrtab_offset;
-  section_headers[SH_SHSTRTAB].sh_offset    = shstrtab_offset;
-  section_headers[SH_SHSTRTAB].sh_size      = shstrtab_size;
-  section_headers[SH_SHSTRTAB].sh_link      = 0;
-  section_headers[SH_SHSTRTAB].sh_info      = 0;
-  section_headers[SH_SHSTRTAB].sh_addralign = shstrtab_alignment;
-  section_headers[SH_SHSTRTAB].sh_entsize   = 0;
-
-  if (generateDebugInformation) {
-    section_headers[SH_DBG_INFO].sh_name      = shstrtab_debug_info_offset;
-    section_headers[SH_DBG_INFO].sh_type      = SHT_PROGBITS;
-    section_headers[SH_DBG_INFO].sh_flags     = 0;
-    section_headers[SH_DBG_INFO].sh_addr      = 0;
-    section_headers[SH_DBG_INFO].sh_offset    = shdbg_info_offset;
-    section_headers[SH_DBG_INFO].sh_size      = shdbg_info_size;
-    section_headers[SH_DBG_INFO].sh_link      = 0;
-    section_headers[SH_DBG_INFO].sh_info      = 0;
-    section_headers[SH_DBG_INFO].sh_addralign = shdbg_info_alignment;
-    section_headers[SH_DBG_INFO].sh_entsize   = 0;
-
-    section_headers[SH_DBG_ABRV].sh_name      = shstrtab_debug_abbrev_offset;
-    section_headers[SH_DBG_ABRV].sh_type      = SHT_PROGBITS;
-    section_headers[SH_DBG_ABRV].sh_flags     = 0;
-    section_headers[SH_DBG_ABRV].sh_addr      = 0;
-    section_headers[SH_DBG_ABRV].sh_offset    = shdbg_abbrev_offset;
-    section_headers[SH_DBG_ABRV].sh_size      = shdbg_abbrev_size;
-    section_headers[SH_DBG_ABRV].sh_link      = 0;
-    section_headers[SH_DBG_ABRV].sh_info      = 0;
-    section_headers[SH_DBG_ABRV].sh_addralign = shdbg_abbrev_alignment;
-    section_headers[SH_DBG_ABRV].sh_entsize   = 0;
-
-    section_headers[SH_DBG_FRM].sh_name      = shstrtab_debug_frame_offset;
-    section_headers[SH_DBG_FRM].sh_type      = SHT_PROGBITS;
-    section_headers[SH_DBG_FRM].sh_flags     = 0;
-    section_headers[SH_DBG_FRM].sh_addr      = 0;
-    section_headers[SH_DBG_FRM].sh_offset    = shdbg_frm_offset;
-    section_headers[SH_DBG_FRM].sh_size      = shdbg_frm_size;
-    section_headers[SH_DBG_FRM].sh_link      = 0;
-    section_headers[SH_DBG_FRM].sh_info      = 0;
-    section_headers[SH_DBG_FRM].sh_addralign = shdbg_frm_alignment;
-    section_headers[SH_DBG_FRM].sh_entsize   = 0;
-
-    section_headers[SH_DBG_STR].sh_name      = shstrtab_debug_str_offset;
-    section_headers[SH_DBG_STR].sh_type      = SHT_PROGBITS;
-    section_headers[SH_DBG_STR].sh_flags     = 0;
-    section_headers[SH_DBG_STR].sh_addr      = 0;
-    section_headers[SH_DBG_STR].sh_offset    = shdbg_str_offset;
-    section_headers[SH_DBG_STR].sh_size      = shdbg_str_size;
-    section_headers[SH_DBG_STR].sh_link      = 0;
-    section_headers[SH_DBG_STR].sh_info      = 0;
-    section_headers[SH_DBG_STR].sh_addralign = shdbg_str_alignment;
-    section_headers[SH_DBG_STR].sh_entsize   = 0;
+  // 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) {
+    it->section_.sh_offset = NextOffset(it->section_, prev);
+    it->section_.sh_addr = 0;
+    it->section_.sh_size = it->GetBuffer()->size();
+    it->section_.sh_link = it->GetLink();
+    pieces.push_back(ElfFilePiece(it->name_, it->section_.sh_offset,
+                                  it->GetBuffer()->data(), it->GetBuffer()->size()));
+    prev = it->section_;
+    if (debug_logging_) {
+      LOG(INFO) << it->name_ << " off=" << it->section_.sh_offset
+                << " " << 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_link = shstrtab_builder_.GetLink();
+  if (debug_logging_) {
+      LOG(INFO) << "shstrtab off=" << shstrtab_builder_.section_.sh_offset
+                << " shstrtab size=" << shstrtab_builder_.section_.sh_size;
   }
 
-  // phase 3: writing file
+  // The section list comes after come after.
+  Elf32_Word sections_offset = RoundUp(
+      shstrtab_builder_.section_.sh_offset + shstrtab_builder_.section_.sh_size,
+      sizeof(Elf32_Word));
 
-  // Elf32_Ehdr
-  if (!elf_file_->WriteFully(&elf_header, sizeof(elf_header))) {
-    PLOG(ERROR) << "Failed to write ELF header for " << elf_file_->GetPath();
+  // Setup the actual symbol arrays.
+  std::vector<Elf32_Sym> dynsym = dynsym_builder_.GenerateSymtab();
+  CHECK_EQ(dynsym.size() * sizeof(Elf32_Sym), dynsym_builder_.section_.sh_size);
+  std::vector<Elf32_Sym> symtab;
+  if (IncludingDebugSymbols()) {
+    symtab = symtab_builder_.GenerateSymtab();
+    CHECK_EQ(symtab.size() * sizeof(Elf32_Sym), symtab_builder_.section_.sh_size);
+  }
+
+  // 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);
+  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;
+
+  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_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;
+
+  // Finish setup of the Ehdr values.
+  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_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(".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()));
+  pieces.push_back(ElfFilePiece(".hash", hash_builder_.section_.sh_offset,
+                                hash.data(), hash.size() * sizeof(Elf32_Word)));
+  pieces.push_back(ElfFilePiece(".rodata", rodata_builder_.section_.sh_offset,
+                                NULL, rodata_builder_.section_.sh_size));
+  pieces.push_back(ElfFilePiece(".text", text_builder_.section_.sh_offset,
+                                NULL, text_builder_.section_.sh_size));
+  if (IncludingDebugSymbols()) {
+    pieces.push_back(ElfFilePiece(".symtab", symtab_builder_.section_.sh_offset,
+                                  symtab.data(), symtab.size() * sizeof(Elf32_Sym)));
+    pieces.push_back(ElfFilePiece(".strtab", symtab_builder_.strtab_.section_.sh_offset,
+                                  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) {
+    // 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)));
+  }
+
+  if (!WriteOutFile(pieces)) {
+    LOG(ERROR) << "Unable to write to file " << elf_file_->GetPath();
     return false;
   }
-
-  // PHDR
-  if (static_cast<off_t>(phdr_offset) != lseek(elf_file_->Fd(), 0, SEEK_CUR)) {
-    PLOG(ERROR) << "Failed to be at expected ELF program header offset phdr_offset "
-                << " for " << elf_file_->GetPath();
-    return false;
-  }
-  if (!elf_file_->WriteFully(program_headers, sizeof(program_headers))) {
-    PLOG(ERROR) << "Failed to write ELF program headers for " << elf_file_->GetPath();
-    return false;
-  }
-
-  // .dynsym
-  DCHECK_LE(phdr_offset + phdr_size, dynsym_offset);
-  if (static_cast<off_t>(dynsym_offset) != lseek(elf_file_->Fd(), dynsym_offset, SEEK_SET)) {
-    PLOG(ERROR) << "Failed to seek to .dynsym offset location " << dynsym_offset
-                << " for " << elf_file_->GetPath();
-    return false;
-  }
-  if (!elf_file_->WriteFully(dynsym, sizeof(dynsym))) {
-    PLOG(ERROR) << "Failed to write .dynsym for " << elf_file_->GetPath();
-    return false;
-  }
-
-  // .dynstr
-  DCHECK_LE(dynsym_offset + dynsym_size, dynstr_offset);
-  if (static_cast<off_t>(dynstr_offset) != lseek(elf_file_->Fd(), dynstr_offset, SEEK_SET)) {
-    PLOG(ERROR) << "Failed to seek to .dynstr offset " << dynstr_offset
-                << " for " << elf_file_->GetPath();
-    return false;
-  }
-  if (!elf_file_->WriteFully(&dynstr[0], dynstr_size)) {
-    PLOG(ERROR) << "Failed to write .dynsym for " << elf_file_->GetPath();
-    return false;
-  }
-
-  // .hash
-  DCHECK_LE(dynstr_offset + dynstr_size, hash_offset);
-  if (static_cast<off_t>(hash_offset) != lseek(elf_file_->Fd(), hash_offset, SEEK_SET)) {
-    PLOG(ERROR) << "Failed to seek to .hash offset " << hash_offset
-                << " for " << elf_file_->GetPath();
-    return false;
-  }
-  if (!elf_file_->WriteFully(hash, sizeof(hash))) {
-    PLOG(ERROR) << "Failed to write .dynsym for " << elf_file_->GetPath();
-    return false;
-  }
-
-  // .rodata .text
-  DCHECK_LE(hash_offset + hash_size, oat_data_offset);
+  // write out the actual oat file data.
+  Elf32_Word oat_data_offset = rodata_builder_.section_.sh_offset;
   if (static_cast<off_t>(oat_data_offset) != lseek(elf_file_->Fd(), oat_data_offset, SEEK_SET)) {
     PLOG(ERROR) << "Failed to seek to .rodata offset " << oat_data_offset
                 << " for " << elf_file_->GetPath();
     return false;
   }
-  std::unique_ptr<BufferedOutputStream> output_stream(new BufferedOutputStream(new FileOutputStream(elf_file_)));
-  if (!oat_writer->Write(output_stream.get())) {
+  std::unique_ptr<BufferedOutputStream> output_stream(
+      new BufferedOutputStream(new FileOutputStream(elf_file_)));
+  if (!oat_writer_->Write(output_stream.get())) {
     PLOG(ERROR) << "Failed to write .rodata and .text for " << elf_file_->GetPath();
     return false;
   }
 
-  // .dynamic
-  DCHECK_LE(oat_data_offset + oat_writer->GetSize(), dynamic_offset);
-  if (static_cast<off_t>(dynamic_offset) != lseek(elf_file_->Fd(), dynamic_offset, SEEK_SET)) {
-    PLOG(ERROR) << "Failed to seek to .dynamic offset " << dynamic_offset
-                << " for " << elf_file_->GetPath();
-    return false;
-  }
-  if (!elf_file_->WriteFully(&dynamic_headers[0], dynamic_size)) {
-    PLOG(ERROR) << "Failed to write .dynamic for " << elf_file_->GetPath();
-    return false;
-  }
-
-  // .shstrtab
-  DCHECK_LE(dynamic_offset + dynamic_size, shstrtab_offset);
-  if (static_cast<off_t>(shstrtab_offset) != lseek(elf_file_->Fd(), shstrtab_offset, SEEK_SET)) {
-    PLOG(ERROR) << "Failed to seek to .shstrtab offset " << shstrtab_offset
-                << " for " << elf_file_->GetPath();
-    return false;
-  }
-  if (!elf_file_->WriteFully(&shstrtab[0], shstrtab_size)) {
-    PLOG(ERROR) << "Failed to write .shstrtab for " << elf_file_->GetPath();
-    return false;
-  }
-
-  if (generateDebugInformation) {
-    // .debug_info
-    DCHECK_LE(shstrtab_offset + shstrtab_size, shdbg_info_offset);
-    if (static_cast<off_t>(shdbg_info_offset) != lseek(elf_file_->Fd(), shdbg_info_offset, SEEK_SET)) {
-      PLOG(ERROR) << "Failed to seek to .shdbg_info offset " << shdbg_info_offset
-                  << " for " << elf_file_->GetPath();
-      return false;
-    }
-    if (!elf_file_->WriteFully(&dbg_info[0], shdbg_info_size)) {
-      PLOG(ERROR) << "Failed to write .debug_info for " << elf_file_->GetPath();
-      return false;
-    }
-
-    // .debug_abbrev
-    DCHECK_LE(shdbg_info_offset + shdbg_info_size, shdbg_abbrev_offset);
-    if (static_cast<off_t>(shdbg_abbrev_offset) != lseek(elf_file_->Fd(), shdbg_abbrev_offset, SEEK_SET)) {
-      PLOG(ERROR) << "Failed to seek to .shdbg_abbrev offset " << shdbg_abbrev_offset
-                  << " for " << elf_file_->GetPath();
-      return false;
-    }
-    if (!elf_file_->WriteFully(&dbg_abbrev[0], shdbg_abbrev_size)) {
-      PLOG(ERROR) << "Failed to write .debug_abbrev for " << elf_file_->GetPath();
-      return false;
-    }
-
-    // .debug_frame
-    DCHECK_LE(shdbg_abbrev_offset + shdbg_abbrev_size, shdbg_frm_offset);
-    if (static_cast<off_t>(shdbg_frm_offset) != lseek(elf_file_->Fd(), shdbg_frm_offset, SEEK_SET)) {
-      PLOG(ERROR) << "Failed to seek to .shdbg_frm offset " << shdbg_frm_offset
-                  << " for " << elf_file_->GetPath();
-      return false;
-    }
-    if (!elf_file_->WriteFully(&((*compiler_driver_->GetCallFrameInformation())[0]), shdbg_frm_size)) {
-      PLOG(ERROR) << "Failed to write .debug_frame for " << elf_file_->GetPath();
-      return false;
-    }
-
-    // .debug_str
-    DCHECK_LE(shdbg_frm_offset + shdbg_frm_size, shdbg_str_offset);
-    if (static_cast<off_t>(shdbg_str_offset) != lseek(elf_file_->Fd(), shdbg_str_offset, SEEK_SET)) {
-      PLOG(ERROR) << "Failed to seek to .shdbg_str offset " << shdbg_str_offset
-                  << " for " << elf_file_->GetPath();
-      return false;
-    }
-    if (!elf_file_->WriteFully(&dbg_str[0], shdbg_str_size)) {
-      PLOG(ERROR) << "Failed to write .debug_frame for " << elf_file_->GetPath();
-      return false;
-    }
-  }
-
-  // section headers (after all sections)
-  if (generateDebugInformation) {
-    DCHECK_LE(shdbg_str_offset + shdbg_str_size, shdr_offset);
-  } else {
-    DCHECK_LE(shstrtab_offset + shstrtab_size, shdr_offset);
-  }
-  if (static_cast<off_t>(shdr_offset) != lseek(elf_file_->Fd(), shdr_offset, SEEK_SET)) {
-    PLOG(ERROR) << "Failed to seek to ELF section headers offset " << shdr_offset
-                << " for " << elf_file_->GetPath();
-    return false;
-  }
-  if (!elf_file_->WriteFully(section_headers, sizeof(section_headers))) {
-    PLOG(ERROR) << "Failed to write ELF section headers for " << elf_file_->GetPath();
-    return false;
-  }
-
-  VLOG(compiler) << "ELF file written successfully: " << elf_file_->GetPath();
   return true;
-}  // NOLINT(readability/fn_size)
+}
+
+bool ElfWriterQuick::ElfBuilder::WriteOutFile(const std::vector<ElfFilePiece>& pieces) {
+  // TODO It would be nice if this checked for overlap.
+  for (auto it = pieces.begin(); it != pieces.end(); ++it) {
+    if (it->data_) {
+      if (static_cast<off_t>(it->offset_) != lseek(elf_file_->Fd(), it->offset_, SEEK_SET)) {
+        PLOG(ERROR) << "Failed to seek to " << it->dbg_name_ << " offset location "
+                    << it->offset_ << " for " << elf_file_->GetPath();
+        return false;
+      }
+      if (!elf_file_->WriteFully(it->data_, it->size_)) {
+        PLOG(ERROR) << "Failed to write " << it->dbg_name_ << " for " << elf_file_->GetPath();
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+void ElfWriterQuick::ElfBuilder::SetupDynamic() {
+  dynamic_builder_.AddDynamicTag(DT_HASH, 0, &hash_builder_);
+  dynamic_builder_.AddDynamicTag(DT_STRTAB, 0, &dynsym_builder_.strtab_);
+  dynamic_builder_.AddDynamicTag(DT_SYMTAB, 0, &dynsym_builder_);
+  dynamic_builder_.AddDynamicTag(DT_SYMENT, sizeof(Elf32_Sym));
+}
+
+void ElfWriterQuick::ElfBuilder::SetupRequiredSymbols() {
+  dynsym_builder_.AddSymbol("oatdata", &rodata_builder_, 0, true,
+                            rodata_builder_.size_, STB_GLOBAL, STT_OBJECT);
+  dynsym_builder_.AddSymbol("oatexec", &text_builder_, 0, true,
+                            text_builder_.size_, STB_GLOBAL, STT_OBJECT);
+  dynsym_builder_.AddSymbol("oatlastword", &text_builder_, text_builder_.size_ - 4,
+                            true, 4, STB_GLOBAL, STT_OBJECT);
+}
+
+void ElfWriterQuick::ElfDynamicBuilder::AddDynamicTag(Elf32_Sword tag, Elf32_Word d_un) {
+  if (tag == DT_NULL) {
+    return;
+  }
+  dynamics_.push_back({NULL, tag, d_un});
+}
+
+void ElfWriterQuick::ElfDynamicBuilder::AddDynamicTag(Elf32_Sword tag, Elf32_Word d_un,
+                                                      ElfSectionBuilder* section) {
+  if (tag == DT_NULL) {
+    return;
+  }
+  dynamics_.push_back({section, tag, d_un});
+}
+
+std::vector<Elf32_Dyn> ElfWriterQuick::ElfDynamicBuilder::GetDynamics(Elf32_Word strsz,
+                                                                      Elf32_Word soname) {
+  std::vector<Elf32_Dyn> ret;
+  for (auto it = dynamics_.cbegin(); it != dynamics_.cend(); ++it) {
+    if (it->section_) {
+      // We are adding an address relative to a section.
+      ret.push_back(
+          {it->tag_, {it->off_ + it->section_->section_.sh_addr}});
+    } else {
+      ret.push_back({it->tag_, {it->off_}});
+    }
+  }
+  ret.push_back({DT_STRSZ, {strsz}});
+  ret.push_back({DT_SONAME, {soname}});
+  ret.push_back({DT_NULL, {0}});
+  return ret;
+}
+
+std::vector<Elf32_Sym> ElfWriterQuick::ElfSymtabBuilder::GenerateSymtab() {
+  std::vector<Elf32_Sym> ret;
+  Elf32_Sym undef_sym;
+  memset(&undef_sym, 0, sizeof(undef_sym));
+  undef_sym.st_shndx = SHN_UNDEF;
+  ret.push_back(undef_sym);
+
+  for (auto it = symbols_.cbegin(); it != symbols_.cend(); ++it) {
+    Elf32_Sym sym;
+    memset(&sym, 0, sizeof(sym));
+    sym.st_name = it->name_idx_;
+    if (it->is_relative_) {
+      sym.st_value = it->addr_ + it->section_->section_.sh_offset;
+    } else {
+      sym.st_value = it->addr_;
+    }
+    sym.st_size = it->size_;
+    sym.st_other = it->other_;
+    sym.st_shndx = it->section_->section_index_;
+    sym.st_info = it->info_;
+
+    ret.push_back(sym);
+  }
+  return ret;
+}
+
+std::string ElfWriterQuick::ElfSymtabBuilder::GenerateStrtab() {
+  std::string tab;
+  tab += '\0';
+  for (auto it = symbols_.begin(); it != symbols_.end(); ++it) {
+    it->name_idx_ = tab.size();
+    tab += it->name_;
+    tab += '\0';
+  }
+  strtab_.section_.sh_size = tab.size();
+  return tab;
+}
+
+void ElfWriterQuick::ElfBuilder::AssignSectionStr(
+    ElfSectionBuilder* builder, std::string* strtab) {
+  builder->section_.sh_name = strtab->size();
+  *strtab += builder->name_;
+  *strtab += '\0';
+  if (debug_logging_) {
+    LOG(INFO) << "adding section name \"" << builder->name_ << "\" "
+              << "to shstrtab at offset " << builder->section_.sh_name;
+  }
+}
+
+// from bionic
+static unsigned elfhash(const char *_name) {
+  const unsigned char *name = (const unsigned char *) _name;
+  unsigned h = 0, g;
+
+  while (*name) {
+    h = (h << 4) + *name++;
+    g = h & 0xf0000000;
+    h ^= g;
+    h ^= g >> 24;
+  }
+  return h;
+}
+
+
+std::vector<Elf32_Word> ElfWriterQuick::ElfSymtabBuilder::GenerateHashContents() {
+  // Here is how The ELF hash table works.
+  // There are 3 arrays to worry about.
+  // * The symbol table where the symbol information is.
+  // * The bucket array which is an array of indexes into the symtab and chain.
+  // * The chain array which is also an array of indexes into the symtab and chain.
+  //
+  // Lets say the state is something like this.
+  // +--------+       +--------+      +-----------+
+  // | symtab |       | bucket |      |   chain   |
+  // |  NULL  |       | 1      |      | STN_UNDEF |
+  // | <sym1> |       | 4      |      | 2         |
+  // | <sym2> |       |        |      | 5         |
+  // | <sym3> |       |        |      | STN_UNDEF |
+  // | <sym4> |       |        |      | 3         |
+  // | <sym5> |       |        |      | STN_UNDEF |
+  // +--------+       +--------+      +-----------+
+  //
+  // The lookup process (in python psudocode) is
+  //
+  // def GetSym(name):
+  //     # NB STN_UNDEF == 0
+  //     indx = bucket[elfhash(name) % num_buckets]
+  //     while indx != STN_UNDEF:
+  //         if GetSymbolName(symtab[indx]) == name:
+  //             return symtab[indx]
+  //         indx = chain[indx]
+  //     return SYMBOL_NOT_FOUND
+  //
+  // Between bucket and chain arrays every symtab index must be present exactly
+  // once (except for STN_UNDEF, which must be present 1 + num_bucket times).
+
+  // Select number of buckets.
+  // This is essentially arbitrary.
+  Elf32_Word nbuckets;
+  Elf32_Word chain_size = GetSize();
+  if (symbols_.size() < 8) {
+    nbuckets = 2;
+  } else if (symbols_.size() < 32) {
+    nbuckets = 4;
+  } else if (symbols_.size() < 256) {
+    nbuckets = 16;
+  } else {
+    // Have about 32 ids per bucket.
+    nbuckets = RoundUp(symbols_.size()/32, 2);
+  }
+  std::vector<Elf32_Word> hash;
+  hash.push_back(nbuckets);
+  hash.push_back(chain_size);
+  uint32_t bucket_offset = hash.size();
+  uint32_t chain_offset = bucket_offset + nbuckets;
+  hash.resize(hash.size() + nbuckets + chain_size, 0);
+
+  Elf32_Word* buckets = hash.data() + bucket_offset;
+  Elf32_Word* chain   = hash.data() + chain_offset;
+
+  // Set up the actual hash table.
+  for (Elf32_Word i = 0; i < symbols_.size(); i++) {
+    // Add 1 since we need to have the null symbol that is not in the symbols
+    // list.
+    Elf32_Word index = i + 1;
+    Elf32_Word hash_val = static_cast<Elf32_Word>(elfhash(symbols_[i].name_.c_str())) % nbuckets;
+    if (buckets[hash_val] == 0) {
+      buckets[hash_val] = index;
+    } else {
+      hash_val = buckets[hash_val];
+      CHECK_LT(hash_val, chain_size);
+      while (chain[hash_val] != 0) {
+        hash_val = chain[hash_val];
+        CHECK_LT(hash_val, chain_size);
+      }
+      chain[hash_val] = index;
+      // Check for loops. Works because if this is non-empty then there must be
+      // another cell which already contains the same symbol index as this one,
+      // which means some symbol has more then one name, which isn't allowed.
+      CHECK_EQ(chain[index], static_cast<Elf32_Word>(0));
+    }
+  }
+
+  return hash;
+}
+
+void ElfWriterQuick::ElfBuilder::SetupEhdr() {
+  memset(&elf_header_, 0, sizeof(elf_header_));
+  elf_header_.e_ident[EI_MAG0]       = ELFMAG0;
+  elf_header_.e_ident[EI_MAG1]       = ELFMAG1;
+  elf_header_.e_ident[EI_MAG2]       = ELFMAG2;
+  elf_header_.e_ident[EI_MAG3]       = ELFMAG3;
+  elf_header_.e_ident[EI_CLASS]      = ELFCLASS32;
+  elf_header_.e_ident[EI_DATA]       = ELFDATA2LSB;
+  elf_header_.e_ident[EI_VERSION]    = EV_CURRENT;
+  elf_header_.e_ident[EI_OSABI]      = ELFOSABI_LINUX;
+  elf_header_.e_ident[EI_ABIVERSION] = 0;
+  elf_header_.e_type = ET_DYN;
+  elf_header_.e_version = 1;
+  elf_header_.e_entry = 0;
+  elf_header_.e_ehsize = sizeof(Elf32_Ehdr);
+  elf_header_.e_phentsize = sizeof(Elf32_Phdr);
+  elf_header_.e_shentsize = sizeof(Elf32_Shdr);
+  elf_header_.e_phoff = sizeof(Elf32_Ehdr);
+}
+
+void ElfWriterQuick::ElfBuilder::SetISA(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+      // Fall through.
+    case kThumb2: {
+      elf_header_.e_machine = EM_ARM;
+      elf_header_.e_flags = EF_ARM_EABI_VER5;
+      break;
+    }
+    case kArm64: {
+      elf_header_.e_machine = EM_AARCH64;
+      elf_header_.e_flags = 0;
+      break;
+    }
+    case kX86: {
+      elf_header_.e_machine = EM_386;
+      elf_header_.e_flags = 0;
+      break;
+    }
+    case kX86_64: {
+      elf_header_.e_machine = EM_X86_64;
+      elf_header_.e_flags = 0;
+      break;
+    }
+    case kMips: {
+      elf_header_.e_machine = EM_MIPS;
+      elf_header_.e_flags = (EF_MIPS_NOREORDER |
+                             EF_MIPS_PIC       |
+                             EF_MIPS_CPIC      |
+                             EF_MIPS_ABI_O32   |
+                             EF_MIPS_ARCH_32R2);
+      break;
+    }
+    default: {
+      fatal_error_ = true;
+      LOG(FATAL) << "Unknown instruction set: " << isa;
+      break;
+    }
+  }
+}
+
+void ElfWriterQuick::ElfSymtabBuilder::AddSymbol(
+    const std::string& name, const ElfSectionBuilder* section, Elf32_Addr addr,
+    bool is_relative, Elf32_Word size, uint8_t binding, uint8_t type, uint8_t other) {
+  CHECK(section);
+  ElfSymtabBuilder::ElfSymbolState state {name, section, addr, size, is_relative,
+                                          MakeStInfo(binding, type), other, 0};
+  symbols_.push_back(state);
+}
+
+bool ElfWriterQuick::Create(File* elf_file,
+                            OatWriter* oat_writer,
+                            const std::vector<const DexFile*>& dex_files,
+                            const std::string& android_root,
+                            bool is_host,
+                            const CompilerDriver& driver) {
+  ElfWriterQuick elf_writer(driver, elf_file);
+  return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
+}
+
+bool ElfWriterQuick::Write(OatWriter* oat_writer,
+                           const std::vector<const DexFile*>& dex_files_unused,
+                           const std::string& android_root_unused,
+                           bool is_host_unused) {
+  const bool debug = false;
+  const OatHeader& oat_header = oat_writer->GetOatHeader();
+  Elf32_Word oat_data_size = oat_header.GetExecutableOffset();
+  uint32_t oat_exec_size = oat_writer->GetSize() - oat_data_size;
+
+  ElfBuilder builder(oat_writer, elf_file_, compiler_driver_->GetInstructionSet(), 0,
+                     oat_data_size, oat_data_size, oat_exec_size, false, debug);
+
+  bool generateDebugInformation = compiler_driver_->GetCallFrameInformation() != nullptr;
+  if (generateDebugInformation) {
+    ElfRawSectionBuilder debug_info(".debug_info",   SHT_PROGBITS, 0, NULL, 0, 1, 0);
+    ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, NULL, 0, 1, 0);
+    ElfRawSectionBuilder debug_str(".debug_str",    SHT_PROGBITS, 0, NULL, 0, 1, 0);
+    ElfRawSectionBuilder debug_frame(".debug_frame",  SHT_PROGBITS, 0, NULL, 0, 4, 0);
+    debug_frame.SetBuffer(*compiler_driver_->GetCallFrameInformation());
+
+    FillInCFIInformation(oat_writer, debug_info.GetBuffer(),
+                         debug_abbrev.GetBuffer(), debug_str.GetBuffer());
+    builder.RegisterRawSection(debug_info);
+    builder.RegisterRawSection(debug_abbrev);
+    builder.RegisterRawSection(debug_frame);
+    builder.RegisterRawSection(debug_str);
+  }
+
+  return builder.Write();
+}
 
 static void UpdateWord(std::vector<uint8_t>*buf, int offset, int data) {
   (*buf)[offset+0] = data;
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index dec75dc..f687d2e 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -17,7 +17,9 @@
 #ifndef ART_COMPILER_ELF_WRITER_QUICK_H_
 #define ART_COMPILER_ELF_WRITER_QUICK_H_
 
+#include "elf_utils.h"
 #include "elf_writer.h"
+#include "instruction_set.h"
 
 namespace art {
 
@@ -45,6 +47,265 @@
     : ElfWriter(driver, elf_file) {}
   ~ElfWriterQuick() {}
 
+  class ElfBuilder;
+  class ElfSectionBuilder {
+   public:
+    ElfSectionBuilder(const std::string& sec_name, Elf32_Word type, Elf32_Word flags,
+                      const ElfSectionBuilder *link, Elf32_Word info, Elf32_Word align,
+                      Elf32_Word entsize)
+        : name_(sec_name), link_(link) {
+      memset(&section_, 0, sizeof(section_));
+      section_.sh_type = type;
+      section_.sh_flags = flags;
+      section_.sh_info = info;
+      section_.sh_addralign = align;
+      section_.sh_entsize = entsize;
+    }
+
+    virtual ~ElfSectionBuilder() {}
+
+    Elf32_Shdr section_;
+    Elf32_Word section_index_ = 0;
+
+   protected:
+    const std::string name_;
+    const ElfSectionBuilder* link_;
+
+    Elf32_Word GetLink() {
+      return (link_) ? link_->section_index_ : 0;
+    }
+
+   private:
+    friend class ElfBuilder;
+  };
+
+  class ElfDynamicBuilder : public ElfSectionBuilder {
+   public:
+    void AddDynamicTag(Elf32_Sword tag, Elf32_Word d_un);
+    void AddDynamicTag(Elf32_Sword tag, Elf32_Word offset, ElfSectionBuilder* section);
+
+    ElfDynamicBuilder(const std::string& sec_name, ElfSectionBuilder *link)
+        : ElfSectionBuilder(sec_name, SHT_DYNAMIC, SHF_ALLOC | SHF_ALLOC, link,
+                            0, kPageSize, sizeof(Elf32_Dyn)) {}
+    ~ElfDynamicBuilder() {}
+
+   protected:
+    struct ElfDynamicState {
+      ElfSectionBuilder* section_;
+      Elf32_Sword tag_;
+      Elf32_Word off_;
+    };
+    std::vector<ElfDynamicState> dynamics_;
+    Elf32_Word GetSize() {
+      // Add 1 for the DT_NULL, 1 for DT_STRSZ, and 1 for DT_SONAME. All of
+      // these must be added when we actually put the file together because
+      // their values are very dependent on state.
+      return dynamics_.size() + 3;
+    }
+
+    // Create the actual dynamic vector. strsz should be the size of the .dynstr
+    // table and soname_off should be the offset of the soname in .dynstr.
+    // Since niether can be found prior to final layout we will wait until here
+    // to add them.
+    std::vector<Elf32_Dyn> GetDynamics(Elf32_Word strsz, Elf32_Word soname_off);
+
+   private:
+    friend class ElfBuilder;
+  };
+
+  class ElfRawSectionBuilder : public ElfSectionBuilder {
+   public:
+    ElfRawSectionBuilder(const std::string& sec_name, Elf32_Word type, Elf32_Word flags,
+                         const ElfSectionBuilder* link, Elf32_Word info, Elf32_Word align,
+                         Elf32_Word entsize)
+        : ElfSectionBuilder(sec_name, type, flags, link, info, align, entsize) {}
+    ~ElfRawSectionBuilder() {}
+    std::vector<uint8_t>* GetBuffer() { return &buf_; }
+    void SetBuffer(std::vector<uint8_t> buf) { buf_ = buf; }
+
+   protected:
+    std::vector<uint8_t> buf_;
+
+   private:
+    friend class ElfBuilder;
+  };
+
+  class ElfOatSectionBuilder : public ElfSectionBuilder {
+   public:
+    ElfOatSectionBuilder(const std::string& sec_name, Elf32_Word size, Elf32_Word offset,
+                         Elf32_Word type, Elf32_Word flags)
+        : ElfSectionBuilder(sec_name, type, flags, NULL, 0, kPageSize, 0),
+          offset_(offset), size_(size) {}
+    ~ElfOatSectionBuilder() {}
+
+   protected:
+    // Offset of the content within the file.
+    Elf32_Word offset_;
+    // Size of the content within the file.
+    Elf32_Word size_;
+
+   private:
+    friend class ElfBuilder;
+  };
+
+  class ElfSymtabBuilder : public ElfSectionBuilder {
+   public:
+    // Add a symbol with given name to this symtab. The symbol refers to
+    // 'relative_addr' within the given section and has the given attributes.
+    void AddSymbol(const std::string& name,
+                   const ElfSectionBuilder* section,
+                   Elf32_Addr addr,
+                   bool is_relative,
+                   Elf32_Word size,
+                   uint8_t binding,
+                   uint8_t type,
+                   uint8_t other = 0);
+
+    ElfSymtabBuilder(const std::string& sec_name, Elf32_Word type,
+                     const std::string& str_name, Elf32_Word str_type, bool alloc)
+        : ElfSectionBuilder(sec_name, type, ((alloc)?SHF_ALLOC:0), &strtab_, 0,
+                            sizeof(Elf32_Word), sizeof(Elf32_Sym)),
+          str_name_(str_name), str_type_(str_type),
+          strtab_(str_name, str_type, ((alloc) ? SHF_ALLOC : 0), NULL, 0, 1, 1) {}
+    ~ElfSymtabBuilder() {}
+
+   protected:
+    std::vector<Elf32_Word> GenerateHashContents();
+    std::string GenerateStrtab();
+    std::vector<Elf32_Sym> GenerateSymtab();
+
+    Elf32_Word GetSize() {
+      // 1 is for the implicit NULL symbol.
+      return symbols_.size() + 1;
+    }
+
+    struct ElfSymbolState {
+      const std::string name_;
+      const ElfSectionBuilder* section_;
+      Elf32_Addr addr_;
+      Elf32_Word size_;
+      bool is_relative_;
+      uint8_t info_;
+      uint8_t other_;
+      // Used during Write() to temporarially hold name index in the strtab.
+      Elf32_Word name_idx_;
+    };
+
+    // Information for the strsym for dynstr sections.
+    const std::string str_name_;
+    Elf32_Word str_type_;
+    // The symbols in the same order they will be in the symbol table.
+    std::vector<ElfSymbolState> symbols_;
+    ElfSectionBuilder strtab_;
+
+   private:
+    friend class ElfBuilder;
+  };
+
+  class ElfBuilder FINAL {
+   public:
+    ElfBuilder(OatWriter* oat_writer,
+               File* elf_file,
+               InstructionSet isa,
+               Elf32_Word rodata_relative_offset,
+               Elf32_Word rodata_size,
+               Elf32_Word text_relative_offset,
+               Elf32_Word text_size,
+               const bool add_symbols,
+               bool debug = false)
+        : oat_writer_(oat_writer),
+          elf_file_(elf_file),
+          add_symbols_(add_symbols),
+          debug_logging_(debug),
+          text_builder_(".text", text_size, text_relative_offset, SHT_PROGBITS,
+                        SHF_ALLOC | SHF_EXECINSTR),
+          rodata_builder_(".rodata", rodata_size, rodata_relative_offset,
+                          SHT_PROGBITS, SHF_ALLOC),
+          dynsym_builder_(".dynsym", SHT_DYNSYM, ".dynstr", SHT_STRTAB, true),
+          symtab_builder_(".symtab", SHT_SYMTAB, ".strtab", SHT_STRTAB, false),
+          hash_builder_(".hash", SHT_HASH, SHF_ALLOC, &dynsym_builder_, 0,
+                        sizeof(Elf32_Word), sizeof(Elf32_Word)),
+          dynamic_builder_(".dynamic", &dynsym_builder_),
+          shstrtab_builder_(".shstrtab", SHT_STRTAB, 0, NULL, 0, 1, 1) {
+      SetupEhdr();
+      SetupDynamic();
+      SetupRequiredSymbols();
+      SetISA(isa);
+    }
+    ~ElfBuilder() {}
+
+    bool Write();
+    ElfSymtabBuilder* GetDefaultDynsymBuilder() { return &dynsym_builder_; }
+
+    // Adds the given raw section to the builder. This will copy it. The caller
+    // is responsible for deallocating their copy.
+    void RegisterRawSection(ElfRawSectionBuilder bld) {
+      other_builders_.push_back(bld);
+    }
+
+   private:
+    OatWriter* oat_writer_;
+    File* elf_file_;
+    const bool add_symbols_;
+    const bool debug_logging_;
+
+    bool fatal_error_ = false;
+
+    Elf32_Ehdr elf_header_;
+
+   public:
+    ElfOatSectionBuilder text_builder_;
+    ElfOatSectionBuilder rodata_builder_;
+    ElfSymtabBuilder dynsym_builder_;
+    ElfSymtabBuilder symtab_builder_;
+    ElfSectionBuilder hash_builder_;
+    ElfDynamicBuilder dynamic_builder_;
+    ElfSectionBuilder shstrtab_builder_;
+    std::vector<ElfRawSectionBuilder> other_builders_;
+
+   private:
+    void SetISA(InstructionSet isa);
+    void SetupEhdr();
+
+    // Sets up a bunch of the required Dynamic Section entries.
+    // Namely it will initialize all the mandatory ones that it can.
+    // Specifically:
+    // DT_HASH
+    // DT_STRTAB
+    // DT_SYMTAB
+    // DT_SYMENT
+    //
+    // Some such as DT_SONAME, DT_STRSZ and DT_NULL will be put in later.
+    void SetupDynamic();
+
+    // Sets up the basic dynamic symbols that are needed, namely all those we
+    // can know already.
+    //
+    // Specifically adds:
+    // oatdata
+    // oatexec
+    // oatlastword
+    void SetupRequiredSymbols();
+    void AssignSectionStr(ElfSectionBuilder *builder, std::string* strtab);
+    struct ElfFilePiece {
+      ElfFilePiece(const std::string& name, Elf32_Word offset, const void* data, Elf32_Word size)
+          : dbg_name_(name), offset_(offset), data_(data), size_(size) {}
+      ~ElfFilePiece() {}
+
+      const std::string& dbg_name_;
+      Elf32_Word offset_;
+      const void *data_;
+      Elf32_Word size_;
+      static bool Compare(ElfFilePiece a, ElfFilePiece b) {
+        return a.offset_ < b.offset_;
+      }
+    };
+
+    // Write each of the pieces out to the file.
+    bool WriteOutFile(const std::vector<ElfFilePiece>& pieces);
+    bool IncludingDebugSymbols() { return add_symbols_ && symtab_builder_.GetSize() > 1; }
+  };
+
   /*
    * @brief Generate the DWARF debug_info and debug_abbrev sections
    * @param oat_writer The Oat file Writer.
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index beafbcc..f05cb66 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -29,30 +29,60 @@
 
 namespace art {
 
-void CodeGenerator::Compile(CodeAllocator* allocator) {
+void CodeGenerator::CompileBaseline(CodeAllocator* allocator) {
   const GrowableArray<HBasicBlock*>& blocks = GetGraph()->GetBlocks();
   DCHECK(blocks.Get(0) == GetGraph()->GetEntryBlock());
   DCHECK(GoesToNextBlock(GetGraph()->GetEntryBlock(), blocks.Get(1)));
+  block_labels_.SetSize(blocks.Size());
+
+  DCHECK_EQ(frame_size_, kUninitializedFrameSize);
+  ComputeFrameSize(GetGraph()->GetMaximumNumberOfOutVRegs()
+                   + GetGraph()->GetNumberOfVRegs()
+                   + 1 /* filler */);
   GenerateFrameEntry();
+
   for (size_t i = 0, e = blocks.Size(); i < e; ++i) {
-    CompileBlock(blocks.Get(i));
+    HBasicBlock* block = blocks.Get(i);
+    Bind(GetLabelOf(block));
+    HGraphVisitor* location_builder = GetLocationBuilder();
+    HGraphVisitor* instruction_visitor = GetInstructionVisitor();
+    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+      HInstruction* current = it.Current();
+      current->Accept(location_builder);
+      InitLocations(current);
+      current->Accept(instruction_visitor);
+    }
   }
+
   size_t code_size = GetAssembler()->CodeSize();
   uint8_t* buffer = allocator->Allocate(code_size);
   MemoryRegion code(buffer, code_size);
   GetAssembler()->FinalizeInstructions(code);
 }
 
-void CodeGenerator::CompileBlock(HBasicBlock* block) {
-  Bind(GetLabelOf(block));
-  HGraphVisitor* location_builder = GetLocationBuilder();
-  HGraphVisitor* instruction_visitor = GetInstructionVisitor();
-  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
-    HInstruction* current = it.Current();
-    current->Accept(location_builder);
-    InitLocations(current);
-    current->Accept(instruction_visitor);
+void CodeGenerator::CompileOptimized(CodeAllocator* allocator) {
+  // The frame size has already been computed during register allocation.
+  DCHECK_NE(frame_size_, kUninitializedFrameSize);
+  const GrowableArray<HBasicBlock*>& blocks = GetGraph()->GetBlocks();
+  DCHECK(blocks.Get(0) == GetGraph()->GetEntryBlock());
+  DCHECK(GoesToNextBlock(GetGraph()->GetEntryBlock(), blocks.Get(1)));
+  block_labels_.SetSize(blocks.Size());
+
+  GenerateFrameEntry();
+  for (size_t i = 0, e = blocks.Size(); i < e; ++i) {
+    HBasicBlock* block = blocks.Get(i);
+    Bind(GetLabelOf(block));
+    HGraphVisitor* instruction_visitor = GetInstructionVisitor();
+    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+      HInstruction* current = it.Current();
+      current->Accept(instruction_visitor);
+    }
   }
+
+  size_t code_size = GetAssembler()->CodeSize();
+  uint8_t* buffer = allocator->Allocate(code_size);
+  MemoryRegion code(buffer, code_size);
+  GetAssembler()->FinalizeInstructions(code);
 }
 
 size_t CodeGenerator::AllocateFreeRegisterInternal(
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index e197ccd..82fa639 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -28,6 +28,7 @@
 namespace art {
 
 static size_t constexpr kVRegSize = 4;
+static size_t constexpr kUninitializedFrameSize = 0;
 
 class DexCompilationUnit;
 
@@ -51,7 +52,8 @@
  public:
   // Compiles the graph to executable instructions. Returns whether the compilation
   // succeeded.
-  void Compile(CodeAllocator* allocator);
+  void CompileBaseline(CodeAllocator* allocator);
+  void CompileOptimized(CodeAllocator* allocator);
   static CodeGenerator* Create(ArenaAllocator* allocator,
                                HGraph* graph,
                                InstructionSet instruction_set);
@@ -61,6 +63,14 @@
   Label* GetLabelOf(HBasicBlock* block) const;
   bool GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const;
 
+  size_t GetStackSlotOfParameter(HParameterValue* parameter) const {
+    // Note that this follows the current calling convention.
+    return GetFrameSize()
+        + kVRegSize  // Art method
+        + (parameter->GetIndex() - graph_->GetNumberOfVRegs() + graph_->GetNumberOfInVRegs())
+          * kVRegSize;
+  }
+
   virtual void GenerateFrameEntry() = 0;
   virtual void GenerateFrameExit() = 0;
   virtual void Bind(Label* label) = 0;
@@ -69,6 +79,7 @@
   virtual HGraphVisitor* GetInstructionVisitor() = 0;
   virtual Assembler* GetAssembler() = 0;
   virtual size_t GetWordSize() const = 0;
+  virtual void ComputeFrameSize(size_t number_of_spill_slots) = 0;
 
   uint32_t GetFrameSize() const { return frame_size_; }
   void SetFrameSize(uint32_t size) { frame_size_ = size; }
@@ -95,14 +106,12 @@
 
  protected:
   CodeGenerator(HGraph* graph, size_t number_of_registers)
-      : frame_size_(0),
+      : frame_size_(kUninitializedFrameSize),
         graph_(graph),
         block_labels_(graph->GetArena(), 0),
         pc_infos_(graph->GetArena(), 32),
-        blocked_registers_(graph->GetArena()->AllocArray<bool>(number_of_registers)) {
-    block_labels_.SetSize(graph->GetBlocks().Size());
-  }
-  ~CodeGenerator() { }
+        blocked_registers_(graph->GetArena()->AllocArray<bool>(number_of_registers)) {}
+  ~CodeGenerator() {}
 
   // Register allocation logic.
   void AllocateRegistersLocally(HInstruction* instruction) const;
@@ -123,7 +132,6 @@
 
  private:
   void InitLocations(HInstruction* instruction);
-  void CompileBlock(HBasicBlock* block);
 
   HGraph* const graph_;
 
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index e888cc1..d61df36 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -129,16 +129,18 @@
         assembler_(codegen->GetAssembler()),
         codegen_(codegen) {}
 
+void CodeGeneratorARM::ComputeFrameSize(size_t number_of_spill_slots) {
+  SetFrameSize(RoundUp(
+      number_of_spill_slots * kVRegSize
+      + kVRegSize  // Art method
+      + kNumberOfPushedRegistersAtEntry * kArmWordSize,
+      kStackAlignment));
+}
+
 void CodeGeneratorARM::GenerateFrameEntry() {
   core_spill_mask_ |= (1 << LR);
   __ PushList((1 << LR));
 
-  SetFrameSize(RoundUp(
-      (GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs()) * kVRegSize
-      + kVRegSize  // filler
-      + kArmWordSize  // Art method
-      + kNumberOfPushedRegistersAtEntry * kArmWordSize,
-      kStackAlignment));
   // The return PC has already been pushed on the stack.
   __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize));
   __ str(R0, Address(SP, 0));
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index c945a06..ac5ef21 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -104,6 +104,7 @@
   explicit CodeGeneratorARM(HGraph* graph);
   virtual ~CodeGeneratorARM() { }
 
+  virtual void ComputeFrameSize(size_t number_of_spill_slots) OVERRIDE;
   virtual void GenerateFrameEntry() OVERRIDE;
   virtual void GenerateFrameExit() OVERRIDE;
   virtual void Bind(Label* label) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 72c697f..c7dca86 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -48,7 +48,16 @@
 CodeGeneratorX86::CodeGeneratorX86(HGraph* graph)
     : CodeGenerator(graph, kNumberOfRegIds),
       location_builder_(graph, this),
-      instruction_visitor_(graph, this) {}
+      instruction_visitor_(graph, this),
+      move_resolver_(graph->GetArena(), this) {}
+
+void CodeGeneratorX86::ComputeFrameSize(size_t number_of_spill_slots) {
+  SetFrameSize(RoundUp(
+      number_of_spill_slots * kVRegSize
+      + kVRegSize  // Art method
+      + kNumberOfPushedRegistersAtEntry * kX86WordSize,
+      kStackAlignment));
+}
 
 static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
   return blocked_registers + kNumberOfAllocIds;
@@ -125,13 +134,6 @@
   static const int kFakeReturnRegister = 8;
   core_spill_mask_ |= (1 << kFakeReturnRegister);
 
-  SetFrameSize(RoundUp(
-      (GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs()) * kVRegSize
-      + kVRegSize  // filler
-      + kX86WordSize  // Art method
-      + kNumberOfPushedRegistersAtEntry * kX86WordSize,
-      kStackAlignment));
-
   // The return PC has already been pushed on the stack.
   __ subl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
   __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
@@ -264,8 +266,8 @@
       __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsCpuRegister());
     } else {
       DCHECK(source.IsStackSlot());
-      __ movl(EAX, Address(ESP, source.GetStackIndex()));
-      __ movl(Address(ESP, destination.GetStackIndex()), EAX);
+      __ pushl(Address(ESP, source.GetStackIndex()));
+      __ popl(Address(ESP, destination.GetStackIndex()));
     }
   }
 }
@@ -302,8 +304,8 @@
       DCHECK(source.IsDoubleStackSlot());
       __ movl(calling_convention.GetRegisterAt(argument_index),
               Address(ESP, source.GetStackIndex()));
-      __ movl(EAX, Address(ESP, source.GetHighStackIndex(kX86WordSize)));
-      __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize)), EAX);
+      __ pushl(Address(ESP, source.GetHighStackIndex(kX86WordSize)));
+      __ popl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize)));
     }
   } else {
     if (source.IsRegister()) {
@@ -315,15 +317,15 @@
       uint32_t argument_index = source.GetQuickParameterIndex();
       __ movl(Address(ESP, destination.GetStackIndex()),
               calling_convention.GetRegisterAt(argument_index));
-      __ movl(EAX, Address(ESP,
+      __ pushl(Address(ESP,
           calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize) + GetFrameSize()));
-      __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), EAX);
+      __ popl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)));
     } else {
       DCHECK(source.IsDoubleStackSlot());
-      __ movl(EAX, Address(ESP, source.GetStackIndex()));
-      __ movl(Address(ESP, destination.GetStackIndex()), EAX);
-      __ movl(EAX, Address(ESP, source.GetHighStackIndex(kX86WordSize)));
-      __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), EAX);
+      __ pushl(Address(ESP, source.GetStackIndex()));
+      __ popl(Address(ESP, destination.GetStackIndex()));
+      __ pushl(Address(ESP, source.GetHighStackIndex(kX86WordSize)));
+      __ popl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)));
     }
   }
 }
@@ -501,7 +503,7 @@
 }
 
 void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
-  // Will be generated at use site.
+  codegen_->Move(constant, constant->GetLocations()->Out(), nullptr);
 }
 
 void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
@@ -573,7 +575,7 @@
 
 void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
-  locations->AddTemp(Location::RequiresRegister());
+  locations->AddTemp(X86CpuLocation(EAX));
 
   InvokeDexCallingConventionVisitor calling_convention_visitor;
   for (size_t i = 0; i < invoke->InputCount(); i++) {
@@ -802,7 +804,6 @@
 }
 
 void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
-  // Nothing to do, the parameter is already at its location.
 }
 
 void LocationsBuilderX86::VisitNot(HNot* instruction) {
@@ -829,15 +830,100 @@
 }
 
 void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
-  LOG(FATAL) << "Unimplemented";
+  LOG(FATAL) << "Unreachable";
 }
 
 void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
-  LOG(FATAL) << "Unimplemented";
+  LOG(FATAL) << "Unreachable";
 }
 
 void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
-  LOG(FATAL) << "Unimplemented";
+  codegen_->GetMoveResolver()->EmitNativeCode(instruction);
+}
+
+X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
+  return codegen_->GetAssembler();
+}
+
+void ParallelMoveResolverX86::MoveMemoryToMemory(int dst, int src) {
+  ScratchRegisterScope ensure_scratch(
+      this, kNoRegister, codegen_->GetNumberOfCoreRegisters());
+  int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
+  __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, src + stack_offset));
+  __ movl(Address(ESP, dst + stack_offset), static_cast<Register>(ensure_scratch.GetRegister()));
+}
+
+void ParallelMoveResolverX86::EmitMove(size_t index) {
+  MoveOperands* move = moves_.Get(index);
+  Location source = move->GetSource();
+  Location destination = move->GetDestination();
+
+  if (source.IsRegister()) {
+    if (destination.IsRegister()) {
+      __ movl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister());
+    } else {
+      DCHECK(destination.IsStackSlot());
+      __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsCpuRegister());
+    }
+  } else if (source.IsStackSlot()) {
+    if (destination.IsRegister()) {
+      __ movl(destination.AsX86().AsCpuRegister(), Address(ESP, source.GetStackIndex()));
+    } else {
+      DCHECK(destination.IsStackSlot());
+      MoveMemoryToMemory(destination.GetStackIndex(),
+                         source.GetStackIndex());
+    }
+  } else {
+    LOG(FATAL) << "Unimplemented";
+  }
+}
+
+void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
+  ScratchRegisterScope ensure_scratch(this, reg, codegen_->GetNumberOfCoreRegisters());
+  int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
+  __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
+  __ movl(Address(ESP, mem + stack_offset), reg);
+  __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
+}
+
+
+void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
+  ScratchRegisterScope ensure_scratch1(
+      this, kNoRegister, codegen_->GetNumberOfCoreRegisters());
+  ScratchRegisterScope ensure_scratch2(
+      this, ensure_scratch1.GetRegister(), codegen_->GetNumberOfCoreRegisters());
+  int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
+  stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
+  __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
+  __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
+  __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
+  __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
+}
+
+void ParallelMoveResolverX86::EmitSwap(size_t index) {
+  MoveOperands* move = moves_.Get(index);
+  Location source = move->GetSource();
+  Location destination = move->GetDestination();
+
+  if (source.IsRegister() && destination.IsRegister()) {
+    __ xchgl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister());
+  } else if (source.IsRegister() && destination.IsStackSlot()) {
+    Exchange(source.AsX86().AsCpuRegister(), destination.GetStackIndex());
+  } else if (source.IsStackSlot() && destination.IsRegister()) {
+    Exchange(destination.AsX86().AsCpuRegister(), source.GetStackIndex());
+  } else if (source.IsStackSlot() && destination.IsStackSlot()) {
+    Exchange(destination.GetStackIndex(), source.GetStackIndex());
+  } else {
+    LOG(FATAL) << "Unimplemented";
+  }
+}
+
+void ParallelMoveResolverX86::SpillScratch(int reg) {
+  __ pushl(static_cast<Register>(reg));
+}
+
+void ParallelMoveResolverX86::RestoreScratch(int reg) {
+  __ popl(static_cast<Register>(reg));
 }
 
 }  // namespace x86
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 4a70636..acc670e 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -19,6 +19,7 @@
 
 #include "code_generator.h"
 #include "nodes.h"
+#include "parallel_move_resolver.h"
 #include "utils/x86/assembler_x86.h"
 
 namespace art {
@@ -59,6 +60,28 @@
   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitor);
 };
 
+class ParallelMoveResolverX86 : public ParallelMoveResolver {
+ public:
+  ParallelMoveResolverX86(ArenaAllocator* allocator, CodeGeneratorX86* codegen)
+      : ParallelMoveResolver(allocator), codegen_(codegen) {}
+
+  virtual void EmitMove(size_t index) OVERRIDE;
+  virtual void EmitSwap(size_t index) OVERRIDE;
+  virtual void SpillScratch(int reg) OVERRIDE;
+  virtual void RestoreScratch(int reg) OVERRIDE;
+
+  X86Assembler* GetAssembler() const;
+
+ private:
+  void Exchange(Register reg, int mem);
+  void Exchange(int mem1, int mem2);
+  void MoveMemoryToMemory(int dst, int src);
+
+  CodeGeneratorX86* const codegen_;
+
+  DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverX86);
+};
+
 class LocationsBuilderX86 : public HGraphVisitor {
  public:
   LocationsBuilderX86(HGraph* graph, CodeGeneratorX86* codegen)
@@ -105,6 +128,7 @@
   explicit CodeGeneratorX86(HGraph* graph);
   virtual ~CodeGeneratorX86() { }
 
+  virtual void ComputeFrameSize(size_t number_of_spill_slots) OVERRIDE;
   virtual void GenerateFrameEntry() OVERRIDE;
   virtual void GenerateFrameExit() OVERRIDE;
   virtual void Bind(Label* label) OVERRIDE;
@@ -145,6 +169,10 @@
   virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
   virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
 
+  ParallelMoveResolverX86* GetMoveResolver() {
+    return &move_resolver_;
+  }
+
  private:
   // Helper method to move a 32bits value between two locations.
   void Move32(Location destination, Location source);
@@ -153,6 +181,7 @@
 
   LocationsBuilderX86 location_builder_;
   InstructionCodeGeneratorX86 instruction_visitor_;
+  ParallelMoveResolverX86 move_resolver_;
   X86Assembler assembler_;
 
   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86);
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 7684bb1..8ee775c 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -56,7 +56,7 @@
   ASSERT_NE(graph, nullptr);
   InternalCodeAllocator allocator;
   CodeGenerator* codegen = CodeGenerator::Create(&arena, graph, kX86);
-  codegen->Compile(&allocator);
+  codegen->CompileBaseline(&allocator);
   typedef int32_t (*fptr)();
 #if defined(__i386__)
   CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
@@ -66,7 +66,7 @@
   }
 #endif
   codegen = CodeGenerator::Create(&arena, graph, kArm);
-  codegen->Compile(&allocator);
+  codegen->CompileBaseline(&allocator);
 #if defined(__arm__)
   CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
   int32_t result = reinterpret_cast<fptr>(allocator.GetMemory())();
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 5c5042e..a49ce64 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -28,8 +28,15 @@
  */
 class HGraphVisualizerPrinter : public HGraphVisitor {
  public:
-  HGraphVisualizerPrinter(HGraph* graph, std::ostream& output, const CodeGenerator& codegen)
-      : HGraphVisitor(graph), output_(output), codegen_(codegen), indent_(0) {}
+  HGraphVisualizerPrinter(HGraph* graph,
+                          std::ostream& output,
+                          const char* pass_name,
+                          const CodeGenerator& codegen)
+      : HGraphVisitor(graph),
+        output_(output),
+        pass_name_(pass_name),
+        codegen_(codegen),
+        indent_(0) {}
 
   void StartTag(const char* name) {
     AddIndent();
@@ -94,6 +101,33 @@
     output_<< std::endl;
   }
 
+  void DumpLocation(Location location, Primitive::Type type) {
+    if (location.IsRegister()) {
+      if (type == Primitive::kPrimDouble || type == Primitive::kPrimFloat) {
+        codegen_.DumpFloatingPointRegister(output_, location.reg().RegId());
+      } else {
+        codegen_.DumpCoreRegister(output_, location.reg().RegId());
+      }
+    } else {
+      DCHECK(location.IsStackSlot());
+      output_ << location.GetStackIndex() << "(sp)";
+    }
+  }
+
+  void VisitParallelMove(HParallelMove* instruction) {
+    output_ << instruction->DebugName();
+    output_ << " (";
+    for (size_t i = 0, e = instruction->NumMoves(); i < e; ++i) {
+      MoveOperands* move = instruction->MoveOperandsAt(i);
+      DumpLocation(move->GetSource(), Primitive::kPrimInt);
+      output_ << " -> ";
+      DumpLocation(move->GetDestination(), Primitive::kPrimInt);
+      if (i + 1 != e) {
+        output_ << ", ";
+      }
+    }
+    output_ << ")";
+  }
 
   void VisitInstruction(HInstruction* instruction) {
     output_ << instruction->DebugName();
@@ -104,24 +138,28 @@
       }
       output_ << "]";
     }
-    if (instruction->GetLifetimePosition() != kNoLifetime) {
+    if (pass_name_ == kLivenessPassName && instruction->GetLifetimePosition() != kNoLifetime) {
       output_ << " (liveness: " << instruction->GetLifetimePosition();
       if (instruction->HasLiveInterval()) {
         output_ << " ";
         const LiveInterval& interval = *instruction->GetLiveInterval();
         interval.Dump(output_);
-        if (interval.HasRegister()) {
-          int reg = interval.GetRegister();
-          output_ << " ";
-          if (instruction->GetType() == Primitive::kPrimFloat
-              || instruction->GetType() == Primitive::kPrimDouble) {
-            codegen_.DumpFloatingPointRegister(output_, reg);
-          } else {
-            codegen_.DumpCoreRegister(output_, reg);
-          }
-        }
       }
       output_ << ")";
+    } else if (pass_name_ == kRegisterAllocatorPassName) {
+      LocationSummary* locations = instruction->GetLocations();
+      if (locations != nullptr) {
+        output_ << " ( ";
+        for (size_t i = 0; i < instruction->InputCount(); ++i) {
+          DumpLocation(locations->InAt(i), instruction->InputAt(i)->GetType());
+          output_ << " ";
+        }
+        output_ << ")";
+        if (locations->Out().IsValid()) {
+          output_ << " -> ";
+          DumpLocation(locations->Out(), instruction->GetType());
+        }
+      }
     }
   }
 
@@ -137,9 +175,9 @@
     }
   }
 
-  void Run(const char* pass_name) {
+  void Run() {
     StartTag("cfg");
-    PrintProperty("name", pass_name);
+    PrintProperty("name", pass_name_);
     VisitInsertionOrder();
     EndTag("cfg");
   }
@@ -188,6 +226,7 @@
 
  private:
   std::ostream& output_;
+  const char* pass_name_;
   const CodeGenerator& codegen_;
   size_t indent_;
 
@@ -209,7 +248,7 @@
   }
 
   is_enabled_ = true;
-  HGraphVisualizerPrinter printer(graph, *output_, codegen_);
+  HGraphVisualizerPrinter printer(graph, *output_, "", codegen_);
   printer.StartTag("compilation");
   printer.PrintProperty("name", pretty_name.c_str());
   printer.PrintProperty("method", pretty_name.c_str());
@@ -227,7 +266,7 @@
   }
 
   is_enabled_ = true;
-  HGraphVisualizerPrinter printer(graph, *output_, codegen_);
+  HGraphVisualizerPrinter printer(graph, *output_, "", codegen_);
   printer.StartTag("compilation");
   printer.PrintProperty("name", name);
   printer.PrintProperty("method", name);
@@ -239,8 +278,8 @@
   if (!is_enabled_) {
     return;
   }
-  HGraphVisualizerPrinter printer(graph_, *output_, codegen_);
-  printer.Run(pass_name);
+  HGraphVisualizerPrinter printer(graph_, *output_, pass_name, codegen_);
+  printer.Run();
 }
 
 }  // namespace art
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
index 2638cf5..7cd74e9 100644
--- a/compiler/optimizing/graph_visualizer.h
+++ b/compiler/optimizing/graph_visualizer.h
@@ -25,6 +25,9 @@
 class DexCompilationUnit;
 class HGraph;
 
+static const char* kLivenessPassName = "liveness";
+static const char* kRegisterAllocatorPassName = "register";
+
 /**
  * If enabled, emits compilation information suitable for the c1visualizer tool
  * and IRHydra.
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 68848de..143d5c9 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -508,6 +508,7 @@
   void ReplaceWith(HInstruction* instruction);
 
 #define INSTRUCTION_TYPE_CHECK(type)                                           \
+  bool Is##type() { return (As##type() != nullptr); }                          \
   virtual H##type* As##type() { return nullptr; }
 
   FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 3dc0928..ccacbef 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -85,6 +85,8 @@
   // For testing purposes, we put a special marker on method names that should be compiled
   // with this compiler. This makes sure we're not regressing.
   bool shouldCompile = dex_compilation_unit.GetSymbol().find("00024opt_00024") != std::string::npos;
+  bool shouldOptimize =
+      dex_compilation_unit.GetSymbol().find("00024reg_00024") != std::string::npos;
 
   ArenaPool pool;
   ArenaAllocator arena(&pool);
@@ -116,7 +118,36 @@
   visualizer.DumpGraph("builder");
 
   CodeVectorAllocator allocator;
-  codegen->Compile(&allocator);
+
+  if (RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) {
+    graph->BuildDominatorTree();
+    graph->TransformToSSA();
+    visualizer.DumpGraph("ssa");
+
+    graph->FindNaturalLoops();
+    SsaLivenessAnalysis liveness(*graph, codegen);
+    liveness.Analyze();
+    visualizer.DumpGraph(kLivenessPassName);
+
+    RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness);
+    register_allocator.AllocateRegisters();
+
+    visualizer.DumpGraph(kRegisterAllocatorPassName);
+    codegen->CompileOptimized(&allocator);
+  } else if (shouldOptimize && RegisterAllocator::Supports(instruction_set)) {
+    LOG(FATAL) << "Could not allocate registers in optimizing compiler";
+  } else {
+    codegen->CompileBaseline(&allocator);
+
+    // Run these phases to get some test coverage.
+    graph->BuildDominatorTree();
+    graph->TransformToSSA();
+    visualizer.DumpGraph("ssa");
+    graph->FindNaturalLoops();
+    SsaLivenessAnalysis liveness(*graph, codegen);
+    liveness.Analyze();
+    visualizer.DumpGraph(kLivenessPassName);
+  }
 
   std::vector<uint8_t> mapping_table;
   codegen->BuildMappingTable(&mapping_table);
@@ -125,19 +156,6 @@
   std::vector<uint8_t> gc_map;
   codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
 
-  // Run these phases to get some test coverage.
-  graph->BuildDominatorTree();
-  graph->TransformToSSA();
-  visualizer.DumpGraph("ssa");
-
-  graph->FindNaturalLoops();
-  SsaLivenessAnalysis liveness(*graph, codegen);
-  liveness.Analyze();
-  visualizer.DumpGraph("liveness");
-
-  RegisterAllocator(graph->GetArena(), *codegen).AllocateRegisters(liveness);
-  visualizer.DumpGraph("register");
-
   return new CompiledMethod(GetCompilerDriver(),
                             instruction_set,
                             allocator.GetMemory(),
diff --git a/compiler/optimizing/parallel_move_resolver.cc b/compiler/optimizing/parallel_move_resolver.cc
index 3d2d136..4a1b6ce 100644
--- a/compiler/optimizing/parallel_move_resolver.cc
+++ b/compiler/optimizing/parallel_move_resolver.cc
@@ -147,4 +147,64 @@
   }
 }
 
+bool ParallelMoveResolver::IsScratchLocation(Location loc) {
+  for (size_t i = 0; i < moves_.Size(); ++i) {
+    if (moves_.Get(i)->Blocks(loc)) {
+      return false;
+    }
+  }
+
+  for (size_t i = 0; i < moves_.Size(); ++i) {
+    if (moves_.Get(i)->GetDestination().Equals(loc)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+int ParallelMoveResolver::AllocateScratchRegister(int blocked, int register_count, bool* spilled) {
+  int scratch = -1;
+  for (int reg = 0; reg < register_count; ++reg) {
+    if ((blocked != reg) &&
+        IsScratchLocation(Location::RegisterLocation(ManagedRegister(reg)))) {
+      scratch = reg;
+      break;
+    }
+  }
+
+  if (scratch == -1) {
+    *spilled = true;
+    for (int reg = 0; reg < register_count; ++reg) {
+      if (blocked != reg) {
+        scratch = reg;
+      }
+    }
+  } else {
+    *spilled = false;
+  }
+
+  return scratch;
+}
+
+
+ParallelMoveResolver::ScratchRegisterScope::ScratchRegisterScope(
+    ParallelMoveResolver* resolver, int blocked, int number_of_registers)
+    : resolver_(resolver),
+      reg_(kNoRegister),
+      spilled_(false) {
+  reg_ = resolver_->AllocateScratchRegister(blocked, number_of_registers, &spilled_);
+
+  if (spilled_) {
+    resolver->SpillScratch(reg_);
+  }
+}
+
+
+ParallelMoveResolver::ScratchRegisterScope::~ScratchRegisterScope() {
+  if (spilled_) {
+    resolver_->RestoreScratch(reg_);
+  }
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/parallel_move_resolver.h b/compiler/optimizing/parallel_move_resolver.h
index ff20cb0..e1189d8 100644
--- a/compiler/optimizing/parallel_move_resolver.h
+++ b/compiler/optimizing/parallel_move_resolver.h
@@ -23,6 +23,7 @@
 namespace art {
 
 class HParallelMove;
+class Location;
 class MoveOperands;
 
 /**
@@ -39,15 +40,37 @@
   void EmitNativeCode(HParallelMove* parallel_move);
 
  protected:
+  class ScratchRegisterScope : public ValueObject {
+   public:
+    ScratchRegisterScope(ParallelMoveResolver* resolver, int blocked, int number_of_registers);
+    ~ScratchRegisterScope();
+
+    int GetRegister() const { return reg_; }
+    bool IsSpilled() const { return spilled_; }
+
+   private:
+    ParallelMoveResolver* resolver_;
+    int reg_;
+    bool spilled_;
+  };
+
+  bool IsScratchLocation(Location loc);
+  int AllocateScratchRegister(int blocked, int register_count, bool* spilled);
+
   // Emit a move.
   virtual void EmitMove(size_t index) = 0;
 
   // Execute a move by emitting a swap of two operands.
   virtual void EmitSwap(size_t index) = 0;
 
+  virtual void SpillScratch(int reg) = 0;
+  virtual void RestoreScratch(int reg) = 0;
+
   // List of moves not yet resolved.
   GrowableArray<MoveOperands*> moves_;
 
+  static constexpr int kNoRegister = -1;
+
  private:
   // Build the initial list of moves.
   void BuildInitialMoveList(HParallelMove* parallel_move);
diff --git a/compiler/optimizing/parallel_move_test.cc b/compiler/optimizing/parallel_move_test.cc
index 88df24d..093856d 100644
--- a/compiler/optimizing/parallel_move_test.cc
+++ b/compiler/optimizing/parallel_move_test.cc
@@ -50,6 +50,9 @@
              << ")";
   }
 
+  virtual void SpillScratch(int reg) {}
+  virtual void RestoreScratch(int reg) {}
+
   std::string GetMessage() const {
     return  message_.str();
   }
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 8c6eb2a..c2a4769 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -24,64 +24,151 @@
 static constexpr size_t kMaxLifetimePosition = -1;
 static constexpr size_t kDefaultNumberOfSpillSlots = 4;
 
-RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator, const CodeGenerator& codegen)
+RegisterAllocator::RegisterAllocator(ArenaAllocator* allocator,
+                                     CodeGenerator* codegen,
+                                     const SsaLivenessAnalysis& liveness)
       : allocator_(allocator),
         codegen_(codegen),
+        liveness_(liveness),
         unhandled_(allocator, 0),
         handled_(allocator, 0),
         active_(allocator, 0),
         inactive_(allocator, 0),
+        physical_register_intervals_(allocator, codegen->GetNumberOfRegisters()),
         spill_slots_(allocator, kDefaultNumberOfSpillSlots),
         processing_core_registers_(false),
         number_of_registers_(-1),
         registers_array_(nullptr),
-        blocked_registers_(allocator->AllocArray<bool>(codegen.GetNumberOfRegisters())) {
-  codegen.SetupBlockedRegisters(blocked_registers_);
+        blocked_registers_(allocator->AllocArray<bool>(codegen->GetNumberOfRegisters())) {
+  codegen->SetupBlockedRegisters(blocked_registers_);
+  physical_register_intervals_.SetSize(codegen->GetNumberOfRegisters());
 }
 
-static bool ShouldProcess(bool processing_core_registers, HInstruction* instruction) {
-  bool is_core_register = (instruction->GetType() != Primitive::kPrimDouble)
-      && (instruction->GetType() != Primitive::kPrimFloat);
+bool RegisterAllocator::CanAllocateRegistersFor(const HGraph& graph,
+                                                InstructionSet instruction_set) {
+  if (!Supports(instruction_set)) {
+    return false;
+  }
+  for (size_t i = 0, e = graph.GetBlocks().Size(); i < e; ++i) {
+    for (HInstructionIterator it(graph.GetBlocks().Get(i)->GetInstructions());
+         !it.Done();
+         it.Advance()) {
+      HInstruction* current = it.Current();
+      if (current->NeedsEnvironment()) return false;
+      if (current->GetType() == Primitive::kPrimLong) return false;
+      if (current->GetType() == Primitive::kPrimFloat) return false;
+      if (current->GetType() == Primitive::kPrimDouble) return false;
+    }
+  }
+  return true;
+}
+
+static bool ShouldProcess(bool processing_core_registers, LiveInterval* interval) {
+  bool is_core_register = (interval->GetType() != Primitive::kPrimDouble)
+      && (interval->GetType() != Primitive::kPrimFloat);
   return processing_core_registers == is_core_register;
 }
 
-void RegisterAllocator::AllocateRegistersInternal(const SsaLivenessAnalysis& liveness) {
+void RegisterAllocator::AllocateRegisters() {
+  processing_core_registers_ = true;
+  AllocateRegistersInternal();
+  processing_core_registers_ = false;
+  AllocateRegistersInternal();
+
+  Resolve();
+
+  if (kIsDebugBuild) {
+    processing_core_registers_ = true;
+    ValidateInternal(true);
+    processing_core_registers_ = false;
+    ValidateInternal(true);
+  }
+}
+
+void RegisterAllocator::BlockRegister(Location location,
+                                      size_t start,
+                                      size_t end,
+                                      Primitive::Type type) {
+  int reg = location.reg().RegId();
+  LiveInterval* interval = physical_register_intervals_.Get(reg);
+  if (interval == nullptr) {
+    interval = LiveInterval::MakeFixedInterval(allocator_, reg, type);
+    physical_register_intervals_.Put(reg, interval);
+    inactive_.Add(interval);
+  }
+  DCHECK(interval->GetRegister() == reg);
+  interval->AddRange(start, end);
+}
+
+void RegisterAllocator::AllocateRegistersInternal() {
   number_of_registers_ = processing_core_registers_
-      ? codegen_.GetNumberOfCoreRegisters()
-      : codegen_.GetNumberOfFloatingPointRegisters();
+      ? codegen_->GetNumberOfCoreRegisters()
+      : codegen_->GetNumberOfFloatingPointRegisters();
 
   registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
 
   // Iterate post-order, to ensure the list is sorted, and the last added interval
   // is the one with the lowest start position.
-  for (size_t i = liveness.GetNumberOfSsaValues(); i > 0; --i) {
-    HInstruction* instruction = liveness.GetInstructionFromSsaIndex(i - 1);
-    if (ShouldProcess(processing_core_registers_, instruction)) {
-      LiveInterval* current = instruction->GetLiveInterval();
+  for (size_t i = liveness_.GetNumberOfSsaValues(); i > 0; --i) {
+    HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i - 1);
+    LiveInterval* current = instruction->GetLiveInterval();
+    if (ShouldProcess(processing_core_registers_, current)) {
       DCHECK(unhandled_.IsEmpty() || current->StartsBefore(unhandled_.Peek()));
-      unhandled_.Add(current);
+
+      LocationSummary* locations = instruction->GetLocations();
+      if (locations->GetTempCount() != 0) {
+        // Note that we already filtered out instructions requiring temporaries in
+        // RegisterAllocator::CanAllocateRegistersFor.
+        LOG(FATAL) << "Unimplemented";
+      }
+
+      // Some instructions define their output in fixed register/stack slot. We need
+      // to ensure we know these locations before doing register allocation. For a
+      // given register, we create an interval that covers these locations. The register
+      // will be unavailable at these locations when trying to allocate one for an
+      // interval.
+      //
+      // The backwards walking ensures the ranges are ordered on increasing start positions.
+      Location output = locations->Out();
+      size_t position = instruction->GetLifetimePosition();
+      if (output.IsRegister()) {
+        // Shift the interval's start by one to account for the blocked register.
+        current->SetFrom(position + 1);
+        current->SetRegister(output.reg().RegId());
+        BlockRegister(output, position, position + 1, instruction->GetType());
+      } else if (output.IsStackSlot()) {
+        current->SetSpillSlot(output.GetStackIndex());
+      }
+      for (size_t i = 0; i < instruction->InputCount(); ++i) {
+        Location input = locations->InAt(i);
+        if (input.IsRegister()) {
+          BlockRegister(input, position, position + 1, instruction->InputAt(i)->GetType());
+        }
+      }
+
+      // Add the interval to the correct list.
+      if (current->HasRegister()) {
+        DCHECK(instruction->IsParameterValue());
+        inactive_.Add(current);
+      } else if (current->HasSpillSlot()) {
+        DCHECK(instruction->IsParameterValue());
+        // Split before first register use.
+        size_t first_register_use = current->FirstRegisterUse();
+        if (first_register_use != kNoLifetime) {
+          LiveInterval* split = Split(current, first_register_use - 1);
+          // The new interval may start at a late
+          AddToUnhandled(split);
+        } else {
+          // Nothing to do, we won't allocate a register for this value.
+        }
+      } else {
+        DCHECK(unhandled_.IsEmpty() || current->StartsBefore(unhandled_.Peek()));
+        unhandled_.Add(current);
+      }
     }
   }
 
   LinearScan();
-  if (kIsDebugBuild) {
-    ValidateInternal(liveness, true);
-  }
-}
-
-bool RegisterAllocator::ValidateInternal(const SsaLivenessAnalysis& liveness,
-                                         bool log_fatal_on_failure) const {
-  // To simplify unit testing, we eagerly create the array of intervals, and
-  // call the helper method.
-  GrowableArray<LiveInterval*> intervals(allocator_, 0);
-  for (size_t i = 0; i < liveness.GetNumberOfSsaValues(); ++i) {
-    HInstruction* instruction = liveness.GetInstructionFromSsaIndex(i);
-    if (ShouldProcess(processing_core_registers_, instruction)) {
-      intervals.Add(instruction->GetLiveInterval());
-    }
-  }
-  return ValidateIntervals(intervals, spill_slots_.Size(), codegen_, allocator_,
-                           processing_core_registers_, log_fatal_on_failure);
 }
 
 class AllRangesIterator : public ValueObject {
@@ -111,6 +198,28 @@
   DISALLOW_COPY_AND_ASSIGN(AllRangesIterator);
 };
 
+bool RegisterAllocator::ValidateInternal(bool log_fatal_on_failure) const {
+  // To simplify unit testing, we eagerly create the array of intervals, and
+  // call the helper method.
+  GrowableArray<LiveInterval*> intervals(allocator_, 0);
+  for (size_t i = 0; i < liveness_.GetNumberOfSsaValues(); ++i) {
+    HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
+    if (ShouldProcess(processing_core_registers_, instruction->GetLiveInterval())) {
+      intervals.Add(instruction->GetLiveInterval());
+    }
+  }
+
+  for (size_t i = 0, e = physical_register_intervals_.Size(); i < e; ++i) {
+    LiveInterval* fixed = physical_register_intervals_.Get(i);
+    if (fixed != nullptr && ShouldProcess(processing_core_registers_, fixed)) {
+      intervals.Add(fixed);
+    }
+  }
+
+  return ValidateIntervals(intervals, spill_slots_.Size(), *codegen_, allocator_,
+                           processing_core_registers_, log_fatal_on_failure);
+}
+
 bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& intervals,
                                           size_t number_of_spill_slots,
                                           const CodeGenerator& codegen,
@@ -132,7 +241,10 @@
   for (size_t i = 0, e = intervals.Size(); i < e; ++i) {
     for (AllRangesIterator it(intervals.Get(i)); !it.Done(); it.Advance()) {
       LiveInterval* current = it.CurrentInterval();
-      if (current->GetParent()->HasSpillSlot()) {
+      HInstruction* defined_by = current->GetParent()->GetDefinedBy();
+      if (current->GetParent()->HasSpillSlot()
+           // Parameters have their own stack slot.
+           && !(defined_by != nullptr && defined_by->IsParameterValue())) {
         BitVector* liveness_of_spill_slot = liveness_of_values.Get(
             number_of_registers + current->GetParent()->GetSpillSlot() / kVRegSize);
         for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
@@ -176,14 +288,14 @@
   return true;
 }
 
-void RegisterAllocator::DumpInterval(std::ostream& stream, LiveInterval* interval) {
+void RegisterAllocator::DumpInterval(std::ostream& stream, LiveInterval* interval) const {
   interval->Dump(stream);
   stream << ": ";
   if (interval->HasRegister()) {
     if (processing_core_registers_) {
-      codegen_.DumpCoreRegister(stream, interval->GetRegister());
+      codegen_->DumpCoreRegister(stream, interval->GetRegister());
     } else {
-      codegen_.DumpFloatingPointRegister(stream, interval->GetRegister());
+      codegen_->DumpFloatingPointRegister(stream, interval->GetRegister());
     }
   } else {
     stream << "spilled";
@@ -196,6 +308,7 @@
   while (!unhandled_.IsEmpty()) {
     // (1) Remove interval with the lowest start position from unhandled.
     LiveInterval* current = unhandled_.Pop();
+    DCHECK(!current->IsFixed() && !current->HasRegister() && !current->HasSpillSlot());
     size_t position = current->GetStart();
 
     // (2) Remove currently active intervals that are dead at this position.
@@ -255,13 +368,6 @@
     free_until[i] = kMaxLifetimePosition;
   }
 
-  // For each active interval, set its register to not free.
-  for (size_t i = 0, e = active_.Size(); i < e; ++i) {
-    LiveInterval* interval = active_.Get(i);
-    DCHECK(interval->HasRegister());
-    free_until[interval->GetRegister()] = 0;
-  }
-
   // For each inactive interval, set its register to be free until
   // the next intersection with `current`.
   // Thanks to SSA, this should only be needed for intervals
@@ -275,6 +381,13 @@
     }
   }
 
+  // For each active interval, set its register to not free.
+  for (size_t i = 0, e = active_.Size(); i < e; ++i) {
+    LiveInterval* interval = active_.Get(i);
+    DCHECK(interval->HasRegister());
+    free_until[interval->GetRegister()] = 0;
+  }
+
   // Pick the register that is free the longest.
   int reg = -1;
   for (size_t i = 0; i < number_of_registers_; ++i) {
@@ -330,9 +443,13 @@
   for (size_t i = 0, e = active_.Size(); i < e; ++i) {
     LiveInterval* active = active_.Get(i);
     DCHECK(active->HasRegister());
-    size_t use = active->FirstRegisterUseAfter(current->GetStart());
-    if (use != kNoLifetime) {
-      next_use[active->GetRegister()] = use;
+    if (active->IsFixed()) {
+      next_use[active->GetRegister()] = current->GetStart();
+    } else {
+      size_t use = active->FirstRegisterUseAfter(current->GetStart());
+      if (use != kNoLifetime) {
+        next_use[active->GetRegister()] = use;
+      }
     }
   }
 
@@ -343,9 +460,17 @@
   for (size_t i = 0, e = inactive_.Size(); i < e; ++i) {
     LiveInterval* inactive = inactive_.Get(i);
     DCHECK(inactive->HasRegister());
-    size_t use = inactive->FirstRegisterUseAfter(current->GetStart());
-    if (use != kNoLifetime) {
-      next_use[inactive->GetRegister()] = use;
+    size_t next_intersection = inactive->FirstIntersectionWith(current);
+    if (next_intersection != kNoLifetime) {
+      if (inactive->IsFixed()) {
+        next_use[inactive->GetRegister()] =
+            std::min(next_intersection, next_use[inactive->GetRegister()]);
+      } else {
+        size_t use = inactive->FirstRegisterUseAfter(current->GetStart());
+        if (use != kNoLifetime) {
+          next_use[inactive->GetRegister()] = std::min(use, next_use[inactive->GetRegister()]);
+        }
+      }
     }
   }
 
@@ -374,6 +499,7 @@
     for (size_t i = 0, e = active_.Size(); i < e; ++i) {
       LiveInterval* active = active_.Get(i);
       if (active->GetRegister() == reg) {
+        DCHECK(!active->IsFixed());
         LiveInterval* split = Split(active, current->GetStart());
         active_.DeleteAt(i);
         handled_.Add(active);
@@ -385,11 +511,19 @@
     for (size_t i = 0; i < inactive_.Size(); ++i) {
       LiveInterval* inactive = inactive_.Get(i);
       if (inactive->GetRegister() == reg) {
-        LiveInterval* split = Split(inactive, current->GetStart());
-        inactive_.DeleteAt(i);
-        handled_.Add(inactive);
-        AddToUnhandled(split);
-        --i;
+        size_t next_intersection = inactive->FirstIntersectionWith(current);
+        if (next_intersection != kNoLifetime) {
+          if (inactive->IsFixed()) {
+            LiveInterval* split = Split(current, next_intersection);
+            AddToUnhandled(split);
+          } else {
+            LiveInterval* split = Split(inactive, current->GetStart());
+            inactive_.DeleteAt(i);
+            handled_.Add(inactive);
+            AddToUnhandled(split);
+            --i;
+          }
+        }
       }
     }
 
@@ -398,13 +532,15 @@
 }
 
 void RegisterAllocator::AddToUnhandled(LiveInterval* interval) {
+  size_t insert_at = 0;
   for (size_t i = unhandled_.Size(); i > 0; --i) {
     LiveInterval* current = unhandled_.Get(i - 1);
     if (current->StartsAfter(interval)) {
-      unhandled_.InsertAt(i, interval);
+      insert_at = i;
       break;
     }
   }
+  unhandled_.InsertAt(insert_at, interval);
 }
 
 LiveInterval* RegisterAllocator::Split(LiveInterval* interval, size_t position) {
@@ -429,7 +565,13 @@
     return;
   }
 
-  // Find when this instruction dies.
+  HInstruction* defined_by = parent->GetDefinedBy();
+  if (defined_by->IsParameterValue()) {
+    // Parameters have their own stack slot.
+    parent->SetSpillSlot(codegen_->GetStackSlotOfParameter(defined_by->AsParameterValue()));
+    return;
+  }
+
   LiveInterval* last_sibling = interval;
   while (last_sibling->GetNextSibling() != nullptr) {
     last_sibling = last_sibling->GetNextSibling();
@@ -451,7 +593,315 @@
     spill_slots_.Put(slot, end);
   }
 
-  interval->GetParent()->SetSpillSlot(slot * kVRegSize);
+  parent->SetSpillSlot(slot * kVRegSize);
+}
+
+static Location ConvertToLocation(LiveInterval* interval) {
+  if (interval->HasRegister()) {
+    return Location::RegisterLocation(ManagedRegister(interval->GetRegister()));
+  } else {
+    DCHECK(interval->GetParent()->HasSpillSlot());
+    return Location::StackSlot(interval->GetParent()->GetSpillSlot());
+  }
+}
+
+// We create a special marker for inputs moves to differentiate them from
+// moves created during resolution. They must be different instructions
+// because the input moves work on the assumption that the interval moves
+// have been executed.
+static constexpr size_t kInputMoveLifetimePosition = 0;
+static bool IsInputMove(HInstruction* instruction) {
+  return instruction->GetLifetimePosition() == kInputMoveLifetimePosition;
+}
+
+void RegisterAllocator::AddInputMoveFor(HInstruction* instruction,
+                                        Location source,
+                                        Location destination) const {
+  if (source.Equals(destination)) return;
+
+  DCHECK(instruction->AsPhi() == nullptr);
+
+  HInstruction* previous = instruction->GetPrevious();
+  HParallelMove* move = nullptr;
+  if (previous == nullptr
+      || previous->AsParallelMove() == nullptr
+      || !IsInputMove(previous)) {
+    move = new (allocator_) HParallelMove(allocator_);
+    move->SetLifetimePosition(kInputMoveLifetimePosition);
+    instruction->GetBlock()->InsertInstructionBefore(move, instruction);
+  } else {
+    move = previous->AsParallelMove();
+  }
+  DCHECK(IsInputMove(move));
+  move->AddMove(new (allocator_) MoveOperands(source, destination));
+}
+
+void RegisterAllocator::InsertParallelMoveAt(size_t position,
+                                             Location source,
+                                             Location destination) const {
+  if (source.Equals(destination)) return;
+
+  HInstruction* at = liveness_.GetInstructionFromPosition(position / 2);
+  if (at == nullptr) {
+    // Block boundary, don't no anything the connection of split siblings will handle it.
+    return;
+  }
+  HParallelMove* move;
+  if ((position & 1) == 1) {
+    // Move must happen after the instruction.
+    DCHECK(!at->IsControlFlow());
+    move = at->GetNext()->AsParallelMove();
+    if (move == nullptr || IsInputMove(move)) {
+      move = new (allocator_) HParallelMove(allocator_);
+      move->SetLifetimePosition(position);
+      at->GetBlock()->InsertInstructionBefore(move, at->GetNext());
+    }
+  } else {
+    // Move must happen before the instruction.
+    HInstruction* previous = at->GetPrevious();
+    if (previous != nullptr && previous->AsParallelMove() != nullptr) {
+      if (IsInputMove(previous)) {
+        previous = previous->GetPrevious();
+      }
+    }
+    if (previous == nullptr || previous->AsParallelMove() == nullptr) {
+      move = new (allocator_) HParallelMove(allocator_);
+      move->SetLifetimePosition(position);
+      at->GetBlock()->InsertInstructionBefore(move, at);
+    } else {
+      move = previous->AsParallelMove();
+    }
+  }
+  move->AddMove(new (allocator_) MoveOperands(source, destination));
+}
+
+void RegisterAllocator::InsertParallelMoveAtExitOf(HBasicBlock* block,
+                                                   Location source,
+                                                   Location destination) const {
+  if (source.Equals(destination)) return;
+
+  DCHECK_EQ(block->GetSuccessors().Size(), 1u);
+  HInstruction* last = block->GetLastInstruction();
+  HInstruction* previous = last->GetPrevious();
+  HParallelMove* move;
+  if (previous == nullptr || previous->AsParallelMove() == nullptr) {
+    move = new (allocator_) HParallelMove(allocator_);
+    block->InsertInstructionBefore(move, last);
+  } else {
+    move = previous->AsParallelMove();
+  }
+  move->AddMove(new (allocator_) MoveOperands(source, destination));
+}
+
+void RegisterAllocator::InsertParallelMoveAtEntryOf(HBasicBlock* block,
+                                                    Location source,
+                                                    Location destination) const {
+  if (source.Equals(destination)) return;
+
+  HInstruction* first = block->GetFirstInstruction();
+  HParallelMove* move = first->AsParallelMove();
+  if (move == nullptr || IsInputMove(move)) {
+    move = new (allocator_) HParallelMove(allocator_);
+    move->SetLifetimePosition(block->GetLifetimeStart());
+    block->InsertInstructionBefore(move, first);
+  }
+  move->AddMove(new (allocator_) MoveOperands(source, destination));
+}
+
+void RegisterAllocator::InsertMoveAfter(HInstruction* instruction,
+                                        Location source,
+                                        Location destination) const {
+  if (source.Equals(destination)) return;
+
+  if (instruction->AsPhi() != nullptr) {
+    InsertParallelMoveAtEntryOf(instruction->GetBlock(), source, destination);
+    return;
+  }
+
+  HParallelMove* move = instruction->GetNext()->AsParallelMove();
+  if (move == nullptr || IsInputMove(move)) {
+    move = new (allocator_) HParallelMove(allocator_);
+    instruction->GetBlock()->InsertInstructionBefore(move, instruction->GetNext());
+  }
+  move->AddMove(new (allocator_) MoveOperands(source, destination));
+}
+
+void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
+  LiveInterval* current = interval;
+  if (current->HasSpillSlot() && current->HasRegister()) {
+    // We spill eagerly, so move must be at definition.
+    InsertMoveAfter(interval->GetDefinedBy(),
+                    Location::RegisterLocation(ManagedRegister(interval->GetRegister())),
+                    Location::StackSlot(interval->GetParent()->GetSpillSlot()));
+  }
+  UsePosition* use = current->GetFirstUse();
+
+  // Walk over all siblings, updating locations of use positions, and
+  // connecting them when they are adjacent.
+  do {
+    Location source = ConvertToLocation(current);
+
+    // Walk over all uses covered by this interval, and update the location
+    // information.
+    while (use != nullptr && use->GetPosition() <= current->GetEnd()) {
+      if (!use->GetIsEnvironment()) {
+        LocationSummary* locations = use->GetUser()->GetLocations();
+        Location expected_location = locations->InAt(use->GetInputIndex());
+        if (expected_location.IsUnallocated()) {
+          locations->SetInAt(use->GetInputIndex(), source);
+        } else {
+          AddInputMoveFor(use->GetUser(), source, expected_location);
+        }
+      }
+      use = use->GetNext();
+    }
+
+    // If the next interval starts just after this one, and has a register,
+    // insert a move.
+    LiveInterval* next_sibling = current->GetNextSibling();
+    if (next_sibling != nullptr
+        && next_sibling->HasRegister()
+        && current->GetEnd() == next_sibling->GetStart()) {
+      Location destination = ConvertToLocation(next_sibling);
+      InsertParallelMoveAt(current->GetEnd(), source, destination);
+    }
+    current = next_sibling;
+  } while (current != nullptr);
+  DCHECK(use == nullptr);
+}
+
+void RegisterAllocator::ConnectSplitSiblings(LiveInterval* interval,
+                                             HBasicBlock* from,
+                                             HBasicBlock* to) const {
+  if (interval->GetNextSibling() == nullptr) {
+    // Nothing to connect. The whole range was allocated to the same location.
+    return;
+  }
+
+  size_t from_position = from->GetLifetimeEnd() - 1;
+  size_t to_position = to->GetLifetimeStart();
+
+  LiveInterval* destination = nullptr;
+  LiveInterval* source = nullptr;
+
+  LiveInterval* current = interval;
+
+  // Check the intervals that cover `from` and `to`.
+  while ((current != nullptr) && (source == nullptr || destination == nullptr)) {
+    if (current->Covers(from_position)) {
+      DCHECK(source == nullptr);
+      source = current;
+    }
+    if (current->Covers(to_position)) {
+      DCHECK(destination == nullptr);
+      destination = current;
+    }
+
+    current = current->GetNextSibling();
+  }
+
+  if (destination == source) {
+    // Interval was not split.
+    return;
+  }
+
+  if (!destination->HasRegister()) {
+    // Values are eagerly spilled. Spill slot already contains appropriate value.
+    return;
+  }
+
+  // If `from` has only one successor, we can put the moves at the exit of it. Otherwise
+  // we need to put the moves at the entry of `to`.
+  if (from->GetSuccessors().Size() == 1) {
+    InsertParallelMoveAtExitOf(from, ConvertToLocation(source), ConvertToLocation(destination));
+  } else {
+    DCHECK_EQ(to->GetPredecessors().Size(), 1u);
+    InsertParallelMoveAtEntryOf(to, ConvertToLocation(source), ConvertToLocation(destination));
+  }
+}
+
+// Returns the location of `interval`, or siblings of `interval`, at `position`.
+static Location FindLocationAt(LiveInterval* interval, size_t position) {
+  LiveInterval* current = interval;
+  while (!current->Covers(position)) {
+    current = current->GetNextSibling();
+    DCHECK(current != nullptr);
+  }
+  return ConvertToLocation(current);
+}
+
+void RegisterAllocator::Resolve() {
+  codegen_->ComputeFrameSize(spill_slots_.Size());
+
+  // Adjust the Out Location of instructions.
+  // TODO: Use pointers of Location inside LiveInterval to avoid doing another iteration.
+  for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
+    HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
+    LiveInterval* current = instruction->GetLiveInterval();
+    LocationSummary* locations = instruction->GetLocations();
+    Location location = locations->Out();
+    if (instruction->AsParameterValue() != nullptr) {
+      // Now that we know the frame size, adjust the parameter's location.
+      if (location.IsStackSlot()) {
+        location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
+        current->SetSpillSlot(location.GetStackIndex());
+        locations->SetOut(location);
+      } else if (location.IsDoubleStackSlot()) {
+        location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
+        current->SetSpillSlot(location.GetStackIndex());
+        locations->SetOut(location);
+      } else if (current->HasSpillSlot()) {
+        current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize());
+      }
+    }
+
+    Location source = ConvertToLocation(current);
+
+    if (location.IsUnallocated()) {
+      if (location.GetPolicy() == Location::kSameAsFirstInput) {
+        locations->SetInAt(0, source);
+      }
+      locations->SetOut(source);
+    } else {
+      DCHECK(source.Equals(location));
+    }
+  }
+
+  // Connect siblings.
+  for (size_t i = 0, e = liveness_.GetNumberOfSsaValues(); i < e; ++i) {
+    HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
+    ConnectSiblings(instruction->GetLiveInterval());
+  }
+
+  // Resolve non-linear control flow across branches. Order does not matter.
+  for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
+    HBasicBlock* block = it.Current();
+    BitVector* live = liveness_.GetLiveInSet(*block);
+    for (uint32_t idx : live->Indexes()) {
+      HInstruction* current = liveness_.GetInstructionFromSsaIndex(idx);
+      LiveInterval* interval = current->GetLiveInterval();
+      for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
+        ConnectSplitSiblings(interval, block->GetPredecessors().Get(i), block);
+      }
+    }
+  }
+
+  // Resolve phi inputs. Order does not matter.
+  for (HLinearOrderIterator it(liveness_); !it.Done(); it.Advance()) {
+    HBasicBlock* current = it.Current();
+    for (HInstructionIterator it(current->GetPhis()); !it.Done(); it.Advance()) {
+      HInstruction* phi = it.Current();
+      for (size_t i = 0, e = current->GetPredecessors().Size(); i < e; ++i) {
+        HBasicBlock* predecessor = current->GetPredecessors().Get(i);
+        DCHECK_EQ(predecessor->GetSuccessors().Size(), 1u);
+        HInstruction* input = phi->InputAt(i);
+        Location source = FindLocationAt(input->GetLiveInterval(),
+                                         predecessor->GetLastInstruction()->GetLifetimePosition());
+        Location destination = ConvertToLocation(phi->GetLiveInterval());
+        InsertParallelMoveAtExitOf(predecessor, source, destination);
+      }
+    }
+  }
 }
 
 }  // namespace art
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index 3393a04..1b5585f 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -23,7 +23,12 @@
 namespace art {
 
 class CodeGenerator;
+class HBasicBlock;
+class HGraph;
+class HInstruction;
+class HParallelMove;
 class LiveInterval;
+class Location;
 class SsaLivenessAnalysis;
 
 /**
@@ -31,26 +36,23 @@
  */
 class RegisterAllocator {
  public:
-  RegisterAllocator(ArenaAllocator* allocator, const CodeGenerator& codegen);
+  RegisterAllocator(ArenaAllocator* allocator,
+                    CodeGenerator* codegen,
+                    const SsaLivenessAnalysis& analysis);
 
   // Main entry point for the register allocator. Given the liveness analysis,
   // allocates registers to live intervals.
-  void AllocateRegisters(const SsaLivenessAnalysis& liveness) {
-    processing_core_registers_ = true;
-    AllocateRegistersInternal(liveness);
-    processing_core_registers_ = false;
-    AllocateRegistersInternal(liveness);
-  }
+  void AllocateRegisters();
 
   // Validate that the register allocator did not allocate the same register to
   // intervals that intersect each other. Returns false if it did not.
-  bool Validate(const SsaLivenessAnalysis& liveness, bool log_fatal_on_failure) {
+  bool Validate(bool log_fatal_on_failure) {
     processing_core_registers_ = true;
-    if (!ValidateInternal(liveness, log_fatal_on_failure)) {
+    if (!ValidateInternal(log_fatal_on_failure)) {
       return false;
     }
     processing_core_registers_ = false;
-    return ValidateInternal(liveness, log_fatal_on_failure);
+    return ValidateInternal(log_fatal_on_failure);
   }
 
   // Helper method for validation. Used by unit testing.
@@ -61,11 +63,21 @@
                                 bool processing_core_registers,
                                 bool log_fatal_on_failure);
 
+  static bool CanAllocateRegistersFor(const HGraph& graph, InstructionSet instruction_set);
+  static bool Supports(InstructionSet instruction_set) {
+    return instruction_set == kX86;
+  }
+
+  size_t GetNumberOfSpillSlots() const {
+    return spill_slots_.Size();
+  }
+
  private:
   // Main methods of the allocator.
   void LinearScan();
   bool TryAllocateFreeReg(LiveInterval* interval);
   bool AllocateBlockedReg(LiveInterval* interval);
+  void Resolve();
 
   // Add `interval` in the sorted list of unhandled intervals.
   void AddToUnhandled(LiveInterval* interval);
@@ -76,16 +88,33 @@
   // Returns whether `reg` is blocked by the code generator.
   bool IsBlocked(int reg) const;
 
+  // Update the interval for the register in `location` to cover [start, end).
+  void BlockRegister(Location location, size_t start, size_t end, Primitive::Type type);
+
   // Allocate a spill slot for the given interval.
   void AllocateSpillSlotFor(LiveInterval* interval);
 
+  // Connect adjacent siblings within blocks.
+  void ConnectSiblings(LiveInterval* interval);
+
+  // Connect siblings between block entries and exits.
+  void ConnectSplitSiblings(LiveInterval* interval, HBasicBlock* from, HBasicBlock* to) const;
+
+  // Helper methods to insert parallel moves in the graph.
+  void InsertParallelMoveAtExitOf(HBasicBlock* block, Location source, Location destination) const;
+  void InsertParallelMoveAtEntryOf(HBasicBlock* block, Location source, Location destination) const;
+  void InsertMoveAfter(HInstruction* instruction, Location source, Location destination) const;
+  void AddInputMoveFor(HInstruction* instruction, Location source, Location destination) const;
+  void InsertParallelMoveAt(size_t position, Location source, Location destination) const;
+
   // Helper methods.
-  void AllocateRegistersInternal(const SsaLivenessAnalysis& liveness);
-  bool ValidateInternal(const SsaLivenessAnalysis& liveness, bool log_fatal_on_failure) const;
-  void DumpInterval(std::ostream& stream, LiveInterval* interval);
+  void AllocateRegistersInternal();
+  bool ValidateInternal(bool log_fatal_on_failure) const;
+  void DumpInterval(std::ostream& stream, LiveInterval* interval) const;
 
   ArenaAllocator* const allocator_;
-  const CodeGenerator& codegen_;
+  CodeGenerator* const codegen_;
+  const SsaLivenessAnalysis& liveness_;
 
   // List of intervals that must be processed, ordered by start position. Last entry
   // is the interval that has the lowest start position.
@@ -102,6 +131,10 @@
   // That is, they have a lifetime hole that spans the start of the new interval.
   GrowableArray<LiveInterval*> inactive_;
 
+  // Fixed intervals for physical registers. Such an interval covers the positions
+  // where an instruction requires a specific register.
+  GrowableArray<LiveInterval*> physical_register_intervals_;
+
   // The spill slots allocated for live intervals.
   GrowableArray<size_t> spill_slots_;
 
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index ff9b9be..bfabc5a 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -43,9 +43,9 @@
   CodeGenerator* codegen = CodeGenerator::Create(&allocator, graph, kX86);
   SsaLivenessAnalysis liveness(*graph, codegen);
   liveness.Analyze();
-  RegisterAllocator register_allocator(&allocator, *codegen);
-  register_allocator.AllocateRegisters(liveness);
-  return register_allocator.Validate(liveness, false);
+  RegisterAllocator register_allocator(&allocator, codegen, liveness);
+  register_allocator.AllocateRegisters();
+  return register_allocator.Validate(false);
 }
 
 /**
@@ -300,9 +300,9 @@
   CodeGenerator* codegen = CodeGenerator::Create(&allocator, graph, kX86);
   SsaLivenessAnalysis liveness(*graph, codegen);
   liveness.Analyze();
-  RegisterAllocator register_allocator(&allocator, *codegen);
-  register_allocator.AllocateRegisters(liveness);
-  ASSERT_TRUE(register_allocator.Validate(liveness, false));
+  RegisterAllocator register_allocator(&allocator, codegen, liveness);
+  register_allocator.AllocateRegisters();
+  ASSERT_TRUE(register_allocator.Validate(false));
 
   HBasicBlock* loop_header = graph->GetBlocks().Get(2);
   HPhi* phi = loop_header->GetFirstPhi()->AsPhi();
@@ -314,7 +314,7 @@
   ASSERT_NE(phi_interval->GetRegister(), loop_update->GetRegister());
 
   HBasicBlock* return_block = graph->GetBlocks().Get(3);
-  HReturn* ret = return_block->GetFirstInstruction()->AsReturn();
+  HReturn* ret = return_block->GetLastInstruction()->AsReturn();
   ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister());
 }
 
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 7903ad6..fc3eb66 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -172,6 +172,7 @@
       // Last use is in the following block.
       first_range_->start_ = start_block_position;
     } else {
+      DCHECK(first_range_->GetStart() > position);
       // There is a hole in the interval. Create a new range.
       first_range_ = new (allocator_) LiveRange(start_block_position, position, first_range_);
     }
@@ -192,6 +193,7 @@
       // There is a use in the following block.
       first_range_->start_ = start;
     } else {
+      DCHECK(first_range_->GetStart() > end);
       // There is a hole in the interval. Create a new range.
       first_range_ = new (allocator_) LiveRange(start, end, first_range_);
     }
diff --git a/compiler/utils/arena_allocator.cc b/compiler/utils/arena_allocator.cc
index 6a39641..925d4a2 100644
--- a/compiler/utils/arena_allocator.cc
+++ b/compiler/utils/arena_allocator.cc
@@ -139,7 +139,7 @@
     if (kUseMemSet || !kUseMemMap) {
       memset(Begin(), 0, bytes_allocated_);
     } else {
-      madvise(Begin(), bytes_allocated_, MADV_DONTNEED);
+      map_->MadviseDontNeedAndZero();
     }
     bytes_allocated_ = 0;
   }
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index a14551c..b07eed3 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1650,7 +1650,7 @@
     pushq(spill_regs.at(i).AsX86_64().AsCpuRegister());
   }
   // return address then method on stack
-  addq(CpuRegister(RSP), Immediate(-frame_size + (spill_regs.size() * kFramePointerSize) +
+  addq(CpuRegister(RSP), Immediate(-static_cast<int64_t>(frame_size) + (spill_regs.size() * kFramePointerSize) +
                                    sizeof(StackReference<mirror::ArtMethod>) /*method*/ +
                                    kFramePointerSize /*return address*/));
 
@@ -1682,7 +1682,7 @@
 void X86_64Assembler::RemoveFrame(size_t frame_size,
                             const std::vector<ManagedRegister>& spill_regs) {
   CHECK_ALIGNED(frame_size, kStackAlignment);
-  addq(CpuRegister(RSP), Immediate(frame_size - (spill_regs.size() * kFramePointerSize) - kFramePointerSize));
+  addq(CpuRegister(RSP), Immediate(static_cast<int64_t>(frame_size) - (spill_regs.size() * kFramePointerSize) - kFramePointerSize));
   for (size_t i = 0; i < spill_regs.size(); ++i) {
     popq(spill_regs.at(i).AsX86_64().AsCpuRegister());
   }
@@ -1691,7 +1691,7 @@
 
 void X86_64Assembler::IncreaseFrameSize(size_t adjust) {
   CHECK_ALIGNED(adjust, kStackAlignment);
-  addq(CpuRegister(RSP), Immediate(-adjust));
+  addq(CpuRegister(RSP), Immediate(-static_cast<int64_t>(adjust)));
 }
 
 void X86_64Assembler::DecreaseFrameSize(size_t adjust) {
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 548d379..6276603 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -29,6 +29,13 @@
 namespace art {
 namespace x86_64 {
 
+// Encodes an immediate value for operands.
+//
+// Note: Immediates can be 64b on x86-64 for certain instructions, but are often restricted
+// to 32b.
+//
+// Note: As we support cross-compilation, the value type must be int64_t. Please be aware of
+// conversion rules in expressions regarding negation, especially size_t on 32b.
 class Immediate {
  public:
   explicit Immediate(int64_t value) : value_(value) {}
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 7201d04..799db9f 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -200,4 +200,122 @@
   DriverFn(&setcc_test_fn, "setcc");
 }
 
+static x86_64::X86_64ManagedRegister ManagedFromCpu(x86_64::Register r) {
+  return x86_64::X86_64ManagedRegister::FromCpuRegister(r);
+}
+
+static x86_64::X86_64ManagedRegister ManagedFromFpu(x86_64::FloatRegister r) {
+  return x86_64::X86_64ManagedRegister::FromXmmRegister(r);
+}
+
+std::string buildframe_test_fn(x86_64::X86_64Assembler* assembler) {
+  // TODO: more interesting spill registers / entry spills.
+
+  // Two random spill regs.
+  std::vector<ManagedRegister> spill_regs;
+  spill_regs.push_back(ManagedFromCpu(x86_64::R10));
+  spill_regs.push_back(ManagedFromCpu(x86_64::RSI));
+
+  // Three random entry spills.
+  ManagedRegisterEntrySpills entry_spills;
+  ManagedRegisterSpill spill(ManagedFromCpu(x86_64::RAX), 8, 0);
+  entry_spills.push_back(spill);
+  ManagedRegisterSpill spill2(ManagedFromCpu(x86_64::RBX), 8, 8);
+  entry_spills.push_back(spill2);
+  ManagedRegisterSpill spill3(ManagedFromFpu(x86_64::XMM1), 8, 16);
+  entry_spills.push_back(spill3);
+
+  x86_64::X86_64ManagedRegister method_reg = ManagedFromCpu(x86_64::RDI);
+
+  size_t frame_size = 10 * kStackAlignment;
+  assembler->BuildFrame(10 * kStackAlignment, method_reg, spill_regs, entry_spills);
+
+  // Construct assembly text counterpart.
+  std::ostringstream str;
+  // 1) Push the spill_regs.
+  str << "pushq %rsi\n";
+  str << "pushq %r10\n";
+  // 2) Move down the stack pointer.
+  ssize_t displacement = -static_cast<ssize_t>(frame_size) + spill_regs.size() * 8 +
+      sizeof(StackReference<mirror::ArtMethod>) + 8;
+  str << "addq $" << displacement << ", %rsp\n";
+  // 3) Make space for method reference, and store it.
+  str << "subq $4, %rsp\n";
+  str << "movl %edi, (%rsp)\n";
+  // 4) Entry spills.
+  str << "movq %rax, " << frame_size + 0 << "(%rsp)\n";
+  str << "movq %rbx, " << frame_size + 8 << "(%rsp)\n";
+  str << "movsd %xmm1, " << frame_size + 16 << "(%rsp)\n";
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, BuildFrame) {
+  DriverFn(&buildframe_test_fn, "BuildFrame");
+}
+
+std::string removeframe_test_fn(x86_64::X86_64Assembler* assembler) {
+  // TODO: more interesting spill registers / entry spills.
+
+  // Two random spill regs.
+  std::vector<ManagedRegister> spill_regs;
+  spill_regs.push_back(ManagedFromCpu(x86_64::R10));
+  spill_regs.push_back(ManagedFromCpu(x86_64::RSI));
+
+  size_t frame_size = 10 * kStackAlignment;
+  assembler->RemoveFrame(10 * kStackAlignment, spill_regs);
+
+  // Construct assembly text counterpart.
+  std::ostringstream str;
+  // 1) Move up the stack pointer.
+  ssize_t displacement = static_cast<ssize_t>(frame_size) - spill_regs.size() * 8 - 8;
+  str << "addq $" << displacement << ", %rsp\n";
+  // 2) Pop spill regs.
+  str << "popq %r10\n";
+  str << "popq %rsi\n";
+  str << "ret\n";
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, RemoveFrame) {
+  DriverFn(&removeframe_test_fn, "RemoveFrame");
+}
+
+std::string increaseframe_test_fn(x86_64::X86_64Assembler* assembler) {
+  assembler->IncreaseFrameSize(0U);
+  assembler->IncreaseFrameSize(kStackAlignment);
+  assembler->IncreaseFrameSize(10 * kStackAlignment);
+
+  // Construct assembly text counterpart.
+  std::ostringstream str;
+  str << "addq $0, %rsp\n";
+  str << "addq $-" << kStackAlignment << ", %rsp\n";
+  str << "addq $-" << 10 * kStackAlignment << ", %rsp\n";
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, IncreaseFrame) {
+  DriverFn(&increaseframe_test_fn, "IncreaseFrame");
+}
+
+std::string decreaseframe_test_fn(x86_64::X86_64Assembler* assembler) {
+  assembler->DecreaseFrameSize(0U);
+  assembler->DecreaseFrameSize(kStackAlignment);
+  assembler->DecreaseFrameSize(10 * kStackAlignment);
+
+  // Construct assembly text counterpart.
+  std::ostringstream str;
+  str << "addq $0, %rsp\n";
+  str << "addq $" << kStackAlignment << ", %rsp\n";
+  str << "addq $" << 10 * kStackAlignment << ", %rsp\n";
+
+  return str.str();
+}
+
+TEST_F(AssemblerX86_64Test, DecreaseFrame) {
+  DriverFn(&decreaseframe_test_fn, "DecreaseFrame");
+}
+
 }  // namespace art
diff --git a/dalvikvm/Android.mk b/dalvikvm/Android.mk
index 03d32f0..31fcd17 100644
--- a/dalvikvm/Android.mk
+++ b/dalvikvm/Android.mk
@@ -38,7 +38,6 @@
 
 ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$(LOCAL_MODULE)
 
-ifeq ($(WITH_HOST_DALVIK),true)
 include $(CLEAR_VARS)
 LOCAL_MODULE := dalvikvm
 LOCAL_MODULE_TAGS := optional
@@ -54,4 +53,3 @@
 include external/libcxx/libcxx.mk
 include $(BUILD_HOST_EXECUTABLE)
 ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)
-endif
diff --git a/dex2oat/Android.mk b/dex2oat/Android.mk
index c17788e..28db711 100644
--- a/dex2oat/Android.mk
+++ b/dex2oat/Android.mk
@@ -36,12 +36,10 @@
   $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler,art/compiler,target,debug,$(dex2oat_arch)))
 endif
 
-ifeq ($(WITH_HOST_DALVIK),true)
-  # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
-  ifeq ($(ART_BUILD_NDEBUG),true)
-    $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libart-compiler,art/compiler,host,ndebug))
-  endif
-  ifeq ($(ART_BUILD_DEBUG),true)
-    $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libartd-compiler,art/compiler,host,debug))
-  endif
+# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
+ifeq ($(ART_BUILD_NDEBUG),true)
+  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libart-compiler,art/compiler,host,ndebug))
+endif
+ifeq ($(ART_BUILD_DEBUG),true)
+  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libartd-compiler,art/compiler,host,debug))
 endif
diff --git a/disassembler/Android.mk b/disassembler/Android.mk
index b4b194d..feacbde 100644
--- a/disassembler/Android.mk
+++ b/disassembler/Android.mk
@@ -98,12 +98,10 @@
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
   $(eval $(call build-libart-disassembler,target,debug))
 endif
-ifeq ($(WITH_HOST_DALVIK),true)
-  # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
-  ifeq ($(ART_BUILD_NDEBUG),true)
-    $(eval $(call build-libart-disassembler,host,ndebug))
-  endif
-  ifeq ($(ART_BUILD_DEBUG),true)
-    $(eval $(call build-libart-disassembler,host,debug))
-  endif
+# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
+ifeq ($(ART_BUILD_NDEBUG),true)
+  $(eval $(call build-libart-disassembler,host,ndebug))
+endif
+ifeq ($(ART_BUILD_DEBUG),true)
+  $(eval $(call build-libart-disassembler,host,debug))
 endif
diff --git a/oatdump/Android.mk b/oatdump/Android.mk
index 7cee00e..ecf6a0b 100644
--- a/oatdump/Android.mk
+++ b/oatdump/Android.mk
@@ -28,11 +28,9 @@
   $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libcutils libartd-disassembler,art/disassembler,target,debug))
 endif
 
-ifeq ($(WITH_HOST_DALVIK),true)
-  ifeq ($(ART_BUILD_HOST_NDEBUG),true)
-    $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libart-disassembler,art/disassembler,host,ndebug))
-  endif
-  ifeq ($(ART_BUILD_HOST_DEBUG),true)
-    $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libartd-disassembler,art/disassembler,host,debug))
-  endif
+ifeq ($(ART_BUILD_HOST_NDEBUG),true)
+  $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libart-disassembler,art/disassembler,host,ndebug))
+endif
+ifeq ($(ART_BUILD_HOST_DEBUG),true)
+  $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libartd-disassembler,art/disassembler,host,debug))
 endif
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 8f8eeba..c40ae7a8 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -196,7 +196,8 @@
 LIBART_GCC_ONLY_SRC_FILES := \
 	interpreter/interpreter_goto_table_impl.cc
 
-LIBART_LDFLAGS := -Wl,--no-fatal-warnings
+LIBART_TARGET_LDFLAGS := -Wl,--no-fatal-warnings
+LIBART_HOST_LDFLAGS :=
 
 LIBART_TARGET_SRC_FILES := \
 	$(LIBART_COMMON_SRC_FILES) \
@@ -368,6 +369,11 @@
 
   LOCAL_CFLAGS := $(LIBART_CFLAGS)
   LOCAL_LDFLAGS := $(LIBART_LDFLAGS)
+  ifeq ($$(art_target_or_host),target)
+    LOCAL_LDFLAGS += $(LIBART_TARGET_LDFLAGS)
+  else
+    LOCAL_LDFLAGS += $(LIBART_HOST_LDFLAGS)
+  endif
   $(foreach arch,$(ART_SUPPORTED_ARCH),
     LOCAL_LDFLAGS_$(arch) := $$(LIBART_TARGET_LDFLAGS_$(arch)))
 
@@ -442,13 +448,11 @@
 
 # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since
 # they are used to cross compile for the target.
-ifeq ($(WITH_HOST_DALVIK),true)
-  ifeq ($(ART_BUILD_NDEBUG),true)
-    $(eval $(call build-libart,host,ndebug))
-  endif
-  ifeq ($(ART_BUILD_DEBUG),true)
-    $(eval $(call build-libart,host,debug))
-  endif
+ifeq ($(ART_BUILD_NDEBUG),true)
+  $(eval $(call build-libart,host,ndebug))
+endif
+ifeq ($(ART_BUILD_DEBUG),true)
+  $(eval $(call build-libart,host,debug))
 endif
 
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 3be0faf..59311bc 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -77,9 +77,10 @@
 #if defined(__i386__)
     // TODO: Set the thread?
     __asm__ __volatile__(
-        "pushl %[referrer]\n\t"     // Store referrer
+        "subl $12, %%esp\n\t"       // Align stack.
+        "pushl %[referrer]\n\t"     // Store referrer.
         "call *%%edi\n\t"           // Call the stub
-        "addl $4, %%esp"            // Pop referrer
+        "addl $16, %%esp"           // Pop referrer
         : "=a" (result)
           // Use the result from eax
         : "a"(arg0), "c"(arg1), "d"(arg2), "D"(code), [referrer]"r"(referrer)
@@ -300,9 +301,10 @@
     // TODO: Set the thread?
     __asm__ __volatile__(
         "movd %[hidden], %%xmm0\n\t"
+        "subl $12, %%esp\n\t"       // Align stack.
         "pushl %[referrer]\n\t"     // Store referrer
         "call *%%edi\n\t"           // Call the stub
-        "addl $4, %%esp"            // Pop referrer
+        "addl $16, %%esp"           // Pop referrer
         : "=a" (result)
           // Use the result from eax
         : "a"(arg0), "c"(arg1), "d"(arg2), "D"(code), [referrer]"m"(referrer), [hidden]"r"(hidden)
diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S
index f1d0746..ae39be1 100644
--- a/runtime/arch/x86/asm_support_x86.S
+++ b/runtime/arch/x86/asm_support_x86.S
@@ -28,6 +28,7 @@
     #define END_MACRO .endmacro
 
     // Clang's as(1) uses $0, $1, and so on for macro arguments.
+    #define RAW_VAR(name,index) $index
     #define VAR(name,index) SYMBOL($index)
     #define PLT_VAR(name, index) SYMBOL($index)
     #define REG_VAR(name,index) %$index
@@ -50,6 +51,7 @@
     // no special meaning to $, so literals are still just $x. The use of altmacro means % is a
     // special character meaning care needs to be taken when passing registers as macro arguments.
     .altmacro
+    #define RAW_VAR(name,index) name&
     #define VAR(name,index) name&
     #define PLT_VAR(name, index) name&@PLT
     #define REG_VAR(name,index) %name
@@ -94,7 +96,7 @@
 #if !defined(__APPLE__)
     #define SYMBOL(name) name
     #if defined(__clang__) && (__clang_major__ < 4) && (__clang_minor__ < 5)
-        // TODO: Disabled for old clang 3.3, this leads to text reolocations and there should be a
+        // TODO: Disabled for old clang 3.3, this leads to text relocations and there should be a
         // better fix.
         #define PLT_SYMBOL(name) name // ## @PLT
     #else
@@ -151,8 +153,10 @@
 END_MACRO
 
 MACRO0(SETUP_GOT_NOSAVE)
+#ifndef __APPLE__
     call __x86.get_pc_thunk.bx
     addl $_GLOBAL_OFFSET_TABLE_, %ebx
+#endif
 END_MACRO
 
 MACRO0(SETUP_GOT)
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 989ecf9..28e4dd6 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -111,7 +111,7 @@
 END_MACRO
 
 MACRO2(NO_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
-    DEFINE_FUNCTION VAR(c_name, 0)
+    DEFINE_FUNCTION RAW_VAR(c_name, 0)
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
     mov %esp, %ecx
     // Outgoing argument set up
@@ -123,11 +123,11 @@
     SETUP_GOT_NOSAVE              // clobbers ebx (harmless here)
     call PLT_VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
     int3                          // unreached
-    END_FUNCTION VAR(c_name, 0)
+    END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO2(ONE_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
-    DEFINE_FUNCTION VAR(c_name, 0)
+    DEFINE_FUNCTION RAW_VAR(c_name, 0)
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
     mov %esp, %ecx
     // Outgoing argument set up
@@ -139,11 +139,11 @@
     SETUP_GOT_NOSAVE              // clobbers ebx (harmless here)
     call PLT_VAR(cxx_name, 1)     // cxx_name(arg1, Thread*, SP)
     int3                          // unreached
-    END_FUNCTION VAR(c_name, 0)
+    END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO2(TWO_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
-    DEFINE_FUNCTION VAR(c_name, 0)
+    DEFINE_FUNCTION RAW_VAR(c_name, 0)
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
     mov %esp, %edx
     // Outgoing argument set up
@@ -155,7 +155,7 @@
     SETUP_GOT_NOSAVE              // clobbers ebx (harmless here)
     call PLT_VAR(cxx_name, 1)     // cxx_name(arg1, arg2, Thread*, SP)
     int3                          // unreached
-    END_FUNCTION VAR(c_name, 0)
+    END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
     /*
@@ -207,7 +207,7 @@
      * pointing back to the original caller.
      */
 MACRO2(INVOKE_TRAMPOLINE, c_name, cxx_name)
-    DEFINE_FUNCTION VAR(c_name, 0)
+    DEFINE_FUNCTION RAW_VAR(c_name, 0)
     // Set up the callee save frame to conform with Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
     // return address
     PUSH edi
@@ -248,7 +248,7 @@
     addl MACRO_LITERAL(4), %esp   // Pop code pointer off stack
     CFI_ADJUST_CFA_OFFSET(-4)
     DELIVER_PENDING_EXCEPTION
-    END_FUNCTION VAR(c_name, 0)
+    END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
@@ -315,7 +315,7 @@
 END_FUNCTION art_quick_invoke_stub
 
 MACRO3(NO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
-    DEFINE_FUNCTION VAR(c_name, 0)
+    DEFINE_FUNCTION RAW_VAR(c_name, 0)
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
     mov %esp, %edx                // remember SP
     SETUP_GOT_NOSAVE              // clobbers ebx (harmless here)
@@ -330,11 +330,11 @@
     CFI_ADJUST_CFA_OFFSET(-16)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)   // return or deliver exception
-    END_FUNCTION VAR(c_name, 0)
+    END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO3(ONE_ARG_DOWNCALL, c_name, cxx_name, return_macro)
-    DEFINE_FUNCTION VAR(c_name, 0)
+    DEFINE_FUNCTION RAW_VAR(c_name, 0)
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
     mov %esp, %edx                // remember SP
     SETUP_GOT_NOSAVE              // clobbers EBX
@@ -349,11 +349,11 @@
     CFI_ADJUST_CFA_OFFSET(-16)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)   // return or deliver exception
-    END_FUNCTION VAR(c_name, 0)
+    END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO3(TWO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
-    DEFINE_FUNCTION VAR(c_name, 0)
+    DEFINE_FUNCTION RAW_VAR(c_name, 0)
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
     mov %esp, %edx                // remember SP
     SETUP_GOT_NOSAVE              // clobbers EBX
@@ -368,11 +368,11 @@
     CFI_ADJUST_CFA_OFFSET(-16)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)   // return or deliver exception
-    END_FUNCTION VAR(c_name, 0)
+    END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO3(THREE_ARG_DOWNCALL, c_name, cxx_name, return_macro)
-    DEFINE_FUNCTION VAR(c_name, 0)
+    DEFINE_FUNCTION RAW_VAR(c_name, 0)
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
     mov %esp, %ebx                // remember SP
     // Outgoing argument set up
@@ -390,7 +390,7 @@
     CFI_ADJUST_CFA_OFFSET(-32)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)   // return or deliver exception
-    END_FUNCTION VAR(c_name, 0)
+    END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO0(RETURN_IF_RESULT_IS_NON_ZERO)
@@ -653,17 +653,17 @@
      */
 DEFINE_FUNCTION art_quick_aput_obj_with_null_and_bound_check
     testl %eax, %eax
-    jnz art_quick_aput_obj_with_bound_check
-    jmp art_quick_throw_null_pointer_exception
+    jnz SYMBOL(art_quick_aput_obj_with_bound_check)
+    jmp SYMBOL(art_quick_throw_null_pointer_exception)
 END_FUNCTION art_quick_aput_obj_with_null_and_bound_check
 
 DEFINE_FUNCTION art_quick_aput_obj_with_bound_check
     movl ARRAY_LENGTH_OFFSET(%eax), %ebx
     cmpl %ebx, %ecx
-    jb art_quick_aput_obj
+    jb SYMBOL(art_quick_aput_obj)
     mov %ecx, %eax
     mov %ebx, %ecx
-    jmp art_quick_throw_array_bounds
+    jmp SYMBOL(art_quick_throw_array_bounds)
 END_FUNCTION art_quick_aput_obj_with_bound_check
 
 DEFINE_FUNCTION art_quick_aput_obj
@@ -1122,7 +1122,7 @@
     movd %xmm0, %ecx              // get target method index stored in xmm0
     movl OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4), %eax  // load the target method
     POP ecx
-    jmp art_quick_invoke_interface_trampoline
+    jmp SYMBOL(art_quick_invoke_interface_trampoline)
 END_FUNCTION art_quick_imt_conflict_trampoline
 
 DEFINE_FUNCTION art_quick_resolution_trampoline
@@ -1218,10 +1218,10 @@
     jnz .Lexception_in_native
 
     // Tear down the callee-save frame.
-    addl MACRO_LITERAL(4), %esp     // Remove padding
+    addl LITERAL(4), %esp     // Remove padding
     CFI_ADJUST_CFA_OFFSET(-4)
     POP ecx
-    addl MACRO_LITERAL(4), %esp     // Avoid edx, as it may be part of the result.
+    addl LITERAL(4), %esp     // Avoid edx, as it may be part of the result.
     CFI_ADJUST_CFA_OFFSET(-4)
     POP ebx
     POP ebp  // Restore callee saves
diff --git a/runtime/arch/x86/thread_x86.cc b/runtime/arch/x86/thread_x86.cc
index 9f36927..b97c143 100644
--- a/runtime/arch/x86/thread_x86.cc
+++ b/runtime/arch/x86/thread_x86.cc
@@ -156,7 +156,11 @@
 
   // Free LDT entry.
 #if defined(__APPLE__)
-  i386_set_ldt(selector >> 3, 0, 1);
+  // TODO: release selectors on OS/X this is a leak which will cause ldt entries to be exhausted
+  // after enough threads are created. However, the following code results in kernel panics in OS/X
+  // 10.9.
+  UNUSED(selector);
+  // i386_set_ldt(selector >> 3, 0, 1);
 #else
   user_desc ldt_entry;
   memset(&ldt_entry, 0, sizeof(ldt_entry));
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index d20eb17..1890181 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -45,54 +45,6 @@
 }
 #endif  // ART_USE_FUTEXES
 
-#if defined(__APPLE__)
-
-// This works on Mac OS 10.6 but hasn't been tested on older releases.
-struct __attribute__((__may_alias__)) darwin_pthread_mutex_t {
-  long padding0;  // NOLINT(runtime/int) exact match to darwin type
-  int padding1;
-  uint32_t padding2;
-  int16_t padding3;
-  int16_t padding4;
-  uint32_t padding5;
-  pthread_t darwin_pthread_mutex_owner;
-  // ...other stuff we don't care about.
-};
-
-struct __attribute__((__may_alias__)) darwin_pthread_rwlock_t {
-  long padding0;  // NOLINT(runtime/int) exact match to darwin type
-  pthread_mutex_t padding1;
-  int padding2;
-  pthread_cond_t padding3;
-  pthread_cond_t padding4;
-  int padding5;
-  int padding6;
-  pthread_t darwin_pthread_rwlock_owner;
-  // ...other stuff we don't care about.
-};
-
-#endif  // __APPLE__
-
-#if defined(__GLIBC__)
-
-struct __attribute__((__may_alias__)) glibc_pthread_mutex_t {
-  int32_t padding0[2];
-  int owner;
-  // ...other stuff we don't care about.
-};
-
-struct __attribute__((__may_alias__)) glibc_pthread_rwlock_t {
-#ifdef __LP64__
-  int32_t padding0[6];
-#else
-  int32_t padding0[7];
-#endif
-  int writer;
-  // ...other stuff we don't care about.
-};
-
-#endif  // __GLIBC__
-
 class ScopedContentionRecorder {
  public:
   ScopedContentionRecorder(BaseMutex* mutex, uint64_t blocked_tid, uint64_t owner_tid)
@@ -219,12 +171,14 @@
 #else
   CHECK_MUTEX_CALL(pthread_rwlock_rdlock, (&rwlock_));
 #endif
+  DCHECK(exclusive_owner_ == 0U || exclusive_owner_ == -1U);
   RegisterAsLocked(self);
   AssertSharedHeld(self);
 }
 
 inline void ReaderWriterMutex::SharedUnlock(Thread* self) {
   DCHECK(self == NULL || self == Thread::Current());
+  DCHECK(exclusive_owner_ == 0U || exclusive_owner_ == -1U);
   AssertSharedHeld(self);
   RegisterAsUnlocked(self);
 #if ART_USE_FUTEXES
@@ -262,26 +216,7 @@
 }
 
 inline uint64_t Mutex::GetExclusiveOwnerTid() const {
-#if ART_USE_FUTEXES
   return exclusive_owner_;
-#elif defined(__BIONIC__)
-  return static_cast<uint64_t>((mutex_.value >> 16) & 0xffff);
-#elif defined(__GLIBC__)
-  return reinterpret_cast<const glibc_pthread_mutex_t*>(&mutex_)->owner;
-#elif defined(__APPLE__)
-  const darwin_pthread_mutex_t* dpmutex = reinterpret_cast<const darwin_pthread_mutex_t*>(&mutex_);
-  pthread_t owner = dpmutex->darwin_pthread_mutex_owner;
-  // 0 for unowned, -1 for PTHREAD_MTX_TID_SWITCHING
-  // TODO: should we make darwin_pthread_mutex_owner volatile and recheck until not -1?
-  if ((owner == (pthread_t)0) || (owner == (pthread_t)-1)) {
-    return 0;
-  }
-  uint64_t tid;
-  CHECK_PTHREAD_CALL(pthread_threadid_np, (owner, &tid), __FUNCTION__);  // Requires Mac OS 10.6
-  return tid;
-#else
-#error unsupported C library
-#endif
 }
 
 inline bool ReaderWriterMutex::IsExclusiveHeld(const Thread* self) const {
@@ -307,23 +242,7 @@
     return exclusive_owner_;
   }
 #else
-#if defined(__BIONIC__)
-  return rwlock_.writerThreadId;
-#elif defined(__GLIBC__)
-  return reinterpret_cast<const glibc_pthread_rwlock_t*>(&rwlock_)->writer;
-#elif defined(__APPLE__)
-  const darwin_pthread_rwlock_t*
-      dprwlock = reinterpret_cast<const darwin_pthread_rwlock_t*>(&rwlock_);
-  pthread_t owner = dprwlock->darwin_pthread_rwlock_owner;
-  if (owner == (pthread_t)0) {
-    return 0;
-  }
-  uint64_t tid;
-  CHECK_PTHREAD_CALL(pthread_threadid_np, (owner, &tid), __FUNCTION__);  // Requires Mac OS 10.6
-  return tid;
-#else
-#error unsupported C library
-#endif
+  return exclusive_owner_;
 #endif
 }
 
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index aeece74..fd1eb12 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -263,19 +263,11 @@
     : BaseMutex(name, level), recursive_(recursive), recursion_count_(0) {
 #if ART_USE_FUTEXES
   state_ = 0;
-  exclusive_owner_ = 0;
   DCHECK_EQ(0, num_contenders_.LoadRelaxed());
-#elif defined(__BIONIC__) || defined(__APPLE__)
-  // Use recursive mutexes for bionic and Apple otherwise the
-  // non-recursive mutexes don't have TIDs to check lock ownership of.
-  pthread_mutexattr_t attributes;
-  CHECK_MUTEX_CALL(pthread_mutexattr_init, (&attributes));
-  CHECK_MUTEX_CALL(pthread_mutexattr_settype, (&attributes, PTHREAD_MUTEX_RECURSIVE));
-  CHECK_MUTEX_CALL(pthread_mutex_init, (&mutex_, &attributes));
-  CHECK_MUTEX_CALL(pthread_mutexattr_destroy, (&attributes));
 #else
-  CHECK_MUTEX_CALL(pthread_mutex_init, (&mutex_, NULL));
+  CHECK_MUTEX_CALL(pthread_mutex_init, (&mutex_, nullptr));
 #endif
+  exclusive_owner_ = 0;
 }
 
 Mutex::~Mutex() {
@@ -336,10 +328,11 @@
     // TODO: Change state_ to be a art::Atomic and use an intention revealing CAS operation
     // that exposes the ordering semantics.
     DCHECK_EQ(state_, 1);
-    exclusive_owner_ = SafeGetTid(self);
 #else
     CHECK_MUTEX_CALL(pthread_mutex_lock, (&mutex_));
 #endif
+    DCHECK_EQ(exclusive_owner_, 0U);
+    exclusive_owner_ = SafeGetTid(self);
     RegisterAsLocked(self);
   }
   recursion_count_++;
@@ -369,7 +362,6 @@
     } while (!done);
     // We again assert no memory fence is needed.
     DCHECK_EQ(state_, 1);
-    exclusive_owner_ = SafeGetTid(self);
 #else
     int result = pthread_mutex_trylock(&mutex_);
     if (result == EBUSY) {
@@ -380,6 +372,8 @@
       PLOG(FATAL) << "pthread_mutex_trylock failed for " << name_;
     }
 #endif
+    DCHECK_EQ(exclusive_owner_, 0U);
+    exclusive_owner_ = SafeGetTid(self);
     RegisterAsLocked(self);
   }
   recursion_count_++;
@@ -394,6 +388,7 @@
 void Mutex::ExclusiveUnlock(Thread* self) {
   DCHECK(self == NULL || self == Thread::Current());
   AssertHeld(self);
+  DCHECK_NE(exclusive_owner_, 0U);
   recursion_count_--;
   if (!recursive_ || recursion_count_ == 0) {
     if (kDebugLocking) {
@@ -402,34 +397,35 @@
     }
     RegisterAsUnlocked(self);
 #if ART_USE_FUTEXES
-  bool done = false;
-  do {
-    int32_t cur_state = state_;
-    if (LIKELY(cur_state == 1)) {
-      // The __sync_bool_compare_and_swap enforces the necessary memory ordering.
-      // We're no longer the owner.
-      exclusive_owner_ = 0;
-      // Change state to 0.
-      done =  __sync_bool_compare_and_swap(&state_, cur_state, 0 /* new state */);
-      if (LIKELY(done)) {  // Spurious fail?
-        // Wake a contender
-        if (UNLIKELY(num_contenders_.LoadRelaxed() > 0)) {
-          futex(&state_, FUTEX_WAKE, 1, NULL, NULL, 0);
+    bool done = false;
+    do {
+      int32_t cur_state = state_;
+      if (LIKELY(cur_state == 1)) {
+        // The __sync_bool_compare_and_swap enforces the necessary memory ordering.
+        // We're no longer the owner.
+        exclusive_owner_ = 0;
+        // Change state to 0.
+        done =  __sync_bool_compare_and_swap(&state_, cur_state, 0 /* new state */);
+        if (LIKELY(done)) {  // Spurious fail?
+          // Wake a contender
+          if (UNLIKELY(num_contenders_.LoadRelaxed() > 0)) {
+            futex(&state_, FUTEX_WAKE, 1, NULL, NULL, 0);
+          }
+        }
+      } else {
+        // Logging acquires the logging lock, avoid infinite recursion in that case.
+        if (this != Locks::logging_lock_) {
+          LOG(FATAL) << "Unexpected state_ in unlock " << cur_state << " for " << name_;
+        } else {
+          LogMessageData data(__FILE__, __LINE__, INTERNAL_FATAL, -1);
+          LogMessage::LogLine(data, StringPrintf("Unexpected state_ %d in unlock for %s",
+                                                 cur_state, name_).c_str());
+          _exit(1);
         }
       }
-    } else {
-      // Logging acquires the logging lock, avoid infinite recursion in that case.
-      if (this != Locks::logging_lock_) {
-        LOG(FATAL) << "Unexpected state_ in unlock " << cur_state << " for " << name_;
-      } else {
-        LogMessageData data(__FILE__, __LINE__, INTERNAL_FATAL, -1);
-        LogMessage::LogLine(data, StringPrintf("Unexpected state_ %d in unlock for %s",
-                                               cur_state, name_).c_str());
-        _exit(1);
-      }
-    }
-  } while (!done);
+    } while (!done);
 #else
+    exclusive_owner_ = 0;
     CHECK_MUTEX_CALL(pthread_mutex_unlock, (&mutex_));
 #endif
   }
@@ -452,12 +448,13 @@
 ReaderWriterMutex::ReaderWriterMutex(const char* name, LockLevel level)
     : BaseMutex(name, level)
 #if ART_USE_FUTEXES
-    , state_(0), exclusive_owner_(0), num_pending_readers_(0), num_pending_writers_(0)
+    , state_(0), num_pending_readers_(0), num_pending_writers_(0)
 #endif
 {  // NOLINT(whitespace/braces)
 #if !ART_USE_FUTEXES
-  CHECK_MUTEX_CALL(pthread_rwlock_init, (&rwlock_, NULL));
+  CHECK_MUTEX_CALL(pthread_rwlock_init, (&rwlock_, nullptr));
 #endif
+  exclusive_owner_ = 0;
 }
 
 ReaderWriterMutex::~ReaderWriterMutex() {
@@ -506,10 +503,11 @@
     }
   } while (!done);
   DCHECK_EQ(state_, -1);
-  exclusive_owner_ = SafeGetTid(self);
 #else
   CHECK_MUTEX_CALL(pthread_rwlock_wrlock, (&rwlock_));
 #endif
+  DCHECK_EQ(exclusive_owner_, 0U);
+  exclusive_owner_ = SafeGetTid(self);
   RegisterAsLocked(self);
   AssertExclusiveHeld(self);
 }
@@ -518,6 +516,7 @@
   DCHECK(self == NULL || self == Thread::Current());
   AssertExclusiveHeld(self);
   RegisterAsUnlocked(self);
+  DCHECK_NE(exclusive_owner_, 0U);
 #if ART_USE_FUTEXES
   bool done = false;
   do {
@@ -538,6 +537,7 @@
     }
   } while (!done);
 #else
+  exclusive_owner_ = 0;
   CHECK_MUTEX_CALL(pthread_rwlock_unlock, (&rwlock_));
 #endif
 }
@@ -578,7 +578,6 @@
       num_pending_writers_--;
     }
   } while (!done);
-  exclusive_owner_ = SafeGetTid(self);
 #else
   timespec ts;
   InitTimeSpec(true, CLOCK_REALTIME, ms, ns, &ts);
@@ -591,6 +590,7 @@
     PLOG(FATAL) << "pthread_rwlock_timedwrlock failed for " << name_;
   }
 #endif
+  exclusive_owner_ = SafeGetTid(self);
   RegisterAsLocked(self);
   AssertSharedHeld(self);
   return true;
@@ -656,7 +656,7 @@
   num_waiters_ = 0;
 #else
   pthread_condattr_t cond_attrs;
-  CHECK_MUTEX_CALL(pthread_condattr_init(&cond_attrs));
+  CHECK_MUTEX_CALL(pthread_condattr_init, (&cond_attrs));
 #if !defined(__APPLE__)
   // Apple doesn't have CLOCK_MONOTONIC or pthread_condattr_setclock.
   CHECK_MUTEX_CALL(pthread_condattr_setclock(&cond_attrs, CLOCK_MONOTONIC));
@@ -763,8 +763,11 @@
   CHECK_GE(guard_.num_contenders_.LoadRelaxed(), 0);
   guard_.num_contenders_--;
 #else
+  uint64_t old_owner = guard_.exclusive_owner_;
+  guard_.exclusive_owner_ = 0;
   guard_.recursion_count_ = 0;
   CHECK_MUTEX_CALL(pthread_cond_wait, (&cond_, &guard_.mutex_));
+  guard_.exclusive_owner_ = old_owner;
 #endif
   guard_.recursion_count_ = old_recursion_count;
 }
@@ -804,6 +807,8 @@
 #else
   int clock = CLOCK_REALTIME;
 #endif
+  uint64_t old_owner = guard_.exclusive_owner_;
+  guard_.exclusive_owner_ = 0;
   guard_.recursion_count_ = 0;
   timespec ts;
   InitTimeSpec(true, clock, ms, ns, &ts);
@@ -812,6 +817,7 @@
     errno = rc;
     PLOG(FATAL) << "TimedWait failed for " << name_;
   }
+  guard_.exclusive_owner_ = old_owner;
 #endif
   guard_.recursion_count_ = old_recursion_count;
 }
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 68b450a..1ba6180 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -245,6 +245,7 @@
   AtomicInteger num_contenders_;
 #else
   pthread_mutex_t mutex_;
+  volatile uint64_t exclusive_owner_;  // Guarded by mutex_.
 #endif
   const bool recursive_;  // Can the lock be recursively held?
   unsigned int recursion_count_;
@@ -358,6 +359,7 @@
   AtomicInteger num_pending_writers_;
 #else
   pthread_rwlock_t rwlock_;
+  volatile uint64_t exclusive_owner_;  // Guarded by rwlock_.
 #endif
   DISALLOW_COPY_AND_ASSIGN(ReaderWriterMutex);
 };
diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc
index 87d1c06..6d5b59c 100644
--- a/runtime/base/unix_file/fd_file.cc
+++ b/runtime/base/unix_file/fd_file.cc
@@ -69,17 +69,29 @@
 }
 
 int FdFile::Flush() {
+#ifdef __linux__
   int rc = TEMP_FAILURE_RETRY(fdatasync(fd_));
+#else
+  int rc = TEMP_FAILURE_RETRY(fsync(fd_));
+#endif
   return (rc == -1) ? -errno : rc;
 }
 
 int64_t FdFile::Read(char* buf, int64_t byte_count, int64_t offset) const {
+#ifdef __linux__
   int rc = TEMP_FAILURE_RETRY(pread64(fd_, buf, byte_count, offset));
+#else
+  int rc = TEMP_FAILURE_RETRY(pread(fd_, buf, byte_count, offset));
+#endif
   return (rc == -1) ? -errno : rc;
 }
 
 int FdFile::SetLength(int64_t new_length) {
+#ifdef __linux__
   int rc = TEMP_FAILURE_RETRY(ftruncate64(fd_, new_length));
+#else
+  int rc = TEMP_FAILURE_RETRY(ftruncate(fd_, new_length));
+#endif
   return (rc == -1) ? -errno : rc;
 }
 
@@ -90,7 +102,11 @@
 }
 
 int64_t FdFile::Write(const char* buf, int64_t byte_count, int64_t offset) {
+#ifdef __linux__
   int rc = TEMP_FAILURE_RETRY(pwrite64(fd_, buf, byte_count, offset));
+#else
+  int rc = TEMP_FAILURE_RETRY(pwrite(fd_, buf, byte_count, offset));
+#endif
   return (rc == -1) ? -errno : rc;
 }
 
diff --git a/runtime/base/unix_file/mapped_file.cc b/runtime/base/unix_file/mapped_file.cc
index bc23a74..63927b1 100644
--- a/runtime/base/unix_file/mapped_file.cc
+++ b/runtime/base/unix_file/mapped_file.cc
@@ -61,7 +61,11 @@
 bool MappedFile::MapReadWrite(int64_t file_size) {
   CHECK(IsOpened());
   CHECK(!IsMapped());
+#ifdef __linux__
   int result = TEMP_FAILURE_RETRY(ftruncate64(Fd(), file_size));
+#else
+  int result = TEMP_FAILURE_RETRY(ftruncate(Fd(), file_size));
+#endif
   if (result == -1) {
     PLOG(ERROR) << "Failed to truncate file '" << GetPath()
                 << "' to size " << file_size;
diff --git a/runtime/base/unix_file/mapped_file.h b/runtime/base/unix_file/mapped_file.h
index 28cc551..73056e9 100644
--- a/runtime/base/unix_file/mapped_file.h
+++ b/runtime/base/unix_file/mapped_file.h
@@ -32,8 +32,13 @@
  public:
   // File modes used in Open().
   enum FileMode {
+#ifdef __linux__
     kReadOnlyMode = O_RDONLY | O_LARGEFILE,
     kReadWriteMode = O_CREAT | O_RDWR | O_LARGEFILE,
+#else
+    kReadOnlyMode = O_RDONLY,
+    kReadWriteMode = O_CREAT | O_RDWR,
+#endif
   };
 
   MappedFile() : FdFile(), file_size_(-1), mapped_file_(NULL) {
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index a0cecb0..349700a 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -62,45 +62,98 @@
 static const size_t kMaxAllocRecordStackDepth = 16;  // Max 255.
 static const size_t kDefaultNumAllocRecords = 64*1024;  // Must be a power of 2.
 
-struct AllocRecordStackTraceElement {
-  mirror::ArtMethod* method;
-  uint32_t dex_pc;
-
-  AllocRecordStackTraceElement() : method(nullptr), dex_pc(0) {
+class AllocRecordStackTraceElement {
+ public:
+  AllocRecordStackTraceElement() : method_(nullptr), dex_pc_(0) {
   }
 
-  int32_t LineNumber() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method->GetLineNumFromDexPC(dex_pc);
+  int32_t LineNumber() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ArtMethod* method = Method();
+    DCHECK(method != nullptr);
+    return method->GetLineNumFromDexPC(DexPc());
   }
+
+  mirror::ArtMethod* Method() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ArtMethod* method = reinterpret_cast<mirror::ArtMethod*>(
+        Thread::Current()->DecodeJObject(method_));
+    return method;
+  }
+
+  void SetMethod(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    ScopedObjectAccessUnchecked soa(Thread::Current());
+    JNIEnv* env = soa.Env();
+    if (method_ != nullptr) {
+      env->DeleteWeakGlobalRef(method_);
+    }
+    method_ = env->NewWeakGlobalRef(soa.AddLocalReference<jobject>(m));
+  }
+
+  uint32_t DexPc() const {
+    return dex_pc_;
+  }
+
+  void SetDexPc(uint32_t pc) {
+    dex_pc_ = pc;
+  }
+
+ private:
+  jobject method_;  // This is a weak global.
+  uint32_t dex_pc_;
 };
 
-struct AllocRecord {
-  mirror::Class* type;
-  size_t byte_count;
-  uint16_t thin_lock_id;
-  AllocRecordStackTraceElement stack[kMaxAllocRecordStackDepth];  // Unused entries have NULL method.
+class AllocRecord {
+ public:
+  AllocRecord() : type_(nullptr), byte_count_(0), thin_lock_id_(0) {}
 
-  size_t GetDepth() {
+  mirror::Class* Type() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::Class* type = reinterpret_cast<mirror::Class*>(
+        Thread::Current()->DecodeJObject(type_));
+    return type;
+  }
+
+  void SetType(mirror::Class* t) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    ScopedObjectAccessUnchecked soa(Thread::Current());
+    JNIEnv* env = soa.Env();
+    if (type_ != nullptr) {
+      env->DeleteWeakGlobalRef(type_);
+    }
+    type_ = env->NewWeakGlobalRef(soa.AddLocalReference<jobject>(t));
+  }
+
+  size_t GetDepth() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     size_t depth = 0;
-    while (depth < kMaxAllocRecordStackDepth && stack[depth].method != NULL) {
+    while (depth < kMaxAllocRecordStackDepth && stack_[depth].Method() != NULL) {
       ++depth;
     }
     return depth;
   }
 
-  void UpdateObjectPointers(IsMarkedCallback* callback, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (type != nullptr) {
-      type = down_cast<mirror::Class*>(callback(type, arg));
-    }
-    for (size_t stack_frame = 0; stack_frame < kMaxAllocRecordStackDepth; ++stack_frame) {
-      mirror::ArtMethod*& m = stack[stack_frame].method;
-      if (m == nullptr) {
-        break;
-      }
-      m = down_cast<mirror::ArtMethod*>(callback(m, arg));
-    }
+  size_t ByteCount() const {
+    return byte_count_;
   }
+
+  void SetByteCount(size_t count) {
+    byte_count_ = count;
+  }
+
+  uint16_t ThinLockId() const {
+    return thin_lock_id_;
+  }
+
+  void SetThinLockId(uint16_t id) {
+    thin_lock_id_ = id;
+  }
+
+  AllocRecordStackTraceElement* StackElement(size_t index) {
+    DCHECK_LT(index, kMaxAllocRecordStackDepth);
+    return &stack_[index];
+  }
+
+ private:
+  jobject type_;  // This is a weak global.
+  size_t byte_count_;
+  uint16_t thin_lock_id_;
+  AllocRecordStackTraceElement stack_[kMaxAllocRecordStackDepth];  // Unused entries have NULL method.
 };
 
 struct Breakpoint {
@@ -848,21 +901,13 @@
 JDWP::JdwpError Dbg::GetOwnedMonitors(JDWP::ObjectId thread_id,
                                       std::vector<JDWP::ObjectId>& monitors,
                                       std::vector<uint32_t>& stack_depths) {
-  ScopedObjectAccessUnchecked soa(Thread::Current());
-  MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
-  if (error != JDWP::ERR_NONE) {
-    return error;
-  }
-  if (!IsSuspendedForDebugger(soa, thread)) {
-    return JDWP::ERR_THREAD_NOT_SUSPENDED;
-  }
-
   struct OwnedMonitorVisitor : public StackVisitor {
-    OwnedMonitorVisitor(Thread* thread, Context* context)
+    OwnedMonitorVisitor(Thread* thread, Context* context,
+                        std::vector<mirror::Object*>* monitor_vector,
+                        std::vector<uint32_t>* stack_depth_vector)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-        : StackVisitor(thread, context), current_stack_depth(0) {}
+      : StackVisitor(thread, context), current_stack_depth(0),
+        monitors(monitor_vector), stack_depths(stack_depth_vector) {}
 
     // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
     // annotalysis.
@@ -876,21 +921,38 @@
 
     static void AppendOwnedMonitors(mirror::Object* owned_monitor, void* arg) {
       OwnedMonitorVisitor* visitor = reinterpret_cast<OwnedMonitorVisitor*>(arg);
-      visitor->monitors.push_back(owned_monitor);
-      visitor->stack_depths.push_back(visitor->current_stack_depth);
+      visitor->monitors->push_back(owned_monitor);
+      visitor->stack_depths->push_back(visitor->current_stack_depth);
     }
 
     size_t current_stack_depth;
-    std::vector<mirror::Object*> monitors;
-    std::vector<uint32_t> stack_depths;
+    std::vector<mirror::Object*>* monitors;
+    std::vector<uint32_t>* stack_depths;
   };
-  std::unique_ptr<Context> context(Context::Create());
-  OwnedMonitorVisitor visitor(thread, context.get());
-  visitor.WalkStack();
 
-  for (size_t i = 0; i < visitor.monitors.size(); ++i) {
-    monitors.push_back(gRegistry->Add(visitor.monitors[i]));
-    stack_depths.push_back(visitor.stack_depths[i]);
+  std::vector<mirror::Object*> monitor_vector;
+  std::vector<uint32_t> stack_depth_vector;
+  ScopedObjectAccessUnchecked soa(Thread::Current());
+  {
+    MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+    Thread* thread;
+    JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+    if (error != JDWP::ERR_NONE) {
+      return error;
+    }
+    if (!IsSuspendedForDebugger(soa, thread)) {
+      return JDWP::ERR_THREAD_NOT_SUSPENDED;
+    }
+    std::unique_ptr<Context> context(Context::Create());
+    OwnedMonitorVisitor visitor(thread, context.get(), &monitor_vector, &stack_depth_vector);
+    visitor.WalkStack();
+  }
+
+  // Add() requires the thread_list_lock_ not held to avoid the lock
+  // level violation.
+  for (size_t i = 0; i < monitor_vector.size(); ++i) {
+    monitors.push_back(gRegistry->Add(monitor_vector[i]));
+    stack_depths.push_back(stack_depth_vector[i]);
   }
 
   return JDWP::ERR_NONE;
@@ -898,19 +960,23 @@
 
 JDWP::JdwpError Dbg::GetContendedMonitor(JDWP::ObjectId thread_id,
                                          JDWP::ObjectId& contended_monitor) {
+  mirror::Object* contended_monitor_obj;
   ScopedObjectAccessUnchecked soa(Thread::Current());
-  MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
-  if (error != JDWP::ERR_NONE) {
-    return error;
+  {
+    MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+    Thread* thread;
+    JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+    if (error != JDWP::ERR_NONE) {
+      return error;
+    }
+    if (!IsSuspendedForDebugger(soa, thread)) {
+      return JDWP::ERR_THREAD_NOT_SUSPENDED;
+    }
+    contended_monitor_obj = Monitor::GetContendedMonitor(thread);
   }
-  if (!IsSuspendedForDebugger(soa, thread)) {
-    return JDWP::ERR_THREAD_NOT_SUSPENDED;
-  }
-
-  contended_monitor = gRegistry->Add(Monitor::GetContendedMonitor(thread));
-
+  // Add() requires the thread_list_lock_ not held to avoid the lock
+  // level violation.
+  contended_monitor = gRegistry->Add(contended_monitor_obj);
   return JDWP::ERR_NONE;
 }
 
@@ -1845,9 +1911,12 @@
   }
   const char* old_cause = soa.Self()->StartAssertNoThreadSuspension("Debugger: GetThreadGroup");
   // Okay, so it's an object, but is it actually a thread?
-  MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
-  Thread* thread;
-  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  JDWP::JdwpError error;
+  {
+    MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+    Thread* thread;
+    error = DecodeThread(soa, thread_id, thread);
+  }
   if (error == JDWP::ERR_THREAD_NOT_ALIVE) {
     // Zombie threads are in the null group.
     expandBufAddObjectId(pReply, JDWP::ObjectId(0));
@@ -1856,9 +1925,9 @@
     mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
     CHECK(c != nullptr);
     mirror::ArtField* f = c->FindInstanceField("group", "Ljava/lang/ThreadGroup;");
-    CHECK(f != NULL);
+    CHECK(f != nullptr);
     mirror::Object* group = f->GetObject(thread_object);
-    CHECK(group != NULL);
+    CHECK(group != nullptr);
     JDWP::ObjectId thread_group_id = gRegistry->Add(group);
     expandBufAddObjectId(pReply, thread_group_id);
   }
@@ -4146,8 +4215,8 @@
     }
     mirror::ArtMethod* m = GetMethod();
     if (!m->IsRuntimeMethod()) {
-      record->stack[depth].method = m;
-      record->stack[depth].dex_pc = GetDexPc();
+      record->StackElement(depth)->SetMethod(m);
+      record->StackElement(depth)->SetDexPc(GetDexPc());
       ++depth;
     }
     return true;
@@ -4156,8 +4225,8 @@
   ~AllocRecordStackVisitor() {
     // Clear out any unused stack trace elements.
     for (; depth < kMaxAllocRecordStackDepth; ++depth) {
-      record->stack[depth].method = NULL;
-      record->stack[depth].dex_pc = 0;
+      record->StackElement(depth)->SetMethod(nullptr);
+      record->StackElement(depth)->SetDexPc(0);
     }
   }
 
@@ -4181,9 +4250,9 @@
 
   // Fill in the basics.
   AllocRecord* record = &recent_allocation_records_[alloc_record_head_];
-  record->type = type;
-  record->byte_count = byte_count;
-  record->thin_lock_id = self->GetThreadId();
+  record->SetType(type);
+  record->SetByteCount(byte_count);
+  record->SetThinLockId(self->GetThreadId());
 
   // Fill in the stack trace.
   AllocRecordStackVisitor visitor(self, record);
@@ -4224,15 +4293,16 @@
   while (count--) {
     AllocRecord* record = &recent_allocation_records_[i];
 
-    LOG(INFO) << StringPrintf(" Thread %-2d %6zd bytes ", record->thin_lock_id, record->byte_count)
-              << PrettyClass(record->type);
+    LOG(INFO) << StringPrintf(" Thread %-2d %6zd bytes ", record->ThinLockId(), record->ByteCount())
+              << PrettyClass(record->Type());
 
     for (size_t stack_frame = 0; stack_frame < kMaxAllocRecordStackDepth; ++stack_frame) {
-      mirror::ArtMethod* m = record->stack[stack_frame].method;
+      AllocRecordStackTraceElement* stack_element = record->StackElement(stack_frame);
+      mirror::ArtMethod* m = stack_element->Method();
       if (m == NULL) {
         break;
       }
-      LOG(INFO) << "    " << PrettyMethod(m) << " line " << record->stack[stack_frame].LineNumber();
+      LOG(INFO) << "    " << PrettyMethod(m) << " line " << stack_element->LineNumber();
     }
 
     // pause periodically to help logcat catch up
@@ -4244,35 +4314,6 @@
   }
 }
 
-void Dbg::UpdateObjectPointers(IsMarkedCallback* callback, void* arg) {
-  if (recent_allocation_records_ != nullptr) {
-    MutexLock mu(Thread::Current(), *alloc_tracker_lock_);
-    size_t i = HeadIndex();
-    size_t count = alloc_record_count_;
-    while (count--) {
-      AllocRecord* record = &recent_allocation_records_[i];
-      DCHECK(record != nullptr);
-      record->UpdateObjectPointers(callback, arg);
-      i = (i + 1) & (alloc_record_max_ - 1);
-    }
-  }
-  if (gRegistry != nullptr) {
-    gRegistry->UpdateObjectPointers(callback, arg);
-  }
-}
-
-void Dbg::AllowNewObjectRegistryObjects() {
-  if (gRegistry != nullptr) {
-    gRegistry->AllowNewObjects();
-  }
-}
-
-void Dbg::DisallowNewObjectRegistryObjects() {
-  if (gRegistry != nullptr) {
-    gRegistry->DisallowNewObjects();
-  }
-}
-
 class StringTable {
  public:
   StringTable() {
@@ -4379,10 +4420,10 @@
     while (count--) {
       AllocRecord* record = &recent_allocation_records_[idx];
 
-      class_names.Add(record->type->GetDescriptor().c_str());
+      class_names.Add(record->Type()->GetDescriptor().c_str());
 
       for (size_t i = 0; i < kMaxAllocRecordStackDepth; i++) {
-        mirror::ArtMethod* m = record->stack[i].method;
+        mirror::ArtMethod* m = record->StackElement(i)->Method();
         if (m != NULL) {
           class_names.Add(m->GetDeclaringClassDescriptor());
           method_names.Add(m->GetName());
@@ -4432,9 +4473,9 @@
       AllocRecord* record = &recent_allocation_records_[idx];
       size_t stack_depth = record->GetDepth();
       size_t allocated_object_class_name_index =
-          class_names.IndexOf(record->type->GetDescriptor().c_str());
-      JDWP::Append4BE(bytes, record->byte_count);
-      JDWP::Append2BE(bytes, record->thin_lock_id);
+          class_names.IndexOf(record->Type()->GetDescriptor().c_str());
+      JDWP::Append4BE(bytes, record->ByteCount());
+      JDWP::Append2BE(bytes, record->ThinLockId());
       JDWP::Append2BE(bytes, allocated_object_class_name_index);
       JDWP::Append1BE(bytes, stack_depth);
 
@@ -4444,14 +4485,14 @@
         // (2b) method name
         // (2b) method source file
         // (2b) line number, clipped to 32767; -2 if native; -1 if no source
-        mirror::ArtMethod* m = record->stack[stack_frame].method;
+        mirror::ArtMethod* m = record->StackElement(stack_frame)->Method();
         size_t class_name_index = class_names.IndexOf(m->GetDeclaringClassDescriptor());
         size_t method_name_index = method_names.IndexOf(m->GetName());
         size_t file_name_index = filenames.IndexOf(GetMethodSourceFile(m));
         JDWP::Append2BE(bytes, class_name_index);
         JDWP::Append2BE(bytes, method_name_index);
         JDWP::Append2BE(bytes, file_name_index);
-        JDWP::Append2BE(bytes, record->stack[stack_frame].LineNumber());
+        JDWP::Append2BE(bytes, record->StackElement(stack_frame)->LineNumber());
       }
 
       idx = (idx + 1) & (alloc_record_max_ - 1);
diff --git a/runtime/debugger.h b/runtime/debugger.h
index 31ffd6e..1cf0b0c 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -41,7 +41,7 @@
 class Object;
 class Throwable;
 }  // namespace mirror
-struct AllocRecord;
+class AllocRecord;
 class Thread;
 class ThrowLocation;
 
@@ -531,11 +531,6 @@
   static size_t HeadIndex() EXCLUSIVE_LOCKS_REQUIRED(alloc_tracker_lock_);
   static void DumpRecentAllocations() LOCKS_EXCLUDED(alloc_tracker_lock_);
 
-  // Updates the stored direct object pointers (called from SweepSystemWeaks).
-  static void UpdateObjectPointers(IsMarkedCallback* callback, void* arg)
-      LOCKS_EXCLUDED(alloc_tracker_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   enum HpifWhen {
     HPIF_WHEN_NEVER = 0,
     HPIF_WHEN_NOW = 1,
@@ -560,9 +555,6 @@
   static void DdmSendHeapSegments(bool native)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static void AllowNewObjectRegistryObjects() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void DisallowNewObjectRegistryObjects() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
  private:
   static void DdmBroadcast(bool connect) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void PostThreadStartOrStop(Thread*, uint32_t)
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 17d1ffc..a27dfad 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -66,6 +66,64 @@
   return true;
 }
 
+const char* DexFileVerifier::CheckLoadStringByIdx(uint32_t idx, const char* error_string) {
+  if (!CheckIndex(idx, dex_file_->NumStringIds(), error_string)) {
+    return nullptr;
+  }
+  return dex_file_->StringDataByIdx(idx);
+}
+
+const char* DexFileVerifier::CheckLoadStringByTypeIdx(uint32_t type_idx, const char* error_string) {
+  if (!CheckIndex(type_idx, dex_file_->NumTypeIds(), error_string)) {
+    return nullptr;
+  }
+  const DexFile::TypeId& type_id = dex_file_->GetTypeId(type_idx);
+  uint32_t idx = type_id.descriptor_idx_;
+  return CheckLoadStringByIdx(idx, error_string);
+}
+
+const DexFile::FieldId* DexFileVerifier::CheckLoadFieldId(uint32_t idx, const char* error_string) {
+  if (!CheckIndex(idx, dex_file_->NumFieldIds(), error_string)) {
+    return nullptr;
+  }
+  return &dex_file_->GetFieldId(idx);
+}
+
+const DexFile::MethodId* DexFileVerifier::CheckLoadMethodId(uint32_t idx, const char* err_string) {
+  if (!CheckIndex(idx, dex_file_->NumMethodIds(), err_string)) {
+    return nullptr;
+  }
+  return &dex_file_->GetMethodId(idx);
+}
+
+// Helper macro to load string and return false on error.
+#define LOAD_STRING(var, idx, error)                  \
+  const char* var = CheckLoadStringByIdx(idx, error); \
+  if (var == nullptr) {                               \
+    return false;                                     \
+  }
+
+// Helper macro to load string by type idx and return false on error.
+#define LOAD_STRING_BY_TYPE(var, type_idx, error)              \
+  const char* var = CheckLoadStringByTypeIdx(type_idx, error); \
+  if (var == nullptr) {                                        \
+    return false;                                              \
+  }
+
+// Helper macro to load method id. Return last parameter on error.
+#define LOAD_METHOD(var, idx, error_string, error_val)                  \
+  const DexFile::MethodId* var  = CheckLoadMethodId(idx, error_string); \
+  if (var == nullptr) {                                                 \
+    return error_val;                                                   \
+  }
+
+// Helper macro to load method id. Return last parameter on error.
+#define LOAD_FIELD(var, idx, fmt, error_val)                \
+  const DexFile::FieldId* var = CheckLoadFieldId(idx, fmt); \
+  if (var == nullptr) {                                     \
+    return error_val;                                       \
+  }
+
 bool DexFileVerifier::Verify(const DexFile* dex_file, const byte* begin, size_t size,
                              const char* location, std::string* error_msg) {
   std::unique_ptr<DexFileVerifier> verifier(new DexFileVerifier(dex_file, begin, size, location));
@@ -120,7 +178,8 @@
   if (UNLIKELY((range_start < file_start) || (range_start > file_end) ||
                (range_end < file_start) || (range_end > file_end))) {
     ErrorStringPrintf("Bad range for %s: %zx to %zx", label,
-                      range_start - file_start, range_end - file_start);
+                      static_cast<size_t>(range_start - file_start),
+                      static_cast<size_t>(range_end - file_start));
     return false;
   }
   return true;
@@ -1319,41 +1378,43 @@
   return true;
 }
 
-uint16_t DexFileVerifier::FindFirstClassDataDefiner(const byte* ptr) const {
+uint32_t DexFileVerifier::FindFirstClassDataDefiner(const byte* ptr) {
   ClassDataItemIterator it(*dex_file_, ptr);
 
   if (it.HasNextStaticField() || it.HasNextInstanceField()) {
-    const DexFile::FieldId& field = dex_file_->GetFieldId(it.GetMemberIndex());
-    return field.class_idx_;
+    LOAD_FIELD(field, it.GetMemberIndex(), "first_class_data_definer field_id", 0x10000U)
+    return field->class_idx_;
   }
 
   if (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
-    const DexFile::MethodId& method = dex_file_->GetMethodId(it.GetMemberIndex());
-    return method.class_idx_;
+    LOAD_METHOD(method, it.GetMemberIndex(), "first_class_data_definer method_id", 0x10000U)
+    return method->class_idx_;
   }
 
   return DexFile::kDexNoIndex16;
 }
 
-uint16_t DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const byte* ptr) const {
+uint32_t DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const byte* ptr) {
   const DexFile::AnnotationsDirectoryItem* item =
       reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr);
   if (item->fields_size_ != 0) {
     DexFile::FieldAnnotationsItem* field_items = (DexFile::FieldAnnotationsItem*) (item + 1);
-    const DexFile::FieldId& field = dex_file_->GetFieldId(field_items[0].field_idx_);
-    return field.class_idx_;
+    LOAD_FIELD(field, field_items[0].field_idx_, "first_annotations_dir_definer field_id", 0x10000U)
+    return field->class_idx_;
   }
 
   if (item->methods_size_ != 0) {
     DexFile::MethodAnnotationsItem* method_items = (DexFile::MethodAnnotationsItem*) (item + 1);
-    const DexFile::MethodId& method = dex_file_->GetMethodId(method_items[0].method_idx_);
-    return method.class_idx_;
+    LOAD_METHOD(method, method_items[0].method_idx_, "first_annotations_dir_definer method id",
+                0x10000U)
+    return method->class_idx_;
   }
 
   if (item->parameters_size_ != 0) {
     DexFile::ParameterAnnotationsItem* parameter_items = (DexFile::ParameterAnnotationsItem*) (item + 1);
-    const DexFile::MethodId& method = dex_file_->GetMethodId(parameter_items[0].method_idx_);
-    return method.class_idx_;
+    LOAD_METHOD(method, parameter_items[0].method_idx_, "first_annotations_dir_definer method id",
+                0x10000U)
+    return method->class_idx_;
   }
 
   return DexFile::kDexNoIndex16;
@@ -1384,7 +1445,8 @@
 
 bool DexFileVerifier::CheckInterTypeIdItem() {
   const DexFile::TypeId* item = reinterpret_cast<const DexFile::TypeId*>(ptr_);
-  const char* descriptor = dex_file_->StringDataByIdx(item->descriptor_idx_);
+
+  LOAD_STRING(descriptor, item->descriptor_idx_, "inter_type_id_item descriptor_idx")
 
   // Check that the descriptor is a valid type.
   if (UNLIKELY(!IsValidDescriptor(descriptor))) {
@@ -1408,14 +1470,17 @@
 
 bool DexFileVerifier::CheckInterProtoIdItem() {
   const DexFile::ProtoId* item = reinterpret_cast<const DexFile::ProtoId*>(ptr_);
-  const char* shorty = dex_file_->StringDataByIdx(item->shorty_idx_);
+
+  LOAD_STRING(shorty, item->shorty_idx_, "inter_proto_id_item shorty_idx")
+
   if (item->parameters_off_ != 0 &&
       !CheckOffsetToTypeMap(item->parameters_off_, DexFile::kDexTypeTypeList)) {
     return false;
   }
 
   // Check the return type and advance the shorty.
-  if (!CheckShortyDescriptorMatch(*shorty, dex_file_->StringByTypeIdx(item->return_type_idx_), true)) {
+  LOAD_STRING_BY_TYPE(return_type, item->return_type_idx_, "inter_proto_id_item return_type_idx")
+  if (!CheckShortyDescriptorMatch(*shorty, return_type, true)) {
     return false;
   }
   shorty++;
@@ -1476,21 +1541,21 @@
   const DexFile::FieldId* item = reinterpret_cast<const DexFile::FieldId*>(ptr_);
 
   // Check that the class descriptor is valid.
-  const char* descriptor = dex_file_->StringByTypeIdx(item->class_idx_);
-  if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) {
-    ErrorStringPrintf("Invalid descriptor for class_idx: '%s'", descriptor);
+  LOAD_STRING_BY_TYPE(class_descriptor, item->class_idx_, "inter_field_id_item class_idx")
+  if (UNLIKELY(!IsValidDescriptor(class_descriptor) || class_descriptor[0] != 'L')) {
+    ErrorStringPrintf("Invalid descriptor for class_idx: '%s'", class_descriptor);
     return false;
   }
 
   // Check that the type descriptor is a valid field name.
-  descriptor = dex_file_->StringByTypeIdx(item->type_idx_);
-  if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] == 'V')) {
-    ErrorStringPrintf("Invalid descriptor for type_idx: '%s'", descriptor);
+  LOAD_STRING_BY_TYPE(type_descriptor, item->type_idx_, "inter_field_id_item type_idx")
+  if (UNLIKELY(!IsValidDescriptor(type_descriptor) || type_descriptor[0] == 'V')) {
+    ErrorStringPrintf("Invalid descriptor for type_idx: '%s'", type_descriptor);
     return false;
   }
 
   // Check that the name is valid.
-  descriptor = dex_file_->StringDataByIdx(item->name_idx_);
+  LOAD_STRING(descriptor, item->name_idx_, "inter_field_id_item name_idx")
   if (UNLIKELY(!IsValidMemberName(descriptor))) {
     ErrorStringPrintf("Invalid field name: '%s'", descriptor);
     return false;
@@ -1523,14 +1588,15 @@
   const DexFile::MethodId* item = reinterpret_cast<const DexFile::MethodId*>(ptr_);
 
   // Check that the class descriptor is a valid reference name.
-  const char* descriptor = dex_file_->StringByTypeIdx(item->class_idx_);
-  if (UNLIKELY(!IsValidDescriptor(descriptor) || (descriptor[0] != 'L' && descriptor[0] != '['))) {
-    ErrorStringPrintf("Invalid descriptor for class_idx: '%s'", descriptor);
+  LOAD_STRING_BY_TYPE(class_descriptor, item->class_idx_, "inter_method_id_item class_idx")
+  if (UNLIKELY(!IsValidDescriptor(class_descriptor) || (class_descriptor[0] != 'L' &&
+                                                        class_descriptor[0] != '['))) {
+    ErrorStringPrintf("Invalid descriptor for class_idx: '%s'", class_descriptor);
     return false;
   }
 
   // Check that the name is valid.
-  descriptor = dex_file_->StringDataByIdx(item->name_idx_);
+  LOAD_STRING(descriptor, item->name_idx_, "inter_method_id_item class_idx")
   if (UNLIKELY(!IsValidMemberName(descriptor))) {
     ErrorStringPrintf("Invalid method name: '%s'", descriptor);
     return false;
@@ -1561,11 +1627,10 @@
 
 bool DexFileVerifier::CheckInterClassDefItem() {
   const DexFile::ClassDef* item = reinterpret_cast<const DexFile::ClassDef*>(ptr_);
-  uint32_t class_idx = item->class_idx_;
-  const char* descriptor = dex_file_->StringByTypeIdx(class_idx);
 
-  if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) {
-    ErrorStringPrintf("Invalid class descriptor: '%s'", descriptor);
+  LOAD_STRING_BY_TYPE(class_descriptor, item->class_idx_, "inter_class_def_item class_idx")
+  if (UNLIKELY(!IsValidDescriptor(class_descriptor) || class_descriptor[0] != 'L')) {
+    ErrorStringPrintf("Invalid class descriptor: '%s'", class_descriptor);
     return false;
   }
 
@@ -1587,9 +1652,10 @@
   }
 
   if (item->superclass_idx_ != DexFile::kDexNoIndex16) {
-    descriptor = dex_file_->StringByTypeIdx(item->superclass_idx_);
-    if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) {
-      ErrorStringPrintf("Invalid superclass: '%s'", descriptor);
+    LOAD_STRING_BY_TYPE(superclass_descriptor, item->superclass_idx_,
+                        "inter_class_def_item superclass_idx")
+    if (UNLIKELY(!IsValidDescriptor(superclass_descriptor) || superclass_descriptor[0] != 'L')) {
+      ErrorStringPrintf("Invalid superclass: '%s'", superclass_descriptor);
       return false;
     }
   }
@@ -1600,9 +1666,10 @@
 
     // Ensure that all interfaces refer to classes (not arrays or primitives).
     for (uint32_t i = 0; i < size; i++) {
-      descriptor = dex_file_->StringByTypeIdx(interfaces->GetTypeItem(i).type_idx_);
-      if (UNLIKELY(!IsValidDescriptor(descriptor) || descriptor[0] != 'L')) {
-        ErrorStringPrintf("Invalid interface: '%s'", descriptor);
+      LOAD_STRING_BY_TYPE(inf_descriptor, interfaces->GetTypeItem(i).type_idx_,
+                          "inter_class_def_item interface type_idx")
+      if (UNLIKELY(!IsValidDescriptor(inf_descriptor) || inf_descriptor[0] != 'L')) {
+        ErrorStringPrintf("Invalid interface: '%s'", inf_descriptor);
         return false;
       }
     }
@@ -1626,7 +1693,10 @@
   // Check that references in class_data_item are to the right class.
   if (item->class_data_off_ != 0) {
     const byte* data = begin_ + item->class_data_off_;
-    uint16_t data_definer = FindFirstClassDataDefiner(data);
+    uint32_t data_definer = FindFirstClassDataDefiner(data);
+    if (data_definer >= 0x10000U) {
+      return false;
+    }
     if (UNLIKELY((data_definer != item->class_idx_) && (data_definer != DexFile::kDexNoIndex16))) {
       ErrorStringPrintf("Invalid class_data_item");
       return false;
@@ -1636,7 +1706,10 @@
   // Check that references in annotations_directory_item are to right class.
   if (item->annotations_off_ != 0) {
     const byte* data = begin_ + item->annotations_off_;
-    uint16_t annotations_definer = FindFirstAnnotationsDirectoryDefiner(data);
+    uint32_t annotations_definer = FindFirstAnnotationsDirectoryDefiner(data);
+    if (annotations_definer >= 0x10000U) {
+      return false;
+    }
     if (UNLIKELY((annotations_definer != item->class_idx_) &&
                  (annotations_definer != DexFile::kDexNoIndex16))) {
       ErrorStringPrintf("Invalid annotations_directory_item");
@@ -1698,11 +1771,14 @@
 
 bool DexFileVerifier::CheckInterClassDataItem() {
   ClassDataItemIterator it(*dex_file_, ptr_);
-  uint16_t defining_class = FindFirstClassDataDefiner(ptr_);
+  uint32_t defining_class = FindFirstClassDataDefiner(ptr_);
+  if (defining_class >= 0x10000U) {
+    return false;
+  }
 
   for (; it.HasNextStaticField() || it.HasNextInstanceField(); it.Next()) {
-    const DexFile::FieldId& field = dex_file_->GetFieldId(it.GetMemberIndex());
-    if (UNLIKELY(field.class_idx_ != defining_class)) {
+    LOAD_FIELD(field, it.GetMemberIndex(), "inter_class_data_item field_id", false)
+    if (UNLIKELY(field->class_idx_ != defining_class)) {
       ErrorStringPrintf("Mismatched defining class for class_data_item field");
       return false;
     }
@@ -1712,8 +1788,8 @@
     if (code_off != 0 && !CheckOffsetToTypeMap(code_off, DexFile::kDexTypeCodeItem)) {
       return false;
     }
-    const DexFile::MethodId& method = dex_file_->GetMethodId(it.GetMemberIndex());
-    if (UNLIKELY(method.class_idx_ != defining_class)) {
+    LOAD_METHOD(method, it.GetMemberIndex(), "inter_class_data_item method_id", false)
+    if (UNLIKELY(method->class_idx_ != defining_class)) {
       ErrorStringPrintf("Mismatched defining class for class_data_item method");
       return false;
     }
@@ -1726,7 +1802,10 @@
 bool DexFileVerifier::CheckInterAnnotationsDirectoryItem() {
   const DexFile::AnnotationsDirectoryItem* item =
       reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr_);
-  uint16_t defining_class = FindFirstAnnotationsDirectoryDefiner(ptr_);
+  uint32_t defining_class = FindFirstAnnotationsDirectoryDefiner(ptr_);
+  if (defining_class >= 0x10000U) {
+    return false;
+  }
 
   if (item->class_annotations_off_ != 0 &&
       !CheckOffsetToTypeMap(item->class_annotations_off_, DexFile::kDexTypeAnnotationSetItem)) {
@@ -1738,8 +1817,8 @@
       reinterpret_cast<const DexFile::FieldAnnotationsItem*>(item + 1);
   uint32_t field_count = item->fields_size_;
   for (uint32_t i = 0; i < field_count; i++) {
-    const DexFile::FieldId& field = dex_file_->GetFieldId(field_item->field_idx_);
-    if (UNLIKELY(field.class_idx_ != defining_class)) {
+    LOAD_FIELD(field, field_item->field_idx_, "inter_annotations_directory_item field_id", false)
+    if (UNLIKELY(field->class_idx_ != defining_class)) {
       ErrorStringPrintf("Mismatched defining class for field_annotation");
       return false;
     }
@@ -1754,8 +1833,9 @@
       reinterpret_cast<const DexFile::MethodAnnotationsItem*>(field_item);
   uint32_t method_count = item->methods_size_;
   for (uint32_t i = 0; i < method_count; i++) {
-    const DexFile::MethodId& method = dex_file_->GetMethodId(method_item->method_idx_);
-    if (UNLIKELY(method.class_idx_ != defining_class)) {
+    LOAD_METHOD(method, method_item->method_idx_, "inter_annotations_directory_item method_id",
+                false)
+    if (UNLIKELY(method->class_idx_ != defining_class)) {
       ErrorStringPrintf("Mismatched defining class for method_annotation");
       return false;
     }
@@ -1770,8 +1850,9 @@
       reinterpret_cast<const DexFile::ParameterAnnotationsItem*>(method_item);
   uint32_t parameter_count = item->parameters_size_;
   for (uint32_t i = 0; i < parameter_count; i++) {
-    const DexFile::MethodId& parameter_method = dex_file_->GetMethodId(parameter_item->method_idx_);
-    if (UNLIKELY(parameter_method.class_idx_ != defining_class)) {
+    LOAD_METHOD(parameter_method, parameter_item->method_idx_,
+                "inter_annotations_directory_item parameter method_id", false)
+    if (UNLIKELY(parameter_method->class_idx_ != defining_class)) {
       ErrorStringPrintf("Mismatched defining class for parameter_annotation");
       return false;
     }
diff --git a/runtime/dex_file_verifier.h b/runtime/dex_file_verifier.h
index 3337785..7489dcd 100644
--- a/runtime/dex_file_verifier.h
+++ b/runtime/dex_file_verifier.h
@@ -71,8 +71,11 @@
   bool CheckIntraSection();
 
   bool CheckOffsetToTypeMap(size_t offset, uint16_t type);
-  uint16_t FindFirstClassDataDefiner(const byte* ptr) const;
-  uint16_t FindFirstAnnotationsDirectoryDefiner(const byte* ptr) const;
+
+  // Note: the result type of the following methods is wider than that of the underlying index
+  // (16b vs 32b). This is so that we can define an error value (anything >= 2^16).
+  uint32_t FindFirstClassDataDefiner(const byte* ptr);
+  uint32_t FindFirstAnnotationsDirectoryDefiner(const byte* ptr);
 
   bool CheckInterStringIdItem();
   bool CheckInterTypeIdItem();
@@ -88,6 +91,16 @@
   bool CheckInterSectionIterate(size_t offset, uint32_t count, uint16_t type);
   bool CheckInterSection();
 
+  // Load a string by (type) index. Checks whether the index is in bounds, printing the error if
+  // not. If there is an error, nullptr is returned.
+  const char* CheckLoadStringByIdx(uint32_t idx, const char* error_fmt);
+  const char* CheckLoadStringByTypeIdx(uint32_t type_idx, const char* error_fmt);
+
+  // Load a field/method Id by index. Checks whether the index is in bounds, printing the error if
+  // not. If there is an error, nullptr is returned.
+  const DexFile::FieldId* CheckLoadFieldId(uint32_t idx, const char* error_fmt);
+  const DexFile::MethodId* CheckLoadMethodId(uint32_t idx, const char* error_fmt);
+
   void ErrorStringPrintf(const char* fmt, ...)
       __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR;
 
diff --git a/runtime/elf_utils.h b/runtime/elf_utils.h
index f3ec713..ce8587b 100644
--- a/runtime/elf_utils.h
+++ b/runtime/elf_utils.h
@@ -17,9 +17,10 @@
 #ifndef ART_RUNTIME_ELF_UTILS_H_
 #define ART_RUNTIME_ELF_UTILS_H_
 
-// Include the micro-API to avoid potential macro conflicts with the
-// compiler's own elf.h file.
-#include "../../bionic/libc/kernel/uapi/linux/elf.h"
+#include <sys/cdefs.h>
+
+// Explicitly include elf.h from elfutils to avoid Linux and other dependencies.
+#include "../../external/elfutils/0.153/libelf/elf.h"
 
 // Architecture dependent flags for the ELF header.
 #define EF_ARM_EABI_VER5 0x05000000
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 6b216c7..3112bc0 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -67,7 +67,7 @@
   action.sa_sigaction = art_fault_handler;
   sigemptyset(&action.sa_mask);
   action.sa_flags = SA_SIGINFO | SA_ONSTACK;
-#if !defined(__mips__)
+#if !defined(__APPLE__) && !defined(__mips__)
   action.sa_restorer = nullptr;
 #endif
 
diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h
index bd04473..2c72ba1 100644
--- a/runtime/gc/accounting/atomic_stack.h
+++ b/runtime/gc/accounting/atomic_stack.h
@@ -49,10 +49,7 @@
     front_index_.StoreRelaxed(0);
     back_index_.StoreRelaxed(0);
     debug_is_sorted_ = true;
-    int result = madvise(begin_, sizeof(T) * capacity_, MADV_DONTNEED);
-    if (result == -1) {
-      PLOG(WARNING) << "madvise failed";
-    }
+    mem_map_->MadviseDontNeedAndZero();
   }
 
   // Beware: Mixing atomic pushes and atomic pops will cause ABA problem.
diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc
index 43a173e..a95c003 100644
--- a/runtime/gc/accounting/card_table.cc
+++ b/runtime/gc/accounting/card_table.cc
@@ -96,7 +96,7 @@
 
 void CardTable::ClearCardTable() {
   COMPILE_ASSERT(kCardClean == 0, clean_card_must_be_0);
-  madvise(mem_map_->Begin(), mem_map_->Size(), MADV_DONTNEED);
+  mem_map_->MadviseDontNeedAndZero();
 }
 
 bool CardTable::AddrIsInCardTable(const void* addr) const {
diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc
index c294bae..224b33e 100644
--- a/runtime/gc/accounting/space_bitmap.cc
+++ b/runtime/gc/accounting/space_bitmap.cc
@@ -79,12 +79,8 @@
 
 template<size_t kAlignment>
 void SpaceBitmap<kAlignment>::Clear() {
-  if (bitmap_begin_ != NULL) {
-    // This returns the memory to the system.  Successive page faults will return zeroed memory.
-    int result = madvise(bitmap_begin_, bitmap_size_, MADV_DONTNEED);
-    if (result == -1) {
-      PLOG(FATAL) << "madvise failed";
-    }
+  if (bitmap_begin_ != nullptr) {
+    mem_map_->MadviseDontNeedAndZero();
   }
 }
 
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index 10b88b3..55262f2 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -1507,6 +1507,9 @@
     if (madvise_size > 0) {
       DCHECK_ALIGNED(madvise_begin, kPageSize);
       DCHECK_EQ(RoundUp(madvise_size, kPageSize), madvise_size);
+      if (!kMadviseZeroes) {
+        memset(madvise_begin, 0, madvise_size);
+      }
       CHECK_EQ(madvise(madvise_begin, madvise_size, MADV_DONTNEED), 0);
     }
     if (madvise_begin - zero_begin) {
@@ -2117,6 +2120,9 @@
           start = reinterpret_cast<byte*>(fpr) + kPageSize;
         }
         byte* end = reinterpret_cast<byte*>(fpr) + fpr_size;
+        if (!kMadviseZeroes) {
+          memset(start, 0, end - start);
+        }
         CHECK_EQ(madvise(start, end - start, MADV_DONTNEED), 0);
         reclaimed_bytes += fpr_size;
         size_t num_pages = fpr_size / kPageSize;
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 9464331..a439188 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -110,11 +110,17 @@
         byte_size -= kPageSize;
         if (byte_size > 0) {
           if (release_pages) {
+            if (!kMadviseZeroes) {
+              memset(start, 0, byte_size);
+            }
             madvise(start, byte_size, MADV_DONTNEED);
           }
         }
       } else {
         if (release_pages) {
+          if (!kMadviseZeroes) {
+            memset(start, 0, byte_size);
+          }
           madvise(start, byte_size, MADV_DONTNEED);
         }
       }
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index c062706..890036b 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -1130,9 +1130,7 @@
   allocations->Reset();
   timings_.EndSplit();
 
-  int success = madvise(sweep_array_free_buffer_mem_map_->BaseBegin(),
-                        sweep_array_free_buffer_mem_map_->BaseSize(), MADV_DONTNEED);
-  DCHECK_EQ(success, 0) << "Failed to madvise the sweep array free buffer pages.";
+  sweep_array_free_buffer_mem_map_->MadviseDontNeedAndZero();
 }
 
 void MarkSweep::Sweep(bool swap_bitmaps) {
diff --git a/runtime/gc/space/bump_pointer_space.cc b/runtime/gc/space/bump_pointer_space.cc
index fd0a92d..8b35692 100644
--- a/runtime/gc/space/bump_pointer_space.cc
+++ b/runtime/gc/space/bump_pointer_space.cc
@@ -64,6 +64,9 @@
 
 void BumpPointerSpace::Clear() {
   // Release the pages back to the operating system.
+  if (!kMadviseZeroes) {
+    memset(Begin(), 0, Limit() - Begin());
+  }
   CHECK_NE(madvise(Begin(), Limit() - Begin(), MADV_DONTNEED), -1) << "madvise failed";
   // Reset the end of the space back to the beginning, we move the end forward as we allocate
   // objects.
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index d18f9f9..5277330 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -38,6 +38,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
+#include "mirror/string-inl.h"
 #include "object_utils.h"
 #include "ScopedLocalRef.h"
 #include "scoped_thread_state_change.h"
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index 49dceb2..d637a94 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -31,8 +31,7 @@
 }
 
 ObjectRegistry::ObjectRegistry()
-    : lock_("ObjectRegistry lock", kJdwpObjectRegistryLock), allow_new_objects_(true),
-      condition_("object registry condition", lock_), next_id_(1) {
+    : lock_("ObjectRegistry lock", kJdwpObjectRegistryLock), next_id_(1) {
 }
 
 JDWP::RefTypeId ObjectRegistry::AddRefType(mirror::Class* c) {
@@ -44,20 +43,17 @@
 }
 
 JDWP::ObjectId ObjectRegistry::InternalAdd(mirror::Object* o) {
-  if (o == NULL) {
+  if (o == nullptr) {
     return 0;
   }
 
+  // Call IdentityHashCode here to avoid a lock level violation between lock_ and monitor_lock.
+  int32_t identity_hash_code = o->IdentityHashCode();
   ScopedObjectAccessUnchecked soa(Thread::Current());
   MutexLock mu(soa.Self(), lock_);
-  while (UNLIKELY(!allow_new_objects_)) {
-    condition_.WaitHoldingLocks(soa.Self());
-  }
-  ObjectRegistryEntry* entry;
-  auto it = object_to_entry_.find(o);
-  if (it != object_to_entry_.end()) {
+  ObjectRegistryEntry* entry = nullptr;
+  if (ContainsLocked(soa.Self(), o, identity_hash_code, &entry)) {
     // This object was already in our map.
-    entry = it->second;
     ++entry->reference_count;
   } else {
     entry = new ObjectRegistryEntry;
@@ -65,7 +61,8 @@
     entry->jni_reference = nullptr;
     entry->reference_count = 0;
     entry->id = 0;
-    object_to_entry_.insert(std::make_pair(o, entry));
+    entry->identity_hash_code = identity_hash_code;
+    object_to_entry_.insert(std::make_pair(identity_hash_code, entry));
 
     // This object isn't in the registry yet, so add it.
     JNIEnv* env = soa.Env();
@@ -84,9 +81,31 @@
   return entry->id;
 }
 
-bool ObjectRegistry::Contains(mirror::Object* o) {
-  MutexLock mu(Thread::Current(), lock_);
-  return object_to_entry_.find(o) != object_to_entry_.end();
+bool ObjectRegistry::Contains(mirror::Object* o, ObjectRegistryEntry** out_entry) {
+  if (o == nullptr) {
+    return false;
+  }
+  // Call IdentityHashCode here to avoid a lock level violation between lock_ and monitor_lock.
+  int32_t identity_hash_code = o->IdentityHashCode();
+  Thread* self = Thread::Current();
+  MutexLock mu(self, lock_);
+  return ContainsLocked(self, o, identity_hash_code, out_entry);
+}
+
+bool ObjectRegistry::ContainsLocked(Thread* self, mirror::Object* o, int32_t identity_hash_code,
+                                    ObjectRegistryEntry** out_entry) {
+  DCHECK(o != nullptr);
+  for (auto it = object_to_entry_.lower_bound(identity_hash_code), end = object_to_entry_.end();
+       it != end && it->first == identity_hash_code; ++it) {
+    ObjectRegistryEntry* entry = it->second;
+    if (o == self->DecodeJObject(entry->jni_reference)) {
+      if (out_entry != nullptr) {
+        *out_entry = entry;
+      }
+      return true;
+    }
+  }
+  return false;
 }
 
 void ObjectRegistry::Clear() {
@@ -194,47 +213,24 @@
   entry->reference_count -= reference_count;
   if (entry->reference_count <= 0) {
     JNIEnv* env = self->GetJniEnv();
-    mirror::Object* object = self->DecodeJObject(entry->jni_reference);
+    // Erase the object from the maps. Note object may be null if it's
+    // a weak ref and the GC has cleared it.
+    int32_t hash_code = entry->identity_hash_code;
+    for (auto it = object_to_entry_.lower_bound(hash_code), end = object_to_entry_.end();
+         it != end && it->first == hash_code; ++it) {
+      if (entry == it->second) {
+        object_to_entry_.erase(it);
+        break;
+      }
+    }
     if (entry->jni_reference_type == JNIWeakGlobalRefType) {
       env->DeleteWeakGlobalRef(entry->jni_reference);
     } else {
       env->DeleteGlobalRef(entry->jni_reference);
     }
-    object_to_entry_.erase(object);
     id_to_entry_.erase(id);
     delete entry;
   }
 }
 
-void ObjectRegistry::UpdateObjectPointers(IsMarkedCallback* callback, void* arg) {
-  MutexLock mu(Thread::Current(), lock_);
-  if (object_to_entry_.empty()) {
-    return;
-  }
-  std::map<mirror::Object*, ObjectRegistryEntry*> new_object_to_entry;
-  for (auto& pair : object_to_entry_) {
-    mirror::Object* new_obj;
-    if (pair.first != nullptr) {
-      new_obj = callback(pair.first, arg);
-      if (new_obj != nullptr) {
-        new_object_to_entry.insert(std::make_pair(new_obj, pair.second));
-      }
-    }
-  }
-  object_to_entry_ = new_object_to_entry;
-}
-
-void ObjectRegistry::AllowNewObjects() {
-  Thread* self = Thread::Current();
-  MutexLock mu(self, lock_);
-  allow_new_objects_ = true;
-  condition_.Broadcast(self);
-}
-
-void ObjectRegistry::DisallowNewObjects() {
-  Thread* self = Thread::Current();
-  MutexLock mu(self, lock_);
-  allow_new_objects_ = false;
-}
-
 }  // namespace art
diff --git a/runtime/jdwp/object_registry.h b/runtime/jdwp/object_registry.h
index 3c6cb15..e1a6875 100644
--- a/runtime/jdwp/object_registry.h
+++ b/runtime/jdwp/object_registry.h
@@ -43,6 +43,10 @@
 
   // The corresponding id, so we only need one map lookup in Add.
   JDWP::ObjectId id;
+
+  // The identity hash code of the object. This is the same as the key
+  // for object_to_entry_. Store this for DisposeObject().
+  int32_t identity_hash_code;
 };
 std::ostream& operator<<(std::ostream& os, const ObjectRegistryEntry& rhs);
 
@@ -55,7 +59,8 @@
  public:
   ObjectRegistry();
 
-  JDWP::ObjectId Add(mirror::Object* o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  JDWP::ObjectId Add(mirror::Object* o)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_);
   JDWP::RefTypeId AddRefType(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<typename T> T Get(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -65,7 +70,9 @@
     return reinterpret_cast<T>(InternalGet(id));
   }
 
-  bool Contains(mirror::Object* o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool Contains(mirror::Object* o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return Contains(o, nullptr);
+  }
 
   void Clear() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -84,26 +91,20 @@
   // Avoid using this and use standard Get when possible.
   jobject GetJObject(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Visit, objects are treated as system weaks.
-  void UpdateObjectPointers(IsMarkedCallback* callback, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // We have allow / disallow functionality since we use system weak sweeping logic to update moved
-  // objects inside of the object_to_entry_ map.
-  void AllowNewObjects() LOCKS_EXCLUDED(lock_);
-  void DisallowNewObjects() LOCKS_EXCLUDED(lock_);
-
  private:
-  JDWP::ObjectId InternalAdd(mirror::Object* o) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  JDWP::ObjectId InternalAdd(mirror::Object* o)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_);
   mirror::Object* InternalGet(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void Demote(ObjectRegistryEntry& entry) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, lock_);
   void Promote(ObjectRegistryEntry& entry) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, lock_);
+  bool Contains(mirror::Object* o, ObjectRegistryEntry** out_entry)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool ContainsLocked(Thread* self, mirror::Object* o, int32_t identity_hash_code,
+                      ObjectRegistryEntry** out_entry)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-  bool allow_new_objects_ GUARDED_BY(lock_);
-  ConditionVariable condition_ GUARDED_BY(lock_);
-
-  std::map<mirror::Object*, ObjectRegistryEntry*> object_to_entry_ GUARDED_BY(lock_);
+  std::multimap<int32_t, ObjectRegistryEntry*> object_to_entry_ GUARDED_BY(lock_);
   SafeMap<JDWP::ObjectId, ObjectRegistryEntry*> id_to_entry_ GUARDED_BY(lock_);
 
   size_t next_id_ GUARDED_BY(lock_);
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 22a61a2..81a8623 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -473,6 +473,18 @@
   return new MemMap(tail_name, actual, tail_size, actual, tail_base_size, tail_prot);
 }
 
+void MemMap::MadviseDontNeedAndZero() {
+  if (base_begin_ != nullptr || base_size_ != 0) {
+    if (!kMadviseZeroes) {
+      memset(base_begin_, 0, base_size_);
+    }
+    int result = madvise(base_begin_, base_size_, MADV_DONTNEED);
+    if (result == -1) {
+      PLOG(WARNING) << "madvise failed";
+    }
+  }
+}
+
 bool MemMap::Protect(int prot) {
   if (base_begin_ == nullptr && base_size_ == 0) {
     prot_ = prot;
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index dc5909b..e42251c 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -30,6 +30,12 @@
 
 namespace art {
 
+#ifdef __linux__
+static constexpr bool kMadviseZeroes = true;
+#else
+static constexpr bool kMadviseZeroes = false;
+#endif
+
 // Used to keep track of mmap segments.
 //
 // On 64b systems not supporting MAP_32BIT, the implementation of MemMap will do a linear scan
@@ -77,6 +83,8 @@
 
   bool Protect(int prot);
 
+  void MadviseDontNeedAndZero();
+
   int GetProtect() const {
     return prot_;
   }
diff --git a/runtime/mem_map_test.cc b/runtime/mem_map_test.cc
index fe76c92..69f618c 100644
--- a/runtime/mem_map_test.cc
+++ b/runtime/mem_map_test.cc
@@ -198,16 +198,17 @@
 #endif
 
 TEST_F(MemMapTest, MapAnonymousExactAddr32bitHighAddr) {
+  uintptr_t start_addr = ART_BASE_ADDRESS + 0x1000000;
   std::string error_msg;
   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousExactAddr32bitHighAddr",
-                                             reinterpret_cast<byte*>(0x71000000),
+                                             reinterpret_cast<byte*>(start_addr),
                                              0x21000000,
                                              PROT_READ | PROT_WRITE,
                                              true,
                                              &error_msg));
   ASSERT_TRUE(map.get() != nullptr) << error_msg;
   ASSERT_TRUE(error_msg.empty());
-  ASSERT_EQ(reinterpret_cast<uintptr_t>(BaseBegin(map.get())), 0x71000000U);
+  ASSERT_EQ(reinterpret_cast<uintptr_t>(BaseBegin(map.get())), start_addr);
 }
 
 TEST_F(MemMapTest, MapAnonymousOverflow) {
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 2c24e33..7e3810c 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -17,7 +17,11 @@
 #include <algorithm>
 #include <set>
 #include <fcntl.h>
+#ifdef __linux__
 #include <sys/sendfile.h>
+#else
+#include <sys/socket.h>
+#endif
 #include <sys/stat.h>
 #include <unistd.h>
 
@@ -241,7 +245,12 @@
     return;
   }
 
+#ifdef __linux__
   if (sendfile(dst.get(), src.get(), nullptr, stat_src.st_size) == -1) {
+#else
+  off_t len;
+  if (sendfile(dst.get(), src.get(), 0, &len, nullptr, 0) == -1) {
+#endif
     PLOG(ERROR) << "Failed to copy profile file " << oldfile << " to " << newfile
       << ". My uid:gid is " << getuid() << ":" << getgid();
   }
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 7490e6a..820bd04 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -32,9 +32,11 @@
 static void EnableDebugger() {
   // To let a non-privileged gdbserver attach to this
   // process, we must set our dumpable flag.
+#if defined(HAVE_PRCTL)
   if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
     PLOG(ERROR) << "prctl(PR_SET_DUMPABLE) failed for pid " << getpid();
   }
+#endif
   // We don't want core dumps, though, so set the core dump size to 0.
   rlimit rl;
   rl.rlim_cur = 0;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 89058c8..ccf478c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -18,7 +18,9 @@
 
 // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
 #include <sys/mount.h>
+#ifdef __linux__
 #include <linux/fs.h>
+#endif
 
 #include <signal.h>
 #include <sys/syscall.h>
@@ -307,7 +309,6 @@
   GetInternTable()->SweepInternTableWeaks(visitor, arg);
   GetMonitorList()->SweepMonitorList(visitor, arg);
   GetJavaVM()->SweepJniWeakGlobals(visitor, arg);
-  Dbg::UpdateObjectPointers(visitor, arg);
 }
 
 bool Runtime::Create(const Options& options, bool ignore_unrecognized) {
@@ -437,6 +438,7 @@
 
 // Do zygote-mode-only initialization.
 bool Runtime::InitZygote() {
+#ifdef __linux__
   // zygote goes into its own process group
   setpgid(0, 0);
 
@@ -467,6 +469,10 @@
   }
 
   return true;
+#else
+  UNIMPLEMENTED(FATAL);
+  return false;
+#endif
 }
 
 void Runtime::DidForkFromZygote() {
@@ -1036,14 +1042,12 @@
   monitor_list_->DisallowNewMonitors();
   intern_table_->DisallowNewInterns();
   java_vm_->DisallowNewWeakGlobals();
-  Dbg::DisallowNewObjectRegistryObjects();
 }
 
 void Runtime::AllowNewSystemWeaks() {
   monitor_list_->AllowNewMonitors();
   intern_table_->AllowNewInterns();
   java_vm_->AllowNewWeakGlobals();
-  Dbg::AllowNewObjectRegistryObjects();
 }
 
 void Runtime::SetInstructionSet(InstructionSet instruction_set) {
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index 960d332..46ee274 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -327,7 +327,7 @@
     while (true) {
     }
   }
-
+#ifdef __linux__
   // Remove our signal handler for this signal...
   struct sigaction action;
   memset(&action, 0, sizeof(action));
@@ -336,6 +336,9 @@
   sigaction(signal_number, &action, NULL);
   // ...and re-raise so we die with the appropriate status.
   kill(getpid(), signal_number);
+#else
+  exit(EXIT_FAILURE);
+#endif
 }
 
 void Runtime::InitPlatformSignalHandlers() {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 021c7c1..6980530 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -495,7 +495,9 @@
   }
 
   // TODO: move this into the Linux GetThreadStack implementation.
-#if !defined(__APPLE__)
+#if defined(__APPLE__)
+  bool is_main_thread = false;
+#else
   // If we're the main thread, check whether we were run with an unlimited stack. In that case,
   // glibc will have reported a 2GB stack for our 32-bit process, and our stack overflow detection
   // will be broken because we'll die long before we get close to 2GB.
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 7700658..f60f795 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1054,6 +1054,7 @@
   if (current_method != nullptr) {
     Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
   }
+#ifdef __linux__
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid));
   if (!backtrace->Unwind(0)) {
     os << prefix << "(backtrace::Unwind failed for thread " << tid << ")\n";
@@ -1095,6 +1096,7 @@
     }
     os << "\n";
   }
+#endif
 }
 
 #if defined(__APPLE__)
diff --git a/test/404-optimizing-allocator/expected.txt b/test/404-optimizing-allocator/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/404-optimizing-allocator/expected.txt
diff --git a/test/404-optimizing-allocator/info.txt b/test/404-optimizing-allocator/info.txt
new file mode 100644
index 0000000..930d42f
--- /dev/null
+++ b/test/404-optimizing-allocator/info.txt
@@ -0,0 +1 @@
+Initial tests for testing the optimizing compiler's register allocator.
diff --git a/test/404-optimizing-allocator/src/Main.java b/test/404-optimizing-allocator/src/Main.java
new file mode 100644
index 0000000..60477f9
--- /dev/null
+++ b/test/404-optimizing-allocator/src/Main.java
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+// Note that $opt$reg$ is a marker for the optimizing compiler to ensure
+// it does use its register allocator.
+
+public class Main {
+  public static void main(String[] args) {
+
+    expectEquals(4, $opt$reg$TestLostCopy());
+    expectEquals(-10, $opt$reg$TestTwoLive());
+    expectEquals(-20, $opt$reg$TestThreeLive());
+    expectEquals(5, $opt$reg$TestFourLive());
+    expectEquals(10, $opt$reg$TestMultipleLive());
+    expectEquals(1, $opt$reg$TestWithBreakAndContinue());
+    expectEquals(-15, $opt$reg$testSpillInIf(5, 6, 7));
+    expectEquals(-567, $opt$reg$TestAgressiveLive(1, 2, 3, 4, 5, 6, 7));
+  }
+
+  public static int $opt$reg$TestLostCopy() {
+    int a = 0;
+    int b = 0;
+    do {
+      b = a;
+      a++;
+    } while (a != 5);
+    return b;
+  }
+
+  public static int $opt$reg$TestTwoLive() {
+    int a = 0;
+    int b = 0;
+    do {
+      a++;
+      b += 3;
+    } while (a != 5);
+    return a - b;
+  }
+
+  public static int $opt$reg$TestThreeLive() {
+    int a = 0;
+    int b = 0;
+    int c = 0;
+    do {
+      a++;
+      b += 3;
+      c += 2;
+    } while (a != 5);
+    return a - b - c;
+  }
+
+  public static int $opt$reg$TestFourLive() {
+    int a = 0;
+    int b = 0;
+    int c = 0;
+    int d = 0;
+    do {
+      a++;
+      b += 3;
+      c += 2;
+      d++;
+    } while (a != 5);
+    return d;
+  }
+
+  public static int $opt$reg$TestMultipleLive() {
+    int a = 0;
+    int b = 0;
+    int c = 0;
+    int d = 0;
+    int e = 0;
+    int f = 0;
+    int g = 0;
+    do {
+      a++;
+      b++;
+      c++;
+      d++;
+      e += 3;
+      f += 2;
+      g += 2;
+    } while (a != 5);
+    return f;
+  }
+
+  public static int $opt$reg$TestWithBreakAndContinue() {
+    int a = 0;
+    int b = 0;
+    do {
+      a++;
+      if (a == 2) {
+        continue;
+      }
+      b++;
+      if (a == 5) {
+        break;
+      }
+    } while (true);
+    return a - b;
+  }
+
+  public static int $opt$reg$testSpillInIf(int a, int b, int c) {
+    int d = 0;
+    int e = 0;
+    if (a == 5) {
+      b++;
+      c++;
+      d += 2;
+      e += 3;
+    }
+
+    return a - b - c - d - e;
+  }
+
+  public static int $opt$reg$TestAgressiveLive(int a, int b, int c, int d, int e, int f, int g) {
+    int h = a - b;
+    int i = c - d;
+    int j = e - f;
+    int k = 42 + g - a;
+    do {
+      b++;
+      while (k != 1) {
+        --k;
+        ++i;
+        if (i == 9) {
+          ++i;
+        }
+        j += 5;
+      }
+      k = 9;
+      h++;
+    } while (h != 5);
+    return a - b - c - d - e - f - g - h - i - j - k;
+  }
+
+  public static void expectEquals(int expected, int value) {
+    if (expected != value) {
+      throw new Error("Expected: " + expected + ", got: " + value);
+    }
+  }
+}
diff --git a/test/Android.mk b/test/Android.mk
index 109382d..7897449 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -144,7 +144,7 @@
 	ANDROID_DATA=/tmp/android-data/test-art-host-oat-default-$(1) \
 	  ANDROID_ROOT=$(HOST_OUT) \
 	  LD_LIBRARY_PATH=$(HOST_LIBRARY_PATH) \
-	  $(HOST_OUT_EXECUTABLES)/dalvikvm $(DALVIKVM_FLAGS) -XXlib:libartd.so -Ximage:$(HOST_CORE_IMG_LOCATION) -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_LIBRARY_PATH) $(1) $(2) \
+	  $(HOST_OUT_EXECUTABLES)/dalvikvm $(DALVIKVM_FLAGS) -XXlib:libartd$(HOST_SHLIB_SUFFIX) -Ximage:$(HOST_CORE_IMG_LOCATION) -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_LIBRARY_PATH) $(1) $(2) \
           && echo test-art-host-oat-default-$(1) PASSED || (echo test-art-host-oat-default-$(1) FAILED && exit 1)
 	$(hide) rm -r /tmp/android-data/test-art-host-oat-default-$(1)
 
@@ -154,7 +154,7 @@
 	ANDROID_DATA=/tmp/android-data/test-art-host-oat-interpreter-$(1) \
 	  ANDROID_ROOT=$(HOST_OUT) \
 	  LD_LIBRARY_PATH=$(HOST_LIBRARY_PATH) \
-	  $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd.so -Ximage:$(HOST_CORE_IMG_LOCATION) $(DALVIKVM_FLAGS) -Xint -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_LIBRARY_PATH) $(1) $(2) \
+	  $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd$(HOST_SHLIB_SUFFIX) -Ximage:$(HOST_CORE_IMG_LOCATION) $(DALVIKVM_FLAGS) -Xint -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_LIBRARY_PATH) $(1) $(2) \
           && echo test-art-host-oat-interpreter-$(1) PASSED || (echo test-art-host-oat-interpreter-$(1) FAILED && exit 1)
 	$(hide) rm -r /tmp/android-data/test-art-host-oat-interpreter-$(1)
 
diff --git a/test/SignalTest/signaltest.cc b/test/SignalTest/signaltest.cc
index b84e395..dfe3197 100644
--- a/test/SignalTest/signaltest.cc
+++ b/test/SignalTest/signaltest.cc
@@ -46,7 +46,7 @@
   action.sa_sigaction = signalhandler;
   sigemptyset(&action.sa_mask);
   action.sa_flags = SA_SIGINFO | SA_ONSTACK;
-#if !defined(__mips__)
+#if !defined(__APPLE__) && !defined(__mips__)
   action.sa_restorer = nullptr;
 #endif
 
diff --git a/tools/Android.mk b/tools/Android.mk
index 6c385dc..d3be17f 100644
--- a/tools/Android.mk
+++ b/tools/Android.mk
@@ -16,7 +16,6 @@
 
 LOCAL_PATH := $(call my-dir)
 
-ifeq ($(WITH_HOST_DALVIK),true)
 # Copy the art shell script to the host's bin directory
 include $(CLEAR_VARS)
 LOCAL_IS_HOST_MODULE := true
@@ -28,5 +27,3 @@
 	@echo "Copy: $(PRIVATE_MODULE) ($@)"
 	$(copy-file-to-new-target)
 	$(hide) chmod 755 $@
-
-endif