Merge "Ensure that OSR doesn't break local-variable get/set"
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
index 606734b..3995ca2 100644
--- a/benchmark/Android.bp
+++ b/benchmark/Android.bp
@@ -17,7 +17,7 @@
 art_cc_library {
     name: "libartbenchmark",
     host_supported: true,
-    defaults: ["art_defaults" ],
+    defaults: ["art_defaults"],
     srcs: [
         "jni_loader.cc",
         "jobject-benchmark/jobject_benchmark.cc",
@@ -31,15 +31,6 @@
         "libbase",
         "libnativehelper",
     ],
-    clang: true,
-    target: {
-        android: {
-            shared_libs: ["libdl"],
-        },
-        host: {
-            host_ldlibs: ["-ldl", "-lpthread"],
-        },
-    },
     cflags: [
         "-Wno-frame-larger-than=",
     ],
@@ -49,7 +40,10 @@
     name: "libartbenchmark-micronative-host",
     host_supported: true,
     device_supported: false,
-    defaults: ["art_debug_defaults", "art_defaults" ],
+    defaults: [
+        "art_debug_defaults",
+        "art_defaults",
+    ],
     srcs: [
         "jni_loader.cc",
         "micro-native/micro_native.cc",
@@ -60,12 +54,6 @@
     ],
     header_libs: ["jni_headers"],
     stl: "libc++_static",
-    clang: true,
-    target: {
-        host: {
-            host_ldlibs: ["-ldl", "-lpthread"],
-        },
-    },
     cflags: [
         "-Wno-frame-larger-than=",
     ],
diff --git a/build/Android.bp b/build/Android.bp
index 65df933..8e8a2f6 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -20,7 +20,6 @@
     // Additional flags are computed by art.go
 
     name: "art_defaults",
-    clang: true,
     cflags: [
         // Base set of cflags used by all things ART.
         "-fno-rtti",
@@ -90,9 +89,6 @@
                 // Apple, it's a pain.
                 "-Wmissing-noreturn",
             ],
-            host_ldlibs: [
-                "-lrt",
-            ],
         },
         host: {
             cflags: [
@@ -109,10 +105,6 @@
                 "-msse4.2",
                 "-mpopcnt",
             ],
-            host_ldlibs: [
-                "-ldl",
-                "-lpthread",
-            ],
         },
     },
 
diff --git a/compiler/Android.bp b/compiler/Android.bp
index b1bef79..3044890 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -23,7 +23,6 @@
     name: "libart-compiler-defaults",
     defaults: ["art_defaults"],
     host_supported: true,
-    clang: true,
     srcs: [
         "compiled_method.cc",
         "debug/elf_debug_writer.cc",
@@ -182,10 +181,6 @@
         },
     },
     target: {
-        host: {
-            // For compiler driver TLS.
-            host_ldlibs: ["-lpthread"],
-        },
         android: {
             // For atrace.
             shared_libs: ["libcutils"],
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index e49f83f..7581962 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -374,8 +374,8 @@
       // Dex pc is not serialized, only used for checking the instructions. Since we access the
       // array based on the index of the quickened instruction, the indexes must line up perfectly.
       // The reader side uses the NeedsIndexForInstruction function too.
-      const Instruction* inst = Instruction::At(code_item->insns_ + info.dex_pc);
-      CHECK(QuickenInfoTable::NeedsIndexForInstruction(inst)) << inst->Opcode();
+      const Instruction& inst = code_item->InstructionAt(info.dex_pc);
+      CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode();
       // Add the index.
       quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 0));
       quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 8));
diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc
index c8e3d5e..925863e 100644
--- a/compiler/dex/inline_method_analyser.cc
+++ b/compiler/dex/inline_method_analyser.cc
@@ -64,14 +64,14 @@
  private:
   explicit Matcher(const DexFile::CodeItem* code_item)
       : code_item_(code_item),
-        instruction_(Instruction::At(code_item->insns_)),
+        instruction_(code_item->Instructions().begin()),
         pos_(0u),
         mark_(0u) { }
 
   static bool DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size);
 
   const DexFile::CodeItem* const code_item_;
-  const Instruction* instruction_;
+  DexInstructionIterator instruction_;
   size_t pos_;
   size_t mark_;
 };
@@ -93,7 +93,7 @@
     return false;
   }
   matcher->pos_ += 1u;
-  matcher->instruction_ = matcher->instruction_->Next();
+  ++matcher->instruction_;
   return true;
 }
 
@@ -105,7 +105,7 @@
     return true;
   }
   matcher->pos_ = matcher->mark_;
-  matcher->instruction_ = matcher->instruction_->Next();
+  ++matcher->instruction_;
   return true;
 }
 
@@ -301,26 +301,27 @@
   // Verify the invoke, prevent a few odd cases and collect IPUTs.
   uint16_t this_vreg = code_item->registers_size_ - code_item->ins_size_;
   uint16_t zero_vreg_mask = 0u;
-  for (const Instruction* instruction = Instruction::At(code_item->insns_);
-      instruction->Opcode() != Instruction::RETURN_VOID;
-      instruction = instruction->Next()) {
-    if (instruction->Opcode() == Instruction::INVOKE_DIRECT) {
-      ArtMethod* target_method = GetTargetConstructor(method, instruction);
+
+  for (const Instruction& instruction : code_item->Instructions()) {
+    if (instruction.Opcode() == Instruction::RETURN_VOID) {
+      break;
+    } else if (instruction.Opcode() == Instruction::INVOKE_DIRECT) {
+      ArtMethod* target_method = GetTargetConstructor(method, &instruction);
       if (target_method == nullptr) {
         return false;
       }
       // We allow forwarding constructors only if they pass more arguments
       // to prevent infinite recursion.
       if (target_method->GetDeclaringClass() == method->GetDeclaringClass() &&
-          instruction->VRegA_35c() <= code_item->ins_size_) {
+          instruction.VRegA_35c() <= code_item->ins_size_) {
         return false;
       }
-      size_t forwarded = CountForwardedConstructorArguments(code_item, instruction, zero_vreg_mask);
+      size_t forwarded = CountForwardedConstructorArguments(code_item, &instruction, zero_vreg_mask);
       if (forwarded == static_cast<size_t>(-1)) {
         return false;
       }
       if (target_method->GetDeclaringClass()->IsObjectClass()) {
-        DCHECK_EQ(Instruction::At(target_method->GetCodeItem()->insns_)->Opcode(),
+        DCHECK_EQ(target_method->GetCodeItem()->Instructions().begin()->Opcode(),
                   Instruction::RETURN_VOID);
       } else {
         const DexFile::CodeItem* target_code_item = target_method->GetCodeItem();
@@ -345,15 +346,15 @@
           return false;
         }
       }
-    } else if (IsInstructionDirectConst(instruction->Opcode())) {
-      zero_vreg_mask |= GetZeroVRegMask(instruction);
+    } else if (IsInstructionDirectConst(instruction.Opcode())) {
+      zero_vreg_mask |= GetZeroVRegMask(&instruction);
       if ((zero_vreg_mask & (1u << this_vreg)) != 0u) {
         return false;  // Overwriting `this` is unsupported.
       }
     } else {
-      DCHECK(IsInstructionIPut(instruction->Opcode()));
-      DCHECK_EQ(instruction->VRegB_22c(), this_vreg);
-      if (!RecordConstructorIPut(method, instruction, this_vreg, zero_vreg_mask, iputs)) {
+      DCHECK(IsInstructionIPut(instruction.Opcode()));
+      DCHECK_EQ(instruction.VRegB_22c(), this_vreg);
+      if (!RecordConstructorIPut(method, &instruction, this_vreg, zero_vreg_mask, iputs)) {
         return false;
       }
     }
@@ -447,8 +448,7 @@
   // We currently support only plain return or 2-instruction methods.
 
   DCHECK_NE(code_item->insns_size_in_code_units_, 0u);
-  const Instruction* instruction = Instruction::At(code_item->insns_);
-  Instruction::Code opcode = instruction->Opcode();
+  Instruction::Code opcode = code_item->Instructions().begin()->Opcode();
 
   switch (opcode) {
     case Instruction::RETURN_VOID:
@@ -519,7 +519,7 @@
 
 bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item,
                                                InlineMethod* result) {
-  const Instruction* return_instruction = Instruction::At(code_item->insns_);
+  DexInstructionIterator return_instruction = code_item->Instructions().begin();
   Instruction::Code return_opcode = return_instruction->Opcode();
   uint32_t reg = return_instruction->VRegA_11x();
   uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
@@ -541,7 +541,7 @@
 
 bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item,
                                               InlineMethod* result) {
-  const Instruction* instruction = Instruction::At(code_item->insns_);
+  DexInstructionIterator instruction = code_item->Instructions().begin();
   const Instruction* return_instruction = instruction->Next();
   Instruction::Code return_opcode = return_instruction->Opcode();
   if (return_opcode != Instruction::RETURN &&
@@ -575,7 +575,7 @@
                                              bool is_static,
                                              ArtMethod* method,
                                              InlineMethod* result) {
-  const Instruction* instruction = Instruction::At(code_item->insns_);
+  DexInstructionIterator instruction = code_item->Instructions().begin();
   Instruction::Code opcode = instruction->Opcode();
   DCHECK(IsInstructionIGet(opcode));
 
@@ -639,7 +639,7 @@
                                              bool is_static,
                                              ArtMethod* method,
                                              InlineMethod* result) {
-  const Instruction* instruction = Instruction::At(code_item->insns_);
+  DexInstructionIterator instruction = code_item->Instructions().begin();
   Instruction::Code opcode = instruction->Opcode();
   DCHECK(IsInstructionIPut(opcode));
 
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index e46dc59..9c5b632 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -64,24 +64,21 @@
   if (method_verifier->HasFailures()) {
     return;
   }
-  const DexFile::CodeItem* code_item = method_verifier->CodeItem();
-  const Instruction* inst = Instruction::At(code_item->insns_);
-  const Instruction* end = Instruction::At(code_item->insns_ +
-                                           code_item->insns_size_in_code_units_);
-
-  for (; inst < end; inst = inst->Next()) {
-    Instruction::Code code = inst->Opcode();
+  IterationRange<DexInstructionIterator> instructions = method_verifier->CodeItem()->Instructions();
+  for (auto it = instructions.begin(); it != instructions.end(); ++it) {
+    const Instruction& inst = *it;
+    const Instruction::Code code = inst.Opcode();
     if (code == Instruction::CHECK_CAST) {
-      uint32_t dex_pc = inst->GetDexPc(code_item->insns_);
+      const uint32_t dex_pc = it.GetDexPC(instructions.begin());
       if (!method_verifier->GetInstructionFlags(dex_pc).IsVisited()) {
         // Do not attempt to quicken this instruction, it's unreachable anyway.
         continue;
       }
       const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
       const verifier::RegType& reg_type(line->GetRegisterType(method_verifier,
-                                                              inst->VRegA_21c()));
+                                                              inst.VRegA_21c()));
       const verifier::RegType& cast_type =
-          method_verifier->ResolveCheckedClass(dex::TypeIndex(inst->VRegB_21c()));
+          method_verifier->ResolveCheckedClass(dex::TypeIndex(inst.VRegB_21c()));
       // Pass null for the method verifier to not record the VerifierDeps dependency
       // if the types are not assignable.
       if (cast_type.IsStrictlyAssignableFrom(reg_type, /* method_verifier */ nullptr)) {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 03d8ef5..7573367 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -762,18 +762,14 @@
     return;
   }
 
-  const uint16_t* code_ptr = code_item->insns_;
-  const uint16_t* code_end = code_item->insns_ + code_item->insns_size_in_code_units_;
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-
-  while (code_ptr < code_end) {
-    const Instruction* inst = Instruction::At(code_ptr);
-    switch (inst->Opcode()) {
+  for (const Instruction& inst : code_item->Instructions()) {
+    switch (inst.Opcode()) {
       case Instruction::CONST_STRING:
       case Instruction::CONST_STRING_JUMBO: {
-        dex::StringIndex string_index((inst->Opcode() == Instruction::CONST_STRING)
-            ? inst->VRegB_21c()
-            : inst->VRegB_31c());
+        dex::StringIndex string_index((inst.Opcode() == Instruction::CONST_STRING)
+            ? inst.VRegB_21c()
+            : inst.VRegB_31c());
         mirror::String* string = class_linker->ResolveString(dex_file, string_index, dex_cache);
         CHECK(string != nullptr) << "Could not allocate a string when forcing determinism";
         break;
@@ -782,8 +778,6 @@
       default:
         break;
     }
-
-    code_ptr += inst->SizeInCodeUnits();
   }
 }
 
@@ -2439,21 +2433,16 @@
     if (clinit != nullptr) {
       const DexFile::CodeItem* code_item = clinit->GetCodeItem();
       DCHECK(code_item != nullptr);
-      const Instruction* inst = Instruction::At(code_item->insns_);
-
-      const uint32_t insns_size = code_item->insns_size_in_code_units_;
-      for (uint32_t dex_pc = 0; dex_pc < insns_size;) {
-        if (inst->Opcode() == Instruction::CONST_STRING) {
+      for (const Instruction& inst : code_item->Instructions()) {
+        if (inst.Opcode() == Instruction::CONST_STRING) {
           ObjPtr<mirror::String> s = class_linker->ResolveString(
-              *dex_file, dex::StringIndex(inst->VRegB_21c()), h_dex_cache);
+              *dex_file, dex::StringIndex(inst.VRegB_21c()), h_dex_cache);
           CHECK(s != nullptr);
-        } else if (inst->Opcode() == Instruction::CONST_STRING_JUMBO) {
+        } else if (inst.Opcode() == Instruction::CONST_STRING_JUMBO) {
           ObjPtr<mirror::String> s = class_linker->ResolveString(
-              *dex_file, dex::StringIndex(inst->VRegB_31c()), h_dex_cache);
+              *dex_file, dex::StringIndex(inst.VRegB_31c()), h_dex_cache);
           CHECK(s != nullptr);
         }
-        dex_pc += inst->SizeInCodeUnits();
-        inst = inst->Next();
       }
     }
   }
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index b8e4f32..3cb3792 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -722,12 +722,10 @@
     }
   }
   ArenaVector<size_t> covered(loop_headers.size(), 0, graph.GetArena()->Adapter(kArenaAllocMisc));
-  const uint16_t* code_ptr = code_item.insns_;
-  const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
-
-  size_t dex_pc = 0;
-  while (code_ptr < code_end) {
-    const Instruction& instruction = *Instruction::At(code_ptr);
+  IterationRange<DexInstructionIterator> instructions = code_item.Instructions();
+  for (auto it = instructions.begin(); it != instructions.end(); ++it) {
+    const uint32_t dex_pc = it.GetDexPC(instructions.begin());
+    const Instruction& instruction = *it;
     if (instruction.IsBranch()) {
       uint32_t target = dex_pc + instruction.GetTargetOffset();
       CheckCovers(target, graph, code_info, loop_headers, &covered);
@@ -743,8 +741,6 @@
         CheckCovers(target, graph, code_info, loop_headers, &covered);
       }
     }
-    dex_pc += instruction.SizeInCodeUnits();
-    code_ptr += instruction.SizeInCodeUnits();
   }
 
   for (size_t i = 0; i < covered.size(); ++i) {
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index e832b10..6ad8036 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -368,17 +368,16 @@
   };
   dex_file_->DecodeDebugPositionInfo(&code_item_, Callback::Position, locations);
   // Instruction-specific tweaks.
-  const Instruction* const begin = Instruction::At(code_item_.insns_);
-  const Instruction* const end = begin->RelativeAt(code_item_.insns_size_in_code_units_);
-  for (const Instruction* inst = begin; inst < end; inst = inst->Next()) {
-    switch (inst->Opcode()) {
+  IterationRange<DexInstructionIterator> instructions = code_item_.Instructions();
+  for (const Instruction& inst : instructions) {
+    switch (inst.Opcode()) {
       case Instruction::MOVE_EXCEPTION: {
         // Stop in native debugger after the exception has been moved.
         // The compiler also expects the move at the start of basic block so
         // we do not want to interfere by inserting native-debug-info before it.
-        locations->ClearBit(inst->GetDexPc(code_item_.insns_));
-        const Instruction* next = inst->Next();
-        if (next < end) {
+        locations->ClearBit(inst.GetDexPc(code_item_.insns_));
+        const Instruction* next = inst.Next();
+        if (DexInstructionIterator(next) != instructions.end()) {
           locations->SetBit(next->GetDexPc(code_item_.insns_));
         }
         break;
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 6c918a3..7e37018 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -71,6 +71,12 @@
   return false;
 }
 
+// Forward declaration.
+static bool IsZeroExtensionAndGet(HInstruction* instruction,
+                                  DataType::Type type,
+                                  /*out*/ HInstruction** operand,
+                                  bool to64 = false);
+
 // Detect a sign extension in instruction from the given type. The to64 parameter
 // denotes if result is long, and thus sign extension from int can be included.
 // Returns the promoted operand on success.
@@ -124,9 +130,19 @@
         return false;
     }
   }
-  // Explicit type conversion to long.
-  if (instruction->IsTypeConversion() && instruction->GetType() == DataType::Type::kInt64) {
-    return IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+  // Explicit type conversions.
+  if (instruction->IsTypeConversion()) {
+    DataType::Type from = instruction->InputAt(0)->GetType();
+    switch (instruction->GetType()) {
+      case DataType::Type::kInt64:
+        return IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+      case DataType::Type::kInt16:
+        return type == DataType::Type::kUint16 &&
+               from == DataType::Type::kUint16 &&
+               IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, to64);
+      default:
+        return false;
+    }
   }
   return false;
 }
@@ -137,7 +153,7 @@
 static bool IsZeroExtensionAndGet(HInstruction* instruction,
                                   DataType::Type type,
                                   /*out*/ HInstruction** operand,
-                                  bool to64 = false) {
+                                  bool to64) {
   // Accept any already wider constant that would be handled properly by zero
   // extension when represented in the *width* of the given narrower data type
   // (the fact that byte/short/int normally sign extend does not matter here).
@@ -200,9 +216,19 @@
       }
     }
   }
-  // Explicit type conversion to long.
-  if (instruction->IsTypeConversion() && instruction->GetType() == DataType::Type::kInt64) {
-    return IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+  // Explicit type conversions.
+  if (instruction->IsTypeConversion()) {
+    DataType::Type from = instruction->InputAt(0)->GetType();
+    switch (instruction->GetType()) {
+      case DataType::Type::kInt64:
+        return IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+      case DataType::Type::kUint16:
+        return type == DataType::Type::kInt16 &&
+               from == DataType::Type::kInt16 &&
+               IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, to64);
+      default:
+        return false;
+    }
   }
   return false;
 }
@@ -1885,9 +1911,17 @@
   bool is_unsigned = false;
   DataType::Type sub_type = a->GetType();
   if (a->IsTypeConversion()) {
-    sub_type = a->InputAt(0)->GetType();
+    HInstruction* hunt = a;
+    while (hunt->IsTypeConversion()) {
+      hunt = hunt->InputAt(0);
+    }
+    sub_type = hunt->GetType();
   } else if (b->IsTypeConversion()) {
-    sub_type = b->InputAt(0)->GetType();
+    HInstruction* hunt = a;
+    while (hunt->IsTypeConversion()) {
+      hunt = hunt->InputAt(0);
+    }
+    sub_type = hunt->GetType();
   }
   if (reduction_type != sub_type &&
       (!IsNarrowerOperands(a, b, sub_type, &r, &s, &is_unsigned) || is_unsigned)) {
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index aeb2b03..1218586 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -669,22 +669,42 @@
 #endif
 #ifdef ART_ENABLE_CODEGEN_mips
     case kMips: {
+      SideEffectsAnalysis* side_effects = new (arena) SideEffectsAnalysis(graph);
+      GVNOptimization* gvn = new (arena) GVNOptimization(graph, *side_effects, "GVN$after_arch");
       mips::PcRelativeFixups* pc_relative_fixups =
           new (arena) mips::PcRelativeFixups(graph, codegen, stats);
       HOptimization* mips_optimizations[] = {
+          side_effects,
+          gvn,
           pc_relative_fixups,
       };
       RunOptimizations(mips_optimizations, arraysize(mips_optimizations), pass_observer);
       break;
     }
 #endif
+#ifdef ART_ENABLE_CODEGEN_mips64
+    case kMips64: {
+      SideEffectsAnalysis* side_effects = new (arena) SideEffectsAnalysis(graph);
+      GVNOptimization* gvn = new (arena) GVNOptimization(graph, *side_effects, "GVN$after_arch");
+      HOptimization* mips64_optimizations[] = {
+          side_effects,
+          gvn,
+      };
+      RunOptimizations(mips64_optimizations, arraysize(mips64_optimizations), pass_observer);
+      break;
+    }
+#endif
 #ifdef ART_ENABLE_CODEGEN_x86
     case kX86: {
+      SideEffectsAnalysis* side_effects = new (arena) SideEffectsAnalysis(graph);
+      GVNOptimization* gvn = new (arena) GVNOptimization(graph, *side_effects, "GVN$after_arch");
       x86::PcRelativeFixups* pc_relative_fixups =
           new (arena) x86::PcRelativeFixups(graph, codegen, stats);
       x86::X86MemoryOperandGeneration* memory_gen =
           new (arena) x86::X86MemoryOperandGeneration(graph, codegen, stats);
       HOptimization* x86_optimizations[] = {
+          side_effects,
+          gvn,
           pc_relative_fixups,
           memory_gen
       };
@@ -694,9 +714,13 @@
 #endif
 #ifdef ART_ENABLE_CODEGEN_x86_64
     case kX86_64: {
+      SideEffectsAnalysis* side_effects = new (arena) SideEffectsAnalysis(graph);
+      GVNOptimization* gvn = new (arena) GVNOptimization(graph, *side_effects, "GVN$after_arch");
       x86::X86MemoryOperandGeneration* memory_gen =
           new (arena) x86::X86MemoryOperandGeneration(graph, codegen, stats);
       HOptimization* x86_64_optimizations[] = {
+          side_effects,
+          gvn,
           memory_gen
       };
       RunOptimizations(x86_64_optimizations, arraysize(x86_64_optimizations), pass_observer);
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index e51b622..4dbe71b 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -126,15 +126,8 @@
   int cmd_result = system(cmd);
   ASSERT_EQ(cmd_result, 0) << strerror(errno);
 
-  // Remove the $d symbols to prevent the disassembler dumping the instructions
-  // as .word
-  snprintf(cmd, sizeof(cmd), "%sobjcopy -N '$d' %s.o %s.oo", toolsdir.c_str(), filename, filename);
-  int cmd_result2 = system(cmd);
-  ASSERT_EQ(cmd_result2, 0) << strerror(errno);
-
   // Disassemble.
-
-  snprintf(cmd, sizeof(cmd), "%sobjdump -d %s.oo | grep '^  *[0-9a-f][0-9a-f]*:'",
+  snprintf(cmd, sizeof(cmd), "%sobjdump -D -M force-thumb --section=.text %s.o  | grep '^  *[0-9a-f][0-9a-f]*:'",
     toolsdir.c_str(), filename);
   if (kPrintResults) {
     // Print the results only, don't check. This is used to generate new output for inserting
@@ -169,9 +162,6 @@
   char buf[FILENAME_MAX];
   snprintf(buf, sizeof(buf), "%s.o", filename);
   unlink(buf);
-
-  snprintf(buf, sizeof(buf), "%s.oo", filename);
-  unlink(buf);
 #endif  // ART_TARGET_ANDROID
 }
 
diff --git a/dalvikvm/Android.bp b/dalvikvm/Android.bp
index 09bbbda..0405fe1 100644
--- a/dalvikvm/Android.bp
+++ b/dalvikvm/Android.bp
@@ -30,15 +30,8 @@
     ],
     whole_static_libs: ["libsigchain"],
     target: {
-        host: {
-            host_ldlibs: [
-                "-ldl",
-                "-lpthread",
-            ],
-        },
         android: {
             shared_libs: [
-                "libdl",
                 "liblog",
             ],
             ldflags: ["-Wl,--export-dynamic"],
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index bdb8ff1..c9125df 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -18,7 +18,6 @@
     name: "libart-dex2oat-defaults",
     defaults: ["art_defaults"],
     host_supported: true,
-    clang: true,
     srcs: [
         "linker/elf_writer.cc",
         "linker/elf_writer_quick.cc",
@@ -27,10 +26,6 @@
         "linker/oat_writer.cc",
     ],
     target: {
-        host: {
-            // For compiler driver TLS.
-            host_ldlibs: ["-lpthread"],
-        },
         android: {
             // For atrace.
             shared_libs: ["libcutils"],
@@ -70,7 +65,7 @@
     defaults: ["libart-dex2oat-defaults"],
     shared_libs: [
         "libart-compiler",
-        "libart"
+        "libart",
     ],
 }
 
@@ -82,7 +77,7 @@
     ],
     shared_libs: [
         "libartd-compiler",
-        "libartd"
+        "libartd",
     ],
 }
 
@@ -126,7 +121,7 @@
     ],
     static_libs: [
         "libart-dex2oat",
-    ]
+    ],
 }
 
 art_cc_binary {
@@ -145,7 +140,7 @@
     ],
     static_libs: [
         "libartd-dex2oat",
-    ]
+    ],
 }
 
 art_cc_binary {
@@ -231,5 +226,5 @@
     ],
     static_libs: [
         "libartd-dex2oat",
-    ]
+    ],
 }
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index e544ab7..7b46531 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1357,7 +1357,7 @@
       DCHECK(!oat_filenames_.empty());
       for (const char* oat_filename : oat_filenames_) {
         std::unique_ptr<File> oat_file(OS::CreateEmptyFile(oat_filename));
-        if (oat_file.get() == nullptr) {
+        if (oat_file == nullptr) {
           PLOG(ERROR) << "Failed to create oat file: " << oat_filename;
           return false;
         }
@@ -1387,7 +1387,7 @@
           vdex_files_.push_back(std::move(vdex_file));
         } else {
           std::unique_ptr<File> vdex_file(OS::CreateEmptyFile(vdex_filename.c_str()));
-          if (vdex_file.get() == nullptr) {
+          if (vdex_file == nullptr) {
             PLOG(ERROR) << "Failed to open vdex file: " << vdex_filename;
             return false;
           }
@@ -1401,13 +1401,15 @@
       }
     } else {
       std::unique_ptr<File> oat_file(new File(oat_fd_, oat_location_, /* check_usage */ true));
-      if (oat_file.get() == nullptr) {
+      if (oat_file == nullptr) {
         PLOG(ERROR) << "Failed to create oat file: " << oat_location_;
         return false;
       }
       oat_file->DisableAutoClose();
       if (oat_file->SetLength(0) != 0) {
         PLOG(WARNING) << "Truncating oat file " << oat_location_ << " failed.";
+        oat_file->Erase();
+        return false;
       }
       oat_files_.push_back(std::move(oat_file));
 
@@ -1436,7 +1438,7 @@
       DCHECK_NE(output_vdex_fd_, -1);
       std::string vdex_location = ReplaceFileExtension(oat_location_, "vdex");
       std::unique_ptr<File> vdex_file(new File(output_vdex_fd_, vdex_location, /* check_usage */ true));
-      if (vdex_file.get() == nullptr) {
+      if (vdex_file == nullptr) {
         PLOG(ERROR) << "Failed to create vdex file: " << vdex_location;
         return false;
       }
@@ -1446,6 +1448,7 @@
       } else {
         if (vdex_file->SetLength(0) != 0) {
           PLOG(ERROR) << "Truncating vdex file " << vdex_location << " failed.";
+          vdex_file->Erase();
           return false;
         }
       }
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 588a3ae..29c9e92 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -74,9 +74,9 @@
         android: {
             shared_libs: [
                 "libpagemap",
-            ]
+            ],
         },
-    }
+    },
 }
 
 art_cc_test {
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 5913832..0c944ce 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -185,21 +185,14 @@
                                std::vector<MethodId*>* method_ids,
                                std::vector<FieldId*>* field_ids) {
   bool has_id = false;
-  // Iterate over all instructions.
-  const uint16_t* insns = code->Insns();
-  for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
-    const Instruction* instruction = Instruction::At(&insns[insn_idx]);
-    const uint32_t insn_width = instruction->SizeInCodeUnits();
-    if (insn_width == 0) {
-      break;
-    }
+  for (const Instruction& instruction : code->Instructions()) {
+    CHECK_GT(instruction.SizeInCodeUnits(), 0u);
     has_id |= GetIdFromInstruction(collections,
-                                   instruction,
+                                   &instruction,
                                    type_ids,
                                    string_ids,
                                    method_ids,
                                    field_ids);
-    insn_idx += insn_width;
   }  // for
   return has_id;
 }
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 362c08b..5dcc87d 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -947,6 +947,11 @@
 
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
+  IterationRange<DexInstructionIterator> Instructions() const {
+    return MakeIterationRange(DexInstructionIterator(Insns()),
+                              DexInstructionIterator(Insns() + InsnsSize()));
+  }
+
  private:
   uint16_t registers_size_;
   uint16_t ins_size_;
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 92a1366..095c960 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1079,16 +1079,15 @@
           code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
 
   // Iterate over all instructions.
-  const uint16_t* insns = code->Insns();
-  for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
-    const Instruction* instruction = Instruction::At(&insns[insn_idx]);
-    const uint32_t insn_width = instruction->SizeInCodeUnits();
+  IterationRange<DexInstructionIterator> instructions = code->Instructions();
+  for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
+    const uint32_t dex_pc = inst.GetDexPC(instructions.begin());
+    const uint32_t insn_width = inst->SizeInCodeUnits();
     if (insn_width == 0) {
-      fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
+      fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", dex_pc);
       break;
     }
-    DumpInstruction(code, code_offset, insn_idx, insn_width, instruction);
-    insn_idx += insn_width;
+    DumpInstruction(code, code_offset, dex_pc, insn_width, &*inst);
   }  // for
 }
 
