Merge "Run an empty checkpoint before marking ends in the CC collector."
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index 2d6b6a3..183f4e3 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -41,7 +41,7 @@
 ART_HOST_TEST_DIR := /tmp/test-art-$(shell echo $$PPID)
 endif
 
-# Core.oat location on the device.
+# core.oat location on the device.
 TARGET_CORE_OAT := $(ART_TARGET_TEST_DIR)/$(DEX2OAT_TARGET_ARCH)/core.oat
 ifdef TARGET_2ND_ARCH
 2ND_TARGET_CORE_OAT := $(ART_TARGET_TEST_DIR)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core.oat
@@ -49,7 +49,7 @@
 
 CORE_OAT_SUFFIX := .oat
 
-# Core.oat locations under the out directory.
+# core.oat locations under the out directory.
 HOST_CORE_OAT_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core
 ifneq ($(HOST_PREFER_32_BIT),true)
 2ND_HOST_CORE_OAT_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(2ND_ART_HOST_ARCH)/core
@@ -63,7 +63,7 @@
 
 CORE_IMG_SUFFIX := .art
 
-# Core.art locations under the out directory.
+# core.art locations under the out directory.
 HOST_CORE_IMG_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core
 ifneq ($(HOST_PREFER_32_BIT),true)
 2ND_HOST_CORE_IMG_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(2ND_ART_HOST_ARCH)/core
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 60668ed..dd21406 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -244,7 +244,7 @@
     endif
   endif
 
-  LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
+  LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime art/disassembler
 
   ifeq ($$(art_target_or_host),host)
     # For compiler driver TLS.
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index 6d48598..8a009cb 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -89,14 +89,15 @@
   DCHECK(dex_gc_map_.empty());
   size_t num_entries, ref_bitmap_bits, pc_bits;
   ComputeGcMapSizes(method_verifier, &num_entries, &ref_bitmap_bits, &pc_bits);
-  // There's a single byte to encode the size of each bitmap.
-  if (ref_bitmap_bits >= kBitsPerByte * 8192 /* 13-bit size */) {
+  const size_t ref_bitmap_bytes = RoundUp(ref_bitmap_bits, kBitsPerByte) / kBitsPerByte;
+  static constexpr size_t kFormatBits = 3;
+  // We have 16 - kFormatBits available for the ref_bitmap_bytes.
+  if ((ref_bitmap_bytes >> (16u - kFormatBits)) != 0) {
     LOG(WARNING) << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers: "
                  << PrettyMethod(method_verifier->GetMethodReference().dex_method_index,
                                  *method_verifier->GetMethodReference().dex_file);
     return false;
   }
-  size_t ref_bitmap_bytes = RoundUp(ref_bitmap_bits, kBitsPerByte) / kBitsPerByte;
   // There are 2 bytes to encode the number of entries.
   if (num_entries > std::numeric_limits<uint16_t>::max()) {
     LOG(WARNING) << "Cannot encode GC map for method with " << num_entries << " entries: "
@@ -122,7 +123,7 @@
   size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries) + 4;
   dex_gc_map_.reserve(table_size);
   // Write table header.
-  dex_gc_map_.push_back(format | ((ref_bitmap_bytes & ~0xFF) >> 5));
+  dex_gc_map_.push_back(format | ((ref_bitmap_bytes & ~0xFF) >> (kBitsPerByte - kFormatBits)));
   dex_gc_map_.push_back(ref_bitmap_bytes & 0xFF);
   dex_gc_map_.push_back(num_entries & 0xFF);
   dex_gc_map_.push_back((num_entries >> 8) & 0xFF);
@@ -147,7 +148,7 @@
   // Check that for every GC point there is a map entry, there aren't entries for non-GC points,
   // that the table data is well formed and all references are marked (or not) in the bitmap.
   verifier::DexPcToReferenceMap map(&data[0]);
-  DCHECK_EQ(data.size(), map.RawSize());
+  CHECK_EQ(data.size(), map.RawSize()) << map.NumEntries() << " " << map.RegWidth();
   size_t map_index = 0;
   const DexFile::CodeItem* code_item = method_verifier->CodeItem();
   for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) {
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index e0c56fc..633bc1b 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -250,8 +250,10 @@
 
 inline bool CompilerDriver::CanReferrerAssumeClassIsInitialized(mirror::Class* referrer_class,
                                                                 mirror::Class* klass) {
-  return (referrer_class != nullptr && referrer_class->IsSubClass(klass)) ||
-      CanAssumeClassIsInitialized(klass);
+  return (referrer_class != nullptr
+          && !referrer_class->IsInterface()
+          && referrer_class->IsSubClass(klass))
+      || CanAssumeClassIsInitialized(klass);
 }
 
 inline bool CompilerDriver::IsStaticFieldsClassInitialized(mirror::Class* referrer_class,
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 84b6a52..4cdf75b 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1410,7 +1410,9 @@
       is_in_image = IsImageClass(method->GetDeclaringClassDescriptor());
     } else {
       is_in_image = instruction_set_ != kX86 && instruction_set_ != kX86_64 &&
-                    heap->FindSpaceFromObject(method->GetDeclaringClass(), false)->IsImageSpace();
+                    heap->FindSpaceFromObject(method->GetDeclaringClass(), false)->IsImageSpace() &&
+                    !cl->IsQuickToInterpreterBridge(
+                        reinterpret_cast<const void*>(compiler_->GetEntryPointOf(method)));
     }
     if (!is_in_image) {
       // We can only branch directly to Methods that are resolved in the DexCache.
diff --git a/compiler/dwarf/headers.h b/compiler/dwarf/headers.h
index ad315ee..ae57755 100644
--- a/compiler/dwarf/headers.h
+++ b/compiler/dwarf/headers.h
@@ -54,9 +54,19 @@
   writer.PushUleb128(return_address_register.num());  // ubyte in DWARF2.
   writer.PushUleb128(1);  // z: Augmentation data size.
   if (is64bit) {
-    writer.PushUint8(address_type | DW_EH_PE_udata8);  // R: Pointer encoding.
+    if (address_type == DW_EH_PE_pcrel) {
+      writer.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata8);   // R: Pointer encoding.
+    } else {
+      DCHECK(address_type == DW_EH_PE_absptr);
+      writer.PushUint8(DW_EH_PE_absptr | DW_EH_PE_udata8);  // R: Pointer encoding.
+    }
   } else {
-    writer.PushUint8(address_type | DW_EH_PE_udata4);  // R: Pointer encoding.
+    if (address_type == DW_EH_PE_pcrel) {
+      writer.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);   // R: Pointer encoding.
+    } else {
+      DCHECK(address_type == DW_EH_PE_absptr);
+      writer.PushUint8(DW_EH_PE_absptr | DW_EH_PE_udata4);  // R: Pointer encoding.
+    }
   }
   writer.PushData(opcodes.data());
   writer.Pad(is64bit ? 8 : 4);
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index 97b3725..900dabe 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -1759,7 +1759,9 @@
     ValueBound lower_bound = range->GetLower();
     DCHECK(lower_bound.IsConstant());
     DCHECK(const_instr->GetValue() <= kMaxConstantForAddingDeoptimize);
