Merge "Remove non-existent ARM insn kThumb2SubsRRI12."
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 704da68..28546e9 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -91,10 +91,12 @@
 # Don't fail a dalvik minimal host build.
 -include $(LLVM_ROOT_PATH)/llvm.mk
 
-# Clang build.
-# ART_TARGET_CLANG := true
+# Clang build support.
+ART_TARGET_CLANG := false
 ifeq ($(HOST_OS),darwin)
-ART_HOST_CLANG := true
+  ART_HOST_CLANG := true
+else
+  ART_HOST_CLANG := false
 endif
 
 # directory used for dalvik-cache on device
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 2ddd09e..0b0c445 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -155,7 +155,6 @@
     LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libnativehelper libz libcutils
     LOCAL_STATIC_LIBRARIES += libgtest
     LOCAL_MODULE_PATH := $(ART_NATIVETEST_OUT)
-    include $(LLVM_DEVICE_BUILD_MK)
     include $(BUILD_EXECUTABLE)
     art_gtest_exe := $$(LOCAL_MODULE_PATH)/$$(LOCAL_MODULE)
     ART_TARGET_GTEST_EXECUTABLES += $$(art_gtest_exe)
@@ -168,7 +167,6 @@
       # Mac OS complains about unresolved symbols if you don't include this.
       LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_host
     endif
-    include $(LLVM_HOST_BUILD_MK)
     include $(BUILD_HOST_EXECUTABLE)
     art_gtest_exe := $(HOST_OUT_EXECUTABLES)/$$(LOCAL_MODULE)
     ART_HOST_GTEST_EXECUTABLES += $$(art_gtest_exe)
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 8f840cc..b1b6fc5 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -106,7 +106,7 @@
 LIBART_COMPILER_CFLAGS :=
 
 ifeq ($(ART_USE_PORTABLE_COMPILER),true)
-LIBART_COMPILER_SRC_FILES +=
+LIBART_COMPILER_SRC_FILES += \
 	dex/portable/mir_to_gbc.cc \
 	elf_writer_mclinker.cc \
 	jni/portable/jni_compiler.cc \
@@ -120,11 +120,12 @@
 	llvm/runtime_support_builder.cc \
 	llvm/runtime_support_builder_arm.cc \
 	llvm/runtime_support_builder_x86.cc
-  LIBART_COMPILER_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
+LIBART_COMPILER_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
 endif
 
 LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES := \
-	dex/compiler_enums.h
+	dex/compiler_enums.h \
+	dex/quick/dex_file_method_inliner.h
 
 # $(1): target or host
 # $(2): ndebug or debug
@@ -211,12 +212,15 @@
       ifeq ($(TARGET_ARCH),arm64)
          $$(info TODOAArch64: $$(LOCAL_PATH)/Android.mk Add Arm64 specific MCLinker libraries)
       endif # TARGET_ARCH != arm64
+      include $(LLVM_DEVICE_BUILD_MK)
     else # host
       LOCAL_STATIC_LIBRARIES += libmcldARMInfo libmcldARMTarget
       LOCAL_STATIC_LIBRARIES += libmcldX86Info libmcldX86Target
       LOCAL_STATIC_LIBRARIES += libmcldMipsInfo libmcldMipsTarget
+      include $(LLVM_HOST_BUILD_MK)
     endif
     LOCAL_STATIC_LIBRARIES += libmcldCore libmcldObject libmcldADT libmcldFragment libmcldTarget libmcldCodeGen libmcldLDVariant libmcldMC libmcldSupport libmcldLD
+    include $(LLVM_GEN_INTRINSICS_MK)
   endif
 
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
@@ -228,13 +232,9 @@
   LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
   ifeq ($$(art_target_or_host),target)
     LOCAL_SHARED_LIBRARIES += libcutils
-    include $(LLVM_GEN_INTRINSICS_MK)
-    include $(LLVM_DEVICE_BUILD_MK)
     include $(BUILD_SHARED_LIBRARY)
   else # host
     LOCAL_STATIC_LIBRARIES += libcutils
-    include $(LLVM_GEN_INTRINSICS_MK)
-    include $(LLVM_HOST_BUILD_MK)
     include $(BUILD_HOST_SHARED_LIBRARY)
   endif
 
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 0999d09..d034b79 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -240,7 +240,7 @@
 #if GCC_VERSION >= 40303
     __builtin___clear_cache(reinterpret_cast<void*>(base), reinterpret_cast<void*>(base + len));
 #else
-    LOG(FATAL) << "UNIMPLEMENTED: cache flush";
+    LOG(WARNING) << "UNIMPLEMENTED: cache flush";
 #endif
   }
 
@@ -353,7 +353,7 @@
     CHECK(method != nullptr);
     TimingLogger timings("CommonTest::CompileMethod", false, false);
     timings.StartSplit("CompileOne");
-    compiler_driver_->CompileOne(method, timings);
+    compiler_driver_->CompileOne(method, &timings);
     MakeExecutable(method);
     timings.EndSplit();
   }
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index f6d724a..d884bc0 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -153,12 +153,14 @@
                                const uint32_t fp_spill_mask,
                                const std::vector<uint8_t>& mapping_table,
                                const std::vector<uint8_t>& vmap_table,
-                               const std::vector<uint8_t>& native_gc_map)
+                               const std::vector<uint8_t>& native_gc_map,
+                               const std::vector<uint8_t>* cfi_info)
     : CompiledCode(&driver, instruction_set, quick_code), frame_size_in_bytes_(frame_size_in_bytes),
       core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
   mapping_table_(driver.DeduplicateMappingTable(mapping_table)),
   vmap_table_(driver.DeduplicateVMapTable(vmap_table)),
-  gc_map_(driver.DeduplicateGCMap(native_gc_map)) {
+  gc_map_(driver.DeduplicateGCMap(native_gc_map)),
+  cfi_info_(driver.DeduplicateCFIInfo(cfi_info)) {
 }
 
 CompiledMethod::CompiledMethod(CompilerDriver& driver,
@@ -169,10 +171,11 @@
                                const uint32_t fp_spill_mask)
     : CompiledCode(&driver, instruction_set, code),
       frame_size_in_bytes_(frame_size_in_bytes),
-      core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) {
-  mapping_table_ = driver.DeduplicateMappingTable(std::vector<uint8_t>());
-  vmap_table_ = driver.DeduplicateVMapTable(std::vector<uint8_t>());
-  gc_map_ = driver.DeduplicateGCMap(std::vector<uint8_t>());
+      core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
+      mapping_table_(driver.DeduplicateMappingTable(std::vector<uint8_t>())),
+      vmap_table_(driver.DeduplicateVMapTable(std::vector<uint8_t>())),
+      gc_map_(driver.DeduplicateGCMap(std::vector<uint8_t>())),
+      cfi_info_(nullptr) {
 }
 
 // Constructs a CompiledMethod for the Portable compiler.
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 6112305..90ae6ee 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -110,7 +110,8 @@
                  const uint32_t fp_spill_mask,
                  const std::vector<uint8_t>& mapping_table,
                  const std::vector<uint8_t>& vmap_table,
-                 const std::vector<uint8_t>& native_gc_map);
+                 const std::vector<uint8_t>& native_gc_map,
+                 const std::vector<uint8_t>* cfi_info);
 
   // Constructs a CompiledMethod for the QuickJniCompiler.
   CompiledMethod(CompilerDriver& driver,
@@ -157,6 +158,10 @@
     return *gc_map_;
   }
 
+  const std::vector<uint8_t>* GetCFIInfo() const {
+    return cfi_info_;
+  }
+
  private:
   // For quick code, the size of the activation used by the code.
   const size_t frame_size_in_bytes_;
@@ -172,6 +177,8 @@
   // For quick code, a map keyed by native PC indices to bitmaps describing what dalvik registers
   // are live. For portable code, the key is a dalvik PC.
   std::vector<uint8_t>* gc_map_;
+  // For quick code, a FDE entry for the debug_frame section.
+  std::vector<uint8_t>* cfi_info_;
 };
 
 }  // namespace art
diff --git a/compiler/compiler_backend.cc b/compiler/compiler_backend.cc
index eaa39f8..0afa665 100644
--- a/compiler/compiler_backend.cc
+++ b/compiler/compiler_backend.cc
@@ -83,6 +83,9 @@
 }
 
 
+// Hack for CFI CIE initialization
+extern std::vector<uint8_t>* X86CFIInitialization();
+
 class QuickBackend : public CompilerBackend {
  public:
   QuickBackend() : CompilerBackend(100) {}
@@ -135,10 +138,11 @@
   }
 
   bool WriteElf(art::File* file,
-                OatWriter& oat_writer,
+                OatWriter* oat_writer,
                 const std::vector<const art::DexFile*>& dex_files,
                 const std::string& android_root,
                 bool is_host, const CompilerDriver& driver) const
+    OVERRIDE
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, driver);
   }
@@ -165,11 +169,27 @@
       bool set_max = cu->mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps);
       CHECK(set_max);
     }
-    return mir_to_lir;;
+    return mir_to_lir;
   }
 
   void InitCompilationUnit(CompilationUnit& cu) const {}
 
+  /*
+   * @brief Generate and return Dwarf CFI initialization, if supported by the
+   * backend.
+   * @param driver CompilerDriver for this compile.
+   * @returns nullptr if not supported by backend or a vector of bytes for CFI DWARF
+   * information.
+   * @note This is used for backtrace information in generated code.
+   */
+  std::vector<uint8_t>* GetCallFrameInformationInitialization(const CompilerDriver& driver) const
+      OVERRIDE {
+    if (driver.GetInstructionSet() == kX86) {
+      return X86CFIInitialization();
+    }
+    return nullptr;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(QuickBackend);
 };
@@ -249,11 +269,12 @@
   }
 
   bool WriteElf(art::File* file,
-                OatWriter& oat_writer,
+                OatWriter* oat_writer,
                 const std::vector<const art::DexFile*>& dex_files,
                 const std::string& android_root,
                 bool is_host, const CompilerDriver& driver) const
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+      OVERRIDE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return art::ElfWriterMclinker::Create(
         file, oat_writer, dex_files, android_root, is_host, driver);
   }
@@ -271,15 +292,17 @@
         (1 << kSuppressExceptionEdges);
   }
 
-  bool isPortable() const { return true; }
+  bool IsPortable() const OVERRIDE {
+    return true;
+  }
 
-  void SetBitcodeFileName(std::string const& filename) {
-    typedef void (*SetBitcodeFileNameFn)(CompilerDriver&, std::string const&);
+  void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) {
+    typedef void (*SetBitcodeFileNameFn)(const CompilerDriver&, const std::string&);
 
     SetBitcodeFileNameFn set_bitcode_file_name =
       reinterpret_cast<SetBitcodeFileNameFn>(compilerLLVMSetBitcodeFileName);
 
-    set_bitcode_file_name(*this, filename);
+    set_bitcode_file_name(driver, filename);
   }
 
  private:
diff --git a/compiler/compiler_backend.h b/compiler/compiler_backend.h
index 01a69af..b473806 100644
--- a/compiler/compiler_backend.h
+++ b/compiler/compiler_backend.h
@@ -23,7 +23,7 @@
 namespace art {
 
 class Backend;
-class CompilationUnit;
+struct CompilationUnit;
 class CompilerDriver;
 class CompiledMethod;
 class MIRGraph;
@@ -40,8 +40,9 @@
     kPortable
   };
 
-  explicit CompilerBackend(int warning)
-      : maximum_compilation_time_before_warning_(warning) {}
+  explicit CompilerBackend(uint64_t warning)
+      : maximum_compilation_time_before_warning_(warning) {
+  }
 
   static CompilerBackend* Create(Kind kind);
 
@@ -49,7 +50,7 @@
 
   virtual void UnInit(CompilerDriver& driver) const = 0;
 
-  virtual CompiledMethod* Compile(CompilerDriver& compiler,
+  virtual CompiledMethod* Compile(CompilerDriver& driver,
                                   const DexFile::CodeItem* code_item,
                                   uint32_t access_flags,
                                   InvokeType invoke_type,
@@ -66,7 +67,7 @@
   virtual uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const = 0;
 
   virtual bool WriteElf(art::File* file,
-                        OatWriter& oat_writer,
+                        OatWriter* oat_writer,
                         const std::vector<const art::DexFile*>& dex_files,
                         const std::string& android_root,
                         bool is_host, const CompilerDriver& driver) const
@@ -79,8 +80,12 @@
     return maximum_compilation_time_before_warning_;
   }
 
-  virtual bool IsPortable() const { return false; }
-  void SetBitcodeFileName(std::string const& filename) {
+  virtual bool IsPortable() const {
+    return false;
+  }
+
+  void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) {
+    UNUSED(driver);
     UNUSED(filename);
   }
 
@@ -88,8 +93,21 @@
 
   virtual ~CompilerBackend() {}
 
+  /*
+   * @brief Generate and return Dwarf CFI initialization, if supported by the
+   * backend.
+   * @param driver CompilerDriver for this compile.
+   * @returns nullptr if not supported by backend or a vector of bytes for CFI DWARF
+   * information.
+   * @note This is used for backtrace information in generated code.
+   */
+  virtual std::vector<uint8_t>* GetCallFrameInformationInitialization(const CompilerDriver& driver)
+      const {
+    return nullptr;
+  }
+
  private:
-  uint64_t maximum_compilation_time_before_warning_;
+  const uint64_t maximum_compilation_time_before_warning_;
 
   DISALLOW_COPY_AND_ASSIGN(CompilerBackend);
 };
diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h
index 8447d23..b9a26d6 100644
--- a/compiler/dex/compiler_ir.h
+++ b/compiler/dex/compiler_ir.h
@@ -64,7 +64,7 @@
   const CompilerBackend* compiler_backend;
   InstructionSet instruction_set;
 
-  const InstructionSetFeatures& GetInstructionSetFeatures() {
+  InstructionSetFeatures GetInstructionSetFeatures() {
     return compiler_driver->GetInstructionSetFeatures();
   }
   // TODO: much of this info available elsewhere.  Go to the original source?
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 6800f7b..2619258 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -128,7 +128,7 @@
   }
 }
 
-static CompiledMethod* CompileMethod(CompilerDriver& compiler,
+static CompiledMethod* CompileMethod(CompilerDriver& driver,
                                      CompilerBackend* compiler_backend,
                                      const DexFile::CodeItem* code_item,
                                      uint32_t access_flags, InvokeType invoke_type,
@@ -143,11 +143,11 @@
   }
 
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  CompilationUnit cu(&compiler.GetArenaPool());
+  CompilationUnit cu(driver.GetArenaPool());
 
-  cu.compiler_driver = &compiler;
+  cu.compiler_driver = &driver;
   cu.class_linker = class_linker;
-  cu.instruction_set = compiler.GetInstructionSet();
+  cu.instruction_set = driver.GetInstructionSet();
   cu.compiler_backend = compiler_backend;
   DCHECK((cu.instruction_set == kThumb2) ||
          (cu.instruction_set == kX86) ||
@@ -216,8 +216,8 @@
   }
 
   /* Create the pass driver and launch it */
-  PassDriver driver(&cu);
-  driver.Launch();
+  PassDriver pass_driver(&cu);
+  pass_driver.Launch();
 
   if (cu.enable_debug & (1 << kDebugDumpCheckStats)) {
     cu.mir_graph->DumpCheckStats();
@@ -257,9 +257,9 @@
   }
 
   cu.EndTiming();
-  compiler.GetTimingsLogger().Start();
-  compiler.GetTimingsLogger().AddLogger(cu.timings);
-  compiler.GetTimingsLogger().End();
+  driver.GetTimingsLogger()->Start();
+  driver.GetTimingsLogger()->AddLogger(cu.timings);
+  driver.GetTimingsLogger()->End();
   return result;
 }
 
diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h
index 8ce1206..22a7b8c 100644
--- a/compiler/dex/frontend.h
+++ b/compiler/dex/frontend.h
@@ -105,7 +105,7 @@
     UniquePtr<art::llvm::IRBuilder> ir_builder_;
 };
 
-struct CompiledMethod;
+class CompiledMethod;
 class CompilerDriver;
 
 }  // namespace art
diff --git a/compiler/dex/pass.h b/compiler/dex/pass.h
index 255892e..9457d5b 100644
--- a/compiler/dex/pass.h
+++ b/compiler/dex/pass.h
@@ -22,8 +22,8 @@
 namespace art {
 
 // Forward declarations.
-class BasicBlock;
-class CompilationUnit;
+struct BasicBlock;
+struct CompilationUnit;
 class Pass;
 
 /**
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
index 3187fbb..70438ec 100644
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -30,6 +30,7 @@
 #include "dex/compiler_internals.h"
 #include "dex/dataflow_iterator-inl.h"
 #include "dex/frontend.h"
+#include "llvm/ir_builder.h"
 #include "llvm/llvm_compilation_unit.h"
 #include "llvm/utils_llvm.h"
 #include "mir_to_gbc.h"
diff --git a/compiler/dex/portable/mir_to_gbc.h b/compiler/dex/portable/mir_to_gbc.h
index 2b681f6..e97634c 100644
--- a/compiler/dex/portable/mir_to_gbc.h
+++ b/compiler/dex/portable/mir_to_gbc.h
@@ -17,11 +17,18 @@
 #ifndef ART_COMPILER_DEX_PORTABLE_MIR_TO_GBC_H_
 #define ART_COMPILER_DEX_PORTABLE_MIR_TO_GBC_H_
 
+#include <llvm/ADT/ArrayRef.h>
+#include <llvm/IR/BasicBlock.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/Module.h>
+
 #include "invoke_type.h"
 #include "compiled_method.h"
 #include "dex/compiler_enums.h"
 #include "dex/compiler_ir.h"
 #include "dex/backend.h"
+#include "llvm/intrinsic_helper.h"
 #include "llvm/llvm_compilation_unit.h"
 #include "safe_map.h"
 
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 3185449..b0b8d1e 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1070,10 +1070,12 @@
     DCHECK_EQ(fp_vmap_table_.size(), 0u);
     vmap_encoder.PushBackUnsigned(0u);  // Size is 0.
   }
+
+  UniquePtr<std::vector<uint8_t> > cfi_info(ReturnCallFrameInformation());
   CompiledMethod* result =
       new CompiledMethod(*cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_,
                          core_spill_mask_, fp_spill_mask_, encoded_mapping_table_,
-                         vmap_encoder.GetData(), native_gc_map_);
+                         vmap_encoder.GetData(), native_gc_map_, cfi_info.get());
   return result;
 }
 
@@ -1216,4 +1218,9 @@
   AppendLIR(load_pc_rel);
 }
 
+std::vector<uint8_t>* Mir2Lir::ReturnCallFrameInformation() {
+  // Default case is to do nothing.
+  return nullptr;
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 3dcb964..b4d8dd6 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -31,7 +31,7 @@
 class MethodVerifier;
 }  // namespace verifier
 
-class CallInfo;
+struct CallInfo;
 class Mir2Lir;
 
 enum InlineMethodOpcode : uint16_t {
@@ -61,6 +61,7 @@
   kInlineOpIGet,
   kInlineOpIPut,
 };
+std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
 
 enum InlineMethodFlags : uint16_t {
   kNoInlineMethodFlags = 0x0000,
@@ -78,13 +79,13 @@
 
   // kIntrinsicIsEmptyOrLength
   kIntrinsicFlagLength  = kIntrinsicFlagNone,
-  kIntrinsicFlagIsEmpty = 1,
+  kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
 
   // kIntrinsicIndexOf
-  kIntrinsicFlagBase0 = 1,
+  kIntrinsicFlagBase0 = kIntrinsicFlagMin,
 
   // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
-  kIntrinsicFlagIsLong     = 1,
+  kIntrinsicFlagIsLong     = kIntrinsicFlagMin,
   // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
   kIntrinsicFlagIsVolatile = 2,
   // kIntrinsicUnsafePut, kIntrinsicUnsafeCas
@@ -187,7 +188,6 @@
      */
     bool GenSpecial(Mir2Lir* backend, uint32_t method_idx);
 
-  private:
     /**
      * To avoid multiple lookups of a class by its descriptor, we cache its
      * type index in the IndexCache. These are the indexes into the IndexCache
@@ -311,6 +311,7 @@
       kProtoCacheLast
     };
 
+  private:
     /**
      * The maximum number of method parameters we support in the ProtoDef.
      */
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index b74052c..8f199f8 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1089,6 +1089,11 @@
                                             bool can_assume_type_is_in_dex_cache,
                                             uint32_t type_idx, RegLocation rl_dest,
                                             RegLocation rl_src);