diff --git a/dexoptanalyzer/Android.bp b/dexoptanalyzer/Android.bp
index 715c209..33366ad 100644
--- a/dexoptanalyzer/Android.bp
+++ b/dexoptanalyzer/Android.bp
@@ -58,7 +58,7 @@
         "art_gtest_defaults",
     ],
     shared_libs: [
-        "libbacktrace"
+        "libbacktrace",
     ],
     srcs: ["dexoptanalyzer_test.cc"],
 }
diff --git a/disassembler/Android.bp b/disassembler/Android.bp
index 086b8c7..8849309 100644
--- a/disassembler/Android.bp
+++ b/disassembler/Android.bp
@@ -18,7 +18,6 @@
     name: "libart-disassembler-defaults",
     defaults: ["art_defaults"],
     host_supported: true,
-    clang: true,
     srcs: [
         "disassembler.cc",
         "disassembler_arm.cc",
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index be78136..bcf007b 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -905,26 +905,23 @@
       if (code_item == nullptr) {
         return;
       }
-      const size_t code_item_size = code_item->insns_size_in_code_units_;
-      const uint16_t* code_ptr = code_item->insns_;
-      const uint16_t* code_end = code_item->insns_ + code_item_size;
 
+      const uint16_t* code_ptr = code_item->insns_;
       // If we inserted a new dex code item pointer, add to total code bytes.
       if (dex_code_item_ptrs_.insert(code_ptr).second) {
-        dex_code_bytes_ += code_item_size * sizeof(code_ptr[0]);
+        dex_code_bytes_ += code_item->insns_size_in_code_units_ * sizeof(code_ptr[0]);
       }
 
-      while (code_ptr < code_end) {
-        const Instruction* inst = Instruction::At(code_ptr);
-        switch (inst->Opcode()) {
+      for (const Instruction& inst : code_item->Instructions()) {
+        switch (inst.Opcode()) {
           case Instruction::CONST_STRING: {
-            const dex::StringIndex string_index(inst->VRegB_21c());
+            const dex::StringIndex string_index(inst.VRegB_21c());
             unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index));
             ++num_string_ids_from_code_;
             break;
           }
           case Instruction::CONST_STRING_JUMBO: {
-            const dex::StringIndex string_index(inst->VRegB_31c());
+            const dex::StringIndex string_index(inst.VRegB_31c());
             unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index));
             ++num_string_ids_from_code_;
             break;
@@ -932,8 +929,6 @@
           default:
             break;
         }
-
-        code_ptr += inst->SizeInCodeUnits();
       }
     }
 
@@ -1520,12 +1515,11 @@
 
   void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) {
     if (code_item != nullptr) {
-      size_t i = 0;
-      while (i < code_item->insns_size_in_code_units_) {
-        const Instruction* instruction = Instruction::At(&code_item->insns_[i]);
-        os << StringPrintf("0x%04zx: ", i) << instruction->DumpHexLE(5)
-           << StringPrintf("\t| %s\n", instruction->DumpString(&dex_file).c_str());
-        i += instruction->SizeInCodeUnits();
+      IterationRange<DexInstructionIterator> instructions = code_item->Instructions();
+      for (auto it = instructions.begin(); it != instructions.end(); ++it) {
+        const size_t dex_pc = it.GetDexPC(instructions.begin());
+        os << StringPrintf("0x%04zx: ", dex_pc) << it->DumpHexLE(5)
+           << StringPrintf("\t| %s\n", it->DumpString(&dex_file).c_str());
       }
     }
   }
diff --git a/openjdkjvm/Android.bp b/openjdkjvm/Android.bp
index 071b434..761df02 100644
--- a/openjdkjvm/Android.bp
+++ b/openjdkjvm/Android.bp
@@ -20,7 +20,7 @@
     srcs: ["OpenjdkJvm.cc"],
     shared_libs: [
         "libbase",
-        "libnativehelper"
+        "libnativehelper",
     ],
 }
 
diff --git a/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp
index b6b1b56..84a90d6 100644
--- a/openjdkjvmti/Android.bp
+++ b/openjdkjvmti/Android.bp
@@ -23,31 +23,33 @@
     name: "libopenjdkjvmti_defaults",
     defaults: ["art_defaults"],
     host_supported: true,
-    srcs: ["events.cc",
-           "fixed_up_dex_file.cc",
-           "object_tagging.cc",
-           "OpenjdkJvmTi.cc",
-           "ti_allocator.cc",
-           "ti_breakpoint.cc",
-           "ti_class.cc",
-           "ti_class_definition.cc",
-           "ti_class_loader.cc",
-           "ti_dump.cc",
-           "ti_field.cc",
-           "ti_heap.cc",
-           "ti_jni.cc",
-           "ti_method.cc",
-           "ti_monitor.cc",
-           "ti_object.cc",
-           "ti_phase.cc",
-           "ti_properties.cc",
-           "ti_search.cc",
-           "ti_stack.cc",
-           "ti_redefine.cc",
-           "ti_thread.cc",
-           "ti_threadgroup.cc",
-           "ti_timers.cc",
-           "transform.cc"],
+    srcs: [
+        "events.cc",
+        "fixed_up_dex_file.cc",
+        "object_tagging.cc",
+        "OpenjdkJvmTi.cc",
+        "ti_allocator.cc",
+        "ti_breakpoint.cc",
+        "ti_class.cc",
+        "ti_class_definition.cc",
+        "ti_class_loader.cc",
+        "ti_dump.cc",
+        "ti_field.cc",
+        "ti_heap.cc",
+        "ti_jni.cc",
+        "ti_method.cc",
+        "ti_monitor.cc",
+        "ti_object.cc",
+        "ti_phase.cc",
+        "ti_properties.cc",
+        "ti_search.cc",
+        "ti_stack.cc",
+        "ti_redefine.cc",
+        "ti_thread.cc",
+        "ti_threadgroup.cc",
+        "ti_timers.cc",
+        "transform.cc",
+    ],
     header_libs: ["libopenjdkjvmti_headers"],
     shared_libs: [
         "libbase",
diff --git a/profman/profile_assistant.cc b/profman/profile_assistant.cc
index c238f0d..ff02b5d 100644
--- a/profman/profile_assistant.cc
+++ b/profman/profile_assistant.cc
@@ -23,8 +23,11 @@
 
 // Minimum number of new methods/classes that profiles
 // must contain to enable recompilation.
-static constexpr const uint32_t kMinNewMethodsForCompilation = 10;
-static constexpr const uint32_t kMinNewClassesForCompilation = 10;
+static constexpr const uint32_t kMinNewMethodsForCompilation = 100;
+static constexpr const uint32_t kMinNewMethodsPercentChangeForCompilation = 2;
+static constexpr const uint32_t kMinNewClassesForCompilation = 50;
+static constexpr const uint32_t kMinNewClassesPercentChangeForCompilation = 2;
+
 
 ProfileAssistant::ProcessingResult ProfileAssistant::ProcessProfilesInternal(
         const std::vector<ScopedFlock>& profile_files,
@@ -55,9 +58,16 @@
     }
   }
 