-    DCHECK_EQ(lower_bound.GetConstant(), const_instr->GetValue() + 1);
+    // Note that the lower bound of the array length may have been refined
+    // through other instructions (such as `HNewArray(length - 4)`).
+    DCHECK_LE(const_instr->GetValue() + 1, lower_bound.GetConstant());
 
     // If array_length is less than lower_const, deoptimize.
     HBoundsCheck* bounds_check = first_constant_index_bounds_check_map_.Get(
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 2a555e4..c497526 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -681,26 +681,30 @@
       const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile();
       Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle(
           outer_compilation_unit_->GetClassLinker()->FindDexCache(outer_dex_file)));
-      Handle<mirror::Class> referrer_class(hs.NewHandle(GetOutermostCompilingClass()));
+      Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
 
       // The index at which the method's class is stored in the DexCache's type array.
       uint32_t storage_index = DexFile::kDexNoIndex;
-      bool is_referrer_class = (resolved_method->GetDeclaringClass() == referrer_class.Get());
-      if (is_referrer_class) {
-        storage_index = referrer_class->GetDexTypeIndex();
+      bool is_outer_class = (resolved_method->GetDeclaringClass() == outer_class.Get());
+      if (is_outer_class) {
+        storage_index = outer_class->GetDexTypeIndex();
       } else if (outer_dex_cache.Get() == dex_cache.Get()) {
         // Get `storage_index` from IsClassOfStaticMethodAvailableToReferrer.
         compiler_driver_->IsClassOfStaticMethodAvailableToReferrer(outer_dex_cache.Get(),
-                                                                   referrer_class.Get(),
+                                                                   GetCompilingClass(),
                                                                    resolved_method,
                                                                    method_idx,
                                                                    &storage_index);
       }
 
-      if (referrer_class.Get()->IsSubClass(resolved_method->GetDeclaringClass())) {
-        // If the referrer class is the declaring class or a subclass
+      if (!outer_class->IsInterface()
+          && outer_class->IsSubClass(resolved_method->GetDeclaringClass())) {
+        // If the outer class is the declaring class or a subclass
         // of the declaring class, no class initialization is needed
         // before the static method call.
+        // Note that in case of inlining, we do not need to add clinit checks
+        // to calls that satisfy this subclass check with any inlined methods. This
+        // will be detected by the optimization passes.
         clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone;
       } else if (storage_index != DexFile::kDexNoIndex) {
         // If the method's class type index is available, check
@@ -721,7 +725,7 @@
               graph_->GetCurrentMethod(),
               storage_index,
               *dex_compilation_unit_->GetDexFile(),
-              is_referrer_class,
+              is_outer_class,
               dex_pc);
           current_block_->AddInstruction(load_class);
           clinit_check = new (arena_) HClinitCheck(load_class, dex_pc);
@@ -810,6 +814,7 @@
   // Add move-result for StringFactory method.
   if (is_string_init) {
     uint32_t orig_this_reg = is_range ? register_index : args[0];
+    UpdateLocal(orig_this_reg, invoke);
     const VerifiedMethod* verified_method =
         compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex());
     if (verified_method == nullptr) {
@@ -823,10 +828,10 @@
     if (map_it != string_init_map.end()) {
       std::set<uint32_t> reg_set = map_it->second;
       for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) {
-        UpdateLocal(*set_it, invoke);
+        HInstruction* load_local = LoadLocal(orig_this_reg, Primitive::kPrimNot);
+        UpdateLocal(*set_it, load_local);
       }
     }
-    UpdateLocal(orig_this_reg, invoke);
   }
   return true;
 }
@@ -909,9 +914,9 @@
       soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
   Handle<mirror::Class> cls(hs.NewHandle(compiler_driver_->ResolveClass(
       soa, dex_cache, class_loader, type_index, dex_compilation_unit_)));
-  Handle<mirror::Class> compiling_class(hs.NewHandle(GetOutermostCompilingClass()));
+  Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
 
-  return compiling_class.Get() == cls.Get();
+  return outer_class.Get() == cls.Get();
 }
 
 bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 64f2c9a..cd10935 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -25,6 +25,7 @@
 #include "dex/verified_method.h"
 #include "driver/dex_compilation_unit.h"
 #include "gc_map_builder.h"
+#include "graph_visualizer.h"
 #include "leb128.h"
 #include "mapping_table.h"
 #include "mirror/array-inl.h"
@@ -159,12 +160,55 @@
   return block;
 }
 
+class DisassemblyScope {
+ public:
+  DisassemblyScope(HInstruction* instruction, const CodeGenerator& codegen)
+      : codegen_(codegen), instruction_(instruction), start_offset_(static_cast<size_t>(-1)) {
+    if (codegen_.GetDisassemblyInformation() != nullptr) {
+      start_offset_ = codegen_.GetAssembler().CodeSize();
+    }
+  }
+
+  ~DisassemblyScope() {
+    // We avoid building this data when we know it will not be used.
+    if (codegen_.GetDisassemblyInformation() != nullptr) {
+      codegen_.GetDisassemblyInformation()->AddInstructionInterval(
+          instruction_, start_offset_, codegen_.GetAssembler().CodeSize());
+    }
+  }
+
+ private:
+  const CodeGenerator& codegen_;
+  HInstruction* instruction_;
+  size_t start_offset_;
+};
+
+
+void CodeGenerator::GenerateSlowPaths() {
+  size_t code_start = 0;
+  for (size_t i = 0, e = slow_paths_.Size(); i < e; ++i) {
+    if (disasm_info_ != nullptr) {
+      code_start = GetAssembler()->CodeSize();
+    }
+    slow_paths_.Get(i)->EmitNativeCode(this);
+    if (disasm_info_ != nullptr) {
+      disasm_info_->AddSlowPathInterval(slow_paths_.Get(i), code_start, GetAssembler()->CodeSize());
+    }
+  }
+}
+
 void CodeGenerator::CompileInternal(CodeAllocator* allocator, bool is_baseline) {
   is_baseline_ = is_baseline;
   HGraphVisitor* instruction_visitor = GetInstructionVisitor();
   DCHECK_EQ(current_block_index_, 0u);
+
+  size_t frame_start = GetAssembler()->CodeSize();
   GenerateFrameEntry();
   DCHECK_EQ(GetAssembler()->cfi().GetCurrentCFAOffset(), static_cast<int>(frame_size_));
+  if (disasm_info_ != nullptr) {
+    disasm_info_->SetFrameEntryInterval(frame_start, GetAssembler()->CodeSize());
+  }
+
   for (size_t e = block_order_->Size(); current_block_index_ < e; ++current_block_index_) {
     HBasicBlock* block = block_order_->Get(current_block_index_);
     // Don't generate code for an empty block. Its predecessors will branch to its successor
@@ -174,6 +218,7 @@
     Bind(block);
     for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
+      DisassemblyScope disassembly_scope(current, *this);
       if (is_baseline) {
         InitLocationsBaseline(current);
       }
@@ -182,10 +227,7 @@
     }
   }
 
-  // Generate the slow paths.
-  for (size_t i = 0, e = slow_paths_.Size(); i < e; ++i) {
-    slow_paths_.Get(i)->EmitNativeCode(this);
-  }
+  GenerateSlowPaths();
 
   // Finalize instructions in assember;
   Finalize(allocator);
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index b1f1674..4cecd61 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -22,6 +22,7 @@
 #include "base/bit_field.h"
 #include "driver/compiler_options.h"
 #include "globals.h"
+#include "graph_visualizer.h"
 #include "locations.h"
 #include "memory_region.h"
 #include "nodes.h"