+    /*
+     * @brief Generate the debug_frame FDE information if possible.
+     * @returns pointer to vector containg CFE information, or NULL.
+     */
+    virtual std::vector<uint8_t>* ReturnCallFrameInformation();
 
     /**
      * @brief Used to insert marker that can be used to associate MIR with LIR.
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 0613cdf..399001c 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -198,7 +198,7 @@
   LockTemp(rX86_ARG2);
 
   /* Build frame, return address already on stack */
-  OpRegImm(kOpSub, rX86_SP, frame_size_ - 4);
+  stack_decrement_ = OpRegImm(kOpSub, rX86_SP, frame_size_ - 4);
 
   /*
    * We can safely skip the stack overflow check if we're
@@ -246,7 +246,7 @@
   NewLIR0(kPseudoMethodExit);
   UnSpillCoreRegs();
   /* Remove frame except for return address */
-  OpRegImm(kOpAdd, rX86_SP, frame_size_ - 4);
+  stack_increment_ = OpRegImm(kOpAdd, rX86_SP, frame_size_ - 4);
   NewLIR0(kX86Ret);
 }
 
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 421d51e..c97d0e6 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -302,6 +302,18 @@
      */
     void InstallLiteralPools();
 
+    /*
+     * @brief Generate the debug_frame CFI information.
+     * @returns pointer to vector containing CFE information
+     */
+    static std::vector<uint8_t>* ReturnCommonCallFrameInformation();
+
+    /*
+     * @brief Generate the debug_frame FDE information.
+     * @returns pointer to vector containing CFE information
+     */
+    std::vector<uint8_t>* ReturnCallFrameInformation();
+
   private:
     void EmitPrefix(const X86EncodingMap* entry);
     void EmitOpcode(const X86EncodingMap* entry);
@@ -549,6 +561,12 @@
 
     // Instructions needing patching with PC relative code addresses.
     GrowableArray<LIR*> call_method_insns_;
+
+    // Prologue decrement of stack pointer.
+    LIR* stack_decrement_;
+
+    // Epilogue increment of stack pointer.
+    LIR* stack_increment_;
 };
 
 }  // namespace art
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index eea7191..7bb866d 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -539,7 +539,8 @@
     : Mir2Lir(cu, mir_graph, arena),
       method_address_insns_(arena, 100, kGrowableArrayMisc),
       class_type_address_insns_(arena, 100, kGrowableArrayMisc),
-      call_method_insns_(arena, 100, kGrowableArrayMisc) {
+      call_method_insns_(arena, 100, kGrowableArrayMisc),
+      stack_decrement_(nullptr), stack_increment_(nullptr) {
   store_method_addr_used_ = false;
   for (int i = 0; i < kX86Last; i++) {
     if (X86Mir2Lir::EncodingMap[i].opcode != i) {
@@ -1118,4 +1119,166 @@
   return true;
 }
 
+/*
+ * @brief Enter a 32 bit quantity into the FDE buffer
+ * @param buf FDE buffer.
+ * @param data Data value.
+ */
+static void PushWord(std::vector<uint8_t>&buf, int data) {
+  buf.push_back(data & 0xff);
+  buf.push_back((data >> 8) & 0xff);
+  buf.push_back((data >> 16) & 0xff);
+  buf.push_back((data >> 24) & 0xff);
+}
+
+/*
+ * @brief Enter an 'advance LOC' into the FDE buffer
+ * @param buf FDE buffer.
+ * @param increment Amount by which to increase the current location.
+ */
+static void AdvanceLoc(std::vector<uint8_t>&buf, uint32_t increment) {
+  if (increment < 64) {
+    // Encoding in opcode.
+    buf.push_back(0x1 << 6 | increment);
+  } else if (increment < 256) {
+    // Single byte delta.
+    buf.push_back(0x02);
+    buf.push_back(increment);
+  } else if (increment < 256 * 256) {
+    // Two byte delta.
+    buf.push_back(0x03);
+    buf.push_back(increment & 0xff);
+    buf.push_back((increment >> 8) & 0xff);
+  } else {
+    // Four byte delta.
+    buf.push_back(0x04);
+    PushWord(buf, increment);
+  }
+}
+
+
+std::vector<uint8_t>* X86CFIInitialization() {
+  return X86Mir2Lir::ReturnCommonCallFrameInformation();
+}
+
+std::vector<uint8_t>* X86Mir2Lir::ReturnCommonCallFrameInformation() {
+  std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+
+  // Length of the CIE (except for this field).
+  PushWord(*cfi_info, 16);
+
+  // CIE id.
+  PushWord(*cfi_info, 0xFFFFFFFFU);
+
+  // Version: 3.
+  cfi_info->push_back(0x03);
+
+  // Augmentation: empty string.
+  cfi_info->push_back(0x0);
+
+  // Code alignment: 1.
+  cfi_info->push_back(0x01);
+
+  // Data alignment: -4.
+  cfi_info->push_back(0x7C);
+
+  // Return address register (R8).
+  cfi_info->push_back(0x08);
+
+  // Initial return PC is 4(ESP): DW_CFA_def_cfa R4 4.
+  cfi_info->push_back(0x0C);
+  cfi_info->push_back(0x04);
+  cfi_info->push_back(0x04);
+
+  // Return address location: 0(SP): DW_CFA_offset R8 1 (* -4);.
+  cfi_info->push_back(0x2 << 6 | 0x08);
+  cfi_info->push_back(0x01);
+
+  // And 2 Noops to align to 4 byte boundary.
+  cfi_info->push_back(0x0);
+  cfi_info->push_back(0x0);
+
+  DCHECK_EQ(cfi_info->size() & 3, 0U);
+  return cfi_info;
+}
+
+static void EncodeUnsignedLeb128(std::vector<uint8_t>& buf, uint32_t value) {
+  uint8_t buffer[12];
+  uint8_t *ptr = EncodeUnsignedLeb128(buffer, value);
+  for (uint8_t *p = buffer; p < ptr; p++) {
+    buf.push_back(*p);
+  }
+}
+
+std::vector<uint8_t>* X86Mir2Lir::ReturnCallFrameInformation() {
+  std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+
+  // Generate the FDE for the method.
+  DCHECK_NE(data_offset_, 0U);
+
+  // Length (will be filled in later in this routine).
+  PushWord(*cfi_info, 0);
+
+  // CIE_pointer (can be filled in by linker); might be left at 0 if there is only
+  // one CIE for the whole debug_frame section.
+  PushWord(*cfi_info, 0);
+
+  // 'initial_location' (filled in by linker).
+  PushWord(*cfi_info, 0);
+
+  // 'address_range' (number of bytes in the method).
+  PushWord(*cfi_info, data_offset_);
+
+  // The instructions in the FDE.
+  if (stack_decrement_ != nullptr) {
+    // Advance LOC to just past the stack decrement.
+    uint32_t pc = NEXT_LIR(stack_decrement_)->offset;
+    AdvanceLoc(*cfi_info, pc);
+
+    // Now update the offset to the call frame: DW_CFA_def_cfa_offset frame_size.
+    cfi_info->push_back(0x0e);
+    EncodeUnsignedLeb128(*cfi_info, frame_size_);
+
+    // We continue with that stack until the epilogue.
+    if (stack_increment_ != nullptr) {
+      uint32_t new_pc = NEXT_LIR(stack_increment_)->offset;
+      AdvanceLoc(*cfi_info, new_pc - pc);
+
+      // We probably have code snippets after the epilogue, so save the
+      // current state: DW_CFA_remember_state.
+      cfi_info->push_back(0x0a);
+
+      // We have now popped the stack: DW_CFA_def_cfa_offset 4.  There is only the return
+      // PC on the stack now.
+      cfi_info->push_back(0x0e);
+      EncodeUnsignedLeb128(*cfi_info, 4);
+
+      // Everything after that is the same as before the epilogue.
+      // Stack bump was followed by RET instruction.
+      LIR *post_ret_insn = NEXT_LIR(NEXT_LIR(stack_increment_));
+      if (post_ret_insn != nullptr) {
+        pc = new_pc;
+        new_pc = post_ret_insn->offset;
+        AdvanceLoc(*cfi_info, new_pc - pc);
+        // Restore the state: DW_CFA_restore_state.
+        cfi_info->push_back(0x0b);
+      }
+    }
+  }
+
+  // Padding to a multiple of 4
+  while ((cfi_info->size() & 3) != 0) {
+    // DW_CFA_nop is encoded as 0.
+    cfi_info->push_back(0);
+  }
+
+  // Set the length of the FDE inside the generated bytes.
+  uint32_t length = cfi_info->size() - 4;
+  (*cfi_info)[0] = length;
+  (*cfi_info)[1] = length >> 8;
+  (*cfi_info)[2] = length >> 16;
+  (*cfi_info)[3] = length >> 24;
+  return cfi_info;
+}
+
 }  // namespace art
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 1b284de..708cce6 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -31,6 +31,7 @@
 #include "dex/verification_results.h"
 #include "dex/verified_method.h"
 #include "dex/quick/dex_file_method_inliner.h"
+#include "driver/compiler_options.h"
 #include "jni_internal.h"
 #include "object_utils.h"
 #include "runtime.h"
@@ -323,10 +324,12 @@
       compiler_enable_auto_elf_loading_(NULL),
       compiler_get_method_code_addr_(NULL),
       support_boot_image_fixup_(instruction_set != kMips),
+      cfi_info_(nullptr),
       dedupe_code_("dedupe code"),
       dedupe_mapping_table_("dedupe mapping table"),
       dedupe_vmap_table_("dedupe vmap table"),
-      dedupe_gc_map_("dedupe gc map") {
+      dedupe_gc_map_("dedupe gc map"),
+      dedupe_cfi_info_("dedupe cfi info") {
   DCHECK(compiler_options_ != nullptr);
   DCHECK(verification_results_ != nullptr);
   DCHECK(method_inliner_map_ != nullptr);
@@ -341,6 +344,11 @@
   if (!image_) {
     CHECK(image_classes_.get() == NULL);
   }
+
+  // Are we generating CFI information?
+  if (compiler_options->GetGenerateGDBInformation()) {
+    cfi_info_.reset(compiler_backend_->GetCallFrameInformationInitialization(*this));
+  }
 }
 
 std::vector<uint8_t>* CompilerDriver::DeduplicateCode(const std::vector<uint8_t>& code) {
@@ -359,6 +367,13 @@
   return dedupe_gc_map_.Add(Thread::Current(), code);
 }
 
+std::vector<uint8_t>* CompilerDriver::DeduplicateCFIInfo(const std::vector<uint8_t>* cfi_info) {
+  if (cfi_info == nullptr) {
+    return nullptr;
+  }
+  return dedupe_cfi_info_.Add(Thread::Current(), *cfi_info);
+}
+
 CompilerDriver::~CompilerDriver() {
   Thread* self = Thread::Current();
   {
@@ -441,11 +456,11 @@
 
 void CompilerDriver::CompileAll(jobject class_loader,
                                 const std::vector<const DexFile*>& dex_files,
-                                TimingLogger& timings) {
+                                TimingLogger* timings) {
   DCHECK(!Runtime::Current()->IsStarted());
   UniquePtr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", thread_count_ - 1));
-  PreCompile(class_loader, dex_files, *thread_pool.get(), timings);
-  Compile(class_loader, dex_files, *thread_pool.get(), timings);
+  PreCompile(class_loader, dex_files, thread_pool.get(), timings);
+  Compile(class_loader, dex_files, thread_pool.get(), timings);
   if (dump_stats_) {
     stats_->Dump();
   }
@@ -483,7 +498,7 @@
   }
 }
 
-void CompilerDriver::CompileOne(mirror::ArtMethod* method, TimingLogger& timings) {
+void CompilerDriver::CompileOne(mirror::ArtMethod* method, TimingLogger* timings) {
   DCHECK(!Runtime::Current()->IsStarted());
   Thread* self = Thread::Current();
   jobject jclass_loader;
@@ -510,7 +525,7 @@
   dex_files.push_back(dex_file);
 
   UniquePtr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", 0U));
-  PreCompile(jclass_loader, dex_files, *thread_pool.get(), timings);
+  PreCompile(jclass_loader, dex_files, thread_pool.get(), timings);
 
   // Can we run DEX-to-DEX compiler on this class ?
   DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile;
@@ -531,7 +546,7 @@
 }
 
 void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                             ThreadPool& thread_pool, TimingLogger& timings) {
+                             ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
@@ -540,7 +555,7 @@
 }
 
 void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                                ThreadPool& thread_pool, TimingLogger& timings) {
+                                ThreadPool* thread_pool, TimingLogger* timings) {
   LoadImageClasses(timings);
 
   Resolve(class_loader, dex_files, thread_pool, timings);
@@ -625,13 +640,13 @@
 }
 
 // Make a list of descriptors for classes to include in the image
-void CompilerDriver::LoadImageClasses(TimingLogger& timings)
+void CompilerDriver::LoadImageClasses(TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_) {
   if (!IsImage()) {
     return;
   }
 
-  timings.NewSplit("LoadImageClasses");
+  timings->NewSplit("LoadImageClasses");
   // Make a first class to load all classes explicitly listed in the file
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
@@ -713,9 +728,9 @@
   MaybeAddToImageClasses(object->GetClass(), compiler_driver->image_classes_.get());
 }
 
-void CompilerDriver::UpdateImageClasses(TimingLogger& timings) {
+void CompilerDriver::UpdateImageClasses(TimingLogger* timings) {
   if (IsImage()) {
-    timings.NewSplit("UpdateImageClasses");
+    timings->NewSplit("UpdateImageClasses");
 
     // Update image_classes_ with classes for objects created by <clinit> methods.
     Thread* self = Thread::Current();
@@ -1368,13 +1383,13 @@
                              jobject class_loader,
                              CompilerDriver* compiler,
                              const DexFile* dex_file,
-                             ThreadPool& thread_pool)
+                             ThreadPool* thread_pool)
     : index_(0),
       class_linker_(class_linker),
       class_loader_(class_loader),
       compiler_(compiler),
       dex_file_(dex_file),
-      thread_pool_(&thread_pool) {}
+      thread_pool_(thread_pool) {}
 
   ClassLinker* GetClassLinker() const {
     CHECK(class_linker_ != NULL);
@@ -1628,7 +1643,7 @@
 }
 
 void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_file,
-                                    ThreadPool& thread_pool, TimingLogger& timings) {
+                                    ThreadPool* thread_pool, TimingLogger* timings) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
   // TODO: we could resolve strings here, although the string table is largely filled with class
@@ -1638,16 +1653,16 @@
   if (IsImage()) {
     // For images we resolve all types, such as array, whereas for applications just those with
     // classdefs are resolved by ResolveClassFieldsAndMethods.
-    timings.NewSplit("Resolve Types");
+    timings->NewSplit("Resolve Types");
     context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_);
   }
 
-  timings.NewSplit("Resolve MethodsAndFields");
+  timings->NewSplit("Resolve MethodsAndFields");
   context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_);
 }
 
 void CompilerDriver::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                            ThreadPool& thread_pool, TimingLogger& timings) {
+                            ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
@@ -1702,8 +1717,8 @@
 }
 
 void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file,
-                                   ThreadPool& thread_pool, TimingLogger& timings) {
-  timings.NewSplit("Verify Dex File");
+                                   ThreadPool* thread_pool, TimingLogger* timings) {
+  timings->NewSplit("Verify Dex File");
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool);
   context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
@@ -1805,8 +1820,8 @@
 }
 
 void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
-                                       ThreadPool& thread_pool, TimingLogger& timings) {
-  timings.NewSplit("InitializeNoClinit");
+                                       ThreadPool* thread_pool, TimingLogger* timings) {
+  timings->NewSplit("InitializeNoClinit");
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, thread_pool);
   size_t thread_count;
@@ -1825,7 +1840,7 @@
 
 void CompilerDriver::InitializeClasses(jobject class_loader,
                                        const std::vector<const DexFile*>& dex_files,
-                                       ThreadPool& thread_pool, TimingLogger& timings) {
+                                       ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
@@ -1834,7 +1849,7 @@
 }
 
 void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                       ThreadPool& thread_pool, TimingLogger& timings) {
+                             ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
@@ -1916,8 +1931,8 @@
 }
 
 void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file,
-                                    ThreadPool& thread_pool, TimingLogger& timings) {
-  timings.NewSplit("Compile Dex File");
+                                    ThreadPool* thread_pool, TimingLogger* timings) {
+  timings->NewSplit("Compile Dex File");
   ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this,
                                      &dex_file, thread_pool);
   context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);
@@ -2037,38 +2052,38 @@
 bool CompilerDriver::WriteElf(const std::string& android_root,
                               bool is_host,
                               const std::vector<const art::DexFile*>& dex_files,
-                              OatWriter& oat_writer,
+                              OatWriter* oat_writer,
                               art::File* file)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return compiler_backend_->WriteElf(file, oat_writer, dex_files, android_root, is_host, *this);
 }
 void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
