Merge "Change the order of functions in .debug_frame to save space."
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index eec471e..dc53853 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -318,6 +318,10 @@
   art_cflags += -DART_READ_BARRIER_TYPE_IS_$(ART_READ_BARRIER_TYPE)=1
   art_asflags += -DART_USE_READ_BARRIER=1
   art_asflags += -DART_READ_BARRIER_TYPE_IS_$(ART_READ_BARRIER_TYPE)=1
+
+  # Temporarily override -fstack-protector-strong with -fstack-protector to avoid a major
+  # slowdown with the read barrier config. b/26744236.
+  art_cflags += -fstack-protector
 endif
 
 ifeq ($(ART_USE_TLAB),true)
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index fe83ba9..dc2c9c9 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -535,7 +535,7 @@
 
 /* -Xexperimental:_ */
 TEST_F(CmdlineParserTest, TestExperimentalFlags) {
-  // Off by default
+  // Default
   EXPECT_SINGLE_PARSE_DEFAULT_VALUE(ExperimentalFlags::kNone,
                                     "",
                                     M::Experimental);
@@ -549,16 +549,6 @@
   EXPECT_SINGLE_PARSE_VALUE(ExperimentalFlags::kLambdas,
                             "-Xexperimental:lambdas",
                             M::Experimental);
-  // Enabled explicitly
-  EXPECT_SINGLE_PARSE_VALUE(ExperimentalFlags::kDefaultMethods,
-                            "-Xexperimental:default-methods",
-                            M::Experimental);
-
-  // Enabled both
-  EXPECT_SINGLE_PARSE_VALUE(ExperimentalFlags::kDefaultMethods | ExperimentalFlags::kLambdas,
-                            "-Xexperimental:default-methods "
-                            "-Xexperimental:lambdas",
-                            M::Experimental);
 }
 
 // -Xverify:_
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 97c672c..740199d 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -847,11 +847,9 @@
 struct CmdlineType<ExperimentalFlags> : CmdlineTypeParser<ExperimentalFlags> {
   Result ParseAndAppend(const std::string& option, ExperimentalFlags& existing) {
     if (option == "none") {
-      existing = existing | ExperimentalFlags::kNone;
+      existing = ExperimentalFlags::kNone;
     } else if (option == "lambdas") {
       existing = existing | ExperimentalFlags::kLambdas;
-    } else if (option == "default-methods") {
-      existing = existing | ExperimentalFlags::kDefaultMethods;
     } else {
       return Result::Failure(std::string("Unknown option '") + option + "'");
     }
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 3766093..22b178c 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -37,13 +37,21 @@
 static constexpr bool kIntrinsicIsStatic[] = {
     true,   // kIntrinsicDoubleCvt
     true,   // kIntrinsicFloatCvt
+    true,   // kIntrinsicFloatIsInfinite
+    true,   // kIntrinsicDoubleIsInfinite
+    true,   // kIntrinsicFloatIsNaN
+    true,   // kIntrinsicDoubleIsNaN
     true,   // kIntrinsicReverseBits
     true,   // kIntrinsicReverseBytes
     true,   // kIntrinsicBitCount
+    true,   // kIntrinsicCompare,
+    true,   // kIntrinsicHighestOneBit
+    true,   // kIntrinsicLowestOneBit
     true,   // kIntrinsicNumberOfLeadingZeros
     true,   // kIntrinsicNumberOfTrailingZeros
     true,   // kIntrinsicRotateRight
     true,   // kIntrinsicRotateLeft
+    true,   // kIntrinsicSignum
     true,   // kIntrinsicAbsInt
     true,   // kIntrinsicAbsLong
     true,   // kIntrinsicAbsFloat
@@ -98,15 +106,23 @@
               "arraysize of kIntrinsicIsStatic unexpected");
 static_assert(kIntrinsicIsStatic[kIntrinsicDoubleCvt], "DoubleCvt must be static");
 static_assert(kIntrinsicIsStatic[kIntrinsicFloatCvt], "FloatCvt must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicFloatIsInfinite], "FloatIsInfinite must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicDoubleIsInfinite], "DoubleIsInfinite must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicFloatIsNaN], "FloatIsNaN must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicDoubleIsNaN], "DoubleIsNaN must be static");
 static_assert(kIntrinsicIsStatic[kIntrinsicReverseBits], "ReverseBits must be static");
 static_assert(kIntrinsicIsStatic[kIntrinsicReverseBytes], "ReverseBytes must be static");
 static_assert(kIntrinsicIsStatic[kIntrinsicBitCount], "BitCount must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicCompare], "Compare must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicHighestOneBit], "HighestOneBit must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicLowestOneBit], "LowestOneBit  must be static");
 static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfLeadingZeros],
               "NumberOfLeadingZeros must be static");
 static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfTrailingZeros],
               "NumberOfTrailingZeros must be static");
 static_assert(kIntrinsicIsStatic[kIntrinsicRotateRight], "RotateRight must be static");
 static_assert(kIntrinsicIsStatic[kIntrinsicRotateLeft], "RotateLeft must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicSignum], "Signum must be static");
 static_assert(kIntrinsicIsStatic[kIntrinsicAbsInt], "AbsInt must be static");
 static_assert(kIntrinsicIsStatic[kIntrinsicAbsLong], "AbsLong must be static");
 static_assert(kIntrinsicIsStatic[kIntrinsicAbsFloat], "AbsFloat must be static");
@@ -261,6 +277,8 @@
     "equals",                // kNameCacheEquals
     "getCharsNoCheck",       // kNameCacheGetCharsNoCheck
     "isEmpty",               // kNameCacheIsEmpty
+    "isInfinite",            // kNameCacheIsInfinite
+    "isNaN",                 // kNameCacheIsNaN
     "indexOf",               // kNameCacheIndexOf
     "length",                // kNameCacheLength
     "<init>",                // kNameCacheInit
@@ -296,10 +314,14 @@
     "putOrderedObject",      // kNameCachePutOrderedObject
     "arraycopy",             // kNameCacheArrayCopy
     "bitCount",              // kNameCacheBitCount
+    "compare",               // kNameCacheCompare
+    "highestOneBit",         // kNameCacheHighestOneBit
+    "lowestOneBit",          // kNameCacheLowestOneBit
     "numberOfLeadingZeros",  // kNameCacheNumberOfLeadingZeros
     "numberOfTrailingZeros",  // kNameCacheNumberOfTrailingZeros
     "rotateRight",           // kNameCacheRotateRight
     "rotateLeft",            // kNameCacheRotateLeft
+    "signum",                // kNameCacheSignum
 };
 
 const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
@@ -319,10 +341,14 @@
     { kClassCacheFloat, 2, { kClassCacheFloat, kClassCacheFloat } },
     // kProtoCacheD_J
     { kClassCacheLong, 1, { kClassCacheDouble } },
+    // kProtoCacheD_Z
+    { kClassCacheBoolean, 1, { kClassCacheDouble } },
     // kProtoCacheJ_D
     { kClassCacheDouble, 1, { kClassCacheLong } },
     // kProtoCacheF_I
     { kClassCacheInt, 1, { kClassCacheFloat } },
+    // kProtoCacheF_Z
+    { kClassCacheBoolean, 1, { kClassCacheFloat } },
     // kProtoCacheI_F
     { kClassCacheFloat, 1, { kClassCacheInt } },
     // kProtoCacheII_I
@@ -351,6 +377,8 @@
     { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } },
     // kProtoCacheJJ_J
     { kClassCacheLong, 2, { kClassCacheLong, kClassCacheLong } },
+    // kProtoCacheJJ_I
+    { kClassCacheInt, 2, { kClassCacheLong, kClassCacheLong } },
     // kProtoCacheJJ_V
     { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } },
     // kProtoCacheJS_V
@@ -444,6 +472,11 @@
     INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
     INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, kIntrinsicFlagToFloatingPoint),
 
+    INTRINSIC(JavaLangFloat, IsInfinite, F_Z, kIntrinsicFloatIsInfinite, 0),
+    INTRINSIC(JavaLangDouble, IsInfinite, D_Z, kIntrinsicDoubleIsInfinite, 0),
+    INTRINSIC(JavaLangFloat, IsNaN, F_Z, kIntrinsicFloatIsNaN, 0),
+    INTRINSIC(JavaLangDouble, IsNaN, D_Z, kIntrinsicDoubleIsNaN, 0),
+
     INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, k32),
     INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, k64),
     INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
@@ -452,10 +485,18 @@
 
     INTRINSIC(JavaLangInteger, BitCount, I_I, kIntrinsicBitCount, k32),
     INTRINSIC(JavaLangLong, BitCount, J_I, kIntrinsicBitCount, k64),
+    INTRINSIC(JavaLangInteger, Compare, II_I, kIntrinsicCompare, k32),
+    INTRINSIC(JavaLangLong, Compare, JJ_I, kIntrinsicCompare, k64),
+    INTRINSIC(JavaLangInteger, HighestOneBit, I_I, kIntrinsicHighestOneBit, k32),
+    INTRINSIC(JavaLangLong, HighestOneBit, J_J, kIntrinsicHighestOneBit, k64),
+    INTRINSIC(JavaLangInteger, LowestOneBit, I_I, kIntrinsicLowestOneBit, k32),
+    INTRINSIC(JavaLangLong, LowestOneBit, J_J, kIntrinsicLowestOneBit, k64),
     INTRINSIC(JavaLangInteger, NumberOfLeadingZeros, I_I, kIntrinsicNumberOfLeadingZeros, k32),
     INTRINSIC(JavaLangLong, NumberOfLeadingZeros, J_I, kIntrinsicNumberOfLeadingZeros, k64),
     INTRINSIC(JavaLangInteger, NumberOfTrailingZeros, I_I, kIntrinsicNumberOfTrailingZeros, k32),
     INTRINSIC(JavaLangLong, NumberOfTrailingZeros, J_I, kIntrinsicNumberOfTrailingZeros, k64),
+    INTRINSIC(JavaLangInteger, Signum, I_I, kIntrinsicSignum, k32),
+    INTRINSIC(JavaLangLong, Signum, J_I, kIntrinsicSignum, k64),
 
     INTRINSIC(JavaLangMath,       Abs, I_I, kIntrinsicAbsInt, 0),
     INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
@@ -750,11 +791,19 @@
                                           intrinsic.d.data & kIntrinsicFlagIsOrdered);
     case kIntrinsicSystemArrayCopyCharArray:
       return backend->GenInlinedArrayCopyCharArray(info);
+    case kIntrinsicFloatIsInfinite:
+    case kIntrinsicDoubleIsInfinite:
+    case kIntrinsicFloatIsNaN:
+    case kIntrinsicDoubleIsNaN:
     case kIntrinsicBitCount:
+    case kIntrinsicCompare:
+    case kIntrinsicHighestOneBit:
+    case kIntrinsicLowestOneBit:
     case kIntrinsicNumberOfLeadingZeros:
     case kIntrinsicNumberOfTrailingZeros:
     case kIntrinsicRotateRight:
     case kIntrinsicRotateLeft:
+    case kIntrinsicSignum:
     case kIntrinsicSystemArrayCopy:
       return false;   // not implemented in quick.
     default:
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 2803623..59b8a53 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -190,6 +190,8 @@
       kNameCacheEquals,
       kNameCacheGetCharsNoCheck,
       kNameCacheIsEmpty,
+      kNameCacheIsInfinite,
+      kNameCacheIsNaN,
       kNameCacheIndexOf,
       kNameCacheLength,
       kNameCacheInit,
@@ -225,10 +227,14 @@
       kNameCachePutOrderedObject,
       kNameCacheArrayCopy,
       kNameCacheBitCount,
+      kNameCacheCompare,
+      kNameCacheHighestOneBit,
+      kNameCacheLowestOneBit,
       kNameCacheNumberOfLeadingZeros,
       kNameCacheNumberOfTrailingZeros,
       kNameCacheRotateRight,
       kNameCacheRotateLeft,
+      kNameCacheSignum,
       kNameCacheLast
     };
 
@@ -247,8 +253,10 @@
       kProtoCacheF_F,
       kProtoCacheFF_F,
       kProtoCacheD_J,
+      kProtoCacheD_Z,
       kProtoCacheJ_D,
       kProtoCacheF_I,
+      kProtoCacheF_Z,
       kProtoCacheI_F,
       kProtoCacheII_I,
       kProtoCacheI_C,
@@ -263,6 +271,7 @@
       kProtoCacheJB_V,
       kProtoCacheJI_V,
       kProtoCacheJJ_J,
+      kProtoCacheJJ_I,
       kProtoCacheJJ_V,
       kProtoCacheJS_V,
       kProtoCacheObject_Z,
diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc
index ebc9a2c..027290f 100644
--- a/compiler/dex/quick/quick_compiler.cc
+++ b/compiler/dex/quick/quick_compiler.cc
@@ -486,11 +486,6 @@
 static_assert(sizeof(kUnsupportedOpcodesSize) == 8 * sizeof(size_t),
               "kUnsupportedOpcodesSize unexpected");
 
-static bool IsUnsupportedExperimentalLambdasOnly(size_t i) {
-  DCHECK_LE(i, arraysize(kUnsupportedOpcodes));
-  return kUnsupportedOpcodes[i] == kUnsupportedLambdaOpcodes;
-}
-
 // The maximum amount of Dalvik register in a method for which we will start compiling. Tries to
 // avoid an abort when we need to manage more SSA registers than we can.
 static constexpr size_t kMaxAllowedDalvikRegisters = INT16_MAX / 2;
@@ -513,36 +508,6 @@
   return true;
 }
 
-// If the ISA has unsupported opcodes, should we skip scanning over them?
-//
-// Most of the time we're compiling non-experimental files, so scanning just slows
-// performance down by as much as 6% with 4 threads.
-// In the rare cases we compile experimental opcodes, the runtime has an option to enable it,
-// which will force scanning for any unsupported opcodes.
-static bool SkipScanningUnsupportedOpcodes(InstructionSet instruction_set) {
-  Runtime* runtime = Runtime::Current();
-  if (UNLIKELY(runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods))) {
-    // Always need to scan opcodes if we have default methods since invoke-super for interface
-    // methods is never going to be supported in the quick compiler.
-    return false;
-  } else if (UNLIKELY(kUnsupportedOpcodesSize[instruction_set] == 0U)) {
-    // All opcodes are supported no matter what. Usually not the case
-    // since experimental opcodes are not implemented in the quick compiler.
-    return true;
-  } else if (LIKELY(!Runtime::Current()->
-                      AreExperimentalFlagsEnabled(ExperimentalFlags::kLambdas))) {
-    // Experimental opcodes are disabled.
-    //
-    // If all unsupported opcodes are experimental we don't need to do scanning.
-    return IsUnsupportedExperimentalLambdasOnly(instruction_set);
-  } else {
-    // Experimental opcodes are enabled.
-    //
-    // Do the opcode scanning if the ISA has any unsupported opcodes.
-    return false;
-  }
-}
-
 bool QuickCompiler::CanCompileInstruction(const MIR* mir,
                                           const DexFile& dex_file) const {
   switch (mir->dalvikInsn.opcode) {
@@ -572,11 +537,8 @@
     return false;
   }
 
-  // Check whether we do have limitations at all.
-  if (kSupportedTypes[cu->instruction_set] == nullptr &&
-      SkipScanningUnsupportedOpcodes(cu->instruction_set)) {
-    return true;
-  }
+  // Since the quick compiler doesn't (and never will) support default methods we always need to
+  // scan opcodes.
 
   // Check if we can compile the prototype.
   const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index 50f0ddb..2e98b69 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -1185,9 +1185,13 @@
         for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
           StackMap stack_map = code_info.GetStackMapAt(s, encoding);
           DCHECK(stack_map.IsValid());
-          const uint32_t pc = stack_map.GetNativePcOffset(encoding);
-          const int32_t dex = stack_map.GetDexPc(encoding);
-          src_mapping_table_from_stack_maps.push_back({pc, dex});
+          // Emit only locations where we have local-variable information.
+          // In particular, skip mappings inside the prologue.
+          if (stack_map.HasDexRegisterMap(encoding)) {
+            const uint32_t pc = stack_map.GetNativePcOffset(encoding);
+            const int32_t dex = stack_map.GetDexPc(encoding);
+            src_mapping_table_from_stack_maps.push_back({pc, dex});
+          }
         }
         std::sort(src_mapping_table_from_stack_maps.begin(),
                   src_mapping_table_from_stack_maps.end());
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index b841675..b65fb36 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -181,7 +181,7 @@
     ASSERT_NE(0U, bitmap_section.Size());
 
     gc::Heap* heap = Runtime::Current()->GetHeap();
-    ASSERT_TRUE(!heap->GetContinuousSpaces().empty());
+    ASSERT_TRUE(heap->HaveContinuousSpaces());
     gc::space::ContinuousSpace* space = heap->GetNonMovingSpace();
     ASSERT_FALSE(space->IsImageSpace());
     ASSERT_TRUE(space != nullptr);
diff --git a/compiler/optimizing/bounds_check_elimination.h b/compiler/optimizing/bounds_check_elimination.h
index b9df686..6dc5320 100644
--- a/compiler/optimizing/bounds_check_elimination.h
+++ b/compiler/optimizing/bounds_check_elimination.h
@@ -29,13 +29,13 @@
   BoundsCheckElimination(HGraph* graph,
                          const SideEffectsAnalysis& side_effects,
                          HInductionVarAnalysis* induction_analysis)
-      : HOptimization(graph, kBoundsCheckEliminiationPassName),
+      : HOptimization(graph, kBoundsCheckEliminationPassName),
         side_effects_(side_effects),
         induction_analysis_(induction_analysis) {}
 
   void Run() OVERRIDE;
 
-  static constexpr const char* kBoundsCheckEliminiationPassName = "BCE";
+  static constexpr const char* kBoundsCheckEliminationPassName = "BCE";
 
  private:
   const SideEffectsAnalysis& side_effects_;
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 32c3a92..2805162 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -21,6 +21,7 @@
 #include <cctype>
 #include <sstream>
 
+#include "bounds_check_elimination.h"
 #include "code_generator.h"
 #include "dead_code_elimination.h"
 #include "disassembler.h"
