Merge "Add a script to run jdwp tests on the chrome buildbot."
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 948c756..91998fa 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -167,6 +167,7 @@
   runtime/mirror/object_test.cc \
   runtime/monitor_pool_test.cc \
   runtime/monitor_test.cc \
+  runtime/oat_file_test.cc \
   runtime/oat_file_assistant_test.cc \
   runtime/parsed_options_test.cc \
   runtime/reference_table_test.cc \
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 4a35e9f..8babc28 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -39,6 +39,22 @@
   return soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
 }
 
+inline mirror::Class* CompilerDriver::ResolveClass(
+    const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+    Handle<mirror::ClassLoader> class_loader, uint16_t cls_index,
+    const DexCompilationUnit* mUnit) {
+  DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
+  DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+  mirror::Class* cls = mUnit->GetClassLinker()->ResolveType(
+      *mUnit->GetDexFile(), cls_index, dex_cache, class_loader);
+  DCHECK_EQ(cls == nullptr, soa.Self()->IsExceptionPending());
+  if (UNLIKELY(cls == nullptr)) {
+    // Clean up any exception left by type resolution.
+    soa.Self()->ClearException();
+  }
+  return cls;
+}
+
 inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass(
     const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
     Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) {
@@ -46,14 +62,7 @@
   DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
   const DexFile::MethodId& referrer_method_id =
       mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex());
-  mirror::Class* referrer_class = mUnit->GetClassLinker()->ResolveType(
-      *mUnit->GetDexFile(), referrer_method_id.class_idx_, dex_cache, class_loader);
-  DCHECK_EQ(referrer_class == nullptr, soa.Self()->IsExceptionPending());
-  if (UNLIKELY(referrer_class == nullptr)) {
-    // Clean up any exception left by type resolution.
-    soa.Self()->ClearException();
-  }
-  return referrer_class;
+  return ResolveClass(soa, dex_cache, class_loader, referrer_method_id.class_idx_, mUnit);
 }
 
 inline mirror::ArtField* CompilerDriver::ResolveFieldWithDexFile(
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 9463c2c..b825293 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -228,6 +228,12 @@
       Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  mirror::Class* ResolveClass(
+      const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+      Handle<mirror::ClassLoader> class_loader, uint16_t type_index,
+      const DexCompilationUnit* mUnit)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Resolve a field. Returns nullptr on failure, including incompatible class change.
   // NOTE: Unlike ClassLinker's ResolveField(), this method enforces is_static.
   mirror::ArtField* ResolveField(
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index d238b2c..c1555aa 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -133,7 +133,7 @@
     return false;
   }
   std::string error_msg;
-  oat_file_ = OatFile::OpenReadable(oat_file.get(), oat_location, &error_msg);
+  oat_file_ = OatFile::OpenReadable(oat_file.get(), oat_location, nullptr, &error_msg);
   if (oat_file_ == nullptr) {
     PLOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location
         << ": " << error_msg;
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 46aed60..c426625 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -122,7 +122,7 @@
     compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
   }
   std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), nullptr,
-                                                  nullptr, false, &error_msg));
+                                                  nullptr, false, nullptr, &error_msg));
   ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
   const OatHeader& oat_header = oat_file->GetOatHeader();
   ASSERT_TRUE(oat_header.IsValid());
diff --git a/compiler/optimizing/boolean_simplifier.cc b/compiler/optimizing/boolean_simplifier.cc
index 0ecc0d7..e9ca042 100644
--- a/compiler/optimizing/boolean_simplifier.cc
+++ b/compiler/optimizing/boolean_simplifier.cc
@@ -65,10 +65,10 @@
   } else if (cond->IsIntConstant()) {
     HIntConstant* int_const = cond->AsIntConstant();
     if (int_const->IsZero()) {
-      return graph->GetIntConstant1();
+      return graph->GetIntConstant(1);
     } else {
       DCHECK(int_const->IsOne());
-      return graph->GetIntConstant0();
+      return graph->GetIntConstant(0);
     }
   }
 
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index 24fa583..b3653fe 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -52,12 +52,11 @@
       HParameterValue(0, Primitive::kPrimNot);  // array
   HInstruction* parameter2 = new (&allocator)
       HParameterValue(0, Primitive::kPrimInt);  // i
-  HInstruction* constant_1 = new (&allocator) HIntConstant(1);
-  HInstruction* constant_0 = new (&allocator) HIntConstant(0);
   entry->AddInstruction(parameter1);
   entry->AddInstruction(parameter2);
-  entry->AddInstruction(constant_1);
-  entry->AddInstruction(constant_0);
+
+  HInstruction* constant_1 = graph->GetIntConstant(1);
+  HInstruction* constant_0 = graph->GetIntConstant(0);
 
   HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
   graph->AddBlock(block1);
@@ -158,14 +157,12 @@
       HParameterValue(0, Primitive::kPrimNot);  // array
   HInstruction* parameter2 = new (&allocator)
       HParameterValue(0, Primitive::kPrimInt);  // i
-  HInstruction* constant_1 = new (&allocator) HIntConstant(1);
-  HInstruction* constant_0 = new (&allocator) HIntConstant(0);
-  HInstruction* constant_max_int = new (&allocator) HIntConstant(INT_MAX);
   entry->AddInstruction(parameter1);
   entry->AddInstruction(parameter2);
-  entry->AddInstruction(constant_1);
-  entry->AddInstruction(constant_0);
-  entry->AddInstruction(constant_max_int);
+
+  HInstruction* constant_1 = graph->GetIntConstant(1);
+  HInstruction* constant_0 = graph->GetIntConstant(0);
+  HInstruction* constant_max_int = graph->GetIntConstant(INT_MAX);
 
   HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
   graph->AddBlock(block1);
@@ -232,14 +229,12 @@
       HParameterValue(0, Primitive::kPrimNot);  // array
   HInstruction* parameter2 = new (&allocator)
       HParameterValue(0, Primitive::kPrimInt);  // i
-  HInstruction* constant_1 = new (&allocator) HIntConstant(1);
-  HInstruction* constant_0 = new (&allocator) HIntConstant(0);
-  HInstruction* constant_max_int = new (&allocator) HIntConstant(INT_MAX);
   entry->AddInstruction(parameter1);
   entry->AddInstruction(parameter2);
-  entry->AddInstruction(constant_1);
-  entry->AddInstruction(constant_0);
-  entry->AddInstruction(constant_max_int);
+
+  HInstruction* constant_1 = graph->GetIntConstant(1);
+  HInstruction* constant_0 = graph->GetIntConstant(0);
+  HInstruction* constant_max_int = graph->GetIntConstant(INT_MAX);
 
   HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
   graph->AddBlock(block1);
@@ -303,15 +298,12 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
-  HInstruction* constant_5 = new (&allocator) HIntConstant(5);
-  HInstruction* constant_4 = new (&allocator) HIntConstant(4);
-  HInstruction* constant_6 = new (&allocator) HIntConstant(6);
-  HInstruction* constant_1 = new (&allocator) HIntConstant(1);
   entry->AddInstruction(parameter);
-  entry->AddInstruction(constant_5);
-  entry->AddInstruction(constant_4);
-  entry->AddInstruction(constant_6);
-  entry->AddInstruction(constant_1);
+
+  HInstruction* constant_5 = graph->GetIntConstant(5);
+  HInstruction* constant_4 = graph->GetIntConstant(4);
+  HInstruction* constant_6 = graph->GetIntConstant(6);
+  HInstruction* constant_1 = graph->GetIntConstant(1);
 
   HBasicBlock* block = new (&allocator) HBasicBlock(graph);
   graph->AddBlock(block);
@@ -379,13 +371,11 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
-  HInstruction* constant_initial = new (allocator) HIntConstant(initial);
-  HInstruction* constant_increment = new (allocator) HIntConstant(increment);
-  HInstruction* constant_10 = new (allocator) HIntConstant(10);
   entry->AddInstruction(parameter);
-  entry->AddInstruction(constant_initial);
-  entry->AddInstruction(constant_increment);
-  entry->AddInstruction(constant_10);
+
+  HInstruction* constant_initial = graph->GetIntConstant(initial);
+  HInstruction* constant_increment = graph->GetIntConstant(increment);
+  HInstruction* constant_10 = graph->GetIntConstant(10);
 
   HBasicBlock* block = new (allocator) HBasicBlock(graph);
   graph->AddBlock(block);
@@ -518,15 +508,12 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
-  HInstruction* constant_initial = new (allocator) HIntConstant(initial);
-  HInstruction* constant_increment = new (allocator) HIntConstant(increment);
-  HInstruction* constant_minus_1 = new (allocator) HIntConstant(-1);
-  HInstruction* constant_10 = new (allocator) HIntConstant(10);
   entry->AddInstruction(parameter);
-  entry->AddInstruction(constant_initial);
-  entry->AddInstruction(constant_increment);
-  entry->AddInstruction(constant_minus_1);
-  entry->AddInstruction(constant_10);
+
+  HInstruction* constant_initial = graph->GetIntConstant(initial);
+  HInstruction* constant_increment = graph->GetIntConstant(increment);
+  HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
+  HInstruction* constant_10 = graph->GetIntConstant(10);
 
   HBasicBlock* block = new (allocator) HBasicBlock(graph);
   graph->AddBlock(block);
@@ -651,12 +638,10 @@
   HBasicBlock* entry = new (allocator) HBasicBlock(graph);
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
-  HInstruction* constant_10 = new (allocator) HIntConstant(10);
-  HInstruction* constant_initial = new (allocator) HIntConstant(initial);
-  HInstruction* constant_increment = new (allocator) HIntConstant(increment);
-  entry->AddInstruction(constant_10);
-  entry->AddInstruction(constant_initial);
-  entry->AddInstruction(constant_increment);
+
+  HInstruction* constant_10 = graph->GetIntConstant(10);
+  HInstruction* constant_initial = graph->GetIntConstant(initial);
+  HInstruction* constant_increment = graph->GetIntConstant(increment);
 
   HBasicBlock* block = new (allocator) HBasicBlock(graph);
   graph->AddBlock(block);
@@ -765,15 +750,12 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
-  HInstruction* constant_initial = new (allocator) HIntConstant(initial);
-  HInstruction* constant_1 = new (allocator) HIntConstant(1);
-  HInstruction* constant_10 = new (allocator) HIntConstant(10);
-  HInstruction* constant_minus_1 = new (allocator) HIntConstant(-1);
   entry->AddInstruction(parameter);
-  entry->AddInstruction(constant_initial);
-  entry->AddInstruction(constant_1);
-  entry->AddInstruction(constant_10);
-  entry->AddInstruction(constant_minus_1);
+
+  HInstruction* constant_initial = graph->GetIntConstant(initial);
+  HInstruction* constant_1 = graph->GetIntConstant(1);
+  HInstruction* constant_10 = graph->GetIntConstant(10);
+  HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
 
   HBasicBlock* block = new (allocator) HBasicBlock(graph);
   graph->AddBlock(block);
@@ -893,13 +875,11 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
-  HInstruction* constant_0 = new (&allocator) HIntConstant(0);
-  HInstruction* constant_minus_1 = new (&allocator) HIntConstant(-1);
-  HInstruction* constant_1 = new (&allocator) HIntConstant(1);
   entry->AddInstruction(parameter);
-  entry->AddInstruction(constant_0);
-  entry->AddInstruction(constant_minus_1);
-  entry->AddInstruction(constant_1);
+
+  HInstruction* constant_0 = graph->GetIntConstant(0);
+  HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
+  HInstruction* constant_1 = graph->GetIntConstant(1);
 
   HBasicBlock* block = new (&allocator) HBasicBlock(graph);
   graph->AddBlock(block);
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index a21c311..2cdd5af 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -215,7 +215,7 @@
   DCHECK(fallthrough_target != nullptr);
   PotentiallyAddSuspendCheck(branch_target, dex_pc);
   HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
-  T* comparison = new (arena_) T(value, GetIntConstant(0));
+  T* comparison = new (arena_) T(value, graph_->GetIntConstant(0));
   current_block_->AddInstruction(comparison);
   HInstruction* ifinst = new (arena_) HIf(comparison);
   current_block_->AddInstruction(ifinst);
@@ -515,7 +515,7 @@
 template<typename T>
 void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) {
   HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
-  HInstruction* second = GetIntConstant(instruction.VRegC_22s());
+  HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22s());
   if (reverse) {
     std::swap(first, second);
   }
@@ -526,7 +526,7 @@
 template<typename T>
 void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) {
   HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
-  HInstruction* second = GetIntConstant(instruction.VRegC_22b());
+  HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22b());
   if (reverse) {
     std::swap(first, second);
   }
@@ -616,11 +616,11 @@
     DCHECK((optimized_invoke_type == invoke_type) || (optimized_invoke_type != kDirect)
            || compiler_driver_->GetCompilerOptions().GetCompilePic());
     bool is_recursive =
-        (target_method.dex_method_index == outer_compilation_unit_->GetDexMethodIndex());
-    DCHECK(!is_recursive || (target_method.dex_file == outer_compilation_unit_->GetDexFile()));
+        (target_method.dex_method_index == dex_compilation_unit_->GetDexMethodIndex());
+    DCHECK(!is_recursive || (target_method.dex_file == dex_compilation_unit_->GetDexFile()));
     invoke = new (arena_) HInvokeStaticOrDirect(
         arena_, number_of_arguments, return_type, dex_pc, target_method.dex_method_index,
-        is_recursive, optimized_invoke_type);
+        is_recursive, invoke_type, optimized_invoke_type);
   }
 
   size_t start_index = 0;
@@ -704,6 +704,34 @@
   return true;
 }
 
+mirror::Class* HGraphBuilder::GetOutermostCompilingClass() const {
+  ScopedObjectAccess soa(Thread::Current());
+  StackHandleScope<2> hs(soa.Self());
+  const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile();
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
+      soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+  Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle(
+      outer_compilation_unit_->GetClassLinker()->FindDexCache(outer_dex_file)));
+
+  return compiler_driver_->ResolveCompilingMethodsClass(
+      soa, outer_dex_cache, class_loader, outer_compilation_unit_);
+}
+
+bool HGraphBuilder::IsOutermostCompilingClass(uint16_t type_index) const {
+  ScopedObjectAccess soa(Thread::Current());
+  StackHandleScope<4> hs(soa.Self());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(
+      dex_compilation_unit_->GetClassLinker()->FindDexCache(*dex_compilation_unit_->GetDexFile())));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
+      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()));
+
+  return compiling_class.Get() == cls.Get();
+}
+
+
 bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
                                            uint32_t dex_pc,
                                            bool is_put) {
@@ -711,7 +739,7 @@
   uint16_t field_index = instruction.VRegB_21c();
 
   ScopedObjectAccess soa(Thread::Current());
-  StackHandleScope<4> hs(soa.Self());
+  StackHandleScope<5> hs(soa.Self());
   Handle<mirror::DexCache> dex_cache(hs.NewHandle(
       dex_compilation_unit_->GetClassLinker()->FindDexCache(*dex_compilation_unit_->GetDexFile())));
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
@@ -724,23 +752,36 @@
     return false;
   }
 
-  Handle<mirror::Class> referrer_class(hs.NewHandle(compiler_driver_->ResolveCompilingMethodsClass(
-      soa, dex_cache, class_loader, outer_compilation_unit_)));
+  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()));
 
   // The index at which the field's class is stored in the DexCache's type array.
   uint32_t storage_index;