@@ -162,6 +163,7 @@
   virtual void Bind(HBasicBlock* block) = 0;
   virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) = 0;
   virtual Assembler* GetAssembler() = 0;
+  virtual const Assembler& GetAssembler() const = 0;
   virtual size_t GetWordSize() const = 0;
   virtual size_t GetFloatingPointSpillSlotSize() const = 0;
   virtual uintptr_t GetAddressOf(HBasicBlock* block) const = 0;
@@ -340,6 +342,9 @@
   static void CreateCommonInvokeLocationSummary(
       HInvoke* invoke, InvokeDexCallingConventionVisitor* visitor);
 
+  void SetDisassemblyInformation(DisassemblyInformation* info) { disasm_info_ = info; }
+  DisassemblyInformation* GetDisassemblyInformation() const { return disasm_info_; }
+
  protected:
   CodeGenerator(HGraph* graph,
                 size_t number_of_core_registers,
@@ -363,6 +368,7 @@
         stack_map_stream_(graph->GetArena()),
         block_order_(nullptr),
         is_baseline_(false),
+        disasm_info_(nullptr),
         graph_(graph),
         compiler_options_(compiler_options),
         slow_paths_(graph->GetArena(), 8),
@@ -446,9 +452,12 @@
   // Whether we are using baseline.
   bool is_baseline_;
 
+  DisassemblyInformation* disasm_info_;
+
  private:
   void InitLocationsBaseline(HInstruction* instruction);
   size_t GetStackOffsetOfSavedRegister(size_t index);
+  void GenerateSlowPaths();
   void CompileInternal(CodeAllocator* allocator, bool is_baseline);
   void BlockIfInRegister(Location location, bool is_out = false) const;
   void EmitEnvironment(HEnvironment* environment, SlowPathCode* slow_path);
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 7169679..bd0bfcd 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -436,6 +436,20 @@
       __ AdjustLabelPosition(block_label);
     }
   }
+  // Adjust pc offsets for the disassembly information.
+  if (disasm_info_ != nullptr) {
+    GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
+    frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
+    frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
+    for (auto& it : *disasm_info_->GetInstructionIntervals()) {
+      it.second.start = __ GetAdjustedPosition(it.second.start);
+      it.second.end = __ GetAdjustedPosition(it.second.end);
+    }
+    for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
+      it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
+      it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
+    }
+  }
 
   CodeGenerator::Finalize(allocator);
 }
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 1599a23..5b4b375 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -254,6 +254,10 @@
     return &assembler_;
   }
 
+  const ArmAssembler& GetAssembler() const OVERRIDE {
+    return assembler_;
+  }
+
   uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
     return GetLabelOf(block)->Position();
   }
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index f96810f..bbe3adc 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -283,6 +283,7 @@
   HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
   Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
+  const Arm64Assembler& GetAssembler() const OVERRIDE { return assembler_; }
   vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; }
 
   // Emit a write barrier.
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 534154f..ec36496 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -228,6 +228,7 @@
   HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
   Mips64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
+  const Mips64Assembler& GetAssembler() const OVERRIDE { return assembler_; }
 
   void MarkGCCard(GpuRegister object, GpuRegister value);
 
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 696d8d5..1ad89c9 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -245,6 +245,10 @@
     return &assembler_;
   }
 
+  const X86Assembler& GetAssembler() const OVERRIDE {
+    return assembler_;
+  }
+
   uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
     return GetLabelOf(block)->Position();
   }
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 215754c..a18e89a 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -245,6 +245,10 @@
     return &assembler_;
   }
 
+  const X86_64Assembler& GetAssembler() const OVERRIDE {
+    return assembler_;
+  }
+
   ParallelMoveResolverX86_64* GetMoveResolver() OVERRIDE {
     return &move_resolver_;
   }
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 9fd8d00..2b85c7c 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -16,17 +16,21 @@
 
 #include "graph_visualizer.h"
 
+#include <dlfcn.h>
+
+#include <cctype>
+#include <sstream>
+
 #include "code_generator.h"
 #include "dead_code_elimination.h"
+#include "disassembler.h"
 #include "licm.h"
 #include "nodes.h"
 #include "optimization.h"
 #include "reference_type_propagation.h"
 #include "register_allocator.h"
 #include "ssa_liveness_analysis.h"
-
-#include <cctype>
-#include <sstream>
+#include "utils/assembler.h"
 
 namespace art {
 
@@ -87,6 +91,60 @@
   }
 }
 
+typedef Disassembler* create_disasm_prototype(InstructionSet instruction_set,
+                                              DisassemblerOptions* options);
+class HGraphVisualizerDisassembler {
+ public:
+  HGraphVisualizerDisassembler(InstructionSet instruction_set, const uint8_t* base_address)
+      : instruction_set_(instruction_set) {
+    libart_disassembler_handle_ =
+        dlopen(kIsDebugBuild ? "libartd-disassembler.so" : "libart-disassembler.so", RTLD_NOW);
+    if (libart_disassembler_handle_ == nullptr) {
+      LOG(WARNING) << "Failed to dlopen libart-disassembler: " << dlerror();
+      return;
+    }
+    create_disasm_prototype* create_disassembler = reinterpret_cast<create_disasm_prototype*>(
+        dlsym(libart_disassembler_handle_, "create_disassembler"));
+    if (create_disassembler == nullptr) {
+      LOG(WARNING) << "Could not find create_disassembler entry: " << dlerror();
+      return;
+    }
+    // Reading the disassembly from 0x0 is easier, so we print relative
+    // addresses. We will only disassemble the code once everything has
+    // been generated, so we can read data in literal pools.
+    disassembler_ = std::unique_ptr<Disassembler>((*create_disassembler)(
+            instruction_set,
+            new DisassemblerOptions(/* absolute_addresses */ false,
+                                    base_address,
+                                    /* can_read_literals */ true)));
+  }
+
+  ~HGraphVisualizerDisassembler() {
+    // We need to call ~Disassembler() before we close the library.
+    disassembler_.reset();
+    if (libart_disassembler_handle_ != nullptr) {
+      dlclose(libart_disassembler_handle_);
+    }
+  }
+
+  void Disassemble(std::ostream& output, size_t start, size_t end) const {
+    const uint8_t* base = disassembler_->GetDisassemblerOptions()->base_address_;
+    if (instruction_set_ == kThumb2) {
+      // ARM and Thumb-2 use the same disassembler. The bottom bit of the
+      // address is used to distinguish between the two.
+      base += 1;
+    }
+    disassembler_->Dump(output, base + start, base + end);
+  }
+
+ private:
+  InstructionSet instruction_set_;
+  std::unique_ptr<Disassembler> disassembler_;
+
+  void* libart_disassembler_handle_;
+};
+
+
 /**
  * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
  */
@@ -96,12 +154,19 @@
                           std::ostream& output,
                           const char* pass_name,
                           bool is_after_pass,
-                          const CodeGenerator& codegen)
+                          const CodeGenerator& codegen,
+                          const DisassemblyInformation* disasm_info = nullptr)
       : HGraphVisitor(graph),
         output_(output),
         pass_name_(pass_name),
         is_after_pass_(is_after_pass),
         codegen_(codegen),