-                                                std::string& target_triple,
-                                                std::string& target_cpu,
-                                                std::string& target_attr) {
+                                                std::string* target_triple,
+                                                std::string* target_cpu,
+                                                std::string* target_attr) {
   switch (instruction_set) {
     case kThumb2:
-      target_triple = "thumb-none-linux-gnueabi";
-      target_cpu = "cortex-a9";
-      target_attr = "+thumb2,+neon,+neonfp,+vfp3,+db";
+      *target_triple = "thumb-none-linux-gnueabi";
+      *target_cpu = "cortex-a9";
+      *target_attr = "+thumb2,+neon,+neonfp,+vfp3,+db";
       break;
 
     case kArm:
-      target_triple = "armv7-none-linux-gnueabi";
+      *target_triple = "armv7-none-linux-gnueabi";
       // TODO: Fix for Nexus S.
-      target_cpu = "cortex-a9";
+      *target_cpu = "cortex-a9";
       // TODO: Fix for Xoom.
-      target_attr = "+v7,+neon,+neonfp,+vfp3,+db";
+      *target_attr = "+v7,+neon,+neonfp,+vfp3,+db";
       break;
 
     case kX86:
-      target_triple = "i386-pc-linux-gnu";
-      target_attr = "";
+      *target_triple = "i386-pc-linux-gnu";
+      *target_attr = "";
       break;
 
     case kMips:
-      target_triple = "mipsel-unknown-linux";
-      target_attr = "mips32r2";
+      *target_triple = "mipsel-unknown-linux";
+      *target_attr = "mips32r2";
       break;
 
     default:
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 377eb6f..6ccbf0f 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -48,7 +48,7 @@
 class CompilerOptions;
 class DexCompilationUnit;
 class DexFileToMethodInlinerMap;
-class InlineIGetIPutData;
+struct InlineIGetIPutData;
 class OatWriter;
 class ParallelCompilationManager;
 class TimingLogger;
@@ -108,11 +108,11 @@
   ~CompilerDriver();
 
   void CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                  TimingLogger& timings)
+                  TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   // Compile a single Method.
-  void CompileOne(mirror::ArtMethod* method, TimingLogger& timings)
+  void CompileOne(mirror::ArtMethod* method, TimingLogger* timings)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   VerificationResults* GetVerificationResults() const {
@@ -123,16 +123,15 @@
     return method_inliner_map_;
   }
 
-  const InstructionSet& GetInstructionSet() const {
+  InstructionSet GetInstructionSet() const {
     return instruction_set_;
   }
 
-  const InstructionSetFeatures& GetInstructionSetFeatures() const {
+  InstructionSetFeatures GetInstructionSetFeatures() const {
     return instruction_set_features_;
   }
 
   const CompilerOptions& GetCompilerOptions() const {
-    DCHECK(compiler_options_ != nullptr);
     return *compiler_options_;
   }
 
@@ -275,21 +274,21 @@
     support_boot_image_fixup_ = support_boot_image_fixup;
   }
 
-  ArenaPool& GetArenaPool() {
-    return arena_pool_;
+  ArenaPool* GetArenaPool() {
+    return &arena_pool_;
   }
 
   bool WriteElf(const std::string& android_root,
                 bool is_host,
                 const std::vector<const DexFile*>& dex_files,
-                OatWriter& oat_writer,
+                OatWriter* oat_writer,
                 File* file);
 
-  // TODO: move to a common home for llvm helpers once quick/portable are merged
+  // TODO: move to a common home for llvm helpers once quick/portable are merged.
   static void InstructionSetToLLVMTarget(InstructionSet instruction_set,
-                                         std::string& target_triple,
-                                         std::string& target_cpu,
-                                         std::string& target_attr);
+                                         std::string* target_triple,
+                                         std::string* target_cpu,
+                                         std::string* target_attr);
 
   void SetCompilerContext(void* compiler_context) {
     compiler_context_ = compiler_context;
@@ -310,8 +309,8 @@
     return dump_passes_;
   }
 
-  CumulativeLogger& GetTimingsLogger() const {
-    return *timings_logger_;
+  CumulativeLogger* GetTimingsLogger() const {
+    return timings_logger_;
   }
 
   class PatchInformation {
@@ -494,6 +493,15 @@
   std::vector<uint8_t>* DeduplicateMappingTable(const std::vector<uint8_t>& code);
   std::vector<uint8_t>* DeduplicateVMapTable(const std::vector<uint8_t>& code);
   std::vector<uint8_t>* DeduplicateGCMap(const std::vector<uint8_t>& code);
+  std::vector<uint8_t>* DeduplicateCFIInfo(const std::vector<uint8_t>* cfi_info);
+
+  /*
+   * @brief return the pointer to the Call Frame Information.
+   * @return pointer to call frame information for this compilation.
+   */
+  std::vector<uint8_t>* GetCallFrameInformation() const {
+    return cfi_info_.get();
+  }
 
  private:
   // Compute constant code and method pointers when possible
@@ -507,43 +515,42 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                  ThreadPool& thread_pool, TimingLogger& timings)
+                  ThreadPool* thread_pool, TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
-  void LoadImageClasses(TimingLogger& timings);
+  void LoadImageClasses(TimingLogger* timings);
 
   // Attempt to resolve all type, methods, fields, and strings
   // referenced from code in the dex file following PathClassLoader
   // ordering semantics.
   void Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-               ThreadPool& thread_pool, TimingLogger& timings)
+               ThreadPool* thread_pool, TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
   void ResolveDexFile(jobject class_loader, const DexFile& dex_file,
-                      ThreadPool& thread_pool, TimingLogger& timings)
+                      ThreadPool* thread_pool, TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   void Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-              ThreadPool& thread_pool, TimingLogger& timings);
+              ThreadPool* thread_pool, TimingLogger* timings);
   void VerifyDexFile(jobject class_loader, const DexFile& dex_file,
-                     ThreadPool& thread_pool, TimingLogger& timings)
+                     ThreadPool* thread_pool, TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   void InitializeClasses(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                         ThreadPool& thread_pool, TimingLogger& timings)
+                         ThreadPool* thread_pool, TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
   void InitializeClasses(jobject class_loader, const DexFile& dex_file,
-                         ThreadPool& thread_pool, TimingLogger& timings)
+                         ThreadPool* thread_pool, TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_, compiled_classes_lock_);
 
-  void UpdateImageClasses(TimingLogger& timings)
-      LOCKS_EXCLUDED(Locks::mutator_lock_);
+  void UpdateImageClasses(TimingLogger* timings) LOCKS_EXCLUDED(Locks::mutator_lock_);
   static void FindClinitImageClassesCallback(mirror::Object* object, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-               ThreadPool& thread_pool, TimingLogger& timings);
+               ThreadPool* thread_pool, TimingLogger* timings);
   void CompileDexFile(jobject class_loader, const DexFile& dex_file,
-                      ThreadPool& thread_pool, TimingLogger& timings)
+                      ThreadPool* thread_pool, TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
   void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
                      InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx,
@@ -627,6 +634,9 @@
 
   bool support_boot_image_fixup_;
 
+  // Call Frame Information, which might be generated to help stack tracebacks.
+  UniquePtr<std::vector<uint8_t> > cfi_info_;
+
   // DeDuplication data structures, these own the corresponding byte arrays.
   class DedupeHashFunc {
    public:
@@ -665,6 +675,7 @@
   DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_mapping_table_;
   DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_vmap_table_;
   DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_gc_map_;
+  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_cfi_info_;
 
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
 };
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 34806ce..2b3af62 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -40,7 +40,7 @@
     timings.StartSplit("CompileAll");
     compiler_driver_->CompileAll(class_loader,
                                  Runtime::Current()->GetCompileTimeClassPath(class_loader),
-                                 timings);
+                                 &timings);
     MakeAllExecutable(class_loader);
     timings.EndSplit();
   }
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 9f6745b..39738ab 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -43,7 +43,8 @@
     large_method_threshold_(kDefaultLargeMethodThreshold),
     small_method_threshold_(kDefaultSmallMethodThreshold),
     tiny_method_threshold_(kDefaultTinyMethodThreshold),
-    num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold)
+    num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold),
+    generate_gdb_information_(false)
 #ifdef ART_SEA_IR_MODE
     , sea_ir_mode_(false)
 #endif
@@ -54,7 +55,8 @@
                   size_t large_method_threshold,
                   size_t small_method_threshold,
                   size_t tiny_method_threshold,
-                  size_t num_dex_methods_threshold
+                  size_t num_dex_methods_threshold,
+                  bool generate_gdb_information
 #ifdef ART_SEA_IR_MODE
                   , bool sea_ir_mode
 #endif
@@ -64,7 +66,8 @@
     large_method_threshold_(large_method_threshold),
     small_method_threshold_(small_method_threshold),
     tiny_method_threshold_(tiny_method_threshold),
-    num_dex_methods_threshold_(num_dex_methods_threshold)
+    num_dex_methods_threshold_(num_dex_methods_threshold),
+    generate_gdb_information_(generate_gdb_information)
 #ifdef ART_SEA_IR_MODE
     , sea_ir_mode_(sea_ir_mode)
 #endif
@@ -118,6 +121,10 @@
   bool GetSeaIrMode();
 #endif
 
+  bool GetGenerateGDBInformation() const {
+    return generate_gdb_information_;
+  }
+
  private:
   CompilerFilter compiler_filter_;
   size_t huge_method_threshold_;
@@ -125,6 +132,7 @@
   size_t small_method_threshold_;
   size_t tiny_method_threshold_;
   size_t num_dex_methods_threshold_;
+  bool generate_gdb_information_;
 
 #ifdef ART_SEA_IR_MODE
   bool sea_ir_mode_;
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index 6db3fa1..ccc26a1 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -30,12 +30,7 @@
 
 namespace art {
 
-ElfWriter::ElfWriter(const CompilerDriver& driver, File* elf_file)
-  : compiler_driver_(&driver), elf_file_(elf_file) {}
-
-ElfWriter::~ElfWriter() {}
-
-Elf32_Addr ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
+uint32_t ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
   Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(SHT_DYNSYM,
                                                            "oatdata",
                                                            false);
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index 99dfc56..3610d1a 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -23,7 +23,6 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "elf_utils.h"
 #include "os.h"
 
 namespace art {
@@ -42,21 +41,23 @@
                                    size_t& oat_data_offset);
 
   // Returns runtime oat_data runtime address for an opened ElfFile.
-  static Elf32_Addr GetOatDataAddress(ElfFile* elf_file);
+  static uint32_t GetOatDataAddress(ElfFile* elf_file);
 
  protected:
-  ElfWriter(const CompilerDriver& driver, File* elf_file);
-  virtual ~ElfWriter();
+  ElfWriter(const CompilerDriver& driver, File* elf_file)
+    : compiler_driver_(&driver), elf_file_(elf_file) {
+  }
 
-  virtual bool Write(OatWriter& oat_writer,
+  virtual ~ElfWriter() {}
+
+  virtual bool Write(OatWriter* oat_writer,
                      const std::vector<const DexFile*>& dex_files,
                      const std::string& android_root,
                      bool is_host)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
 
-  // Setup by constructor
-  const CompilerDriver* compiler_driver_;
-  File* elf_file_;
+  const CompilerDriver* const compiler_driver_;
+  File* const elf_file_;
 };
 
 }  // namespace art
diff --git a/compiler/elf_writer_mclinker.cc b/compiler/elf_writer_mclinker.cc
index c7baf4f..b2d3a69 100644
--- a/compiler/elf_writer_mclinker.cc
+++ b/compiler/elf_writer_mclinker.cc
@@ -16,6 +16,7 @@
 
 #include "elf_writer_mclinker.h"
 
+#include <llvm/Support/ELF.h>
 #include <llvm/Support/TargetSelect.h>
 
 #include <mcld/Environment.h>
@@ -32,7 +33,6 @@
 #include "class_linker.h"
 #include "dex_method_iterator.h"
 #include "driver/compiler_driver.h"
-#include "elf_file.h"
 #include "globals.h"
 #include "mirror/art_method.h"
 #include "mirror/art_method-inl.h"
@@ -44,12 +44,14 @@
 namespace art {
 
 ElfWriterMclinker::ElfWriterMclinker(const CompilerDriver& driver, File* elf_file)
-  : ElfWriter(driver, elf_file), oat_input_(NULL) {}
+  : ElfWriter(driver, elf_file), oat_input_(nullptr) {
+}
 
-ElfWriterMclinker::~ElfWriterMclinker() {}
+ElfWriterMclinker::~ElfWriterMclinker() {
+}
 
 bool ElfWriterMclinker::Create(File* elf_file,
-                               OatWriter& oat_writer,
+                               OatWriter* oat_writer,
                                const std::vector<const DexFile*>& dex_files,
                                const std::string& android_root,
                                bool is_host,
@@ -58,29 +60,29 @@
   return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
 }
 
-bool ElfWriterMclinker::Write(OatWriter& oat_writer,
+bool ElfWriterMclinker::Write(OatWriter* oat_writer,
                               const std::vector<const DexFile*>& dex_files,
                               const std::string& android_root,
                               bool is_host) {
   std::vector<uint8_t> oat_contents;
-  oat_contents.reserve(oat_writer.GetSize());
+  oat_contents.reserve(oat_writer->GetSize());
   VectorOutputStream output_stream("oat contents", oat_contents);
-  CHECK(oat_writer.Write(output_stream));
-  CHECK_EQ(oat_writer.GetSize(), oat_contents.size());
+  CHECK(oat_writer->Write(&output_stream));
+  CHECK_EQ(oat_writer->GetSize(), oat_contents.size());
 
   Init();
   AddOatInput(oat_contents);
-#if defined(ART_USE_PORTABLE_COMPILER)
-  AddMethodInputs(dex_files);
-  AddRuntimeInputs(android_root, is_host);
-#endif
+  if (kUsePortableCompiler) {
+    AddMethodInputs(dex_files);
+    AddRuntimeInputs(android_root, is_host);
+  }
   if (!Link()) {
     return false;
   }
   oat_contents.clear();
-#if defined(ART_USE_PORTABLE_COMPILER)
-  FixupOatMethodOffsets(dex_files);
-#endif
+  if (kUsePortableCompiler) {
+    FixupOatMethodOffsets(dex_files);
+  }
   return true;
 }
 
@@ -100,9 +102,9 @@
   std::string target_cpu;
   std::string target_attr;
   CompilerDriver::InstructionSetToLLVMTarget(compiler_driver_->GetInstructionSet(),
-                                             target_triple,
-                                             target_cpu,
-                                             target_attr);
+                                             &target_triple,
+                                             &target_cpu,
+                                             &target_attr);
 
   // Based on mclinker's llvm-mcld.cpp main() and LinkerTest
   //
@@ -236,7 +238,6 @@
                          text_section);
 }
 
-#if defined(ART_USE_PORTABLE_COMPILER)
 void ElfWriterMclinker::AddMethodInputs(const std::vector<const DexFile*>& dex_files) {
   DCHECK(oat_input_ != NULL);
 
@@ -320,7 +321,6 @@
   mcld::Input* libm_lib_input_input = ir_builder_->ReadInput(libm_lib, libm_lib);
   CHECK(libm_lib_input_input != NULL);
 }
-#endif
 
 bool ElfWriterMclinker::Link() {
   // link inputs
@@ -345,7 +345,6 @@
   return true;
 }
 
-#if defined(ART_USE_PORTABLE_COMPILER)
 void ElfWriterMclinker::FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files) {
   std::string error_msg;
   UniquePtr<ElfFile> elf_file(ElfFile::Open(elf_file_, true, false, &error_msg));
@@ -409,6 +408,5 @@
   }
   return compiled_code_offset;
 }
-#endif
 
 }  // namespace art
diff --git a/compiler/elf_writer_mclinker.h b/compiler/elf_writer_mclinker.h
index 8ee7231..13757ed 100644
--- a/compiler/elf_writer_mclinker.h
+++ b/compiler/elf_writer_mclinker.h
@@ -37,11 +37,11 @@
 
 class CompiledCode;
 
-class ElfWriterMclinker : public ElfWriter {
+class ElfWriterMclinker FINAL : public ElfWriter {
  public:
   // Write an ELF file. Returns true on success, false on failure.
   static bool Create(File* file,
-                     OatWriter& oat_writer,
+                     OatWriter* oat_writer,
                      const std::vector<const DexFile*>& dex_files,
                      const std::string& android_root,
                      bool is_host,
@@ -49,10 +49,11 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  protected:
-  virtual bool Write(OatWriter& oat_writer,
-                     const std::vector<const DexFile*>& dex_files,
-                     const std::string& android_root,
-                     bool is_host)
+  bool Write(OatWriter* oat_writer,
+             const std::vector<const DexFile*>& dex_files,
+             const std::string& android_root,
+             bool is_host)
+      OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
@@ -65,13 +66,11 @@
   void AddCompiledCodeInput(const CompiledCode& compiled_code);
   void AddRuntimeInputs(const std::string& android_root, bool is_host);
   bool Link();
-#if defined(ART_USE_PORTABLE_COMPILER)
   void FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   uint32_t FixupCompiledCodeOffset(ElfFile& elf_file,
-                                   ::llvm::ELF::Elf32_Addr oatdata_address,
+                                   uint32_t oatdata_address,
                                    const CompiledCode& compiled_code);
-#endif
 
   // Setup by Init()
   UniquePtr<mcld::LinkerConfig> linker_config_;
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 3191374..4b823ef 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -29,13 +29,8 @@
 
 namespace art {
 
-ElfWriterQuick::ElfWriterQuick(const CompilerDriver& driver, File* elf_file)
-  : ElfWriter(driver, elf_file) {}
-
-ElfWriterQuick::~ElfWriterQuick() {}
-
 bool ElfWriterQuick::Create(File* elf_file,
-                            OatWriter& oat_writer,
+                            OatWriter* oat_writer,
                             const std::vector<const DexFile*>& dex_files,
                             const std::string& android_root,
                             bool is_host,
@@ -44,7 +39,7 @@
   return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
 }
 
-bool ElfWriterQuick::Write(OatWriter& oat_writer,
+bool ElfWriterQuick::Write(OatWriter* oat_writer,
                            const std::vector<const DexFile*>& dex_files_unused,
                            const std::string& android_root_unused,
                            bool is_host_unused) {
@@ -103,6 +98,7 @@
   // | .rodata\0               |
   // | .text\0                 |
   // | .shstrtab\0             |
+  // | .debug_frame\0          |
   // +-------------------------+
   // | Elf32_Shdr NULL         |
   // | Elf32_Shdr .dynsym      |
@@ -112,6 +108,9 @@
   // | Elf32_Shdr .rodata      |
   // | Elf32_Shdr .dynamic     |
   // | Elf32_Shdr .shstrtab    |
+  // | Elf32_Shdr .debug_info  |  (Optional)
+  // | Elf32_Shdr .debug_abbrev|  (Optional)
+  // | Elf32_Shdr .debug_frame |  (Optional)
   // +-------------------------+
 
   // phase 1: computing offsets
@@ -197,7 +196,7 @@
   // .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();
+  const OatHeader& oat_header = oat_writer->GetOatHeader();
   CHECK(oat_header.IsValid());
   uint32_t oat_data_size = oat_header.GetExecutableOffset();
   expected_offset += oat_data_size;
@@ -210,9 +209,9 @@
   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;
+  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);
+  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;
@@ -264,6 +263,18 @@
   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) {
@@ -271,6 +282,52 @@
     LOG(INFO) << "shstrtab_size=" << shstrtab_size << std::hex << " " << shstrtab_size;
   }
 
+  // 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);
+  }
+
+  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;
+  }
+
+  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;
+  }
+
+  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);
@@ -282,7 +339,11 @@
   const uint8_t SH_TEXT     = 5;
   const uint8_t SH_DYNAMIC  = 6;
   const uint8_t SH_SHSTRTAB = 7;
-  const uint8_t SH_NUM      = 8;
+  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) {
@@ -559,6 +620,52 @@
   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;
+  }
+
   // phase 3: writing file
 
   // Elf32_Ehdr
@@ -622,13 +729,13 @@
     return false;
   }
   BufferedOutputStream output_stream(new FileOutputStream(elf_file_));
-  if (!oat_writer.Write(output_stream)) {
+  if (!oat_writer->Write(&output_stream)) {
     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);
+  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();
@@ -651,8 +758,62 @@
     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)
-  DCHECK_LE(shstrtab_offset + shstrtab_size, shdr_offset);
+  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();
@@ -665,6 +826,164 @@
 
   VLOG(compiler) << "ELF file written successfully: " << elf_file_->GetPath();
   return true;