-  std::pair<bool, bool> pair = compiler_driver_->IsFastStaticField(
-      dex_cache.Get(), referrer_class.Get(), resolved_field.Get(), field_index, &storage_index);
-  bool can_easily_access = is_put ? pair.second : pair.first;
-  if (!can_easily_access) {
+  bool is_referrer_class = (referrer_class.Get() == resolved_field->GetDeclaringClass());
+  if (is_referrer_class) {
+    storage_index = referrer_class->GetDexTypeIndex();
+  } else if (outer_dex_cache.Get() != dex_cache.Get()) {
+    // The compiler driver cannot currently understand multple dex caches involved. Just bailout.
     return false;
+  } else {
+    std::pair<bool, bool> pair = compiler_driver_->IsFastStaticField(
+        outer_dex_cache.Get(),
+        referrer_class.Get(),
+        resolved_field.Get(),
+        field_index,
+        &storage_index);
+    bool can_easily_access = is_put ? pair.second : pair.first;
+    if (!can_easily_access) {
+      return false;
+    }
   }
 
   // TODO: find out why this check is needed.
   bool is_in_dex_cache = compiler_driver_->CanAssumeTypeIsPresentInDexCache(
       *outer_compilation_unit_->GetDexFile(), storage_index);
   bool is_initialized = resolved_field->GetDeclaringClass()->IsInitialized() && is_in_dex_cache;
-  bool is_referrer_class = (referrer_class.Get() == resolved_field->GetDeclaringClass());
 
   HLoadClass* constant = new (arena_) HLoadClass(storage_index, is_referrer_class, dex_pc);
   current_block_->AddInstruction(constant);
@@ -783,9 +824,9 @@
   HInstruction* second = nullptr;
   if (second_is_constant) {
     if (type == Primitive::kPrimInt) {
-      second = GetIntConstant(second_vreg_or_constant);
+      second = graph_->GetIntConstant(second_vreg_or_constant);
     } else {
-      second = GetLongConstant(second_vreg_or_constant);
+      second = graph_->GetLongConstant(second_vreg_or_constant);
     }
   } else {
     second = LoadLocal(second_vreg_or_constant, type);
@@ -849,7 +890,7 @@
                                         bool is_range,
                                         uint32_t* args,
                                         uint32_t register_index) {
-  HInstruction* length = GetIntConstant(number_of_vreg_arguments);
+  HInstruction* length = graph_->GetIntConstant(number_of_vreg_arguments);
   QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
       ? kQuickAllocArrayWithAccessCheck
       : kQuickAllocArray;
@@ -869,7 +910,7 @@
   temps.Add(object);
   for (size_t i = 0; i < number_of_vreg_arguments; ++i) {
     HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type);
-    HInstruction* index = GetIntConstant(i);
+    HInstruction* index = graph_->GetIntConstant(i);
     current_block_->AddInstruction(
         new (arena_) HArraySet(object, index, value, type, dex_pc));
   }
@@ -883,8 +924,8 @@
                                        Primitive::Type anticipated_type,
                                        uint32_t dex_pc) {
   for (uint32_t i = 0; i < element_count; ++i) {
-    HInstruction* index = GetIntConstant(i);
-    HInstruction* value = GetIntConstant(data[i]);
+    HInstruction* index = graph_->GetIntConstant(i);
+    HInstruction* value = graph_->GetIntConstant(data[i]);
     current_block_->AddInstruction(new (arena_) HArraySet(
       object, index, value, anticipated_type, dex_pc));
   }
@@ -908,7 +949,7 @@
 
   // Implementation of this DEX instruction seems to be that the bounds check is
   // done before doing any stores.
-  HInstruction* last_index = GetIntConstant(payload->element_count - 1);
+  HInstruction* last_index = graph_->GetIntConstant(payload->element_count - 1);
   current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_pc));
 
   switch (payload->element_width) {
@@ -949,8 +990,8 @@
                                            uint32_t element_count,
                                            uint32_t dex_pc) {
   for (uint32_t i = 0; i < element_count; ++i) {
-    HInstruction* index = GetIntConstant(i);
-    HInstruction* value = GetLongConstant(data[i]);
+    HInstruction* index = graph_->GetIntConstant(i);
+    HInstruction* value = graph_->GetLongConstant(data[i]);
     current_block_->AddInstruction(new (arena_) HArraySet(
       object, index, value, Primitive::kPrimLong, dex_pc));
   }
@@ -966,7 +1007,7 @@
   // `CanAccessTypeWithoutChecks` will tell whether the method being
   // built is trying to access its own class, so that the generated
   // code can optimize for this case. However, the optimization does not
-  // work for inlining, so we use `IsCompilingClass` instead.
+  // work for inlining, so we use `IsOutermostCompilingClass` instead.
   bool dont_use_is_referrers_class;
   bool can_access = compiler_driver_->CanAccessTypeWithoutChecks(
       dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index,
@@ -976,7 +1017,8 @@
     return false;
   }
   HInstruction* object = LoadLocal(reference, Primitive::kPrimNot);
-  HLoadClass* cls = new (arena_) HLoadClass(type_index, IsCompilingClass(type_index), dex_pc);
+  HLoadClass* cls = new (arena_) HLoadClass(
+      type_index, IsOutermostCompilingClass(type_index), dex_pc);
   current_block_->AddInstruction(cls);
   // The class needs a temporary before being used by the type check.
   Temporaries temps(graph_);
@@ -1040,7 +1082,7 @@
   PotentiallyAddSuspendCheck(case_target, dex_pc);
 
   // The current case's value.
-  HInstruction* this_case_value = GetIntConstant(case_value_int);
+  HInstruction* this_case_value = graph_->GetIntConstant(case_value_int);
 
   // Compare value and this_case_value.
   HEqual* comparison = new (arena_) HEqual(value, this_case_value);
@@ -1098,28 +1140,28 @@
   switch (instruction.Opcode()) {
     case Instruction::CONST_4: {
       int32_t register_index = instruction.VRegA();
-      HIntConstant* constant = GetIntConstant(instruction.VRegB_11n());
+      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_11n());
       UpdateLocal(register_index, constant);
       break;
     }
 
     case Instruction::CONST_16: {
       int32_t register_index = instruction.VRegA();
-      HIntConstant* constant = GetIntConstant(instruction.VRegB_21s());
+      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21s());
       UpdateLocal(register_index, constant);
       break;
     }
 
     case Instruction::CONST: {
       int32_t register_index = instruction.VRegA();
-      HIntConstant* constant = GetIntConstant(instruction.VRegB_31i());
+      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_31i());
       UpdateLocal(register_index, constant);
       break;
     }
 
     case Instruction::CONST_HIGH16: {
       int32_t register_index = instruction.VRegA();
-      HIntConstant* constant = GetIntConstant(instruction.VRegB_21h() << 16);
+      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21h() << 16);
       UpdateLocal(register_index, constant);
       break;
     }
@@ -1130,7 +1172,7 @@
       int64_t value = instruction.VRegB_21s();
       value <<= 48;
       value >>= 48;
-      HLongConstant* constant = GetLongConstant(value);
+      HLongConstant* constant = graph_->GetLongConstant(value);
       UpdateLocal(register_index, constant);
       break;
     }
@@ -1141,14 +1183,14 @@
       int64_t value = instruction.VRegB_31i();
       value <<= 32;
       value >>= 32;
-      HLongConstant* constant = GetLongConstant(value);
+      HLongConstant* constant = graph_->GetLongConstant(value);
       UpdateLocal(register_index, constant);
       break;
     }
 
     case Instruction::CONST_WIDE: {
       int32_t register_index = instruction.VRegA();
-      HLongConstant* constant = GetLongConstant(instruction.VRegB_51l());
+      HLongConstant* constant = graph_->GetLongConstant(instruction.VRegB_51l());
       UpdateLocal(register_index, constant);
       break;
     }
@@ -1156,7 +1198,7 @@
     case Instruction::CONST_WIDE_HIGH16: {
       int32_t register_index = instruction.VRegA();
       int64_t value = static_cast<int64_t>(instruction.VRegB_21h()) << 48;
-      HLongConstant* constant = GetLongConstant(value);
+      HLongConstant* constant = graph_->GetLongConstant(value);
       UpdateLocal(register_index, constant);
       break;
     }
@@ -1971,7 +2013,7 @@
       // `CanAccessTypeWithoutChecks` will tell whether the method being
       // built is trying to access its own class, so that the generated
       // code can optimize for this case. However, the optimization does not
-      // work for inlining, so we use `IsCompilingClass` instead.
+      // work for inlining, so we use `IsOutermostCompilingClass` instead.
       bool can_access = compiler_driver_->CanAccessTypeWithoutChecks(
           dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index,
           &type_known_final, &type_known_abstract, &dont_use_is_referrers_class);
@@ -1980,7 +2022,7 @@
         return false;
       }
       current_block_->AddInstruction(
-          new (arena_) HLoadClass(type_index, IsCompilingClass(type_index), dex_pc));
+          new (arena_) HLoadClass(type_index, IsOutermostCompilingClass(type_index), dex_pc));
       UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
       break;
     }
@@ -2058,24 +2100,6 @@
   return true;
 }  // NOLINT(readability/fn_size)
 
-HIntConstant* HGraphBuilder::GetIntConstant(int32_t constant) {
-  switch (constant) {
-    case 0: return graph_->GetIntConstant0();
-    case 1: return graph_->GetIntConstant1();
-    default: {
-      HIntConstant* instruction = new (arena_) HIntConstant(constant);
-      graph_->AddConstant(instruction);
-      return instruction;
-    }
-  }
-}
-
-HLongConstant* HGraphBuilder::GetLongConstant(int64_t constant) {
-  HLongConstant* instruction = new (arena_) HLongConstant(constant);
-  graph_->AddConstant(instruction);
-  return instruction;
-}
-
 HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
   return locals_.Get(register_index);
 }
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index c70170b..6a0738a 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -96,8 +96,6 @@
   void MaybeUpdateCurrentBlock(size_t index);
   HBasicBlock* FindBlockStartingAt(int32_t index) const;
 
-  HIntConstant* GetIntConstant(int32_t constant);
-  HLongConstant* GetLongConstant(int64_t constant);
   void InitializeLocals(uint16_t count);
   HLocal* GetLocalAt(int register_index) const;
   void UpdateLocal(int register_index, HInstruction* instruction) const;
@@ -225,13 +223,10 @@
 
   void MaybeRecordStat(MethodCompilationStat compilation_stat);
 
+  mirror::Class* GetOutermostCompilingClass() const;
+
   // Returns whether `type_index` points to the outer-most compiling method's class.
-  bool IsCompilingClass(uint16_t type_index) const {
-    uint32_t referrer_index = outer_compilation_unit_->GetDexMethodIndex();
-    const DexFile::MethodId& method_id =
-        outer_compilation_unit_->GetDexFile()->GetMethodId(referrer_index);
-    return method_id.class_idx_ == type_index;
-  }
+  bool IsOutermostCompilingClass(uint16_t type_index) const;
 
   ArenaAllocator* const arena_;
 
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 5a79a69..97c470b 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2326,10 +2326,8 @@
 void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
   DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
 
-  LocationSummary::CallKind call_kind = op->GetResultType() == Primitive::kPrimLong
-      ? LocationSummary::kCall
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(op, call_kind);
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
 
   switch (op->GetResultType()) {
     case Primitive::kPrimInt: {
@@ -2339,12 +2337,10 @@
       break;
     }
     case Primitive::kPrimLong: {
-      InvokeRuntimeCallingConvention calling_convention;
-      locations->SetInAt(0, Location::RegisterPairLocation(
-          calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
-      locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
-      // The runtime helper puts the output in R0,R1.
-      locations->SetOut(Location::RegisterPairLocation(R0, R1));
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->AddTemp(Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister());
       break;
     }
     default:
@@ -2392,24 +2388,56 @@
       break;
     }
     case Primitive::kPrimLong: {
-      // TODO: Inline the assembly instead of calling the runtime.
-      InvokeRuntimeCallingConvention calling_convention;
-      DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
-      DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
-      DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegister<Register>());
-      DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
-      DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
+      Register o_h = out.AsRegisterPairHigh<Register>();
+      Register o_l = out.AsRegisterPairLow<Register>();
 
-      int32_t entry_point_offset;
+      Register temp = locations->GetTemp(0).AsRegister<Register>();
+
+      Register high = first.AsRegisterPairHigh<Register>();
+      Register low = first.AsRegisterPairLow<Register>();
+
+      Register second_reg = second.AsRegister<Register>();
+
       if (op->IsShl()) {
-        entry_point_offset = QUICK_ENTRY_POINT(pShlLong);
+        // Shift the high part
+        __ and_(second_reg, second_reg, ShifterOperand(63));
+        __ Lsl(o_h, high, second_reg);
+        // Shift the low part and `or` what overflew on the high part
+        __ rsb(temp, second_reg, ShifterOperand(32));
+        __ Lsr(temp, low, temp);
+        __ orr(o_h, o_h, ShifterOperand(temp));
+        // If the shift is > 32 bits, override the high part
+        __ subs(temp, second_reg, ShifterOperand(32));
+        __ it(PL);
+        __ Lsl(o_h, low, temp, false, PL);
+        // Shift the low part
+        __ Lsl(o_l, low, second_reg);
       } else if (op->IsShr()) {
-        entry_point_offset = QUICK_ENTRY_POINT(pShrLong);
+        // Shift the low part
+        __ and_(second_reg, second_reg, ShifterOperand(63));
+        __ Lsr(o_l, low, second_reg);
+        // Shift the high part and `or` what underflew on the low part
+        __ rsb(temp, second_reg, ShifterOperand(32));
+        __ Lsl(temp, high, temp);
+        __ orr(o_l, o_l, ShifterOperand(temp));
+        // If the shift is > 32 bits, override the low part
+        __ subs(temp, second_reg, ShifterOperand(32));
+        __ it(PL);
+        __ Asr(o_l, high, temp, false, PL);
+        // Shift the high part
+        __ Asr(o_h, high, second_reg);
       } else {
-        entry_point_offset = QUICK_ENTRY_POINT(pUshrLong);
+        // same as Shr except we use `Lsr`s and not `Asr`s
+        __ and_(second_reg, second_reg, ShifterOperand(63));
+        __ Lsr(o_l, low, second_reg);
+        __ rsb(temp, second_reg, ShifterOperand(32));
+        __ Lsl(temp, high, temp);
+        __ orr(o_l, o_l, ShifterOperand(temp));
+        __ subs(temp, second_reg, ShifterOperand(32));
+        __ it(PL);
+        __ Lsr(o_l, high, temp, false, PL);
+        __ Lsr(o_h, high, second_reg);
       }
-      __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
-      __ blx(LR);
       break;
     }
     default:
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 40f0adc..6053ad5 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -474,10 +474,8 @@
   HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
   graph->AddBlock(first_block);
   entry->AddSuccessor(first_block);
-  HIntConstant* constant0 = new (&allocator) HIntConstant(0);
-  entry->AddInstruction(constant0);
-  HIntConstant* constant1 = new (&allocator) HIntConstant(1);
-  entry->AddInstruction(constant1);
+  HIntConstant* constant0 = graph->GetIntConstant(0);
+  HIntConstant* constant1 = graph->GetIntConstant(1);
   HEqual* equal = new (&allocator) HEqual(constant0, constant0);
   first_block->AddInstruction(equal);
   first_block->AddInstruction(new (&allocator) HIf(equal));
@@ -582,11 +580,9 @@
     code_block->AddSuccessor(exit_block);
     graph->SetExitBlock(exit_block);
 
-    HIntConstant cst_lhs(lhs[i]);
-    code_block->AddInstruction(&cst_lhs);
-    HIntConstant cst_rhs(rhs[i]);
-    code_block->AddInstruction(&cst_rhs);
-    HLessThan cmp_lt(&cst_lhs, &cst_rhs);
+    HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
+    HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
+    HLessThan cmp_lt(cst_lhs, cst_rhs);
     code_block->AddInstruction(&cmp_lt);
     HReturn ret(&cmp_lt);
     code_block->AddInstruction(&ret);
@@ -639,11 +635,9 @@
     if_false_block->AddSuccessor(exit_block);
     graph->SetExitBlock(exit_block);
 
-    HIntConstant cst_lhs(lhs[i]);
-    if_block->AddInstruction(&cst_lhs);
-    HIntConstant cst_rhs(rhs[i]);
-    if_block->AddInstruction(&cst_rhs);
-    HLessThan cmp_lt(&cst_lhs, &cst_rhs);
+    HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
+    HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
+    HLessThan cmp_lt(cst_lhs, cst_rhs);
     if_block->AddInstruction(&cmp_lt);
     // We insert a temporary to separate the HIf from the HLessThan and force
     // the materialization of the condition.
@@ -652,13 +646,11 @@
     HIf if_lt(&cmp_lt);
     if_block->AddInstruction(&if_lt);
 
-    HIntConstant cst_lt(1);
-    if_true_block->AddInstruction(&cst_lt);
-    HReturn ret_lt(&cst_lt);
+    HIntConstant* cst_lt = graph->GetIntConstant(1);
+    HReturn ret_lt(cst_lt);
     if_true_block->AddInstruction(&ret_lt);
-    HIntConstant cst_ge(0);
-    if_false_block->AddInstruction(&cst_ge);
-    HReturn ret_ge(&cst_ge);
+    HIntConstant* cst_ge = graph->GetIntConstant(0);
+    HReturn ret_ge(cst_ge);
     if_false_block->AddInstruction(&ret_ge);
 
     auto hook_before_codegen = [](HGraph* graph_in) {
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index ec0cc3e..b7a92b5 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -55,20 +55,20 @@
       if (inst->IsBinaryOperation()) {
         // Constant folding: replace `op(a, b)' with a constant at
         // compile time if `a' and `b' are both constants.
-        HConstant* constant =
-            inst->AsBinaryOperation()->TryStaticEvaluation();
+        HConstant* constant = inst->AsBinaryOperation()->TryStaticEvaluation();
         if (constant != nullptr) {
-          inst->GetBlock()->ReplaceAndRemoveInstructionWith(inst, constant);
+          inst->ReplaceWith(constant);
+          inst->GetBlock()->RemoveInstruction(inst);
         } else {
           inst->Accept(&simplifier);
         }
       } else if (inst->IsUnaryOperation()) {
         // Constant folding: replace `op(a)' with a constant at compile
         // time if `a' is a constant.
-        HConstant* constant =
-            inst->AsUnaryOperation()->TryStaticEvaluation();
+        HConstant* constant = inst->AsUnaryOperation()->TryStaticEvaluation();
         if (constant != nullptr) {
-          inst->GetBlock()->ReplaceAndRemoveInstructionWith(inst, constant);
+          inst->ReplaceWith(constant);
+          inst->GetBlock()->RemoveInstruction(inst);
         }
       } else if (inst->IsDivZeroCheck()) {
         // We can safely remove the check if the input is a non-null constant.
@@ -173,9 +173,8 @@
     //    REM dst, src, src
     // with
     //    CONSTANT 0
-    ArenaAllocator* allocator = GetGraph()->GetArena();
-    block->ReplaceAndRemoveInstructionWith(instruction,
-                                           HConstant::NewConstant(allocator, type, 0));
+    instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
+    block->RemoveInstruction(instruction);
   }
 }
 
@@ -195,7 +194,6 @@
   }
 
   HBasicBlock* block = instruction->GetBlock();
-  ArenaAllocator* allocator = GetGraph()->GetArena();
 
   // We assume that GVN has run before, so we only perform a pointer
   // comparison.  If for some reason the values are equal but the pointers are
@@ -208,8 +206,8 @@
     //    CONSTANT 0
     // Note that we cannot optimise `x - x` to `0` for floating-point. It does
     // not work when `x` is an infinity.