+        disasm_info_(disasm_info),
+        disassembler_(disasm_info_ != nullptr
+                      ? new HGraphVisualizerDisassembler(
+                            codegen_.GetInstructionSet(),
+                            codegen_.GetAssembler().CodeBufferBaseAddress())
+                      : nullptr),
         indent_(0) {}
 
   void StartTag(const char* name) {
@@ -173,6 +238,9 @@
       HBasicBlock* predecessor = block->GetPredecessors().Get(i);
       output_ << " \"B" << predecessor->GetBlockId() << "\" ";
     }
+    if (block->IsEntryBlock() && (disasm_info_ != nullptr)) {
+      output_ << " \"" << kDisassemblyBlockFrameEntry << "\" ";
+    }
     output_<< std::endl;
   }
 
@@ -183,6 +251,11 @@
       HBasicBlock* successor = block->GetSuccessors().Get(i);
       output_ << " \"B" << successor->GetBlockId() << "\" ";
     }
+    if (block->IsExitBlock() &&
+        (disasm_info_ != nullptr) &&
+        !disasm_info_->GetSlowPathIntervals().empty()) {
+      output_ << " \"" << kDisassemblyBlockSlowPaths << "\" ";
+    }
     output_<< std::endl;
   }
 
@@ -266,9 +339,9 @@
     StartAttributeStream("kind") << barrier->GetBarrierKind();
   }
 
-  void VisitLoadClass(HLoadClass* load_cass) OVERRIDE {
+  void VisitLoadClass(HLoadClass* load_class) OVERRIDE {
     StartAttributeStream("gen_clinit_check") << std::boolalpha
-        << load_cass->MustGenerateClinitCheck() << std::noboolalpha;
+        << load_class->MustGenerateClinitCheck() << std::noboolalpha;
   }
 
   void VisitCheckCast(HCheckCast* check_cast) OVERRIDE {
@@ -378,10 +451,20 @@
         }
       }
     }
+    if (disasm_info_ != nullptr) {
+      DCHECK(disassembler_ != nullptr);
+      // If the information is available, disassemble the code generated for
+      // this instruction.
+      auto it = disasm_info_->GetInstructionIntervals().find(instruction);
+      if (it != disasm_info_->GetInstructionIntervals().end()
+          && it->second.start != it->second.end) {
+        output_ << std::endl;
+        disassembler_->Disassemble(output_, it->second.start, it->second.end);
+      }
+    }
   }
 
   void PrintInstructions(const HInstructionList& list) {
-    const char* kEndInstructionMarker = "<|@";
     for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
       HInstruction* instruction = it.Current();
       int bci = 0;
@@ -399,11 +482,83 @@
     }
   }
 
+  void DumpStartOfDisassemblyBlock(const char* block_name,
+                                   int predecessor_index,
+                                   int successor_index) {
+    StartTag("block");
+    PrintProperty("name", block_name);
+    PrintInt("from_bci", -1);
+    PrintInt("to_bci", -1);
+    if (predecessor_index != -1) {
+      PrintProperty("predecessors", "B", predecessor_index);
+    } else {
+      PrintEmptyProperty("predecessors");
+    }
+    if (successor_index != -1) {
+      PrintProperty("successors", "B", successor_index);
+    } else {
+      PrintEmptyProperty("successors");
+    }
+    PrintEmptyProperty("xhandlers");
+    PrintEmptyProperty("flags");
+    StartTag("states");
+    StartTag("locals");
+    PrintInt("size", 0);
+    PrintProperty("method", "None");
+    EndTag("locals");
+    EndTag("states");
+    StartTag("HIR");
+  }
+
+  void DumpEndOfDisassemblyBlock() {
+    EndTag("HIR");
+    EndTag("block");
+  }
+
+  void DumpDisassemblyBlockForFrameEntry() {
+    DumpStartOfDisassemblyBlock(kDisassemblyBlockFrameEntry,
+                                -1,
+                                GetGraph()->GetEntryBlock()->GetBlockId());
+    output_ << "    0 0 disasm " << kDisassemblyBlockFrameEntry << " ";
+    GeneratedCodeInterval frame_entry = disasm_info_->GetFrameEntryInterval();
+    if (frame_entry.start != frame_entry.end) {
+      output_ << std::endl;
+      disassembler_->Disassemble(output_, frame_entry.start, frame_entry.end);
+    }
+    output_ << kEndInstructionMarker << std::endl;
+    DumpEndOfDisassemblyBlock();
+  }
+
+  void DumpDisassemblyBlockForSlowPaths() {
+    if (disasm_info_->GetSlowPathIntervals().empty()) {
+      return;
+    }
+    // If the graph has an exit block we attach the block for the slow paths
+    // after it. Else we just add the block to the graph without linking it to
+    // any other.
+    DumpStartOfDisassemblyBlock(
+        kDisassemblyBlockSlowPaths,
+        GetGraph()->HasExitBlock() ? GetGraph()->GetExitBlock()->GetBlockId() : -1,
+        -1);
+    for (SlowPathCodeInfo info : disasm_info_->GetSlowPathIntervals()) {
+      output_ << "    0 0 disasm " << info.slow_path->GetDescription() << std::endl;
+      disassembler_->Disassemble(output_, info.code_interval.start, info.code_interval.end);
+      output_ << kEndInstructionMarker << std::endl;
+    }
+    DumpEndOfDisassemblyBlock();
+  }
+
   void Run() {
     StartTag("cfg");
     std::string pass_desc = std::string(pass_name_) + (is_after_pass_ ? " (after)" : " (before)");
     PrintProperty("name", pass_desc.c_str());
+    if (disasm_info_ != nullptr) {
+      DumpDisassemblyBlockForFrameEntry();
+    }
     VisitInsertionOrder();
+    if (disasm_info_ != nullptr) {
+      DumpDisassemblyBlockForSlowPaths();
+    }
     EndTag("cfg");
   }
 
@@ -450,11 +605,17 @@
     EndTag("block");
   }
 
+  static constexpr const char* const kEndInstructionMarker = "<|@";
+  static constexpr const char* const kDisassemblyBlockFrameEntry = "FrameEntry";
+  static constexpr const char* const kDisassemblyBlockSlowPaths = "SlowPaths";
+
  private:
   std::ostream& output_;
   const char* pass_name_;
   const bool is_after_pass_;
   const CodeGenerator& codegen_;
+  const DisassemblyInformation* disasm_info_;
+  std::unique_ptr<HGraphVisualizerDisassembler> disassembler_;
   size_t indent_;
 
   DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
@@ -483,4 +644,13 @@
   }
 }
 