@@ -505,6 +506,7 @@
     if (IsPass(LICM::kLoopInvariantCodeMotionPassName)
         || IsPass(HDeadCodeElimination::kFinalDeadCodeEliminationPassName)
         || IsPass(HDeadCodeElimination::kInitialDeadCodeEliminationPassName)
+        || IsPass(BoundsCheckElimination::kBoundsCheckEliminationPassName)
         || IsPass(SsaBuilder::kSsaBuilderPassName)) {
       HLoopInformation* info = instruction->GetBlock()->GetLoopInformation();
       if (info == nullptr) {
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 5caf077..a6be324 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -131,6 +131,16 @@
       return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
           Intrinsics::kFloatFloatToRawIntBits : Intrinsics::kFloatIntBitsToFloat;
 
+    // Floating-point tests.
+    case kIntrinsicFloatIsInfinite:
+      return Intrinsics::kFloatIsInfinite;
+    case kIntrinsicDoubleIsInfinite:
+      return Intrinsics::kDoubleIsInfinite;
+    case kIntrinsicFloatIsNaN:
+      return Intrinsics::kFloatIsNaN;
+    case kIntrinsicDoubleIsNaN:
+      return Intrinsics::kDoubleIsNaN;
+
     // Bit manipulations.
     case kIntrinsicReverseBits:
       switch (GetType(method.d.data, true)) {
@@ -186,6 +196,36 @@
           LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
           UNREACHABLE();
       }
+    case kIntrinsicCompare:
+      switch (GetType(method.d.data, true)) {
+        case Primitive::kPrimInt:
+          return Intrinsics::kIntegerCompare;
+        case Primitive::kPrimLong:
+          return Intrinsics::kLongCompare;
+        default:
+          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+          UNREACHABLE();
+      }
+    case kIntrinsicHighestOneBit:
+      switch (GetType(method.d.data, true)) {
+        case Primitive::kPrimInt:
+          return Intrinsics::kIntegerHighestOneBit;
+        case Primitive::kPrimLong:
+          return Intrinsics::kLongHighestOneBit;
+        default:
+          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+          UNREACHABLE();
+      }
+    case kIntrinsicLowestOneBit:
+      switch (GetType(method.d.data, true)) {
+        case Primitive::kPrimInt:
+          return Intrinsics::kIntegerLowestOneBit;
+        case Primitive::kPrimLong:
+          return Intrinsics::kLongLowestOneBit;
+        default:
+          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+          UNREACHABLE();
+      }
     case kIntrinsicNumberOfLeadingZeros:
       switch (GetType(method.d.data, true)) {
         case Primitive::kPrimInt:
@@ -206,6 +246,16 @@
           LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
           UNREACHABLE();
       }
+    case kIntrinsicSignum:
+      switch (GetType(method.d.data, true)) {
+        case Primitive::kPrimInt:
+          return Intrinsics::kIntegerSignum;
+        case Primitive::kPrimLong:
+          return Intrinsics::kLongSignum;
+        default:
+          LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+          UNREACHABLE();
+      }
 
     // Abs.
     case kIntrinsicAbsDouble:
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index e72f927..97fe587 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -1580,13 +1580,9 @@
 UNIMPLEMENTED_INTRINSIC(IntegerBitCount)
 UNIMPLEMENTED_INTRINSIC(IntegerReverse)
 UNIMPLEMENTED_INTRINSIC(IntegerReverseBytes)
-UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
-UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
 UNIMPLEMENTED_INTRINSIC(LongBitCount)
 UNIMPLEMENTED_INTRINSIC(LongReverse)
 UNIMPLEMENTED_INTRINSIC(LongReverseBytes)
-UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
-UNIMPLEMENTED_INTRINSIC(LongRotateRight)
 UNIMPLEMENTED_INTRINSIC(ShortReverseBytes)
 UNIMPLEMENTED_INTRINSIC(MathMinDoubleDouble)
 UNIMPLEMENTED_INTRINSIC(MathMinFloatFloat)
@@ -1621,6 +1617,26 @@
 UNIMPLEMENTED_INTRINSIC(MathTan)
 UNIMPLEMENTED_INTRINSIC(MathTanh)
 
+UNIMPLEMENTED_INTRINSIC(FloatIsInfinite)
+UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite)
+UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
+UNIMPLEMENTED_INTRINSIC(DoubleIsNaN)
+
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
+UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerSignum)
+UNIMPLEMENTED_INTRINSIC(LongSignum)
+
+// Rotate operations are handled as HRor instructions.
+UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
+UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
+UNIMPLEMENTED_INTRINSIC(LongRotateRight)
+
 #undef UNIMPLEMENTED_INTRINSIC
 
 #undef __
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 8cf2d4f..c888f01 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -1465,11 +1465,7 @@
 }
 
 UNIMPLEMENTED_INTRINSIC(IntegerBitCount)
-UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
-UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
 UNIMPLEMENTED_INTRINSIC(LongBitCount)
-UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
-UNIMPLEMENTED_INTRINSIC(LongRotateRight)
 UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
 UNIMPLEMENTED_INTRINSIC(SystemArrayCopy)
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
@@ -1493,6 +1489,26 @@
 UNIMPLEMENTED_INTRINSIC(MathTan)
 UNIMPLEMENTED_INTRINSIC(MathTanh)
 
+UNIMPLEMENTED_INTRINSIC(FloatIsInfinite)
+UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite)
+UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
+UNIMPLEMENTED_INTRINSIC(DoubleIsNaN)
+
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
+UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerSignum)
+UNIMPLEMENTED_INTRINSIC(LongSignum)
+
+// Rotate operations are handled as HRor instructions.
+UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
+UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
+UNIMPLEMENTED_INTRINSIC(LongRotateRight)
+
 #undef UNIMPLEMENTED_INTRINSIC
 
 #undef __
diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h
index ea38034..88217b3 100644
--- a/compiler/optimizing/intrinsics_list.h
+++ b/compiler/optimizing/intrinsics_list.h
@@ -23,23 +23,35 @@
 
 #define INTRINSICS_LIST(V) \
   V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(DoubleIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(DoubleIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(DoubleLongBitsToDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(FloatFloatToRawIntBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(FloatIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(FloatIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(FloatIntBitsToFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(IntegerReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(IntegerReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(IntegerBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(IntegerCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(IntegerHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(IntegerLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(IntegerNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(IntegerRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(IntegerRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(IntegerSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(LongReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(LongReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(LongBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(LongCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(LongHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(LongLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(LongNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(LongRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(LongRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
+  V(LongSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(ShortReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(MathAbsDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
   V(MathAbsFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 81112b1..0d9cf09 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -1013,6 +1013,21 @@
 UNIMPLEMENTED_INTRINSIC(MathSinh)
 UNIMPLEMENTED_INTRINSIC(MathTan)
 UNIMPLEMENTED_INTRINSIC(MathTanh)
+
+UNIMPLEMENTED_INTRINSIC(FloatIsInfinite)
+UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite)
+UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
+UNIMPLEMENTED_INTRINSIC(DoubleIsNaN)
+
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
+UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerSignum)
+UNIMPLEMENTED_INTRINSIC(LongSignum)
+
 #undef UNIMPLEMENTED_INTRINSIC
 
 #undef __
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 769c422..cba84fa 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -1760,6 +1760,20 @@
 UNIMPLEMENTED_INTRINSIC(MathTan)
 UNIMPLEMENTED_INTRINSIC(MathTanh)
 
+UNIMPLEMENTED_INTRINSIC(FloatIsInfinite)
+UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite)
+UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
+UNIMPLEMENTED_INTRINSIC(DoubleIsNaN)
+
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
+UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerSignum)
+UNIMPLEMENTED_INTRINSIC(LongSignum)
+
 #undef UNIMPLEMENTED_INTRINSIC
 
 #undef __
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 3f5688b..acc40bc 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -2593,11 +2593,27 @@
 
 UNIMPLEMENTED_INTRINSIC(MathRoundDouble)
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
+UNIMPLEMENTED_INTRINSIC(SystemArrayCopy)
+
+UNIMPLEMENTED_INTRINSIC(FloatIsInfinite)
+UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite)
+UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
+UNIMPLEMENTED_INTRINSIC(DoubleIsNaN)
+
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
+UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerSignum)
+UNIMPLEMENTED_INTRINSIC(LongSignum)
+
+// Rotate operations are handled as HRor instructions.
 UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
 UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
 UNIMPLEMENTED_INTRINSIC(LongRotateRight)
 UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
-UNIMPLEMENTED_INTRINSIC(SystemArrayCopy)
 
 #undef UNIMPLEMENTED_INTRINSIC
 
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 23a628f..6ccc5d1 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -2592,6 +2592,22 @@
 }
 
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
+
+UNIMPLEMENTED_INTRINSIC(FloatIsInfinite)
+UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite)
+UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
+UNIMPLEMENTED_INTRINSIC(DoubleIsNaN)
+
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
+UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongHighestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(LongLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(IntegerSignum)
+UNIMPLEMENTED_INTRINSIC(LongSignum)
+
+// Rotate operations are handled as HRor instructions.
 UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
 UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
 UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index adf8734..92f758d 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2221,10 +2221,7 @@
     SetSideEffects(GetSideEffects().Union(SideEffects::CanTriggerGC()));
   }
   // Adjust method's exception status from intrinsic table.
-  switch (exceptions) {
-    case kNoThrow: SetCanThrow(false); break;
-    case kCanThrow: SetCanThrow(true); break;
-  }
+  SetCanThrow(exceptions == kCanThrow);
 }
 
 bool HNewInstance::IsStringAlloc() const {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 5246fd1..41c2f17 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -159,7 +159,7 @@
 
   static ReferenceTypeInfo CreateInvalid() { return ReferenceTypeInfo(); }
 
-  static bool IsValidHandle(TypeHandle handle) SHARED_REQUIRES(Locks::mutator_lock_) {
+  static bool IsValidHandle(TypeHandle handle) {
     return handle.GetReference() != nullptr;
   }
 
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 527c242..779f319 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -23,21 +23,41 @@
 
 namespace art {
 
-class RTPVisitor : public HGraphDelegateVisitor {
+static inline ReferenceTypeInfo::TypeHandle GetRootHandle(StackHandleScopeCollection* handles,
+                                                          ClassLinker::ClassRoot class_root,
+                                                          ReferenceTypeInfo::TypeHandle* cache) {
+  if (!ReferenceTypeInfo::IsValidHandle(*cache)) {
+    // Mutator lock is required for NewHandle.
+    ClassLinker* linker = Runtime::Current()->GetClassLinker();
+    ScopedObjectAccess soa(Thread::Current());
+    *cache = handles->NewHandle(linker->GetClassRoot(class_root));
+  }
+  return *cache;
+}
+
+ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetObjectClassHandle() {
+  return GetRootHandle(handles_, ClassLinker::kJavaLangObject, &object_class_handle_);
+}
+
+ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetClassClassHandle() {
+  return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_);
+}
+
+ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() {
+  return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_);
+}
+
+ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowableClassHandle() {
+  return GetRootHandle(handles_, ClassLinker::kJavaLangThrowable, &throwable_class_handle_);
+}
+
+class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor {
  public:
   RTPVisitor(HGraph* graph,
-             StackHandleScopeCollection* handles,
-             ArenaVector<HInstruction*>* worklist,
-             ReferenceTypeInfo::TypeHandle object_class_handle,
-             ReferenceTypeInfo::TypeHandle class_class_handle,
-             ReferenceTypeInfo::TypeHandle string_class_handle,
-             ReferenceTypeInfo::TypeHandle throwable_class_handle)
+             HandleCache* handle_cache,
+             ArenaVector<HInstruction*>* worklist)
     : HGraphDelegateVisitor(graph),
-      handles_(handles),
-      object_class_handle_(object_class_handle),
-      class_class_handle_(class_class_handle),
-      string_class_handle_(string_class_handle),
-      throwable_class_handle_(throwable_class_handle),
+      handle_cache_(handle_cache),
       worklist_(worklist) {}
 
   void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
@@ -64,11 +84,7 @@
                                bool is_exact);
 
  private:
-  StackHandleScopeCollection* handles_;
-  ReferenceTypeInfo::TypeHandle object_class_handle_;
-  ReferenceTypeInfo::TypeHandle class_class_handle_;
-  ReferenceTypeInfo::TypeHandle string_class_handle_;
-  ReferenceTypeInfo::TypeHandle throwable_class_handle_;
+  HandleCache* handle_cache_;
   ArenaVector<HInstruction*>* worklist_;
 };
 
@@ -76,24 +92,9 @@
                                                    StackHandleScopeCollection* handles,
                                                    const char* name)
     : HOptimization(graph, name),
-      handles_(handles),
+      handle_cache_(handles),
       worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)) {
   worklist_.reserve(kDefaultWorklistSize);
-  // Mutator lock is required for NewHandle, but annotalysis ignores constructors.
-  ScopedObjectAccess soa(Thread::Current());
-  ClassLinker* linker = Runtime::Current()->GetClassLinker();
-  object_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject));
-  string_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangString));
-  class_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangClass));
-  throwable_class_handle_ =
-      handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangThrowable));
-
-  if (kIsDebugBuild) {
-    DCHECK(ReferenceTypeInfo::IsValidHandle(object_class_handle_));
-    DCHECK(ReferenceTypeInfo::IsValidHandle(class_class_handle_));
-    DCHECK(ReferenceTypeInfo::IsValidHandle(string_class_handle_));
-    DCHECK(ReferenceTypeInfo::IsValidHandle(throwable_class_handle_));
-  }
 }
 
 void ReferenceTypePropagation::ValidateTypes() {
@@ -137,13 +138,7 @@
 }
 
 void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
-  RTPVisitor visitor(graph_,
-                     handles_,
-                     &worklist_,
-                     object_class_handle_,
-                     class_class_handle_,
-                     string_class_handle_,
-                     throwable_class_handle_);
+  RTPVisitor visitor(graph_, &handle_cache_, &worklist_);
   // Handle Phis first as there might be instructions in the same block who depend on them.
   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
     VisitPhi(it.Current()->AsPhi());
@@ -243,7 +238,7 @@
         ScopedObjectAccess soa(Thread::Current());
         HInstruction* insert_point = notNullBlock->GetFirstInstruction();
         ReferenceTypeInfo object_rti = ReferenceTypeInfo::Create(
-            object_class_handle_, /* is_exact */ true);
+            handle_cache_.GetObjectClassHandle(), /* is_exact */ true);
         if (ShouldCreateBoundType(insert_point, obj, object_rti, nullptr, notNullBlock)) {
           bound_type = new (graph_->GetArena()) HBoundType(obj);
           bound_type->SetUpperBound(object_rti, /* bound_can_be_null */ false);
@@ -395,9 +390,9 @@
   }
 }
 
-void RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
-                                    mirror::Class* klass,
-                                    bool is_exact) {
+void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
+                                                              mirror::Class* klass,
+                                                              bool is_exact) {
   if (instr->IsInvokeStaticOrDirect() && instr->AsInvokeStaticOrDirect()->IsStringInit()) {
     // Calls to String.<init> are replaced with a StringFactory.
     if (kIsDebugBuild) {
@@ -422,22 +417,22 @@
           << "Expected String.<init>: " << PrettyMethod(method);
     }
     instr->SetReferenceTypeInfo(
-        ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
+        ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
   } else if (klass != nullptr) {
     ScopedObjectAccess soa(Thread::Current());
-    ReferenceTypeInfo::TypeHandle handle = handles_->NewHandle(klass);
+    ReferenceTypeInfo::TypeHandle handle = handle_cache_->NewHandle(klass);
     is_exact = is_exact || klass->CannotBeAssignedFromOtherTypes();
     instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
   } else {
     instr->SetReferenceTypeInfo(
-        ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
+        ReferenceTypeInfo::Create(handle_cache_->GetObjectClassHandle(), /* is_exact */ false));
   }
 }
 
-void RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
-                                         uint16_t type_idx,
-                                         const DexFile& dex_file,
-                                         bool is_exact) {
+void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
+                                                                   uint16_t type_idx,
+                                                                   const DexFile& dex_file,
+                                                                   bool is_exact) {
   DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
 
   ScopedObjectAccess soa(Thread::Current());
@@ -447,11 +442,11 @@
   SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
 }
 
-void RTPVisitor::VisitNewInstance(HNewInstance* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitNewInstance(HNewInstance* instr) {
   UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
 }
 
-void RTPVisitor::VisitNewArray(HNewArray* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitNewArray(HNewArray* instr) {
   UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
 }
 
@@ -467,7 +462,7 @@
   return dex_cache->GetResolvedType(type_idx);
 }
 
-void RTPVisitor::VisitParameterValue(HParameterValue* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitParameterValue(HParameterValue* instr) {
   ScopedObjectAccess soa(Thread::Current());
   // We check if the existing type is valid: the inliner may have set it.
   if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
@@ -477,8 +472,8 @@
   }
 }
 
-void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
-                                           const FieldInfo& info) {
+void ReferenceTypePropagation::RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
+                                                                     const FieldInfo& info) {
   if (instr->GetType() != Primitive::kPrimNot) {
     return;
   }
@@ -500,57 +495,61 @@
   SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
 }
 
-void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
   UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
 }
 
-void RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
   UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
 }
 
-void RTPVisitor::VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedInstanceFieldGet(
+    HUnresolvedInstanceFieldGet* instr) {
   // TODO: Use descriptor to get the actual type.
   if (instr->GetFieldType() == Primitive::kPrimNot) {
     instr->SetReferenceTypeInfo(
-      ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
+      ReferenceTypeInfo::Create(handle_cache_->GetObjectClassHandle(), /* is_exact */ false));
   }
 }
 
-void RTPVisitor::VisitUnresolvedStaticFieldGet(HUnresolvedStaticFieldGet* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedStaticFieldGet(
+    HUnresolvedStaticFieldGet* instr) {
   // TODO: Use descriptor to get the actual type.
   if (instr->GetFieldType() == Primitive::kPrimNot) {
     instr->SetReferenceTypeInfo(
-      ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
+      ReferenceTypeInfo::Create(handle_cache_->GetObjectClassHandle(), /* is_exact */ false));
   }
 }
 
-void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitLoadClass(HLoadClass* instr) {
   ScopedObjectAccess soa(Thread::Current());
   // Get type from dex cache assuming it was populated by the verifier.
   mirror::Class* resolved_class =
       GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
   if (resolved_class != nullptr) {
     instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
-        handles_->NewHandle(resolved_class), /* is_exact */ true));
+        handle_cache_->NewHandle(resolved_class), /* is_exact */ true));
   }
-  instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_class_handle_, /* is_exact */ true));
+  instr->SetReferenceTypeInfo(
+      ReferenceTypeInfo::Create(handle_cache_->GetClassClassHandle(), /* is_exact */ true));
 }
 
-void RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitClinitCheck(HClinitCheck* instr) {
   instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
 }
 