-    block->ReplaceAndRemoveInstructionWith(instruction,
-                                           HConstant::NewConstant(allocator, type, 0));
+    instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
+    block->RemoveInstruction(instruction);
   }
 }
 
@@ -225,10 +223,8 @@
     //    CONSTANT 0
     Primitive::Type type = instruction->GetType();
     HBasicBlock* block = instruction->GetBlock();
-    ArenaAllocator* allocator = GetGraph()->GetArena();
-
-    block->ReplaceAndRemoveInstructionWith(instruction,
-                                           HConstant::NewConstant(allocator, type, 0));
+    instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
+    block->RemoveInstruction(instruction);
   }
 }
 
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index 6ceccfb..6853d54 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -101,14 +101,16 @@
   // Expected difference after constant folding.
   diff_t expected_cf_diff = {
     { "  2: IntConstant [5]\n", "  2: IntConstant\n" },
-    { "  5: Neg(2) [8]\n",      "  12: IntConstant [8]\n" },
+    { "  10: SuspendCheck\n",   "  10: SuspendCheck\n"
+                                "  12: IntConstant [8]\n" },
+    { "  5: Neg(2) [8]\n",      removed },
     { "  8: Return(5)\n",       "  8: Return(12)\n" }
   };
   std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the value of the computed constant.
   auto check_after_cf = [](HGraph* graph) {
-    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
+    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
     ASSERT_TRUE(inst->IsIntConstant());
     ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1);
   };
@@ -160,14 +162,16 @@
   diff_t expected_cf_diff = {
     { "  3: IntConstant [9]\n", "  3: IntConstant\n" },
     { "  5: IntConstant [9]\n", "  5: IntConstant\n" },
-    { "  9: Add(3, 5) [12]\n",  "  16: IntConstant [12]\n" },
+    { "  14: SuspendCheck\n",   "  14: SuspendCheck\n"
+                                "  16: IntConstant [12]\n" },
+    { "  9: Add(3, 5) [12]\n",  removed },
     { "  12: Return(9)\n",      "  12: Return(16)\n" }
   };
   std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the value of the computed constant.
   auto check_after_cf = [](HGraph* graph) {
-    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
+    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
     ASSERT_TRUE(inst->IsIntConstant());
     ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
   };
@@ -195,8 +199,8 @@
  *     v0 <- 1                  0.      const/4 v0, #+1
  *     v1 <- 2                  1.      const/4 v1, #+2
  *     v0 <- v0 + v1            2.      add-int/2addr v0, v1
- *     v1 <- 3                  3.      const/4 v1, #+3
- *     v2 <- 4                  4.      const/4 v2, #+4
+ *     v1 <- 4                  3.      const/4 v1, #+4
+ *     v2 <- 5                  4.      const/4 v2, #+5
  *     v1 <- v1 + v2            5.      add-int/2addr v1, v2
  *     v2 <- v0 + v1            6.      add-int v2, v0, v1
  *     return v2                8.      return v2
@@ -206,8 +210,8 @@
     Instruction::CONST_4 | 0 << 8 | 1 << 12,
     Instruction::CONST_4 | 1 << 8 | 2 << 12,
     Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
-    Instruction::CONST_4 | 1 << 8 | 3 << 12,
-    Instruction::CONST_4 | 2 << 8 | 4 << 12,
+    Instruction::CONST_4 | 1 << 8 | 4 << 12,
+    Instruction::CONST_4 | 2 << 8 | 5 << 12,
     Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
     Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
     Instruction::RETURN | 2 << 8);
@@ -234,24 +238,28 @@
     { "  5: IntConstant [9]\n",   "  5: IntConstant\n" },
     { "  11: IntConstant [17]\n", "  11: IntConstant\n" },
     { "  13: IntConstant [17]\n", "  13: IntConstant\n" },
-    { "  9: Add(3, 5) [21]\n",    "  28: IntConstant\n" },
-    { "  17: Add(11, 13) [21]\n", "  29: IntConstant\n" },
-    { "  21: Add(9, 17) [24]\n",  "  30: IntConstant [24]\n" },
+    { "  26: SuspendCheck\n",     "  26: SuspendCheck\n"
+                                  "  28: IntConstant\n"
+                                  "  29: IntConstant\n"
+                                  "  30: IntConstant [24]\n" },
+    { "  9: Add(3, 5) [21]\n",    removed },
+    { "  17: Add(11, 13) [21]\n", removed },
+    { "  21: Add(9, 17) [24]\n",  removed  },
     { "  24: Return(21)\n",       "  24: Return(30)\n" }
   };
   std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the values of the computed constants.
   auto check_after_cf = [](HGraph* graph) {
-    HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
+    HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
     ASSERT_TRUE(inst1->IsIntConstant());
-    ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 3);
-    HInstruction* inst2 = inst1->GetNext();
+    ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 12);
+    HInstruction* inst2 = inst1->GetPrevious();
     ASSERT_TRUE(inst2->IsIntConstant());
-    ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 7);
-    HInstruction* inst3 = inst2->GetNext();
+    ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 9);
+    HInstruction* inst3 = inst2->GetPrevious();
     ASSERT_TRUE(inst3->IsIntConstant());
-    ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 10);
+    ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
   };
 
   // Expected difference after dead code elimination.
@@ -306,14 +314,16 @@
   diff_t expected_cf_diff = {
     { "  3: IntConstant [9]\n", "  3: IntConstant\n" },
     { "  5: IntConstant [9]\n", "  5: IntConstant\n" },
-    { "  9: Sub(3, 5) [12]\n",  "  16: IntConstant [12]\n" },
+    { "  14: SuspendCheck\n",   "  14: SuspendCheck\n"
+                                "  16: IntConstant [12]\n" },
+    { "  9: Sub(3, 5) [12]\n",  removed },
     { "  12: Return(9)\n",      "  12: Return(16)\n" }
   };
   std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the value of the computed constant.
   auto check_after_cf = [](HGraph* graph) {
-    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
+    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
     ASSERT_TRUE(inst->IsIntConstant());
     ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
   };
@@ -368,14 +378,16 @@
   diff_t expected_cf_diff = {
     { "  6: LongConstant [12]\n", "  6: LongConstant\n" },
     { "  8: LongConstant [12]\n", "  8: LongConstant\n" },
-    { "  12: Add(6, 8) [15]\n",   "  19: LongConstant [15]\n" },
+    { "  17: SuspendCheck\n",     "  17: SuspendCheck\n"
+                                  "  19: LongConstant [15]\n" },
+    { "  12: Add(6, 8) [15]\n",   removed },
     { "  15: Return(12)\n",       "  15: Return(19)\n" }
   };
   std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the value of the computed constant.
   auto check_after_cf = [](HGraph* graph) {
-    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
+    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
     ASSERT_TRUE(inst->IsLongConstant());
     ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
   };
@@ -431,14 +443,16 @@
   diff_t expected_cf_diff = {
     { "  6: LongConstant [12]\n", "  6: LongConstant\n" },
     { "  8: LongConstant [12]\n", "  8: LongConstant\n" },
-    { "  12: Sub(6, 8) [15]\n",   "  19: LongConstant [15]\n" },
+    { "  17: SuspendCheck\n",     "  17: SuspendCheck\n"
+                                  "  19: LongConstant [15]\n" },
+    { "  12: Sub(6, 8) [15]\n",   removed },
     { "  15: Return(12)\n",       "  15: Return(19)\n" }
   };
   std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the value of the computed constant.
   auto check_after_cf = [](HGraph* graph) {
-    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
+    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
     ASSERT_TRUE(inst->IsLongConstant());
     ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
   };
@@ -469,51 +483,51 @@
  *                              16-bit
  *                              offset
  *                              ------
- *     v0 <- 0                   0.     const/4 v0, #+0
- *     v1 <- 1                   1.     const/4 v1, #+1
+ *     v0 <- 1                   0.     const/4 v0, #+1
+ *     v1 <- 2                   1.     const/4 v1, #+2
  *     v2 <- v0 + v1             2.     add-int v2, v0, v1
  *     goto L2                   4.     goto +4
- * L1: v1 <- v0 + 3              5.     add-int/lit16 v1, v0, #+3
+ * L1: v1 <- v0 + 5              5.     add-int/lit16 v1, v0, #+5
  *     goto L3                   7.     goto +4
- * L2: v0 <- v2 + 2              8.     add-int/lit16 v0, v2, #+2
+ * L2: v0 <- v2 + 4              8.     add-int/lit16 v0, v2, #+4
  *     goto L1                  10.     goto +(-5)
- * L3: v2 <- v1 + 4             11.     add-int/lit16 v2, v1, #+4
+ * L3: v2 <- v1 + 8             11.     add-int/lit16 v2, v1, #+8
  *     return v2                13.     return v2
  */
 TEST(ConstantFolding, IntConstantFoldingAndJumps) {
   const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
-    Instruction::CONST_4 | 0 << 8 | 0 << 12,
-    Instruction::CONST_4 | 1 << 8 | 1 << 12,
+    Instruction::CONST_4 | 0 << 8 | 1 << 12,
+    Instruction::CONST_4 | 1 << 8 | 2 << 12,
     Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
     Instruction::GOTO | 4 << 8,
-    Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
+    Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 5,
     Instruction::GOTO | 4 << 8,
-    Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
+    Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 4,
     static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
-    Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
+    Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 8,
     Instruction::RETURN | 2 << 8);
 
   std::string expected_before =
     "BasicBlock 0, succ: 1\n"
-    "  3: IntConstant [9]\n"            // v0 <- 0
-    "  5: IntConstant [9]\n"            // v1 <- 1
-    "  13: IntConstant [14]\n"          // const 3
-    "  18: IntConstant [19]\n"          // const 2
-    "  24: IntConstant [25]\n"          // const 4
+    "  3: IntConstant [9]\n"            // v0 <- 1
+    "  5: IntConstant [9]\n"            // v1 <- 2
+    "  13: IntConstant [14]\n"          // const 5
+    "  18: IntConstant [19]\n"          // const 4
+    "  24: IntConstant [25]\n"          // const 8
     "  30: SuspendCheck\n"
     "  31: Goto 1\n"
     "BasicBlock 1, pred: 0, succ: 3\n"
-    "  9: Add(3, 5) [19]\n"             // v2 <- v0 + v1 = 0 + 1 = 1
+    "  9: Add(3, 5) [19]\n"             // v2 <- v0 + v1 = 1 + 2 = 3
     "  11: Goto 3\n"                    // goto L2
     "BasicBlock 2, pred: 3, succ: 4\n"  // L1:
-    "  14: Add(19, 13) [25]\n"          // v1 <- v0 + 3 = 3 + 3 = 6
+    "  14: Add(19, 13) [25]\n"          // v1 <- v0 + 3 = 7 + 5 = 12
     "  16: Goto 4\n"                    // goto L3
     "BasicBlock 3, pred: 1, succ: 2\n"  // L2:
-    "  19: Add(9, 18) [14]\n"           // v0 <- v2 + 2 = 1 + 2 = 3
+    "  19: Add(9, 18) [14]\n"           // v0 <- v2 + 2 = 3 + 4 = 7
     "  21: SuspendCheck\n"
     "  22: Goto 2\n"                    // goto L1
     "BasicBlock 4, pred: 2, succ: 5\n"  // L3:
-    "  25: Add(14, 24) [28]\n"          // v2 <- v1 + 4 = 6 + 4 = 10
+    "  25: Add(14, 24) [28]\n"          // v2 <- v1 + 4 = 12 + 8 = 20
     "  28: Return(25)\n"                // return v2
     "BasicBlock 5, pred: 4\n"
     "  29: Exit\n";
@@ -525,28 +539,33 @@
     { "  13: IntConstant [14]\n", "  13: IntConstant\n" },
     { "  18: IntConstant [19]\n", "  18: IntConstant\n" },
     { "  24: IntConstant [25]\n", "  24: IntConstant\n" },
-    { "  9: Add(3, 5) [19]\n",    "  32: IntConstant []\n" },
-    { "  14: Add(19, 13) [25]\n", "  34: IntConstant\n" },
-    { "  19: Add(9, 18) [14]\n",  "  33: IntConstant []\n" },
-    { "  25: Add(14, 24) [28]\n", "  35: IntConstant [28]\n" },
+    { "  30: SuspendCheck\n",     "  30: SuspendCheck\n"
+                                  "  32: IntConstant []\n"
+                                  "  33: IntConstant []\n"
+                                  "  34: IntConstant\n"
+                                  "  35: IntConstant [28]\n" },
+    { "  9: Add(3, 5) [19]\n",    removed },
+    { "  14: Add(19, 13) [25]\n", removed },
+    { "  19: Add(9, 18) [14]\n",  removed },
+    { "  25: Add(14, 24) [28]\n", removed },
     { "  28: Return(25)\n",       "  28: Return(35)\n"}
   };
   std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the values of the computed constants.
   auto check_after_cf = [](HGraph* graph) {
-    HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
+    HInstruction* inst1 = graph->GetBlock(4)->GetFirstInstruction()->InputAt(0);
     ASSERT_TRUE(inst1->IsIntConstant());
-    ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 1);
-    HInstruction* inst2 = graph->GetBlock(2)->GetFirstInstruction();
+    ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 20);
+    HInstruction* inst2 = inst1->GetPrevious();
     ASSERT_TRUE(inst2->IsIntConstant());
-    ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 6);
-    HInstruction* inst3 = graph->GetBlock(3)->GetFirstInstruction();
+    ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 12);
+    HInstruction* inst3 = inst2->GetPrevious();
     ASSERT_TRUE(inst3->IsIntConstant());
-    ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
-    HInstruction* inst4 = graph->GetBlock(4)->GetFirstInstruction();
+    ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 7);
+    HInstruction* inst4 = inst3->GetPrevious();
     ASSERT_TRUE(inst4->IsIntConstant());
-    ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 10);
+    ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 3);
   };
 
   // Expected difference after dead code elimination.
@@ -611,25 +630,25 @@
 
   // Expected difference after constant folding.
   diff_t expected_cf_diff = {
-    { "  3: IntConstant [15, 22, 8]\n",      "  3: IntConstant [15, 22]\n" },
+    { "  3: IntConstant [15, 22, 8]\n",      "  3: IntConstant [9, 15, 22]\n" },
     { "  5: IntConstant [22, 8]\n",          "  5: IntConstant [22]\n" },
-    { "  8: GreaterThanOrEqual(3, 5) [9]\n", "  23: IntConstant [9]\n" },
-    { "  9: If(8)\n",                        "  9: If(23)\n" }
+    { "  8: GreaterThanOrEqual(3, 5) [9]\n", removed },
+    { "  9: If(8)\n",                        "  9: If(3)\n" }
   };
   std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the values of the computed constants.
   auto check_after_cf = [](HGraph* graph) {
-    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
+    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
     ASSERT_TRUE(inst->IsIntConstant());
     ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
   };
 
   // Expected difference after dead code elimination.
   diff_t expected_dce_diff = {
-    { "  3: IntConstant [15, 22]\n", "  3: IntConstant [22]\n" },
-    { "  22: Phi(3, 5) [15]\n",      "  22: Phi(3, 5)\n" },
-    { "  15: Add(22, 3)\n",          removed }
+    { "  3: IntConstant [9, 15, 22]\n", "  3: IntConstant [9, 22]\n" },
+    { "  22: Phi(3, 5) [15]\n",         "  22: Phi(3, 5)\n" },
+    { "  15: Add(22, 3)\n",             removed }
   };
   std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
 
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 09a3ae4..7c3c2bf 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -80,8 +80,7 @@
   }
 
   // Ensure `block` ends with a branch instruction.
-  HInstruction* last_inst = block->GetLastInstruction();
-  if (last_inst == nullptr || !last_inst->IsControlFlow()) {
+  if (!block->EndsWithControlFlowInstruction()) {
     AddError(StringPrintf("Block %d does not end with a branch instruction.",
                           block->GetBlockId()));
   }
@@ -476,4 +475,15 @@
   }
 }
 
+void SSAChecker::VisitConstant(HConstant* instruction) {
+  HBasicBlock* block = instruction->GetBlock();
+  if (!block->IsEntryBlock()) {
+    AddError(StringPrintf(
+        "%s %d should be in the entry block but is in block %d.",
+        instruction->DebugName(),
+        instruction->GetId(),
+        block->GetBlockId()));
+  }
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index 5ec3003..89fea0a 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -107,6 +107,7 @@
   void VisitBinaryOperation(HBinaryOperation* op) OVERRIDE;
   void VisitCondition(HCondition* op) OVERRIDE;
   void VisitIf(HIf* instruction) OVERRIDE;
+  void VisitConstant(HConstant* instruction) OVERRIDE;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SSAChecker);
diff --git a/compiler/optimizing/graph_test.cc b/compiler/optimizing/graph_test.cc
index 4742e4d..50398b4 100644
--- a/compiler/optimizing/graph_test.cc
+++ b/compiler/optimizing/graph_test.cc
@@ -28,8 +28,7 @@
 static HBasicBlock* createIfBlock(HGraph* graph, ArenaAllocator* allocator) {
   HBasicBlock* if_block = new (allocator) HBasicBlock(graph);
   graph->AddBlock(if_block);
-  HInstruction* instr = new (allocator) HIntConstant(4);
-  if_block->AddInstruction(instr);
+  HInstruction* instr = graph->GetIntConstant(4);
   HInstruction* equal = new (allocator) HEqual(instr, instr);
   if_block->AddInstruction(equal);
   instr = new (allocator) HIf(equal);
@@ -45,6 +44,12 @@
   return block;
 }
 