+  uint32_t min_change_in_methods_for_compilation = std::max(
+      (kMinNewMethodsPercentChangeForCompilation * number_of_methods) / 100,
+      kMinNewMethodsForCompilation);
+  uint32_t min_change_in_classes_for_compilation = std::max(
+      (kMinNewClassesPercentChangeForCompilation * number_of_classes) / 100,
+      kMinNewClassesForCompilation);
   // Check if there is enough new information added by the current profiles.
-  if (((info.GetNumberOfMethods() - number_of_methods) < kMinNewMethodsForCompilation) &&
-      ((info.GetNumberOfResolvedClasses() - number_of_classes) < kMinNewClassesForCompilation)) {
+  if (((info.GetNumberOfMethods() - number_of_methods) < min_change_in_methods_for_compilation) &&
+      ((info.GetNumberOfResolvedClasses() - number_of_classes)
+          < min_change_in_classes_for_compilation)) {
     return kSkipCompilation;
   }
 
diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc
index 8cbf8c3..73724b2 100644
--- a/profman/profile_assistant_test.cc
+++ b/profman/profile_assistant_test.cc
@@ -335,6 +335,46 @@
     ASSERT_EQ(expected_clases.size(), found);
   }
 
+  int CheckCompilationMethodPercentChange(uint16_t methods_in_cur_profile,
+                                          uint16_t methods_in_ref_profile) {
+    ScratchFile profile;
+    ScratchFile reference_profile;
+    std::vector<int> profile_fds({ GetFd(profile)});
+    int reference_profile_fd = GetFd(reference_profile);
+    std::vector<uint32_t> hot_methods_cur;
+    std::vector<uint32_t> hot_methods_ref;
+    std::vector<uint32_t> empty_vector;
+    for (size_t i = 0; i < methods_in_cur_profile; ++i) {
+      hot_methods_cur.push_back(i);
+    }
+    for (size_t i = 0; i < methods_in_ref_profile; ++i) {
+      hot_methods_ref.push_back(i);
+    }
+    ProfileCompilationInfo info1;
+    uint16_t methods_in_profile = std::max(methods_in_cur_profile, methods_in_ref_profile);
+    SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_cur, empty_vector, empty_vector,
+        profile,  &info1);
+    ProfileCompilationInfo info2;
+    SetupBasicProfile("p1", 1, methods_in_profile, hot_methods_ref, empty_vector, empty_vector,
+        reference_profile,  &info2);
+    return ProcessProfiles(profile_fds, reference_profile_fd);
+  }
+
+  int CheckCompilationClassPercentChange(uint16_t classes_in_cur_profile,
+                                         uint16_t classes_in_ref_profile) {
+    ScratchFile profile;
+    ScratchFile reference_profile;
+
+    std::vector<int> profile_fds({ GetFd(profile)});
+    int reference_profile_fd = GetFd(reference_profile);
+
+    ProfileCompilationInfo info1;
+    SetupProfile("p1", 1, 0, classes_in_cur_profile, profile,  &info1);
+    ProfileCompilationInfo info2;
+    SetupProfile("p1", 1, 0, classes_in_ref_profile, reference_profile, &info2);
+    return ProcessProfiles(profile_fds, reference_profile_fd);
+  }
+
   std::unique_ptr<ArenaAllocator> arena_;
 
   // Cache of inline caches generated during tests.
@@ -460,7 +500,7 @@
       GetFd(profile2)});
   int reference_profile_fd = GetFd(reference_profile);
 
-  const uint16_t kNumberOfMethodsToSkipCompilation = 1;
+  const uint16_t kNumberOfMethodsToSkipCompilation = 24;  // Threshold is 100.
   ProfileCompilationInfo info1;
   SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
   ProfileCompilationInfo info2;
@@ -489,6 +529,42 @@
   CheckProfileInfo(profile2, info2);
 }
 
+TEST_F(ProfileAssistantTest, DoNotAdviseCompilationMethodPercentage) {
+  const uint16_t kNumberOfMethodsInRefProfile = 6000;
+  const uint16_t kNumberOfMethodsInCurProfile = 6100;  // Threshold is 2%.
+  // We should not advise compilation.
+  ASSERT_EQ(ProfileAssistant::kSkipCompilation,
+            CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
+                                                kNumberOfMethodsInRefProfile));
+}
+
+TEST_F(ProfileAssistantTest, ShouldAdviseCompilationMethodPercentage) {
+  const uint16_t kNumberOfMethodsInRefProfile = 6000;
+  const uint16_t kNumberOfMethodsInCurProfile = 6200;  // Threshold is 2%.
+  // We should advise compilation.
+  ASSERT_EQ(ProfileAssistant::kCompile,
+            CheckCompilationMethodPercentChange(kNumberOfMethodsInCurProfile,
+                                                kNumberOfMethodsInRefProfile));
+}
+
+TEST_F(ProfileAssistantTest, DoNotdviseCompilationClassPercentage) {
+  const uint16_t kNumberOfClassesInRefProfile = 6000;
+  const uint16_t kNumberOfClassesInCurProfile = 6110;  // Threshold is 2%.
+  // We should not advise compilation.
+  ASSERT_EQ(ProfileAssistant::kSkipCompilation,
+            CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
+                                               kNumberOfClassesInRefProfile));
+}
+
+TEST_F(ProfileAssistantTest, ShouldAdviseCompilationClassPercentage) {
+  const uint16_t kNumberOfClassesInRefProfile = 6000;
+  const uint16_t kNumberOfClassesInCurProfile = 6120;  // Threshold is 2%.
+  // We should advise compilation.
+  ASSERT_EQ(ProfileAssistant::kCompile,
+            CheckCompilationClassPercentChange(kNumberOfClassesInCurProfile,
+                                               kNumberOfClassesInRefProfile));
+}
+
 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
   ScratchFile profile1;
   ScratchFile profile2;
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 06e83b9..a3a45e1 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -356,10 +356,9 @@
                 "thread_android.cc",
             ],
             shared_libs: [
-                "libdl",
                 // For android::FileMap used by libziparchive.
                 "libutils",
-                "libtombstoned_client"
+                "libtombstoned_client",
             ],
             static_libs: [
                 // ZipArchive support, the order matters here to get all symbols.
@@ -398,7 +397,6 @@
     generated_headers: ["cpp-define-generator-asm-support"],
     // export our headers so the libart-gtest targets can use it as well.
     export_generated_headers: ["cpp-define-generator-asm-support"],
-    clang: true,
     include_dirs: [
         "art/sigchainlib",
         "art",
@@ -493,8 +491,8 @@
 art_cc_library {
     name: "libartd",
     defaults: [
-       "art_debug_defaults",
-       "libart_defaults",
+        "art_debug_defaults",
+        "libart_defaults",
     ],
 }
 
@@ -503,12 +501,12 @@
     defaults: ["libart-gtest-defaults"],
     srcs: [
         "common_runtime_test.cc",
-        "dexopt_test.cc"
+        "dexopt_test.cc",
     ],
     shared_libs: [
         "libartd",
         "libbase",
-        "libbacktrace"
+        "libbacktrace",
     ],
 }
 
@@ -613,7 +611,7 @@
         "libbacktrace",
     ],
     header_libs: [
-        "art_cmdlineparser_headers",  // For parsed_options_test.
+        "art_cmdlineparser_headers", // For parsed_options_test.
     ],
 }
 
@@ -635,7 +633,7 @@
 }
 
 cc_library_headers {
-  name: "libart_runtime_headers",
-  host_supported: true,
-  export_include_dirs: ["."],
+    name: "libart_runtime_headers",
+    host_supported: true,
+    export_include_dirs: ["."],
 }
diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc
index eb8ced0..6d1de00 100644
--- a/runtime/base/unix_file/fd_file.cc
+++ b/runtime/base/unix_file/fd_file.cc
@@ -70,7 +70,7 @@
     if (guard_state_ < GuardState::kClosed) {
       LOG(ERROR) << "File " << file_path_ << " wasn't explicitly closed before destruction.";
     }