+}  // NOLINT(readability/fn_size)
+
+static void UpdateWord(std::vector<uint8_t>*buf, int offset, int data) {
+  (*buf)[offset+0] = data;
+  (*buf)[offset+1] = data >> 8;
+  (*buf)[offset+2] = data >> 16;
+  (*buf)[offset+3] = data >> 24;
+}
+
+static void PushWord(std::vector<uint8_t>*buf, int data) {
+  buf->push_back(data & 0xff);
+  buf->push_back((data >> 8) & 0xff);
+  buf->push_back((data >> 16) & 0xff);
+  buf->push_back((data >> 24) & 0xff);
+}
+
+static void PushHalf(std::vector<uint8_t>*buf, int data) {
+  buf->push_back(data & 0xff);
+  buf->push_back((data >> 8) & 0xff);
+}
+
+// DWARF constants needed to generate CFI information.
+enum {
+  // Tag encodings.
+  DW_TAG_compile_unit = 0x11,
+  DW_TAG_subprogram = 0X2e,
+
+  // Attribute encodings.
+  DW_AT_name = 0x03,
+  DW_AT_low_pc = 0x11,
+  DW_AT_high_pc = 0x12,
+  DW_AT_language = 0x13,
+
+  // Constant encoding.
+  DW_CHILDREN_no = 0x00,
+  DW_CHILDREN_yes = 0x01,
+
+  // Attribute form encodings.
+  DW_FORM_addr = 0x01,
+  DW_FORM_data1 = 0x0b,
+  DW_FORM_strp = 0x0e,
+
+  // Language encoding.
+  DW_LANG_Java = 0x000b
+};
+
+void ElfWriterQuick::FillInCFIInformation(OatWriter* oat_writer,
+                                          std::vector<uint8_t>* dbg_info,
+                                          std::vector<uint8_t>* dbg_abbrev,
+                                          std::vector<uint8_t>* dbg_str) {
+  // Create the debug_abbrev section with boilerplate information.
+  // We only care about low_pc and high_pc right now for the compilation
+  // unit and methods.
+
+  // Tag 1: Compilation unit: DW_TAG_compile_unit.
+  dbg_abbrev->push_back(1);
+  dbg_abbrev->push_back(DW_TAG_compile_unit);
+
+  // There are children (the methods).
+  dbg_abbrev->push_back(DW_CHILDREN_yes);
+
+  // DW_LANG_Java DW_FORM_data1.
+  dbg_abbrev->push_back(DW_AT_language);
+  dbg_abbrev->push_back(DW_FORM_data1);
+
+  // DW_AT_low_pc DW_FORM_addr.
+  dbg_abbrev->push_back(DW_AT_low_pc);
+  dbg_abbrev->push_back(DW_FORM_addr);
+
+  // DW_AT_high_pc DW_FORM_addr.
+  dbg_abbrev->push_back(DW_AT_high_pc);
+  dbg_abbrev->push_back(DW_FORM_addr);
+
+  // End of DW_TAG_compile_unit.
+  PushHalf(dbg_abbrev, 0);
+
+  // Tag 2: Compilation unit: DW_TAG_subprogram.
+  dbg_abbrev->push_back(2);
+  dbg_abbrev->push_back(DW_TAG_subprogram);
+
+  // There are no children.
+  dbg_abbrev->push_back(DW_CHILDREN_no);
+
+  // Name of the method.
+  dbg_abbrev->push_back(DW_AT_name);
+  dbg_abbrev->push_back(DW_FORM_strp);
+
+  // DW_AT_low_pc DW_FORM_addr.
+  dbg_abbrev->push_back(DW_AT_low_pc);
+  dbg_abbrev->push_back(DW_FORM_addr);
+
+  // DW_AT_high_pc DW_FORM_addr.
+  dbg_abbrev->push_back(DW_AT_high_pc);
+  dbg_abbrev->push_back(DW_FORM_addr);
+
+  // End of DW_TAG_subprogram.
+  PushHalf(dbg_abbrev, 0);
+
+  // Start the debug_info section with the header information
+  // 'unit_length' will be filled in later.
+  PushWord(dbg_info, 0);
+
+  // 'version' - 3.
+  PushHalf(dbg_info, 3);
+
+  // Offset into .debug_abbrev section (always 0).
+  PushWord(dbg_info, 0);
+
+  // Address size: 4.
+  dbg_info->push_back(4);
+
+  // Start the description for the compilation unit.
+  // This uses tag 1.
+  dbg_info->push_back(1);
+
+  // The language is Java.
+  dbg_info->push_back(DW_LANG_Java);
+
+  // Leave space for low_pc and high_pc.
+  int low_pc_offset = dbg_info->size();
+  PushWord(dbg_info, 0);
+  PushWord(dbg_info, 0);
+
+  // Walk through the information in the method table, and enter into dbg_info.
+  const std::vector<OatWriter::DebugInfo>& dbg = oat_writer->GetCFIMethodInfo();
+  uint32_t low_pc = 0xFFFFFFFFU;
+  uint32_t high_pc = 0;
+
+  for (uint32_t i = 0; i < dbg.size(); i++) {
+    const OatWriter::DebugInfo& info = dbg[i];
+    if (info.low_pc_ < low_pc) {
+      low_pc = info.low_pc_;
+    }
+    if (info.high_pc_ > high_pc) {
+      high_pc = info.high_pc_;
+    }
+
+    // Start a new TAG: subroutine (2).
+    dbg_info->push_back(2);
+
+    // Enter the name into the string table (and NUL terminate).
+    uint32_t str_offset = dbg_str->size();
+    dbg_str->insert(dbg_str->end(), info.method_name_.begin(), info.method_name_.end());
+    dbg_str->push_back('\0');
+
+    // Enter name, low_pc, high_pc.
+    PushWord(dbg_info, str_offset);
+    PushWord(dbg_info, info.low_pc_);
+    PushWord(dbg_info, info.high_pc_);
+  }
+
+  // One byte terminator
+  dbg_info->push_back(0);
+
+  // We have now walked all the methods.  Fill in lengths and low/high PCs.
+  UpdateWord(dbg_info, 0, dbg_info->size() - 4);
+  UpdateWord(dbg_info, low_pc_offset, low_pc);
+  UpdateWord(dbg_info, low_pc_offset + 4, high_pc);
 }
 
 }  // namespace art
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index f36d06f..dec75dc 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -21,11 +21,11 @@
 
 namespace art {
 
-class ElfWriterQuick : public ElfWriter {
+class ElfWriterQuick FINAL : public ElfWriter {
  public:
   // Write an ELF file. Returns true on success, false on failure.
   static bool Create(File* file,
-                     OatWriter& oat_writer,
+                     OatWriter* oat_writer,
                      const std::vector<const DexFile*>& dex_files,
                      const std::string& android_root,
                      bool is_host,
@@ -33,15 +33,27 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  protected:
-  virtual bool Write(OatWriter& oat_writer,
-                     const std::vector<const DexFile*>& dex_files,
-                     const std::string& android_root,
-                     bool is_host)
+  bool Write(OatWriter* oat_writer,
+             const std::vector<const DexFile*>& dex_files,
+             const std::string& android_root,
+             bool is_host)
+      OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
-  ElfWriterQuick(const CompilerDriver& driver, File* elf_file);
-  ~ElfWriterQuick();
+  ElfWriterQuick(const CompilerDriver& driver, File* elf_file)
+    : ElfWriter(driver, elf_file) {}
+  ~ElfWriterQuick() {}
+
+  /*
+   * @brief Generate the DWARF debug_info and debug_abbrev sections
+   * @param oat_writer The Oat file Writer.
+   * @param dbg_info Compilation unit information.
+   * @param dbg_abbrev Abbreviations used to generate dbg_info.
+   * @param dbg_str Debug strings.
+   */
+  void FillInCFIInformation(OatWriter* oat_writer, std::vector<uint8_t>* dbg_info,
+                            std::vector<uint8_t>* dbg_abbrev, std::vector<uint8_t>* dbg_str);
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick);
 };
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 16e2aa2..619b056 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -49,15 +49,15 @@
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
       TimingLogger timings("ImageTest::WriteRead", false, false);
       timings.StartSplit("CompileAll");
-#if defined(ART_USE_PORTABLE_COMPILER)
-      // TODO: we disable this for portable so the test executes in a reasonable amount of time.
-      //       We shouldn't need to do this.
-      runtime_->SetCompilerFilter(Runtime::kInterpretOnly);
-#endif
+      if (kUsePortableCompiler) {
+        // TODO: we disable this for portable so the test executes in a reasonable amount of time.
+        //       We shouldn't need to do this.
+        compiler_options_->SetCompilerFilter(CompilerOptions::kInterpretOnly);
+      }
       for (const DexFile* dex_file : class_linker->GetBootClassPath()) {
         dex_file->EnableWrite();
       }
-      compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
+      compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
 
       ScopedObjectAccess soa(Thread::Current());
       OatWriter oat_writer(class_linker->GetBootClassPath(),
@@ -65,7 +65,7 @@
       bool success = compiler_driver_->WriteElf(GetTestAndroidRoot(),
                                                 !kIsTargetBuild,
                                                 class_linker->GetBootClassPath(),
-                                                oat_writer,
+                                                &oat_writer,
                                                 tmp_elf.GetFile());
       ASSERT_TRUE(success);
       timings.EndSplit();
diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc
index a5acd2a..4ce714a 100644
--- a/compiler/llvm/compiler_llvm.cc
+++ b/compiler/llvm/compiler_llvm.cc
@@ -175,16 +175,16 @@
 }  // namespace llvm
 }  // namespace art
 
-inline static art::llvm::CompilerLLVM* ContextOf(art::CompilerDriver& driver) {
+static art::llvm::CompilerLLVM* ContextOf(art::CompilerDriver& driver) {
   void *compiler_context = driver.GetCompilerContext();
   CHECK(compiler_context != NULL);
   return reinterpret_cast<art::llvm::CompilerLLVM*>(compiler_context);
 }
 
-inline static const art::llvm::CompilerLLVM* ContextOf(const art::CompilerDriver& driver) {
+static art::llvm::CompilerLLVM* ContextOf(const art::CompilerDriver& driver) {
   void *compiler_context = driver.GetCompilerContext();
   CHECK(compiler_context != NULL);
-  return reinterpret_cast<const art::llvm::CompilerLLVM*>(compiler_context);
+  return reinterpret_cast<art::llvm::CompilerLLVM*>(compiler_context);
 }
 
 extern "C" void ArtInitCompilerContext(art::CompilerDriver& driver) {
@@ -233,7 +233,7 @@
   return result;
 }
 
-extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver,
-                                               std::string const& filename) {
+extern "C" void compilerLLVMSetBitcodeFileName(const art::CompilerDriver& driver,
+                                               const std::string& filename) {
   ContextOf(driver)->SetBitcodeFileName(filename);
 }
diff --git a/compiler/llvm/compiler_llvm.h b/compiler/llvm/compiler_llvm.h
index 65bc16b..c2211fb 100644
--- a/compiler/llvm/compiler_llvm.h
+++ b/compiler/llvm/compiler_llvm.h
@@ -70,7 +70,7 @@
     return insn_set_;
   }
 
-  void SetBitcodeFileName(std::string const& filename) {
+  void SetBitcodeFileName(const std::string& filename) {
     bitcode_filename_ = filename;
   }
 
diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc
index d23706d..1d027f9 100644
--- a/compiler/llvm/llvm_compilation_unit.cc
+++ b/compiler/llvm/llvm_compilation_unit.cc
@@ -199,7 +199,8 @@
   std::string target_triple;
   std::string target_cpu;
   std::string target_attr;
-  CompilerDriver::InstructionSetToLLVMTarget(GetInstructionSet(), target_triple, target_cpu, target_attr);
+  CompilerDriver::InstructionSetToLLVMTarget(GetInstructionSet(), &target_triple, &target_cpu,
+                                             &target_attr);
 
   std::string errmsg;
   const ::llvm::Target* target =
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 55a962f..6dbba9f 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -105,7 +105,7 @@
   jobject class_loader = NULL;
   if (kCompile) {
     TimingLogger timings("OatTest::WriteRead", false, false);
-    compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
+    compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
   }
 
   ScopedObjectAccess soa(Thread::Current());
@@ -119,12 +119,12 @@
   bool success = compiler_driver_->WriteElf(GetTestAndroidRoot(),
                                             !kIsTargetBuild,
                                             class_linker->GetBootClassPath(),
-                                            oat_writer,
+                                            &oat_writer,
                                             tmp.GetFile());
   ASSERT_TRUE(success);
 
   if (kCompile) {  // OatWriter strips the code, regenerate to compare
-    compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
+    compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
   }
   std::string error_msg;
   UniquePtr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), NULL, false,
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 7c5669a..a400bdd 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -229,7 +229,7 @@
       oat_classes_.push_back(oat_class);
       offset += oat_class->SizeOf();
     }
-    oat_dex_files_[i]->UpdateChecksum(*oat_header_);
+    oat_dex_files_[i]->UpdateChecksum(oat_header_);
   }
   return offset;
 }
@@ -293,7 +293,7 @@
        class_def_index++, (*oat_class_index)++) {
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
     offset = InitOatCodeClassDef(offset, *oat_class_index, class_def_index, dex_file, class_def);
-    oat_classes_[*oat_class_index]->UpdateChecksum(*oat_header_);
+    oat_classes_[*oat_class_index]->UpdateChecksum(oat_header_);
   }
   return offset;
 }
@@ -378,6 +378,27 @@
       uint32_t thumb_offset = compiled_method->CodeDelta();
       quick_code_offset = offset + sizeof(code_size) + thumb_offset;
 
+      std::vector<uint8_t>* cfi_info = compiler_driver_->GetCallFrameInformation();
+      if (cfi_info != nullptr) {
+      // Copy in the FDE, if present
+      const std::vector<uint8_t>* fde = compiled_method->GetCFIInfo();
+        if (fde != nullptr) {
+          // Copy the information into cfi_info and then fix the address in the new copy.
+          int cur_offset = cfi_info->size();
+          cfi_info->insert(cfi_info->end(), fde->begin(), fde->end());
+
+          // Set the 'initial_location' field to address the start of the method.
+          uint32_t new_value = quick_code_offset - oat_header_->GetExecutableOffset();
+          uint32_t offset_to_update = cur_offset + 2*sizeof(uint32_t);
+          (*cfi_info)[offset_to_update+0] = new_value;
+          (*cfi_info)[offset_to_update+1] = new_value >> 8;
+          (*cfi_info)[offset_to_update+2] = new_value >> 16;
+          (*cfi_info)[offset_to_update+3] = new_value >> 24;
+          method_info_.push_back(DebugInfo(PrettyMethod(class_def_method_index, dex_file, false),
+                                           new_value, new_value + code_size));
+        }
+      }
+
       // Deduplicate code arrays
       SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter =
           code_offsets_.find(quick_code);
@@ -499,42 +520,42 @@
 }
 
 #define DCHECK_OFFSET() \
-  DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out.Seek(0, kSeekCurrent)) \
+  DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
     << "file_offset=" << file_offset << " relative_offset=" << relative_offset
 
 #define DCHECK_OFFSET_() \
-  DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out.Seek(0, kSeekCurrent)) \
+  DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
     << "file_offset=" << file_offset << " offset_=" << offset_
 