+static HBasicBlock* createEntryBlock(HGraph* graph, ArenaAllocator* allocator) {
+  HBasicBlock* block = createGotoBlock(graph, allocator);
+  graph->SetEntryBlock(block);
+  return block;
+}
+
 static HBasicBlock* createReturnBlock(HGraph* graph, ArenaAllocator* allocator) {
   HBasicBlock* block = new (allocator) HBasicBlock(graph);
   graph->AddBlock(block);
@@ -69,7 +74,7 @@
   ArenaAllocator allocator(&pool);
 
   HGraph* graph = new (&allocator) HGraph(&allocator);
-  HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+  HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
   HBasicBlock* if_block = createIfBlock(graph, &allocator);
   HBasicBlock* if_true = createGotoBlock(graph, &allocator);
   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
@@ -104,7 +109,7 @@
   ArenaAllocator allocator(&pool);
 
   HGraph* graph = new (&allocator) HGraph(&allocator);
-  HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+  HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
   HBasicBlock* if_block = createIfBlock(graph, &allocator);
   HBasicBlock* if_false = createGotoBlock(graph, &allocator);
   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
@@ -139,12 +144,11 @@
   ArenaAllocator allocator(&pool);
 
   HGraph* graph = new (&allocator) HGraph(&allocator);
-  HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+  HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
   HBasicBlock* if_block = createIfBlock(graph, &allocator);
   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
   HBasicBlock* exit_block = createExitBlock(graph, &allocator);
 
-  graph->SetEntryBlock(entry_block);
   entry_block->AddSuccessor(if_block);
   if_block->AddSuccessor(if_block);
   if_block->AddSuccessor(return_block);
@@ -175,12 +179,11 @@
   ArenaAllocator allocator(&pool);
 
   HGraph* graph = new (&allocator) HGraph(&allocator);
-  HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+  HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
   HBasicBlock* if_block = createIfBlock(graph, &allocator);
   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
   HBasicBlock* exit_block = createExitBlock(graph, &allocator);
 
-  graph->SetEntryBlock(entry_block);
   entry_block->AddSuccessor(if_block);
   if_block->AddSuccessor(return_block);
   if_block->AddSuccessor(if_block);
@@ -211,13 +214,12 @@
   ArenaAllocator allocator(&pool);
 
   HGraph* graph = new (&allocator) HGraph(&allocator);
-  HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+  HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
   HBasicBlock* first_if_block = createIfBlock(graph, &allocator);
   HBasicBlock* if_block = createIfBlock(graph, &allocator);
   HBasicBlock* loop_block = createGotoBlock(graph, &allocator);
   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
 
-  graph->SetEntryBlock(entry_block);
   entry_block->AddSuccessor(first_if_block);
   first_if_block->AddSuccessor(if_block);
   first_if_block->AddSuccessor(loop_block);
@@ -251,13 +253,12 @@
   ArenaAllocator allocator(&pool);
 
   HGraph* graph = new (&allocator) HGraph(&allocator);
-  HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+  HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
   HBasicBlock* first_if_block = createIfBlock(graph, &allocator);
   HBasicBlock* if_block = createIfBlock(graph, &allocator);
   HBasicBlock* loop_block = createGotoBlock(graph, &allocator);
   HBasicBlock* return_block = createReturnBlock(graph, &allocator);
 
-  graph->SetEntryBlock(entry_block);
   entry_block->AddSuccessor(first_if_block);
   first_if_block->AddSuccessor(if_block);
   first_if_block->AddSuccessor(loop_block);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 968fe3e..4b990f1 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -50,7 +50,9 @@
       HInstruction* next = instruction->GetNext();
       HInvokeStaticOrDirect* call = instruction->AsInvokeStaticOrDirect();
       if (call != nullptr) {
-        if (!TryInline(call, call->GetDexMethodIndex(), call->GetInvokeType())) {
+        // We use the original invoke type to ensure the resolution of the called method
+        // works properly.
+        if (!TryInline(call, call->GetDexMethodIndex(), call->GetOriginalInvokeType())) {
           if (kIsDebugBuild) {
             std::string callee_name =
                 PrettyMethod(call->GetDexMethodIndex(), *outer_compilation_unit_.GetDexFile());
@@ -68,87 +70,87 @@
                          uint32_t method_index,
                          InvokeType invoke_type) const {
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile& outer_dex_file = *outer_compilation_unit_.GetDexFile();
-  VLOG(compiler) << "Try inlining " << PrettyMethod(method_index, outer_dex_file);
+  const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
+  VLOG(compiler) << "Try inlining " << PrettyMethod(method_index, caller_dex_file);
 
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::DexCache> dex_cache(
-      hs.NewHandle(outer_compilation_unit_.GetClassLinker()->FindDexCache(outer_dex_file)));
+      hs.NewHandle(caller_compilation_unit_.GetClassLinker()->FindDexCache(caller_dex_file)));
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(outer_compilation_unit_.GetClassLoader())));
+      soa.Decode<mirror::ClassLoader*>(caller_compilation_unit_.GetClassLoader())));
   Handle<mirror::ArtMethod> resolved_method(hs.NewHandle(
       compiler_driver_->ResolveMethod(
-          soa, dex_cache, class_loader, &outer_compilation_unit_, method_index, invoke_type)));
+          soa, dex_cache, class_loader, &caller_compilation_unit_, method_index, invoke_type)));
 
   if (resolved_method.Get() == nullptr) {
-    VLOG(compiler) << "Method cannot be resolved " << PrettyMethod(method_index, outer_dex_file);
+    VLOG(compiler) << "Method cannot be resolved " << PrettyMethod(method_index, caller_dex_file);
     return false;
   }
 
+  bool can_use_dex_cache = true;
+  const DexFile& outer_dex_file = *outer_compilation_unit_.GetDexFile();
   if (resolved_method->GetDexFile()->GetLocation().compare(outer_dex_file.GetLocation()) != 0) {
-    VLOG(compiler) << "Did not inline "
-                   << PrettyMethod(method_index, outer_dex_file)
-                   << " because it is in a different dex file";
-    return false;
+    can_use_dex_cache = false;
   }
 
   const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
 
   if (code_item == nullptr) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
                    << " is not inlined because it is native";
     return false;
   }
 
   if (code_item->insns_size_in_code_units_ > kMaxInlineCodeUnits) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
                    << " is too big to inline";
     return false;
   }
 
   if (code_item->tries_size_ != 0) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
                    << " is not inlined because of try block";
     return false;
   }
 
   if (!resolved_method->GetDeclaringClass()->IsVerified()) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
                    << " is not inlined because its class could not be verified";
     return false;
   }
 
   if (resolved_method->ShouldNotInline()) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
                    << " was already flagged as non inlineable";
     return false;
   }
 
-  if (!TryBuildAndInline(resolved_method, invoke_instruction, method_index)) {
+  if (!TryBuildAndInline(resolved_method, invoke_instruction, method_index, can_use_dex_cache)) {
     resolved_method->SetShouldNotInline();
     return false;
   }
 
-  VLOG(compiler) << "Successfully inlined " << PrettyMethod(method_index, outer_dex_file);
+  VLOG(compiler) << "Successfully inlined " << PrettyMethod(method_index, caller_dex_file);
   MaybeRecordStat(kInlinedInvoke);
   return true;
 }
 
 bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method,
                                  HInvoke* invoke_instruction,
-                                 uint32_t method_index) const {
+                                 uint32_t method_index,
+                                 bool can_use_dex_cache) const {
   ScopedObjectAccess soa(Thread::Current());
   const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
-  const DexFile& outer_dex_file = *outer_compilation_unit_.GetDexFile();
+  const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
 
   DexCompilationUnit dex_compilation_unit(
     nullptr,
-    outer_compilation_unit_.GetClassLoader(),
-    outer_compilation_unit_.GetClassLinker(),
-    outer_dex_file,
+    caller_compilation_unit_.GetClassLoader(),
+    caller_compilation_unit_.GetClassLinker(),
+    *resolved_method->GetDexFile(),
     code_item,
     resolved_method->GetDeclaringClass()->GetDexClassDefIndex(),
-    method_index,
+    resolved_method->GetDexMethodIndex(),
     resolved_method->GetAccessFlags(),
     nullptr);
 
@@ -159,25 +161,25 @@
   HGraphBuilder builder(callee_graph,
                         &dex_compilation_unit,
                         &outer_compilation_unit_,
-                        &outer_dex_file,
+                        resolved_method->GetDexFile(),
                         compiler_driver_,
                         &inline_stats);
 
   if (!builder.BuildGraph(*code_item)) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
                    << " could not be built, so cannot be inlined";
     return false;
   }
 
   if (!RegisterAllocator::CanAllocateRegistersFor(*callee_graph,
                                                   compiler_driver_->GetInstructionSet())) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
                    << " cannot be inlined because of the register allocator";
     return false;
   }
 
   if (!callee_graph->TryBuildingSsa()) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
                    << " could not be transformed to SSA";
     return false;
   }
@@ -199,8 +201,12 @@
   }
 
   if (depth_ + 1 < kDepthLimit) {
-    HInliner inliner(
-        callee_graph, outer_compilation_unit_, compiler_driver_, stats_, depth_ + 1);
+    HInliner inliner(callee_graph,
+                     outer_compilation_unit_,
+                     dex_compilation_unit,
+                     compiler_driver_,
+                     stats_,
+                     depth_ + 1);
     inliner.Run();
   }
 
@@ -209,7 +215,7 @@
   for (; !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
     if (block->IsLoopHeader()) {
-      VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+      VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
                      << " could not be inlined because it contains a loop";
       return false;
     }
@@ -223,18 +229,25 @@
       }
 
       if (current->CanThrow()) {
-        VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
                        << " could not be inlined because " << current->DebugName()
                        << " can throw";
         return false;
       }
 
       if (current->NeedsEnvironment()) {
-        VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
                        << " could not be inlined because " << current->DebugName()
                        << " needs an environment";
         return false;
       }
+
+      if (!can_use_dex_cache && current->NeedsDexCache()) {
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
+                       << " could not be inlined because " << current->DebugName()
+                       << " it is in a different dex file and requires access to the dex cache";
+        return false;
+      }
     }
   }
 
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 1251977..1dbc7d3 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -32,11 +32,13 @@
  public:
   HInliner(HGraph* outer_graph,
            const DexCompilationUnit& outer_compilation_unit,
+           const DexCompilationUnit& caller_compilation_unit,
            CompilerDriver* compiler_driver,
            OptimizingCompilerStats* stats,
            size_t depth = 0)
       : HOptimization(outer_graph, true, kInlinerPassName, stats),
         outer_compilation_unit_(outer_compilation_unit),
+        caller_compilation_unit_(caller_compilation_unit),
         compiler_driver_(compiler_driver),
         depth_(depth) {}
 
@@ -48,9 +50,11 @@
   bool TryInline(HInvoke* invoke_instruction, uint32_t method_index, InvokeType invoke_type) const;
   bool TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method,
                          HInvoke* invoke_instruction,
-                         uint32_t method_index) const;
+                         uint32_t method_index,
+                         bool can_use_dex_cache) const;
 
   const DexCompilationUnit& outer_compilation_unit_;
+  const DexCompilationUnit& caller_compilation_unit_;
   CompilerDriver* const compiler_driver_;
   const size_t depth_;
 
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2ef19b9..56ec8a7 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -292,8 +292,7 @@
       //    MUL dst, src, pow_of_2
       // with
       //    SHL dst, src, log2(pow_of_2)
-      HIntConstant* shift = new (allocator) HIntConstant(WhichPowerOf2(factor));
-      block->InsertInstructionBefore(shift, instruction);
+      HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
       HShl* shl = new(allocator) HShl(type, input_other, shift);
       block->ReplaceAndRemoveInstructionWith(instruction, shl);
     }
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 4f6565d..dca612e 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -287,39 +287,62 @@
   return true;
 }
 