-void RTPVisitor::VisitLoadString(HLoadString* instr) {
-  instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
+void ReferenceTypePropagation::RTPVisitor::VisitLoadString(HLoadString* instr) {
+  instr->SetReferenceTypeInfo(
+      ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
 }
 
-void RTPVisitor::VisitLoadException(HLoadException* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitLoadException(HLoadException* instr) {
   DCHECK(instr->GetBlock()->IsCatchBlock());
   TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
 
   if (catch_info->IsCatchAllTypeIndex()) {
-    instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(throwable_class_handle_,
-                                                          /* is_exact */ false));
+    instr->SetReferenceTypeInfo(
+        ReferenceTypeInfo::Create(handle_cache_->GetThrowableClassHandle(), /* is_exact */ false));
   } else {
     UpdateReferenceTypeInfo(instr,
                             catch_info->GetCatchTypeIndex(),
@@ -559,7 +558,7 @@
   }
 }
 
-void RTPVisitor::VisitNullCheck(HNullCheck* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitNullCheck(HNullCheck* instr) {
   ScopedObjectAccess soa(Thread::Current());
   ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
   if (parent_rti.IsValid()) {
@@ -567,7 +566,7 @@
   }
 }
 
-void RTPVisitor::VisitBoundType(HBoundType* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitBoundType(HBoundType* instr) {
   ScopedObjectAccess soa(Thread::Current());
 
   ReferenceTypeInfo class_rti = instr->GetUpperBound();
@@ -601,7 +600,7 @@
   }
 }
 
-void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
+void ReferenceTypePropagation::RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
   ScopedObjectAccess soa(Thread::Current());
 
   HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
@@ -677,7 +676,8 @@
     result_type_handle = b_type_handle;
     is_exact = false;
   } else if (!a_is_interface && !b_is_interface) {
-    result_type_handle = handles_->NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
+    result_type_handle =
+        handle_cache_.NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
     is_exact = false;
   } else {
     // This can happen if:
@@ -687,17 +687,14 @@
     //        void foo(Interface i, boolean cond) {
     //          Object o = cond ? i : new Object();
     //        }
-    result_type_handle = object_class_handle_;
+    result_type_handle = handle_cache_.GetObjectClassHandle();
     is_exact = false;
   }
 
   return ReferenceTypeInfo::Create(result_type_handle, is_exact);
 }
 
-static void UpdateArrayGet(HArrayGet* instr,
-                           StackHandleScopeCollection* handles,
-                           ReferenceTypeInfo::TypeHandle object_class_handle)
-    SHARED_REQUIRES(Locks::mutator_lock_) {
+void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache) {
   DCHECK_EQ(Primitive::kPrimNot, instr->GetType());
 
   ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
@@ -707,13 +704,14 @@
 
   Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
   if (handle->IsObjectArrayClass()) {
-    ReferenceTypeInfo::TypeHandle component_handle = handles->NewHandle(handle->GetComponentType());
+    ReferenceTypeInfo::TypeHandle component_handle =
+        handle_cache->NewHandle(handle->GetComponentType());
     instr->SetReferenceTypeInfo(
         ReferenceTypeInfo::Create(component_handle, /* is_exact */ false));
   } else {
     // We don't know what the parent actually is, so we fallback to object.
     instr->SetReferenceTypeInfo(
-        ReferenceTypeInfo::Create(object_class_handle, /* is_exact */ false));
+        ReferenceTypeInfo::Create(handle_cache->GetObjectClassHandle(), /* is_exact */ false));
   }
 }
 
@@ -733,7 +731,7 @@
   } else if (instr->IsArrayGet()) {
     // TODO: consider if it's worth "looking back" and binding the input object
     // to an array type.
-    UpdateArrayGet(instr->AsArrayGet(), handles_, object_class_handle_);
+    UpdateArrayGet(instr->AsArrayGet(), &handle_cache_);
   } else {
     LOG(FATAL) << "Invalid instruction (should not get here)";
   }
@@ -741,7 +739,7 @@
   return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
 }
 
-void RTPVisitor::VisitInvoke(HInvoke* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitInvoke(HInvoke* instr) {
   if (instr->GetType() != Primitive::kPrimNot) {
     return;
   }
@@ -755,13 +753,13 @@
   SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
 }
 
-void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
+void ReferenceTypePropagation::RTPVisitor::VisitArrayGet(HArrayGet* instr) {
   if (instr->GetType() != Primitive::kPrimNot) {
     return;
   }
 
   ScopedObjectAccess soa(Thread::Current());
-  UpdateArrayGet(instr, handles_, object_class_handle_);
+  UpdateArrayGet(instr, handle_cache_);
   if (!instr->GetReferenceTypeInfo().IsValid()) {
     worklist_->push_back(instr);
   }
@@ -796,7 +794,7 @@
     // All inputs are NullConstants, set the type to object.
     // This may happen in the presence of inlining.
     instr->SetReferenceTypeInfo(
-        ReferenceTypeInfo::Create(object_class_handle_, /* is_exact */ false));
+        ReferenceTypeInfo::Create(handle_cache_.GetObjectClassHandle(), /* is_exact */ false));
     return;
   }
 
@@ -886,4 +884,5 @@
     }
   }
 }
+
 }  // namespace art
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index 5c05592..47ba027 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -40,6 +40,31 @@
   static constexpr const char* kReferenceTypePropagationPassName = "reference_type_propagation";
 
  private:
+  class HandleCache {
+   public:
+    explicit HandleCache(StackHandleScopeCollection* handles) : handles_(handles) { }
+
+    template <typename T>
+    MutableHandle<T> NewHandle(T* object) SHARED_REQUIRES(Locks::mutator_lock_) {
+      return handles_->NewHandle(object);
+    }
+
+    ReferenceTypeInfo::TypeHandle GetObjectClassHandle();
+    ReferenceTypeInfo::TypeHandle GetClassClassHandle();
+    ReferenceTypeInfo::TypeHandle GetStringClassHandle();
+    ReferenceTypeInfo::TypeHandle GetThrowableClassHandle();
+
+   private:
+    StackHandleScopeCollection* handles_;
+
+    ReferenceTypeInfo::TypeHandle object_class_handle_;
+    ReferenceTypeInfo::TypeHandle class_class_handle_;
+    ReferenceTypeInfo::TypeHandle string_class_handle_;
+    ReferenceTypeInfo::TypeHandle throwable_class_handle_;
+  };
+
+  class RTPVisitor;
+
   void VisitPhi(HPhi* phi);
   void VisitBasicBlock(HBasicBlock* block);
   void UpdateBoundType(HBoundType* bound_type) SHARED_REQUIRES(Locks::mutator_lock_);
@@ -53,19 +78,18 @@
   bool UpdateNullability(HInstruction* instr);
   bool UpdateReferenceTypeInfo(HInstruction* instr);
 
+  static void UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
   ReferenceTypeInfo MergeTypes(const ReferenceTypeInfo& a, const ReferenceTypeInfo& b)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
   void ValidateTypes();
 
-  StackHandleScopeCollection* handles_;
+  HandleCache handle_cache_;
 
   ArenaVector<HInstruction*> worklist_;
 
-  ReferenceTypeInfo::TypeHandle object_class_handle_;
-  ReferenceTypeInfo::TypeHandle class_class_handle_;
-  ReferenceTypeInfo::TypeHandle string_class_handle_;
-  ReferenceTypeInfo::TypeHandle throwable_class_handle_;
 
   static constexpr size_t kDefaultWorklistSize = 8;
 
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 61d4152..7a0decb 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -40,7 +40,7 @@
 #include "gc/space/image_space.h"
 #include "gc/space/large_object_space.h"
 #include "gc/space/space-inl.h"
-#include "image.h"
+#include "image-inl.h"
 #include "indenter.h"
 #include "linker/buffered_output_stream.h"
 #include "linker/file_output_stream.h"
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 7e4ce91..1668dc5 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -35,7 +35,7 @@
 #include "elf_file.h"
 #include "elf_file_impl.h"
 #include "gc/space/image_space.h"
-#include "image.h"
+#include "image-inl.h"
 #include "mirror/abstract_method.h"
 #include "mirror/object-inl.h"
 #include "mirror/method.h"
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ff38394..bb709e8 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -53,6 +53,7 @@
 #include "gc/heap.h"
 #include "gc/space/image_space.h"
 #include "handle_scope-inl.h"
+#include "image-inl.h"
 #include "intern_table.h"
 #include "interpreter/interpreter.h"
 #include "jit/jit.h"
@@ -2926,19 +2927,19 @@
   CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation();
   // For app images, the dex cache location may be a suffix of the dex file location since the
   // dex file location is an absolute path.
-  const size_t dex_cache_length = dex_cache->GetLocation()->GetLength();
+  const std::string dex_cache_location = dex_cache->GetLocation()->ToModifiedUtf8();
+  const size_t dex_cache_length = dex_cache_location.length();
   CHECK_GT(dex_cache_length, 0u) << dex_file.GetLocation();
   std::string dex_file_location = dex_file.GetLocation();
   CHECK_GE(dex_file_location.length(), dex_cache_length)
-      << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation();
+      << dex_cache_location << " " << dex_file.GetLocation();
   // Take suffix.
   const std::string dex_file_suffix = dex_file_location.substr(
       dex_file_location.length() - dex_cache_length,
       dex_cache_length);
   // Example dex_cache location is SettingsProvider.apk and
   // dex file location is /system/priv-app/SettingsProvider/SettingsProvider.apk
-  CHECK(dex_cache->GetLocation()->Equals(dex_file_suffix))
-      << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation();
+  CHECK_EQ(dex_cache_location, dex_file_suffix);
   // Clean up pass to remove null dex caches.
   // Null dex caches can occur due to class unloading and we are lazily removing null entries.
   JavaVMExt* const vm = self->GetJniEnv()->vm;
@@ -5973,15 +5974,6 @@
   Runtime* const runtime = Runtime::Current();
 
   const bool is_interface = klass->IsInterface();
-  // TODO It might in the future prove useful to make interfaces have full iftables, allowing a
-  // faster invoke-super implementation in the interpreter/across dex-files.
-  // We will just skip doing any of this on non-debug builds for speed.
-  if (is_interface &&
-      !kIsDebugBuild &&
-      !runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) {
-    return true;
-  }
-
   const bool has_superclass = klass->HasSuperClass();
   const bool fill_tables = !is_interface;
   const size_t super_ifcount = has_superclass ? klass->GetSuperClass()->GetIfTableCount() : 0U;
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index d503dd4..4975c29 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -1063,8 +1063,8 @@
   friend class ImageWriter;  // for GetClassRoots
   friend class JniCompilerTest;  // for GetRuntimeQuickGenericJniStub
   friend class JniInternalTest;  // for GetRuntimeQuickGenericJniStub
+  ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName);  // for DexLock, and RegisterDexFileLocked
   ART_FRIEND_TEST(mirror::DexCacheTest, Open);  // for AllocDexCache
-
   DISALLOW_COPY_AND_ASSIGN(ClassLinker);
 };
 
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 471d7ca..40dfda9 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -1201,4 +1201,42 @@
   EXPECT_FALSE(statics.Get()->IsBootStrapClassLoaded());
 }
 
+// Regression test for b/26799552.
+TEST_F(ClassLinkerTest, RegisterDexFileName) {
+  ScopedObjectAccess soa(Thread::Current());
+  StackHandleScope<2> hs(soa.Self());
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  MutableHandle<mirror::DexCache> dex_cache(hs.NewHandle<mirror::DexCache>(nullptr));
+  {
+    ReaderMutexLock mu(soa.Self(), *class_linker->DexLock());
+    for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) {
+      dex_cache.Assign(down_cast<mirror::DexCache*>(soa.Self()->DecodeJObject(data.weak_root)));
+      if (dex_cache.Get() != nullptr) {
+        break;
+      }
+    }
+    ASSERT_TRUE(dex_cache.Get() != nullptr);
+  }
+  // Make a copy of the dex cache and change the name.
+  dex_cache.Assign(dex_cache->Clone(soa.Self())->AsDexCache());
+  const uint16_t data[] = { 0x20AC, 0x20A1 };
+  Handle<mirror::String> location(hs.NewHandle(mirror::String::AllocFromUtf16(soa.Self(),
+                                                                              arraysize(data),
+                                                                              data)));
+  dex_cache->SetLocation(location.Get());
+  const DexFile* old_dex_file = dex_cache->GetDexFile();
+
+  DexFile* dex_file = new DexFile(old_dex_file->Begin(),
+                                  old_dex_file->Size(),
+                                  location->ToModifiedUtf8(),
+                                  0u,
+                                  nullptr,
+                                  nullptr);
+  {
+    WriterMutexLock mu(soa.Self(), *class_linker->DexLock());
+    // Check that inserting with a UTF16 name works.
+    class_linker->RegisterDexFileLocked(*dex_file, dex_cache);
+  }
+}
+
 }  // namespace art
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 968b37b..200121e 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -1260,6 +1260,7 @@
   mutable std::unique_ptr<TypeLookupTable> lookup_table_;
 
   friend class DexFileVerifierTest;
+  ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName);  // for constructor
 };
 
 struct DexFileReference {
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 727f4fc..7a852e2 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -2538,20 +2538,6 @@
     return false;
   }
 
-  // Only the static initializer may have code in an interface.
-  // TODO We should have some way determine whether to allow this experimental flag without the
-  // runtime being started.
-  // We assume experimental flags are enabled when running without a runtime to enable tools like
-  // dexdump to handle dex files with these features.
-  if (((class_access_flags & kAccInterface) != 0)
-      && !is_clinit_by_name
-      && Runtime::Current() != nullptr
-      && !Runtime::Current()->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) {
-    *error_msg = StringPrintf("Non-clinit interface method %" PRIu32 " should not have code",
-                              method_index);
-    return false;
-  }
-
   // Instance constructors must not be synchronized and a few other flags.
   if (is_init_by_name) {
     static constexpr uint32_t kInitAllowed =
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 08c9b49..638fdb4 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1779,8 +1779,7 @@
 
   void FinalizeHandleScope(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_);
 
-  StackReference<mirror::Object>* GetFirstHandleScopeEntry()
-      SHARED_REQUIRES(Locks::mutator_lock_) {
+  StackReference<mirror::Object>* GetFirstHandleScopeEntry() {
     return handle_scope_->GetHandle(0).GetReference();
   }
 
diff --git a/runtime/experimental_flags.h b/runtime/experimental_flags.h
index 2e674e9..198f3fa 100644
--- a/runtime/experimental_flags.h
+++ b/runtime/experimental_flags.h
@@ -27,7 +27,6 @@
   enum {
     kNone           = 0x0000,
     kLambdas        = 0x0001,
-    kDefaultMethods = 0x0002,
   };
 
   constexpr ExperimentalFlags() : value_(0x0000) {}
@@ -69,10 +68,6 @@
     stream << (started ? "|" : "") << "kLambdas";
     started = true;
   }
-  if (e & ExperimentalFlags::kDefaultMethods) {
-    stream << (started ? "|" : "") << "kDefaultMethods";
-    started = true;
-  }
   if (!started) {
     stream << "kNone";
   }
diff --git a/runtime/gc/accounting/mod_union_table_test.cc b/runtime/gc/accounting/mod_union_table_test.cc
index edab1b0..349d6ff 100644
--- a/runtime/gc/accounting/mod_union_table_test.cc
+++ b/runtime/gc/accounting/mod_union_table_test.cc
@@ -22,6 +22,7 @@
 #include "mirror/array-inl.h"
 #include "space_bitmap-inl.h"
 #include "thread-inl.h"
+#include "thread_list.h"
 
 namespace art {
 namespace gc {
@@ -184,7 +185,11 @@
   std::unique_ptr<space::DlMallocSpace> other_space(space::DlMallocSpace::Create(
       "other space", 128 * KB, 4 * MB, 4 * MB, nullptr, false));
   ASSERT_TRUE(other_space.get() != nullptr);
-  heap->AddSpace(other_space.get());
+  {
+    ScopedThreadSuspension sts(self, kSuspended);
+    ScopedSuspendAll ssa("Add image space");
+    heap->AddSpace(other_space.get());
+  }
   std::unique_ptr<ModUnionTable> table(ModUnionTableFactory::Create(
       type, space, other_space.get()));
   ASSERT_TRUE(table.get() != nullptr);
@@ -253,6 +258,8 @@
   std::ostringstream oss2;
   table->Dump(oss2);
   // Remove the space we added so it doesn't persist to the next test.
+  ScopedThreadSuspension sts(self, kSuspended);
+  ScopedSuspendAll ssa("Add image space");
   heap->RemoveSpace(other_space.get());
 }
 
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index bcfcb89..9397c35 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -24,6 +24,7 @@
 #include "gc/reference_processor.h"
 #include "gc/space/image_space.h"
 #include "gc/space/space-inl.h"
+#include "image-inl.h"
 #include "intern_table.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
@@ -2066,8 +2067,9 @@
 }
 
 void ConcurrentCopying::FinishPhase() {
+  Thread* const self = Thread::Current();
   {
-    MutexLock mu(Thread::Current(), mark_stack_lock_);
+    MutexLock mu(self, mark_stack_lock_);
     CHECK_EQ(pooled_mark_stacks_.size(), kMarkStackPoolSize);
   }
   region_space_ = nullptr;
@@ -2075,7 +2077,8 @@
     MutexLock mu(Thread::Current(), skipped_blocks_lock_);
     skipped_blocks_map_.clear();
   }
-  WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
+  ReaderMutexLock mu(self, *Locks::mutator_lock_);
+  WriterMutexLock mu2(self, *Locks::heap_bitmap_lock_);
   heap_->ClearMarkedObjects();
 }
 
diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h
index 954c80e..580486a 100644
--- a/runtime/gc/collector/garbage_collector.h
+++ b/runtime/gc/collector/garbage_collector.h
@@ -153,7 +153,9 @@
   void ResetCumulativeStatistics() REQUIRES(!pause_histogram_lock_);
   // Swap the live and mark bitmaps of spaces that are active for the collector. For partial GC,
   // this is the allocation space, for full GC then we swap the zygote bitmaps too.
-  void SwapBitmaps() REQUIRES(Locks::heap_bitmap_lock_);
+  void SwapBitmaps()
+      REQUIRES(Locks::heap_bitmap_lock_)
+      SHARED_REQUIRES(Locks::mutator_lock_);
   uint64_t GetTotalPausedTimeNs() REQUIRES(!pause_histogram_lock_);
   int64_t GetTotalFreedBytes() const {
     return total_freed_bytes_;
diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h
index 8a12094..4831157 100644
--- a/runtime/gc/collector/mark_compact.h
+++ b/runtime/gc/collector/mark_compact.h
@@ -106,7 +106,7 @@
       REQUIRES(Locks::mutator_lock_);
 
   // Sweeps unmarked objects to complete the garbage collection.
-  void Sweep(bool swap_bitmaps) REQUIRES(Locks::heap_bitmap_lock_);
+  void Sweep(bool swap_bitmaps) REQUIRES(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
   // Sweeps unmarked objects to complete the garbage collection.
   void SweepLargeObjects(bool swap_bitmaps) REQUIRES(Locks::heap_bitmap_lock_);
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 5427f88..64c8e9a 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -1467,7 +1467,9 @@
   }
   CHECK(mark_stack_->IsEmpty());  // Ensure that the mark stack is empty.
   mark_stack_->Reset();
-  WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
+  Thread* const self = Thread::Current();
+  ReaderMutexLock mu(self, *Locks::mutator_lock_);
+  WriterMutexLock mu2(self, *Locks::heap_bitmap_lock_);
   heap_->ClearMarkedObjects();
 }
 
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 245f96b..b61bef7 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -85,7 +85,7 @@
   void Init();
 
   // Find the default mark bitmap.
-  void FindDefaultSpaceBitmap();
+  void FindDefaultSpaceBitmap() SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Marks all objects in the root set at the start of a garbage collection.
   void MarkRoots(Thread* self)
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index a905904..0199e1a 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -135,7 +135,9 @@
       REQUIRES(Locks::mutator_lock_);
 
   // Sweeps unmarked objects to complete the garbage collection.
-  virtual void Sweep(bool swap_bitmaps) REQUIRES(Locks::heap_bitmap_lock_);
+  virtual void Sweep(bool swap_bitmaps)
+      REQUIRES(Locks::heap_bitmap_lock_)
+      SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Sweeps unmarked objects to complete the garbage collection.
   void SweepLargeObjects(bool swap_bitmaps) REQUIRES(Locks::heap_bitmap_lock_);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 8cd8d73..137540a 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -801,6 +801,7 @@
   if (!Runtime::Current()->IsAotCompiler()) {
     return false;
   }