-    CHECK_GE(guard_state_, GuardState::kClosed);
+    DCHECK_GE(guard_state_, GuardState::kClosed);
   }
   if (auto_close_ && fd_ != -1) {
     if (Close() != 0) {
@@ -135,7 +135,7 @@
 
 bool FdFile::Open(const std::string& path, int flags, mode_t mode) {
   static_assert(O_RDONLY == 0, "Readonly flag has unexpected value.");
-  CHECK_EQ(fd_, -1) << path;
+  DCHECK_EQ(fd_, -1) << path;
   read_only_mode_ = ((flags & O_ACCMODE) == O_RDONLY);
   fd_ = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
   if (fd_ == -1) {
@@ -158,7 +158,7 @@
 
   // Test here, so the file is closed and not leaked.
   if (kCheckSafeUsage) {
-    CHECK_GE(guard_state_, GuardState::kFlushed) << "File " << file_path_
+    DCHECK_GE(guard_state_, GuardState::kFlushed) << "File " << file_path_
         << " has not been flushed before closing.";
     moveUp(GuardState::kClosed, nullptr);
   }
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 4807427..ac91d52 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -21,9 +21,11 @@
 #include <string>
 #include <vector>
 
+#include "base/iteration_range.h"
 #include "base/logging.h"
 #include "base/value_object.h"
 #include "dex_file_types.h"
+#include "dex_instruction_iterator.h"
 #include "globals.h"
 #include "jni.h"
 #include "modifiers.h"
@@ -293,6 +295,15 @@
 
   // Raw code_item.
   struct CodeItem {
+    IterationRange<DexInstructionIterator> Instructions() const {
+      return { DexInstructionIterator(insns_),
+               DexInstructionIterator(insns_ + insns_size_in_code_units_)};
+    }
+
+    const Instruction& InstructionAt(uint32_t dex_pc) const {
+      return *Instruction::At(insns_ + dex_pc);
+    }
+
     uint16_t registers_size_;            // the number of registers used by this code
                                          //   (locals + parameters)
     uint16_t ins_size_;                  // the number of words of incoming arguments to the method
diff --git a/runtime/dex_instruction_iterator.h b/runtime/dex_instruction_iterator.h
new file mode 100644
index 0000000..6585875
--- /dev/null
+++ b/runtime/dex_instruction_iterator.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 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_DEX_INSTRUCTION_ITERATOR_H_
+#define ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_
+
+#include <iterator>
+
+#include "dex_instruction.h"
+#include "base/logging.h"
+
+namespace art {
+
+class DexInstructionIterator : public std::iterator<std::forward_iterator_tag, Instruction> {
+ public:
+  using Type = std::iterator<std::forward_iterator_tag, Instruction>::value_type;
+  using difference_type = typename std::iterator<std::forward_iterator_tag, Type>::difference_type;
+
+  DexInstructionIterator() = default;
+  DexInstructionIterator(const DexInstructionIterator&) = default;
+  DexInstructionIterator(DexInstructionIterator&&) = default;
+  DexInstructionIterator& operator=(const DexInstructionIterator&) = default;
+  DexInstructionIterator& operator=(DexInstructionIterator&&) = default;
+
+  explicit DexInstructionIterator(const Type* inst) : inst_(inst) {}
+  explicit DexInstructionIterator(const uint16_t* inst) : inst_(Type::At(inst)) {}
+
+  ALWAYS_INLINE bool operator==(const DexInstructionIterator& other) const {
+    return inst_ == other.inst_ || inst_ == nullptr || other.inst_ == nullptr;
+  }
+
+  // Value after modification.
+  DexInstructionIterator& operator++() {
+    inst_ = inst_->Next();
+    return *this;
+  }
+
+  // Value before modification.
+  DexInstructionIterator operator++(int) {
+    DexInstructionIterator temp = *this;
+    ++*this;
+    return temp;
+  }
+
+  const Type& operator*() const {
+    return *inst_;
+  }
+
+  const Type* operator->() const {
+    return &**this;
+  }
+
+  // Return the dex pc for an iterator compared to the code item begin.
+  uint32_t GetDexPC(const DexInstructionIterator& code_item_begin) {
+    return reinterpret_cast<const uint16_t*>(inst_) -
+        reinterpret_cast<const uint16_t*>(code_item_begin.inst_);
+  }
+
+  const Type* Inst() const {
+    return inst_;
+  }
+
+ private:
+  const Type* inst_ = nullptr;
+};
+
+static inline bool operator!=(const DexInstructionIterator& lhs,
+                              const DexInstructionIterator& rhs) {
+  return !(lhs == rhs);
+}
+
+static inline bool operator<(const DexInstructionIterator& lhs,
+                             const DexInstructionIterator& rhs) {
+  return lhs.Inst() < rhs.Inst();
+}
+
+static inline bool operator>(const DexInstructionIterator& lhs,
+                             const DexInstructionIterator& rhs) {
+  return rhs < lhs;
+}
+
+static inline bool operator<=(const DexInstructionIterator& lhs,
+                              const DexInstructionIterator& rhs) {
+  return !(rhs < lhs);
+}
+
+static inline bool operator>=(const DexInstructionIterator& lhs,
+                              const DexInstructionIterator& rhs) {
+  return !(lhs < rhs);
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_
diff --git a/runtime/dex_instruction_test.cc b/runtime/dex_instruction_test.cc
index 3f7ac57..48ed027 100644
--- a/runtime/dex_instruction_test.cc
+++ b/runtime/dex_instruction_test.cc
@@ -15,6 +15,7 @@
  */
 
 #include "dex_instruction-inl.h"
+#include "dex_instruction_iterator.h"
 #include "gtest/gtest.h"
 
 namespace art {
@@ -73,7 +74,7 @@
   Build45cc(4u /* num_vregs */, 16u /* method_idx */, 32u /* proto_idx */,
             0xcafe /* arg_regs */, instruction);
 
-  const Instruction* ins = Instruction::At(instruction);
+  DexInstructionIterator ins(instruction);
   ASSERT_EQ(4u, ins->SizeInCodeUnits());
 
   ASSERT_TRUE(ins->HasVRegA());
@@ -108,7 +109,7 @@
   Build4rcc(4u /* num_vregs */, 16u /* method_idx */, 32u /* proto_idx */,
             0xcafe /* arg_regs */, instruction);
 
-  const Instruction* ins = Instruction::At(instruction);
+  DexInstructionIterator ins(instruction);
   ASSERT_EQ(4u, ins->SizeInCodeUnits());
 
   ASSERT_TRUE(ins->HasVRegA());
@@ -154,7 +155,7 @@
                                std::vector<uint16_t> args) {
   uint16_t inst[6] = {};
   Build35c(inst, code, method_idx, args);
-  return Instruction::At(inst)->DumpString(nullptr);
+  return DexInstructionIterator(inst)->DumpString(nullptr);
 }
 
 TEST(Instruction, DumpString) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 211381c..eef2773 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1119,7 +1119,7 @@
       const DexFile::CodeItem* code;
       code = caller->GetCodeItem();
       CHECK_LT(dex_pc, code->insns_size_in_code_units_);
-      const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
+      const Instruction* instr = &code->InstructionAt(dex_pc);
       Instruction::Code instr_code = instr->Opcode();
       bool is_range;
       switch (instr_code) {
@@ -2484,7 +2484,7 @@
     uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
     const DexFile::CodeItem* code_item = caller_method->GetCodeItem();
     DCHECK_LT(dex_pc, code_item->insns_size_in_code_units_);
-    const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]);
+    const Instruction* instr = &code_item->InstructionAt(dex_pc);
     Instruction::Code instr_code = instr->Opcode();
     DCHECK(instr_code == Instruction::INVOKE_INTERFACE ||
            instr_code == Instruction::INVOKE_INTERFACE_RANGE)
@@ -2600,7 +2600,7 @@
   ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
   uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
   const DexFile::CodeItem* code = caller_method->GetCodeItem();
-  const Instruction* inst = Instruction::At(&code->insns_[dex_pc]);
+  const Instruction* inst = &code->InstructionAt(dex_pc);
   DCHECK(inst->Opcode() == Instruction::INVOKE_POLYMORPHIC ||
          inst->Opcode() == Instruction::INVOKE_POLYMORPHIC_RANGE);
   const DexFile* dex_file = caller_method->GetDexFile();
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index cff3ea7..2dd4db3 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -237,7 +237,8 @@
 }
 
 IndirectRef IndirectReferenceTable::Add(IRTSegmentState previous_state,
-                                        ObjPtr<mirror::Object> obj) {
+                                        ObjPtr<mirror::Object> obj,
+                                        std::string* error_msg) {
   if (kDebugIRT) {
     LOG(INFO) << "+++ Add: previous_state=" << previous_state.top_index
               << " top_index=" << segment_state_.top_index
@@ -253,28 +254,34 @@
 
   if (top_index == max_entries_) {
     if (resizable_ == ResizableCapacity::kNo) {
-      LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow "
-                 << "(max=" << max_entries_ << ")\n"
-                 << MutatorLockedDumpable<IndirectReferenceTable>(*this);
-      UNREACHABLE();
+      std::ostringstream oss;
+      oss << "JNI ERROR (app bug): " << kind_ << " table overflow "
+          << "(max=" << max_entries_ << ")"
+          << MutatorLockedDumpable<IndirectReferenceTable>(*this);
+      *error_msg = oss.str();
+      return nullptr;
     }
 
     // Try to double space.
     if (std::numeric_limits<size_t>::max() / 2 < max_entries_) {
-      LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow "
-                 << "(max=" << max_entries_ << ")" << std::endl
-                 << MutatorLockedDumpable<IndirectReferenceTable>(*this)
-                << " Resizing failed: exceeds size_t";
-      UNREACHABLE();
+      std::ostringstream oss;
+      oss << "JNI ERROR (app bug): " << kind_ << " table overflow "
+          << "(max=" << max_entries_ << ")" << std::endl
+          << MutatorLockedDumpable<IndirectReferenceTable>(*this)
+          << " Resizing failed: exceeds size_t";
+      *error_msg = oss.str();
+      return nullptr;
     }
 
-    std::string error_msg;
-    if (!Resize(max_entries_ * 2, &error_msg)) {
-      LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow "
-                 << "(max=" << max_entries_ << ")" << std::endl
-                 << MutatorLockedDumpable<IndirectReferenceTable>(*this)
-                 << " Resizing failed: " << error_msg;
-      UNREACHABLE();
+    std::string inner_error_msg;
+    if (!Resize(max_entries_ * 2, &inner_error_msg)) {
+      std::ostringstream oss;
+      oss << "JNI ERROR (app bug): " << kind_ << " table overflow "
+          << "(max=" << max_entries_ << ")" << std::endl
+          << MutatorLockedDumpable<IndirectReferenceTable>(*this)
+          << " Resizing failed: " << inner_error_msg;
+      *error_msg = oss.str();
+      return nullptr;
     }
   }
 
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index 6d52d95..bf287b1 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -244,8 +244,10 @@
   bool IsValid() const;
 
   // Add a new entry. "obj" must be a valid non-null object reference. This function will
-  // abort if the table is full (max entries reached, or expansion failed).
-  IndirectRef Add(IRTSegmentState previous_state, ObjPtr<mirror::Object> obj)
+  // return null if an error happened (with an appropriate error message set).
+  IndirectRef Add(IRTSegmentState previous_state,
+                  ObjPtr<mirror::Object> obj,
+                  std::string* error_msg)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Given an IndirectRef in the table, return the Object it refers to.
diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc
index 6aefe23..9278509 100644
--- a/runtime/indirect_reference_table_test.cc
+++ b/runtime/indirect_reference_table_test.cc
@@ -80,13 +80,13 @@
   EXPECT_FALSE(irt.Remove(cookie, iref0)) << "unexpectedly successful removal";
 
   // Add three, check, remove in the order in which they were added.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
-  IndirectRef iref1 = irt.Add(cookie, obj1.Get());
+  IndirectRef iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
   CheckDump(&irt, 2, 2);
-  IndirectRef iref2 = irt.Add(cookie, obj2.Get());
+  IndirectRef iref2 = irt.Add(cookie, obj2.Get(), &error_msg);
   EXPECT_TRUE(iref2 != nullptr);
   CheckDump(&irt, 3, 3);
 
@@ -108,11 +108,11 @@
   EXPECT_TRUE(irt.Get(iref0) == nullptr);
 
   // Add three, remove in the opposite order.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
-  iref1 = irt.Add(cookie, obj1.Get());
+  iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
-  iref2 = irt.Add(cookie, obj2.Get());
+  iref2 = irt.Add(cookie, obj2.Get(), &error_msg);
   EXPECT_TRUE(iref2 != nullptr);
   CheckDump(&irt, 3, 3);
 
@@ -128,11 +128,11 @@
 
   // Add three, remove middle / middle / bottom / top.  (Second attempt
   // to remove middle should fail.)
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
-  iref1 = irt.Add(cookie, obj1.Get());
+  iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
-  iref2 = irt.Add(cookie, obj2.Get());
+  iref2 = irt.Add(cookie, obj2.Get(), &error_msg);
   EXPECT_TRUE(iref2 != nullptr);
   CheckDump(&irt, 3, 3);
 
@@ -157,20 +157,20 @@
   // Add four entries.  Remove #1, add new entry, verify that table size
   // is still 4 (i.e. holes are getting filled).  Remove #1 and #3, verify
   // that we delete one and don't hole-compact the other.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
-  iref1 = irt.Add(cookie, obj1.Get());
+  iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
-  iref2 = irt.Add(cookie, obj2.Get());
+  iref2 = irt.Add(cookie, obj2.Get(), &error_msg);
   EXPECT_TRUE(iref2 != nullptr);
-  IndirectRef iref3 = irt.Add(cookie, obj3.Get());
+  IndirectRef iref3 = irt.Add(cookie, obj3.Get(), &error_msg);
   EXPECT_TRUE(iref3 != nullptr);
   CheckDump(&irt, 4, 4);
 
   ASSERT_TRUE(irt.Remove(cookie, iref1));
   CheckDump(&irt, 3, 3);
 
-  iref1 = irt.Add(cookie, obj1.Get());
+  iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
 
   ASSERT_EQ(4U, irt.Capacity()) << "hole not filled";
@@ -193,12 +193,12 @@
   // Add an entry, remove it, add a new entry, and try to use the original
   // iref.  They have the same slot number but are for different objects.
   // With the extended checks in place, this should fail.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_TRUE(irt.Remove(cookie, iref0));
   CheckDump(&irt, 0, 0);
-  iref1 = irt.Add(cookie, obj1.Get());
+  iref1 = irt.Add(cookie, obj1.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_FALSE(irt.Remove(cookie, iref0)) << "mismatched del succeeded";
@@ -209,12 +209,12 @@
 
   // Same as above, but with the same object.  A more rigorous checker
   // (e.g. with slot serialization) will catch this.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_TRUE(irt.Remove(cookie, iref0));
   CheckDump(&irt, 0, 0);
-  iref1 = irt.Add(cookie, obj0.Get());
+  iref1 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref1 != nullptr);
   CheckDump(&irt, 1, 1);
   if (iref0 != iref1) {
@@ -229,7 +229,7 @@
   ASSERT_TRUE(irt.Get(nullptr) == nullptr);
 
   // Stale lookup.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   EXPECT_TRUE(iref0 != nullptr);
   CheckDump(&irt, 1, 1);
   ASSERT_TRUE(irt.Remove(cookie, iref0));
@@ -241,12 +241,12 @@
   static const size_t kTableInitial = kTableMax / 2;
   IndirectRef manyRefs[kTableInitial];
   for (size_t i = 0; i < kTableInitial; i++) {
-    manyRefs[i] = irt.Add(cookie, obj0.Get());
+    manyRefs[i] = irt.Add(cookie, obj0.Get(), &error_msg);
     ASSERT_TRUE(manyRefs[i] != nullptr) << "Failed adding " << i;
     CheckDump(&irt, i + 1, 1);
   }
   // ...this one causes overflow.
-  iref0 = irt.Add(cookie, obj0.Get());
+  iref0 = irt.Add(cookie, obj0.Get(), &error_msg);
   ASSERT_TRUE(iref0 != nullptr);
   ASSERT_EQ(kTableInitial + 1, irt.Capacity());
   CheckDump(&irt, kTableInitial + 1, 1);
@@ -306,16 +306,16 @@
 
     CheckDump(&irt, 0, 0);
 
-    IndirectRef iref0 = irt.Add(cookie0, obj0.Get());
-    IndirectRef iref1 = irt.Add(cookie0, obj1.Get());
-    IndirectRef iref2 = irt.Add(cookie0, obj2.Get());
+    IndirectRef iref0 = irt.Add(cookie0, obj0.Get(), &error_msg);
+    IndirectRef iref1 = irt.Add(cookie0, obj1.Get(), &error_msg);
+    IndirectRef iref2 = irt.Add(cookie0, obj2.Get(), &error_msg);
 
     EXPECT_TRUE(irt.Remove(cookie0, iref1));
 
     // New segment.
     const IRTSegmentState cookie1 = irt.GetSegmentState();
 
-    IndirectRef iref3 = irt.Add(cookie1, obj3.Get());
+    IndirectRef iref3 = irt.Add(cookie1, obj3.Get(), &error_msg);
 
     // Must not have filled the previous hole.
     EXPECT_EQ(irt.Capacity(), 4u);
@@ -337,21 +337,21 @@
 
     CheckDump(&irt, 0, 0);
 
-    IndirectRef iref0 = irt.Add(cookie0, obj0.Get());
+    IndirectRef iref0 = irt.Add(cookie0, obj0.Get(), &error_msg);
 
     // New segment.
     const IRTSegmentState cookie1 = irt.GetSegmentState();
 
-    IndirectRef iref1 = irt.Add(cookie1, obj1.Get());
-    IndirectRef iref2 = irt.Add(cookie1, obj2.Get());
-    IndirectRef iref3 = irt.Add(cookie1, obj3.Get());
+    IndirectRef iref1 = irt.Add(cookie1, obj1.Get(), &error_msg);
+    IndirectRef iref2 = irt.Add(cookie1, obj2.Get(), &error_msg);
+    IndirectRef iref3 = irt.Add(cookie1, obj3.Get(), &error_msg);
 
     EXPECT_TRUE(irt.Remove(cookie1, iref2));
 
     // Pop segment.
     irt.SetSegmentState(cookie1);
 
-    IndirectRef iref4 = irt.Add(cookie1, obj4.Get());
+    IndirectRef iref4 = irt.Add(cookie1, obj4.Get(), &error_msg);
 
     EXPECT_EQ(irt.Capacity(), 2u);
     EXPECT_TRUE(irt.Get(iref2) == nullptr);
@@ -373,25 +373,25 @@
 
     CheckDump(&irt, 0, 0);
 
-    IndirectRef iref0 = irt.Add(cookie0, obj0.Get());
+    IndirectRef iref0 = irt.Add(cookie0, obj0.Get(), &error_msg);
 
     // New segment.
     const IRTSegmentState cookie1 = irt.GetSegmentState();
 
-    IndirectRef iref1 = irt.Add(cookie1, obj1.Get());
-    IndirectRef iref2 = irt.Add(cookie1, obj2.Get());
+    IndirectRef iref1 = irt.Add(cookie1, obj1.Get(), &error_msg);
+    IndirectRef iref2 = irt.Add(cookie1, obj2.Get(), &error_msg);
 
     EXPECT_TRUE(irt.Remove(cookie1, iref1));
 
     // New segment.
     const IRTSegmentState cookie2 = irt.GetSegmentState();
 
-    IndirectRef iref3 = irt.Add(cookie2, obj3.Get());
+    IndirectRef iref3 = irt.Add(cookie2, obj3.Get(), &error_msg);
 
     // Pop segment.
     irt.SetSegmentState(cookie2);
 
-    IndirectRef iref4 = irt.Add(cookie1, obj4.Get());
+    IndirectRef iref4 = irt.Add(cookie1, obj4.Get(), &error_msg);
 
     EXPECT_EQ(irt.Capacity(), 3u);
     EXPECT_TRUE(irt.Get(iref1) == nullptr);
@@ -412,20 +412,20 @@
 
     CheckDump(&irt, 0, 0);
 
-    IndirectRef iref0 = irt.Add(cookie0, obj0.Get());
+    IndirectRef iref0 = irt.Add(cookie0, obj0.Get(), &error_msg);
 
     // New segment.
     const IRTSegmentState cookie1 = irt.GetSegmentState();
 
-    IndirectRef iref1 = irt.Add(cookie1, obj1.Get());
+    IndirectRef iref1 = irt.Add(cookie1, obj1.Get(), &error_msg);
     EXPECT_TRUE(irt.Remove(cookie1, iref1));
 
     // Emptied segment, push new one.
     const IRTSegmentState cookie2 = irt.GetSegmentState();
 
-    IndirectRef iref2 = irt.Add(cookie1, obj1.Get());
-    IndirectRef iref3 = irt.Add(cookie1, obj2.Get());
-    IndirectRef iref4 = irt.Add(cookie1, obj3.Get());
+    IndirectRef iref2 = irt.Add(cookie1, obj1.Get(), &error_msg);
+    IndirectRef iref3 = irt.Add(cookie1, obj2.Get(), &error_msg);
+    IndirectRef iref4 = irt.Add(cookie1, obj3.Get(), &error_msg);
 
     EXPECT_TRUE(irt.Remove(cookie1, iref3));
 
@@ -433,7 +433,7 @@
     UNUSED(cookie2);
     irt.SetSegmentState(cookie1);
 
-    IndirectRef iref5 = irt.Add(cookie1, obj4.Get());
+    IndirectRef iref5 = irt.Add(cookie1, obj4.Get(), &error_msg);
 
     EXPECT_EQ(irt.Capacity(), 2u);
     EXPECT_TRUE(irt.Get(iref3) == nullptr);
@@ -455,14 +455,14 @@
 
     CheckDump(&irt, 0, 0);
 
-    IndirectRef iref0 = irt.Add(cookie0, obj0.Get());
+    IndirectRef iref0 = irt.Add(cookie0, obj0.Get(), &error_msg);
 
     // New segment.
     const IRTSegmentState cookie1 = irt.GetSegmentState();
 
-    IndirectRef iref1 = irt.Add(cookie1, obj1.Get());
-    IndirectRef iref2 = irt.Add(cookie1, obj1.Get());
-    IndirectRef iref3 = irt.Add(cookie1, obj2.Get());
+    IndirectRef iref1 = irt.Add(cookie1, obj1.Get(), &error_msg);
+    IndirectRef iref2 = irt.Add(cookie1, obj1.Get(), &error_msg);
+    IndirectRef iref3 = irt.Add(cookie1, obj2.Get(), &error_msg);
 
     EXPECT_TRUE(irt.Remove(cookie1, iref2));
 
@@ -473,7 +473,7 @@
     const IRTSegmentState cookie1_second = irt.GetSegmentState();
     UNUSED(cookie1_second);
 
-    IndirectRef iref4 = irt.Add(cookie1, obj3.Get());
+    IndirectRef iref4 = irt.Add(cookie1, obj3.Get(), &error_msg);
 
     EXPECT_EQ(irt.Capacity(), 2u);
     EXPECT_TRUE(irt.Get(iref3) == nullptr);
@@ -504,7 +504,7 @@
   const IRTSegmentState cookie = kIRTFirstSegment;
 
   for (size_t i = 0; i != kTableMax + 1; ++i) {
-    irt.Add(cookie, obj0.Get());
+    irt.Add(cookie, obj0.Get(), &error_msg);
   }
 
   EXPECT_EQ(irt.Capacity(), kTableMax + 1);
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 71ab01e..fb37825 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -393,7 +393,7 @@
 
   // create instruction data for invoke-direct {v0, v1} of method with fake index
   uint16_t inst_data[3] = { 0x2070, 0x0000, 0x0010 };
-  const Instruction* inst = Instruction::At(inst_data);
+  DexInstructionIterator inst(inst_data);
 
   JValue result;
   ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, method, 0);
@@ -403,7 +403,7 @@
   shadow_frame->SetVRegReference(0, reference_empty_string);
   shadow_frame->SetVRegReference(1, string_arg);
 
-  interpreter::DoCall<false, false>(method, self, *shadow_frame, inst, inst_data[0], &result);
+  interpreter::DoCall<false, false>(method, self, *shadow_frame, &*inst, inst_data[0], &result);
   mirror::String* string_result = reinterpret_cast<mirror::String*>(result.GetL());
   EXPECT_EQ(string_arg->GetLength(), string_result->GetLength());
 
@@ -1027,12 +1027,12 @@
 
   // create instruction data for invoke-direct {v0, v1} of method with fake index
   uint16_t inst_data[3] = { 0x2070, 0x0000, 0x0010 };
-  const Instruction* inst = Instruction::At(inst_data);
+  DexInstructionIterator inst(inst_data);
 
   JValue result;
   ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, method, 0);
   shadow_frame->SetVRegDouble(0, 1.23);
-  interpreter::DoCall<false, false>(method, self, *shadow_frame, inst, inst_data[0], &result);
+  interpreter::DoCall<false, false>(method, self, *shadow_frame, &*inst, inst_data[0], &result);
   ObjPtr<mirror::String> string_result = reinterpret_cast<mirror::String*>(result.GetL());
   ASSERT_TRUE(string_result != nullptr);
 
@@ -1187,12 +1187,12 @@
 
       // create instruction data for invoke-direct {v0} of method with fake index
       uint16_t inst_data[3] = { 0x1070, 0x0000, 0x0010 };
-      const Instruction* inst = Instruction::At(inst_data);
+      DexInstructionIterator inst(inst_data);
 
       interpreter::DoCall<false, false>(boot_cp_init,
                                         self,
                                         *shadow_frame,
-                                        inst,
+                                        &*inst,
                                         inst_data[0],
                                         &result);
       CHECK(!self->IsExceptionPending());
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index c0d1861..5a16053 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -589,7 +589,12 @@
     return nullptr;
   }
   WriterMutexLock mu(self, *Locks::jni_globals_lock_);
-  IndirectRef ref = globals_.Add(kIRTFirstSegment, obj);
+  std::string error_msg;
+  IndirectRef ref = globals_.Add(kIRTFirstSegment, obj, &error_msg);
+  if (UNLIKELY(ref == nullptr)) {
+    LOG(FATAL) << error_msg;
+    UNREACHABLE();
+  }
   return reinterpret_cast<jobject>(ref);
 }
 
@@ -607,7 +612,12 @@
     self->CheckEmptyCheckpointFromWeakRefAccess(Locks::jni_weak_globals_lock_);
     weak_globals_add_condition_.WaitHoldingLocks(self);
   }
-  IndirectRef ref = weak_globals_.Add(kIRTFirstSegment, obj);
+  std::string error_msg;
+  IndirectRef ref = weak_globals_.Add(kIRTFirstSegment, obj, &error_msg);
+  if (UNLIKELY(ref == nullptr)) {
+    LOG(FATAL) << error_msg;
+    UNREACHABLE();
+  }
   return reinterpret_cast<jweak>(ref);
 }
 
diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc
index 1bd095a..ad01324 100644
--- a/runtime/jit/profiling_info.cc
+++ b/runtime/jit/profiling_info.cc
@@ -43,15 +43,12 @@
   // instructions we are interested in profiling.
   DCHECK(!method->IsNative());
 
-  const DexFile::CodeItem& code_item = *method->GetCodeItem();
-  const uint16_t* code_ptr = code_item.insns_;
-  const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
-
-  uint32_t dex_pc = 0;
   std::vector<uint32_t> entries;
-  while (code_ptr < code_end) {
-    const Instruction& instruction = *Instruction::At(code_ptr);
-    switch (instruction.Opcode()) {
+
+  IterationRange<DexInstructionIterator> instructions = method->GetCodeItem()->Instructions();
+  for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
+    const uint32_t dex_pc = inst.GetDexPC(instructions.begin());
+    switch (inst->Opcode()) {
       case Instruction::INVOKE_VIRTUAL:
       case Instruction::INVOKE_VIRTUAL_RANGE:
       case Instruction::INVOKE_VIRTUAL_QUICK:
@@ -64,8 +61,6 @@
       default:
         break;
     }
-    dex_pc += instruction.SizeInCodeUnits();
-    code_ptr += instruction.SizeInCodeUnits();
   }
 
   // We always create a `ProfilingInfo` object, even if there is no instruction we are
diff --git a/runtime/jni_env_ext-inl.h b/runtime/jni_env_ext-inl.h
index 25893b7..d66df08 100644
--- a/runtime/jni_env_ext-inl.h
+++ b/runtime/jni_env_ext-inl.h
@@ -25,7 +25,13 @@
 
 template<typename T>
 inline T JNIEnvExt::AddLocalReference(ObjPtr<mirror::Object> obj) {
-  IndirectRef ref = locals.Add(local_ref_cookie, obj);
+  std::string error_msg;
+  IndirectRef ref = locals.Add(local_ref_cookie, obj, &error_msg);
+  if (UNLIKELY(ref == nullptr)) {
+    // This is really unexpected if we allow resizing local IRTs...
+    LOG(FATAL) << error_msg;
+    UNREACHABLE();
+  }
 
   // TODO: fix this to understand PushLocalFrame, so we can turn it on.
   if (false) {
diff --git a/runtime/jni_env_ext.cc b/runtime/jni_env_ext.cc
index 3ff94f9..8352657 100644
--- a/runtime/jni_env_ext.cc
+++ b/runtime/jni_env_ext.cc
@@ -99,7 +99,14 @@
   if (obj == nullptr) {
     return nullptr;
   }
-  return reinterpret_cast<jobject>(locals.Add(local_ref_cookie, obj));
+  std::string error_msg;
+  jobject ref = reinterpret_cast<jobject>(locals.Add(local_ref_cookie, obj, &error_msg));
+  if (UNLIKELY(ref == nullptr)) {
+    // This is really unexpected if we allow resizing local IRTs...
+    LOG(FATAL) << error_msg;
+    UNREACHABLE();
+  }
+  return ref;
 }
 
 void JNIEnvExt::DeleteLocalRef(jobject obj) {
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 77a5b55..78f6b25 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -128,7 +128,8 @@
 }
 
 inline ArraySlice<ArtMethod> Class::GetDirectMethodsSliceUnchecked(PointerSize pointer_size) {
-  return GetMethodsSliceRangeUnchecked(pointer_size,
+  return GetMethodsSliceRangeUnchecked(GetMethodsPtr(),
+                                       pointer_size,
                                        GetDirectMethodsStartOffset(),
                                        GetVirtualMethodsStartOffset());
 }
@@ -140,7 +141,8 @@
 }
 
 inline ArraySlice<ArtMethod> Class::GetDeclaredMethodsSliceUnchecked(PointerSize pointer_size) {
-  return GetMethodsSliceRangeUnchecked(pointer_size,
+  return GetMethodsSliceRangeUnchecked(GetMethodsPtr(),
+                                       pointer_size,
                                        GetDirectMethodsStartOffset(),
                                        GetCopiedMethodsStartOffset());
 }
@@ -152,7 +154,8 @@
 
 inline ArraySlice<ArtMethod> Class::GetDeclaredVirtualMethodsSliceUnchecked(
     PointerSize pointer_size) {
-  return GetMethodsSliceRangeUnchecked(pointer_size,
+  return GetMethodsSliceRangeUnchecked(GetMethodsPtr(),
+                                       pointer_size,
                                        GetVirtualMethodsStartOffset(),
                                        GetCopiedMethodsStartOffset());
 }
@@ -164,9 +167,11 @@
 }
 
 inline ArraySlice<ArtMethod> Class::GetVirtualMethodsSliceUnchecked(PointerSize pointer_size) {
-  return GetMethodsSliceRangeUnchecked(pointer_size,
+  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
+  return GetMethodsSliceRangeUnchecked(methods,
+                                       pointer_size,
                                        GetVirtualMethodsStartOffset(),
-                                       NumMethods());
+                                       NumMethods(methods));
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -176,7 +181,11 @@
 }
 
 inline ArraySlice<ArtMethod> Class::GetCopiedMethodsSliceUnchecked(PointerSize pointer_size) {
-  return GetMethodsSliceRangeUnchecked(pointer_size, GetCopiedMethodsStartOffset(), NumMethods());
+  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
+  return GetMethodsSliceRangeUnchecked(methods,
+                                       pointer_size,
+                                       GetCopiedMethodsStartOffset(),
+                                       NumMethods(methods));
 }
 
 inline LengthPrefixedArray<ArtMethod>* Class::GetMethodsPtr() {
@@ -187,19 +196,21 @@
 template<VerifyObjectFlags kVerifyFlags>
 inline ArraySlice<ArtMethod> Class::GetMethodsSlice(PointerSize pointer_size) {
   DCHECK(IsLoaded() || IsErroneous());
-  return GetMethodsSliceRangeUnchecked(pointer_size, 0, NumMethods());
+  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
+  return GetMethodsSliceRangeUnchecked(methods, pointer_size, 0, NumMethods(methods));
 }
 
-inline ArraySlice<ArtMethod> Class::GetMethodsSliceRangeUnchecked(PointerSize pointer_size,
-                                                                  uint32_t start_offset,
-                                                                  uint32_t end_offset) {
+inline ArraySlice<ArtMethod> Class::GetMethodsSliceRangeUnchecked(
+    LengthPrefixedArray<ArtMethod>* methods,
+    PointerSize pointer_size,
+    uint32_t start_offset,
+    uint32_t end_offset) {
   DCHECK_LE(start_offset, end_offset);
-  DCHECK_LE(end_offset, NumMethods());
+  DCHECK_LE(end_offset, NumMethods(methods));
   uint32_t size = end_offset - start_offset;
   if (size == 0u) {
     return ArraySlice<ArtMethod>();
   }
-  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
   DCHECK(methods != nullptr);
   DCHECK_LE(end_offset, methods->size());
   size_t method_size = ArtMethod::Size(pointer_size);
@@ -211,7 +222,10 @@
 }
 
 inline uint32_t Class::NumMethods() {
-  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
+  return NumMethods(GetMethodsPtr());
+}
+
+inline uint32_t Class::NumMethods(LengthPrefixedArray<ArtMethod>* methods) {
   return (methods == nullptr) ? 0 : methods->size();
 }
 
@@ -969,7 +983,8 @@
 
 inline ArraySlice<ArtMethod> Class::GetMethods(PointerSize pointer_size) {
   CheckPointerSize(pointer_size);
-  return GetMethodsSliceRangeUnchecked(pointer_size, 0u, NumMethods());
+  LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr();
+  return GetMethodsSliceRangeUnchecked(methods, pointer_size, 0u, NumMethods(methods));
 }
 
 inline IterationRange<StrideIterator<ArtField>> Class::GetIFields() {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index c44b616..148273b 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -773,6 +773,8 @@
   ALWAYS_INLINE uint32_t NumDeclaredVirtualMethods() REQUIRES_SHARED(Locks::mutator_lock_);
 
   ALWAYS_INLINE uint32_t NumMethods() REQUIRES_SHARED(Locks::mutator_lock_);
+  static ALWAYS_INLINE uint32_t NumMethods(LengthPrefixedArray<ArtMethod>* methods)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ArtMethod* GetVirtualMethod(size_t i, PointerSize pointer_size)
@@ -1294,9 +1296,11 @@
   ALWAYS_INLINE void SetMethodsPtrInternal(LengthPrefixedArray<ArtMethod>* new_methods)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ALWAYS_INLINE ArraySlice<ArtMethod> GetMethodsSliceRangeUnchecked(PointerSize pointer_size,
-                                                                    uint32_t start_offset,
-                                                                    uint32_t end_offset)
+  ALWAYS_INLINE static ArraySlice<ArtMethod> GetMethodsSliceRangeUnchecked(
+      LengthPrefixedArray<ArtMethod>* methods,
+      PointerSize pointer_size,
+      uint32_t start_offset,
+      uint32_t end_offset)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   template <bool throw_on_failure>
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index e4ad55d..b789ac6 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -616,18 +616,11 @@
 }
 
 static bool HasMonitorEnterInstructions(const DexFile::CodeItem* const code_item) {
-  const Instruction* inst = Instruction::At(code_item->insns_);
-
-  uint32_t insns_size = code_item->insns_size_in_code_units_;
-  for (uint32_t dex_pc = 0; dex_pc < insns_size;) {
-    if (inst->Opcode() == Instruction::MONITOR_ENTER) {
+  for (const Instruction& inst : code_item->Instructions()) {
+    if (inst.Opcode() == Instruction::MONITOR_ENTER) {
       return true;
     }
-
-    dex_pc += inst->SizeInCodeUnits();
-    inst = inst->Next();
   }
-
   return false;
 }
 
@@ -683,7 +676,7 @@
   if (register_line == nullptr) {
     return nullptr;
   }
-  const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
+  const Instruction* inst = &code_item_->InstructionAt(dex_pc);
   return GetQuickFieldAccess(inst, register_line);
 }
 
@@ -723,7 +716,7 @@
   if (register_line == nullptr) {
     return nullptr;
   }
-  const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
+  const Instruction* inst = &code_item_->InstructionAt(dex_pc);
   const bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
   return GetQuickInvokedMethod(inst, register_line, is_range, false);
 }
@@ -929,9 +922,8 @@
         // Note: this can fail before we touch any instruction, for the signature of a method. So
         //       add a check.
         if (work_insn_idx_ < dex::kDexNoIndex) {
-          const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
-          const Instruction* inst = Instruction::At(insns);
-          int opcode_flags = Instruction::FlagsOf(inst->Opcode());
+          const Instruction& inst = code_item_->InstructionAt(work_insn_idx_);
+          int opcode_flags = Instruction::FlagsOf(inst.Opcode());
 
           if ((opcode_flags & Instruction::kThrow) == 0 && CurrentInsnFlags()->IsInTry()) {
             saved_line_->CopyFromLine(work_line_.get());
@@ -990,14 +982,12 @@
 }
 
 bool MethodVerifier::ComputeWidthsAndCountOps() {
-  const uint16_t* insns = code_item_->insns_;
-  size_t insns_size = code_item_->insns_size_in_code_units_;
-  const Instruction* inst = Instruction::At(insns);
   size_t new_instance_count = 0;
   size_t monitor_enter_count = 0;
-  size_t dex_pc = 0;
 
-  while (dex_pc < insns_size) {
+  IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
+  DexInstructionIterator inst = instructions.begin();
+  for ( ; inst < instructions.end(); ++inst) {
     Instruction::Code opcode = inst->Opcode();
     switch (opcode) {
       case Instruction::APUT_OBJECT:
@@ -1019,15 +1009,14 @@
       default:
         break;
     }
-    size_t inst_size = inst->SizeInCodeUnits();
-    GetInstructionFlags(dex_pc).SetIsOpcode();
-    dex_pc += inst_size;
-    inst = inst->RelativeAt(inst_size);
+    GetInstructionFlags(inst.GetDexPC(instructions.begin())).SetIsOpcode();
   }
 
-  if (dex_pc != insns_size) {
+  if (inst != instructions.end()) {
+    const size_t insns_size = code_item_->insns_size_in_code_units_;
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "code did not end where expected ("
-                                      << dex_pc << " vs. " << insns_size << ")";
+                                      << inst.GetDexPC(instructions.begin()) << " vs. "
+                                      << insns_size << ")";
     return false;
   }
 
@@ -1105,15 +1094,13 @@
 
 template <bool kAllowRuntimeOnlyInstructions>
 bool MethodVerifier::VerifyInstructions() {
-  const Instruction* inst = Instruction::At(code_item_->insns_);
-
   /* Flag the start of the method as a branch target, and a GC point due to stack overflow errors */
   GetInstructionFlags(0).SetBranchTarget();
   GetInstructionFlags(0).SetCompileTimeInfoPoint();
-
-  uint32_t insns_size = code_item_->insns_size_in_code_units_;
-  for (uint32_t dex_pc = 0; dex_pc < insns_size;) {
-    if (!VerifyInstruction<kAllowRuntimeOnlyInstructions>(inst, dex_pc)) {
+  IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
+  for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
+    const uint32_t dex_pc = inst.GetDexPC(instructions.begin());
+    if (!VerifyInstruction<kAllowRuntimeOnlyInstructions>(&*inst, dex_pc)) {
       DCHECK_NE(failures_.size(), 0U);
       return false;
     }
@@ -1134,8 +1121,6 @@
     } else if (inst->IsReturn()) {
       GetInstructionFlags(dex_pc).SetCompileTimeInfoPointAndReturn();
     }
-    dex_pc += inst->SizeInCodeUnits();
-    inst = inst->Next();
   }
   return true;
 }
@@ -1671,9 +1656,10 @@
   }
   vios->Stream() << "Dumping instructions and register lines:\n";
   ScopedIndentation indent1(vios);
-  const Instruction* inst = Instruction::At(code_item_->insns_);
-  for (size_t dex_pc = 0; dex_pc < code_item_->insns_size_in_code_units_;
-      dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) {
+
+  IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
+  for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
+    const size_t dex_pc = inst.GetDexPC(instructions.begin());
     RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
     if (reg_line != nullptr) {
       vios->Stream() << reg_line->Dump(this) << "\n";
@@ -1938,9 +1924,10 @@
      * we are almost certainly going to have some dead code.
      */
     int dead_start = -1;
-    uint32_t insn_idx = 0;
-    for (; insn_idx < insns_size;
-         insn_idx += Instruction::At(code_item_->insns_ + insn_idx)->SizeInCodeUnits()) {
+
+    IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
+    for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
+      const uint32_t insn_idx = inst.GetDexPC(instructions.begin());
       /*
        * Switch-statement data doesn't get "visited" by scanner. It
        * may or may not be preceded by a padding NOP (for alignment).
@@ -1956,8 +1943,9 @@
       }
 
       if (!GetInstructionFlags(insn_idx).IsVisited()) {
-        if (dead_start < 0)
+        if (dead_start < 0) {
           dead_start = insn_idx;
+        }
       } else if (dead_start >= 0) {
         LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start)
                         << "-" << reinterpret_cast<void*>(insn_idx - 1);
@@ -1965,8 +1953,9 @@
       }
     }
     if (dead_start >= 0) {
-      LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start)
-                      << "-" << reinterpret_cast<void*>(insn_idx - 1);
+      LogVerifyInfo()
+          << "dead code " << reinterpret_cast<void*>(dead_start)
+          << "-" << reinterpret_cast<void*>(instructions.end().GetDexPC(instructions.begin()));
     }
     // To dump the state of the verify after a method, do something like:
     // if (dex_file_->PrettyMethod(dex_method_idx_) ==
@@ -2340,17 +2329,17 @@
         while (0 != prev_idx && !GetInstructionFlags(prev_idx).IsOpcode()) {
           prev_idx--;
         }
-        const Instruction* prev_inst = Instruction::At(code_item_->insns_ + prev_idx);
-        switch (prev_inst->Opcode()) {
+        const Instruction& prev_inst = code_item_->InstructionAt(prev_idx);
+        switch (prev_inst.Opcode()) {
           case Instruction::MOVE_OBJECT:
           case Instruction::MOVE_OBJECT_16:
           case Instruction::MOVE_OBJECT_FROM16:
-            if (prev_inst->VRegB() == inst->VRegA_11x()) {
+            if (prev_inst.VRegB() == inst->VRegA_11x()) {
               // Redo the copy. This won't change the register types, but update the lock status
               // for the aliased register.
               work_line_->CopyRegister1(this,
-                                        prev_inst->VRegA(),
-                                        prev_inst->VRegB(),
+                                        prev_inst.VRegA(),
+                                        prev_inst.VRegB(),
                                         kTypeCategoryRef);
             }
             break;
@@ -2648,7 +2637,7 @@
         break;
       }
 
-      const Instruction* instance_of_inst = Instruction::At(code_item_->insns_ + instance_of_idx);
+      const Instruction* instance_of_inst = &code_item_->InstructionAt(instance_of_idx);
 
       /* Check for peep-hole pattern of:
        *    ...;
@@ -2710,7 +2699,7 @@
                             work_insn_idx_)) {
               break;
             }
-            const Instruction* move_inst = Instruction::At(code_item_->insns_ + move_idx);
+            const Instruction* move_inst = &code_item_->InstructionAt(move_idx);
             switch (move_inst->Opcode()) {
               case Instruction::MOVE_OBJECT:
                 if (move_inst->VRegA_12x() == instance_of_inst->VRegB_22c()) {
@@ -3648,7 +3637,7 @@
    *        and this change should not be used in those cases.
    */
   if ((opcode_flags & Instruction::kContinue) != 0) {
-    DCHECK_EQ(Instruction::At(code_item_->insns_ + work_insn_idx_), inst);
+    DCHECK_EQ(&code_item_->InstructionAt(work_insn_idx_), inst);
     uint32_t next_insn_idx = work_insn_idx_ + inst->SizeInCodeUnits();
     if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";
diff --git a/sigchainlib/Android.bp b/sigchainlib/Android.bp
index 0c64b7d..7aab726 100644
--- a/sigchainlib/Android.bp
+++ b/sigchainlib/Android.bp
@@ -25,9 +25,6 @@
         srcs: ["sigchain.cc"],
     },
     target: {
-        host: {
-            host_ldlibs: ["-ldl"],
-        },
         android: {
             shared_libs: ["liblog"],
         },
@@ -49,9 +46,6 @@
     defaults: ["art_defaults"],
     srcs: ["sigchain_dummy.cc"],
     target: {
-        host: {
-            host_ldlibs: ["-ldl"],
-        },
         android: {
             shared_libs: ["liblog"],
         },
diff --git a/simulator/Android.bp b/simulator/Android.bp
index a399289..74b5a90 100644
--- a/simulator/Android.bp
+++ b/simulator/Android.bp
@@ -73,7 +73,7 @@
     ],
 
     header_libs: ["libart_simulator_headers"],
-    export_include_dirs: ["."],  // TODO: Consider a proper separation.
+    export_include_dirs: ["."], // TODO: Consider a proper separation.
 }
 
 art_cc_library {
diff --git a/test/566-polymorphic-inlining/run b/test/566-polymorphic-inlining/run
new file mode 100644
index 0000000..2919f46
--- /dev/null
+++ b/test/566-polymorphic-inlining/run
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright 2017 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.
+
+# -Xjitinitialsize:32M to prevent profiling info creation failure.
+exec ${RUN} \
+  --runtime-option -Xjitinitialsize:32M \
+  "${@}"
diff --git a/test/660-checker-simd-sad-char/src/Main.java b/test/660-checker-simd-sad-char/src/Main.java
index bb0c58f..2535d49 100644
--- a/test/660-checker-simd-sad-char/src/Main.java
+++ b/test/660-checker-simd-sad-char/src/Main.java
@@ -23,7 +23,7 @@
 
   // TODO: consider unsigned SAD too, b/64091002
 
-  private static char sadShort2Short(char[] s1, char[] s2) {
+  private static char sadChar2Char(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     char sad = 0;
     for (int i = 0; i < min_length; i++) {
@@ -32,7 +32,7 @@
     return sad;
   }
 
-  private static char sadShort2ShortAlt(char[] s1, char[] s2) {
+  private static char sadChar2CharAlt(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     char sad = 0;
     for (int i = 0; i < min_length; i++) {
@@ -43,7 +43,7 @@
     return sad;
   }
 
-  private static char sadShort2ShortAlt2(char[] s1, char[] s2) {
+  private static char sadChar2CharAlt2(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     char sad = 0;
     for (int i = 0; i < min_length; i++) {
@@ -56,7 +56,7 @@
     return sad;
   }
 
-  /// CHECK-START: int Main.sadShort2Int(char[], char[]) loop_optimization (before)
+  /// CHECK-START: int Main.sadChar2Int(char[], char[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
@@ -68,9 +68,9 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
-  /// CHECK-START-ARM64: int Main.sadShort2Int(char[], char[]) loop_optimization (after)
+  /// CHECK-START-ARM64: int Main.sadChar2Int(char[], char[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
-  private static int sadShort2Int(char[] s1, char[] s2) {
+  private static int sadChar2Int(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     int sad = 0;
     for (int i = 0; i < min_length; i++) {
@@ -79,7 +79,7 @@
     return sad;
   }
 
-  /// CHECK-START: int Main.sadShort2IntAlt(char[], char[]) loop_optimization (before)
+  /// CHECK-START: int Main.sadChar2IntAlt(char[], char[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
@@ -91,9 +91,9 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
-  /// CHECK-START-ARM64: int Main.sadShort2IntAlt(char[], char[]) loop_optimization (after)
+  /// CHECK-START-ARM64: int Main.sadChar2IntAlt(char[], char[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
-  private static int sadShort2IntAlt(char[] s1, char[] s2) {
+  private static int sadChar2IntAlt(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     int sad = 0;
     for (int i = 0; i < min_length; i++) {
@@ -104,7 +104,7 @@
     return sad;
   }
 
-  /// CHECK-START: int Main.sadShort2IntAlt2(char[], char[]) loop_optimization (before)
+  /// CHECK-START: int Main.sadChar2IntAlt2(char[], char[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
@@ -116,9 +116,9 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
-  /// CHECK-START-ARM64: int Main.sadShort2IntAlt2(char[], char[]) loop_optimization (after)
+  /// CHECK-START-ARM64: int Main.sadChar2IntAlt2(char[], char[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
-  private static int sadShort2IntAlt2(char[] s1, char[] s2) {
+  private static int sadChar2IntAlt2(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     int sad = 0;
     for (int i = 0; i < min_length; i++) {
@@ -131,7 +131,7 @@
     return sad;
   }
 
-  /// CHECK-START: long Main.sadShort2Long(char[], char[]) loop_optimization (before)
+  /// CHECK-START: long Main.sadChar2Long(char[], char[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
@@ -146,9 +146,9 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
-  /// CHECK-START-ARM64: long Main.sadShort2Long(char[], char[]) loop_optimization (after)
+  /// CHECK-START-ARM64: long Main.sadChar2Long(char[], char[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
-  private static long sadShort2Long(char[] s1, char[] s2) {
+  private static long sadChar2Long(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     long sad = 0;
     for (int i = 0; i < min_length; i++) {
@@ -159,7 +159,7 @@
     return sad;
   }
 
-  /// CHECK-START: long Main.sadShort2LongAt1(char[], char[]) loop_optimization (before)
+  /// CHECK-START: long Main.sadChar2LongAt1(char[], char[]) loop_optimization (before)
   /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
   /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
   /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
@@ -174,9 +174,9 @@
   /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
   //
-  /// CHECK-START-ARM64: long Main.sadShort2LongAt1(char[], char[]) loop_optimization (after)
+  /// CHECK-START-ARM64: long Main.sadChar2LongAt1(char[], char[]) loop_optimization (after)
   /// CHECK-NOT: VecSADAccumulate
-  private static long sadShort2LongAt1(char[] s1, char[] s2) {
+  private static long sadChar2LongAt1(char[] s1, char[] s2) {
     int min_length = Math.min(s1.length, s2.length);
     long sad = 1;  // starts at 1
     for (int i = 0; i < min_length; i++) {
@@ -191,22 +191,22 @@
     // Cross-test the two most extreme values individually.
     char[] s1 = { 0, 0x8000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
     char[] s2 = { 0, 0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-    expectEquals(1, sadShort2Short(s1, s2));
-    expectEquals(1, sadShort2Short(s2, s1));
-    expectEquals(1, sadShort2ShortAlt(s1, s2));
-    expectEquals(1, sadShort2ShortAlt(s2, s1));
-    expectEquals(1, sadShort2ShortAlt2(s1, s2));
-    expectEquals(1, sadShort2ShortAlt2(s2, s1));
-    expectEquals(1, sadShort2Int(s1, s2));
-    expectEquals(1, sadShort2Int(s2, s1));
-    expectEquals(1, sadShort2IntAlt(s1, s2));
-    expectEquals(1, sadShort2IntAlt(s2, s1));
-    expectEquals(1, sadShort2IntAlt2(s1, s2));
-    expectEquals(1, sadShort2IntAlt2(s2, s1));
-    expectEquals(1L, sadShort2Long(s1, s2));
-    expectEquals(1L, sadShort2Long(s2, s1));
-    expectEquals(2L, sadShort2LongAt1(s1, s2));
-    expectEquals(2L, sadShort2LongAt1(s2, s1));
+    expectEquals(1, sadChar2Char(s1, s2));
+    expectEquals(1, sadChar2Char(s2, s1));
+    expectEquals(1, sadChar2CharAlt(s1, s2));
+    expectEquals(1, sadChar2CharAlt(s2, s1));
+    expectEquals(1, sadChar2CharAlt2(s1, s2));
+    expectEquals(1, sadChar2CharAlt2(s2, s1));
+    expectEquals(1, sadChar2Int(s1, s2));
+    expectEquals(1, sadChar2Int(s2, s1));
+    expectEquals(1, sadChar2IntAlt(s1, s2));
+    expectEquals(1, sadChar2IntAlt(s2, s1));
+    expectEquals(1, sadChar2IntAlt2(s1, s2));
+    expectEquals(1, sadChar2IntAlt2(s2, s1));
+    expectEquals(1L, sadChar2Long(s1, s2));
+    expectEquals(1L, sadChar2Long(s2, s1));
+    expectEquals(2L, sadChar2LongAt1(s1, s2));
+    expectEquals(2L, sadChar2LongAt1(s2, s1));
 
     // Use cross-values to test all cases.
     char[] interesting = {
@@ -233,14 +233,14 @@
     }
     s1[k] = 10;
     s2[k] = 2;
-    expectEquals(56196, sadShort2Short(s1, s2));
-    expectEquals(56196, sadShort2ShortAlt(s1, s2));
-    expectEquals(56196, sadShort2ShortAlt2(s1, s2));
-    expectEquals(1497988, sadShort2Int(s1, s2));
-    expectEquals(1497988, sadShort2IntAlt(s1, s2));
-    expectEquals(1497988, sadShort2IntAlt2(s1, s2));
-    expectEquals(1497988L, sadShort2Long(s1, s2));
-    expectEquals(1497989L, sadShort2LongAt1(s1, s2));
+    expectEquals(56196, sadChar2Char(s1, s2));
+    expectEquals(56196, sadChar2CharAlt(s1, s2));
+    expectEquals(56196, sadChar2CharAlt2(s1, s2));
+    expectEquals(1497988, sadChar2Int(s1, s2));
+    expectEquals(1497988, sadChar2IntAlt(s1, s2));
+    expectEquals(1497988, sadChar2IntAlt2(s1, s2));
+    expectEquals(1497988L, sadChar2Long(s1, s2));
+    expectEquals(1497989L, sadChar2LongAt1(s1, s2));
 
     System.out.println("passed");
   }
diff --git a/test/660-checker-simd-sad-short2/expected.txt b/test/660-checker-simd-sad-short2/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/660-checker-simd-sad-short2/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/660-checker-simd-sad-short2/info.txt b/test/660-checker-simd-sad-short2/info.txt
new file mode 100644
index 0000000..b56c119
--- /dev/null
+++ b/test/660-checker-simd-sad-short2/info.txt
@@ -0,0 +1 @@
+Functional tests on SAD vectorization.
diff --git a/test/660-checker-simd-sad-short2/src/Main.java b/test/660-checker-simd-sad-short2/src/Main.java
new file mode 100644
index 0000000..7acc490
--- /dev/null
+++ b/test/660-checker-simd-sad-short2/src/Main.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/**
+ * Tests for SAD (sum of absolute differences).
+ *
+ * Special case, char array that is first casted to short, forcing sign extension.
+ */
+public class Main {
+
+  // TODO: lower precision still coming, b/64091002
+
+  private static short sadCastedChar2Short(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    short sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(((short) s1[i]) - ((short) s2[i]));
+    }
+    return sad;
+  }
+
+  private static short sadCastedChar2ShortAlt(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    short sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      short s = (short) s1[i];
+      short p = (short) s2[i];
+      sad += s >= p ? s - p : p - s;
+    }
+    return sad;
+  }
+
+  private static short sadCastedChar2ShortAlt2(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    short sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      short s = (short) s1[i];
+      short p = (short) s2[i];
+      int x = s - p;
+      if (x < 0) x = -x;
+      sad += x;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadCastedChar2Int(char[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:s\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadCastedChar2Int(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  private static int sadCastedChar2Int(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      sad += Math.abs(((short) s1[i]) - ((short) s2[i]));
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadCastedChar2IntAlt(char[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:s\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Cnv2>>,<<Cnv1>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadCastedChar2IntAlt(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  private static int sadCastedChar2IntAlt(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      short s = (short) s1[i];
+      short p = (short) s2[i];
+      sad += s >= p ? s - p : p - s;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: int Main.sadCastedChar2IntAlt2(char[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:s\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Cnv1>>,<<Cnv2>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: int Main.sadCastedChar2IntAlt2(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<Cons0>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  private static int sadCastedChar2IntAlt2(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    int sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      short s = (short) s1[i];
+      short p = (short) s2[i];
+      int x = s - p;
+      if (x < 0) x = -x;
+      sad += x;
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadCastedChar2Long(char[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:s\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv3:j\d+>>   TypeConversion [<<Cnv1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv4:j\d+>>   TypeConversion [<<Cnv2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv3>>,<<Cnv4>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadCastedChar2Long(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 0                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  private static long sadCastedChar2Long(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    long sad = 0;
+    for (int i = 0; i < min_length; i++) {
+      long x = (short) s1[i];
+      long y = (short) s2[i];
+      sad += Math.abs(x - y);
+    }
+    return sad;
+  }
+
+  /// CHECK-START: long Main.sadCastedChar2LongAt1(char[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons1:i\d+>>  IntConstant 1                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:j\d+>>   Phi [<<ConsL>>,{{j\d+}}]       loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get1:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:c\d+>>   ArrayGet [{{l\d+}},<<Phi1>>]   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv1:s\d+>>   TypeConversion [<<Get1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv2:s\d+>>   TypeConversion [<<Get2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv3:j\d+>>   TypeConversion [<<Cnv1>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv4:j\d+>>   TypeConversion [<<Cnv2>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Sub:j\d+>>    Sub [<<Cnv3>>,<<Cnv4>>]        loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsLong loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi2>>,<<Intrin>>]      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons1>>]       loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: long Main.sadCastedChar2LongAt1(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Cons0:i\d+>>  IntConstant 0                  loop:none
+  /// CHECK-DAG: <<Cons8:i\d+>>  IntConstant 8                  loop:none
+  /// CHECK-DAG: <<ConsL:j\d+>>  LongConstant 1                 loop:none
+  /// CHECK-DAG: <<Set:d\d+>>    VecSetScalars [<<ConsL>>]      loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Cons0>>,{{i\d+}}]       loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:d\d+>>   Phi [<<Set>>,{{d\d+}}]         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load1:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Load2:d\d+>>  VecLoad [{{l\d+}},<<Phi1>>]    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<SAD:d\d+>>    VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:                 Add [<<Phi1>>,<<Cons8>>]       loop:<<Loop>>      outer_loop:none
+  private static long sadCastedChar2LongAt1(char[] s1, char[] s2) {
+    int min_length = Math.min(s1.length, s2.length);
+    long sad = 1;  // starts at 1
+    for (int i = 0; i < min_length; i++) {
+      long x = (short) s1[i];
+      long y = (short) s2[i];
+      sad += Math.abs(x - y);
+    }
+    return sad;
+  }
+
+  public static void main(String[] args) {
+    // Cross-test the two most extreme values individually.
+    char[] s1 = { 0, 0x8000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    char[] s2 = { 0, 0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    expectEquals(-1, sadCastedChar2Short(s1, s2));
+    expectEquals(-1, sadCastedChar2Short(s2, s1));
+    expectEquals(-1, sadCastedChar2ShortAlt(s1, s2));
+    expectEquals(-1, sadCastedChar2ShortAlt(s2, s1));
+    expectEquals(-1, sadCastedChar2ShortAlt2(s1, s2));
+    expectEquals(-1, sadCastedChar2ShortAlt2(s2, s1));
+    expectEquals(65535, sadCastedChar2Int(s1, s2));
+    expectEquals(65535, sadCastedChar2Int(s2, s1));
+    expectEquals(65535, sadCastedChar2IntAlt(s1, s2));
+    expectEquals(65535, sadCastedChar2IntAlt(s2, s1));
+    expectEquals(65535, sadCastedChar2IntAlt2(s1, s2));
+    expectEquals(65535, sadCastedChar2IntAlt2(s2, s1));
+    expectEquals(65535L, sadCastedChar2Long(s1, s2));
+    expectEquals(65535L, sadCastedChar2Long(s2, s1));
+    expectEquals(65536L, sadCastedChar2LongAt1(s1, s2));
+    expectEquals(65536L, sadCastedChar2LongAt1(s2, s1));
+
+    // Use cross-values to test all cases.
+    char[] interesting = {
+      (char) 0x0000,
+      (char) 0x0001,
+      (char) 0x0002,
+      (char) 0x1234,
+      (char) 0x8000,
+      (char) 0x8001,
+      (char) 0x7fff,
+      (char) 0xffff
+    };
+    int n = interesting.length;
+    int m = n * n + 1;
+    s1 = new char[m];
+    s2 = new char[m];
+    int k = 0;
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < n; j++) {
+        s1[k] = interesting[i];
+        s2[k] = interesting[j];
+        k++;
+      }
+    }
+    s1[k] = 10;
+    s2[k] = 2;
+    expectEquals(-18932, sadCastedChar2Short(s1, s2));
+    expectEquals(-18932, sadCastedChar2ShortAlt(s1, s2));
+    expectEquals(-18932, sadCastedChar2ShortAlt2(s1, s2));
+    expectEquals(1291788, sadCastedChar2Int(s1, s2));
+    expectEquals(1291788, sadCastedChar2IntAlt(s1, s2));
+    expectEquals(1291788, sadCastedChar2IntAlt2(s1, s2));
+    expectEquals(1291788L, sadCastedChar2Long(s1, s2));
+    expectEquals(1291789L, sadCastedChar2LongAt1(s1, s2));
+
+    System.out.println("passed");
+  }
+
+  private static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
diff --git a/test/961-default-iface-resolution-gen/run b/test/961-default-iface-resolution-gen/run
new file mode 100755
index 0000000..fdcd2a8
--- /dev/null
+++ b/test/961-default-iface-resolution-gen/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 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 with a 2 minute default dex2oat timeout and a 2.5 minute hard dex2oat timeout.
+./default-run "$@" --dex2oat-timeout 120 --dex2oat-rt-timeout 180
diff --git a/test/Android.bp b/test/Android.bp
index 38d0651..d2eccb0 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -86,10 +86,6 @@
                 "libziparchive",
                 "libz-host",
             ],
-            host_ldlibs: [
-                "-ldl",
-                "-lpthread",
-            ],
             cflags: [
                 // gtest issue
                 "-Wno-used-but-marked-unused",
@@ -107,7 +103,6 @@
             ],
             shared_libs: [
                 "liblog",
-                "libdl",
                 "libz",
             ],
             cflags: [
@@ -169,26 +164,15 @@
     whole_static_libs: [
         "libart-compiler-gtest",
         "libart-runtime-gtest",
-        "libgtest"
+        "libgtest",
     ],
     shared_libs: [
         "libartd",
         "libartd-compiler",
         "libbase",
-        "libbacktrace"
+        "libbacktrace",
     ],
     target: {
-        android: {
-            shared_libs: [
-                "libdl",
-            ],
-        },
-        host: {
-            host_ldlibs: [
-                "-ldl",
-                "-lpthread",
-            ],
-        },
         darwin: {
             enabled: false,
         },
@@ -206,17 +190,6 @@
         "libbase",
         "libnativehelper",
     ],
-    target: {
-        android: {
-            shared_libs: ["libdl"],
-        },
-        host: {
-            host_ldlibs: [
-                "-ldl",
-                "-lpthread",
-            ],
-        },
-    },
 }
 
 art_cc_test_library {
@@ -237,7 +210,7 @@
 }
 
 art_cc_defaults {
-   name: "libtiagent-base-defaults",
+    name: "libtiagent-base-defaults",
     defaults: ["libartagent-defaults"],
     srcs: [
         // These are the ART-independent parts.
@@ -302,7 +275,7 @@
         "1926-missed-frame-pop/frame_pop_missed.cc",
         "1927-exception-event/exception_event.cc",
         "1930-monitor-info/monitor.cc",
-        "1932-monitor-events-misc/monitor_misc.cc"
+        "1932-monitor-events-misc/monitor_misc.cc",
     ],
     shared_libs: [
         "libbase",
@@ -359,7 +332,7 @@
 
 art_cc_test_library {
     name: "libtistress",
-    defaults: [ "libtistress-defaults"],
+    defaults: ["libtistress-defaults"],
     shared_libs: ["libart"],
 }
 
@@ -422,24 +395,13 @@
         "656-annotation-lookup-generic-jni/test.cc",
         "661-oat-writer-layout/oat_writer_layout.cc",
         "664-aget-verifier/aget-verifier.cc",
-        "708-jit-cache-churn/jit.cc"
+        "708-jit-cache-churn/jit.cc",
     ],
     shared_libs: [
         "libbacktrace",
         "libbase",
         "libnativehelper",
     ],
-    target: {
-        android: {
-            shared_libs: ["libdl"],
-        },
-        host: {
-            host_ldlibs: [
-                "-ldl",
-                "-lpthread",
-            ],
-        },
-    },
 }
 
 art_cc_test_library {
@@ -467,18 +429,4 @@
     ],
     header_libs: ["libnativebridge-dummy-headers"],
     srcs: ["115-native-bridge/nativebridge.cc"],
-    target: {
-        android: {
-            shared_libs: ["libdl"],
-        },
-        host: {
-            host_ldlibs: [
-                "-ldl",
-                "-lpthread",
-            ],
-        },
-        linux: {
-            host_ldlibs: ["-lrt"],
-        },
-    },
 }
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index c16c487..d37e6bc 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -70,6 +70,10 @@
 VDEX_FILTER=""
 PROFILE="n"
 RANDOM_PROFILE="n"
+# The normal dex2oat timeout.
+DEX2OAT_TIMEOUT="60"
+# The *hard* timeout where we really start trying to kill the dex2oat.
+DEX2OAT_RT_TIMEOUT="90"
 
 # if "y", set -Xstacktracedir and inform the test of its location. When
 # this is set, stack trace dumps (from signal 3) will be written to a file
@@ -87,6 +91,22 @@
     if [ "x$1" = "x--quiet" ]; then
         QUIET="y"
         shift
+    elif [ "x$1" = "x--dex2oat-rt-timeout" ]; then
+        shift
+        if [ "x$1" = "x" ]; then
+            echo "$0 missing argument to --dex2oat-rt-timeout" 1>&2
+            exit 1
+        fi
+        DEX2OAT_RT_TIMEOUT="$1"
+        shift
+    elif [ "x$1" = "x--dex2oat-timeout" ]; then
+        shift
+        if [ "x$1" = "x" ]; then
+            echo "$0 missing argument to --dex2oat-timeout" 1>&2
+            exit 1
+        fi
+        DEX2OAT_TIMEOUT="$1"
+        shift
     elif [ "x$1" = "x--jvmti" ]; then
         IS_JVMTI_TEST="y"
         shift
@@ -646,10 +666,11 @@
   # Note: as we don't know how decent targets are (e.g., emulator), only do this on the host for
   #       now. We should try to improve this.
   #       The current value is rather arbitrary. run-tests should compile quickly.
+  # Watchdog timeout is in milliseconds so add 3 '0's to the dex2oat timeout.
   if [ "$HOST" != "n" ]; then
     # Use SIGRTMIN+2 to try to dump threads.
     # Use -k 1m to SIGKILL it a minute later if it hasn't ended.
-    dex2oat_cmdline="timeout -k 1m -s SIGRTMIN+2 90s ${dex2oat_cmdline} --watchdog-timeout=60000"
+    dex2oat_cmdline="timeout -k ${DEX2OAT_TIMEOUT}s -s SIGRTMIN+2 ${DEX2OAT_RT_TIMEOUT}s ${dex2oat_cmdline} --watchdog-timeout=${DEX2OAT_TIMEOUT}000"
   fi
   if [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then
     vdex_cmdline="${dex2oat_cmdline} ${VDEX_FILTER} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex --output-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
diff --git a/test/testrunner/env.py b/test/testrunner/env.py
index d45d009..cc19afc 100644
--- a/test/testrunner/env.py
+++ b/test/testrunner/env.py
@@ -115,82 +115,9 @@
 # Keep going after encountering a test failure?
 ART_TEST_KEEP_GOING = _getEnvBoolean('ART_TEST_KEEP_GOING', True)
 
-# Do you want all tests, even those that are time consuming?
-ART_TEST_FULL = _getEnvBoolean('ART_TEST_FULL', False)
-
-# Do you want interpreter tests run?
-ART_TEST_INTERPRETER = _getEnvBoolean('ART_TEST_INTERPRETER', ART_TEST_FULL)
-ART_TEST_INTERPRETER_ACCESS_CHECKS = _getEnvBoolean('ART_TEST_INTERPRETER_ACCESS_CHECKS',
-                                                   ART_TEST_FULL)
-
-# Do you want JIT tests run?
-ART_TEST_JIT = _getEnvBoolean('ART_TEST_JIT', ART_TEST_FULL)
-
-# Do you want optimizing compiler tests run?
-ART_TEST_OPTIMIZING = _getEnvBoolean('ART_TEST_OPTIMIZING', ART_TEST_FULL)
-
-# Do you want to test the optimizing compiler with graph coloring register allocation?
-ART_TEST_OPTIMIZING_GRAPH_COLOR = _getEnvBoolean('ART_TEST_OPTIMIZING_GRAPH_COLOR', ART_TEST_FULL)
-
-# Do you want to do run-tests with profiles?
-ART_TEST_SPEED_PROFILE = _getEnvBoolean('ART_TEST_SPEED_PROFILE', ART_TEST_FULL)
-
-# Do we want to test PIC-compiled tests ("apps")?
-ART_TEST_PIC_TEST = _getEnvBoolean('ART_TEST_PIC_TEST', ART_TEST_FULL)
-# Do you want tracing tests run?
-ART_TEST_TRACE = _getEnvBoolean('ART_TEST_TRACE', ART_TEST_FULL)
-
-# Do you want tracing tests (streaming mode) run?
-ART_TEST_TRACE_STREAM = _getEnvBoolean('ART_TEST_TRACE_STREAM', ART_TEST_FULL)
-
-# Do you want tests with GC verification enabled run?
-ART_TEST_GC_VERIFY = _getEnvBoolean('ART_TEST_GC_VERIFY', ART_TEST_FULL)
-
-# Do you want tests with the GC stress mode enabled run?
-ART_TEST_GC_STRESS = _getEnvBoolean('ART_TEST_GC_STRESS', ART_TEST_FULL)
-
-# Do you want tests with the JNI forcecopy mode enabled run?
-ART_TEST_JNI_FORCECOPY = _getEnvBoolean('ART_TEST_JNI_FORCECOPY', ART_TEST_FULL)
-
-# Do you want run-tests with relocation disabled run?
-ART_TEST_RUN_TEST_RELOCATE = _getEnvBoolean('ART_TEST_RUN_TEST_RELOCATE', ART_TEST_FULL)
-
-# Do you want run-tests with prebuilding?
-ART_TEST_RUN_TEST_PREBUILD = _getEnvBoolean('ART_TEST_RUN_TEST_PREBUILD', ART_TEST_FULL)
-
-# Do you want run-tests with no prebuilding enabled run?
-ART_TEST_RUN_TEST_NO_PREBUILD = _getEnvBoolean('ART_TEST_RUN_TEST_NO_PREBUILD', ART_TEST_FULL)
-
-# Do you want run-tests with a pregenerated core.art?
-ART_TEST_RUN_TEST_IMAGE = _getEnvBoolean('ART_TEST_RUN_TEST_IMAGE', ART_TEST_FULL)
-
-# Do you want run-tests without a pregenerated core.art?
-ART_TEST_RUN_TEST_NO_IMAGE = _getEnvBoolean('ART_TEST_RUN_TEST_NO_IMAGE', ART_TEST_FULL)
-
-# Do you want run-tests with relocation enabled but patchoat failing?
-ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT = _getEnvBoolean('ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT',
-                                                       ART_TEST_FULL)
-
-# Do you want run-tests without a dex2oat?
-ART_TEST_RUN_TEST_NO_DEX2OAT = _getEnvBoolean('ART_TEST_RUN_TEST_NO_DEX2OAT', ART_TEST_FULL)
-
-# Do you want run-tests with libartd.so?
-ART_TEST_RUN_TEST_DEBUG = _getEnvBoolean('ART_TEST_RUN_TEST_DEBUG', ART_TEST_FULL)
-
-# Do you want run-tests with libart.so?
-ART_TEST_RUN_TEST_NDEBUG = _getEnvBoolean('ART_TEST_RUN_TEST_NDEBUG', ART_TEST_FULL)
-
 # Do you want failed tests to have their artifacts cleaned up?
 ART_TEST_RUN_TEST_ALWAYS_CLEAN = _getEnvBoolean('ART_TEST_RUN_TEST_ALWAYS_CLEAN', True)
 
-# Do you want run-tests with the --debuggable flag
-ART_TEST_RUN_TEST_DEBUGGABLE = _getEnvBoolean('ART_TEST_RUN_TEST_DEBUGGABLE', ART_TEST_FULL)
-
-# Do you want to test multi-part boot-image functionality?
-ART_TEST_RUN_TEST_MULTI_IMAGE = _getEnvBoolean('ART_TEST_RUN_TEST_MULTI_IMAGE', ART_TEST_FULL)
-
-ART_TEST_DEBUG_GC = _getEnvBoolean('ART_TEST_DEBUG_GC', False)
-
 ART_TEST_BISECTION = _getEnvBoolean('ART_TEST_BISECTION', False)
 
 DEX2OAT_HOST_INSTRUCTION_SET_FEATURES = _env.get('DEX2OAT_HOST_INSTRUCTION_SET_FEATURES')
@@ -217,8 +144,6 @@
 # Note: ART_2ND_PHONY_TEST_HOST_SUFFIX is 2ND_ART_PHONY_HOST_TARGET_SUFFIX in .mk files
 # Python does not let us have variable names starting with a digit, so it has differ.
 
-ART_TEST_RUN_TEST_JVMTI_STRESS = _getEnvBoolean('ART_TEST_RUN_TEST_JVMTI_STRESS', ART_TEST_FULL)
-
 if TARGET_2ND_ARCH:
   if "64" in TARGET_ARCH:
     ART_PHONY_TEST_TARGET_SUFFIX = "64"
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index e07198b..2a772ff 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -45,6 +45,7 @@
 
 """
 import argparse
+import collections
 import fnmatch
 import itertools
 import json
@@ -60,21 +61,6 @@
 import env
 from target_config import target_config
 
-TARGET_TYPES = set()
-RUN_TYPES = set()
-PREBUILD_TYPES = set()
-COMPILER_TYPES = set()
-RELOCATE_TYPES = set()
-TRACE_TYPES = set()
-GC_TYPES = set()
-JNI_TYPES = set()
-IMAGE_TYPES = set()
-PICTEST_TYPES = set()
-DEBUGGABLE_TYPES = set()
-ADDRESS_SIZES = set()
-OPTIMIZING_COMPILER_TYPES = set()
-JVMTI_TYPES = set()
-ADDRESS_SIZES_TARGET = {'host': set(), 'target': set()}
 # timeout for individual tests.
 # TODO: make it adjustable per tests and for buildbots
 timeout = 3000 # 50 minutes
@@ -128,6 +114,12 @@
 gdb_arg = ''
 stop_testrunner = False
 dex2oat_jobs = -1   # -1 corresponds to default threads for dex2oat
+run_all_configs = False
+
+# Dict to store user requested test variants.
+# key: variant_type.
+# value: set of variants user wants to run of type <key>.
+_user_input_variants = collections.defaultdict(set)
 
 def gather_test_info():
   """The method gathers test information about the test to be run which includes
@@ -151,7 +143,7 @@
   VARIANT_TYPE_DICT['jvmti'] = {'no-jvmti', 'jvmti-stress', 'redefine-stress', 'trace-stress',
                                 'field-stress', 'step-stress'}
   VARIANT_TYPE_DICT['compiler'] = {'interp-ac', 'interpreter', 'jit', 'optimizing',
-                              'regalloc_gc', 'speed-profile'}
+                                   'regalloc_gc', 'speed-profile'}
 
   for v_type in VARIANT_TYPE_DICT:
     TOTAL_VARIANTS_SET = TOTAL_VARIANTS_SET.union(VARIANT_TYPE_DICT.get(v_type))
@@ -173,106 +165,75 @@
     # Bisection search writes to standard output.
     env.ART_TEST_QUIET = False
 
-  if not TARGET_TYPES:
-    TARGET_TYPES.add('host')
-    TARGET_TYPES.add('target')
+  global _user_input_variants
+  global run_all_configs
+  if run_all_configs:
+    target_types = _user_input_variants['target']
+    _user_input_variants = VARIANT_TYPE_DICT
+    _user_input_variants['target'] = target_types
 
-  if env.ART_TEST_RUN_TEST_NO_PREBUILD:
-    PREBUILD_TYPES.add('no-prebuild')
-  if env.ART_TEST_RUN_TEST_NO_DEX2OAT:
-    PREBUILD_TYPES.add('no-dex2oat')
-  if env.ART_TEST_RUN_TEST_PREBUILD or not PREBUILD_TYPES: # Default
-    PREBUILD_TYPES.add('prebuild')
+  if not _user_input_variants['target']:
+    _user_input_variants['target'].add('host')
+    _user_input_variants['target'].add('target')
 
-  if env.ART_TEST_INTERPRETER_ACCESS_CHECKS:
-    COMPILER_TYPES.add('interp-ac')
-  if env.ART_TEST_INTERPRETER:
-    COMPILER_TYPES.add('interpreter')
-  if env.ART_TEST_JIT:
-    COMPILER_TYPES.add('jit')
-  if env.ART_TEST_OPTIMIZING_GRAPH_COLOR:
-    COMPILER_TYPES.add('regalloc_gc')
-    OPTIMIZING_COMPILER_TYPES.add('regalloc_gc')
-  if env.ART_TEST_OPTIMIZING:
-    COMPILER_TYPES.add('optimizing')
-    OPTIMIZING_COMPILER_TYPES.add('optimizing')
-  if env.ART_TEST_SPEED_PROFILE:
-    COMPILER_TYPES.add('speed-profile')
+  if not _user_input_variants['prebuild']: # Default
+    _user_input_variants['prebuild'].add('prebuild')
 
   # By default only run without jvmti
-  if not JVMTI_TYPES:
-    JVMTI_TYPES.add('no-jvmti')
+  if not _user_input_variants['jvmti']:
+    _user_input_variants['jvmti'].add('no-jvmti')
 
   # By default we run all 'compiler' variants.
-  if not COMPILER_TYPES:
-    COMPILER_TYPES.add('optimizing')
-    COMPILER_TYPES.add('jit')
-    COMPILER_TYPES.add('interpreter')
-    COMPILER_TYPES.add('interp-ac')
-    COMPILER_TYPES.add('speed-profile')
-    OPTIMIZING_COMPILER_TYPES.add('optimizing')
+  if not _user_input_variants['compiler']:
+    _user_input_variants['compiler'].add('optimizing')
+    _user_input_variants['compiler'].add('jit')
+    _user_input_variants['compiler'].add('interpreter')
+    _user_input_variants['compiler'].add('interp-ac')
+    _user_input_variants['compiler'].add('speed-profile')
 
-  if env.ART_TEST_RUN_TEST_RELOCATE:
-    RELOCATE_TYPES.add('relocate')
-  if env.ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT:
-    RELOCATE_TYPES.add('relocate-npatchoat')
-  if not RELOCATE_TYPES: # Default
-    RELOCATE_TYPES.add('no-relocate')
+  if not _user_input_variants['relocate']: # Default
+    _user_input_variants['relocate'].add('no-relocate')
 
-  if env.ART_TEST_TRACE:
-    TRACE_TYPES.add('trace')
-  if env.ART_TEST_TRACE_STREAM:
-    TRACE_TYPES.add('stream')
-  if not TRACE_TYPES: # Default
-    TRACE_TYPES.add('ntrace')
+  if not _user_input_variants['trace']: # Default
+    _user_input_variants['trace'].add('ntrace')
 
-  if env.ART_TEST_GC_STRESS:
-    GC_TYPES.add('gcstress')
-  if env.ART_TEST_GC_VERIFY:
-    GC_TYPES.add('gcverify')
-  if not GC_TYPES: # Default
-    GC_TYPES.add('cms')
+  if not _user_input_variants['gc']: # Default
+    _user_input_variants['gc'].add('cms')
 
-  if env.ART_TEST_JNI_FORCECOPY:
-    JNI_TYPES.add('forcecopy')
-  if not JNI_TYPES: # Default
-    JNI_TYPES.add('checkjni')
+  if not _user_input_variants['jni']: # Default
+    _user_input_variants['jni'].add('checkjni')
 
-  if env.ART_TEST_RUN_TEST_NO_IMAGE:
-    IMAGE_TYPES.add('no-image')
-  if env.ART_TEST_RUN_TEST_MULTI_IMAGE:
-    IMAGE_TYPES.add('multipicimage')
-  if env.ART_TEST_RUN_TEST_IMAGE or not IMAGE_TYPES: # Default
-    IMAGE_TYPES.add('picimage')
+  if not _user_input_variants['image']: # Default
+    _user_input_variants['image'].add('picimage')
 
-  if env.ART_TEST_PIC_TEST:
-    PICTEST_TYPES.add('pictest')
-  if not PICTEST_TYPES: # Default
-    PICTEST_TYPES.add('npictest')
 
-  if env.ART_TEST_RUN_TEST_NDEBUG:
-    RUN_TYPES.add('ndebug')
-  if env.ART_TEST_RUN_TEST_DEBUG or not RUN_TYPES: # Default
-    RUN_TYPES.add('debug')
+  if not _user_input_variants['pictest']: # Default
+    _user_input_variants['pictest'].add('npictest')
 
-  if env.ART_TEST_RUN_TEST_DEBUGGABLE:
-    DEBUGGABLE_TYPES.add('debuggable')
-  if not DEBUGGABLE_TYPES: # Default
-    DEBUGGABLE_TYPES.add('ndebuggable')
+  if not _user_input_variants['debuggable']: # Default
+    _user_input_variants['debuggable'].add('ndebuggable')
 
-  if not ADDRESS_SIZES:
-    ADDRESS_SIZES_TARGET['target'].add(env.ART_PHONY_TEST_TARGET_SUFFIX)
-    ADDRESS_SIZES_TARGET['host'].add(env.ART_PHONY_TEST_HOST_SUFFIX)
+  if not _user_input_variants['run']: # Default
+    _user_input_variants['run'].add('debug')
+
+  _user_input_variants['address_sizes_target'] = collections.defaultdict(set)
+  if not _user_input_variants['address_sizes']:
+    _user_input_variants['address_sizes_target']['target'].add(
+        env.ART_PHONY_TEST_TARGET_SUFFIX)
+    _user_input_variants['address_sizes_target']['host'].add(
+        env.ART_PHONY_TEST_HOST_SUFFIX)
     if env.ART_TEST_RUN_TEST_2ND_ARCH:
-      ADDRESS_SIZES_TARGET['host'].add(env.ART_2ND_PHONY_TEST_HOST_SUFFIX)
-      ADDRESS_SIZES_TARGET['target'].add(env.ART_2ND_PHONY_TEST_TARGET_SUFFIX)
+      _user_input_variants['address_sizes_target']['host'].add(
+          env.ART_2ND_PHONY_TEST_HOST_SUFFIX)
+      _user_input_variants['address_sizes_target']['target'].add(
+          env.ART_2ND_PHONY_TEST_TARGET_SUFFIX)
   else:
-    ADDRESS_SIZES_TARGET['host'] = ADDRESS_SIZES_TARGET['host'].union(ADDRESS_SIZES)
-    ADDRESS_SIZES_TARGET['target'] = ADDRESS_SIZES_TARGET['target'].union(ADDRESS_SIZES)
+    _user_input_variants['address_sizes_target']['host'] = _user_input_variants['address_sizes']
+    _user_input_variants['address_sizes_target']['target'] = _user_input_variants['address_sizes']
 
   global n_thread
   if n_thread is -1:
-    if 'target' in TARGET_TYPES:
+    if 'target' in _user_input_variants['target']:
       n_thread = get_default_threads('target')
     else:
       n_thread = get_default_threads('host')
@@ -308,20 +269,12 @@
   options_all = ''
   global total_test_count
   total_test_count = len(tests)
-  total_test_count *= len(RUN_TYPES)
-  total_test_count *= len(PREBUILD_TYPES)
-  total_test_count *= len(RELOCATE_TYPES)
-  total_test_count *= len(TRACE_TYPES)
-  total_test_count *= len(GC_TYPES)
-  total_test_count *= len(JNI_TYPES)
-  total_test_count *= len(IMAGE_TYPES)
-  total_test_count *= len(PICTEST_TYPES)
-  total_test_count *= len(DEBUGGABLE_TYPES)
-  total_test_count *= len(COMPILER_TYPES)
-  total_test_count *= len(JVMTI_TYPES)
+  for variant_type in VARIANT_TYPE_DICT:
+    if not (variant_type == 'target' or 'address_sizes' in variant_type):
+      total_test_count *= len(_user_input_variants[variant_type])
   target_address_combinations = 0
-  for target in TARGET_TYPES:
-    for address_size in ADDRESS_SIZES_TARGET[target]:
+  for target in _user_input_variants['target']:
+    for address_size in _user_input_variants['address_sizes_target'][target]:
       target_address_combinations += 1
   total_test_count *= target_address_combinations
 
@@ -345,14 +298,16 @@
   if dex2oat_jobs != -1:
     options_all += ' --dex2oat-jobs ' + str(dex2oat_jobs)
 
-  config = itertools.product(tests, TARGET_TYPES, RUN_TYPES, PREBUILD_TYPES,
-                             COMPILER_TYPES, RELOCATE_TYPES, TRACE_TYPES,
-                             GC_TYPES, JNI_TYPES, IMAGE_TYPES, PICTEST_TYPES,
-                             DEBUGGABLE_TYPES, JVMTI_TYPES)
+  config = itertools.product(tests, _user_input_variants['target'], _user_input_variants['run'],
+                             _user_input_variants['prebuild'], _user_input_variants['compiler'],
+                             _user_input_variants['relocate'], _user_input_variants['trace'],
+                             _user_input_variants['gc'], _user_input_variants['jni'],
+                             _user_input_variants['image'], _user_input_variants['pictest'],
+                             _user_input_variants['debuggable'], _user_input_variants['jvmti'])
 
   for test, target, run, prebuild, compiler, relocate, trace, gc, \
       jni, image, pictest, debuggable, jvmti in config:
-    for address_size in ADDRESS_SIZES_TARGET[target]:
+    for address_size in _user_input_variants['address_sizes_target'][target]:
       if stop_testrunner:
         # When ART_TEST_KEEP_GOING is set to false, then as soon as a test
         # fails, stop_testrunner is set to True. When this happens, the method
@@ -577,11 +532,10 @@
       total_test_count)
 
     if result == 'FAIL' or result == 'TIMEOUT':
-      info += ('%s %s %s\n%s\n') % (
+      info += ('%s %s %s\n') % (
         progress_info,
         test_name,
-        COLOR_ERROR + result + COLOR_NORMAL,
-        failed_test_info)
+        COLOR_ERROR + result + COLOR_NORMAL)
     else:
       result_text = ''
       if result == 'PASS':
@@ -810,19 +764,19 @@
   regex += '(' + '|'.join(VARIANT_TYPE_DICT['address_sizes']) + ')$'
   match = re.match(regex, test_name)
   if match:
-    TARGET_TYPES.add(match.group(1))
-    RUN_TYPES.add(match.group(2))
-    PREBUILD_TYPES.add(match.group(3))
-    COMPILER_TYPES.add(match.group(4))
-    RELOCATE_TYPES.add(match.group(5))
-    TRACE_TYPES.add(match.group(6))
-    GC_TYPES.add(match.group(7))
-    JNI_TYPES.add(match.group(8))
-    IMAGE_TYPES.add(match.group(9))
-    PICTEST_TYPES.add(match.group(10))
-    DEBUGGABLE_TYPES.add(match.group(11))
-    JVMTI_TYPES.add(match.group(12))
-    ADDRESS_SIZES.add(match.group(14))
+    _user_input_variants['target'].add(match.group(1))
+    _user_input_variants['run'].add(match.group(2))
+    _user_input_variants['prebuild'].add(match.group(3))
+    _user_input_variants['compiler'].add(match.group(4))
+    _user_input_variants['relocate'].add(match.group(5))
+    _user_input_variants['trace'].add(match.group(6))
+    _user_input_variants['gc'].add(match.group(7))
+    _user_input_variants['jni'].add(match.group(8))
+    _user_input_variants['image'].add(match.group(9))
+    _user_input_variants['pictest'].add(match.group(10))
+    _user_input_variants['debuggable'].add(match.group(11))
+    _user_input_variants['jvmti'].add(match.group(12))
+    _user_input_variants['address_sizes'].add(match.group(14))
     return {match.group(13)}
   raise ValueError(test_name + " is not a valid test")
 
@@ -871,6 +825,7 @@
   global gdb_arg
   global timeout
   global dex2oat_jobs
+  global run_all_configs
 
   parser = argparse.ArgumentParser(description="Runs all or a subset of the ART test suite.")
   parser.add_argument('-t', '--test', dest='test', help='name of the test')
@@ -878,10 +833,7 @@
   parser.add_argument('--timeout', default=timeout, type=int, dest='timeout')
   for variant in TOTAL_VARIANTS_SET:
     flag = '--' + variant
-    flag_dest = variant.replace('-', '_')
-    if variant == '32' or variant == '64':
-      flag_dest = 'n' + flag_dest
-    parser.add_argument(flag, action='store_true', dest=flag_dest)
+    parser.add_argument(flag, action='store_true', dest=variant)
   parser.add_argument('--verbose', '-v', action='store_true', dest='verbose')
   parser.add_argument('--dry-run', action='store_true', dest='dry_run')
   parser.add_argument("--skip", action="append", dest="skips", default=[],
@@ -900,6 +852,8 @@
   parser.add_argument('--gdb-arg', dest='gdb_arg')
   parser.add_argument('--dex2oat-jobs', type=int, dest='dex2oat_jobs',
                       help='Number of dex2oat jobs')
+  parser.add_argument('-a', '--all', action='store_true', dest='run_all',
+                      help="Run all the possible configurations for the input test set")
 
   options = vars(parser.parse_args())
   if options['build_target']:
@@ -910,82 +864,12 @@
   env.EXTRA_DISABLED_TESTS.update(set(options['skips']))
   if options['test']:
     test = parse_test_name(options['test'])
-  if options['pictest']:
-    PICTEST_TYPES.add('pictest')
-  if options['ndebug']:
-    RUN_TYPES.add('ndebug')
-  if options['interp_ac']:
-    COMPILER_TYPES.add('interp-ac')
-  if options['picimage']:
-    IMAGE_TYPES.add('picimage')
-  if options['n64']:
-    ADDRESS_SIZES.add('64')
-  if options['interpreter']:
-    COMPILER_TYPES.add('interpreter')
-  if options['jni']:
-    JNI_TYPES.add('jni')
-  if options['relocate_npatchoat']:
-    RELOCATE_TYPES.add('relocate-npatchoat')
-  if options['no_prebuild']:
-    PREBUILD_TYPES.add('no-prebuild')
-  if options['npictest']:
-    PICTEST_TYPES.add('npictest')
-  if options['no_dex2oat']:
-    PREBUILD_TYPES.add('no-dex2oat')
-  if options['jit']:
-    COMPILER_TYPES.add('jit')
-  if options['relocate']:
-    RELOCATE_TYPES.add('relocate')
-  if options['ndebuggable']:
-    DEBUGGABLE_TYPES.add('ndebuggable')
-  if options['no_image']:
-    IMAGE_TYPES.add('no-image')
-  if options['optimizing']:
-    COMPILER_TYPES.add('optimizing')
-  if options['speed_profile']:
-    COMPILER_TYPES.add('speed-profile')
-  if options['trace']:
-    TRACE_TYPES.add('trace')
-  if options['gcstress']:
-    GC_TYPES.add('gcstress')
-  if options['no_relocate']:
-    RELOCATE_TYPES.add('no-relocate')
-  if options['target']:
-    TARGET_TYPES.add('target')
-  if options['forcecopy']:
-    JNI_TYPES.add('forcecopy')
-  if options['n32']:
-    ADDRESS_SIZES.add('32')
-  if options['host']:
-    TARGET_TYPES.add('host')
-  if options['gcverify']:
-    GC_TYPES.add('gcverify')
-  if options['debuggable']:
-    DEBUGGABLE_TYPES.add('debuggable')
-  if options['prebuild']:
-    PREBUILD_TYPES.add('prebuild')
-  if options['debug']:
-    RUN_TYPES.add('debug')
-  if options['checkjni']:
-    JNI_TYPES.add('checkjni')
-  if options['ntrace']:
-    TRACE_TYPES.add('ntrace')
-  if options['cms']:
-    GC_TYPES.add('cms')
-  if options['multipicimage']:
-    IMAGE_TYPES.add('multipicimage')
-  if options['jvmti_stress']:
-    JVMTI_TYPES.add('jvmti-stress')
-  if options['redefine_stress']:
-    JVMTI_TYPES.add('redefine-stress')
-  if options['field_stress']:
-    JVMTI_TYPES.add('field-stress')
-  if options['step_stress']:
-    JVMTI_TYPES.add('step-stress')
-  if options['trace_stress']:
-    JVMTI_TYPES.add('trace-stress')
-  if options['no_jvmti']:
-    JVMTI_TYPES.add('no-jvmti')
+
+  for variant_type in VARIANT_TYPE_DICT:
+    for variant in VARIANT_TYPE_DICT[variant_type]:
+      if options.get(variant):
+        _user_input_variants[variant_type].add(variant)
+
   if options['verbose']:
     verbose = True
   if options['n_thread']:
@@ -1002,6 +886,8 @@
   timeout = options['timeout']
   if options['dex2oat_jobs']:
     dex2oat_jobs = options['dex2oat_jobs']
+  if options['run_all']:
+    run_all_configs = True
 
   return test
 
@@ -1011,9 +897,9 @@
   setup_test_env()
   if build:
     build_targets = ''
-    if 'host' in TARGET_TYPES:
+    if 'host' in _user_input_variants['target']:
       build_targets += 'test-art-host-run-test-dependencies'
-    if 'target' in TARGET_TYPES:
+    if 'target' in _user_input_variants['target']:
       build_targets += 'test-art-target-run-test-dependencies'
     build_command = 'make'
     build_command += ' -j'
diff --git a/tools/cpp-define-generator/Android.bp b/tools/cpp-define-generator/Android.bp
index 59c5211..57c9c09 100644
--- a/tools/cpp-define-generator/Android.bp
+++ b/tools/cpp-define-generator/Android.bp
@@ -20,7 +20,7 @@
 //
 // In the future we may wish to parameterize this on (32,64)x(read_barrier,no_read_barrier).
 
-cc_binary {  // Do not use art_cc_binary because HOST_PREFER_32_BIT is incompatible with genrule.
+cc_binary { // Do not use art_cc_binary because HOST_PREFER_32_BIT is incompatible with genrule.
     name: "cpp-define-generator-data",
     host_supported: true,
     device_supported: false,
@@ -39,9 +39,9 @@
 // For the exact filename that this generates to run make command on just
 // this rule later.
 genrule {
-  name: "cpp-define-generator-asm-support",
-  out: ["asm_support_gen.h"],
-  tools: ["cpp-define-generator-data"],
-  tool_files: ["verify-asm-support"],
-  cmd: "$(location verify-asm-support) --quiet \"$(location cpp-define-generator-data)\" \"$(out)\""
+    name: "cpp-define-generator-asm-support",
+    out: ["asm_support_gen.h"],
+    tools: ["cpp-define-generator-data"],
+    tool_files: ["verify-asm-support"],
+    cmd: "$(location verify-asm-support) --quiet \"$(location cpp-define-generator-data)\" \"$(out)\"",
 }
diff --git a/tools/titrace/Android.bp b/tools/titrace/Android.bp
index b95ec9d..097622e 100644
--- a/tools/titrace/Android.bp
+++ b/tools/titrace/Android.bp
@@ -19,7 +19,10 @@
 cc_defaults {
     name: "titrace-defaults",
     host_supported: true,
-    srcs: ["titrace.cc", "instruction_decoder.cc"],
+    srcs: [
+        "titrace.cc",
+        "instruction_decoder.cc",
+    ],
     defaults: ["art_defaults"],
 
     // Note that this tool needs to be built for both 32-bit and 64-bit since it requires
@@ -27,7 +30,7 @@
     compile_multilib: "both",
 
     shared_libs: [
-        "libbase"
+        "libbase",
     ],
     target: {
         android: {
@@ -37,7 +40,7 @@
     },
     header_libs: [
         "libopenjdkjvmti_headers",
-        "libart_runtime_headers"    // for dex_instruction_list.h only
+        "libart_runtime_headers", // for dex_instruction_list.h only
         // "libbase_headers",
     ],
     multilib: {
diff --git a/tools/wrapagentproperties/Android.bp b/tools/wrapagentproperties/Android.bp
index c39b81a..8dec847 100644
--- a/tools/wrapagentproperties/Android.bp
+++ b/tools/wrapagentproperties/Android.bp
@@ -27,7 +27,7 @@
     compile_multilib: "both",
 
     shared_libs: [
-        "libbase"
+        "libbase",
     ],
     target: {
         android: {
@@ -62,5 +62,5 @@
         "art_debug_defaults",
         "wrapagentproperties-defaults",
     ],
-    shared_libs: [ ],
+    shared_libs: [],
 }