-void HGraph::AddConstant(HConstant* instruction) {
-  HInstruction* last_instruction = entry_block_->GetLastInstruction();
-  if (last_instruction == nullptr || !last_instruction->IsControlFlow()) {
-    // Called from the builder. Insert at the end of the block.
-    entry_block_->AddInstruction(instruction);
+void HGraph::InsertConstant(HConstant* constant) {
+  // New constants are inserted before the final control-flow instruction
+  // of the graph, or at its end if called from the graph builder.
+  if (entry_block_->EndsWithControlFlowInstruction()) {
+    entry_block_->InsertInstructionBefore(constant, entry_block_->GetLastInstruction());
   } else {
-    // Entry block ends with control-flow. Insert before the last instruction.
-    entry_block_->InsertInstructionBefore(instruction, last_instruction);
+    entry_block_->AddInstruction(constant);
   }
 }
 
 HNullConstant* HGraph::GetNullConstant() {
   if (cached_null_constant_ == nullptr) {
     cached_null_constant_ = new (arena_) HNullConstant();
-    AddConstant(cached_null_constant_);
+    InsertConstant(cached_null_constant_);
   }
   return cached_null_constant_;
 }
 
-HIntConstant* HGraph::GetIntConstant0() {
-  if (cached_int_constant0_ == nullptr) {
-    cached_int_constant0_ = new (arena_) HIntConstant(0);
-    AddConstant(cached_int_constant0_);
+template <class InstructionType, typename ValueType>
+InstructionType* HGraph::CreateConstant(ValueType value,
+                                        ArenaSafeMap<ValueType, InstructionType*>* cache) {
+  // Try to find an existing constant of the given value.
+  InstructionType* constant = nullptr;
+  auto cached_constant = cache->find(value);
+  if (cached_constant != cache->end()) {
+    constant = cached_constant->second;
   }
-  return cached_int_constant0_;
+
+  // If not found or previously deleted, create and cache a new instruction.
+  if (constant == nullptr || constant->GetBlock() == nullptr) {
+    constant = new (arena_) InstructionType(value);
+    cache->Overwrite(value, constant);
+    InsertConstant(constant);
+  }
+  return constant;
 }
 
-HIntConstant* HGraph::GetIntConstant1() {
-  if (cached_int_constant1_ == nullptr) {
-    cached_int_constant1_ = new (arena_) HIntConstant(1);
-    AddConstant(cached_int_constant1_);
+HConstant* HGraph::GetConstant(Primitive::Type type, int64_t value) {
+  switch (type) {
+    case Primitive::Type::kPrimBoolean:
+      DCHECK(IsUint<1>(value));
+      FALLTHROUGH_INTENDED;
+    case Primitive::Type::kPrimByte:
+    case Primitive::Type::kPrimChar:
+    case Primitive::Type::kPrimShort:
+    case Primitive::Type::kPrimInt:
+      DCHECK(IsInt(Primitive::ComponentSize(type) * kBitsPerByte, value));
+      return GetIntConstant(static_cast<int32_t>(value));
+
+    case Primitive::Type::kPrimLong:
+      return GetLongConstant(value);
+
+    default:
+      LOG(FATAL) << "Unsupported constant type";
+      UNREACHABLE();
   }
-  return cached_int_constant1_;
 }
 
 void HLoopInformation::Add(HBasicBlock* block) {
@@ -676,7 +699,7 @@
 HConstant* HUnaryOperation::TryStaticEvaluation() const {
   if (GetInput()->IsIntConstant()) {
     int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
-    return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
+    return GetBlock()->GetGraph()->GetIntConstant(value);
   } else if (GetInput()->IsLongConstant()) {
     // TODO: Implement static evaluation of long unary operations.
     //
@@ -692,15 +715,15 @@
   if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
     int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
                              GetRight()->AsIntConstant()->GetValue());
-    return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
+    return GetBlock()->GetGraph()->GetIntConstant(value);
   } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
     int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
                              GetRight()->AsLongConstant()->GetValue());
     if (GetResultType() == Primitive::kPrimLong) {
-      return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value);
+      return GetBlock()->GetGraph()->GetLongConstant(value);
     } else {
       DCHECK_EQ(GetResultType(), Primitive::kPrimInt);
-      return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
+      return GetBlock()->GetGraph()->GetIntConstant(static_cast<int32_t>(value));
     }
   }
   return nullptr;
@@ -733,16 +756,6 @@
   return this == if_->GetPreviousDisregardingMoves();
 }
 
-HConstant* HConstant::NewConstant(ArenaAllocator* allocator, Primitive::Type type, int64_t val) {
-  if (type == Primitive::kPrimInt) {
-    DCHECK(IsInt<32>(val));
-    return new (allocator) HIntConstant(val);
-  } else {
-    DCHECK_EQ(type, Primitive::kPrimLong);
-    return new (allocator) HLongConstant(val);
-  }
-}
-
 bool HInstruction::Equals(HInstruction* other) const {
   if (!InstructionTypeEquals(other)) return false;
   DCHECK_EQ(GetKind(), other->GetKind());
@@ -832,6 +845,10 @@
          && (loop_info == nullptr || !loop_info->IsBackEdge(*this));
 }
 
+bool HBasicBlock::EndsWithControlFlowInstruction() const {
+  return !GetInstructions().IsEmpty() && GetLastInstruction()->IsControlFlow();
+}
+
 bool HBasicBlock::EndsWithIf() const {
   return !GetInstructions().IsEmpty() && GetLastInstruction()->IsIf();
 }
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 664cf18..c4e2798 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_OPTIMIZING_NODES_H_
 #define ART_COMPILER_OPTIMIZING_NODES_H_
 
+#include "base/arena_containers.h"
 #include "base/arena_object.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
 #include "handle.h"
@@ -33,16 +34,20 @@
 
 class GraphChecker;
 class HBasicBlock;
+class HDoubleConstant;
 class HEnvironment;
+class HFloatConstant;
+class HGraphVisitor;
 class HInstruction;
 class HIntConstant;
 class HInvoke;
-class HGraphVisitor;
+class HLongConstant;
 class HNullConstant;
 class HPhi;
 class HSuspendCheck;
 class LiveInterval;
 class LocationSummary;
+class SsaBuilder;
 
 static const int kDefaultNumberOfBlocks = 8;
 static const int kDefaultNumberOfSuccessors = 2;
@@ -115,7 +120,10 @@
         temporaries_vreg_slots_(0),
         has_array_accesses_(false),
         debuggable_(debuggable),
-        current_instruction_id_(start_instruction_id) {}
+        current_instruction_id_(start_instruction_id),
+        cached_null_constant_(nullptr),
+        cached_int_constants_(std::less<int32_t>(), arena->Adapter()),
+        cached_long_constants_(std::less<int64_t>(), arena->Adapter()) {}
 
   ArenaAllocator* GetArena() const { return arena_; }
   const GrowableArray<HBasicBlock*>& GetBlocks() const { return blocks_; }
@@ -128,7 +136,6 @@
   void SetExitBlock(HBasicBlock* block) { exit_block_ = block; }
 
   void AddBlock(HBasicBlock* block);
-  void AddConstant(HConstant* instruction);
 
   // Try building the SSA form of this graph, with dominance computation and loop
   // recognition. Returns whether it was successful in doing all these steps.
@@ -219,9 +226,17 @@
 
   bool IsDebuggable() const { return debuggable_; }
 
+  // Returns a constant of the given type and value. If it does not exist
+  // already, it is created and inserted into the graph. Only integral types
+  // are currently supported.
+  HConstant* GetConstant(Primitive::Type type, int64_t value);
   HNullConstant* GetNullConstant();
-  HIntConstant* GetIntConstant0();
-  HIntConstant* GetIntConstant1();
+  HIntConstant* GetIntConstant(int32_t value) {
+    return CreateConstant(value, &cached_int_constants_);
+  }
+  HLongConstant* GetLongConstant(int64_t value) {
+    return CreateConstant(value, &cached_long_constants_);
+  }
 
  private:
   HBasicBlock* FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const;
@@ -235,6 +250,10 @@
   void RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const;
   void RemoveDeadBlocks(const ArenaBitVector& visited) const;
 
+  template <class InstType, typename ValueType>
+  InstType* CreateConstant(ValueType value, ArenaSafeMap<ValueType, InstType*>* cache);
+  void InsertConstant(HConstant* instruction);
+
   ArenaAllocator* const arena_;
 
   // List of blocks in insertion order.
@@ -269,12 +288,10 @@
   // The current id to assign to a newly added instruction. See HInstruction.id_.
   int32_t current_instruction_id_;
 
-  // Cached null constant that might be created when building SSA form.
-  HNullConstant* cached_null_constant_;
-
   // Cached common constants often needed by optimization passes.
-  HIntConstant* cached_int_constant0_;
-  HIntConstant* cached_int_constant1_;
+  HNullConstant* cached_null_constant_;
+  ArenaSafeMap<int32_t, HIntConstant*> cached_int_constants_;
+  ArenaSafeMap<int64_t, HLongConstant*> cached_long_constants_;
 
   ART_FRIEND_TEST(GraphTest, IfSuccessorSimpleJoinBlock1);
   DISALLOW_COPY_AND_ASSIGN(HGraph);
@@ -602,6 +619,7 @@
   bool IsCatchBlock() const { return is_catch_block_; }
   void SetIsCatchBlock() { is_catch_block_ = true; }
 
+  bool EndsWithControlFlowInstruction() const;
   bool EndsWithIf() const;
   bool HasSinglePhi() const;
 
@@ -1248,6 +1266,8 @@
     return NeedsEnvironment() || IsLoadClass() || IsLoadString();
   }
 
+  virtual bool NeedsDexCache() const { return false; }
+
  protected:
   virtual const HUserRecord<HInstruction*> InputRecordAt(size_t i) const = 0;
   virtual void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) = 0;
@@ -1906,8 +1926,6 @@
   virtual bool IsZero() const { return false; }
   virtual bool IsOne() const { return false; }
 
-  static HConstant* NewConstant(ArenaAllocator* allocator, Primitive::Type type, int64_t val);
-
   DECLARE_INSTRUCTION(Constant);
 
  private:
@@ -1916,8 +1934,6 @@
 
 class HFloatConstant : public HConstant {
  public:
-  explicit HFloatConstant(float value) : HConstant(Primitive::kPrimFloat), value_(value) {}
-
   float GetValue() const { return value_; }
 
   bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -1942,15 +1958,19 @@
   DECLARE_INSTRUCTION(FloatConstant);
 
  private:
+  explicit HFloatConstant(float value) : HConstant(Primitive::kPrimFloat), value_(value) {}
+
   const float value_;
 
+  // Only the SsaBuilder can currently create floating-point constants. If we
+  // ever need to create them later in the pipeline, we will have to handle them
+  // the same way as integral constants.
+  friend class SsaBuilder;
   DISALLOW_COPY_AND_ASSIGN(HFloatConstant);
 };
 
 class HDoubleConstant : public HConstant {
  public:
-  explicit HDoubleConstant(double value) : HConstant(Primitive::kPrimDouble), value_(value) {}
-
   double GetValue() const { return value_; }
 
   bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -1975,15 +1995,19 @@
   DECLARE_INSTRUCTION(DoubleConstant);
 
  private:
+  explicit HDoubleConstant(double value) : HConstant(Primitive::kPrimDouble), value_(value) {}
+
   const double value_;
 
+  // Only the SsaBuilder can currently create floating-point constants. If we
+  // ever need to create them later in the pipeline, we will have to handle them
+  // the same way as integral constants.
+  friend class SsaBuilder;
   DISALLOW_COPY_AND_ASSIGN(HDoubleConstant);
 };
 
 class HNullConstant : public HConstant {
  public:
-  HNullConstant() : HConstant(Primitive::kPrimNot) {}
-
   bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
     return true;
   }
@@ -1995,6 +2019,9 @@
   DECLARE_INSTRUCTION(NullConstant);
 
  private:
+  HNullConstant() : HConstant(Primitive::kPrimNot) {}
+
+  friend class HGraph;
   DISALLOW_COPY_AND_ASSIGN(HNullConstant);
 };
 
@@ -2002,8 +2029,6 @@
 // synthesized (for example with the if-eqz instruction).
 class HIntConstant : public HConstant {
  public:
-  explicit HIntConstant(int32_t value) : HConstant(Primitive::kPrimInt), value_(value) {}
-
   int32_t GetValue() const { return value_; }
 
   bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -2024,15 +2049,18 @@
   DECLARE_INSTRUCTION(IntConstant);
 
  private:
+  explicit HIntConstant(int32_t value) : HConstant(Primitive::kPrimInt), value_(value) {}
+
   const int32_t value_;
 
+  friend class HGraph;
+  ART_FRIEND_TEST(GraphTest, InsertInstructionBefore);
+  ART_FRIEND_TEST(ParallelMoveTest, ConstantLast);
   DISALLOW_COPY_AND_ASSIGN(HIntConstant);
 };
 
 class HLongConstant : public HConstant {
  public:
-  explicit HLongConstant(int64_t value) : HConstant(Primitive::kPrimLong), value_(value) {}
-
   int64_t GetValue() const { return value_; }
 
   bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -2048,8 +2076,11 @@
   DECLARE_INSTRUCTION(LongConstant);
 
  private:
+  explicit HLongConstant(int64_t value) : HConstant(Primitive::kPrimLong), value_(value) {}
+
   const int64_t value_;
 
+  friend class HGraph;
   DISALLOW_COPY_AND_ASSIGN(HLongConstant);
 };
 
@@ -2129,8 +2160,10 @@
                         uint32_t dex_pc,
                         uint32_t dex_method_index,
                         bool is_recursive,
+                        InvokeType original_invoke_type,
                         InvokeType invoke_type)
       : HInvoke(arena, number_of_arguments, return_type, dex_pc, dex_method_index),
+        original_invoke_type_(original_invoke_type),
         invoke_type_(invoke_type),
         is_recursive_(is_recursive) {}
 
@@ -2140,12 +2173,15 @@
     return false;
   }
 
+  InvokeType GetOriginalInvokeType() const { return original_invoke_type_; }
   InvokeType GetInvokeType() const { return invoke_type_; }
   bool IsRecursive() const { return is_recursive_; }
+  bool NeedsDexCache() const OVERRIDE { return !IsRecursive(); }
 
   DECLARE_INSTRUCTION(InvokeStaticOrDirect);
 
  private:
+  const InvokeType original_invoke_type_;
   const InvokeType invoke_type_;
   const bool is_recursive_;
 
@@ -3024,6 +3060,8 @@
     return loaded_class_rti_.IsExact();
   }
 
+  bool NeedsDexCache() const OVERRIDE { return !is_referrers_class_; }
+
   DECLARE_INSTRUCTION(LoadClass);
 
  private:
@@ -3059,6 +3097,7 @@
 
   // TODO: Can we deopt or debug when we resolve a string?
   bool NeedsEnvironment() const OVERRIDE { return false; }
+  bool NeedsDexCache() const OVERRIDE { return true; }
 
   DECLARE_INSTRUCTION(LoadString);
 
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index eaa30df..5ce73ba 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -316,7 +316,7 @@
   InstructionSimplifier simplify1(graph, stats);
   HBooleanSimplifier boolean_not(graph);
 
-  HInliner inliner(graph, dex_compilation_unit, driver, stats);
+  HInliner inliner(graph, dex_compilation_unit, dex_compilation_unit, driver, stats);
 
   HConstantFolding fold2(graph);
   SideEffectsAnalysis side_effects(graph);
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 7a2d84b..7c3a035 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -644,11 +644,10 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimInt);
-  HInstruction* constant1 = new (allocator) HIntConstant(0);
-  HInstruction* constant2 = new (allocator) HIntConstant(0);
   entry->AddInstruction(parameter);
-  entry->AddInstruction(constant1);
-  entry->AddInstruction(constant2);
+
+  HInstruction* constant1 = graph->GetIntConstant(1);
+  HInstruction* constant2 = graph->GetIntConstant(2);
 
   HBasicBlock* block = new (allocator) HBasicBlock(graph);
   graph->AddBlock(block);
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index ae6bf16..fcc4e69 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -353,7 +353,7 @@
  * is used for floating point operations. We create a floating-point equivalent
  * constant to make the operations correctly typed.
  */