+  ScopedObjectAccess soa(Thread::Current());
   for (const auto& space : continuous_spaces_) {
     if (space->IsImageSpace() || space->IsZygoteSpace()) {
       return false;
@@ -1381,15 +1382,18 @@
   uint64_t total_alloc_space_allocated = 0;
   uint64_t total_alloc_space_size = 0;
   uint64_t managed_reclaimed = 0;
-  for (const auto& space : continuous_spaces_) {
-    if (space->IsMallocSpace()) {
-      gc::space::MallocSpace* malloc_space = space->AsMallocSpace();
-      if (malloc_space->IsRosAllocSpace() || !CareAboutPauseTimes()) {
-        // Don't trim dlmalloc spaces if we care about pauses since this can hold the space lock
-        // for a long period of time.
-        managed_reclaimed += malloc_space->Trim();
+  {
+    ScopedObjectAccess soa(self);
+    for (const auto& space : continuous_spaces_) {
+      if (space->IsMallocSpace()) {
+        gc::space::MallocSpace* malloc_space = space->AsMallocSpace();
+        if (malloc_space->IsRosAllocSpace() || !CareAboutPauseTimes()) {
+          // Don't trim dlmalloc spaces if we care about pauses since this can hold the space lock
+          // for a long period of time.
+          managed_reclaimed += malloc_space->Trim();
+        }
+        total_alloc_space_size += malloc_space->Size();
       }
-      total_alloc_space_size += malloc_space->Size();
     }
   }
   total_alloc_space_allocated = GetBytesAllocated();
@@ -1520,6 +1524,7 @@
 }
 
 void Heap::DumpSpaces(std::ostream& stream) const {
+  ScopedObjectAccess soa(Thread::Current());
   for (const auto& space : continuous_spaces_) {
     accounting::ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
     accounting::ContinuousSpaceBitmap* mark_bitmap = space->GetMarkBitmap();
@@ -1598,6 +1603,9 @@
 }
 
 space::RosAllocSpace* Heap::GetRosAllocSpace(gc::allocator::RosAlloc* rosalloc) const {
+  if (rosalloc_space_ != nullptr && rosalloc_space_->GetRosAlloc() == rosalloc) {
+    return rosalloc_space_;
+  }
   for (const auto& space : continuous_spaces_) {
     if (space->AsContinuousSpace()->IsRosAllocSpace()) {
       if (space->AsContinuousSpace()->AsRosAllocSpace()->GetRosAlloc() == rosalloc) {
@@ -3530,7 +3538,8 @@
 
 void Heap::ClampGrowthLimit() {
   // Use heap bitmap lock to guard against races with BindLiveToMarkBitmap.
-  WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
+  ScopedObjectAccess soa(Thread::Current());
+  WriterMutexLock mu(soa.Self(), *Locks::heap_bitmap_lock_);
   capacity_ = growth_limit_;
   for (const auto& space : continuous_spaces_) {
     if (space->IsMallocSpace()) {
@@ -3546,6 +3555,7 @@
 
 void Heap::ClearGrowthLimit() {
   growth_limit_ = capacity_;
+  ScopedObjectAccess soa(Thread::Current());
   for (const auto& space : continuous_spaces_) {
     if (space->IsMallocSpace()) {
       gc::space::MallocSpace* malloc_space = space->AsMallocSpace();
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 1b7e2c9..c02e2d3 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -308,7 +308,10 @@
   void ThreadFlipEnd(Thread* self) REQUIRES(!*thread_flip_lock_);
 
   // Clear all of the mark bits, doesn't clear bitmaps which have the same live bits as mark bits.
-  void ClearMarkedObjects() REQUIRES(Locks::heap_bitmap_lock_);
+  // Mutator lock is required for GetContinuousSpaces.
+  void ClearMarkedObjects()
+      REQUIRES(Locks::heap_bitmap_lock_)
+      SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Initiates an explicit garbage collection.
   void CollectGarbage(bool clear_soft_references)
@@ -359,8 +362,12 @@
   // due to usage by tests.
   void SetSpaceAsDefault(space::ContinuousSpace* continuous_space)
       REQUIRES(!Locks::heap_bitmap_lock_);
-  void AddSpace(space::Space* space) REQUIRES(!Locks::heap_bitmap_lock_);
-  void RemoveSpace(space::Space* space) REQUIRES(!Locks::heap_bitmap_lock_);
+  void AddSpace(space::Space* space)
+      REQUIRES(!Locks::heap_bitmap_lock_)
+      REQUIRES(Locks::mutator_lock_);
+  void RemoveSpace(space::Space* space)
+    REQUIRES(!Locks::heap_bitmap_lock_)
+    REQUIRES(Locks::mutator_lock_);
 
   // Set target ideal heap utilization ratio, implements
   // dalvik.system.VMRuntime.setTargetHeapUtilization.
@@ -378,7 +385,13 @@
   void UpdateProcessState(ProcessState process_state)
       REQUIRES(!*pending_task_lock_, !*gc_complete_lock_);
 
-  const std::vector<space::ContinuousSpace*>& GetContinuousSpaces() const {
+  bool HaveContinuousSpaces() const NO_THREAD_SAFETY_ANALYSIS {
+    // No lock since vector empty is thread safe.
+    return !continuous_spaces_.empty();
+  }
+
+  const std::vector<space::ContinuousSpace*>& GetContinuousSpaces() const
+      SHARED_REQUIRES(Locks::mutator_lock_) {
     return continuous_spaces_;
   }
 
@@ -518,10 +531,13 @@
   // get the space that corresponds to an object's address. Current implementation searches all
   // spaces in turn. If fail_ok is false then failing to find a space will cause an abort.
   // TODO: consider using faster data structure like binary tree.
-  space::ContinuousSpace* FindContinuousSpaceFromObject(const mirror::Object*, bool fail_ok) const;
+  space::ContinuousSpace* FindContinuousSpaceFromObject(const mirror::Object*, bool fail_ok) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
   space::DiscontinuousSpace* FindDiscontinuousSpaceFromObject(const mirror::Object*,
-                                                              bool fail_ok) const;
-  space::Space* FindSpaceFromObject(const mirror::Object*, bool fail_ok) const;
+                                                              bool fail_ok) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+  space::Space* FindSpaceFromObject(const mirror::Object*, bool fail_ok) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
 
   void DumpForSigQuit(std::ostream& os) REQUIRES(!*gc_complete_lock_);
 
@@ -577,7 +593,9 @@
       REQUIRES(Locks::heap_bitmap_lock_);
 
   // Unbind any bound bitmaps.
-  void UnBindBitmaps() REQUIRES(Locks::heap_bitmap_lock_);
+  void UnBindBitmaps()
+      REQUIRES(Locks::heap_bitmap_lock_)
+      SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Returns the boot image spaces. There may be multiple boot image spaces.
   const std::vector<space::ImageSpace*>& GetBootImageSpaces() const {
@@ -604,7 +622,8 @@
   }
 
   // Return the corresponding rosalloc space.
-  space::RosAllocSpace* GetRosAllocSpace(gc::allocator::RosAlloc* rosalloc) const;
+  space::RosAllocSpace* GetRosAllocSpace(gc::allocator::RosAlloc* rosalloc) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
 
   space::MallocSpace* GetNonMovingSpace() const {
     return non_moving_space_;
@@ -962,7 +981,8 @@
   void ProcessCards(TimingLogger* timings,
                     bool use_rem_sets,
                     bool process_alloc_space_cards,
-                    bool clear_alloc_space_cards);
+                    bool clear_alloc_space_cards)
+      SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Push an object onto the allocation stack.
   void PushOnAllocationStack(Thread* self, mirror::Object** obj)
@@ -1005,10 +1025,10 @@
       REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_);
 
   // All-known continuous spaces, where objects lie within fixed bounds.
-  std::vector<space::ContinuousSpace*> continuous_spaces_;
+  std::vector<space::ContinuousSpace*> continuous_spaces_ GUARDED_BY(Locks::mutator_lock_);
 
   // All-known discontinuous spaces, where objects may be placed throughout virtual memory.
-  std::vector<space::DiscontinuousSpace*> discontinuous_spaces_;
+  std::vector<space::DiscontinuousSpace*> discontinuous_spaces_ GUARDED_BY(Locks::mutator_lock_);
 
   // All-known alloc spaces, where objects may be or have been allocated.
   std::vector<space::AllocSpace*> alloc_spaces_;
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index e754a52..455d28e 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -319,7 +319,7 @@
 namespace allocator {
 
 // Implement the dlmalloc morecore callback.
-void* ArtDlMallocMoreCore(void* mspace, intptr_t increment) {
+void* ArtDlMallocMoreCore(void* mspace, intptr_t increment) SHARED_REQUIRES(Locks::mutator_lock_) {
   Runtime* runtime = Runtime::Current();
   Heap* heap = runtime->GetHeap();
   ::art::gc::space::DlMallocSpace* dlmalloc_space = heap->GetDlMallocSpace();
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 9ff3d8d..891e280 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -30,6 +30,7 @@
 #include "base/time_utils.h"
 #include "base/unix_file/fd_file.h"
 #include "gc/accounting/space_bitmap-inl.h"
+#include "image-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "oat_file.h"
@@ -1032,11 +1033,12 @@
     bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_object_visitor);
     FixupObjectAdapter fixup_adapter(boot_image, boot_oat, app_image, app_oat);
     // Fixup image roots.
-    CHECK(app_image.ContainsSource(reinterpret_cast<uintptr_t>(image_header.GetImageRoots())));
+    CHECK(app_image.ContainsSource(reinterpret_cast<uintptr_t>(
+        image_header.GetImageRoots<kWithoutReadBarrier>())));
     image_header.RelocateImageObjects(app_image.Delta());
     CHECK_EQ(image_header.GetImageBegin(), target_base);
     // Fix up dex cache DexFile pointers.
-    auto* dex_caches = image_header.GetImageRoot(ImageHeader::kDexCaches)->
+    auto* dex_caches = image_header.GetImageRoot<kWithoutReadBarrier>(ImageHeader::kDexCaches)->
         AsObjectArray<mirror::DexCache>();
     for (int32_t i = 0, count = dex_caches->GetLength(); i < count; ++i) {
       mirror::DexCache* dex_cache = dex_caches->Get(i);
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index 49126d2..fd4d0a1 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -247,7 +247,10 @@
 size_t RosAllocSpace::Trim() {
   VLOG(heap) << "RosAllocSpace::Trim() ";
   {
-    MutexLock mu(Thread::Current(), lock_);
+    Thread* const self = Thread::Current();
+    // SOA required for Rosalloc::Trim() -> ArtRosAllocMoreCore() -> Heap::GetRosAllocSpace.
+    ScopedObjectAccess soa(self);
+    MutexLock mu(self, lock_);
     // Trim to release memory at the end of the space.
     rosalloc_->Trim();
   }
@@ -373,7 +376,8 @@
 namespace allocator {
 
 // Callback from rosalloc when it needs to increase the footprint.
-void* ArtRosAllocMoreCore(allocator::RosAlloc* rosalloc, intptr_t increment) {
+void* ArtRosAllocMoreCore(allocator::RosAlloc* rosalloc, intptr_t increment)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
   Heap* heap = Runtime::Current()->GetHeap();
   art::gc::space::RosAllocSpace* rosalloc_space = heap->GetRosAllocSpace(rosalloc);
   DCHECK(rosalloc_space != nullptr);
diff --git a/runtime/gc/space/space_create_test.cc b/runtime/gc/space/space_create_test.cc
index aea2d9f..170f927 100644
--- a/runtime/gc/space/space_create_test.cc
+++ b/runtime/gc/space/space_create_test.cc
@@ -170,7 +170,11 @@
 
   gc::Heap* heap = Runtime::Current()->GetHeap();
   space::Space* old_space = space;
-  heap->RemoveSpace(old_space);
+  {
+    ScopedThreadSuspension sts(self, kSuspended);
+    ScopedSuspendAll ssa("Add image space");
+    heap->RemoveSpace(old_space);
+  }
   heap->RevokeAllThreadLocalBuffers();
   space::ZygoteSpace* zygote_space = space->CreateZygoteSpace("alloc space",
                                                               heap->IsLowMemoryMode(),
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index e588eb3..20ef44a 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -27,6 +27,7 @@
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
 #include "scoped_thread_state_change.h"
+#include "thread_list.h"
 #include "zygote_space.h"
 
 namespace art {
@@ -43,7 +44,11 @@
     if (revoke) {
       heap->RevokeAllThreadLocalBuffers();
     }
-    heap->AddSpace(space);
+    {
+      ScopedThreadStateChange sts(Thread::Current(), kSuspended);
+      ScopedSuspendAll ssa("Add image space");
+      heap->AddSpace(space);
+    }
     heap->SetSpaceAsDefault(space);
   }
 
diff --git a/runtime/handle.h b/runtime/handle.h
index 5b3bb60..a415373 100644
--- a/runtime/handle.h
+++ b/runtime/handle.h
@@ -70,13 +70,11 @@
     return reinterpret_cast<jobject>(reference_);
   }
 
-  ALWAYS_INLINE StackReference<mirror::Object>* GetReference()
-      SHARED_REQUIRES(Locks::mutator_lock_) {
+  ALWAYS_INLINE StackReference<mirror::Object>* GetReference() {
     return reference_;
   }
 
-  ALWAYS_INLINE const StackReference<mirror::Object>* GetReference() const
-      SHARED_REQUIRES(Locks::mutator_lock_) {
+  ALWAYS_INLINE const StackReference<mirror::Object>* GetReference() const {
     return reference_;
   }
 
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index e617348..d53a0e4 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -62,8 +62,7 @@
   ALWAYS_INLINE mirror::Object* GetReference(size_t i) const
       SHARED_REQUIRES(Locks::mutator_lock_);
 
-  ALWAYS_INLINE Handle<mirror::Object> GetHandle(size_t i)
-      SHARED_REQUIRES(Locks::mutator_lock_);
+  ALWAYS_INLINE Handle<mirror::Object> GetHandle(size_t i);
 
   ALWAYS_INLINE MutableHandle<mirror::Object> GetMutableHandle(size_t i)
       SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/image-inl.h b/runtime/image-inl.h
new file mode 100644
index 0000000..e3307d8
--- /dev/null
+++ b/runtime/image-inl.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_IMAGE_INL_H_
+#define ART_RUNTIME_IMAGE_INL_H_
+
+#include "image.h"
+
+namespace art {
+
+template <ReadBarrierOption kReadBarrierOption>
+inline mirror::Object* ImageHeader::GetImageRoot(ImageRoot image_root) const {
+  mirror::ObjectArray<mirror::Object>* image_roots = GetImageRoots<kReadBarrierOption>();
+  return image_roots->Get<kVerifyNone, kReadBarrierOption>(static_cast<int32_t>(image_root));
+}
+
+template <ReadBarrierOption kReadBarrierOption>
+inline mirror::ObjectArray<mirror::Object>* ImageHeader::GetImageRoots() const {
+  // Need a read barrier as it's not visited during root scan.
+  // Pass in the address of the local variable to the read barrier
+  // rather than image_roots_ because it won't move (asserted below)
+  // and it's a const member.
+  mirror::ObjectArray<mirror::Object>* image_roots =
+      reinterpret_cast<mirror::ObjectArray<mirror::Object>*>(image_roots_);
+  mirror::ObjectArray<mirror::Object>* result =
+      ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Object>, kReadBarrierOption>(
+          &image_roots);
+  DCHECK_EQ(image_roots, result);
+  return image_roots;
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_IMAGE_INL_H_
diff --git a/runtime/image.cc b/runtime/image.cc
index 2fed4d3..de00343 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -128,24 +128,6 @@
   return reinterpret_cast<const char*>(magic_);
 }
 
-mirror::Object* ImageHeader::GetImageRoot(ImageRoot image_root) const {
-  return GetImageRoots()->Get(image_root);
-}
-
-mirror::ObjectArray<mirror::Object>* ImageHeader::GetImageRoots() const {
-  // Need a read barrier as it's not visited during root scan.
-  // Pass in the address of the local variable to the read barrier
-  // rather than image_roots_ because it won't move (asserted below)
-  // and it's a const member.
-  mirror::ObjectArray<mirror::Object>* image_roots =
-      reinterpret_cast<mirror::ObjectArray<mirror::Object>*>(image_roots_);
-  mirror::ObjectArray<mirror::Object>* result =
-      ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Object>, kWithReadBarrier>(
-          &image_roots);
-  DCHECK_EQ(image_roots, result);
-  return result;
-}
-
 ArtMethod* ImageHeader::GetImageMethod(ImageMethod index) const {
   CHECK_LT(static_cast<size_t>(index), kImageMethodsCount);
   return reinterpret_cast<ArtMethod*>(image_methods_[index]);
diff --git a/runtime/image.h b/runtime/image.h
index b3f177b..c449e43 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -212,8 +212,11 @@
     return GetImageSection(kSectionArtMethods);
   }
 
+  template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   mirror::Object* GetImageRoot(ImageRoot image_root) const
       SHARED_REQUIRES(Locks::mutator_lock_);
+
+  template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   mirror::ObjectArray<mirror::Object>* GetImageRoots() const
       SHARED_REQUIRES(Locks::mutator_lock_);
 
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 96854da..74a2532 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -22,6 +22,7 @@
 #include "gc/collector/garbage_collector.h"
 #include "gc/space/image_space.h"
 #include "gc/weak_root_state.h"
+#include "image-inl.h"
 #include "mirror/dex_cache-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index ecd4de9..6c9cc70 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -518,10 +518,10 @@
         Dbg::IsForcedInterpreterNeededForCalling(self, target);
 }
 
-static void ArtInterpreterToCompiledCodeBridge(Thread* self,
-                                               const DexFile::CodeItem* code_item,
-                                               ShadowFrame* shadow_frame,
-                                               JValue* result)
+void ArtInterpreterToCompiledCodeBridge(Thread* self,
+                                        const DexFile::CodeItem* code_item,
+                                        ShadowFrame* shadow_frame,
+                                        JValue* result)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ArtMethod* method = shadow_frame->GetMethod();
   // Ensure static methods are initialized.
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 932d255..949112d 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -980,6 +980,9 @@
   return branch_offset <= 0;
 }
 
+void ArtInterpreterToCompiledCodeBridge(Thread* self, const DexFile::CodeItem* code_item,
+                                        ShadowFrame* shadow_frame, JValue* result);
+
 // Explicitly instantiate all DoInvoke functions.
 #define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range, _do_check)                      \
   template SHARED_REQUIRES(Locks::mutator_lock_)                                     \
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index ca00621..d50cfe6 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -21,6 +21,7 @@
 #include "base/stl_util.h"  // MakeUnique
 #include "experimental_flags.h"
 #include "interpreter_common.h"
+#include "jit/jit.h"
 #include "safe_math.h"
 
 #include <memory>  // std::unique_ptr
@@ -183,9 +184,25 @@
       self->AssertNoPendingException();
     }
     instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+    ArtMethod *method = shadow_frame.GetMethod();
+
     if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
       instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
-                                        shadow_frame.GetMethod(), 0);
+                                        method, 0);
+    }
+
+    if (UNLIKELY(Runtime::Current()->GetJit() != nullptr &&
+                 Runtime::Current()->GetJit()->JitAtFirstUse() &&
+                 method->HasAnyCompiledCode())) {
+      JValue result;
+
+      // Pop the shadow frame before calling into compiled code.
+      self->PopShadowFrame();
+      ArtInterpreterToCompiledCodeBridge(self, code_item, &shadow_frame, &result);
+      // Push the shadow frame back as the caller will expect it.
+      self->PushShadowFrame(&shadow_frame);
+
+      return result;
     }
   }
 
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index c3b75b2..56a213c 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -17,6 +17,7 @@
 #include "base/stl_util.h"  // MakeUnique
 #include "experimental_flags.h"
 #include "interpreter_common.h"
+#include "jit/jit.h"
 #include "safe_math.h"
 
 #include <memory>  // std::unique_ptr
@@ -96,9 +97,26 @@
     if (kIsDebugBuild) {
         self->AssertNoPendingException();
     }
+
+    ArtMethod* method = shadow_frame.GetMethod();
+
     if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
       instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
-                                        shadow_frame.GetMethod(), 0);
+                                        method, 0);
+    }
+
+    if (UNLIKELY(Runtime::Current()->GetJit() != nullptr &&
+                 Runtime::Current()->GetJit()->JitAtFirstUse() &&
+                 method->HasAnyCompiledCode())) {
+      JValue result;
+
+      // Pop the shadow frame before calling into compiled code.
+      self->PopShadowFrame();
+      ArtInterpreterToCompiledCodeBridge(self, code_item, &shadow_frame, &result);
+      // Push the shadow frame back as the caller will expect it.
+      self->PushShadowFrame(&shadow_frame);
+
+      return result;
     }
   }
   const uint16_t* const insns = code_item->insns_;
diff --git a/runtime/interpreter/mterp/arm/footer.S b/runtime/interpreter/mterp/arm/footer.S
index 617f572..1dba856 100644
--- a/runtime/interpreter/mterp/arm/footer.S
+++ b/runtime/interpreter/mterp/arm/footer.S
@@ -150,12 +150,8 @@
     b MterpDone
 MterpReturn:
     ldr     r2, [rFP, #OFF_FP_RESULT_REGISTER]
-    ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
     str     r0, [r2]
     str     r1, [r2, #4]
-    mov     r0, rSELF
-    ands    lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
-    blne    MterpSuspendCheck                       @ (self)
     mov     r0, #1                                  @ signal return to caller.
 MterpDone:
     add     sp, sp, #4                              @ un-align 64
diff --git a/runtime/interpreter/mterp/arm/op_check_cast.S b/runtime/interpreter/mterp/arm/op_check_cast.S
index 3e3ac70..24eba45 100644
--- a/runtime/interpreter/mterp/arm/op_check_cast.S
+++ b/runtime/interpreter/mterp/arm/op_check_cast.S
@@ -5,10 +5,10 @@
     EXPORT_PC
     FETCH    r0, 1                      @ r0<- BBBB
     mov      r1, rINST, lsr #8          @ r1<- AA
-    GET_VREG r1, r1                     @ r1<- object
+    VREG_INDEX_TO_ADDR r1, r1           @ r1<- &object
     ldr      r2, [rFP, #OFF_FP_METHOD]  @ r2<- method
     mov      r3, rSELF                  @ r3<- self
-    bl       MterpCheckCast             @ (index, obj, method, self)
+    bl       MterpCheckCast             @ (index, &obj, method, self)
     PREFETCH_INST 2
     cmp      r0, #0
     bne      MterpPossibleException
diff --git a/runtime/interpreter/mterp/arm/op_instance_of.S b/runtime/interpreter/mterp/arm/op_instance_of.S
index e94108c..d76f0b0 100644
--- a/runtime/interpreter/mterp/arm/op_instance_of.S
+++ b/runtime/interpreter/mterp/arm/op_instance_of.S
@@ -8,12 +8,12 @@
     EXPORT_PC
     FETCH     r0, 1                     @ r0<- CCCC
     mov       r1, rINST, lsr #12        @ r1<- B
-    GET_VREG  r1, r1                    @ r1<- vB (object)
+    VREG_INDEX_TO_ADDR r1, r1           @ r1<- &object
     ldr       r2, [rFP, #OFF_FP_METHOD] @ r2<- method
     mov       r3, rSELF                 @ r3<- self
     mov       r9, rINST, lsr #8         @ r9<- A+
     and       r9, r9, #15               @ r9<- A
-    bl        MterpInstanceOf           @ (index, obj, method, self)
+    bl        MterpInstanceOf           @ (index, &obj, method, self)
     ldr       r1, [rSELF, #THREAD_EXCEPTION_OFFSET]
     PREFETCH_INST 2
     cmp       r1, #0                    @ exception pending?
diff --git a/runtime/interpreter/mterp/arm/op_return.S b/runtime/interpreter/mterp/arm/op_return.S
index a4ffd04..1888373 100644
--- a/runtime/interpreter/mterp/arm/op_return.S
+++ b/runtime/interpreter/mterp/arm/op_return.S
@@ -6,6 +6,10 @@
     /* op vAA */
     .extern MterpThreadFenceForConstructor
     bl      MterpThreadFenceForConstructor
+    ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
+    mov     r0, rSELF
+    ands    lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    blne    MterpSuspendCheck                       @ (self)
     mov     r2, rINST, lsr #8           @ r2<- AA
     GET_VREG r0, r2                     @ r0<- vAA
     mov     r1, #0
diff --git a/runtime/interpreter/mterp/arm/op_return_void.S b/runtime/interpreter/mterp/arm/op_return_void.S
index f6dfd99..cbea2bf 100644
--- a/runtime/interpreter/mterp/arm/op_return_void.S
+++ b/runtime/interpreter/mterp/arm/op_return_void.S
@@ -1,5 +1,9 @@
     .extern MterpThreadFenceForConstructor
     bl      MterpThreadFenceForConstructor
+    ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
+    mov     r0, rSELF
+    ands    lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    blne    MterpSuspendCheck                       @ (self)
     mov    r0, #0
     mov    r1, #0
     b      MterpReturn
diff --git a/runtime/interpreter/mterp/arm/op_return_void_no_barrier.S b/runtime/interpreter/mterp/arm/op_return_void_no_barrier.S
index 7322940..2dde7ae 100644
--- a/runtime/interpreter/mterp/arm/op_return_void_no_barrier.S
+++ b/runtime/interpreter/mterp/arm/op_return_void_no_barrier.S
@@ -1,3 +1,7 @@
+    ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
+    mov     r0, rSELF
+    ands    lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    blne    MterpSuspendCheck                       @ (self)
     mov    r0, #0
     mov    r1, #0
     b      MterpReturn
diff --git a/runtime/interpreter/mterp/arm/op_return_wide.S b/runtime/interpreter/mterp/arm/op_return_wide.S
index 2881c87..cfab530 100644
--- a/runtime/interpreter/mterp/arm/op_return_wide.S
+++ b/runtime/interpreter/mterp/arm/op_return_wide.S
@@ -4,6 +4,10 @@
     /* return-wide vAA */
     .extern MterpThreadFenceForConstructor
     bl      MterpThreadFenceForConstructor
+    ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
+    mov     r0, rSELF
+    ands    lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    blne    MterpSuspendCheck                       @ (self)
     mov     r2, rINST, lsr #8           @ r2<- AA
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[AA]
     ldmia   r2, {r0-r1}                 @ r0/r1 <- vAA/vAA+1
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 9975458..0afd276 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -274,13 +274,15 @@
   return false;
 }
 
-extern "C" bool MterpCheckCast(uint32_t index, Object* obj, art::ArtMethod* method,
-                               Thread* self)
+extern "C" bool MterpCheckCast(uint32_t index, StackReference<mirror::Object>* vreg_addr,
+                               art::ArtMethod* method, Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
   if (UNLIKELY(c == nullptr)) {
     return true;
   }
+  // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
+  Object* obj = vreg_addr->AsMirrorPtr();
   if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
     ThrowClassCastException(c, obj->GetClass());
     return true;
@@ -288,13 +290,15 @@
   return false;
 }
 
-extern "C" bool MterpInstanceOf(uint32_t index, Object* obj, art::ArtMethod* method,
-                                Thread* self)
+extern "C" bool MterpInstanceOf(uint32_t index, StackReference<mirror::Object>* vreg_addr,
+                                art::ArtMethod* method, Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   Class* c = ResolveVerifyAndClinit(index, method, self, false, false);
   if (UNLIKELY(c == nullptr)) {
     return false;  // Caller will check for pending exception.  Return value unimportant.
   }
+  // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
+  Object* obj = vreg_addr->AsMirrorPtr();
   return (obj != nullptr) && obj->InstanceOf(c);
 }
 
@@ -505,8 +509,7 @@
                                                uint64_t* new_value, Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
-  ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite,
-                                          sizeof(int64_t));
+  ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t));
   if (LIKELY(field != nullptr)) {
     // Compiled code can't use transactional mode.
     field->Set64<false>(field->GetDeclaringClass(), *new_value);
@@ -524,8 +527,7 @@
 extern "C" int artSet8InstanceFromMterp(uint32_t field_idx, mirror::Object* obj, uint8_t new_value,
                                         ArtMethod* referrer)
     SHARED_REQUIRES(Locks::mutator_lock_) {
-  ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
-                                          sizeof(int8_t));
+  ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int8_t));
   if (LIKELY(field != nullptr && obj != nullptr)) {
     Primitive::Type type = field->GetTypeAsPrimitiveType();
     if (type == Primitive::kPrimBoolean) {
@@ -582,7 +584,7 @@
 }
 
 extern "C" int artSetObjInstanceFromMterp(uint32_t field_idx, mirror::Object* obj,
-                                         mirror::Object* new_value, ArtMethod* referrer)
+                                          mirror::Object* new_value, ArtMethod* referrer)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
                                           sizeof(mirror::HeapReference<mirror::Object>));
diff --git a/runtime/interpreter/mterp/out/mterp_arm.S b/runtime/interpreter/mterp/out/mterp_arm.S
index 9ae98a2..78c784b 100644
--- a/runtime/interpreter/mterp/out/mterp_arm.S
+++ b/runtime/interpreter/mterp/out/mterp_arm.S
@@ -599,6 +599,10 @@
 /* File: arm/op_return_void.S */
     .extern MterpThreadFenceForConstructor
     bl      MterpThreadFenceForConstructor
+    ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
+    mov     r0, rSELF
+    ands    lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    blne    MterpSuspendCheck                       @ (self)
     mov    r0, #0
     mov    r1, #0
     b      MterpReturn
@@ -615,6 +619,10 @@
     /* op vAA */
     .extern MterpThreadFenceForConstructor
     bl      MterpThreadFenceForConstructor
+    ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
+    mov     r0, rSELF
+    ands    lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    blne    MterpSuspendCheck                       @ (self)
     mov     r2, rINST, lsr #8           @ r2<- AA
     GET_VREG r0, r2                     @ r0<- vAA
     mov     r1, #0
@@ -630,6 +638,10 @@
     /* return-wide vAA */
     .extern MterpThreadFenceForConstructor
     bl      MterpThreadFenceForConstructor
+    ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
+    mov     r0, rSELF
+    ands    lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    blne    MterpSuspendCheck                       @ (self)
     mov     r2, rINST, lsr #8           @ r2<- AA
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[AA]
     ldmia   r2, {r0-r1}                 @ r0/r1 <- vAA/vAA+1
@@ -648,6 +660,10 @@
     /* op vAA */
     .extern MterpThreadFenceForConstructor
     bl      MterpThreadFenceForConstructor
+    ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
+    mov     r0, rSELF
+    ands    lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    blne    MterpSuspendCheck                       @ (self)
     mov     r2, rINST, lsr #8           @ r2<- AA
     GET_VREG r0, r2                     @ r0<- vAA
     mov     r1, #0
@@ -878,10 +894,10 @@
     EXPORT_PC
     FETCH    r0, 1                      @ r0<- BBBB
     mov      r1, rINST, lsr #8          @ r1<- AA
-    GET_VREG r1, r1                     @ r1<- object
+    VREG_INDEX_TO_ADDR r1, r1           @ r1<- &object
     ldr      r2, [rFP, #OFF_FP_METHOD]  @ r2<- method
     mov      r3, rSELF                  @ r3<- self
-    bl       MterpCheckCast             @ (index, obj, method, self)
+    bl       MterpCheckCast             @ (index, &obj, method, self)
     PREFETCH_INST 2
     cmp      r0, #0
     bne      MterpPossibleException
@@ -903,12 +919,12 @@
     EXPORT_PC
     FETCH     r0, 1                     @ r0<- CCCC
     mov       r1, rINST, lsr #12        @ r1<- B
-    GET_VREG  r1, r1                    @ r1<- vB (object)
+    VREG_INDEX_TO_ADDR r1, r1           @ r1<- &object
     ldr       r2, [rFP, #OFF_FP_METHOD] @ r2<- method
     mov       r3, rSELF                 @ r3<- self
     mov       r9, rINST, lsr #8         @ r9<- A+
     and       r9, r9, #15               @ r9<- A
-    bl        MterpInstanceOf           @ (index, obj, method, self)
+    bl        MterpInstanceOf           @ (index, &obj, method, self)
     ldr       r1, [rSELF, #THREAD_EXCEPTION_OFFSET]
     PREFETCH_INST 2
     cmp       r1, #0                    @ exception pending?
@@ -3385,6 +3401,10 @@
     .balign 128
 .L_op_return_void_no_barrier: /* 0x73 */
 /* File: arm/op_return_void_no_barrier.S */
+    ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
+    mov     r0, rSELF
+    ands    lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    blne    MterpSuspendCheck                       @ (self)
     mov    r0, #0
     mov    r1, #0
     b      MterpReturn
@@ -12183,12 +12203,8 @@
     b MterpDone
 MterpReturn:
     ldr     r2, [rFP, #OFF_FP_RESULT_REGISTER]
-    ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
     str     r0, [r2]
     str     r1, [r2, #4]
-    mov     r0, rSELF
-    ands    lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
-    blne    MterpSuspendCheck                       @ (self)
     mov     r0, #1                                  @ signal return to caller.
 MterpDone:
     add     sp, sp, #4                              @ un-align 64
diff --git a/runtime/interpreter/mterp/out/mterp_x86.S b/runtime/interpreter/mterp/out/mterp_x86.S
index 923d502..e2918dc 100644
--- a/runtime/interpreter/mterp/out/mterp_x86.S
+++ b/runtime/interpreter/mterp/out/mterp_x86.S
@@ -575,6 +575,12 @@
 /* File: x86/op_return_void.S */
     .extern MterpThreadFenceForConstructor
     call    MterpThreadFenceForConstructor
+    movl    rSELF, %eax
+    testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
+    jz      1f
+    movl    %eax, OUT_ARG0(%esp)
+    call    MterpSuspendCheck
+1:
     xorl    %eax, %eax
     xorl    %ecx, %ecx
     jmp     MterpReturn
@@ -591,6 +597,12 @@
     /* op vAA */
     .extern MterpThreadFenceForConstructor
     call    MterpThreadFenceForConstructor
+    movl    rSELF, %eax
+    testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
+    jz      1f
+    movl    %eax, OUT_ARG0(%esp)
+    call    MterpSuspendCheck
+1:
     GET_VREG %eax rINST                     # eax <- vAA
     xorl    %ecx, %ecx
     jmp     MterpReturn
@@ -605,6 +617,12 @@
     /* return-wide vAA */
     .extern MterpThreadFenceForConstructor
     call    MterpThreadFenceForConstructor
+    movl    rSELF, %eax
+    testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
+    jz      1f
+    movl    %eax, OUT_ARG0(%esp)
+    call    MterpSuspendCheck
+1:
     GET_VREG %eax rINST                     # eax <- v[AA+0]
     GET_VREG_HIGH %ecx rINST                # ecx <- v[AA+1]
     jmp     MterpReturn
@@ -622,6 +640,12 @@
     /* op vAA */
     .extern MterpThreadFenceForConstructor
     call    MterpThreadFenceForConstructor
+    movl    rSELF, %eax
+    testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
+    jz      1f
+    movl    %eax, OUT_ARG0(%esp)
+    call    MterpSuspendCheck
+1:
     GET_VREG %eax rINST                     # eax <- vAA
     xorl    %ecx, %ecx
     jmp     MterpReturn
@@ -827,13 +851,13 @@
     EXPORT_PC
     movzwl  2(rPC), %eax                    # eax <- BBBB
     movl    %eax, OUT_ARG0(%esp)
-    GET_VREG %ecx rINST
+    leal    VREG_ADDRESS(rINST), %ecx
     movl    %ecx, OUT_ARG1(%esp)
     movl    OFF_FP_METHOD(rFP),%eax
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpCheckCast                  # (index, obj, method, self)
+    call    MterpCheckCast                  # (index, &obj, method, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpPossibleException
@@ -855,13 +879,13 @@
     movl    %eax, OUT_ARG0(%esp)
     movl    rINST, %eax                     # eax <- BA
     sarl    $4, %eax                       # eax <- B
-    GET_VREG %ecx %eax                      # Get object
+    leal    VREG_ADDRESS(%eax), %ecx        # Get object address
     movl    %ecx, OUT_ARG1(%esp)
     movl    OFF_FP_METHOD(rFP),%eax
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpInstanceOf                 # (index, obj, method, self)
+    call    MterpInstanceOf                 # (index, &obj, method, self)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
@@ -3145,6 +3169,12 @@
     .balign 128
 .L_op_return_void_no_barrier: /* 0x73 */
 /* File: x86/op_return_void_no_barrier.S */
+    movl    rSELF, %eax
+    testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
+    jz      1f
+    movl    %eax, OUT_ARG0(%esp)
+    call    MterpSuspendCheck
+1:
     xorl    %eax, %eax
     xorl    %ecx, %ecx
     jmp     MterpReturn
@@ -12921,12 +12951,6 @@
     movl    OFF_FP_RESULT_REGISTER(rFP), %edx
     movl    %eax, (%edx)
     movl    %ecx, 4(%edx)
-    movl    rSELF, %eax
-    testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
-    jz      1f
-    movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
-1:
     mov     $1, %eax
 MterpDone:
     /* Restore callee save register */
diff --git a/runtime/interpreter/mterp/x86/footer.S b/runtime/interpreter/mterp/x86/footer.S
index 8f79b37..a2a36c4 100644
--- a/runtime/interpreter/mterp/x86/footer.S
+++ b/runtime/interpreter/mterp/x86/footer.S
@@ -169,12 +169,6 @@
     movl    OFF_FP_RESULT_REGISTER(rFP), %edx
     movl    %eax, (%edx)
     movl    %ecx, 4(%edx)
-    movl    rSELF, %eax
-    testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
-    jz      1f
-    movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
-1:
     mov     $$1, %eax
 MterpDone:
     /* Restore callee save register */
diff --git a/runtime/interpreter/mterp/x86/op_check_cast.S b/runtime/interpreter/mterp/x86/op_check_cast.S
index 3d85f5e..018432a 100644
--- a/runtime/interpreter/mterp/x86/op_check_cast.S
+++ b/runtime/interpreter/mterp/x86/op_check_cast.S
@@ -5,13 +5,13 @@
     EXPORT_PC
     movzwl  2(rPC), %eax                    # eax <- BBBB
     movl    %eax, OUT_ARG0(%esp)
-    GET_VREG %ecx rINST
+    leal    VREG_ADDRESS(rINST), %ecx
     movl    %ecx, OUT_ARG1(%esp)
     movl    OFF_FP_METHOD(rFP),%eax
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpCheckCast                  # (index, obj, method, self)
+    call    MterpCheckCast                  # (index, &obj, method, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpPossibleException
diff --git a/runtime/interpreter/mterp/x86/op_instance_of.S b/runtime/interpreter/mterp/x86/op_instance_of.S
index cfbd4a0..c9bfba5 100644
--- a/runtime/interpreter/mterp/x86/op_instance_of.S
+++ b/runtime/interpreter/mterp/x86/op_instance_of.S
@@ -10,13 +10,13 @@
     movl    %eax, OUT_ARG0(%esp)
     movl    rINST, %eax                     # eax <- BA
     sarl    $$4, %eax                       # eax <- B
-    GET_VREG %ecx %eax                      # Get object
+    leal    VREG_ADDRESS(%eax), %ecx        # Get object address
     movl    %ecx, OUT_ARG1(%esp)
     movl    OFF_FP_METHOD(rFP),%eax
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpInstanceOf                 # (index, obj, method, self)
+    call    MterpInstanceOf                 # (index, &obj, method, self)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
diff --git a/runtime/interpreter/mterp/x86/op_return.S b/runtime/interpreter/mterp/x86/op_return.S
index 1658322..183b3bf 100644
--- a/runtime/interpreter/mterp/x86/op_return.S
+++ b/runtime/interpreter/mterp/x86/op_return.S
@@ -6,6 +6,12 @@
     /* op vAA */
     .extern MterpThreadFenceForConstructor
     call    MterpThreadFenceForConstructor
+    movl    rSELF, %eax
+    testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
+    jz      1f
+    movl    %eax, OUT_ARG0(%esp)
+    call    MterpSuspendCheck
+1:
     GET_VREG %eax rINST                     # eax <- vAA
     xorl    %ecx, %ecx
     jmp     MterpReturn
diff --git a/runtime/interpreter/mterp/x86/op_return_void.S b/runtime/interpreter/mterp/x86/op_return_void.S
index b74446e..f3e24c7 100644
--- a/runtime/interpreter/mterp/x86/op_return_void.S
+++ b/runtime/interpreter/mterp/x86/op_return_void.S
@@ -1,5 +1,11 @@
     .extern MterpThreadFenceForConstructor
     call    MterpThreadFenceForConstructor
+    movl    rSELF, %eax
+    testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
+    jz      1f
+    movl    %eax, OUT_ARG0(%esp)
+    call    MterpSuspendCheck
+1:
     xorl    %eax, %eax
     xorl    %ecx, %ecx
     jmp     MterpReturn
diff --git a/runtime/interpreter/mterp/x86/op_return_void_no_barrier.S b/runtime/interpreter/mterp/x86/op_return_void_no_barrier.S
index abc7c4d..add4e20 100644
--- a/runtime/interpreter/mterp/x86/op_return_void_no_barrier.S
+++ b/runtime/interpreter/mterp/x86/op_return_void_no_barrier.S
@@ -1,3 +1,9 @@
+    movl    rSELF, %eax
+    testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
+    jz      1f
+    movl    %eax, OUT_ARG0(%esp)
+    call    MterpSuspendCheck
+1:
     xorl    %eax, %eax
     xorl    %ecx, %ecx
     jmp     MterpReturn
diff --git a/runtime/interpreter/mterp/x86/op_return_wide.S b/runtime/interpreter/mterp/x86/op_return_wide.S
index 00effd6..34a3380 100644
--- a/runtime/interpreter/mterp/x86/op_return_wide.S
+++ b/runtime/interpreter/mterp/x86/op_return_wide.S
@@ -4,6 +4,12 @@
     /* return-wide vAA */
     .extern MterpThreadFenceForConstructor
     call    MterpThreadFenceForConstructor
+    movl    rSELF, %eax
+    testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
+    jz      1f
+    movl    %eax, OUT_ARG0(%esp)
+    call    MterpSuspendCheck
+1:
     GET_VREG %eax rINST                     # eax <- v[AA+0]
     GET_VREG_HIGH %ecx rINST                # ecx <- v[AA+1]
     jmp     MterpReturn
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 8f4d24f..f540814 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -202,6 +202,13 @@
   }
 }
 
+bool Jit::JitAtFirstUse() {
+  if (instrumentation_cache_ != nullptr) {
+    return instrumentation_cache_->HotMethodThreshold() == 0;
+  }
+  return false;
+}
+
 Jit::~Jit() {
   DCHECK(!save_profiling_info_ || !ProfileSaver::IsStarted());
   if (dump_info_on_shutdown_) {
@@ -217,7 +224,6 @@
 }
 
 void Jit::CreateInstrumentationCache(size_t compile_threshold, size_t warmup_threshold) {
-  CHECK_GT(compile_threshold, 0U);
   instrumentation_cache_.reset(
       new jit::JitInstrumentationCache(compile_threshold, warmup_threshold));
 }
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 429edf6..a80f51f 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -86,6 +86,8 @@
   // into the specified class linker to the jit debug interface,
   void DumpTypeInfoForLoadedTypes(ClassLinker* linker);
 
+  bool JitAtFirstUse();
+
  private:
   Jit();
   bool LoadCompiler(std::string* error_msg);
@@ -142,6 +144,10 @@
   void SetSaveProfilingInfo(bool b) {
     save_profiling_info_ = b;
   }
+  void SetJitAtFirstUse() {
+    use_jit_ = true;
+    compile_threshold_ = 0;
+  }
 
  private:
   bool use_jit_;
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 64b2c89..bec6e13 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -719,7 +719,7 @@
   }
 }
 
-void JitCodeCache::GetCompiledArtMethods(const std::set<const std::string>& dex_base_locations,
+void JitCodeCache::GetCompiledArtMethods(const std::set<std::string>& dex_base_locations,
                                          std::vector<ArtMethod*>& methods) {
   MutexLock mu(Thread::Current(), lock_);
   for (auto it : method_code_map_) {
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 67fa928..69fc553 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -153,7 +153,7 @@
   void* MoreCore(const void* mspace, intptr_t increment);
 
   // Adds to `methods` all the compiled ArtMethods which are part of any of the given dex locations.
-  void GetCompiledArtMethods(const std::set<const std::string>& dex_base_locations,
+  void GetCompiledArtMethods(const std::set<std::string>& dex_base_locations,
                              std::vector<ArtMethod*>& methods)
       REQUIRES(!lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/jit/jit_instrumentation.cc b/runtime/jit/jit_instrumentation.cc
index 6b47b67..d597b36 100644
--- a/runtime/jit/jit_instrumentation.cc
+++ b/runtime/jit/jit_instrumentation.cc
@@ -162,6 +162,14 @@
                                                mirror::Object* /*this_object*/,
                                                ArtMethod* method,
                                                uint32_t /*dex_pc*/) {
+  if (UNLIKELY(Runtime::Current()->GetJit()->JitAtFirstUse())) {
+    // The compiler requires a ProfilingInfo object.
+    ProfilingInfo::Create(thread, method, /* retry_allocation */ true);
+    JitCompileTask compile_task(method, JitCompileTask::kCompile);
+    compile_task.Run(thread);
+    return;
+  }
+
   instrumentation_cache_->AddSamples(thread, method, 1);
 }
 
diff --git a/runtime/jit/jit_instrumentation.h b/runtime/jit/jit_instrumentation.h
index 620c087..06559ad 100644
--- a/runtime/jit/jit_instrumentation.h
+++ b/runtime/jit/jit_instrumentation.h
@@ -101,6 +101,11 @@
       SHARED_REQUIRES(Locks::mutator_lock_);
   void CreateThreadPool();
   void DeleteThreadPool(Thread* self);
+
+  size_t HotMethodThreshold() const {
+    return hot_method_threshold_;
+  }
+
   // Wait until there is no more pending compilation tasks.
   void WaitForCompilationToFinish(Thread* self);
 
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index f3f5f95..b1a5a4b 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -42,13 +42,12 @@
 ProfileSaver::ProfileSaver(const std::string& output_filename,
                            jit::JitCodeCache* jit_code_cache,
                            const std::vector<std::string>& code_paths)
-    : output_filename_(output_filename),
-      jit_code_cache_(jit_code_cache),
-      tracked_dex_base_locations_(code_paths.begin(), code_paths.end()),
+    : jit_code_cache_(jit_code_cache),
       code_cache_last_update_time_ns_(0),
       shutting_down_(false),
       wait_lock_("ProfileSaver wait lock"),
       period_condition_("ProfileSaver period condition", wait_lock_) {
+  AddTrackedLocations(output_filename, code_paths);
 }
 
 void ProfileSaver::Run() {
@@ -86,8 +85,6 @@
 }
 
 bool ProfileSaver::ProcessProfilingInfo() {
-  VLOG(profiler) << "Save profiling information to: " << output_filename_;
-
   uint64_t last_update_time_ns = jit_code_cache_->GetLastUpdateTimeNs();
   if (last_update_time_ns - code_cache_last_update_time_ns_
       < kMinimumTimeBetweenCodeCacheUpdatesNs) {
@@ -99,18 +96,36 @@
 
   uint64_t start = NanoTime();
   code_cache_last_update_time_ns_ = last_update_time_ns;
-  std::vector<ArtMethod*> methods;
+  SafeMap<std::string, std::set<std::string>> tracked_locations;
   {
-    ScopedObjectAccess soa(Thread::Current());
-    jit_code_cache_->GetCompiledArtMethods(tracked_dex_base_locations_, methods);
+    // Make a copy so that we don't hold the lock while doing I/O.
+    MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
+    tracked_locations = tracked_dex_base_locations_;
   }
-  if (methods.size() < kMinimumNrOrMethodsToSave) {
-    VLOG(profiler) << "Not enough information to save. Nr of methods: " << methods.size();
-    return false;
-  }
+  for (const auto& it : tracked_locations) {
+    if (ShuttingDown(Thread::Current())) {
+      return true;
+    }
+    const std::string& filename = it.first;
+    const std::set<std::string>& locations = it.second;
+    std::vector<ArtMethod*> methods;
+    {
+      ScopedObjectAccess soa(Thread::Current());
+      jit_code_cache_->GetCompiledArtMethods(locations, methods);
+    }
+    if (methods.size() < kMinimumNrOrMethodsToSave) {
+      VLOG(profiler) << "Not enough information to save to: " << filename
+          <<" Nr of methods: " << methods.size();
+      return false;
+    }
 
-  ProfileCompilationInfo::SaveProfilingInfo(output_filename_, methods);
-  VLOG(profiler) << "Profile process time: " << PrettyDuration(NanoTime() - start);
+    if (!ProfileCompilationInfo::SaveProfilingInfo(filename, methods)) {
+      LOG(WARNING) << "Could not save profiling info to " << filename;
+      return false;
+    }
+
+    VLOG(profiler) << "Profile process time: " << PrettyDuration(NanoTime() - start);
+  }
   return true;
 }
 
@@ -137,9 +152,13 @@
   DCHECK(jit_code_cache != nullptr);
 
   MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
-  // Don't start two profile saver threads.
   if (instance_ != nullptr) {
-    DCHECK(false) << "Tried to start two profile savers";
+    // If we already have an instance, make sure it uses the same jit_code_cache.
+    // This may be called multiple times via Runtime::registerAppInfo (e.g. for
+    // apps which share the same runtime).
+    DCHECK_EQ(instance_->jit_code_cache_, jit_code_cache);
+    // Add the code_paths to the tracked locations.
+    instance_->AddTrackedLocations(output_filename, code_paths);
     return;
   }
 
@@ -161,7 +180,7 @@
 
   {
     MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
-    VLOG(profiler) << "Stopping profile saver thread for file: " << instance_->output_filename_;
+    VLOG(profiler) << "Stopping profile saver thread";
     profile_saver = instance_;
     profiler_pthread = profiler_pthread_;
     if (instance_ == nullptr) {
@@ -202,4 +221,15 @@
   return instance_ != nullptr;
 }
 
+void ProfileSaver::AddTrackedLocations(const std::string& output_filename,
+                                       const std::vector<std::string>& code_paths) {
+  auto it = tracked_dex_base_locations_.find(output_filename);
+  if (it == tracked_dex_base_locations_.end()) {
+    tracked_dex_base_locations_.Put(output_filename,
+                                    std::set<std::string>(code_paths.begin(), code_paths.end()));
+  } else {
+    it->second.insert(code_paths.begin(), code_paths.end());
+  }
+}
+
 }   // namespace art
diff --git a/runtime/jit/profile_saver.h b/runtime/jit/profile_saver.h
index d60142b..3342790 100644
--- a/runtime/jit/profile_saver.h
+++ b/runtime/jit/profile_saver.h
@@ -20,12 +20,14 @@
 #include "base/mutex.h"
 #include "jit_code_cache.h"
 #include "offline_profiling_info.h"
+#include "safe_map.h"
 
 namespace art {
 
 class ProfileSaver {
  public:
-  // Starts the profile saver thread.
+  // Starts the profile saver thread if not already started.
+  // If the saver is already running it adds (output_filename, code_paths) to its tracked locations.
   static void Start(const std::string& output_filename,
                     jit::JitCodeCache* jit_code_cache,
                     const std::vector<std::string>& code_paths)
@@ -58,14 +60,18 @@
   // Returns true if the saver is shutting down (ProfileSaver::Stop() has been called).
   bool ShuttingDown(Thread* self) REQUIRES(!Locks::profiler_lock_);
 
+  void AddTrackedLocations(const std::string& output_filename,
+                           const std::vector<std::string>& code_paths)
+      REQUIRES(Locks::profiler_lock_);
+
   // The only instance of the saver.
   static ProfileSaver* instance_ GUARDED_BY(Locks::profiler_lock_);
   // Profile saver thread.
   static pthread_t profiler_pthread_ GUARDED_BY(Locks::profiler_lock_);
 
-  const std::string output_filename_;
   jit::JitCodeCache* jit_code_cache_;
-  const std::set<const std::string> tracked_dex_base_locations_;
+  SafeMap<std::string, std::set<std::string>> tracked_dex_base_locations_
+      GUARDED_BY(Locks::profiler_lock_);
   uint64_t code_cache_last_update_time_ns_;
   bool shutting_down_ GUARDED_BY(Locks::profiler_lock_);
 
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index 7b058d0..692c6cb 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -50,7 +50,7 @@
   CHECK_EQ(num_resolved_fields != 0u, resolved_fields != nullptr);
 
   SetDexFile(dex_file);
-  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location);
+  SetLocation(location);
   SetStrings(strings);
   SetResolvedTypes(resolved_types);
   SetResolvedMethods(resolved_methods);
@@ -79,5 +79,9 @@
   }
 }
 
+void DexCache::SetLocation(mirror::String* location) {
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location);
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 5ed061f..0002076 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -191,11 +191,12 @@
     return GetFieldPtr<const DexFile*>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_));
   }
 
-  void SetDexFile(const DexFile* dex_file) SHARED_REQUIRES(Locks::mutator_lock_)
-      ALWAYS_INLINE {
-    return SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file);
+  void SetDexFile(const DexFile* dex_file) SHARED_REQUIRES(Locks::mutator_lock_) {
+    SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file);
   }
 
+  void SetLocation(mirror::String* location) SHARED_REQUIRES(Locks::mutator_lock_);
+
   // NOTE: Get/SetElementPtrSize() are intended for working with ArtMethod** and ArtField**
   // provided by GetResolvedMethods/Fields() and ArtMethod::GetDexCacheResolvedMethods(),
   // so they need to be public.
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index 8febb62..8f108fa 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -314,32 +314,33 @@
   size_t largeObjectsSize = 0;
   size_t largeObjectsUsed = 0;
   gc::Heap* heap = Runtime::Current()->GetHeap();
-  for (gc::space::ContinuousSpace* space : heap->GetContinuousSpaces()) {
-    if (space->IsImageSpace()) {
-      // Currently don't include the image space.
-    } else if (space->IsZygoteSpace()) {
-      gc::space::ZygoteSpace* zygote_space = space->AsZygoteSpace();
-      zygoteSize += zygote_space->Size();
-      zygoteUsed += zygote_space->GetBytesAllocated();
-    } else if (space->IsMallocSpace()) {
-      // This is a malloc space.
-      gc::space::MallocSpace* malloc_space = space->AsMallocSpace();
-      allocSize += malloc_space->GetFootprint();
-      allocUsed += malloc_space->GetBytesAllocated();
-    } else if (space->IsBumpPointerSpace()) {
-      ScopedObjectAccess soa(env);
-      gc::space::BumpPointerSpace* bump_pointer_space = space->AsBumpPointerSpace();
-      allocSize += bump_pointer_space->Size();
-      allocUsed += bump_pointer_space->GetBytesAllocated();
+  {
+    ScopedObjectAccess soa(env);
+    for (gc::space::ContinuousSpace* space : heap->GetContinuousSpaces()) {
+      if (space->IsImageSpace()) {
+        // Currently don't include the image space.
+      } else if (space->IsZygoteSpace()) {
+        gc::space::ZygoteSpace* zygote_space = space->AsZygoteSpace();
+        zygoteSize += zygote_space->Size();
+        zygoteUsed += zygote_space->GetBytesAllocated();
+      } else if (space->IsMallocSpace()) {
+        // This is a malloc space.
+        gc::space::MallocSpace* malloc_space = space->AsMallocSpace();
+        allocSize += malloc_space->GetFootprint();
+        allocUsed += malloc_space->GetBytesAllocated();
+      } else if (space->IsBumpPointerSpace()) {
+        gc::space::BumpPointerSpace* bump_pointer_space = space->AsBumpPointerSpace();
+        allocSize += bump_pointer_space->Size();
+        allocUsed += bump_pointer_space->GetBytesAllocated();
+      }
+    }
+    for (gc::space::DiscontinuousSpace* space : heap->GetDiscontinuousSpaces()) {
+      if (space->IsLargeObjectSpace()) {
+        largeObjectsSize += space->AsLargeObjectSpace()->GetBytesAllocated();
+        largeObjectsUsed += largeObjectsSize;
+      }
     }
   }
-  for (gc::space::DiscontinuousSpace* space : heap->GetDiscontinuousSpaces()) {
-    if (space->IsLargeObjectSpace()) {
-      largeObjectsSize += space->AsLargeObjectSpace()->GetBytesAllocated();
-      largeObjectsUsed += largeObjectsSize;
-    }
-  }
-
   size_t allocFree = allocSize - allocUsed;
   size_t zygoteFree = zygoteSize - zygoteUsed;
   size_t largeObjectsFree = largeObjectsSize - largeObjectsUsed;
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 67d825e..a7881ac 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -65,6 +65,7 @@
     DEBUG_ENABLE_SAFEMODE           = 1 << 3,
     DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
     DEBUG_GENERATE_DEBUG_INFO       = 1 << 5,
+    DEBUG_ALWAYS_JIT                = 1 << 6,
   };
 
   Runtime* const runtime = Runtime::Current();
@@ -109,6 +110,13 @@
   // This is for backwards compatibility with Dalvik.
   debug_flags &= ~DEBUG_ENABLE_ASSERT;
 
+  if ((debug_flags & DEBUG_ALWAYS_JIT) != 0) {
+    jit::JitOptions* jit_options = runtime->GetJITOptions();
+    CHECK(jit_options != nullptr);
+    jit_options->SetJitAtFirstUse();
+    debug_flags &= ~DEBUG_ALWAYS_JIT;
+  }
+
   if (debug_flags != 0) {
     LOG(ERROR) << StringPrintf("Unknown bits set in debug_flags: %#x", debug_flags);
   }
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index b34b5505..de90f0a 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -30,6 +30,7 @@
 #include "oat_file_assistant.h"
 #include "scoped_thread_state_change.h"
 #include "thread-inl.h"
+#include "thread_list.h"
 
 namespace art {
 
@@ -376,7 +377,11 @@
           std::string temp_error_msg;
           // Add image space has a race condition since other threads could be reading from the
           // spaces array.
-          runtime->GetHeap()->AddSpace(image_space.get());
+          {
+            ScopedThreadSuspension sts(self, kSuspended);
+            ScopedSuspendAll ssa("Add image space");
+            runtime->GetHeap()->AddSpace(image_space.get());
+          }
           added_image_space = true;
           if (!runtime->GetClassLinker()->AddImageSpace(image_space.get(),
                                                         h_loader,
@@ -386,7 +391,11 @@
                                                         /*out*/&temp_error_msg)) {
             LOG(INFO) << "Failed to add image file " << temp_error_msg;
             dex_files.clear();
-            runtime->GetHeap()->RemoveSpace(image_space.get());
+            {
+              ScopedThreadSuspension sts(self, kSuspended);
+              ScopedSuspendAll ssa("Remove image space");
+              runtime->GetHeap()->RemoveSpace(image_space.get());
+            }
             added_image_space = false;
             // Non-fatal, don't update error_msg.
           }
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 341be9a..aa64ee3 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -565,13 +565,6 @@
     args.Set(M::HeapGrowthLimit, args.GetOrDefault(M::MemoryMaximumSize));
   }
 
-  if (args.GetOrDefault(M::Experimental) & ExperimentalFlags::kDefaultMethods) {
-    LOG(WARNING) << "Default method support has been enabled. The verifier will be less strict "
-                 << "in some cases. All existing invoke opcodes have an unstable updated "
-                 << "specification and are nearly guaranteed to change over time. Do not attempt "
-                 << "to write shipping code against the invoke opcodes with this flag.";
-  }
-
   if (args.GetOrDefault(M::Experimental) & ExperimentalFlags::kLambdas) {
     LOG(WARNING) << "Experimental lambdas have been enabled. All lambda opcodes have "
                  << "an unstable specification and are nearly guaranteed to change over time. "
@@ -698,8 +691,8 @@
   UsageMessage(stream, "  -X[no]image-dex2oat (Whether to create and use a boot image)\n");
   UsageMessage(stream, "  -Xno-dex-file-fallback "
                        "(Don't fall back to dex files without oat files)\n");
-  UsageMessage(stream, "  -Xexperimental:{lambdas,default-methods} "
-                       "(Enable new experimental dalvik opcodes and semantics, off by default)\n");
+  UsageMessage(stream, "  -Xexperimental:lambdas "
+                       "(Enable new and experimental dalvik opcodes and semantics)\n");
   UsageMessage(stream, "\n");
 
   UsageMessage(stream, "The following previously supported Dalvik options are ignored:\n");
diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h
index ca456c2..1bb816b 100644
--- a/runtime/quick/inline_method_analyser.h
+++ b/runtime/quick/inline_method_analyser.h
@@ -37,13 +37,21 @@
 enum InlineMethodOpcode : uint16_t {
   kIntrinsicDoubleCvt,
   kIntrinsicFloatCvt,
+  kIntrinsicFloatIsInfinite,
+  kIntrinsicDoubleIsInfinite,
+  kIntrinsicFloatIsNaN,
+  kIntrinsicDoubleIsNaN,
   kIntrinsicReverseBits,
   kIntrinsicReverseBytes,
   kIntrinsicBitCount,
+  kIntrinsicCompare,
+  kIntrinsicHighestOneBit,
+  kIntrinsicLowestOneBit,
   kIntrinsicNumberOfLeadingZeros,
   kIntrinsicNumberOfTrailingZeros,
   kIntrinsicRotateRight,
   kIntrinsicRotateLeft,
+  kIntrinsicSignum,
   kIntrinsicAbsInt,
   kIntrinsicAbsLong,
   kIntrinsicAbsFloat,
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index f138c81..0c06ca6 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -71,7 +71,7 @@
 #include "gc/space/image_space.h"
 #include "gc/space/space-inl.h"
 #include "handle_scope-inl.h"
-#include "image.h"
+#include "image-inl.h"
 #include "instrumentation.h"
 #include "intern_table.h"
 #include "interpreter/interpreter.h"
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index c5b009d..308f3ba 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -113,7 +113,7 @@
 RUNTIME_OPTIONS_KEY (Unit,                NoDexFileFallback)
 RUNTIME_OPTIONS_KEY (std::string,         CpuAbiList)
 RUNTIME_OPTIONS_KEY (std::string,         Fingerprint)
-RUNTIME_OPTIONS_KEY (ExperimentalFlags,   Experimental,     ExperimentalFlags::kNone) // -Xexperimental:{, lambdas, default-methods}
+RUNTIME_OPTIONS_KEY (ExperimentalFlags,   Experimental,     ExperimentalFlags::kNone) // -Xexperimental:{none, lambdas}
 
 // Not parse-able from command line, but can be provided explicitly.
 // (Do not add anything here that is defined in ParsedOptions::MakeParser)
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 7e0f337..2890a98 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -608,7 +608,6 @@
 bool MethodVerifier::Verify() {
   // Some older code doesn't correctly mark constructors as such. Test for this case by looking at
   // the name.
-  Runtime* runtime = Runtime::Current();
   const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
   const char* method_name = dex_file_->StringDataByIdx(method_id.name_idx_);
   bool instance_constructor_by_name = strcmp("<init>", method_name) == 0;
@@ -678,12 +677,9 @@
       }
       if ((class_def_->GetJavaAccessFlags() & kAccInterface) != 0) {
         // Interface methods must be public and abstract (if default methods are disabled).
-        bool default_methods_supported =
-            runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods);
-        uint32_t kRequired = kAccPublic | (default_methods_supported ? 0 : kAccAbstract);
+        uint32_t kRequired = kAccPublic;
         if ((method_access_flags_ & kRequired) != kRequired) {
-          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be public"
-                                            << (default_methods_supported ? "" : " and abstract");
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be public";
           return false;
         }
         // In addition to the above, interface methods must not be protected.
@@ -715,19 +711,14 @@
       // default methods enabled we also allow other public, static, non-final methods to have code.
       // Otherwise that is the only type of method allowed.
       if (!(IsConstructor() && IsStatic())) {
-        if (runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) {
-          if (IsInstanceConstructor()) {
-            Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-static constructor";
-            return false;
-          } else if (method_access_flags_ & kAccFinal) {
-            Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have final methods";
-            return false;
-          } else if (!(method_access_flags_ & kAccPublic)) {
-            Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-public members";
-            return false;
-          }
-        } else {
-          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be abstract";
+        if (IsInstanceConstructor()) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-static constructor";
+          return false;
+        } else if (method_access_flags_ & kAccFinal) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have final methods";
+          return false;
+        } else if (!(method_access_flags_ & kAccPublic)) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-public members";
           return false;
         }
       }
@@ -3713,12 +3704,10 @@
   // Note: this check must be after the initializer check, as those are required to fail a class,
   //       while this check implies an IncompatibleClassChangeError.
   if (klass->IsInterface()) {
-    Runtime* runtime = Runtime::Current();
-    const bool default_methods_supported =
-        runtime == nullptr ||
-        runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods);
+    // methods called on interfaces should be invoke-interface, invoke-super, or invoke-static.
     if (method_type != METHOD_INTERFACE &&
-        (!default_methods_supported || method_type != METHOD_STATIC)) {
+        method_type != METHOD_STATIC &&
+        method_type != METHOD_SUPER) {
       Fail(VERIFY_ERROR_CLASS_CHANGE)
           << "non-interface method " << PrettyMethod(dex_method_idx, *dex_file_)
           << " is in an interface class " << PrettyClass(klass);
diff --git a/test/048-reflect-v8/run b/test/048-reflect-v8/run
deleted file mode 100644
index ba3318a..0000000
--- a/test/048-reflect-v8/run
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2016 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.
-
-
-# Ensure that the default methods are turned on for dalvikvm and dex2oat
-${RUN} "$@" --experimental default-methods
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index 3e6d1f4..06cfd0a 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -622,28 +622,39 @@
   static int[][] mA;
 
   /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (before)
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: NullCheck
-  /// CHECK-DAG: ArrayLength
-  /// CHECK-DAG: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: InvokeStaticOrDirect
-  /// CHECK-DAG: ArraySet
-
+  //  Array references mA[i] and ..[j] both in inner loop.
+  /// CHECK-DAG:  <<Get1:l\d+>>  ArrayGet [<<Array1:l\d+>>,<<Bounds1:i\d+>>] loop:<<InnerLoop:B\d+>>
+  /// CHECK-DAG:  <<Array1>>     NullCheck [<<Field1:l\d+>>]                 loop:<<InnerLoop>>
+  /// CHECK-DAG:  <<Len1:i\d+>>  ArrayLength [<<Array1>>]                    loop:<<InnerLoop>>
+  /// CHECK-DAG:  <<Bounds1>>    BoundsCheck [<<Index1:i\d+>>,<<Len1>>]      loop:<<InnerLoop>>
+  /// CHECK-DAG:  <<Get2:i\d+>>  ArrayGet [<<Array2:l\d+>>,<<Bounds2:i\d+>>] loop:<<InnerLoop>>
+  /// CHECK-DAG:  <<Array2>>     NullCheck [<<Get1>>]                        loop:<<InnerLoop>>
+  /// CHECK-DAG:  <<Len2:i\d+>>  ArrayLength [<<Array2>>]                    loop:<<InnerLoop>>
+  /// CHECK-DAG:  <<Bounds2>>    BoundsCheck [<<Index2:i\d+>>,<<Len2>>]      loop:<<InnerLoop>>
+  /// CHECK-DAG:                 InvokeStaticOrDirect [<<Get2>>]             loop:<<InnerLoop>>
+  /// CHECK-DAG:  <<Index2>>     Phi                                         loop:<<InnerLoop>>
+  /// CHECK-DAG:  <<Index1>>     Phi                                         loop:<<OuterLoop:B\d+>>
+  /// CHECK-DAG:  <<Field1>>     StaticFieldGet                              loop:none
+  /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>"
+  //
+  /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (after)
+  //  Array reference mA[i] hoisted to same level as deopt.
+  /// CHECK-DAG:                 Deoptimize                                  loop:<<OuterLoop:B\d+>>
+  /// CHECK-DAG:                 ArrayLength                                 loop:<<OuterLoop>>
+  /// CHECK-DAG:  <<Get1:l\d+>>  ArrayGet [<<Array1:l\d+>>,<<Index1:i\d+>>]  loop:<<OuterLoop>>
+  //  Array reference ..[j] still in inner loop, with a direct index.
+  /// CHECK-DAG:  <<Get2:i\d+>>  ArrayGet [<<Array2:l\d+>>,<<Index2:i\d+>>]  loop:<<InnerLoop:B\d+>>
+  /// CHECK-DAG:                 InvokeStaticOrDirect [<<Get2>>]             loop:<<InnerLoop>>
+  /// CHECK-DAG:  <<Index2>>     Phi                                         loop:<<InnerLoop>>
+  /// CHECK-DAG:  <<Index1>>     Phi                                         loop:<<OuterLoop>>
+  //  Synthetic phi.
+  /// CHECK-DAG:  <<Array2>>     Phi                                         loop:<<OuterLoop>>
+  /// CHECK-DAG:  <<Array1>>     StaticFieldGet                              loop:none
+  /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>"
+  //
   /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (after)
   /// CHECK-NOT: NullCheck
-  /// CHECK-NOT: ArrayLength
   /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-NOT: ArrayGet
-  /// CHECK-DAG: InvokeStaticOrDirect
-  /// CHECK-DAG: ArraySet
-  /// CHECK-DAG: Exit
-  /// CHECK-DAG: Deoptimize
-
   static void dynamicBCEAndIntrinsic(int n) {
     for (int i = 0; i < n; i++) {
       for (int j = 0; j < n; j++) {
diff --git a/test/530-checker-loops/src/Main.java b/test/530-checker-loops/src/Main.java
index f1d9a37..deff279 100644
--- a/test/530-checker-loops/src/Main.java
+++ b/test/530-checker-loops/src/Main.java
@@ -26,7 +26,7 @@
   //
 
   /// CHECK-START: int Main.linear(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linear(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -40,7 +40,7 @@
   }
 
   /// CHECK-START: int Main.linearDown(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearDown(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -54,7 +54,7 @@
   }
 
   /// CHECK-START: int Main.linearObscure(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearObscure(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -69,7 +69,7 @@
   }
 
   /// CHECK-START: int Main.linearVeryObscure(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearVeryObscure(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -84,7 +84,7 @@
   }
 
   /// CHECK-START: int Main.hiddenStride(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.hiddenStride(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -101,7 +101,7 @@
   }
 
   /// CHECK-START: int Main.linearWhile(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearWhile(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -116,7 +116,7 @@
   }
 
   /// CHECK-START: int Main.linearThreeWayPhi(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearThreeWayPhi(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -134,7 +134,7 @@
   }
 
   /// CHECK-START: int Main.linearFourWayPhi(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearFourWayPhi(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -156,7 +156,7 @@
   }
 
   /// CHECK-START: int Main.wrapAroundThenLinear(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.wrapAroundThenLinear(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -173,7 +173,7 @@
   }
 
   /// CHECK-START: int Main.wrapAroundThenLinearThreeWayPhi(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.wrapAroundThenLinearThreeWayPhi(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -194,7 +194,7 @@
   }
 
   /// CHECK-START: int[] Main.linearWithParameter(int) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int[] Main.linearWithParameter(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -208,7 +208,7 @@
   }
 
   /// CHECK-START: int[] Main.linearCopy(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int[] Main.linearCopy(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -223,8 +223,8 @@
   }
 
   /// CHECK-START: int Main.linearByTwo(int[]) BCE (before)
-  /// CHECK: BoundsCheck
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearByTwo(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -241,7 +241,7 @@
   }
 
   /// CHECK-START: int Main.linearByTwoSkip1(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearByTwoSkip1(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -255,10 +255,12 @@
   }
 
   /// CHECK-START: int Main.linearByTwoSkip2(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearByTwoSkip2(int[]) BCE (after)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: int Main.linearByTwoSkip2(int[]) BCE (after)
   /// CHECK-NOT: Deoptimize
   private static int linearByTwoSkip2(int x[]) {
     int result = 0;
@@ -270,7 +272,7 @@
   }
 
   /// CHECK-START: int Main.linearWithCompoundStride() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearWithCompoundStride() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -287,7 +289,7 @@
   }
 
   /// CHECK-START: int Main.linearWithLargePositiveStride() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearWithLargePositiveStride() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -305,10 +307,12 @@
   }
 
   /// CHECK-START: int Main.linearWithVeryLargePositiveStride() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearWithVeryLargePositiveStride() BCE (after)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: int Main.linearWithVeryLargePositiveStride() BCE (after)
   /// CHECK-NOT: Deoptimize
   private static int linearWithVeryLargePositiveStride() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
@@ -323,7 +327,7 @@
   }
 
   /// CHECK-START: int Main.linearWithLargeNegativeStride() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearWithLargeNegativeStride() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -341,10 +345,12 @@
   }
 
   /// CHECK-START: int Main.linearWithVeryLargeNegativeStride() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearWithVeryLargeNegativeStride() BCE (after)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: int Main.linearWithVeryLargeNegativeStride() BCE (after)
   /// CHECK-NOT: Deoptimize
   private static int linearWithVeryLargeNegativeStride() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
@@ -359,7 +365,7 @@
   }
 
   /// CHECK-START: int Main.linearForNEUp() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearForNEUp() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -374,7 +380,7 @@
   }
 
   /// CHECK-START: int Main.linearForNEDown() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearForNEDown() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -389,7 +395,7 @@
   }
 
   /// CHECK-START: int Main.linearDoWhileUp() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearDoWhileUp() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -405,7 +411,7 @@
   }
 
   /// CHECK-START: int Main.linearDoWhileDown() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearDoWhileDown() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -421,10 +427,12 @@
   }
 
   /// CHECK-START: int Main.linearShort() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.linearShort() BCE (after)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: int Main.linearShort() BCE (after)
   /// CHECK-NOT: Deoptimize
   private static int linearShort() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -437,7 +445,7 @@
   }
 
   /// CHECK-START: int Main.invariantFromPreLoop(int[], int) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.invariantFromPreLoop(int[], int) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -458,20 +466,11 @@
   }
 
   /// CHECK-START: void Main.linearTriangularOnTwoArrayLengths(int) BCE (before)
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: void Main.linearTriangularOnTwoArrayLengths(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static void linearTriangularOnTwoArrayLengths(int n) {
     int[] a = new int[n];
@@ -488,20 +487,11 @@
   }
 
   /// CHECK-START: void Main.linearTriangularOnOneArrayLength(int) BCE (before)
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: void Main.linearTriangularOnOneArrayLength(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static void linearTriangularOnOneArrayLength(int n) {
     int[] a = new int[n];
@@ -518,20 +508,11 @@
   }
 
   /// CHECK-START: void Main.linearTriangularOnParameter(int) BCE (before)
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: void Main.linearTriangularOnParameter(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static void linearTriangularOnParameter(int n) {
     int[] a = new int[n];
@@ -548,32 +529,13 @@
   }
 
   /// CHECK-START: void Main.linearTriangularVariations(int) BCE (before)
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: void Main.linearTriangularVariations(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static void linearTriangularVariations(int n) {
     int[] a = new int[n];
@@ -616,22 +578,11 @@
   }
 
   /// CHECK-START: void Main.bubble(int[]) BCE (before)
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: If
-  /// CHECK: ArraySet
-  /// CHECK: ArraySet
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: void Main.bubble(int[]) BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: If
-  /// CHECK: ArraySet
-  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static void bubble(int[] a) {
     for (int i = a.length; --i >= 0;) {
@@ -646,7 +597,7 @@
   }
 
   /// CHECK-START: int Main.periodicIdiom(int) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.periodicIdiom(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -664,7 +615,7 @@
   }
 
   /// CHECK-START: int Main.periodicSequence2(int) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.periodicSequence2(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -685,10 +636,10 @@
   }
 
   /// CHECK-START: int Main.periodicSequence4(int) BCE (before)
-  /// CHECK: BoundsCheck
-  /// CHECK: BoundsCheck
-  /// CHECK: BoundsCheck
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.periodicSequence4(int) BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -713,7 +664,7 @@
   }
 
   /// CHECK-START: int Main.justRightUp1() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.justRightUp1() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -728,7 +679,7 @@
   }
 
   /// CHECK-START: int Main.justRightUp2() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.justRightUp2() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -743,7 +694,7 @@
   }
 
   /// CHECK-START: int Main.justRightUp3() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.justRightUp3() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -758,10 +709,12 @@
   }
 
   /// CHECK-START: int Main.justOOBUp() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.justOOBUp() BCE (after)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: int Main.justOOBUp() BCE (after)
   /// CHECK-NOT: Deoptimize
   private static int justOOBUp() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -774,7 +727,7 @@
   }
 
   /// CHECK-START: int Main.justRightDown1() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.justRightDown1() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -789,7 +742,7 @@
   }
 
   /// CHECK-START: int Main.justRightDown2() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.justRightDown2() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -804,7 +757,7 @@
   }
 
   /// CHECK-START: int Main.justRightDown3() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.justRightDown3() BCE (after)
   /// CHECK-NOT: BoundsCheck