-bool OatWriter::Write(OutputStream& out) {
-  const size_t file_offset = out.Seek(0, kSeekCurrent);
+bool OatWriter::Write(OutputStream* out) {
+  const size_t file_offset = out->Seek(0, kSeekCurrent);
 
-  if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) {
-    PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
+  if (!out->WriteFully(oat_header_, sizeof(*oat_header_))) {
+    PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
     return false;
   }
   size_oat_header_ += sizeof(*oat_header_);
 
-  if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
-    PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
+  if (!out->WriteFully(image_file_location_.data(), image_file_location_.size())) {
+    PLOG(ERROR) << "Failed to write oat header image file location to " << out->GetLocation();
     return false;
   }
   size_oat_header_image_file_location_ += image_file_location_.size();
 
   if (!WriteTables(out, file_offset)) {
-    LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
+    LOG(ERROR) << "Failed to write oat tables to " << out->GetLocation();
     return false;
   }
 
   size_t relative_offset = WriteCode(out, file_offset);
   if (relative_offset == 0) {
-    LOG(ERROR) << "Failed to write oat code to " << out.GetLocation();
+    LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
     return false;
   }
 
   relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
   if (relative_offset == 0) {
-    LOG(ERROR) << "Failed to write oat code for dex files to " << out.GetLocation();
+    LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
     return false;
   }
 
@@ -577,26 +598,26 @@
     #undef DO_STAT
 
     VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
-    CHECK_EQ(file_offset + size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+    CHECK_EQ(file_offset + size_total, static_cast<uint32_t>(out->Seek(0, kSeekCurrent)));
     CHECK_EQ(size_, size_total);
   }
 
-  CHECK_EQ(file_offset + size_, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+  CHECK_EQ(file_offset + size_, static_cast<uint32_t>(out->Seek(0, kSeekCurrent)));
   CHECK_EQ(size_, relative_offset);
 
   return true;
 }
 
-bool OatWriter::WriteTables(OutputStream& out, const size_t file_offset) {
+bool OatWriter::WriteTables(OutputStream* out, const size_t file_offset) {
   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
     if (!oat_dex_files_[i]->Write(this, out, file_offset)) {
-      PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
+      PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
       return false;
     }
   }
   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
     uint32_t expected_offset = file_offset + oat_dex_files_[i]->dex_file_offset_;
-    off_t actual_offset = out.Seek(expected_offset, kSeekSet);
+    off_t actual_offset = out->Seek(expected_offset, kSeekSet);
     if (static_cast<uint32_t>(actual_offset) != expected_offset) {
       const DexFile* dex_file = (*dex_files_)[i];
       PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
@@ -604,29 +625,29 @@
       return false;
     }
     const DexFile* dex_file = (*dex_files_)[i];
-    if (!out.WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
+    if (!out->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
       PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation()
-                  << " to " << out.GetLocation();
+                  << " to " << out->GetLocation();
       return false;
     }
     size_dex_file_ += dex_file->GetHeader().file_size_;
   }
   for (size_t i = 0; i != oat_classes_.size(); ++i) {
     if (!oat_classes_[i]->Write(this, out, file_offset)) {
-      PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
+      PLOG(ERROR) << "Failed to write oat methods information to " << out->GetLocation();
       return false;
     }
   }
   return true;
 }
 
-size_t OatWriter::WriteCode(OutputStream& out, const size_t file_offset) {
+size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset) {
   size_t relative_offset = oat_header_->GetExecutableOffset();
-  off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
+  off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
   size_t expected_file_offset = file_offset + relative_offset;
   if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
-                << " Expected: " << expected_file_offset << " File: " << out.GetLocation();
+                << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
     return 0;
   }
   DCHECK_OFFSET();
@@ -637,10 +658,10 @@
       do { \
         uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
         uint32_t alignment_padding = aligned_offset - relative_offset; \
-        out.Seek(alignment_padding, kSeekCurrent); \
+        out->Seek(alignment_padding, kSeekCurrent); \
         size_trampoline_alignment_ += alignment_padding; \
-        if (!out.WriteFully(&(*field)[0], field->size())) { \
-          PLOG(ERROR) << "Failed to write " # field " to " << out.GetLocation(); \
+        if (!out->WriteFully(&(*field)[0], field->size())) { \
+          PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
           return false; \
         } \
         size_ ## field += field->size(); \
@@ -662,7 +683,7 @@
   return relative_offset;
 }
 
-size_t OatWriter::WriteCodeDexFiles(OutputStream& out,
+size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
                                     const size_t file_offset,
                                     size_t relative_offset) {
   size_t oat_class_index = 0;
@@ -678,7 +699,7 @@
   return relative_offset;
 }
 
-size_t OatWriter::WriteCodeDexFile(OutputStream& out, const size_t file_offset,
+size_t OatWriter::WriteCodeDexFile(OutputStream* out, const size_t file_offset,
                                    size_t relative_offset, size_t* oat_class_index,
                                    const DexFile& dex_file) {
   for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
@@ -694,12 +715,12 @@
 }
 
 void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
-                                   const DexFile& dex_file, OutputStream& out) const {
+                                   const DexFile& dex_file, const OutputStream& out) const {
   PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file)
       << " to " << out.GetLocation();
 }
 
-size_t OatWriter::WriteCodeClassDef(OutputStream& out,
+size_t OatWriter::WriteCodeClassDef(OutputStream* out,
                                     const size_t file_offset,
                                     size_t relative_offset,
                                     size_t oat_class_index,
@@ -747,7 +768,7 @@
   return relative_offset;
 }
 
-size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
+size_t OatWriter::WriteCodeMethod(OutputStream* out, const size_t file_offset,
                                   size_t relative_offset, size_t oat_class_index,
                                   size_t class_def_method_index, size_t* method_offsets_index,
                                   bool is_static, uint32_t method_idx, const DexFile& dex_file) {
@@ -763,12 +784,12 @@
       uint32_t aligned_offset = compiled_method->AlignCode(relative_offset);
       uint32_t aligned_code_delta = aligned_offset - relative_offset;
       if (aligned_code_delta != 0) {
-        off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
+        off_t new_offset = out->Seek(aligned_code_delta, kSeekCurrent);
         size_code_alignment_ += aligned_code_delta;
         uint32_t expected_offset = file_offset + aligned_offset;
         if (static_cast<uint32_t>(new_offset) != expected_offset) {
           PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
-              << " Expected: " << expected_offset << " File: " << out.GetLocation();
+              << " Expected: " << expected_offset << " File: " << out->GetLocation();
           return 0;
         }
         relative_offset += aligned_code_delta;
@@ -787,15 +808,15 @@
               << PrettyMethod(method_idx, dex_file);
       } else {
         DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
-        if (!out.WriteFully(&code_size, sizeof(code_size))) {
-          ReportWriteFailure("method code size", method_idx, dex_file, out);
+        if (!out->WriteFully(&code_size, sizeof(code_size))) {
+          ReportWriteFailure("method code size", method_idx, dex_file, *out);
           return 0;
         }
         size_code_size_ += sizeof(code_size);
         relative_offset += sizeof(code_size);
         DCHECK_OFFSET();
-        if (!out.WriteFully(&(*quick_code)[0], code_size)) {
-          ReportWriteFailure("method code", method_idx, dex_file, out);
+        if (!out->WriteFully(&(*quick_code)[0], code_size)) {
+          ReportWriteFailure("method code", method_idx, dex_file, *out);
           return 0;
         }
         size_code_ += code_size;
@@ -818,8 +839,8 @@
       DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
           || relative_offset == method_offsets.mapping_table_offset_)
           << PrettyMethod(method_idx, dex_file);
-      if (!out.WriteFully(&mapping_table[0], mapping_table_size)) {
-        ReportWriteFailure("mapping table", method_idx, dex_file, out);
+      if (!out->WriteFully(&mapping_table[0], mapping_table_size)) {
+        ReportWriteFailure("mapping table", method_idx, dex_file, *out);
         return 0;
       }
       size_mapping_table_ += mapping_table_size;
@@ -842,8 +863,8 @@
       DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
           || relative_offset == method_offsets.vmap_table_offset_)
           << PrettyMethod(method_idx, dex_file);
-      if (!out.WriteFully(&vmap_table[0], vmap_table_size)) {
-        ReportWriteFailure("vmap table", method_idx, dex_file, out);
+      if (!out->WriteFully(&vmap_table[0], vmap_table_size)) {
+        ReportWriteFailure("vmap table", method_idx, dex_file, *out);
         return 0;
       }
       size_vmap_table_ += vmap_table_size;
@@ -866,8 +887,8 @@
       DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
           || relative_offset == method_offsets.gc_map_offset_)
           << PrettyMethod(method_idx, dex_file);
-      if (!out.WriteFully(&gc_map[0], gc_map_size)) {
-        ReportWriteFailure("GC map", method_idx, dex_file, out);
+      if (!out->WriteFully(&gc_map[0], gc_map_size)) {
+        ReportWriteFailure("GC map", method_idx, dex_file, *out);
         return 0;
       }
       size_gc_map_ += gc_map_size;
@@ -897,42 +918,42 @@
           + (sizeof(methods_offsets_[0]) * methods_offsets_.size());
 }
 
-void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
-  oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
-  oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
-  oat_header.UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
-  oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
-  oat_header.UpdateChecksum(&methods_offsets_[0],
+void OatWriter::OatDexFile::UpdateChecksum(OatHeader* oat_header) const {
+  oat_header->UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
+  oat_header->UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
+  oat_header->UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
+  oat_header->UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
+  oat_header->UpdateChecksum(&methods_offsets_[0],
                             sizeof(methods_offsets_[0]) * methods_offsets_.size());
 }
 
 bool OatWriter::OatDexFile::Write(OatWriter* oat_writer,
-                                  OutputStream& out,
+                                  OutputStream* out,
                                   const size_t file_offset) const {
   DCHECK_OFFSET_();
-  if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
-    PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
+  if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
+    PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
     return false;
   }
   oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
-  if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
-    PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
+  if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
+    PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
     return false;
   }
   oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
-  if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
-    PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
+  if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
+    PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
     return false;
   }
   oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
-  if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
-    PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
+  if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
+    PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
     return false;
   }
   oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
-  if (!out.WriteFully(&methods_offsets_[0],
+  if (!out->WriteFully(&methods_offsets_[0],
                       sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
-    PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
+    PLOG(ERROR) << "Failed to write methods offsets to " << out->GetLocation();
     return false;
   }
   oat_writer->size_oat_dex_file_methods_offsets_ +=
@@ -1020,48 +1041,48 @@
           + (sizeof(method_offsets_[0]) * method_offsets_.size());
 }
 
-void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
-  oat_header.UpdateChecksum(&status_, sizeof(status_));
-  oat_header.UpdateChecksum(&type_, sizeof(type_));
+void OatWriter::OatClass::UpdateChecksum(OatHeader* oat_header) const {
+  oat_header->UpdateChecksum(&status_, sizeof(status_));
+  oat_header->UpdateChecksum(&type_, sizeof(type_));
   if (method_bitmap_size_ != 0) {
     CHECK_EQ(kOatClassSomeCompiled, type_);
-    oat_header.UpdateChecksum(&method_bitmap_size_, sizeof(method_bitmap_size_));
-    oat_header.UpdateChecksum(method_bitmap_->GetRawStorage(), method_bitmap_size_);
+    oat_header->UpdateChecksum(&method_bitmap_size_, sizeof(method_bitmap_size_));
+    oat_header->UpdateChecksum(method_bitmap_->GetRawStorage(), method_bitmap_size_);
   }
-  oat_header.UpdateChecksum(&method_offsets_[0],
-                            sizeof(method_offsets_[0]) * method_offsets_.size());
+  oat_header->UpdateChecksum(&method_offsets_[0],
+                             sizeof(method_offsets_[0]) * method_offsets_.size());
 }
 
 bool OatWriter::OatClass::Write(OatWriter* oat_writer,
-                                OutputStream& out,
+                                OutputStream* out,
                                 const size_t file_offset) const {
   DCHECK_OFFSET_();
-  if (!out.WriteFully(&status_, sizeof(status_))) {
-    PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
+  if (!out->WriteFully(&status_, sizeof(status_))) {
+    PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
     return false;
   }
   oat_writer->size_oat_class_status_ += sizeof(status_);
-  if (!out.WriteFully(&type_, sizeof(type_))) {
-    PLOG(ERROR) << "Failed to write oat class type to " << out.GetLocation();
+  if (!out->WriteFully(&type_, sizeof(type_))) {
+    PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
     return false;
   }
   oat_writer->size_oat_class_type_ += sizeof(type_);
   if (method_bitmap_size_ != 0) {
     CHECK_EQ(kOatClassSomeCompiled, type_);
-    if (!out.WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
-      PLOG(ERROR) << "Failed to write method bitmap size to " << out.GetLocation();
+    if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
+      PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
       return false;
     }
     oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
-    if (!out.WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
-      PLOG(ERROR) << "Failed to write method bitmap to " << out.GetLocation();
+    if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
+      PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
       return false;
     }
     oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
   }
-  if (!out.WriteFully(&method_offsets_[0],
+  if (!out->WriteFully(&method_offsets_[0],
                       sizeof(method_offsets_[0]) * method_offsets_.size())) {
-    PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
+    PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
     return false;
   }
   oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 067c789..3d4b48a 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -78,10 +78,23 @@
     return size_;
   }
 
-  bool Write(OutputStream& out);
+  bool Write(OutputStream* out);
 
   ~OatWriter();
 
+  struct DebugInfo {
+    DebugInfo(const std::string& method_name, uint32_t low_pc, uint32_t high_pc)
+      : method_name_(method_name), low_pc_(low_pc), high_pc_(high_pc) {
+    }
+    std::string method_name_;
+    uint32_t    low_pc_;
+    uint32_t    high_pc_;
+  };
+
+  const std::vector<DebugInfo>& GetCFIMethodInfo() const {
+    return method_info_;
+  }
+
  private:
   size_t InitOatHeader();
   size_t InitOatDexFiles(size_t offset);
@@ -105,28 +118,28 @@
                            bool is_native, InvokeType type, uint32_t method_idx, const DexFile&)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool WriteTables(OutputStream& out, const size_t file_offset);
-  size_t WriteCode(OutputStream& out, const size_t file_offset);
-  size_t WriteCodeDexFiles(OutputStream& out, const size_t file_offset, size_t relative_offset);
-  size_t WriteCodeDexFile(OutputStream& out, const size_t file_offset, size_t relative_offset,
+  bool WriteTables(OutputStream* out, const size_t file_offset);
+  size_t WriteCode(OutputStream* out, const size_t file_offset);
+  size_t WriteCodeDexFiles(OutputStream* out, const size_t file_offset, size_t relative_offset);
+  size_t WriteCodeDexFile(OutputStream* out, const size_t file_offset, size_t relative_offset,
                           size_t* oat_class_index, const DexFile& dex_file);
-  size_t WriteCodeClassDef(OutputStream& out, const size_t file_offset, size_t relative_offset,
+  size_t WriteCodeClassDef(OutputStream* out, const size_t file_offset, size_t relative_offset,
                            size_t oat_class_index, const DexFile& dex_file,
                            const DexFile::ClassDef& class_def);
-  size_t WriteCodeMethod(OutputStream& out, const size_t file_offset, size_t relative_offset,
+  size_t WriteCodeMethod(OutputStream* out, const size_t file_offset, size_t relative_offset,
                          size_t oat_class_index, size_t class_def_method_index,
                          size_t* method_offsets_index, bool is_static, uint32_t method_idx,
                          const DexFile& dex_file);
 
   void ReportWriteFailure(const char* what, uint32_t method_idx, const DexFile& dex_file,
-                          OutputStream& out) const;
+                          const OutputStream& out) const;
 
   class OatDexFile {
    public:
     explicit OatDexFile(size_t offset, const DexFile& dex_file);
     size_t SizeOf() const;
-    void UpdateChecksum(OatHeader& oat_header) const;
-    bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const;
+    void UpdateChecksum(OatHeader* oat_header) const;
+    bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
 
     // Offset of start of OatDexFile from beginning of OatHeader. It is
     // used to validate file position when writing.
@@ -153,8 +166,8 @@
     size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const;
     size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
     size_t SizeOf() const;
-    void UpdateChecksum(OatHeader& oat_header) const;
-    bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const;
+    void UpdateChecksum(OatHeader* oat_header) const;
+    bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
 
     CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
       DCHECK(compiled_methods_ != NULL);
@@ -205,6 +218,8 @@
     DISALLOW_COPY_AND_ASSIGN(OatClass);
   };
 
+  std::vector<DebugInfo> method_info_;
+
   const CompilerDriver* const compiler_driver_;
 
   // note OatFile does not take ownership of the DexFiles
diff --git a/compiler/utils/arena_bit_vector.cc b/compiler/utils/arena_bit_vector.cc
index 6f03524..220ff14 100644
--- a/compiler/utils/arena_bit_vector.cc
+++ b/compiler/utils/arena_bit_vector.cc
@@ -42,6 +42,8 @@
 
 ArenaBitVector::ArenaBitVector(ArenaAllocator* arena, unsigned int start_bits,
                                bool expandable, OatBitMapKind kind)
-  :  BitVector(start_bits, expandable, new (arena) ArenaBitVectorAllocator(arena)), kind_(kind) {}
+  :  BitVector(start_bits, expandable, new (arena) ArenaBitVectorAllocator(arena)), kind_(kind) {
+  UNUSED(kind_);
+}
 
 }  // namespace art
diff --git a/compiler/utils/arm/managed_register_arm.cc b/compiler/utils/arm/managed_register_arm.cc
index 57c2305..1fdc110 100644
--- a/compiler/utils/arm/managed_register_arm.cc
+++ b/compiler/utils/arm/managed_register_arm.cc
@@ -21,16 +21,6 @@
 namespace art {
 namespace arm {
 
-// We need all registers for caching of locals.
-// Register R9 .. R15 are reserved.
-static const int kNumberOfAvailableCoreRegisters = (R8 - R0) + 1;
-static const int kNumberOfAvailableSRegisters = kNumberOfSRegisters;
-static const int kNumberOfAvailableDRegisters = kNumberOfDRegisters;
-static const int kNumberOfAvailableOverlappingDRegisters =
-    kNumberOfOverlappingDRegisters;
-static const int kNumberOfAvailableRegisterPairs = kNumberOfRegisterPairs;
-
-
 // Returns true if this managed-register overlaps the other managed-register.
 bool ArmManagedRegister::Overlaps(const ArmManagedRegister& other) const {
   if (IsNoRegister() || other.IsNoRegister()) return false;
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index c9be4ed..296254d 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -282,7 +282,9 @@
   byte* cursor_;
   byte* limit_;
   AssemblerFixup* fixup_;
+#ifndef NDEBUG
   bool fixups_processed_;
+#endif
 
   // Head of linked list of slow paths
   SlowPath* slow_path_;
diff --git a/compiler/utils/mips/managed_register_mips.cc b/compiler/utils/mips/managed_register_mips.cc
index 195dafb..5a8c048 100644
--- a/compiler/utils/mips/managed_register_mips.cc
+++ b/compiler/utils/mips/managed_register_mips.cc
@@ -21,17 +21,6 @@
 namespace art {
 namespace mips {
 
-// These core registers are never available for allocation.
-static const Register kReservedCoreRegistersArray[] = { S0, S1 };
-
-// We need all registers for caching.
-static const int kNumberOfAvailableCoreRegisters = (S7 - T0) + 1;
-static const int kNumberOfAvailableFRegisters = kNumberOfFRegisters;
-static const int kNumberOfAvailableDRegisters = kNumberOfDRegisters;
-static const int kNumberOfAvailableOverlappingDRegisters =
-    kNumberOfOverlappingDRegisters;
-static const int kNumberOfAvailableRegisterPairs = kNumberOfRegisterPairs;
-
 bool MipsManagedRegister::Overlaps(const MipsManagedRegister& other) const {
   if (IsNoRegister() || other.IsNoRegister()) return false;
   CHECK(IsValidManagedRegister());
diff --git a/compiler/utils/x86/managed_register_x86.cc b/compiler/utils/x86/managed_register_x86.cc
index 4697d06..7fae7a8 100644
--- a/compiler/utils/x86/managed_register_x86.cc
+++ b/compiler/utils/x86/managed_register_x86.cc
@@ -21,19 +21,6 @@
 namespace art {
 namespace x86 {
 
-// These cpu registers are never available for allocation.
-static const Register kReservedCpuRegistersArray[] = { ESP };
-
-
-// We reduce the number of available registers for allocation in debug-code
-// mode in order to increase register pressure.
-
-// We need all registers for caching.
-static const int kNumberOfAvailableCpuRegisters = kNumberOfCpuRegisters;
-static const int kNumberOfAvailableXmmRegisters = kNumberOfXmmRegisters;
-static const int kNumberOfAvailableRegisterPairs = kNumberOfRegisterPairs;
-
-
 // Define register pairs.
 // This list must be kept in sync with the RegisterPair enum.
 #define REGISTER_PAIR_LIST(P) \
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index a082e36..041a66b 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -349,9 +349,9 @@
                                                         dump_passes,
                                                         &compiler_phases_timings));
 
-    driver->GetCompilerBackend()->SetBitcodeFileName(bitcode_filename);
+    driver->GetCompilerBackend()->SetBitcodeFileName(*driver.get(), bitcode_filename);
 
-    driver->CompileAll(class_loader, dex_files, timings);
+    driver->CompileAll(class_loader, dex_files, &timings);
 
     timings.NewSplit("dex2oat OatWriter");
     std::string image_file_location;
@@ -377,7 +377,7 @@
                          &timings);
 
     TimingLogger::ScopedSplit split("Writing ELF", &timings);
-    if (!driver->WriteElf(android_root, is_host, dex_files, oat_writer, oat_file)) {
+    if (!driver->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) {
       LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath();
       return NULL;
     }
@@ -760,6 +760,7 @@
   bool dump_passes = false;
   bool dump_slow_timing = kIsDebugBuild;
   bool watch_dog_enabled = !kIsTargetBuild;
+  bool generate_gdb_information = kIsDebugBuild;
 
   for (int i = 0; i < argc; i++) {
     const StringPiece option(argv[i]);
@@ -797,6 +798,10 @@
       watch_dog_enabled = true;
     } else if (option == "--no-watch-dog") {
       watch_dog_enabled = false;
+    } else if (option == "--gen-gdb-info") {
+      generate_gdb_information = true;
+    } else if (option == "--no-gen-gdb-info") {
+      generate_gdb_information = false;
     } else if (option.starts_with("-j")) {
       const char* thread_count_str = option.substr(strlen("-j")).data();
       if (!ParseInt(thread_count_str, &thread_count)) {
@@ -1042,7 +1047,8 @@
                                    large_method_threshold,
                                    small_method_threshold,
                                    tiny_method_threshold,
-                                   num_dex_methods_threshold
+                                   num_dex_methods_threshold,
+                                   generate_gdb_information
 #ifdef ART_SEA_IR_MODE
                                    , compiler_options.sea_ir_ = true;
 #endif
@@ -1302,7 +1308,7 @@
       LOG(INFO) << Dumpable<TimingLogger>(timings);
     }
     if (dump_passes) {
-      LOG(INFO) << Dumpable<CumulativeLogger>(compiler.get()->GetTimingsLogger());
+      LOG(INFO) << Dumpable<CumulativeLogger>(*compiler.get()->GetTimingsLogger());
     }
     return EXIT_SUCCESS;
   }
diff --git a/disassembler/Android.mk b/disassembler/Android.mk
index 1ce7b13..ca08b09 100644
--- a/disassembler/Android.mk
+++ b/disassembler/Android.mk
@@ -90,13 +90,9 @@
   LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
   ifeq ($$(art_target_or_host),target)
     LOCAL_SHARED_LIBRARIES += libcutils
-    include $(LLVM_GEN_INTRINSICS_MK)
-    include $(LLVM_DEVICE_BUILD_MK)
     include $(BUILD_SHARED_LIBRARY)
   else # host
     LOCAL_STATIC_LIBRARIES += libcutils
-    include $(LLVM_GEN_INTRINSICS_MK)
-    include $(LLVM_HOST_BUILD_MK)
     include $(BUILD_HOST_SHARED_LIBRARY)
   endif
 endef
diff --git a/runtime/Android.mk b/runtime/Android.mk
index d6d2b42..10ef64b 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -74,7 +74,6 @@
 	intern_table.cc \
 	interpreter/interpreter.cc \
 	interpreter/interpreter_common.cc \
-	interpreter/interpreter_goto_table_impl.cc \
 	interpreter/interpreter_switch_impl.cc \
 	jdwp/jdwp_event.cc \
 	jdwp/jdwp_expand_buf.cc \
@@ -185,6 +184,10 @@
 	entrypoints/quick/quick_throw_entrypoints.cc \
 	entrypoints/quick/quick_trampoline_entrypoints.cc
 
+# Source files that only compile with GCC.
+LIBART_GCC_ONLY_SRC_FILES := \
+	interpreter/interpreter_goto_table_impl.cc
+
 LIBART_LDFLAGS := -Wl,--no-fatal-warnings
 
 LIBART_TARGET_SRC_FILES := \
@@ -300,6 +303,7 @@
 
 # $(1): target or host
 # $(2): ndebug or debug
+# 3(3): true or false for LOCAL_CLANG
 define build-libart
   ifneq ($(1),target)
     ifneq ($(1),host)
@@ -311,9 +315,15 @@
       $$(error expected ndebug or debug for argument 2, received $(2))
     endif
   endif
+  ifneq ($(3),true)
+    ifneq ($(3),false)
+      $$(error expected true or false for argument 3, received $(3))
+    endif
+  endif
 
   art_target_or_host := $(1)
   art_ndebug_or_debug := $(2)
+  art_clang := $(3)
 
   include $(CLEAR_VARS)
   ifeq ($$(art_target_or_host),target)
@@ -354,11 +364,14 @@
   $(foreach arch,$(ART_SUPPORTED_ARCH),
     LOCAL_LDFLAGS_$(arch) := $$(LIBART_TARGET_LDFLAGS_$(arch)))
 
+  ifeq ($$(art_clang),false)
+    LOCAL_SRC_FILES += $(LIBART_GCC_ONLY_SRC_FILES)
+  else
+    LOCAL_CLANG := true
+  endif
   ifeq ($$(art_target_or_host),target)
-    LOCAL_CLANG := $(ART_TARGET_CLANG)
     LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
   else # host
-    LOCAL_CLANG := $(ART_HOST_CLANG)
     LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
   endif
   ifeq ($$(art_ndebug_or_debug),debug)
@@ -389,7 +402,14 @@
       LOCAL_LDLIBS += -lrt
     endif
   endif
-  include $(LLVM_GEN_INTRINSICS_MK)
+  ifeq ($(ART_USE_PORTABLE_COMPILER),true)
+    include $(LLVM_GEN_INTRINSICS_MK)
+    ifeq ($$(art_target_or_host),target)
+      include $(LLVM_DEVICE_BUILD_MK)
+    else # host
+      include $(LLVM_HOST_BUILD_MK)
+    endif
+  endif
   LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
   LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 
@@ -398,27 +418,25 @@
   endif
 
   ifeq ($$(art_target_or_host),target)
-    include $(LLVM_DEVICE_BUILD_MK)
     include $(BUILD_SHARED_LIBRARY)
   else # host
-    include $(LLVM_HOST_BUILD_MK)
     include $(BUILD_HOST_SHARED_LIBRARY)
   endif
 endef
 
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-  $(eval $(call build-libart,target,ndebug))
+  $(eval $(call build-libart,target,ndebug,$(ART_TARGET_CLANG)))
 endif
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
-  $(eval $(call build-libart,target,debug))
+  $(eval $(call build-libart,target,debug,$(ART_TARGET_CLANG)))
 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 ($(WITH_HOST_DALVIK),true)
   ifeq ($(ART_BUILD_NDEBUG),true)
-    $(eval $(call build-libart,host,ndebug))
+    $(eval $(call build-libart,host,ndebug,$(ART_HOST_CLANG)))
   endif
   ifeq ($(ART_BUILD_DEBUG),true)
-    $(eval $(call build-libart,host,debug))
+    $(eval $(call build-libart,host,debug,$(ART_HOST_CLANG)))
   endif
 endif
diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S
index 9ec1995..267717a 100644
--- a/runtime/arch/x86/asm_support_x86.S
+++ b/runtime/arch/x86/asm_support_x86.S
@@ -19,38 +19,25 @@
 
 #include "asm_support_x86.h"
 
-#if defined(__APPLE__)
-    // Mac OS' as(1) doesn't let you name macro parameters.
+#if defined(__clang__)
+    // Clang's as(1) doesn't let you name macro parameters.
     #define MACRO0(macro_name) .macro macro_name
     #define MACRO1(macro_name, macro_arg1) .macro macro_name
     #define MACRO2(macro_name, macro_arg1, macro_args2) .macro macro_name
     #define MACRO3(macro_name, macro_arg1, macro_args2, macro_args3) .macro macro_name
     #define END_MACRO .endmacro
 
-    // Mac OS' as(1) uses $0, $1, and so on for macro arguments, and function names
-    // are mangled with an extra underscore prefix. The use of $x for arguments
-    // mean that literals need to be represented with $$x in macros.
-    #define SYMBOL(name) _ ## name
-    #define PLT_SYMBOL(name) _ ## name
+    // Clang's as(1) uses $0, $1, and so on for macro arguments.
     #define VAR(name,index) SYMBOL($index)
     #define PLT_VAR(name, index) SYMBOL($index)
     #define REG_VAR(name,index) %$index
     #define CALL_MACRO(name,index) $index
+    #define FUNCTION_TYPE(name,index) .type $index, @function
+    #define SIZE(name,index) .size $index, .-$index
+
+    //  The use of $x for arguments mean that literals need to be represented with $$x in macros.
     #define LITERAL(value) $value
     #define MACRO_LITERAL(value) $$value
-
-    // Mac OS' doesn't like cfi_* directives
-    #define CFI_STARTPROC
-    #define CFI_ENDPROC
-    #define CFI_ADJUST_CFA_OFFSET(size)
-    #define CFI_DEF_CFA(reg,size)
-    #define CFI_DEF_CFA_REGISTER(reg)
-    #define CFI_RESTORE(reg)
-    #define CFI_REL_OFFSET(reg,size)
-
-    // Mac OS' doesn't support certain directives
-    #define FUNCTION_TYPE(name)
-    #define SIZE(name)
 #else
     // Regular gas(1) lets you name macro parameters.
     #define MACRO0(macro_name) .macro macro_name
@@ -65,16 +52,19 @@
     // 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 SYMBOL(name) name
-    #define PLT_SYMBOL(name) name@PLT
     #define VAR(name,index) name&
     #define PLT_VAR(name, index) name&@PLT
     #define REG_VAR(name,index) %name
     #define CALL_MACRO(name,index) name&
+    #define FUNCTION_TYPE(name,index) .type name&, @function
+    #define SIZE(name,index) .size name, .-name
+
     #define LITERAL(value) $value
     #define MACRO_LITERAL(value) $value
+#endif
 
-    // CFI support
+    // CFI support.
+#if !defined(__APPLE__)
     #define CFI_STARTPROC .cfi_startproc
     #define CFI_ENDPROC .cfi_endproc
     #define CFI_ADJUST_CFA_OFFSET(size) .cfi_adjust_cfa_offset size
@@ -82,9 +72,25 @@
     #define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg
     #define CFI_RESTORE(reg) .cfi_restore reg
     #define CFI_REL_OFFSET(reg,size) .cfi_rel_offset reg,size
+#else
+    // Mac OS' doesn't like cfi_* directives.
+    #define CFI_STARTPROC
+    #define CFI_ENDPROC
+    #define CFI_ADJUST_CFA_OFFSET(size)
+    #define CFI_DEF_CFA(reg,size)
+    #define CFI_DEF_CFA_REGISTER(reg)
+    #define CFI_RESTORE(reg)
+    #define CFI_REL_OFFSET(reg,size)
+#endif
 
-    #define FUNCTION_TYPE(name) .type name&, @function
-    #define SIZE(name) .size name, .-name
+    // Symbols.
+#if !defined(__APPLE__)
+    #define SYMBOL(name) name
+    #define PLT_SYMBOL(name) name
+#else
+    // Mac OS' symbols have an _ prefix.
+    #define SYMBOL(name) _ ## name
+    #define PLT_SYMBOL(name) _ ## name
 #endif
 
     /* Cache alignment for function entry */
@@ -93,7 +99,7 @@
 END_MACRO
 
 MACRO1(DEFINE_FUNCTION, c_name)
-    FUNCTION_TYPE(\c_name)
+    FUNCTION_TYPE(\c_name, 0)
     .globl VAR(c_name, 0)
     ALIGN_FUNCTION_ENTRY
 VAR(c_name, 0):
@@ -102,7 +108,7 @@
 
 MACRO1(END_FUNCTION, c_name)
     CFI_ENDPROC
-    SIZE(\c_name)
+    SIZE(\c_name, 0)
 END_MACRO
 
 MACRO1(PUSH, reg)
@@ -118,7 +124,7 @@
 END_MACRO
 
 MACRO1(UNIMPLEMENTED,name)
-    FUNCTION_TYPE(\name)
+    FUNCTION_TYPE(\name, 0)
     .globl VAR(name, 0)
     ALIGN_FUNCTION_ENTRY
 VAR(name, 0):
@@ -126,7 +132,7 @@
     int3
     int3
     CFI_ENDPROC
-    SIZE(\name)
+    SIZE(\name, 0)
 END_MACRO
 
 MACRO0(SETUP_GOT_NOSAVE)
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 3da7409..754d1dd 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -46,6 +46,7 @@
       return array_class;
     }
   }
+  DCHECK(!element_class->IsPrimitiveVoid());
   std::string descriptor("[");
   descriptor += ClassHelper(element_class).GetDescriptor();
   SirtRef<mirror::ClassLoader> class_loader(self, element_class->GetClassLoader());
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 3a17e41..c646b86 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -22,6 +22,83 @@
 
 namespace art {
 
+// -------------------------------------------------------------------
+// Binary GDB JIT Interface as described in
+//   http://sourceware.org/gdb/onlinedocs/gdb/Declarations.html
+extern "C" {
+  typedef enum {
+    JIT_NOACTION = 0,
+    JIT_REGISTER_FN,
+    JIT_UNREGISTER_FN
+  } JITAction;
+
+  struct JITCodeEntry {
+    JITCodeEntry* next_;
+    JITCodeEntry* prev_;
+    const byte *symfile_addr_;
+    uint64_t symfile_size_;
+  };
+
+  struct JITDescriptor {
+    uint32_t version_;
+    uint32_t action_flag_;
+    JITCodeEntry* relevant_entry_;
+    JITCodeEntry* first_entry_;
+  };
+
+  // GDB will place breakpoint into this function.
+  // To prevent GCC from inlining or removing it we place noinline attribute
+  // and inline assembler statement inside.
+  void __attribute__((noinline)) __jit_debug_register_code() {
+    __asm__("");
+  }
+
+  // GDB will inspect contents of this descriptor.
+  // Static initialization is necessary to prevent GDB from seeing
+  // uninitialized descriptor.
+  JITDescriptor __jit_debug_descriptor = { 1, JIT_NOACTION, nullptr, nullptr };
+}
+
+
+static JITCodeEntry* CreateCodeEntry(const byte *symfile_addr,
+                                     uintptr_t symfile_size) {
+  JITCodeEntry* entry = new JITCodeEntry;
+  entry->symfile_addr_ = symfile_addr;
+  entry->symfile_size_ = symfile_size;
+  entry->prev_ = nullptr;
+
+  // TODO: Do we need a lock here?
+  entry->next_ = __jit_debug_descriptor.first_entry_;
+  if (entry->next_ != nullptr) {
+    entry->next_->prev_ = entry;
+  }
+  __jit_debug_descriptor.first_entry_ = entry;
+  __jit_debug_descriptor.relevant_entry_ = entry;
+
+  __jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN;
+  __jit_debug_register_code();
+  return entry;
+}
+
+
+static void UnregisterCodeEntry(JITCodeEntry* entry) {
+  // TODO: Do we need a lock here?
+  if (entry->prev_ != nullptr) {
+    entry->prev_->next_ = entry->next_;
+  } else {
+    __jit_debug_descriptor.first_entry_ = entry->next_;
+  }
+
+  if (entry->next_ != nullptr) {
+    entry->next_->prev_ = entry->prev_;
+  }
+
+  __jit_debug_descriptor.relevant_entry_ = entry;
+  __jit_debug_descriptor.action_flag_ = JIT_UNREGISTER_FN;
+  __jit_debug_register_code();
+  delete entry;
+}
+
 ElfFile::ElfFile(File* file, bool writable, bool program_header_only)
   : file_(file),
     writable_(writable),
@@ -38,7 +115,9 @@
     dynstr_section_start_(NULL),
     hash_section_start_(NULL),
     symtab_symbol_table_(NULL),
-    dynsym_symbol_table_(NULL) {
+    dynsym_symbol_table_(NULL),
+    jit_elf_image_(NULL),
+    jit_gdb_entry_(NULL) {
   CHECK(file != NULL);
 }
 
@@ -172,6 +251,10 @@
   STLDeleteElements(&segments_);
   delete symtab_symbol_table_;
   delete dynsym_symbol_table_;
+  delete jit_elf_image_;
+  if (jit_gdb_entry_) {
+    UnregisterCodeEntry(jit_gdb_entry_);
+  }
 }
 
 bool ElfFile::SetMap(MemMap* map, std::string* error_msg) {
@@ -830,6 +913,11 @@
     }
   }
 
+  // Use GDB JIT support to do stack backtrace, etc.
+  if (executable) {
+    GdbJITSupport();
+  }
+
   return true;
 }
 
@@ -843,4 +931,269 @@
   return false;
 }
 
+static bool check_section_name(ElfFile& file, int section_num, const char *name) {
+  Elf32_Shdr& section_header = file.GetSectionHeader(section_num);
+  const char *section_name = file.GetString(SHT_SYMTAB, section_header.sh_name);
+  return strcmp(name, section_name) == 0;
+}
+
+static void IncrementUint32(byte *p, uint32_t increment) {
+  uint32_t *u = reinterpret_cast<uint32_t *>(p);
+  *u += increment;
+}
+
+static void RoundAndClear(byte *image, uint32_t& offset, int pwr2) {
+  uint32_t mask = pwr2 - 1;
+  while (offset & mask) {
+    image[offset++] = 0;
+  }
+}
+
+// Simple macro to bump a point to a section header to the next one.
+#define BUMP_SHENT(sp) \
+  sp = reinterpret_cast<Elf32_Shdr *> (\
+      reinterpret_cast<byte*>(sp) + elf_hdr.e_shentsize);\
+  offset += elf_hdr.e_shentsize
+
+void ElfFile::GdbJITSupport() {
+  // We only get here if we only are mapping the program header.
+  DCHECK(program_header_only_);
+
+  // Well, we need the whole file to do this.
+  std::string error_msg;
+  UniquePtr<ElfFile> ptr(Open(const_cast<File*>(file_), false, false, &error_msg));
+  ElfFile& all = *ptr;
+
+  // Do we have interesting sections?
+  // Is this an OAT file with interesting sections?
+  if (all.GetSectionHeaderNum() != kExpectedSectionsInOATFile) {
+    return;
+  }
+  if (!check_section_name(all, 8, ".debug_info") ||
+      !check_section_name(all, 9, ".debug_abbrev") ||
+      !check_section_name(all, 10, ".debug_frame") ||
+      !check_section_name(all, 11, ".debug_str")) {
+    return;
+  }
+
+  // Okay, we are good enough.  Fake up an ELF image and tell GDB about it.
+  // We need some extra space for the debug and string sections, the ELF header, and the
+  // section header.
+  uint32_t needed_size = KB;
+
+  for (Elf32_Word i = 1; i < all.GetSectionHeaderNum(); i++) {
+    Elf32_Shdr& section_header = all.GetSectionHeader(i);
+    if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
+      // Debug section: we need it.
+      needed_size += section_header.sh_size;
+    } else if (section_header.sh_type == SHT_STRTAB &&
+                strcmp(".shstrtab",
+                       all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
+      // We also need the shared string table.
+      needed_size += section_header.sh_size;
+
+      // We also need the extra strings .symtab\0.strtab\0
+      needed_size += 16;
+    }
+  }
+
+  // Start creating our image.
+  jit_elf_image_ = new byte[needed_size];
+
+  // Create the Elf Header by copying the old one
+  Elf32_Ehdr& elf_hdr =
+    *reinterpret_cast<Elf32_Ehdr*>(jit_elf_image_);
+
+  elf_hdr = all.GetHeader();
+  elf_hdr.e_entry = 0;
+  elf_hdr.e_phoff = 0;
+  elf_hdr.e_phnum = 0;
+  elf_hdr.e_phentsize = 0;
+  elf_hdr.e_type = ET_EXEC;
+
+  uint32_t offset = sizeof(Elf32_Ehdr);
+
+  // Copy the debug sections and string table.
+  uint32_t debug_offsets[kExpectedSectionsInOATFile];
+  memset(debug_offsets, '\0', sizeof debug_offsets);
+  Elf32_Shdr *text_header = nullptr;
+  int extra_shstrtab_entries = -1;
+  int text_section_index = -1;
+  int section_index = 1;
+  for (Elf32_Word i = 1; i < kExpectedSectionsInOATFile; i++) {
+    Elf32_Shdr& section_header = all.GetSectionHeader(i);
+    // Round up to multiple of 4, ensuring zero fill.
+    RoundAndClear(jit_elf_image_, offset, 4);
+    if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
+      // Debug section: we need it.  Unfortunately, it wasn't mapped in.
+      debug_offsets[i] = offset;
+      // Read it from the file.
+      lseek(file_->Fd(), section_header.sh_offset, SEEK_SET);
+      read(file_->Fd(), jit_elf_image_ + offset, section_header.sh_size);
+      offset += section_header.sh_size;
+      section_index++;
+      offset += 16;
+    } else if (section_header.sh_type == SHT_STRTAB &&
+                strcmp(".shstrtab",
+                       all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
+      // We also need the shared string table.
+      debug_offsets[i] = offset;
+      // Read it from the file.
+      lseek(file_->Fd(), section_header.sh_offset, SEEK_SET);
+      read(file_->Fd(), jit_elf_image_ + offset, section_header.sh_size);
+      offset += section_header.sh_size;
+      // We also need the extra strings .symtab\0.strtab\0
+      extra_shstrtab_entries = section_header.sh_size;
+      memcpy(jit_elf_image_+offset, ".symtab\0.strtab\0", 16);
+      offset += 16;
+      section_index++;
+    } else if (section_header.sh_flags & SHF_EXECINSTR) {
+      DCHECK(strcmp(".text", all.GetString(SHT_SYMTAB,
+                                           section_header.sh_name)) == 0);
+      text_header = &section_header;
+      text_section_index = section_index++;
+    }
+  }
+  DCHECK(text_header != nullptr);
+  DCHECK_NE(extra_shstrtab_entries, -1);
+
+  // We now need to update the addresses for debug_info and debug_frame to get to the
+  // correct offset within the .text section.
+  uint32_t text_start_addr = 0;
+  for (uint32_t i = 0; i < segments_.size(); i++) {
+    if (segments_[i]->GetProtect() & PROT_EXEC) {
+      // We found the .text section.
+      text_start_addr = reinterpret_cast<uint32_t>(segments_[i]->Begin());
+      break;
+    }
+  }
+  DCHECK_NE(text_start_addr, 0U);
+
+  byte *p = jit_elf_image_+debug_offsets[8];
+  byte *end = p + all.GetSectionHeader(8).sh_size;
+
+  // For debug_info; patch compilation using low_pc @ offset 13, high_pc at offset 17.
+  IncrementUint32(p + 13, text_start_addr);
+  IncrementUint32(p + 17, text_start_addr);
+
+  // Now fix the low_pc, high_pc for each method address.
+  // First method starts at offset 0x15, each subsequent method is 1+3*4 bytes further.
+  for (p += 0x15; p < end; p += 1 /* attr# */ + 3 * sizeof(uint32_t) /* addresses */) {
+    IncrementUint32(p + 1 + sizeof(uint32_t), text_start_addr);
+    IncrementUint32(p + 1 + 2 * sizeof(uint32_t), text_start_addr);
+  }
+
+  // Now we have to handle the debug_frame method start addresses
+  p = jit_elf_image_+debug_offsets[10];
+  end = p + all.GetSectionHeader(10).sh_size;
+
+  // Skip past the CIE.
+  p += *reinterpret_cast<uint32_t *>(p) + 4;
+
+  // And walk the FDEs.
+  for (; p < end; p += *reinterpret_cast<uint32_t *>(p) + sizeof(uint32_t)) {
+    IncrementUint32(p + 2 * sizeof(uint32_t), text_start_addr);
+  }
+
+  // Create the data for the symbol table.
+  const int kSymbtabAlignment = 16;
+  RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
+  uint32_t symtab_offset = offset;
+
+  // First entry is empty.
+  memset(jit_elf_image_+offset, 0, sizeof(Elf32_Sym));
+  offset += sizeof(Elf32_Sym);
+
+  // Symbol 1 is the real .text section.
+  Elf32_Sym& sym_ent = *reinterpret_cast<Elf32_Sym*>(jit_elf_image_+offset);
+  sym_ent.st_name = 1; /* .text */
+  sym_ent.st_value = text_start_addr;
+  sym_ent.st_size = text_header->sh_size;
+  SetBindingAndType(&sym_ent, STB_LOCAL, STT_SECTION);
+  sym_ent.st_other = 0;
+  sym_ent.st_shndx = text_section_index;
+  offset += sizeof(Elf32_Sym);
+
+  // Create the data for the string table.
+  RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
+  const int kTextStringSize = 7;
+  uint32_t strtab_offset = offset;
+  memcpy(jit_elf_image_+offset, "\0.text", kTextStringSize);
+  offset += kTextStringSize;
+
+  // Create the section header table.
+  // Round up to multiple of kSymbtabAlignment, ensuring zero fill.
+  RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
+  elf_hdr.e_shoff = offset;
+  Elf32_Shdr *sp =
+    reinterpret_cast<Elf32_Shdr *>(jit_elf_image_ + offset);
+
+  // Copy the first empty index.
+  *sp = all.GetSectionHeader(0);
+  BUMP_SHENT(sp);
+
+  elf_hdr.e_shnum = 1;
+  for (Elf32_Word i = 1; i < kExpectedSectionsInOATFile; i++) {
+    Elf32_Shdr& section_header = all.GetSectionHeader(i);
+    if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
+      // Debug section: we need it.
+      *sp = section_header;
+      sp->sh_offset = debug_offsets[i];
+      sp->sh_addr = 0;
+      elf_hdr.e_shnum++;
+      BUMP_SHENT(sp);
+    } else if (section_header.sh_type == SHT_STRTAB &&
+                strcmp(".shstrtab",
+                       all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
+      // We also need the shared string table.
+      *sp = section_header;
+      sp->sh_offset = debug_offsets[i];
+      sp->sh_size += 16; /* sizeof ".symtab\0.strtab\0" */
+      sp->sh_addr = 0;
+      elf_hdr.e_shstrndx = elf_hdr.e_shnum;
+      elf_hdr.e_shnum++;
+      BUMP_SHENT(sp);
+    }
+  }
+
+  // Add a .text section for the matching code section.
+  *sp = *text_header;
+  sp->sh_type = SHT_NOBITS;
+  sp->sh_offset = 0;
+  sp->sh_addr = text_start_addr;
+  elf_hdr.e_shnum++;
+  BUMP_SHENT(sp);
+
+  // .symtab section:  Need an empty index and the .text entry
+  sp->sh_name = extra_shstrtab_entries;
+  sp->sh_type = SHT_SYMTAB;
+  sp->sh_flags = 0;
+  sp->sh_addr = 0;
+  sp->sh_offset = symtab_offset;
+  sp->sh_size = 2 * sizeof(Elf32_Sym);
+  sp->sh_link = elf_hdr.e_shnum + 1;  // Link to .strtab section.
+  sp->sh_info = 0;
+  sp->sh_addralign = 16;
+  sp->sh_entsize = sizeof(Elf32_Sym);
+  elf_hdr.e_shnum++;
+  BUMP_SHENT(sp);
+
+  // .strtab section:  Enough for .text\0.
+  sp->sh_name = extra_shstrtab_entries + 8;
+  sp->sh_type = SHT_STRTAB;
+  sp->sh_flags = 0;
+  sp->sh_addr = 0;
+  sp->sh_offset = strtab_offset;
+  sp->sh_size = kTextStringSize;
+  sp->sh_link = 0;
+  sp->sh_info = 0;
+  sp->sh_addralign = 16;
+  sp->sh_entsize = 0;
+  elf_hdr.e_shnum++;
+  BUMP_SHENT(sp);
+
+  // We now have enough information to tell GDB about our file.
+  jit_gdb_entry_ = CreateCodeEntry(jit_elf_image_, offset);
+}
+
 }  // namespace art
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 8a0a5f8..d2a044e 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -29,6 +29,12 @@
 
 namespace art {
 
+// Interface to GDB JIT for backtrace information.
+extern "C" {
+  struct JITCodeEntry;
+}
+
+
 // Used for compile time and runtime for ElfFile access. Because of
 // the need for use at runtime, cannot directly use LLVM classes such as
 // ELFObjectFile.
@@ -171,6 +177,13 @@
 
   SymbolTable* symtab_symbol_table_;
   SymbolTable* dynsym_symbol_table_;
+
+  // Support for GDB JIT
+  byte* jit_elf_image_;
+  JITCodeEntry* jit_gdb_entry_;
+  void GdbJITSupport();
+  // Is this an OAT file with debug information in it?
+  static constexpr uint32_t kExpectedSectionsInOATFile = 12;
 };
 
 }  // namespace art
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 59da7a0..737fa3e 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -92,6 +92,7 @@
     }
     CheckReferenceResult(o, self);
   }
+  VerifyObject(o);
   return o;
 }
 
@@ -109,6 +110,7 @@
     }
     CheckReferenceResult(o, self);
   }
+  VerifyObject(o);
   return o;
 }
 
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 5b4ca80..dd2bb5d 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -439,9 +439,6 @@
   hash_set<Run*, hash_run, eq_run> full_runs_[kNumOfSizeBrackets];
   // The set of free pages.
   std::set<FreePageRun*> free_page_runs_ GUARDED_BY(lock_);
-  // The free page run whose end address is the end of the memory
-  // region that's managed by this allocator, if any.
-  FreePageRun* last_free_page_run_;
   // The current runs where the allocations are first attempted for
   // the size brackes that do not use thread-local
   // runs. current_runs_[i] is guarded by size_bracket_locks_[i].
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 7b2bc3b..c39e56f 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -861,7 +861,7 @@
         size_t mark_stack_increment = std::min(mark_stack_delta, mark_stack_remaining);
         mark_stack_end -= mark_stack_increment;
         mark_stack_->PopBackCount(static_cast<int32_t>(mark_stack_increment));
-        DCHECK_EQ(mark_stack_end, mark_stack_->End());
+        DCHECK_EQ(mark_stack_end, const_cast<const art::mirror::Object **>(mark_stack_->End()));
         // Add the new task to the thread pool.
         auto* task = new CardScanTask(thread_pool, this, space->GetMarkBitmap(), card_begin,
                                       card_begin + card_increment, minimum_age,
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index a4c9dea..4668a19 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -61,7 +61,8 @@
 namespace collector {
 
 static constexpr bool kProtectFromSpace = true;
-static constexpr bool kResetFromSpace = true;
+static constexpr bool kClearFromSpace = true;
+static constexpr bool kStoreStackTraces = false;
 
 // TODO: Unduplicate logic.
 void SemiSpace::ImmuneSpace(space::ContinuousSpace* space) {
@@ -169,6 +170,19 @@
 }
 
 void SemiSpace::MarkingPhase() {
+  if (kStoreStackTraces) {
+    Locks::mutator_lock_->AssertExclusiveHeld(self_);
+    // Store the stack traces into the runtime fault string in case we get a heap corruption
+    // related crash later.
+    ThreadState old_state = self_->SetStateUnsafe(kRunnable);
+    std::ostringstream oss;
+    Runtime* runtime = Runtime::Current();
+    runtime->GetThreadList()->DumpForSigQuit(oss);
+    runtime->GetThreadList()->DumpNativeStacks(oss);
+    runtime->SetFaultMessage(oss.str());
+    CHECK_EQ(self_->SetStateUnsafe(old_state), kRunnable);
+  }
+
   if (generational_) {
     if (gc_cause_ == kGcCauseExplicit || gc_cause_ == kGcCauseForNativeAlloc ||
         clear_soft_references_) {
@@ -353,19 +367,17 @@
     TimingLogger::ScopedSplit split("UnBindBitmaps", &timings_);
     GetHeap()->UnBindBitmaps();
   }
-  // Release the memory used by the from space.
-  if (kResetFromSpace) {
-    // Clearing from space.
+  if (kClearFromSpace) {
+    // Release the memory used by the from space.
     from_space_->Clear();
   }
+  from_space_->Reset();
   // Protect the from space.
-  VLOG(heap)
-      << "mprotect region " << reinterpret_cast<void*>(from_space_->Begin()) << " - "
-      << reinterpret_cast<void*>(from_space_->Limit());
+  VLOG(heap) << "Protecting space " << *from_space_;
   if (kProtectFromSpace) {
-    mprotect(from_space_->Begin(), from_space_->Capacity(), PROT_NONE);
+    from_space_->GetMemMap()->Protect(PROT_NONE);
   } else {
-    mprotect(from_space_->Begin(), from_space_->Capacity(), PROT_READ);
+    from_space_->GetMemMap()->Protect(PROT_READ);
   }
   if (saved_bytes_ > 0) {
     VLOG(heap) << "Avoided dirtying " << PrettySize(saved_bytes_);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 2e6d2c2..9ad21cf 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -318,6 +318,91 @@
   }
 }
 
+std::string Heap::SafeGetClassDescriptor(mirror::Class* klass) {
+  if (!IsValidContinuousSpaceObjectAddress(klass)) {
+    return StringPrintf("<non heap address klass %p>", klass);
+  }
+  mirror::Class* component_type = klass->GetComponentType<kVerifyNone>();
+  if (IsValidContinuousSpaceObjectAddress(component_type) && klass->IsArrayClass<kVerifyNone>()) {
+    std::string result("[");
+    result += SafeGetClassDescriptor(component_type);
+    return result;
+  } else if (UNLIKELY(klass->IsPrimitive<kVerifyNone>())) {
+    return Primitive::Descriptor(klass->GetPrimitiveType<kVerifyNone>());
+  } else if (UNLIKELY(klass->IsProxyClass())) {
+    return Runtime::Current()->GetClassLinker()->GetDescriptorForProxy(klass);
+  } else {
+    mirror::DexCache* dex_cache = klass->GetDexCache();
+    if (!IsValidContinuousSpaceObjectAddress(dex_cache)) {
+      return StringPrintf("<non heap address dex_cache %p>", dex_cache);
+    }
+    const DexFile* dex_file = dex_cache->GetDexFile();
+    uint16_t class_def_idx = klass->GetDexClassDefIndex();
+    if (class_def_idx == DexFile::kDexNoIndex16) {
+      return "<class def not found>";
+    }
+    const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx);
+    const DexFile::TypeId& type_id = dex_file->GetTypeId(class_def.class_idx_);
+    return dex_file->GetTypeDescriptor(type_id);
+  }
+}
+
+std::string Heap::SafePrettyTypeOf(mirror::Object* obj) {
+  if (obj == nullptr) {
+    return "null";
+  }
+  mirror::Class* klass = obj->GetClass<kVerifyNone>();
+  if (klass == nullptr) {
+    return "(class=null)";
+  }
+  std::string result(SafeGetClassDescriptor(klass));
+  if (obj->IsClass()) {
+    result += "<" + SafeGetClassDescriptor(obj->AsClass()) + ">";
+  }
+  return result;
+}
+
+void Heap::DumpObject(std::ostream& stream, mirror::Object* obj) {
+  if (obj == nullptr) {
+    stream << "(obj=null)";
+    return;
+  }
+  if (IsAligned<kObjectAlignment>(obj)) {
+    space::Space* space = nullptr;
+    // Don't use find space since it only finds spaces which actually contain objects instead of
+    // spaces which may contain objects (e.g. cleared bump pointer spaces).
+    for (const auto& cur_space : continuous_spaces_) {
+      if (cur_space->HasAddress(obj)) {
+        space = cur_space;
+        break;
+      }
+    }
+    if (space == nullptr) {
+      if (allocator_mem_map_.get() == nullptr || !allocator_mem_map_->HasAddress(obj)) {
+        stream << "obj " << obj << " not a valid heap address";
+        return;
+      } else if (allocator_mem_map_.get() != nullptr) {
+        allocator_mem_map_->Protect(PROT_READ | PROT_WRITE);
+      }
+    }
+    // Unprotect all the spaces.
+    for (const auto& space : continuous_spaces_) {
+      mprotect(space->Begin(), space->Capacity(), PROT_READ | PROT_WRITE);
+    }
+    stream << "Object " << obj;
+    if (space != nullptr) {
+      stream << " in space " << *space;
+    }
+    mirror::Class* klass = obj->GetClass();
+    stream << "\nclass=" << klass;
+    if (klass != nullptr) {
+      stream << " type= " << SafePrettyTypeOf(obj);
+    }
+    // Re-protect the address we faulted on.
+    mprotect(AlignDown(obj, kPageSize), kPageSize, PROT_NONE);
+  }
+}
+
 bool Heap::IsCompilingBoot() const {
   for (const auto& space : continuous_spaces_) {
     if (space->IsImageSpace() || space->IsZygoteSpace()) {
@@ -809,16 +894,23 @@
   if (obj == nullptr) {
     return true;
   }
-  return IsAligned<kObjectAlignment>(obj) && IsHeapAddress(obj);
+  return IsAligned<kObjectAlignment>(obj) && FindSpaceFromObject(obj, true) != nullptr;
 }
 
 bool Heap::IsNonDiscontinuousSpaceHeapAddress(const mirror::Object* obj) const {
   return FindContinuousSpaceFromObject(obj, true) != nullptr;
 }
 
-bool Heap::IsHeapAddress(const mirror::Object* obj) const {
-  // TODO: This might not work for large objects.
-  return FindSpaceFromObject(obj, true) != nullptr;
+bool Heap::IsValidContinuousSpaceObjectAddress(const mirror::Object* obj) const {
+  if (obj == nullptr || !IsAligned<kObjectAlignment>(obj)) {
+    return false;
+  }
+  for (const auto& space : continuous_spaces_) {
+    if (space->HasAddress(obj)) {
+      return true;
+    }
+  }
+  return false;
 }
 
 bool Heap::IsLiveObjectLocked(mirror::Object* obj, bool search_allocation_stack,
@@ -1539,6 +1631,7 @@
 void Heap::SwapSemiSpaces() {
   // Swap the spaces so we allocate into the space which we just evacuated.
   std::swap(bump_pointer_space_, temp_space_);
+  bump_pointer_space_->Clear();
 }
 
 void Heap::Compact(space::ContinuousMemMapAllocSpace* target_space,
@@ -1616,7 +1709,7 @@
     CHECK(temp_space_->IsEmpty());
     semi_space_collector_->SetFromSpace(bump_pointer_space_);
     semi_space_collector_->SetToSpace(temp_space_);
-    mprotect(temp_space_->Begin(), temp_space_->Capacity(), PROT_READ | PROT_WRITE);
+    temp_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
     collector = semi_space_collector_;
     gc_type = collector::kGcTypeFull;
   } else if (current_allocator_ == kAllocatorTypeRosAlloc ||
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 2f227d0..b194d8d 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -223,9 +223,6 @@
   bool IsValidObjectAddress(const mirror::Object* obj) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Returns true if the address passed in is a heap address, doesn't need to be aligned.
-  bool IsHeapAddress(const mirror::Object* obj) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   // Faster alternative to IsHeapAddress since finding if an object is in the large object space is
   // very slow.
   bool IsNonDiscontinuousSpaceHeapAddress(const mirror::Object* obj) const
@@ -519,6 +516,12 @@
 
   void DumpSpaces(std::ostream& stream = LOG(INFO));
 
+  // Dump object should only be used by the signal handler.
+  void DumpObject(std::ostream& stream, mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS;
+  // Safe version of pretty type of which check to make sure objects are heap addresses.
+  std::string SafeGetClassDescriptor(mirror::Class* klass) NO_THREAD_SAFETY_ANALYSIS;
+  std::string SafePrettyTypeOf(mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS;
+
   // GC performance measuring
   void DumpGcPerformanceInfo(std::ostream& os);
 
@@ -600,6 +603,10 @@
   template <bool kGrow>
   bool IsOutOfMemoryOnAllocation(AllocatorType allocator_type, size_t alloc_size);
 
+  // Returns true if the address passed in is within the address range of a continuous space.
+  bool IsValidContinuousSpaceObjectAddress(const mirror::Object* obj) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Pushes a list of cleared references out to the managed heap.
   void SetReferenceReferent(mirror::Object* reference, mirror::Object* referent)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/gc/space/bump_pointer_space.cc b/runtime/gc/space/bump_pointer_space.cc
index 43674ea..fcd3b70 100644
--- a/runtime/gc/space/bump_pointer_space.cc
+++ b/runtime/gc/space/bump_pointer_space.cc
@@ -61,6 +61,9 @@
 void BumpPointerSpace::Clear() {
   // Release the pages back to the operating system.
   CHECK_NE(madvise(Begin(), Limit() - Begin(), MADV_DONTNEED), -1) << "madvise failed";
+}
+
+void BumpPointerSpace::Reset() {
   // Reset the end of the space back to the beginning, we move the end forward as we allocate
   // objects.
   SetEnd(Begin());
@@ -75,8 +78,9 @@
 }
 
 void BumpPointerSpace::Dump(std::ostream& os) const {
-  os << reinterpret_cast<void*>(Begin()) << "-" << reinterpret_cast<void*>(End()) << " - "
-     << reinterpret_cast<void*>(Limit());
+  os << GetName() << " "
+      << reinterpret_cast<void*>(Begin()) << "-" << reinterpret_cast<void*>(End()) << " - "
+      << reinterpret_cast<void*>(Limit());
 }
 
 mirror::Object* BumpPointerSpace::GetNextObject(mirror::Object* obj) {
diff --git a/runtime/gc/space/bump_pointer_space.h b/runtime/gc/space/bump_pointer_space.h
index 476b833..2c9d35f 100644
--- a/runtime/gc/space/bump_pointer_space.h
+++ b/runtime/gc/space/bump_pointer_space.h
@@ -92,8 +92,11 @@
     return nullptr;
   }
 
-  // Clear the memory and reset the pointer to the start of the space.
-  void Clear() OVERRIDE LOCKS_EXCLUDED(block_lock_);
+  // Madvise the memory back to the OS.
+  void Clear() OVERRIDE;
+
+  // Reset the pointer to the start of the space.
+  void Reset() OVERRIDE LOCKS_EXCLUDED(block_lock_);
 
   void Dump(std::ostream& os) const;
 
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index caedaaf..b591486 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -281,12 +281,15 @@
 }
 
 void DlMallocSpace::Clear() {
-  // TODO: Delete and create new mspace here.
   madvise(GetMemMap()->Begin(), GetMemMap()->Size(), MADV_DONTNEED);
   GetLiveBitmap()->Clear();
   GetMarkBitmap()->Clear();
 }
 
+void DlMallocSpace::Reset() {
+  // TODO: Delete and create new mspace here.
+}
+
 #ifndef NDEBUG
 void DlMallocSpace::CheckMoreCoreForPrecondition() {
   lock_.AssertHeld(Thread::Current());
diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h
index 6ea10ad..4bf16ce 100644
--- a/runtime/gc/space/dlmalloc_space.h
+++ b/runtime/gc/space/dlmalloc_space.h
@@ -113,6 +113,7 @@
   uint64_t GetObjectsAllocated() OVERRIDE;
 
   void Clear() OVERRIDE;
+  void Reset() OVERRIDE;
 
   bool IsDlMallocSpace() const OVERRIDE {
     return true;
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index fe8421d..fb621ea 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -304,12 +304,15 @@
 }
 
 void RosAllocSpace::Clear() {
-  // TODO: Delete and create new mspace here.
   madvise(GetMemMap()->Begin(), GetMemMap()->Size(), MADV_DONTNEED);
   GetLiveBitmap()->Clear();
   GetMarkBitmap()->Clear();
 }
 
+void RosAllocSpace::Reset() {
+  // TODO: Delete and create new mspace here.
+}
+
 }  // namespace space
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h
index bd32196..5bc425d 100644
--- a/runtime/gc/space/rosalloc_space.h
+++ b/runtime/gc/space/rosalloc_space.h
@@ -80,6 +80,7 @@
   void SetFootprintLimit(size_t limit) OVERRIDE;
 
   void Clear() OVERRIDE;
+  void Reset() OVERRIDE;
   MallocSpace* CreateInstance(const std::string& name, MemMap* mem_map, void* allocator,
                               byte* begin, byte* end, byte* limit, size_t growth_limit);
 
diff --git a/runtime/gc/space/space.h b/runtime/gc/space/space.h
index 0f8f38a..37d7c80 100644
--- a/runtime/gc/space/space.h
+++ b/runtime/gc/space/space.h
@@ -399,6 +399,9 @@
   // Free all memory associated with this space.
   virtual void Clear() = 0;
 
+  // Reset the space back to an empty space.
+  virtual void Reset() = 0;
+
   accounting::SpaceBitmap* GetLiveBitmap() const {
     return live_bitmap_.get();
   }
diff --git a/runtime/gc/space/zygote_space.cc b/runtime/gc/space/zygote_space.cc
index a60ab38..d1c3d03 100644
--- a/runtime/gc/space/zygote_space.cc
+++ b/runtime/gc/space/zygote_space.cc
@@ -61,6 +61,10 @@
   LOG(FATAL) << "Unimplemented";
 }
 
+void ZygoteSpace::Reset() {
+  LOG(FATAL) << "Unimplemented";
+}
+
 ZygoteSpace::ZygoteSpace(const std::string& name, MemMap* mem_map, size_t objects_allocated)
     : ContinuousMemMapAllocSpace(name, mem_map, mem_map->Begin(), mem_map->End(), mem_map->End(),
                                  kGcRetentionPolicyFullCollect),
diff --git a/runtime/gc/space/zygote_space.h b/runtime/gc/space/zygote_space.h
index 8cd1a9f..8880548 100644
--- a/runtime/gc/space/zygote_space.h
+++ b/runtime/gc/space/zygote_space.h
@@ -71,7 +71,8 @@
     return objects_allocated_;
   }
 
-  void Clear();
+  void Clear() OVERRIDE;
+  void Reset() OVERRIDE;
 
  protected:
   virtual accounting::SpaceBitmap::SweepCallback* GetSweepCallback() {
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 40d4ea3..abe7fe1 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -286,11 +286,39 @@
 }
 
 enum InterpreterImplKind {
-  kSwitchImpl,            // switch-based interpreter implementation.
-  kComputedGotoImplKind   // computed-goto-based interpreter implementation.
+  kSwitchImpl,            // Switch-based interpreter implementation.
+  kComputedGotoImplKind   // Computed-goto-based interpreter implementation.
 };
 
-static const InterpreterImplKind kInterpreterImplKind = kComputedGotoImplKind;
+#if !defined(__clang__)
+static constexpr InterpreterImplKind kInterpreterImplKind = kComputedGotoImplKind;
+#else
+// Clang 3.4 fails to build the goto interpreter implementation.
+static constexpr InterpreterImplKind kInterpreterImplKind = kSwitchImpl;
+template<bool do_access_check, bool transaction_active>
+JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+                       ShadowFrame& shadow_frame, JValue result_register) {
+  LOG(FATAL) << "UNREACHABLE";
+  exit(0);
+}
+// Explicit definitions of ExecuteGotoImpl.
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<true, false>(Thread* self, MethodHelper& mh,
+                                    const DexFile::CodeItem* code_item,
+                                    ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<false, false>(Thread* self, MethodHelper& mh,
+                                     const DexFile::CodeItem* code_item,
+                                     ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<true, true>(Thread* self, MethodHelper& mh,
+                                    const DexFile::CodeItem* code_item,
+                                    ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<false, true>(Thread* self, MethodHelper& mh,
+                                     const DexFile::CodeItem* code_item,
+                                     ShadowFrame& shadow_frame, JValue result_register);
+#endif
 
 static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                       ShadowFrame& shadow_frame, JValue result_register)
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index a03e420..589e0b0 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -515,11 +515,11 @@
   return found_dex_pc;
 }
 
-static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
-  __attribute__((cold, noreturn, noinline));
+static inline void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
+  __attribute__((cold, noreturn))
+  SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static inline void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh) {
   LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(&mh.GetDexFile());
   exit(0);  // Unreachable, keep GCC happy.
 }
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index 1ec795f..fdbdfeb 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -96,9 +96,9 @@
 };
 
 struct JdwpEvent;
-struct JdwpNetStateBase;
+class JdwpNetStateBase;
 struct ModBasket;
-struct Request;
+class Request;
 
 /*
  * State for JDWP functions.
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 478cc36..484c21a 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -323,9 +323,9 @@
   size_t result;
   constexpr auto kNewFlags = static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis);
   if (IsArrayInstance<kVerifyFlags>()) {
-    result = AsArray<kNewFlags>()->SizeOf<>();
+    result = AsArray<kNewFlags>()->template SizeOf<kNewFlags>();
   } else if (IsClass<kNewFlags>()) {
-    result = AsClass<kNewFlags>()->SizeOf<kNewFlags>();
+    result = AsClass<kNewFlags>()->template SizeOf<kNewFlags>();
   } else {
     result = GetClass<kNewFlags>()->GetObjectSize();
   }
@@ -485,7 +485,6 @@
   if (kVerifyFlags & kVerifyWrites) {
     VerifyObject(new_value);
   }
-  HeapReference<Object> objref(HeapReference<Object>::FromMirrorPtr(new_value));
   byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
   HeapReference<Object>* objref_addr = reinterpret_cast<HeapReference<Object>*>(raw_addr);
   if (UNLIKELY(is_volatile)) {
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 3c703ba..decbc66 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -56,13 +56,17 @@
 static jobject VMRuntime_newNonMovableArray(JNIEnv* env, jobject, jclass javaElementClass,
                                             jint length) {
   ScopedFastNativeObjectAccess soa(env);
+  if (UNLIKELY(length < 0)) {
+    ThrowNegativeArraySizeException(length);
+    return nullptr;
+  }
   mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
   if (UNLIKELY(element_class == nullptr)) {
     ThrowNullPointerException(NULL, "element class == null");
     return nullptr;
   }
-  if (UNLIKELY(length < 0)) {
-    ThrowNegativeArraySizeException(length);
+  if (UNLIKELY(element_class->IsPrimitiveVoid())) {
+    ThrowIllegalArgumentException(NULL, "Can't allocate an array of void");
     return nullptr;
   }
   Runtime* runtime = Runtime::Current();
@@ -76,6 +80,34 @@
   return soa.AddLocalReference<jobject>(result);
 }
 
+static jobject VMRuntime_newUnpaddedArray(JNIEnv* env, jobject, jclass javaElementClass,
+                                          jint length) {
+  ScopedFastNativeObjectAccess soa(env);
+  if (UNLIKELY(length < 0)) {
+    ThrowNegativeArraySizeException(length);
+    return nullptr;
+  }
+  mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+  if (UNLIKELY(element_class == nullptr)) {
+    ThrowNullPointerException(NULL, "element class == null");
+    return nullptr;
+  }
+  if (UNLIKELY(element_class->IsPrimitiveVoid())) {
+    ThrowIllegalArgumentException(NULL, "Can't allocate an array of void");
+    return nullptr;
+  }
+  Runtime* runtime = Runtime::Current();
+  mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(), element_class);
+  if (UNLIKELY(array_class == nullptr)) {
+    return nullptr;
+  }
+  gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
+  mirror::Array* result = mirror::Array::Alloc<true>(soa.Self(), array_class, length,
+                                                     array_class->GetComponentSize(), allocator,
+                                                     true);
+  return soa.AddLocalReference<jobject>(result);
+}
+
 static jlong VMRuntime_addressOf(JNIEnv* env, jobject, jobject javaArray) {
   if (javaArray == NULL) {  // Most likely allocation failed
     return 0;
@@ -497,6 +529,7 @@
   NATIVE_METHOD(VMRuntime, isDebuggerActive, "()Z"),
   NATIVE_METHOD(VMRuntime, nativeSetTargetHeapUtilization, "(F)V"),
   NATIVE_METHOD(VMRuntime, newNonMovableArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"),
+  NATIVE_METHOD(VMRuntime, newUnpaddedArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"),
   NATIVE_METHOD(VMRuntime, properties, "()[Ljava/lang/String;"),
   NATIVE_METHOD(VMRuntime, setTargetSdkVersionNative, "(I)V"),
   NATIVE_METHOD(VMRuntime, registerNativeAllocation, "(I)V"),
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1ef15f7..90ba7d3 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -91,6 +91,8 @@
       resolution_method_(nullptr),
       imt_conflict_method_(nullptr),
       default_imt_(nullptr),
+      fault_message_lock_("Fault message lock"),
+      fault_message_(""),
       method_verifiers_lock_("Method verifiers lock"),
       threads_being_born_(0),
       shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)),
@@ -1598,4 +1600,9 @@
   DCHECK(IsActiveTransaction());
   preinitialization_transaction->RecordWeakStringRemoval(s, hash_code);
 }
+
+void Runtime::SetFaultMessage(const std::string& message) {
+  MutexLock mu(Thread::Current(), fault_message_lock_);
+  fault_message_ = message;
+}
 }  // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 8924921..7f8e915 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -60,7 +60,7 @@
 class CompilerCallbacks;
 class DexFile;
 class InternTable;
-struct JavaVMExt;
+class JavaVMExt;
 class MonitorList;
 class MonitorPool;
 class SignalCatcher;
@@ -446,6 +446,13 @@
   void RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code) const
       EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
 
+  void SetFaultMessage(const std::string& message);
+  // Only read by the signal handler, NO_THREAD_SAFETY_ANALYSIS to prevent lock order violations
+  // with the unexpected_signal_lock_.
+  const std::string& GetFaultMessage() NO_THREAD_SAFETY_ANALYSIS {
+    return fault_message_;
+  }
+
  private:
   static void InitPlatformSignalHandlers();
 
@@ -520,6 +527,10 @@
 
   mirror::ObjectArray<mirror::ArtMethod>* default_imt_;
 
+  // Fault message, printed when we get a SIGSEGV.
+  Mutex fault_message_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  std::string fault_message_ GUARDED_BY(fault_message_lock_);
+
   // Method verifier set, used so that we can update their GC roots.
   Mutex method_verifiers_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   std::set<verifier::MethodVerifier*> method_verifiers_;
diff --git a/runtime/runtime_android.cc b/runtime/runtime_android.cc
index 2013294..14e5574 100644
--- a/runtime/runtime_android.cc
+++ b/runtime/runtime_android.cc
@@ -14,12 +14,58 @@
  * limitations under the License.
  */
 
-#include "runtime.h"
+#include <signal.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <inttypes.h>
+
+#include "base/logging.h"
+#include "base/mutex.h"
+#include "base/stringprintf.h"
+#include "thread-inl.h"
+#include "utils.h"
 
 namespace art {
 
+struct sigaction old_action;
+void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_context) {
+  static bool handlingUnexpectedSignal = false;
+  if (handlingUnexpectedSignal) {
+    LogMessageData data(__FILE__, __LINE__, INTERNAL_FATAL, -1);
+    LogMessage::LogLine(data, "HandleUnexpectedSignal reentered\n");
+    _exit(1);
+  }
+  handlingUnexpectedSignal = true;
+  gAborting++;  // set before taking any locks
+  MutexLock mu(Thread::Current(), *Locks::unexpected_signal_lock_);
+
+  Runtime* runtime = Runtime::Current();
+  if (runtime != nullptr) {
+    // Print this out first in case DumpObject faults.
+    LOG(INTERNAL_FATAL) << "Fault message: " << runtime->GetFaultMessage();
+    gc::Heap* heap = runtime->GetHeap();
+    if (heap != nullptr && info != nullptr) {
+      LOG(INTERNAL_FATAL) << "Dump heap object at fault address: ";
+      heap->DumpObject(LOG(INTERNAL_FATAL), reinterpret_cast<mirror::Object*>(info->si_addr));
+    }
+  }
+  // Run the old signal handler.
+  old_action.sa_sigaction(signal_number, info, raw_context);
+}
+
 void Runtime::InitPlatformSignalHandlers() {
-  // On a device, debuggerd will give us a stack trace. Nothing to do here.
+  // On the host, we don't have debuggerd to dump a stack for us when something unexpected happens.
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  sigemptyset(&action.sa_mask);
+  action.sa_sigaction = HandleUnexpectedSignal;
+  // Use the three-argument sa_sigaction handler.
+  action.sa_flags |= SA_SIGINFO;
+  // Use the alternate signal stack so we can catch stack overflows.
+  action.sa_flags |= SA_ONSTACK;
+  int rc = 0;
+  rc += sigaction(SIGSEGV, &action, &old_action);
+  CHECK_EQ(rc, 0);
 }
 
 }  // namespace art
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index 73ac034..f15e0bf 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -24,7 +24,7 @@
 #include "base/logging.h"
 #include "base/mutex.h"
 #include "base/stringprintf.h"
-#include "thread.h"
+#include "thread-inl.h"
 #include "utils.h"
 
 namespace art {
@@ -305,7 +305,15 @@
                       << "Thread: " << tid << " \"" << thread_name << "\"\n"
                       << "Registers:\n" << Dumpable<UContext>(thread_context) << "\n"
                       << "Backtrace:\n" << Dumpable<Backtrace>(thread_backtrace);
-
+  Runtime* runtime = Runtime::Current();
+  if (runtime != nullptr) {
+    gc::Heap* heap = runtime->GetHeap();
+    LOG(INTERNAL_FATAL) << "Fault message: " << runtime->GetFaultMessage();
+    if (heap != nullptr && info != nullptr) {
+      LOG(INTERNAL_FATAL) << "Dump heap object at fault address: ";
+      heap->DumpObject(LOG(INTERNAL_FATAL), reinterpret_cast<mirror::Object*>(info->si_addr));
+    }
+  }
   if (getenv("debug_db_uid") != NULL || getenv("art_wait_for_gdb_on_crash") != NULL) {
     LOG(INTERNAL_FATAL) << "********************************************************\n"
                         << "* Process " << getpid() << " thread " << tid << " \"" << thread_name << "\""
diff --git a/runtime/thread.h b/runtime/thread.h
index f9d31af..6df2b1c 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -42,6 +42,12 @@
 
 namespace art {
 
+namespace gc {
+namespace collector {
+class SemiSpace;
+}  // namespace collector
+}  // namespace gc
+
 namespace mirror {
   class ArtMethod;
   class Array;
@@ -61,7 +67,7 @@
 class Context;
 struct DebugInvokeReq;
 class DexFile;
-struct JavaVMExt;
+class JavaVMExt;
 struct JNIEnvExt;
 class Monitor;
 class Runtime;
@@ -851,6 +857,7 @@
 
  private:
   friend class Dbg;  // For SetStateUnsafe.
+  friend class gc::collector::SemiSpace;  // For getting stack traces.
   friend class Monitor;
   friend class MonitorInfo;
   friend class Runtime;  // For CreatePeer.
diff --git a/runtime/utils.cc b/runtime/utils.cc
index df1ab94..d8f8f8f 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1232,8 +1232,8 @@
 
     execv(program, &args[0]);
 
-    PLOG(FATAL) << "Failed to execv(" << command_line << ")";
-    return false;
+    PLOG(ERROR) << "Failed to execv(" << command_line << ")";
+    exit(1);
   } else {
     if (pid == -1) {
       *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
diff --git a/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc
index 0bf6767..c43fee5 100644
--- a/runtime/zip_archive_test.cc
+++ b/runtime/zip_archive_test.cc
@@ -32,10 +32,10 @@
 TEST_F(ZipArchiveTest, FindAndExtract) {
   std::string error_msg;
   UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileName().c_str(), &error_msg));
-  ASSERT_TRUE(zip_archive.get() != false) << error_msg;
+  ASSERT_TRUE(zip_archive.get() != nullptr) << error_msg;
   ASSERT_TRUE(error_msg.empty());
   UniquePtr<ZipEntry> zip_entry(zip_archive->Find("classes.dex", &error_msg));
-  ASSERT_TRUE(zip_entry.get() != false);
+  ASSERT_TRUE(zip_entry.get() != nullptr);
   ASSERT_TRUE(error_msg.empty());
 
   ScratchFile tmp;
diff --git a/tools/generate-operator-out.py b/tools/generate-operator-out.py
index 19266b4..56b8674 100755
--- a/tools/generate-operator-out.py
+++ b/tools/generate-operator-out.py
@@ -23,7 +23,7 @@
 import sys
 
 
-_ENUM_START_RE = re.compile(r'\benum\b\s+(\S+)\s+\{')
+_ENUM_START_RE = re.compile(r'\benum\b\s+(\S+)\s+:?.*\{')
 _ENUM_VALUE_RE = re.compile(r'([A-Za-z0-9_]+)(.*)')
 _ENUM_END_RE = re.compile(r'^\s*\};$')
 _ENUMS = {}