-static HFloatConstant* GetFloatEquivalent(HIntConstant* constant) {
+HFloatConstant* SsaBuilder::GetFloatEquivalent(HIntConstant* constant) {
   // We place the floating point constant next to this constant.
   HFloatConstant* result = constant->GetNext()->AsFloatConstant();
   if (result == nullptr) {
@@ -375,7 +375,7 @@
  * is used for floating point operations. We create a floating-point equivalent
  * constant to make the operations correctly typed.
  */
-static HDoubleConstant* GetDoubleEquivalent(HLongConstant* constant) {
+HDoubleConstant* SsaBuilder::GetDoubleEquivalent(HLongConstant* constant) {
   // We place the floating point constant next to this constant.
   HDoubleConstant* result = constant->GetNext()->AsDoubleConstant();
   if (result == nullptr) {
@@ -398,7 +398,7 @@
  * floating point registers and core registers), we need to create a copy of the
  * phi with a floating point / reference type.
  */
-static HPhi* GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, Primitive::Type type) {
+HPhi* SsaBuilder::GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, Primitive::Type type) {
   // We place the floating point /reference phi next to this phi.
   HInstruction* next = phi->GetNext();
   if (next != nullptr
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index 24dc449..569b3e2 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -85,6 +85,10 @@
   static constexpr const char* kSsaBuilderPassName = "ssa_builder";
 
  private:
+  static HFloatConstant* GetFloatEquivalent(HIntConstant* constant);
+  static HDoubleConstant* GetDoubleEquivalent(HLongConstant* constant);
+  static HPhi* GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, Primitive::Type type);
+
   // Locals for the current block being visited.
   HEnvironment* current_locals_;
 
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 9914ef4..5818a37 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -17,7 +17,8 @@
 #ifndef ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_
 #define ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_
 
-#include "base/bit_vector.h"
+#include "base/arena_containers.h"
+#include "base/bit_vector-inl.h"
 #include "base/value_object.h"
 #include "memory_region.h"
 #include "nodes.h"
@@ -40,7 +41,8 @@
         stack_mask_max_(-1),
         dex_pc_max_(0),
         native_pc_offset_max_(0),
-        number_of_stack_maps_with_inline_info_(0) {}
+        number_of_stack_maps_with_inline_info_(0),
+        dex_map_hash_to_stack_map_indices_(std::less<uint32_t>(), allocator->Adapter()) {}
 
   // Compute bytes needed to encode a mask with the given maximum element.
   static uint32_t StackMaskEncodingSize(int max_element) {
@@ -59,6 +61,7 @@
     size_t dex_register_locations_start_index;
     size_t inline_infos_start_index;
     BitVector* live_dex_registers_mask;
+    uint32_t dex_register_map_hash;
   };
 
   struct InlineInfoEntry {
@@ -80,6 +83,7 @@
     entry.inlining_depth = inlining_depth;
     entry.dex_register_locations_start_index = dex_register_locations_.Size();
     entry.inline_infos_start_index = inline_infos_.Size();
+    entry.dex_register_map_hash = 0;
     if (num_dex_registers != 0) {
       entry.live_dex_registers_mask =
           new (allocator_) ArenaBitVector(allocator_, num_dex_registers, true);
@@ -105,7 +109,7 @@
     inline_infos_.Add(entry);
   }
 
-  size_t ComputeNeededSize() const {
+  size_t ComputeNeededSize() {
     size_t size = CodeInfo::kFixedSize
         + ComputeStackMapsSize()
         + ComputeDexRegisterMapsSize()
@@ -118,7 +122,7 @@
     return StackMaskEncodingSize(stack_mask_max_);
   }
 
-  size_t ComputeStackMapsSize() const {
+  size_t ComputeStackMapsSize() {
     return stack_maps_.Size() * StackMap::ComputeStackMapSize(
         ComputeStackMaskSize(),
         ComputeInlineInfoSize(),
@@ -146,10 +150,13 @@
   }
 
   // Compute the size of all the Dex register maps.
-  size_t ComputeDexRegisterMapsSize() const {
+  size_t ComputeDexRegisterMapsSize() {
     size_t size = 0;
     for (size_t i = 0; i < stack_maps_.Size(); ++i) {
-      size += ComputeDexRegisterMapSize(stack_maps_.Get(i));
+      if (FindEntryWithTheSameDexMap(i) == kNoSameDexMapFound) {
+        // Entries with the same dex map will have the same offset.
+        size += ComputeDexRegisterMapSize(stack_maps_.Get(i));
+      }
     }
     return size;
   }
@@ -161,11 +168,11 @@
       + (number_of_stack_maps_with_inline_info_ * InlineInfo::kFixedSize);
   }
 
-  size_t ComputeDexRegisterMapsStart() const {
+  size_t ComputeDexRegisterMapsStart() {
     return CodeInfo::kFixedSize + ComputeStackMapsSize();
   }
 
-  size_t ComputeInlineInfoStart() const {
+  size_t ComputeInlineInfoStart() {
     return ComputeDexRegisterMapsStart() + ComputeDexRegisterMapsSize();
   }
 
@@ -206,38 +213,47 @@
         stack_map.SetStackMask(code_info, *entry.sp_mask);
       }
 
-      if (entry.num_dex_registers != 0) {
-        // Set the Dex register map.
-        MemoryRegion register_region =
-            dex_register_locations_region.Subregion(
-                next_dex_register_map_offset,
-                ComputeDexRegisterMapSize(entry));
-        next_dex_register_map_offset += register_region.size();
-        DexRegisterMap dex_register_map(register_region);
-        stack_map.SetDexRegisterMapOffset(
+      if (entry.num_dex_registers == 0) {
+        // No dex map available.
+        stack_map.SetDexRegisterMapOffset(code_info, StackMap::kNoDexRegisterMap);
+      } else {
+        // Search for an entry with the same dex map.
+        size_t entry_with_same_map = FindEntryWithTheSameDexMap(i);
+        if (entry_with_same_map != kNoSameDexMapFound) {
+          // If we have a hit reuse the offset.
+          stack_map.SetDexRegisterMapOffset(code_info,
+              code_info.GetStackMapAt(entry_with_same_map).GetDexRegisterMapOffset(code_info));
+        } else {
+          // New dex registers maps should be added to the stack map.
+          MemoryRegion register_region =
+              dex_register_locations_region.Subregion(
+                  next_dex_register_map_offset,
+                  ComputeDexRegisterMapSize(entry));
+          next_dex_register_map_offset += register_region.size();
+          DexRegisterMap dex_register_map(register_region);
+          stack_map.SetDexRegisterMapOffset(
             code_info, register_region.start() - dex_register_locations_region.start());
 
-        // Offset in `dex_register_map` where to store the next register entry.
-        size_t offset = DexRegisterMap::kFixedSize;
-        dex_register_map.SetLiveBitMask(offset,
-                                        entry.num_dex_registers,
-                                        *entry.live_dex_registers_mask);
-        offset += DexRegisterMap::LiveBitMaskSize(entry.num_dex_registers);
-        for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
-             dex_register_number < entry.num_dex_registers;
-             ++dex_register_number) {
-          if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
-            DexRegisterLocation dex_register_location = dex_register_locations_.Get(
-                entry.dex_register_locations_start_index + index_in_dex_register_locations);
-            dex_register_map.SetRegisterInfo(offset, dex_register_location);
-            offset += DexRegisterMap::EntrySize(dex_register_location);
-            ++index_in_dex_register_locations;
+          // Offset in `dex_register_map` where to store the next register entry.
+          size_t offset = DexRegisterMap::kFixedSize;
+          dex_register_map.SetLiveBitMask(offset,
+                                          entry.num_dex_registers,
+                                          *entry.live_dex_registers_mask);
+          offset += DexRegisterMap::LiveBitMaskSize(entry.num_dex_registers);
+          for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
+               dex_register_number < entry.num_dex_registers;
+               ++dex_register_number) {
+            if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
+              DexRegisterLocation dex_register_location = dex_register_locations_.Get(
+                  entry.dex_register_locations_start_index + index_in_dex_register_locations);
+              dex_register_map.SetRegisterInfo(offset, dex_register_location);
+              offset += DexRegisterMap::EntrySize(dex_register_location);
+              ++index_in_dex_register_locations;
+            }
           }
+          // Ensure we reached the end of the Dex registers region.
+          DCHECK_EQ(offset, register_region.size());
         }
-        // Ensure we reached the end of the Dex registers region.
-        DCHECK_EQ(offset, register_region.size());
-      } else {
-        stack_map.SetDexRegisterMapOffset(code_info, StackMap::kNoDexRegisterMap);
       }
 
       // Set the inlining info.
@@ -271,11 +287,86 @@
       DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
           << DexRegisterLocation::PrettyDescriptor(kind);
       dex_register_locations_.Add(DexRegisterLocation(kind, value));
-      stack_maps_.Get(stack_maps_.Size() - 1).live_dex_registers_mask->SetBit(dex_register);
+      StackMapEntry entry = stack_maps_.Get(stack_maps_.Size() - 1);
+      entry.live_dex_registers_mask->SetBit(dex_register);
+      entry.dex_register_map_hash += (1 << dex_register);
+      entry.dex_register_map_hash += static_cast<uint32_t>(value);
+      entry.dex_register_map_hash += static_cast<uint32_t>(kind);
+      stack_maps_.Put(stack_maps_.Size() - 1, entry);
     }
   }
 
  private:
+  // Returns the index of an entry with the same dex register map
+  // or kNoSameDexMapFound if no such entry exists.
+  size_t FindEntryWithTheSameDexMap(size_t entry_index) {
+    StackMapEntry entry = stack_maps_.Get(entry_index);
+    auto entries_it = dex_map_hash_to_stack_map_indices_.find(entry.dex_register_map_hash);
+    if (entries_it == dex_map_hash_to_stack_map_indices_.end()) {
+      // We don't have a perfect hash functions so we need a list to collect all stack maps
+      // which might have the same dex register map.
+      GrowableArray<uint32_t> stack_map_indices(allocator_, 1);
+      stack_map_indices.Add(entry_index);
+      dex_map_hash_to_stack_map_indices_.Put(entry.dex_register_map_hash, stack_map_indices);
+      return kNoSameDexMapFound;
+    }
+
+    // TODO: We don't need to add ourselves to the map if we can guarantee that
+    // FindEntryWithTheSameDexMap is called just once per stack map entry.
+    // A good way to do this is to cache the offset in the stack map entry. This
+    // is easier to do if we add markers when the stack map constructions begins
+    // and when it ends.
+
+    // We might have collisions, so we need to check whether or not we should
+    // add the entry to the map. `needs_to_be_added` keeps track of this.
+    bool needs_to_be_added = true;
+    size_t result = kNoSameDexMapFound;
+    for (size_t i = 0; i < entries_it->second.Size(); i++) {
+      size_t test_entry_index = entries_it->second.Get(i);
+      if (test_entry_index == entry_index) {
+        needs_to_be_added = false;
+      } else if (HaveTheSameDexMaps(stack_maps_.Get(test_entry_index), entry)) {
+        result = test_entry_index;
+        needs_to_be_added = false;
+        break;
+      }
+    }
+    if (needs_to_be_added) {
+      entries_it->second.Add(entry_index);
+    }
+    return result;
+  }
+
+  bool HaveTheSameDexMaps(const StackMapEntry& a, const StackMapEntry& b) const {
+    if (a.live_dex_registers_mask == nullptr && b.live_dex_registers_mask == nullptr) {
+      return true;
+    }
+    if (a.live_dex_registers_mask == nullptr || b.live_dex_registers_mask == nullptr) {
+      return false;
+    }
+    if (a.num_dex_registers != b.num_dex_registers) {
+      return false;
+    }
+
+    int index_in_dex_register_locations = 0;
+    for (uint32_t i = 0; i < a.num_dex_registers; i++) {
+      if (a.live_dex_registers_mask->IsBitSet(i) != b.live_dex_registers_mask->IsBitSet(i)) {
+        return false;
+      }
+      if (a.live_dex_registers_mask->IsBitSet(i)) {
+        DexRegisterLocation a_loc = dex_register_locations_.Get(
+            a.dex_register_locations_start_index + index_in_dex_register_locations);
+        DexRegisterLocation b_loc = dex_register_locations_.Get(
+            b.dex_register_locations_start_index + index_in_dex_register_locations);
+        if (a_loc != b_loc) {
+          return false;
+        }
+        ++index_in_dex_register_locations;
+      }
+    }
+    return true;
+  }
+
   ArenaAllocator* allocator_;
   GrowableArray<StackMapEntry> stack_maps_;
   GrowableArray<DexRegisterLocation> dex_register_locations_;
@@ -285,6 +376,10 @@
   uint32_t native_pc_offset_max_;
   size_t number_of_stack_maps_with_inline_info_;
 
+  ArenaSafeMap<uint32_t, GrowableArray<uint32_t>> dex_map_hash_to_stack_map_indices_;
+
+  static constexpr uint32_t kNoSameDexMapFound = -1;
+
   ART_FRIEND_TEST(StackMapTest, Test1);
   ART_FRIEND_TEST(StackMapTest, Test2);
   ART_FRIEND_TEST(StackMapTest, TestNonLiveDexRegisters);
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index e7075c0..e5a9790 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -231,4 +231,54 @@
   ASSERT_EQ(stack_map.GetDexRegisterMapOffset(code_info), StackMap::kNoDexRegisterMapSmallEncoding);
 }
 
+TEST(StackMapTest, TestShareDexRegisterMap) {
+  ArenaPool pool;
+  ArenaAllocator arena(&pool);
+  StackMapStream stream(&arena);
+
+  ArenaBitVector sp_mask(&arena, 0, false);
+  uint32_t number_of_dex_registers = 2;
+  // First stack map.
+  stream.AddStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
+  stream.AddDexRegisterEntry(0, DexRegisterLocation::Kind::kInRegister, 0);
+  stream.AddDexRegisterEntry(1, DexRegisterLocation::Kind::kConstant, -2);
+  // Second stack map, which should share the same dex register map.
+  stream.AddStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
+  stream.AddDexRegisterEntry(0, DexRegisterLocation::Kind::kInRegister, 0);
+  stream.AddDexRegisterEntry(1, DexRegisterLocation::Kind::kConstant, -2);
+  // Third stack map (doesn't share the dex register map).
+  stream.AddStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
+  stream.AddDexRegisterEntry(0, DexRegisterLocation::Kind::kInRegister, 2);
+  stream.AddDexRegisterEntry(1, DexRegisterLocation::Kind::kConstant, -2);
+
+  size_t size = stream.ComputeNeededSize();
+  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  MemoryRegion region(memory, size);
+  stream.FillIn(region);
+
+  CodeInfo ci(region);
+  // Verify first stack map.
+  StackMap sm0 = ci.GetStackMapAt(0);
+  DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, number_of_dex_registers);
+  ASSERT_EQ(0, dex_registers0.GetMachineRegister(0, number_of_dex_registers));
+  ASSERT_EQ(-2, dex_registers0.GetConstant(1, number_of_dex_registers));
+
+  // Verify second stack map.
+  StackMap sm1 = ci.GetStackMapAt(1);
+  DexRegisterMap dex_registers1 = ci.GetDexRegisterMapOf(sm1, number_of_dex_registers);
+  ASSERT_EQ(0, dex_registers1.GetMachineRegister(0, number_of_dex_registers));
+  ASSERT_EQ(-2, dex_registers1.GetConstant(1, number_of_dex_registers));
+
+  // Verify third stack map.
+  StackMap sm2 = ci.GetStackMapAt(2);
+  DexRegisterMap dex_registers2 = ci.GetDexRegisterMapOf(sm2, number_of_dex_registers);
+  ASSERT_EQ(2, dex_registers2.GetMachineRegister(0, number_of_dex_registers));
+  ASSERT_EQ(-2, dex_registers2.GetConstant(1, number_of_dex_registers));
+
+  // Verify dex register map offsets.
+  ASSERT_EQ(sm0.GetDexRegisterMapOffset(ci), sm1.GetDexRegisterMapOffset(ci));
+  ASSERT_NE(sm0.GetDexRegisterMapOffset(ci), sm2.GetDexRegisterMapOffset(ci));
+  ASSERT_NE(sm1.GetDexRegisterMapOffset(ci), sm2.GetDexRegisterMapOffset(ci));
+}
+
 }  // namespace art
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index 8730f52..dd0dba2 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -100,6 +100,10 @@
     return rm_;
   }
 
+  Register GetSecondRegister() const {
+    return rs_;
+  }
+
   enum Type {
     kUnknown = -1,
     kRegister,
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 6d0571e..a894319 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -825,10 +825,12 @@
   if (so.IsImmediate()) {
     // Check special cases.
     if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) {
-      if (opcode == SUB) {
-        thumb_opcode = 5U /* 0b0101 */;
-      } else {
-        thumb_opcode = 0;
+      if (!set_cc) {
+        if (opcode == SUB) {
+          thumb_opcode = 5U;
+        } else if (opcode == ADD) {
+          thumb_opcode = 0U;
+        }
       }
       uint32_t imm = so.GetImmediate();
 
@@ -836,13 +838,14 @@
       uint32_t imm3 = (imm >> 8) & 7U /* 0b111 */;
       uint32_t imm8 = imm & 0xff;
 
-      encoding = B31 | B30 | B29 | B28 | B25 |
-           thumb_opcode << 21 |
-           rn << 16 |
-           rd << 8 |
-           i << 26 |
-           imm3 << 12 |
-           imm8;
+      encoding = B31 | B30 | B29 | B28 |
+          (set_cc ? B20 : B25) |
+          thumb_opcode << 21 |
+          rn << 16 |
+          rd << 8 |
+          i << 26 |
+          imm3 << 12 |
+          imm8;
     } else {
       // Modified immediate.
       uint32_t imm = ModifiedImmediate(so.encodingThumb());
@@ -852,19 +855,19 @@
       }
       encoding = B31 | B30 | B29 | B28 |
           thumb_opcode << 21 |
-          (set_cc ? 1 : 0) << 20 |
+          (set_cc ? B20 : 0) |
           rn << 16 |
           rd << 8 |
           imm;
     }
   } else if (so.IsRegister()) {
-     // Register (possibly shifted)
-     encoding = B31 | B30 | B29 | B27 | B25 |
-         thumb_opcode << 21 |
-         (set_cc ? 1 : 0) << 20 |
-         rn << 16 |
-         rd << 8 |
-         so.encodingThumb();
+    // Register (possibly shifted)
+    encoding = B31 | B30 | B29 | B27 | B25 |
+        thumb_opcode << 21 |
+        (set_cc ? B20 : 0) |
+        rn << 16 |
+        rd << 8 |
+        so.encodingThumb();
   }
   Emit32(encoding);
 }
@@ -921,6 +924,8 @@
       use_immediate = true;
       immediate = so.GetImmediate();
     } else {
+      CHECK(!(so.IsRegister() && so.IsShift() && so.GetSecondRegister() != kNoRegister))
+          << "No register-shifted register instruction available in thumb";
       // Adjust rn and rd: only two registers will be emitted.
       switch (opcode) {
         case AND:
diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc
index ebea9d4..813996b 100644
--- a/compiler/utils/arm/assembler_thumb2_test.cc
+++ b/compiler/utils/arm/assembler_thumb2_test.cc
@@ -227,4 +227,24 @@
   DriverStr(expected, "abs");
 }
 
+TEST_F(AssemblerThumb2Test, sub) {
+  __ subs(arm::R1, arm::R0, arm::ShifterOperand(42));
+  __ sub(arm::R1, arm::R0, arm::ShifterOperand(42));
+
+  const char* expected =
+      "subs r1, r0, #42\n"
+      "subw r1, r0, #42\n";
+  DriverStr(expected, "sub");
+}
+
+TEST_F(AssemblerThumb2Test, add) {
+  __ adds(arm::R1, arm::R0, arm::ShifterOperand(42));
+  __ add(arm::R1, arm::R0, arm::ShifterOperand(42));
+
+  const char* expected =
+      "adds r1, r0, #42\n"
+      "addw r1, r0, #42\n";
+  DriverStr(expected, "add");
+}
+
 }  // namespace art
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 14bcd4b..daca971 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1453,7 +1453,9 @@
     std::string error_msg;
     const OatFile* oat_file = class_linker->FindOpenedOatFileFromOatLocation(oat_location);
     if (oat_file == nullptr) {
-      oat_file = OatFile::Open(oat_location, oat_location, nullptr, nullptr, false, &error_msg);
+      oat_file = OatFile::Open(oat_location, oat_location,
+                               nullptr, nullptr, false, nullptr,
+                               &error_msg);
       if (oat_file == nullptr) {
         os << "NOT FOUND: " << error_msg << "\n";
         return false;
@@ -2193,7 +2195,7 @@
                    std::ostream* os) {
   std::string error_msg;
   OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false,
-                                    &error_msg);
+                                    nullptr, &error_msg);
   if (oat_file == nullptr) {
     fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
     return EXIT_FAILURE;
@@ -2209,7 +2211,7 @@
 static int SymbolizeOat(const char* oat_filename, std::string& output_name) {
   std::string error_msg;
   OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false,
-                                    &error_msg);
+                                    nullptr, &error_msg);
   if (oat_file == nullptr) {
     fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
     return EXIT_FAILURE;
diff --git a/runtime/base/arena_containers.h b/runtime/base/arena_containers.h
index ceff6e8..e6fe6c0 100644
--- a/runtime/base/arena_containers.h
+++ b/runtime/base/arena_containers.h
@@ -85,8 +85,7 @@
 typedef ArenaAllocatorAdapterKindImpl<kArenaAllocatorCountAllocations> ArenaAllocatorAdapterKind;
 
 template <>
-class ArenaAllocatorAdapter<void>
-    : private DebugStackReference, private ArenaAllocatorAdapterKind {
+class ArenaAllocatorAdapter<void> : private ArenaAllocatorAdapterKind {
  public:
   typedef void value_type;
   typedef void* pointer;
@@ -99,14 +98,12 @@
 
   explicit ArenaAllocatorAdapter(ArenaAllocator* arena_allocator,
                                  ArenaAllocKind kind = kArenaAllocSTL)
-      : DebugStackReference(arena_allocator),
-        ArenaAllocatorAdapterKind(kind),
+      : ArenaAllocatorAdapterKind(kind),
         arena_allocator_(arena_allocator) {
   }
   template <typename U>
   ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other)
-      : DebugStackReference(other),
-        ArenaAllocatorAdapterKind(other),
+      : ArenaAllocatorAdapterKind(other),
         arena_allocator_(other.arena_allocator_) {
   }
   ArenaAllocatorAdapter(const ArenaAllocatorAdapter&) = default;
@@ -121,7 +118,7 @@
 };
 
 template <typename T>
-class ArenaAllocatorAdapter : private DebugStackReference, private ArenaAllocatorAdapterKind {
+class ArenaAllocatorAdapter : private ArenaAllocatorAdapterKind {
  public:
   typedef T value_type;
   typedef T* pointer;
@@ -137,14 +134,12 @@
   };
 
   explicit ArenaAllocatorAdapter(ArenaAllocator* arena_allocator, ArenaAllocKind kind)
-      : DebugStackReference(arena_allocator),
-        ArenaAllocatorAdapterKind(kind),
+      : ArenaAllocatorAdapterKind(kind),
         arena_allocator_(arena_allocator) {
   }
   template <typename U>
   ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other)
-      : DebugStackReference(other),
-        ArenaAllocatorAdapterKind(other),
+      : ArenaAllocatorAdapterKind(other),
         arena_allocator_(other.arena_allocator_) {
   }
   ArenaAllocatorAdapter(const ArenaAllocatorAdapter&) = default;
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index c8ede48..da39573 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -421,15 +421,26 @@
     }
   }
 
-  std::string GetBaseLocation() const {
-    size_t pos = location_.rfind(kMultiDexSeparator);
+  static std::string GetBaseLocation(const std::string& location) {
+    return GetBaseLocation(location.c_str());
+  }
+
+  // Returns the ':classes*.dex' part of the dex location. Returns an empty
+  // string if there is no multidex suffix for the given location.
+  // The kMultiDexSeparator is included in the returned suffix.
+  static std::string GetMultiDexSuffix(const std::string& location) {
+    size_t pos = location.rfind(kMultiDexSeparator);
     if (pos == std::string::npos) {
-      return location_;
+      return "";
     } else {
-      return location_.substr(0, pos);
+      return location.substr(pos);
     }
   }
 
+  std::string GetBaseLocation() const {
+    return GetBaseLocation(location_);
+  }
+
   // For DexFiles directly from .dex files, this is the checksum from the DexFile::Header.
   // For DexFiles opened from a zip files, this will be the ZipEntry CRC32 of classes.dex.
   uint32_t GetLocationChecksum() const {
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 7f5a181..09ef3ee 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -377,4 +377,13 @@
   ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
 }
 
+TEST(DexFileUtilsTest, GetBaseLocationAndMultiDexSuffix) {
+  EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar"));
+  EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes2.dex"));
+  EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes8.dex"));
+  EXPECT_EQ("", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar"));
+  EXPECT_EQ(":classes2.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes2.dex"));
+  EXPECT_EQ(":classes8.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes8.dex"));
+}
+
 }  // namespace art
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 14f770d..1fb3252 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -788,7 +788,8 @@
 
   OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, image_header.GetOatDataBegin(),
                                     image_header.GetOatFileBegin(),