@@ -819,10 +772,12 @@
   }
 
   /// CHECK-START: int Main.justOOBDown() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int Main.justOOBDown() BCE (after)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: int Main.justOOBDown() BCE (after)
   /// CHECK-NOT: Deoptimize
   private static int justOOBDown() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -835,66 +790,74 @@
   }
 
   /// CHECK-START: void Main.lowerOOB(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: void Main.lowerOOB(int[]) BCE (after)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: void Main.lowerOOB(int[]) BCE (after)
   /// CHECK-NOT: Deoptimize
   private static void lowerOOB(int[] x) {
+    // OOB!
     for (int i = -1; i < x.length; i++) {
       sResult += x[i];
     }
   }
 
   /// CHECK-START: void Main.upperOOB(int[]) BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: void Main.upperOOB(int[]) BCE (after)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: void Main.upperOOB(int[]) BCE (after)
   /// CHECK-NOT: Deoptimize
   private static void upperOOB(int[] x) {
+    // OOB!
     for (int i = 0; i <= x.length; i++) {
       sResult += x[i];
     }
   }
 
   /// CHECK-START: void Main.doWhileUpOOB() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: void Main.doWhileUpOOB() BCE (after)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: void Main.doWhileUpOOB() BCE (after)
   /// CHECK-NOT: Deoptimize
   private static void doWhileUpOOB() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
     int i = 0;