+void HGraphVisualizer::DumpGraphWithDisassembly() const {
+  DCHECK(output_ != nullptr);
+  if (!graph_->GetBlocks().IsEmpty()) {
+    HGraphVisualizerPrinter printer(
+        graph_, *output_, "disassembly", true, codegen_, codegen_.GetDisassemblyInformation());
+    printer.Run();
+  }
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
index 513bceb..b6b66df 100644
--- a/compiler/optimizing/graph_visualizer.h
+++ b/compiler/optimizing/graph_visualizer.h
@@ -19,6 +19,8 @@
 
 #include <ostream>
 
+#include "arch/instruction_set.h"
+#include "base/arena_containers.h"
 #include "base/value_object.h"
 
 namespace art {
@@ -26,11 +28,75 @@
 class CodeGenerator;
 class DexCompilationUnit;
 class HGraph;
+class HInstruction;
+class SlowPathCode;
 
 /**
  * This class outputs the HGraph in the C1visualizer format.
  * Note: Currently only works if the compiler is single threaded.
  */
+struct GeneratedCodeInterval {
+  size_t start;
+  size_t end;
+};
+
+struct SlowPathCodeInfo {
+  const SlowPathCode* slow_path;
+  GeneratedCodeInterval code_interval;
+};
+
+// This information is filled by the code generator. It will be used by the
+// graph visualizer to associate disassembly of the generated code with the
+// instructions and slow paths. We assume that the generated code follows the
+// following structure:
+//   - frame entry
+//   - instructions
+//   - slow paths
+class DisassemblyInformation {
+ public:
+  explicit DisassemblyInformation(ArenaAllocator* allocator)
+      : frame_entry_interval_({0, 0}),
+        instruction_intervals_(std::less<const HInstruction*>(), allocator->Adapter()),
+        slow_path_intervals_(allocator->Adapter()) {}
+
+  void SetFrameEntryInterval(size_t start, size_t end) {
+    frame_entry_interval_ = {start, end};
+  }
+
+  void AddInstructionInterval(HInstruction* instr, size_t start, size_t end) {
+    instruction_intervals_.Put(instr, {start, end});
+  }
+
+  void AddSlowPathInterval(SlowPathCode* slow_path, size_t start, size_t end) {
+    slow_path_intervals_.push_back({slow_path, {start, end}});
+  }
+
+  GeneratedCodeInterval GetFrameEntryInterval() const {
+    return frame_entry_interval_;
+  }
+
+  GeneratedCodeInterval* GetFrameEntryInterval() {
+    return &frame_entry_interval_;
+  }
+
+  const ArenaSafeMap<const HInstruction*, GeneratedCodeInterval>& GetInstructionIntervals() const {
+    return instruction_intervals_;
+  }
+
+  ArenaSafeMap<const HInstruction*, GeneratedCodeInterval>* GetInstructionIntervals() {
+    return &instruction_intervals_;
+  }
+
+  const ArenaVector<SlowPathCodeInfo>& GetSlowPathIntervals() const { return slow_path_intervals_; }
+
+  ArenaVector<SlowPathCodeInfo>* GetSlowPathIntervals() { return &slow_path_intervals_; }
+
+ private:
+  GeneratedCodeInterval frame_entry_interval_;
+  ArenaSafeMap<const HInstruction*, GeneratedCodeInterval> instruction_intervals_;
+  ArenaVector<SlowPathCodeInfo> slow_path_intervals_;
+};
+
 class HGraphVisualizer : public ValueObject {
  public:
   HGraphVisualizer(std::ostream* output,
@@ -39,6 +105,7 @@
 
   void PrintHeader(const char* method_name) const;
   void DumpGraph(const char* pass_name, bool is_after_pass = true) const;
+  void DumpGraphWithDisassembly() const;
 
  private:
   std::ostream* const output_;
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 678924d..e375f7b 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -324,6 +324,11 @@
         block->ReplaceAndRemoveInstructionWith(
             equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value));
         RecordSimplification();
+      } else {
+        // Replace (bool_value == integer_not_zero_nor_one_constant) with false
+        equal->ReplaceWith(GetGraph()->GetIntConstant(0));
+        block->RemoveInstruction(equal);
+        RecordSimplification();
       }
     }
   }
@@ -347,6 +352,11 @@
         not_equal->ReplaceWith(input_value);
         block->RemoveInstruction(not_equal);
         RecordSimplification();
+      } else {
+        // Replace (bool_value != integer_not_zero_nor_one_constant) with true
+        not_equal->ReplaceWith(GetGraph()->GetIntConstant(1));
+        block->RemoveInstruction(not_equal);
+        RecordSimplification();
       }
     }
   }
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index ad67813..0c7b6f7 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -92,19 +92,21 @@
  public:
   PassInfoPrinter(HGraph* graph,
                   const char* method_name,
-                  const CodeGenerator& codegen,
+                  CodeGenerator* codegen,
                   std::ostream* visualizer_output,
                   CompilerDriver* compiler_driver)
       : method_name_(method_name),
         timing_logger_enabled_(compiler_driver->GetDumpPasses()),
         timing_logger_(method_name, true, true),
+        disasm_info_(graph->GetArena()),
         visualizer_enabled_(!compiler_driver->GetDumpCfgFileName().empty()),
-        visualizer_(visualizer_output, graph, codegen) {
+        visualizer_(visualizer_output, graph, *codegen) {
     if (strstr(method_name, kStringFilter) == nullptr) {
       timing_logger_enabled_ = visualizer_enabled_ = false;
     }
     if (visualizer_enabled_) {
       visualizer_.PrintHeader(method_name_);
+      codegen->SetDisassemblyInformation(&disasm_info_);
     }
   }
 
@@ -115,6 +117,12 @@
     }
   }
 
+  void DumpDisassembly() const {
+    if (visualizer_enabled_) {
+      visualizer_.DumpGraphWithDisassembly();
+    }
+  }
+
  private:
   void StartPass(const char* pass_name) {
     // Dump graph first, then start timer.
@@ -141,6 +149,8 @@
   bool timing_logger_enabled_;
   TimingLogger timing_logger_;
 
+  DisassemblyInformation disasm_info_;
+
   bool visualizer_enabled_;
   HGraphVisualizer visualizer_;
 
@@ -224,12 +234,13 @@
                                    CodeGenerator* codegen,
                                    CompilerDriver* driver,
                                    const DexCompilationUnit& dex_compilation_unit,
-                                   PassInfoPrinter* pass_info) const;
+                                   PassInfoPrinter* pass_info_printer) const;
 
   // Just compile without doing optimizations.
   CompiledMethod* CompileBaseline(CodeGenerator* codegen,
                                   CompilerDriver* driver,
-                                  const DexCompilationUnit& dex_compilation_unit) const;
+                                  const DexCompilationUnit& dex_compilation_unit,
+                                  PassInfoPrinter* pass_info_printer) const;
 
   std::unique_ptr<OptimizingCompilerStats> compilation_stats_;
 
@@ -429,7 +440,7 @@
 
   MaybeRecordStat(MethodCompilationStat::kCompiledOptimized);
 
-  return CompiledMethod::SwapAllocCompiledMethod(
+  CompiledMethod* compiled_method = CompiledMethod::SwapAllocCompiledMethod(
       compiler_driver,
       codegen->GetInstructionSet(),
       ArrayRef<const uint8_t>(allocator.GetMemory()),
@@ -445,12 +456,15 @@
       ArrayRef<const uint8_t>(),  // native_gc_map.
       ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()),
       ArrayRef<const LinkerPatch>());
+  pass_info_printer->DumpDisassembly();
+  return compiled_method;
 }
 
 CompiledMethod* OptimizingCompiler::CompileBaseline(
     CodeGenerator* codegen,
     CompilerDriver* compiler_driver,
-    const DexCompilationUnit& dex_compilation_unit) const {
+    const DexCompilationUnit& dex_compilation_unit,
+    PassInfoPrinter* pass_info_printer) const {
   CodeVectorAllocator allocator;
   codegen->CompileBaseline(&allocator);
 
@@ -466,7 +480,7 @@
   codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
 
   MaybeRecordStat(MethodCompilationStat::kCompiledBaseline);
-  return CompiledMethod::SwapAllocCompiledMethod(
+  CompiledMethod* compiled_method = CompiledMethod::SwapAllocCompiledMethod(
       compiler_driver,
       codegen->GetInstructionSet(),
       ArrayRef<const uint8_t>(allocator.GetMemory()),
@@ -482,6 +496,8 @@
       AlignVectorSize(gc_map),
       ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()),
       ArrayRef<const LinkerPatch>());
+  pass_info_printer->DumpDisassembly();
+  return compiled_method;
 }
 
 CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