-                                    !Runtime::Current()->IsAotCompiler(), error_msg);
+                                    !Runtime::Current()->IsAotCompiler(),
+                                    nullptr, error_msg);
   if (oat_file == NULL) {
     *error_msg = StringPrintf("Failed to open oat file '%s' referenced from image %s: %s",
                               oat_filename.c_str(), GetName(), error_msg->c_str());
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 356e3d2..69cb22d 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -17,10 +17,11 @@
 #include "oat_file.h"
 
 #include <dlfcn.h>
-#include <sstream>
 #include <string.h>
 #include <unistd.h>
 
+#include <sstream>
+
 #include "base/bit_vector.h"
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
@@ -38,12 +39,33 @@
 
 namespace art {
 
+std::string OatFile::ResolveRelativeEncodedDexLocation(
+      const char* abs_dex_location, const std::string& rel_dex_location) {
+  if (abs_dex_location != nullptr && rel_dex_location[0] != '/') {
+    // Strip :classes<N>.dex used for secondary multidex files.
+    std::string base = DexFile::GetBaseLocation(rel_dex_location);
+    std::string multidex_suffix = DexFile::GetMultiDexSuffix(rel_dex_location);
+
+    // Check if the base is a suffix of the provided abs_dex_location.
+    std::string target_suffix = "/" + base;
+    std::string abs_location(abs_dex_location);
+    if (abs_location.size() > target_suffix.size()) {
+      size_t pos = abs_location.size() - target_suffix.size();
+      if (abs_location.compare(pos, std::string::npos, target_suffix) == 0) {
+        return abs_location + multidex_suffix;
+      }
+    }
+  }
+  return rel_dex_location;
+}
+
 void OatFile::CheckLocation(const std::string& location) {
   CHECK(!location.empty());
 }
 
 OatFile* OatFile::OpenWithElfFile(ElfFile* elf_file,
                                   const std::string& location,
+                                  const char* abs_dex_location,
                                   std::string* error_msg) {
   std::unique_ptr<OatFile> oat_file(new OatFile(location, false));
   oat_file->elf_file_.reset(elf_file);
@@ -53,7 +75,7 @@
   oat_file->begin_ = elf_file->Begin() + offset;
   oat_file->end_ = elf_file->Begin() + size + offset;
   // Ignore the optional .bss section when opening non-executable.
-  return oat_file->Setup(error_msg) ? oat_file.release() : nullptr;
+  return oat_file->Setup(abs_dex_location, error_msg) ? oat_file.release() : nullptr;
 }
 
 OatFile* OatFile::Open(const std::string& filename,
@@ -61,6 +83,7 @@
                        uint8_t* requested_base,
                        uint8_t* oat_file_begin,
                        bool executable,
+                       const char* abs_dex_location,
                        std::string* error_msg) {
   CHECK(!filename.empty()) << location;
   CheckLocation(location);
@@ -80,7 +103,7 @@
     return nullptr;
   }
   ret.reset(OpenElfFile(file.get(), location, requested_base, oat_file_begin, false, executable,
-                        error_msg));
+                        abs_dex_location, error_msg));
 
   // It would be nice to unlink here. But we might have opened the file created by the
   // ScopedLock, which we better not delete to avoid races. TODO: Investigate how to fix the API
@@ -88,14 +111,18 @@
   return ret.release();
 }
 
-OatFile* OatFile::OpenWritable(File* file, const std::string& location, std::string* error_msg) {
+OatFile* OatFile::OpenWritable(File* file, const std::string& location,
+                               const char* abs_dex_location,
+                               std::string* error_msg) {
   CheckLocation(location);
-  return OpenElfFile(file, location, nullptr, nullptr, true, false, error_msg);
+  return OpenElfFile(file, location, nullptr, nullptr, true, false, abs_dex_location, error_msg);
 }
 
-OatFile* OatFile::OpenReadable(File* file, const std::string& location, std::string* error_msg) {
+OatFile* OatFile::OpenReadable(File* file, const std::string& location,
+                               const char* abs_dex_location,
+                               std::string* error_msg) {
   CheckLocation(location);
-  return OpenElfFile(file, location, nullptr, nullptr, false, false, error_msg);
+  return OpenElfFile(file, location, nullptr, nullptr, false, false, abs_dex_location, error_msg);
 }
 
 OatFile* OatFile::OpenElfFile(File* file,
@@ -104,10 +131,11 @@
                               uint8_t* oat_file_begin,
                               bool writable,
                               bool executable,
+                              const char* abs_dex_location,
                               std::string* error_msg) {
   std::unique_ptr<OatFile> oat_file(new OatFile(location, executable));
   bool success = oat_file->ElfFileOpen(file, requested_base, oat_file_begin, writable, executable,
-                                       error_msg);
+                                       abs_dex_location, error_msg);
   if (!success) {
     CHECK(!error_msg->empty());
     return nullptr;
@@ -131,6 +159,7 @@
 
 bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file_begin,
                           bool writable, bool executable,
+                          const char* abs_dex_location,
                           std::string* error_msg) {
   // TODO: rename requested_base to oat_data_begin
   elf_file_.reset(ElfFile::Open(file, writable, /*program_header_only*/true, error_msg,
@@ -180,10 +209,10 @@
     bss_end_ += sizeof(uint32_t);
   }
 
-  return Setup(error_msg);
+  return Setup(abs_dex_location, error_msg);
 }
 
-bool OatFile::Setup(std::string* error_msg) {
+bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) {
   if (!GetOatHeader().IsValid()) {
     std::string cause = GetOatHeader().GetValidationErrorMessage();
     *error_msg = StringPrintf("Invalid oat header for '%s': %s", GetLocation().c_str(),
@@ -230,7 +259,9 @@
       return false;
     }
 
-    std::string dex_file_location(dex_file_location_data, dex_file_location_size);
+    std::string dex_file_location = ResolveRelativeEncodedDexLocation(
+        abs_dex_location,
+        std::string(dex_file_location_data, dex_file_location_size));
 
     uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat);
     oat += sizeof(dex_file_checksum);
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 564185c..51952f3 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -43,14 +43,18 @@
   // Opens an oat file contained within the given elf file. This is always opened as
   // non-executable at the moment.
   static OatFile* OpenWithElfFile(ElfFile* elf_file, const std::string& location,
+                                  const char* abs_dex_location,
                                   std::string* error_msg);
   // Open an oat file. Returns NULL on failure.  Requested base can
   // optionally be used to request where the file should be loaded.
+  // See the ResolveRelativeEncodedDexLocation for a description of how the
+  // abs_dex_location argument is used.
   static OatFile* Open(const std::string& filename,
                        const std::string& location,
                        uint8_t* requested_base,
                        uint8_t* oat_file_begin,
                        bool executable,
+                       const char* abs_dex_location,
                        std::string* error_msg);
 
   // Open an oat file from an already opened File.
@@ -58,9 +62,13 @@
   // where relocations may be required. Currently used from
   // ImageWriter which wants to open a writable version from an existing
   // file descriptor for patching.
-  static OatFile* OpenWritable(File* file, const std::string& location, std::string* error_msg);
+  static OatFile* OpenWritable(File* file, const std::string& location,
+                               const char* abs_dex_location,
+                               std::string* error_msg);
   // Opens an oat file from an already opened File. Maps it PROT_READ, MAP_PRIVATE.
-  static OatFile* OpenReadable(File* file, const std::string& location, std::string* error_msg);
+  static OatFile* OpenReadable(File* file, const std::string& location,
+                               const char* abs_dex_location,
+                               std::string* error_msg);
 
   ~OatFile();
 
@@ -279,6 +287,18 @@
   const uint8_t* BssBegin() const;
   const uint8_t* BssEnd() const;
 
+  // Returns the absolute dex location for the encoded relative dex location.
+  //
+  // If not nullptr, abs_dex_location is used to resolve the absolute dex
+  // location of relative dex locations encoded in the oat file.
+  // For example, given absolute location "/data/app/foo/base.apk", encoded
+  // dex locations "base.apk", "base.apk:classes2.dex", etc. would be resolved
+  // to "/data/app/foo/base.apk", "/data/app/foo/base.apk:classes2.dex", etc.
+  // Relative encoded dex locations that don't match the given abs_dex_location
+  // are left unchanged.
+  static std::string ResolveRelativeEncodedDexLocation(
+      const char* abs_dex_location, const std::string& rel_dex_location);
+
  private:
   static void CheckLocation(const std::string& location);
 
@@ -288,14 +308,17 @@
                               uint8_t* oat_file_begin,  // Override base if not null
                               bool writable,
                               bool executable,
+                              const char* abs_dex_location,
                               std::string* error_msg);
 
   explicit OatFile(const std::string& filename, bool executable);
   bool ElfFileOpen(File* file, uint8_t* requested_base,
                    uint8_t* oat_file_begin,  // Override where the file is loaded to if not null
                    bool writable, bool executable,
+                   const char* abs_dex_location,
                    std::string* error_msg);
-  bool Setup(std::string* error_msg);
+
+  bool Setup(const char* abs_dex_location, std::string* error_msg);
 
   // The oat file name.
   //
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index f87fa4f..d92f59b 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -737,18 +737,19 @@
   CHECK(error_msg != nullptr);
 
   // The odex file name is formed by replacing the dex_location extension with
-  // .odex and inserting an isa directory. For example:
+  // .odex and inserting an oat/<isa> directory. For example:
   //   location = /foo/bar/baz.jar
-  //   odex_location = /foo/bar/<isa>/baz.odex
+  //   odex_location = /foo/bar/oat/<isa>/baz.odex
 
-  // Find the directory portion of the dex location and add the isa directory.
+  // Find the directory portion of the dex location and add the oat/<isa>
+  // directory.
   size_t pos = location.rfind('/');
   if (pos == std::string::npos) {
     *error_msg = "Dex location " + location + " has no directory.";
     return false;
   }
   std::string dir = location.substr(0, pos+1);
-  dir += std::string(GetInstructionSetString(isa));
+  dir += "oat/" + std::string(GetInstructionSetString(isa));
 
   // Find the file portion of the dex location.
   std::string file;
@@ -850,7 +851,7 @@
       std::string error_msg;
       cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(),
             odex_file_name.c_str(), nullptr, nullptr, load_executable_,
-            &error_msg));
+            dex_location_, &error_msg));
       if (cached_odex_file_.get() == nullptr) {
         VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file "
           << odex_file_name << ": " << error_msg;
@@ -875,7 +876,8 @@
       const std::string& oat_file_name = *OatFileName();
       std::string error_msg;
       cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(),
-            oat_file_name.c_str(), nullptr, nullptr, load_executable_, &error_msg));
+            oat_file_name.c_str(), nullptr, nullptr, load_executable_,
+            dex_location_, &error_msg));
       if (cached_oat_file_.get() == nullptr) {
         VLOG(oat) << "OatFileAssistant test for existing oat file "
           << oat_file_name << ": " << error_msg;
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 958b440..f2abcf9 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -151,11 +151,12 @@
   static std::vector<std::unique_ptr<const DexFile>> LoadDexFiles(
       const OatFile& oat_file, const char* dex_location);
 
-  // If the dex file has been pre-compiled on the host, the compiled oat file
-  // will have the extension .odex, and is referred to as the odex file.
-  // It is called odex for legacy reasons; the file is really an oat file. The
-  // odex file will typically have a patch delta of 0 and need to be relocated
-  // before use for the purposes of ASLR.
+  // If the dex file has been installed with a compiled oat file alongside
+  // it, the compiled oat file will have the extension .odex, and is referred
+  // to as the odex file. It is called odex for legacy reasons; the file is
+  // really an oat file. The odex file will often, but not always, have a
+  // patch delta of 0 and need to be relocated before use for the purposes of
+  // ASLR. The odex file is treated as if it were read-only.
   // These methods return the location and status of the odex file for the dex
   // location.
   // Notes:
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index be8652c..b2798d3 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -44,10 +44,13 @@
     scratch_dir_ = android_data_ + "/OatFileAssistantTest";
     ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700));
 
-    // Create a subdirectory in scratch for the current isa.
-    // This is the location that will be used for odex files in the tests.
-    isa_dir_ = scratch_dir_ + "/" + GetInstructionSetString(kRuntimeISA);
-    ASSERT_EQ(0, mkdir(isa_dir_.c_str(), 0700));
+    // Create a subdirectory in scratch for odex files.
+    odex_oat_dir_ = scratch_dir_ + "/oat";
+    ASSERT_EQ(0, mkdir(odex_oat_dir_.c_str(), 0700));
+
+    odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA));
+    ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700));
+
 
     // Verify the environment is as we expect
     uint32_t checksum;
@@ -90,8 +93,11 @@
   }
 
   virtual void TearDown() {
-    ClearDirectory(isa_dir_.c_str());
-    ASSERT_EQ(0, rmdir(isa_dir_.c_str()));
+    ClearDirectory(odex_dir_.c_str());
+    ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
+
+    ClearDirectory(odex_oat_dir_.c_str());
+    ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
 
     ClearDirectory(scratch_dir_.c_str());
     ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
@@ -153,10 +159,10 @@
     return scratch_dir_;
   }
 
-  // ISA directory is the subdirectory in the scratch directory where odex
+  // Odex directory is the subdirectory in the scratch directory where odex
   // files should be located.
-  std::string GetISADir() {
-    return isa_dir_;
+  std::string GetOdexDir() {
+    return odex_dir_;
   }
 
   // Generate an odex file for the purposes of test.
@@ -241,7 +247,8 @@
   }
 
   std::string scratch_dir_;
-  std::string isa_dir_;
+  std::string odex_oat_dir_;
+  std::string odex_dir_;
   std::vector<std::unique_ptr<MemMap>> image_reservation_;
 };
 
@@ -326,12 +333,43 @@
   GenerateOatForTest(dex_location.c_str());
 
   // Verify we can load both dex files.
-  OatFileAssistant executable_oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
-  std::unique_ptr<OatFile> oat_file = executable_oat_file_assistant.GetBestOatFile();
+  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
   ASSERT_TRUE(oat_file.get() != nullptr);
   EXPECT_TRUE(oat_file->IsExecutable());
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  dex_files = executable_oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
+  dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
+  EXPECT_EQ(2u, dex_files.size());
+}
+
+// Case: We have a MultiDEX file and up-to-date OAT file for it with relative
+// encoded dex locations.
+// Expect: The oat file status is kUpToDate.
+TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) {
+  std::string dex_location = GetScratchDir() + "/RelativeEncodedDexLocation.jar";
+  std::string oat_location = GetOdexDir() + "/RelativeEncodedDexLocation.oat";
+
+  // Create the dex file
+  Copy(GetMultiDexSrc1(), dex_location);
+
+  // Create the oat file with relative encoded dex location.
+  std::vector<std::string> args;
+  args.push_back("--dex-file=" + dex_location);
+  args.push_back("--dex-location=" + std::string("RelativeEncodedDexLocation.jar"));
+  args.push_back("--oat-file=" + oat_location);
+
+  std::string error_msg;
+  ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
+
+  // Verify we can load both dex files.
+  OatFileAssistant oat_file_assistant(dex_location.c_str(),
+                                      oat_location.c_str(),
+                                      kRuntimeISA, true);
+  std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
+  ASSERT_TRUE(oat_file.get() != nullptr);
+  EXPECT_TRUE(oat_file->IsExecutable());
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
+  dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
   EXPECT_EQ(2u, dex_files.size());
 }
 