+    // OOB!
     do {
       sResult += x[i++];
     } while (i <= x.length);
   }
 
   /// CHECK-START: void Main.doWhileDownOOB() BCE (before)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: void Main.doWhileDownOOB() BCE (after)
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: void Main.doWhileDownOOB() BCE (after)
   /// CHECK-NOT: Deoptimize
   private static void doWhileDownOOB() {
     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
     int i = x.length - 1;
+    // OOB!
     do {
       sResult += x[i--];
     } while (-1 <= i);
   }
 
   /// CHECK-START: int[] Main.multiply1() BCE (before)
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int[] Main.multiply1() BCE (after)
   /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
   /// CHECK-NOT: Deoptimize
   private static int[] multiply1() {
     int[] a = new int[10];
@@ -912,21 +875,20 @@
   }
 
   /// CHECK-START: int[] Main.multiply2() BCE (before)
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
+  /// CHECK-DAG: BoundsCheck
   //
   /// CHECK-START: int[] Main.multiply2() BCE (after)
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: ArraySet
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: int[] Main.multiply2() BCE (after)
+  /// CHECK-NOT: Deoptimize
   static int[] multiply2() {
     int[] a = new int[10];
     try {
       for (int i = -3; i <= 3; i++) {
         for (int j = -3; j <= 3; j++) {
           // Range [-9,9]: unsafe.
-         a[i * j] += 1;
+          a[i * j] += 1;
         }
       }
     } catch (Exception e) {
@@ -936,24 +898,19 @@
   }
 
   /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (before)
-  /// CHECK: StaticFieldGet
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: StaticFieldSet
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: NullCheck   loop:<<Loop>>
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
   //
   /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after)