@@ -557,7 +573,7 @@
 
   PassInfoPrinter pass_info_printer(graph,
                                     method_name.c_str(),
-                                    *codegen.get(),
+                                    codegen.get(),
                                     visualizer_output_.get(),
                                     compiler_driver);
 
@@ -617,7 +633,10 @@
       MaybeRecordStat(MethodCompilationStat::kNotOptimizedRegisterAllocator);
     }
 
-    return CompileBaseline(codegen.get(), compiler_driver, dex_compilation_unit);
+    return CompileBaseline(codegen.get(),
+                           compiler_driver,
+                           dex_compilation_unit,
+                           &pass_info_printer);
   } else {
     return nullptr;
   }
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index a048c85..6784098 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -222,9 +222,10 @@
   ClassLinker* cl = Runtime::Current()->GetClassLinker();
   mirror::DexCache* dex_cache = cl->FindDexCache(info.GetDexFile());
   ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), dex_cache);
-  DCHECK(field != nullptr);
-  mirror::Class* klass = field->GetType<false>();
-  SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
+  if (field != nullptr) {
+    mirror::Class* klass = field->GetType<false>();
+    SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
+  }
 }
 
 void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
@@ -323,9 +324,10 @@
   mirror::DexCache* dex_cache = cl->FindDexCache(instr->GetDexFile());
   ArtMethod* method = dex_cache->GetResolvedMethod(
       instr->GetDexMethodIndex(), cl->GetImagePointerSize());
-  DCHECK(method != nullptr);
-  mirror::Class* klass = method->GetReturnType(false);
-  SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
+  if (method != nullptr) {
+    mirror::Class* klass = method->GetReturnType(false);
+    SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
+  }
 }
 
 void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index eb8de06..077579c 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -44,6 +44,10 @@
   return vixl_masm_->BufferCapacity() - vixl_masm_->RemainingBufferSpace();
 }
 
+const uint8_t* Arm64Assembler::CodeBufferBaseAddress() const {
+  return vixl_masm_->GetStartAddress<uint8_t*>();
+}
+
 void Arm64Assembler::FinalizeInstructions(const MemoryRegion& region) {
   // Copy the instructions from the buffer.
   MemoryRegion from(vixl_masm_->GetStartAddress<void*>(), CodeSize());
diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h
index b53c11b..db95537 100644
--- a/compiler/utils/arm64/assembler_arm64.h
+++ b/compiler/utils/arm64/assembler_arm64.h
@@ -77,7 +77,8 @@
   void FinalizeCode() OVERRIDE;
 
   // Size of generated code.
-  size_t CodeSize() const;
+  size_t CodeSize() const OVERRIDE;
+  const uint8_t* CodeBufferBaseAddress() const OVERRIDE;
 
   // Copy instructions out of assembly buffer into the given region of memory.
   void FinalizeInstructions(const MemoryRegion& region);
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 0381af3..ee2d594 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -386,6 +386,7 @@
 
   // Size of generated code
   virtual size_t CodeSize() const { return buffer_.Size(); }
+  virtual const uint8_t* CodeBufferBaseAddress() const { return buffer_.contents(); }
 
   // Copy instructions out of assembly buffer into the given region of memory
   virtual void FinalizeInstructions(const MemoryRegion& region) {
diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc
index 6334717..e604c1f 100644
--- a/disassembler/disassembler.cc
+++ b/disassembler/disassembler.cc
@@ -55,4 +55,8 @@
   }
 }
 
+Disassembler* create_disassembler(InstructionSet instruction_set, DisassemblerOptions* options) {
+  return Disassembler::Create(instruction_set, options);
+}
+
 }  // namespace art
diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h
index 966ee3a..b99e5c2 100644
--- a/disassembler/disassembler.h
+++ b/disassembler/disassembler.h
@@ -63,6 +63,10 @@
   // Dump instructions within a range.
   virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) = 0;
 
+  const DisassemblerOptions* GetDisassemblerOptions() const {
+    return disassembler_options_;
+  }
+
  protected:
   explicit Disassembler(DisassemblerOptions* disassembler_options)
       : disassembler_options_(disassembler_options) {
@@ -80,6 +84,9 @@
   return (value & (1 << bit)) != 0;
 }
 
+extern "C"
+Disassembler* create_disassembler(InstructionSet instruction_set, DisassemblerOptions* options);
+
 }  // namespace art
 
 #endif  // ART_DISASSEMBLER_DISASSEMBLER_H_
diff --git a/oatdump/Android.mk b/oatdump/Android.mk
index f01afc5..a3ef38d 100644
--- a/oatdump/Android.mk
+++ b/oatdump/Android.mk
@@ -47,12 +47,28 @@
 	@echo Output in $(ART_DUMP_OAT_PATH)/core.host.oatdump.txt
 endif
 
-.PHONY: dump-oat-core-target
+.PHONY: dump-oat-core-target-$(TARGET_ARCH)
 ifeq ($(ART_BUILD_TARGET),true)
-dump-oat-core-target: $(TARGET_CORE_IMAGE_default_no-pic_32) $(OATDUMP)
+dump-oat-core-target-$(TARGET_ARCH): $(TARGET_CORE_IMAGE_default_no-pic_$(ART_PHONY_TEST_TARGET_SUFFIX)) $(OATDUMP)
 	$(OATDUMP) --image=$(TARGET_CORE_IMG_LOCATION) \