@@ -362,7 +400,7 @@
 // Expect: The oat file status is kNeedsRelocation.
 TEST_F(OatFileAssistantTest, DexOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar";
-  std::string odex_location = GetISADir() + "/DexOdexNoOat.odex";
+  std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
 
   // Create the dex and odex files
   Copy(GetDexSrc1(), dex_location);
@@ -388,7 +426,7 @@
 // Expect: The oat file status is kNeedsRelocation.
 TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar";
-  std::string odex_location = GetISADir() + "/StrippedDexOdexNoOat.odex";
+  std::string odex_location = GetOdexDir() + "/StrippedDexOdexNoOat.odex";
 
   // Create the dex and odex files
   Copy(GetDexSrc1(), dex_location);
@@ -437,7 +475,7 @@
 // Expect: The oat file status is kNeedsRelocation.
 TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
   std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar";
-  std::string odex_location = GetISADir() + "/StrippedDexOdexOat.odex";
+  std::string odex_location = GetOdexDir() + "/StrippedDexOdexOat.odex";
 
   // Create the oat file from a different dex file so it looks out of date.
   Copy(GetDexSrc2(), dex_location);
@@ -494,8 +532,8 @@
 // Expect: It shouldn't crash.
 TEST_F(OatFileAssistantTest, OdexOatOverlap) {
   std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
-  std::string odex_location = GetISADir() + "/OdexOatOverlap.odex";
-  std::string oat_location = GetISADir() + "/OdexOatOverlap.oat";
+  std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex";
+  std::string oat_location = GetOdexDir() + "/OdexOatOverlap.oat";
 
   // Create the dex and odex files
   Copy(GetDexSrc1(), dex_location);
@@ -532,7 +570,7 @@
 // Expect: The oat file status is kUpToDate, because PIC needs no relocation.
 TEST_F(OatFileAssistantTest, DexPicOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/DexPicOdexNoOat.jar";
-  std::string odex_location = GetISADir() + "/DexPicOdexNoOat.odex";
+  std::string odex_location = GetOdexDir() + "/DexPicOdexNoOat.odex";
 
   // Create the dex and odex files
   Copy(GetDexSrc1(), dex_location);
@@ -772,7 +810,7 @@
 // avoid using up the virtual memory address space.
 TEST_F(OatFileAssistantTest, RaceToGenerate) {
   std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar";
-  std::string oat_location = GetISADir() + "/RaceToGenerate.oat";
+  std::string oat_location = GetOdexDir() + "/RaceToGenerate.oat";
 
   // We use the lib core dex file, because it's large, and hopefully should
   // take a while to generate.
@@ -802,7 +840,7 @@
 // Expect: We should load the odex file non-executable.
 TEST_F(OatFileAssistantNoDex2OatTest, LoadDexOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
-  std::string odex_location = GetISADir() + "/LoadDexOdexNoOat.odex";
+  std::string odex_location = GetOdexDir() + "/LoadDexOdexNoOat.odex";
 
   // Create the dex and odex files
   Copy(GetDexSrc1(), dex_location);
@@ -824,7 +862,7 @@
 // Expect: We should load the odex file non-executable.
 TEST_F(OatFileAssistantNoDex2OatTest, LoadMultiDexOdexNoOat) {
   std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
-  std::string odex_location = GetISADir() + "/LoadMultiDexOdexNoOat.odex";
+  std::string odex_location = GetOdexDir() + "/LoadMultiDexOdexNoOat.odex";
 
   // Create the dex and odex files
   Copy(GetMultiDexSrc1(), dex_location);
@@ -847,11 +885,11 @@
 
   EXPECT_TRUE(OatFileAssistant::DexFilenameToOdexFilename(
         "/foo/bar/baz.jar", kArm, &odex_file, &error_msg)) << error_msg;
-  EXPECT_EQ("/foo/bar/arm/baz.odex", odex_file);
+  EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
 
   EXPECT_TRUE(OatFileAssistant::DexFilenameToOdexFilename(
         "/foo/bar/baz.funnyext", kArm, &odex_file, &error_msg)) << error_msg;
-  EXPECT_EQ("/foo/bar/arm/baz.odex", odex_file);
+  EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
 
   EXPECT_FALSE(OatFileAssistant::DexFilenameToOdexFilename(
         "nopath.jar", kArm, &odex_file, &error_msg));
diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc
new file mode 100644
index 0000000..f2213e9
--- /dev/null
+++ b/runtime/oat_file_test.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "oat_file.h"
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(OatFileTest, ResolveRelativeEncodedDexLocation) {
+  EXPECT_EQ(std::string("/data/app/foo/base.apk"),
+      OatFile::ResolveRelativeEncodedDexLocation(
+        nullptr, "/data/app/foo/base.apk"));
+
+  EXPECT_EQ(std::string("/system/framework/base.apk"),
+      OatFile::ResolveRelativeEncodedDexLocation(
+        "/data/app/foo/base.apk", "/system/framework/base.apk"));
+
+  EXPECT_EQ(std::string("/data/app/foo/base.apk"),
+      OatFile::ResolveRelativeEncodedDexLocation(
+        "/data/app/foo/base.apk", "base.apk"));
+
+  EXPECT_EQ(std::string("/data/app/foo/base.apk"),
+      OatFile::ResolveRelativeEncodedDexLocation(
+        "/data/app/foo/base.apk", "foo/base.apk"));
+
+  EXPECT_EQ(std::string("/data/app/foo/base.apk:classes2.dex"),
+      OatFile::ResolveRelativeEncodedDexLocation(
+        "/data/app/foo/base.apk", "base.apk:classes2.dex"));
+
+  EXPECT_EQ(std::string("/data/app/foo/base.apk:classes11.dex"),
+      OatFile::ResolveRelativeEncodedDexLocation(
+        "/data/app/foo/base.apk", "base.apk:classes11.dex"));
+
+  EXPECT_EQ(std::string("base.apk"),
+      OatFile::ResolveRelativeEncodedDexLocation(
+        "/data/app/foo/sludge.apk", "base.apk"));
+
+  EXPECT_EQ(std::string("o/base.apk"),
+      OatFile::ResolveRelativeEncodedDexLocation(
+        "/data/app/foo/base.apk", "o/base.apk"));
+}
+
+}  // namespace art
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 2dacfe2..9ca00b1 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -688,7 +688,7 @@
     return false;
   }
   std::unique_ptr<OatFile> oat_file(OatFile::OpenWithElfFile(elf_file.release(), oat_location,
-                                                             &error_msg));
+                                                             nullptr, &error_msg));
   if (oat_file.get() == nullptr) {
     LOG(INFO) << "Unable to use '" << oat_filename << "' because " << error_msg;
     return false;
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 629fc9a..6ec7cc8 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -212,6 +212,14 @@
   // Get the actual kind of the location.
   Kind GetInternalKind() const { return kind_; }
 
+  bool operator==(DexRegisterLocation other) const {
+    return kind_ == other.kind_ && value_ == other.value_;
+  }
+
+  bool operator!=(DexRegisterLocation other) const {
+    return !(*this == other);
+  }
+
  private:
   Kind kind_;
   int32_t value_;
diff --git a/runtime/utils.h b/runtime/utils.h
index e20412e..1a7fdfb 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -110,6 +110,7 @@
 
 // Check whether an N-bit two's-complement representation can hold value.
 static inline bool IsInt(int N, intptr_t value) {
+  if (N == kBitsPerIntPtrT) return true;
   CHECK_LT(0, N);
   CHECK_LT(N, kBitsPerIntPtrT);
   intptr_t limit = static_cast<intptr_t>(1) << (N - 1);
diff --git a/test/462-checker-inlining-across-dex-files/expected.txt b/test/462-checker-inlining-across-dex-files/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/462-checker-inlining-across-dex-files/expected.txt
diff --git a/test/462-checker-inlining-across-dex-files/info.txt b/test/462-checker-inlining-across-dex-files/info.txt
new file mode 100644
index 0000000..57008c3
--- /dev/null
+++ b/test/462-checker-inlining-across-dex-files/info.txt
@@ -0,0 +1 @@
+Check our inlining heuristics across dex files in optimizing.
diff --git a/test/462-checker-inlining-across-dex-files/src-multidex/OtherDex.java b/test/462-checker-inlining-across-dex-files/src-multidex/OtherDex.java
new file mode 100644
index 0000000..cee8e0f
--- /dev/null
+++ b/test/462-checker-inlining-across-dex-files/src-multidex/OtherDex.java
@@ -0,0 +1,64 @@
+/*
+* 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 OtherDex {
+  public static void emptyMethod() {
+  }
+
+  public static int returnIntMethod() {
+    return 38;
+  }
+
+  public static int returnOtherDexStatic() {
+    return myStatic;
+  }
+
+  public static int returnMainStatic() {
+    return Main.myStatic;
+  }
+
+  public static int recursiveCall() {
+    return recursiveCall();
+  }
+
+  public static String returnString() {
+    return "OtherDex";
+  }
+
+  public static Class returnOtherDexClass() {
+    return OtherDex.class;
+  }
+
+  public static Class returnMainClass() {
+    return Main.class;
+  }
+
+  private static Class returnOtherDexClass2() {
+    return OtherDex.class;
+  }
+
+  public static Class returnOtherDexClassStaticCall() {
+    // Do not call returnOtherDexClass, as it may have been flagged
+    // as non-inlineable.
+    return returnOtherDexClass2();
+  }
+
+  public static Class returnOtherDexCallingMain() {
+    return Main.getOtherClass();
+  }
+
+  static int myStatic = 1;
+}
diff --git a/test/462-checker-inlining-across-dex-files/src/Main.java b/test/462-checker-inlining-across-dex-files/src/Main.java
new file mode 100644
index 0000000..d5563b8
--- /dev/null
+++ b/test/462-checker-inlining-across-dex-files/src/Main.java
@@ -0,0 +1,202 @@
+/*
+* 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.
+*/
+
+// Add a class that will be the first entry in the dex cache, to
+// avoid having the OtherDex and Main classes share the same cache index.
+class AAA {
+}
+
+public class Main {
+
+  // CHECK-START: void Main.inlineEmptyMethod() inliner (before)
+  // CHECK-DAG:     [[Invoke:v\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      ReturnVoid
+
+  // CHECK-START: void Main.inlineEmptyMethod() inliner (after)
+  // CHECK-NOT:                      InvokeStaticOrDirect
+
+  public static void inlineEmptyMethod() {
+    OtherDex.emptyMethod();
+  }
+
+  // CHECK-START: int Main.inlineReturnIntMethod() inliner (before)
+  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  // CHECK-START: int Main.inlineReturnIntMethod() inliner (after)
+  // CHECK-NOT:                      InvokeStaticOrDirect
+
+  // CHECK-START: int Main.inlineReturnIntMethod() inliner (after)
+  // CHECK-DAG:     [[Const38:i\d+]] IntConstant 38
+  // CHECK-DAG:                      Return [ [[Const38]] ]
+
+  public static int inlineReturnIntMethod() {
+    return OtherDex.returnIntMethod();
+  }
+
+  // CHECK-START: int Main.dontInlineOtherDexStatic() inliner (before)
+  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  // CHECK-START: int Main.dontInlineOtherDexStatic() inliner (after)
+  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  public static int dontInlineOtherDexStatic() {
+    return OtherDex.returnOtherDexStatic();
+  }
+
+  // CHECK-START: int Main.inlineMainStatic() inliner (before)
+  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  // CHECK-START: int Main.inlineMainStatic() inliner (after)
+  // CHECK-NOT:                      InvokeStaticOrDirect
+
+  // CHECK-START: int Main.inlineMainStatic() inliner (after)
+  // CHECK-DAG:     [[Static:i\d+]]  StaticFieldGet
+  // CHECK-DAG:                      Return [ [[Static]] ]
+
+  public static int inlineMainStatic() {
+    return OtherDex.returnMainStatic();
+  }
+
+  // CHECK-START: int Main.dontInlineRecursiveCall() inliner (before)
+  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  // CHECK-START: int Main.dontInlineRecursiveCall() inliner (after)
+  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  public static int dontInlineRecursiveCall() {
+    return OtherDex.recursiveCall();
+  }
+
+  // CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (before)
+  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  // CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (after)
+  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  public static String dontInlineReturnString() {
+    return OtherDex.returnString();
+  }
+
+  // CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (before)
+  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  // CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (after)
+  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  public static Class dontInlineOtherDexClass() {
+    return OtherDex.returnOtherDexClass();
+  }
+
+  // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (before)
+  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after)
+  // CHECK-NOT:                      InvokeStaticOrDirect
+
+  // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after)
+  // CHECK-DAG:     [[Class:l\d+]]  LoadClass
+  // CHECK-DAG:                     Return [ [[Class]] ]
+
+  public static Class inlineMainClass() {
+    return OtherDex.returnMainClass();
+  }
+
+  // CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (before)
+  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  // CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (after)
+  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  public static Class dontInlineOtherDexClassStaticCall() {
+    return OtherDex.returnOtherDexClassStaticCall();
+  }
+
+  // CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (before)
+  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  // CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (after)
+  // CHECK-NOT:                      InvokeStaticOrDirect
+
+  // CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (after)
+  // CHECK-DAG:     [[Class:l\d+]]  LoadClass
+  // CHECK-DAG:                     Return [ [[Class]] ]
+
+  public static Class inlineOtherDexCallingMain() {
+    return OtherDex.returnOtherDexCallingMain();
+  }
+
+  public static Class getOtherClass() {
+    return Main.class;
+  }
+
+  public static void main(String[] args) {
+    inlineEmptyMethod();
+    if (inlineReturnIntMethod() != 38) {
+      throw new Error("Expected 38");
+    }
+
+    if (dontInlineOtherDexStatic() != 1) {
+      throw new Error("Expected 1");
+    }
+
+    if (inlineMainStatic() != 42) {
+      throw new Error("Expected 42");
+    }
+
+    if (dontInlineReturnString() != "OtherDex") {
+      throw new Error("Expected OtherDex");
+    }
+
+    if (dontInlineOtherDexClass() != OtherDex.class) {
+      throw new Error("Expected " + OtherDex.class);
+    }
+
+    if (dontInlineOtherDexClassStaticCall() != OtherDex.class) {
+      throw new Error("Expected " + OtherDex.class);
+    }
+
+    if (inlineMainClass() != Main.class) {
+      throw new Error("Expected " + Main.class);
+    }
+
+    if (inlineOtherDexCallingMain() != Main.class) {
+      throw new Error("Expected " + Main.class);
+    }
+  }
+
+  // Reference the AAA class to ensure it is in the dex cache.
+  public static Class<?> cls = AAA.class;
+
+  // Add a field that will be the first entry in the dex cache, to
+  // avoid having the OtherDex.myStatic and Main.myStatic fields
+  // share the same cache index.
+  public static int aaa = 32;
+  public static int myStatic = 42;
+}
diff --git a/test/464-checker-inline-sharpen-calls/expected.txt b/test/464-checker-inline-sharpen-calls/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/464-checker-inline-sharpen-calls/expected.txt
diff --git a/test/464-checker-inline-sharpen-calls/info.txt b/test/464-checker-inline-sharpen-calls/info.txt
new file mode 100644
index 0000000..9e56030
--- /dev/null
+++ b/test/464-checker-inline-sharpen-calls/info.txt
@@ -0,0 +1 @@
+Check that we inline sharpen calls.
diff --git a/test/464-checker-inline-sharpen-calls/src/Main.java b/test/464-checker-inline-sharpen-calls/src/Main.java
new file mode 100644
index 0000000..1b25b42
--- /dev/null
+++ b/test/464-checker-inline-sharpen-calls/src/Main.java
@@ -0,0 +1,54 @@
+/*
+* 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 final class Main {
+
+  public void invokeVirtual() {
+  }
+
+  // CHECK-START: void Main.inlineSharpenInvokeVirtual(Main) inliner (before)
+  // CHECK-DAG:     [[Invoke:v\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      ReturnVoid
+
+  // CHECK-START: void Main.inlineSharpenInvokeVirtual(Main) inliner (after)
+  // CHECK-NOT:                      InvokeStaticOrDirect
+
+  public static void inlineSharpenInvokeVirtual(Main m) {
+    m.invokeVirtual();
+  }
+
+  // CHECK-START: int Main.inlineSharpenStringInvoke() inliner (before)
+  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      Return [ [[Invoke]] ]
+
+  // CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after)
+  // CHECK-NOT:                      InvokeStaticOrDirect
+
+  // CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after)
+  // CHECK-DAG:     [[Field:i\d+]]   InstanceFieldGet
+  // CHECK-DAG:                      Return [ [[Field]] ]
+
+  public static int inlineSharpenStringInvoke() {
+    return "Foo".length();
+  }
+
+  public static void main(String[] args) {
+    inlineSharpenInvokeVirtual(new Main());
+    if (inlineSharpenStringInvoke() != 3) {
+      throw new Error("Expected 3");
+    }
+  }
+}
diff --git a/test/etc/default-build b/test/etc/default-build
index 58c9564..fbe97f9 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -39,7 +39,7 @@
 fi
 
 mkdir classes
-${JAVAC} -d classes `find src -name '*.java'`
+${JAVAC} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'`
 
 if [ -d src2 ]; then
   ${JAVAC} -d classes `find src2 -name '*.java'`
@@ -72,6 +72,15 @@
   fi
 fi
 
-if [ ${NEED_DEX} = "true" ]; then
+# Create a single jar with two dex files for multidex.
+if [ -d src-multidex ]; then
+  mkdir classes2
+  ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'`
+  if [ ${NEED_DEX} = "true" ]; then
+    ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \
+      --dump-width=1000 ${DX_FLAGS} classes2
+    zip $TEST_NAME.jar classes.dex classes2.dex
+  fi
+elif [ ${NEED_DEX} = "true" ]; then
   zip $TEST_NAME.jar classes.dex
 fi
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index b87b2ff..30d99bb 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -74,7 +74,11 @@
   description: "Failing due to missing localhost on hammerhead and volantis.",
   result: EXEC_FAILED,
   modes: [device],
-  names: ["libcore.javax.crypto.CipherTest#testCipherInitWithCertificate"]
+  names: ["libcore.javax.crypto.CipherTest#testCipherInitWithCertificate",
+          "libcore.net.NetworkSecurityPolicyTest#testCleartextTrafficPolicyWithFtpURLConnection",
+          "libcore.net.NetworkSecurityPolicyTest#testCleartextTrafficPolicyWithJarFtpURLConnection",
+          "libcore.net.NetworkSecurityPolicyTest#testCleartextTrafficPolicyWithLoggingSocketHandler"
+         ]
 },
 {
   description: "Test timeouts",
diff --git a/tools/setup-buildbot-device.sh b/tools/setup-buildbot-device.sh
index fc396b6..7faf86e 100755
--- a/tools/setup-buildbot-device.sh
+++ b/tools/setup-buildbot-device.sh
@@ -24,5 +24,9 @@
 adb shell setenforce 0
 adb shell getenforce
 
+echo -e "${green}Setting local loopback${nc}"
+adb shell ifconfig lo up
+adb shell ifconfig
+
 echo -e "${green}List properties${nc}"
 adb shell getprop