-  /// CHECK: StaticFieldGet
-  /// CHECK-NOT: NullCheck
-  /// CHECK-NOT: ArrayLength
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: StaticFieldSet
-  /// CHECK: Exit
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
+  /// CHECK-DAG: ArrayGet    loop:{{B\d+}}
+  /// CHECK-DAG: Deoptimize  loop:none
+  //
+  /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after)
+  /// CHECK-NOT: NullCheck   loop:{{B\d+}}
+  /// CHECK-NOT: ArrayLength loop:{{B\d+}}
+  /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
   private static int linearDynamicBCE1(int[] x, int lo, int hi) {
     int result = 0;
     for (int i = lo; i < hi; i++) {
@@ -963,24 +920,19 @@
   }
 
   /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (before)
-  /// CHECK: StaticFieldGet
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: StaticFieldSet
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: NullCheck   loop:<<Loop>>
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
   //
   /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after)
-  /// CHECK: StaticFieldGet
-  /// CHECK-NOT: NullCheck
-  /// CHECK-NOT: ArrayLength
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: StaticFieldSet
-  /// CHECK: Exit
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
+  /// CHECK-DAG: ArrayGet    loop:{{B\d+}}
+  /// CHECK-DAG: Deoptimize  loop:none
+  //
+  /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after)
+  /// CHECK-NOT: NullCheck   loop:{{B\d+}}
+  /// CHECK-NOT: ArrayLength loop:{{B\d+}}
+  /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
   private static int linearDynamicBCE2(int[] x, int lo, int hi, int offset) {
     int result = 0;
     for (int i = lo; i < hi; i++) {
@@ -990,19 +942,19 @@
   }
 
   /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (before)
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: NullCheck   loop:<<Loop>>
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
   //
   /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after)
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
-  /// CHECK-NOT: NullCheck
-  /// CHECK-NOT: ArrayLength
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
+  /// CHECK-DAG: ArrayGet    loop:{{B\d+}}
+  /// CHECK-DAG: Deoptimize  loop:none
+  //
+  /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after)
+  /// CHECK-NOT: NullCheck   loop:{{B\d+}}
+  /// CHECK-NOT: ArrayLength loop:{{B\d+}}
+  /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
   private static int wrapAroundDynamicBCE(int[] x) {
     int w = 9;
     int result = 0;
@@ -1014,19 +966,19 @@
   }
 
   /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (before)
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: NullCheck   loop:<<Loop>>
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
   //
   /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after)
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
-  /// CHECK-NOT: NullCheck
-  /// CHECK-NOT: ArrayLength
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
+  /// CHECK-DAG: ArrayGet    loop:{{B\d+}}
+  /// CHECK-DAG: Deoptimize  loop:none
+  //
+  /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after)
+  /// CHECK-NOT: NullCheck   loop:{{B\d+}}
+  /// CHECK-NOT: ArrayLength loop:{{B\d+}}
+  /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
   private static int periodicDynamicBCE(int[] x) {
     int k = 0;
     int result = 0;
@@ -1038,20 +990,19 @@
   }
 
   /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before)
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: NullCheck   loop:<<Loop>>
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
   //
   /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