-	  --output=$(ART_DUMP_OAT_PATH)/core.target.oatdump.txt --instruction-set=$(TARGET_ARCH)
-	@echo Output in $(ART_DUMP_OAT_PATH)/core.target.oatdump.txt
+	  --output=$(ART_DUMP_OAT_PATH)/core.target.$(TARGET_ARCH).oatdump.txt --instruction-set=$(TARGET_ARCH)
+	@echo Output in $(ART_DUMP_OAT_PATH)/core.target.$(TARGET_ARCH).oatdump.txt
+endif
+
+ifdef TARGET_2ND_ARCH
+.PHONY: dump-oat-core-target-$(TARGET_2ND_ARCH)
+ifeq ($(ART_BUILD_TARGET),true)
+dump-oat-core-target-$(TARGET_2ND_ARCH): $(TARGET_CORE_IMAGE_default_no-pic_$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)) $(OATDUMP)
+	$(OATDUMP) --image=$(TARGET_CORE_IMG_LOCATION) \
+	  --output=$(ART_DUMP_OAT_PATH)/core.target.$(TARGET_2ND_ARCH).oatdump.txt --instruction-set=$(TARGET_2ND_ARCH)
+	@echo Output in $(ART_DUMP_OAT_PATH)/core.target.$(TARGET_2ND_ARCH).oatdump.txt
+endif
+endif
+
+.PHONY: dump-oat-core-target
+dump-oat-core-target: dump-oat-core-target-$(TARGET_ARCH)
+ifdef TARGET_2ND_ARCH
+dump-oat-core-target: dump-oat-core-target-$(TARGET_2ND_ARCH)
 endif
 
 .PHONY: dump-oat-boot-$(TARGET_ARCH)
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 9e9dea6..b3801b3 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -355,7 +355,7 @@
       disassembler_(Disassembler::Create(instruction_set_,
                                          new DisassemblerOptions(options_.absolute_addresses_,
                                                                  oat_file.Begin(),
-                                                                 true /* can_read_litals_ */))) {
+                                                                 true /* can_read_literals_ */))) {
     CHECK(options_.class_loader_ != nullptr);
     CHECK(options_.class_filter_ != nullptr);
     CHECK(options_.method_filter_ != nullptr);
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index 90b0d53..d81e0a9 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -70,7 +70,7 @@
   struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
   *out_sp = static_cast<uintptr_t>(sc->arm_sp);
-  VLOG(signals) << "sp: " << *out_sp;
+  VLOG(signals) << "sp: " << std::hex << *out_sp;
   if (*out_sp == 0) {
     return;
   }
diff --git a/runtime/barrier.cc b/runtime/barrier.cc
index d21f551..0d842cc 100644
--- a/runtime/barrier.cc
+++ b/runtime/barrier.cc
@@ -16,6 +16,7 @@
 
 #include "barrier.h"
 
+#include "base/logging.h"
 #include "base/mutex.h"
 #include "base/time_utils.h"
 #include "thread.h"
@@ -87,7 +88,14 @@
 }
 
 Barrier::~Barrier() {
-  CHECK_EQ(count_, 0) << "Attempted to destroy barrier with non zero count";
+  if (gAborting == 0) {
+    // Only check when not aborting.
+    CHECK_EQ(count_, 0) << "Attempted to destroy barrier with non zero count";
+  } else {
+    if (count_ != 0) {
+      LOG(WARNING) << "Attempted to destroy barrier with non zero count " << count_;
+    }
+  }
 }
 
 }  // namespace art
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index bf6aef0..27a9ba0 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -172,6 +172,15 @@
                                                         bool allow_soft_failures,
                                                         std::string* error) {
   DCHECK(class_def != nullptr);
+
+  // A class must not be abstract and final.
+  if ((class_def->access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) {
+    *error = "Verifier rejected class ";
+    *error += PrettyDescriptor(dex_file->GetClassDescriptor(*class_def));
+    *error += ": class is abstract and final.";
+    return kHardFailure;
+  }
+
   const uint8_t* class_data = dex_file->GetClassData(*class_def);
   if (class_data == nullptr) {
     // empty class, probably a marker interface
@@ -858,14 +867,18 @@
     case Instruction::kVerifyVarArgNonZero:
       // Fall-through.
     case Instruction::kVerifyVarArg: {
-      if (inst->GetVerifyExtraFlags() == Instruction::kVerifyVarArgNonZero && inst->VRegA() <= 0) {
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid arg count (" << inst->VRegA() << ") in "
+      // Instructions that can actually return a negative value shouldn't have this flag.
+      uint32_t v_a = dchecked_integral_cast<uint32_t>(inst->VRegA());
+      if ((inst->GetVerifyExtraFlags() == Instruction::kVerifyVarArgNonZero && v_a == 0) ||
+          v_a > Instruction::kMaxVarArgRegs) {
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid arg count (" << v_a << ") in "
                                              "non-range invoke";
         return false;
       }
+
       uint32_t args[Instruction::kMaxVarArgRegs];
       inst->GetVarArgs(args);
-      result = result && CheckVarArgRegs(inst->VRegA(), args);
+      result = result && CheckVarArgRegs(v_a, args);
       break;
     }
     case Instruction::kVerifyVarArgRangeNonZero:
@@ -1176,10 +1189,6 @@
 }
 
 bool MethodVerifier::CheckVarArgRegs(uint32_t vA, uint32_t arg[]) {
-  if (vA > Instruction::kMaxVarArgRegs) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid arg count (" << vA << ") in non-range invoke)";
-    return false;
-  }
   uint16_t registers_size = code_item_->registers_size_;
   for (uint32_t idx = 0; idx < vA; idx++) {
     if (arg[idx] >= registers_size) {
@@ -1292,13 +1301,22 @@
 
 bool MethodVerifier::SetTypesFromSignature() {
   RegisterLine* reg_line = reg_table_.GetLine(0);
-  int arg_start = code_item_->registers_size_ - code_item_->ins_size_;
+
+  // Should have been verified earlier.
+  DCHECK_GE(code_item_->registers_size_, code_item_->ins_size_);
+
+  uint32_t arg_start = code_item_->registers_size_ - code_item_->ins_size_;
   size_t expected_args = code_item_->ins_size_;   /* long/double count as two */
 
-  DCHECK_GE(arg_start, 0);      /* should have been verified earlier */
   // Include the "this" pointer.
   size_t cur_arg = 0;
   if (!IsStatic()) {
+    if (expected_args == 0) {
+      // Expect at least a receiver.
+      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected 0 args, but method is not static";
+      return false;
+    }
+
     // If this is a constructor for a class other than java.lang.Object, mark the first ("this")
     // argument as uninitialized. This restricts field access until the superclass constructor is
     // called.
diff --git a/test/137-cfi/run b/test/137-cfi/run
index 78cf2aa..ecbbbc7 100755
--- a/test/137-cfi/run
+++ b/test/137-cfi/run
@@ -14,8 +14,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Temporarily disable address space layout randomization (ASLR).
-# This is need on host so that the linker loads core.oat at fixed address.
-export LD_USE_LOAD_BIAS=1
-
 exec ${RUN} "$@"
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index 3c3b939..aa4dda1 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -927,6 +927,36 @@
     return (false == arg) ? 3 : 5;
   }
 
+  /// CHECK-START: boolean Main.EqualBoolVsIntConst(boolean) instruction_simplifier_after_bce (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const2:i\d+>>   IntConstant 2
+  /// CHECK-DAG:     <<BoolNot:z\d+>>  BooleanNot [<<Arg>>]
+  /// CHECK-DAG:     <<Cond:z\d+>>     Equal [<<BoolNot>>,<<Const2>>]
+  /// CHECK-DAG:                       Return [<<Cond>>]
+
+  /// CHECK-START: boolean Main.EqualBoolVsIntConst(boolean) instruction_simplifier_after_bce (after)
+  /// CHECK-DAG:     <<False:i\d+>>    IntConstant 0
+  /// CHECK-DAG:                       Return [<<False>>]
+
+  public static boolean EqualBoolVsIntConst(boolean arg) {
+    return (arg ? 0 : 1) == 2;
+  }
+
+  /// CHECK-START: boolean Main.NotEqualBoolVsIntConst(boolean) instruction_simplifier_after_bce (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const2:i\d+>>   IntConstant 2
+  /// CHECK-DAG:     <<BoolNot:z\d+>>  BooleanNot [<<Arg>>]
+  /// CHECK-DAG:     <<Cond:z\d+>>     NotEqual [<<BoolNot>>,<<Const2>>]
+  /// CHECK-DAG:                       Return [<<Cond>>]
+
+  /// CHECK-START: boolean Main.NotEqualBoolVsIntConst(boolean) instruction_simplifier_after_bce (after)
+  /// CHECK-DAG:     <<True:i\d+>>     IntConstant 1
+  /// CHECK-DAG:                       Return [<<True>>]
+
+  public static boolean NotEqualBoolVsIntConst(boolean arg) {
+    return (arg ? 0 : 1) != 2;
+  }
+
   /*
    * Test simplification of double Boolean negation. Note that sometimes
    * both negations can be removed but we only expect the simplifier to
diff --git a/test/508-checker-disassembly/expected.txt b/test/508-checker-disassembly/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/508-checker-disassembly/expected.txt
diff --git a/test/508-checker-disassembly/info.txt b/test/508-checker-disassembly/info.txt
new file mode 100644
index 0000000..4a25b21
--- /dev/null
+++ b/test/508-checker-disassembly/info.txt
@@ -0,0 +1 @@
+Check that inlining disassembly in the .cfg works correctly.
diff --git a/test/508-checker-disassembly/src/Main.java b/test/508-checker-disassembly/src/Main.java
new file mode 100644
index 0000000..29c9374
--- /dev/null
+++ b/test/508-checker-disassembly/src/Main.java
@@ -0,0 +1,29 @@
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+public class Main {
+  // A very simple check that disassembly information has been added to the
+  // graph. We check that sections have been added for the frame entry and a
+  // slow path.
+  /// CHECK-START: int Main.DisassembledFunction(int) disassembly (after)
+  /// CHECK:       FrameEntry
+  /// CHECK:       DivZeroCheckSlowPath{{.*}}
+  public int DisassembledFunction(int arg) {
+    return 7 / arg;
+  }
+
+  public static void main(String[] args) {}
+}
diff --git a/test/508-referrer-method/expected.txt b/test/508-referrer-method/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/508-referrer-method/expected.txt
diff --git a/test/508-referrer-method/info.txt b/test/508-referrer-method/info.txt
new file mode 100644
index 0000000..5f533e7
--- /dev/null
+++ b/test/508-referrer-method/info.txt
@@ -0,0 +1,2 @@
+Regression test for the optimizing compiler, which used
+to do incorrect access checks on static calls when inlining.
diff --git a/test/508-referrer-method/src/Main.java b/test/508-referrer-method/src/Main.java
new file mode 100644
index 0000000..07b25e4
--- /dev/null
+++ b/test/508-referrer-method/src/Main.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Main needs to be a subclass that has access to the
+// protected p1.PackagePrivateA.method.
+public class Main extends p1.PublicC {
+  public static void main(String[] args) {
+    int result = p1.InPackage.$inline$method();
+    if (result != 42) {
+      throw new Error("Expected 42, got " + result);
+    }
+  }
+}
diff --git a/test/508-referrer-method/src/p1/InPackage.java b/test/508-referrer-method/src/p1/InPackage.java
new file mode 100644
index 0000000..84c7d25
--- /dev/null
+++ b/test/508-referrer-method/src/p1/InPackage.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package p1;
+
+public class InPackage {
+  public static int $inline$method() {
+    // Call must be through a public subclass of the holder
+    // of the protected method, so that the Main class also has
+    // access to it.
+    return PublicB.method();
+  }
+}
diff --git a/test/508-referrer-method/src/p1/PackagePrivateA.java b/test/508-referrer-method/src/p1/PackagePrivateA.java
new file mode 100644
index 0000000..af8cfe8
--- /dev/null
+++ b/test/508-referrer-method/src/p1/PackagePrivateA.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package p1;
+
+class PackagePrivateA {
+  protected static int method() {
+    return 42;
+  }
+}
diff --git a/test/508-referrer-method/src/p1/PublicB.java b/test/508-referrer-method/src/p1/PublicB.java
new file mode 100644
index 0000000..58e9304
--- /dev/null
+++ b/test/508-referrer-method/src/p1/PublicB.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package p1;
+
+public class PublicB extends PackagePrivateA {
+}
diff --git a/test/508-referrer-method/src/p1/PublicC.java b/test/508-referrer-method/src/p1/PublicC.java
new file mode 100644
index 0000000..d68e93b
--- /dev/null
+++ b/test/508-referrer-method/src/p1/PublicC.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package p1;
+
+public class PublicC extends PackagePrivateA {
+}
diff --git a/test/511-clinit-interface/expected.txt b/test/511-clinit-interface/expected.txt
new file mode 100644
index 0000000..ccaf6f8
--- /dev/null
+++ b/test/511-clinit-interface/expected.txt
@@ -0,0 +1 @@
+Enter
diff --git a/test/511-clinit-interface/info.txt b/test/511-clinit-interface/info.txt
new file mode 100644
index 0000000..1351b29
--- /dev/null
+++ b/test/511-clinit-interface/info.txt
@@ -0,0 +1,2 @@
+Test that compilers don't crash when having to compile
+an interface method.
diff --git a/test/511-clinit-interface/smali/BogusInterface.smali b/test/511-clinit-interface/smali/BogusInterface.smali
new file mode 100644
index 0000000..619df24
--- /dev/null
+++ b/test/511-clinit-interface/smali/BogusInterface.smali
@@ -0,0 +1,23 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public abstract interface LBogusInterface;
+
+.super Ljava/lang/Object;
+
+.method public static <clinit>()V
+   .registers 2
+   invoke-static {}, LMain;->method()V
+   return-void
+.end method
diff --git a/test/511-clinit-interface/src/Main.java b/test/511-clinit-interface/src/Main.java
new file mode 100644
index 0000000..c4d0c66
--- /dev/null
+++ b/test/511-clinit-interface/src/Main.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    // Workaround for b/18051191.
+    System.out.println("Enter");
+    Class<?> c = Class.forName("BogusInterface");
+  }
+
+  public static void method() {
+  }
+}
diff --git a/test/513-array-deopt/expected.txt b/test/513-array-deopt/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/513-array-deopt/expected.txt
diff --git a/test/513-array-deopt/info.txt b/test/513-array-deopt/info.txt
new file mode 100644
index 0000000..afce9d9
--- /dev/null
+++ b/test/513-array-deopt/info.txt
@@ -0,0 +1,2 @@
+Regression test for the BCE phase of optimizing,
+that used to have wrong assumptions about array length bounds.
diff --git a/test/513-array-deopt/src/Main.java b/test/513-array-deopt/src/Main.java
new file mode 100644
index 0000000..a0ae4c3
--- /dev/null
+++ b/test/513-array-deopt/src/Main.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  public static int[] bar(int[] a) {
+    a[0] = 0;
+    a[1] = 0;
+    a[2] = 0;
+    // Up to this point, we record that the lower bound is 2.
+    // The next instruction will record that the lower bound is 5.
+    // The deoptimization code used to assume the lower bound has
+    // to be check it will add for the deoptimization (here, it
+    // would be 2).
+    return new int[a.length - 5];
+  }
+
+  public static void main(String[] args) {
+    int[] a = new int[5];
+    a = bar(a);
+    if (a.length != 0) {
+      throw new Error("Expected 0, got " + a.length);
+    }
+  }
+}
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 09841bf..cf6be83 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -409,6 +409,10 @@
     export DYLD_LIBRARY_PATH="${ANDROID_ROOT}/lib"
     export PATH="$PATH:${ANDROID_ROOT}/bin"
 
+    # Temporarily disable address space layout randomization (ASLR).
+    # This is needed on the host so that the linker loads core.oat at the necessary address.
+    export LD_USE_LOAD_BIAS=1
+
     cmdline="$dalvikvm_cmdline"
 
     if [ "$TIME_OUT" = "y" ]; then