-  /// CHECK-NOT: NullCheck
-  /// CHECK-NOT: ArrayLength
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: Exit
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
+  /// CHECK-DAG: ArrayGet    loop:{{B\d+}}
+  /// CHECK-DAG: Deoptimize  loop:none
+  //
+  /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
+  /// CHECK-NOT: NullCheck   loop:{{B\d+}}
+  /// CHECK-NOT: ArrayLength loop:{{B\d+}}
+  /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
   static int dynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) {
     // This loop could be infinite for hi = max int. Since i is also used
     // as subscript, however, dynamic bce can proceed.
@@ -1063,16 +1014,14 @@
   }
 
   /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before)
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
   //
   /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+  //
+  /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
   /// CHECK-NOT: Deoptimize
   static int noDynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) {
     // As above, but now the index is not used as subscript,
@@ -1085,16 +1034,14 @@
   }
 
   /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (before)
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
   //
   /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after)
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+  //
+  /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after)
   /// CHECK-NOT: Deoptimize
   static int noDynamicBCEMixedInductionTypes(int[] x, long lo, long hi) {
     int result = 0;
@@ -1107,42 +1054,21 @@
   }
 
   /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (before)
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: NotEqual
-  /// CHECK: If
-  /// CHECK: If
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: If
-  /// CHECK: BoundsCheck
-  /// CHECK: BoundsCheck
-  /// CHECK: BoundsCheck
-  /// CHECK: BoundsCheck
-  /// CHECK: BoundsCheck
-  /// CHECK: BoundsCheck
+  /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop:B\d+>>
+  /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
+  /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
   //
   /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after)
-  /// CHECK: NullCheck
-  /// CHECK: ArrayLength
-  /// CHECK: NotEqual
-  /// CHECK: If
-  /// CHECK: If
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: If
-  /// CHECK: Deoptimize
-  /// CHECK: BoundsCheck
-  /// CHECK: BoundsCheck
-  /// CHECK: BoundsCheck
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK: Exit
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
-  /// CHECK: Deoptimize
-  /// CHECK-NOT: ArrayGet
+  //  Order matters:
+  /// CHECK:              Deoptimize loop:<<Loop:B\d+>>
+  //  CHECK-NOT:          Goto       loop:<<Loop>>
+  /// CHECK-DAG: {{l\d+}} ArrayGet   loop:<<Loop>>
+  /// CHECK-DAG: {{l\d+}} ArrayGet   loop:<<Loop>>
+  /// CHECK-DAG: {{l\d+}} ArrayGet   loop:<<Loop>>
+  /// CHECK:              Goto       loop:<<Loop>>
+  //
+  /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after)
+  /// CHECK-DAG: Deoptimize loop:none
   static int dynamicBCEAndConstantIndices(int[] x, int[][] a, int lo, int hi) {
     // Deliberately test array length on a before the loop so that only bounds checks
     // on constant subscripts remain, making them a viable candidate for hoisting.
@@ -1166,80 +1092,73 @@
     return result;
   }
 
-  /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], java.lang.Integer[], int, int) BCE (before)
-  /// CHECK: If
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
-  /// CHECK: BoundsCheck
-  /// CHECK: ArrayGet
+  /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (before)
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: ArrayGet    loop:<<Loop>>
+  /// CHECK-DAG: ArrayGet    loop:<<Loop>>
+  /// CHECK-DAG: ArrayGet    loop:<<Loop>>
+  /// CHECK-DAG: ArrayGet    loop:<<Loop>>
+  /// CHECK-DAG: ArrayGet    loop:<<Loop>>
+  /// CHECK-DAG: ArrayGet    loop:<<Loop>>
+  /// CHECK-DAG: ArrayGet    loop:<<Loop>>
+  /// CHECK-DAG: ArrayGet    loop:<<Loop>>
+  //  For brevity, just test occurrence of at least one of each in the loop:
+  /// CHECK-DAG: NullCheck   loop:<<Loop>>
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
   //
-  /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], java.lang.Integer[], int, int) BCE (after)
-  /// CHECK-DAG: If
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-NOT: BoundsCheck
-  /// CHECK-NOT: ArrayGet
-  /// CHECK-DAG: Exit
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: Deoptimize
-  /// CHECK-DAG: ArrayGet
-  static int dynamicBCEAndConstantIndicesAllTypes(int[] q,
-                                                  boolean[] r,
-                                                  byte[] s,
-                                                  char[] t,
-                                                  short[] u,
-                                                  int[] v,
-                                                  long[] w,
-                                                  float[] x,
-                                                  double[] y,
-                                                  Integer[] z, int lo, int hi) {
+  /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after)
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-NOT: ArrayGet    loop:<<Loop>>
+  //
+  /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after)
+  /// CHECK-NOT: NullCheck   loop:{{B\d+}}
+  /// CHECK-NOT: ArrayLength loop:{{B\d+}}
+  /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
+  //
+  /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after)
+  /// CHECK-DAG: Deoptimize  loop:none
+  static int dynamicBCEAndConstantIndicesAllPrimTypes(int[] q,
+                                                      boolean[] r,
+                                                      byte[] s,
+                                                      char[] t,
+                                                      short[] u,
+                                                      int[] v,
+                                                      long[] w,
+                                                      float[] x,
+                                                      double[] y, int lo, int hi) {
     int result = 0;
     for (int i = lo; i < hi; i++) {
+      // All constant index array references can be hoisted out of the loop during BCE on q[i].
       result += q[i] + (r[0] ? 1 : 0) + (int) s[0] + (int) t[0] + (int) u[0] + (int) v[0] +
-                                        (int) w[0] + (int) x[0] + (int) y[0] + (int) z[0];
+                                        (int) w[0] + (int) x[0] + (int) y[0];
+    }
+    return result;
+  }
+
+  /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (before)
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: NullCheck   loop:<<Loop>>
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+  /// CHECK-DAG: ArrayGet    loop:<<Loop>>
+  /// CHECK-DAG: NullCheck   loop:<<Loop>>
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>
+  /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+  //
+  /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after)
+  /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
+  /// CHECK-DAG: Deoptimize  loop:none
+  //
+  /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after)
+  /// CHECK-NOT: ArrayLength loop:{{B\d+}}
+  /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
+  static int dynamicBCEAndConstantIndexRefType(int[] q, Integer[] z, int lo, int hi) {
+    int result = 0;
+    for (int i = lo; i < hi; i++) {
+      // Similar to above, but now implicit call to intValue() may prevent hoisting
+      // z[0] itself during BCE on q[i]. Therefore, we just check BCE on q[i].
+      result += q[i] + z[0];
     }
     return result;
   }
@@ -1501,9 +1420,10 @@
     long[] x6 = { 6 };
     float[] x7 = { 7 };
     double[] x8 = { 8 };
+    expectEquals(415,
+        dynamicBCEAndConstantIndicesAllPrimTypes(x, x1, x2, x3, x4, x5, x6, x7, x8, 0, 10));
     Integer[] x9 = { 9 };
-    expectEquals(505,
-        dynamicBCEAndConstantIndicesAllTypes(x, x1, x2, x3, x4, x5, x6, x7, x8, x9, 0, 10));
+    expectEquals(145, dynamicBCEAndConstantIndexRefType(x, x9, 0, 10));
   }
 
   private static void expectEquals(int expected, int result) {
diff --git a/test/960-default-smali/run b/test/960-default-smali/run
deleted file mode 100755
index 22f6800..0000000
--- a/test/960-default-smali/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-${RUN} --experimental default-methods "$@"
diff --git a/test/961-default-iface-resolution-generated/run b/test/961-default-iface-resolution-generated/run
deleted file mode 100755
index 22f6800..0000000
--- a/test/961-default-iface-resolution-generated/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-${RUN} --experimental default-methods "$@"
diff --git a/test/962-iface-static/run b/test/962-iface-static/run
deleted file mode 100755
index d37737f..0000000
--- a/test/962-iface-static/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-${RUN} --experimental default-methods "$@"
diff --git a/test/963-default-range-smali/run b/test/963-default-range-smali/run
deleted file mode 100755
index d37737f..0000000
--- a/test/963-default-range-smali/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-${RUN} --experimental default-methods "$@"
diff --git a/test/964-default-iface-init-generated/run b/test/964-default-iface-init-generated/run
deleted file mode 100755
index 22f6800..0000000
--- a/test/964-default-iface-init-generated/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-${RUN} --experimental default-methods "$@"
diff --git a/test/965-default-verify/run b/test/965-default-verify/run
deleted file mode 100755
index 8944ea9..0000000
--- a/test/965-default-verify/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-${RUN} "$@" --experimental default-methods
diff --git a/test/966-default-conflict/run b/test/966-default-conflict/run
deleted file mode 100755
index 8944ea9..0000000
--- a/test/966-default-conflict/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-${RUN} "$@" --experimental default-methods
diff --git a/test/967-default-ame/run b/test/967-default-ame/run
deleted file mode 100755
index 8944ea9..0000000
--- a/test/967-default-ame/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-${RUN} "$@" --experimental default-methods
diff --git a/test/968-default-partial-compile-generated/run b/test/968-default-partial-compile-generated/run
deleted file mode 100755
index 6d2930d..0000000
--- a/test/968-default-partial-compile-generated/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-${RUN} "$@" --experimental default-methods
diff --git a/test/969-iface-super/run b/test/969-iface-super/run
deleted file mode 100755
index 8944ea9..0000000
--- a/test/969-iface-super/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-${RUN} "$@" --experimental default-methods
diff --git a/test/970-iface-super-resolution-generated/run b/test/970-iface-super-resolution-generated/run
deleted file mode 100755
index 6d2930d..0000000
--- a/test/970-iface-super-resolution-generated/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-${RUN} "$@" --experimental default-methods
diff --git a/test/971-iface-super/run b/test/971-iface-super/run
deleted file mode 100755
index 6d2930d..0000000
--- a/test/971-iface-super/run
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-${RUN} "$@" --experimental default-methods
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 4500863..429af6a 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -525,16 +525,19 @@
 
 TEST_ART_BROKEN_OPTIMIZING_DEBUGGABLE_RUN_TESTS :=
 
+# Tests that should fail in the read barrier configuration with the interpreter.
+# 004: Occasional timeout: "TEST TIMED OUT!" (b/26786154).
+# 141: Occasional failures: "Aborted" (b/25866001).
+TEST_ART_BROKEN_INTERPRETER_READ_BARRIER_RUN_TESTS := \
+  004-ThreadStress \
+  141-class-unload
 
 # Tests that should fail in the read barrier configuration with the default (Quick) compiler (AOT).
-# 004: Occasional timeout: "TEST TIMED OUT!" (b/26786154).
-# 137: Quick has no support for read barriers and punts to the
-#      interpreter, but CFI unwinding expects managed frames.
-# 554: Quick does not support JIT profiling.
+# Quick has no support for read barriers and punts to the interpreter, so this list is composed of
+# tests expected to fail with the interpreter, both on the concurrent collector and in general.
 TEST_ART_BROKEN_DEFAULT_READ_BARRIER_RUN_TESTS := \
-  004-ThreadStress \
-  137-cfi \
-  554-jit-profile-file
+  $(TEST_ART_BROKEN_INTERPRETER_READ_BARRIER_RUN_TESTS) \
+  $(TEST_ART_BROKEN_INTERPRETER_RUN_TESTS)
 
 # Tests that should fail in the read barrier configuration with the Optimizing compiler (AOT).
 # 004: Occasional timeout: "TEST TIMED OUT!" (b/26786154).
@@ -560,6 +563,13 @@
   496-checker-inlining-and-class-loader
 
 ifeq ($(ART_USE_READ_BARRIER),true)
+  ifneq (,$(filter interpreter,$(COMPILER_TYPES)))
+    ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES), \
+        $(PREBUILD_TYPES),interpreter,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES), \
+        $(JNI_TYPES),$(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES), \
+        $(TEST_ART_BROKEN_INTERPRETER_READ_BARRIER_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+  endif
+
   ifneq (,$(filter default,$(COMPILER_TYPES)))
     ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES), \
         $(PREBUILD_TYPES),default,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES), \
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 351e99e..6d67f84 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -260,6 +260,7 @@
           "dalvik.system.JniTest#testPassingShorts",
           "dalvik.system.JniTest#testPassingThis",
           "libcore.util.NativeAllocationRegistryTest#testBadSize",
+          "libcore.util.NativeAllocationRegistryTest#testEarlyFree",
           "libcore.util.NativeAllocationRegistryTest#testNativeAllocationAllocatorAndNoSharedRegistry",
           "libcore.util.NativeAllocationRegistryTest#testNativeAllocationAllocatorAndSharedRegistry",
           "libcore.util.NativeAllocationRegistryTest#testNativeAllocationNoAllocatorAndNoSharedRegistry",