Merge "ART: More lenient lock merging in the verifier"
diff --git a/.gitignore b/.gitignore
index c4cf98b..4e806c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 JIT_ART
+**/__pycache__/**
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 52df7de..f34b5ed 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -21,6 +21,7 @@
 #include "utils.h"
 #include <numeric>
 #include "gtest/gtest.h"
+#include "runtime/experimental_flags.h"
 
 #define EXPECT_NULL(expected) EXPECT_EQ(reinterpret_cast<const void*>(expected), \
                                         reinterpret_cast<void*>(nullptr));
@@ -529,22 +530,32 @@
   }
 }  // TEST_F
 
-/* -X[no]experimental-lambdas */
-TEST_F(CmdlineParserTest, TestExperimentalLambdas) {
+/* -Xexperimental:_ */
+TEST_F(CmdlineParserTest, TestExperimentalFlags) {
   // Off by default
-  EXPECT_SINGLE_PARSE_DEFAULT_VALUE(false,
+  EXPECT_SINGLE_PARSE_DEFAULT_VALUE(ExperimentalFlags::kNone,
                                     "",
-                                    M::ExperimentalLambdas);
+                                    M::Experimental);
 
   // Disabled explicitly
-  EXPECT_SINGLE_PARSE_VALUE(false,
-                            "-Xnoexperimental-lambdas",
-                            M::ExperimentalLambdas);
+  EXPECT_SINGLE_PARSE_VALUE(ExperimentalFlags::kNone,
+                            "-Xexperimental:none",
+                            M::Experimental);
 
   // Enabled explicitly
-  EXPECT_SINGLE_PARSE_VALUE(true,
-                            "-Xexperimental-lambdas",
-                            M::ExperimentalLambdas);
+  EXPECT_SINGLE_PARSE_VALUE(ExperimentalFlags::kLambdas,
+                            "-Xexperimental:lambdas",
+                            M::Experimental);
+  // Enabled explicitly
+  EXPECT_SINGLE_PARSE_VALUE(ExperimentalFlags::kDefaultMethods,
+                            "-Xexperimental:default-methods",
+                            M::Experimental);
+
+  // Enabled both
+  EXPECT_SINGLE_PARSE_VALUE(ExperimentalFlags::kDefaultMethods | ExperimentalFlags::kLambdas,
+                            "-Xexperimental:default-methods "
+                            "-Xexperimental:lambdas",
+                            M::Experimental);
 }
 
 // -Xverify:_
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index a57b619..c594adb 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -28,6 +28,7 @@
 #include "jdwp/jdwp.h"
 #include "runtime/base/logging.h"
 #include "runtime/base/time_utils.h"
+#include "runtime/experimental_flags.h"
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
 #include "profiler_options.h"
@@ -838,6 +839,23 @@
   static constexpr bool kCanParseBlankless = true;
 };
 
+template<>
+struct CmdlineType<ExperimentalFlags> : CmdlineTypeParser<ExperimentalFlags> {
+  Result ParseAndAppend(const std::string& option, ExperimentalFlags& existing) {
+    if (option == "none") {
+      existing = existing | ExperimentalFlags::kNone;
+    } else if (option == "lambdas") {
+      existing = existing | ExperimentalFlags::kLambdas;
+    } else if (option == "default-methods") {
+      existing = existing | ExperimentalFlags::kDefaultMethods;
+    } else {
+      return Result::Failure(std::string("Unknown option '") + option + "'");
+    }
+    return Result::SuccessNoValue();
+  }
+
+  static const char* Name() { return "ExperimentalFlags"; }
+};
 
 }  // namespace art
 #endif  // ART_CMDLINE_CMDLINE_TYPES_H_
diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc
index 1cd742a..c2fe553 100644
--- a/compiler/dex/quick/quick_compiler.cc
+++ b/compiler/dex/quick/quick_compiler.cc
@@ -37,6 +37,7 @@
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
 #include "elf_writer_quick.h"
+#include "experimental_flags.h"
 #include "jni/quick/jni_compiler.h"
 #include "mir_to_lir.h"
 #include "mirror/object.h"
@@ -523,7 +524,8 @@
     // All opcodes are supported no matter what. Usually not the case
     // since experimental opcodes are not implemented in the quick compiler.
     return true;
-  } else if (LIKELY(!Runtime::Current()->AreExperimentalLambdasEnabled())) {
+  } else if (LIKELY(!Runtime::Current()->
+                      AreExperimentalFlagsEnabled(ExperimentalFlags::kLambdas))) {
     // Experimental opcodes are disabled.
     //
     // If all unsupported opcodes are experimental we don't need to do scanning.
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 2897006..6a743eb 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -41,6 +41,7 @@
 #include "driver/dex_compilation_unit.h"
 #include "gc_map_builder.h"
 #include "graph_visualizer.h"
+#include "intrinsics.h"
 #include "leb128.h"
 #include "mapping_table.h"
 #include "mirror/array-inl.h"
@@ -1381,4 +1382,57 @@
   }
 }
 
+void CodeGenerator::CreateSystemArrayCopyLocationSummary(HInvoke* invoke) {
+  // Check to see if we have known failures that will cause us to have to bail out
+  // to the runtime, and just generate the runtime call directly.
+  HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
+  HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
+
+  // The positions must be non-negative.
+  if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
+      (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
+    // We will have to fail anyways.
+    return;
+  }
+
+  // The length must be >= 0.
+  HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
+  if (length != nullptr) {
+    int32_t len = length->GetValue();
+    if (len < 0) {
+      // Just call as normal.
+      return;
+    }
+  }
+
+  SystemArrayCopyOptimizations optimizations(invoke);
+
+  if (optimizations.GetDestinationIsSource()) {
+    if (src_pos != nullptr && dest_pos != nullptr && src_pos->GetValue() < dest_pos->GetValue()) {
+      // We only support backward copying if source and destination are the same.
+      return;
+    }
+  }
+
+  if (optimizations.GetDestinationIsPrimitiveArray() || optimizations.GetSourceIsPrimitiveArray()) {
+    // We currently don't intrinsify primitive copying.
+    return;
+  }
+
+  ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetArena();
+  LocationSummary* locations = new (allocator) LocationSummary(invoke,
+                                                               LocationSummary::kCallOnSlowPath,
+                                                               kIntrinsified);
+  // arraycopy(Object src, int src_pos, Object dest, int dest_pos, int length).
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
+  locations->SetInAt(2, Location::RequiresRegister());
+  locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
+  locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
+
+  locations->AddTemp(Location::RequiresRegister());
+  locations->AddTemp(Location::RequiresRegister());
+  locations->AddTemp(Location::RequiresRegister());
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index acce5b3..b04dfc0 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -421,6 +421,8 @@
                                              Location runtime_type_index_location,
                                              Location runtime_return_location);
 
+  static void CreateSystemArrayCopyLocationSummary(HInvoke* invoke);
+
   void SetDisassemblyInformation(DisassemblyInformation* info) { disasm_info_ = info; }
   DisassemblyInformation* GetDisassemblyInformation() const { return disasm_info_; }
 
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index d172fba..8c1820b 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1645,6 +1645,7 @@
   DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
 
   IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
+                                         codegen_->GetAssembler(),
                                          codegen_->GetInstructionSetFeatures());
   if (intrinsic.TryDispatch(invoke)) {
     return;
@@ -1684,6 +1685,7 @@
 
 void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
   IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(),
+                                         codegen_->GetAssembler(),
                                          codegen_->GetInstructionSetFeatures());
   if (intrinsic.TryDispatch(invoke)) {
     return;
@@ -3512,6 +3514,47 @@
   }
 }
 
+Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
+                                                             Opcode opcode) {
+  DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
+  if (constant->IsConstant() &&
+      CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
+    return Location::ConstantLocation(constant->AsConstant());
+  }
+  return Location::RequiresRegister();
+}
+
+bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
+                                                       Opcode opcode) {
+  uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
+  if (Primitive::Is64BitType(input_cst->GetType())) {
+    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
+        CanEncodeConstantAsImmediate(High32Bits(value), opcode);
+  } else {
+    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
+  }
+}
+
+bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
+  ShifterOperand so;
+  ArmAssembler* assembler = codegen_->GetAssembler();
+  if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
+    return true;
+  }
+  Opcode neg_opcode = kNoOperand;
+  switch (opcode) {
+    case AND:
+      neg_opcode = BIC;
+      break;
+    case ORR:
+      neg_opcode = ORN;
+      break;
+    default:
+      return false;
+  }
+  return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
+}
+
 void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
                                                  const FieldInfo& field_info) {
   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
@@ -4912,17 +4955,18 @@
       nullptr);
 }
 
-void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
-void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
-void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
+void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
+void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
 
-void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
+void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   DCHECK(instruction->GetResultType() == Primitive::kPrimInt
          || instruction->GetResultType() == Primitive::kPrimLong);
+  // Note: GVN reorders commutative operations to have the constant on the right hand side.
   locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
@@ -4938,48 +4982,131 @@
   HandleBitwiseOperation(instruction);
 }
 
+void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
+  // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
+  if (value == 0xffffffffu) {
+    if (out != first) {
+      __ mov(out, ShifterOperand(first));
+    }
+    return;
+  }
+  if (value == 0u) {
+    __ mov(out, ShifterOperand(0));
+    return;
+  }
+  ShifterOperand so;
+  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
+    __ and_(out, first, so);
+  } else {
+    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
+    __ bic(out, first, ShifterOperand(~value));
+  }
+}
+
+void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
+  // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
+  if (value == 0u) {
+    if (out != first) {
+      __ mov(out, ShifterOperand(first));
+    }
+    return;
+  }
+  if (value == 0xffffffffu) {
+    __ mvn(out, ShifterOperand(0));
+    return;
+  }
+  ShifterOperand so;
+  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
+    __ orr(out, first, so);
+  } else {
+    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
+    __ orn(out, first, ShifterOperand(~value));
+  }
+}
+
+void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
+  // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
+  if (value == 0u) {
+    if (out != first) {
+      __ mov(out, ShifterOperand(first));
+    }
+    return;
+  }
+  __ eor(out, first, ShifterOperand(value));
+}
+
 void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
   LocationSummary* locations = instruction->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  Location out = locations->Out();
+
+  if (second.IsConstant()) {
+    uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
+    uint32_t value_low = Low32Bits(value);
+    if (instruction->GetResultType() == Primitive::kPrimInt) {
+      Register first_reg = first.AsRegister<Register>();
+      Register out_reg = out.AsRegister<Register>();
+      if (instruction->IsAnd()) {
+        GenerateAndConst(out_reg, first_reg, value_low);
+      } else if (instruction->IsOr()) {
+        GenerateOrrConst(out_reg, first_reg, value_low);
+      } else {
+        DCHECK(instruction->IsXor());
+        GenerateEorConst(out_reg, first_reg, value_low);
+      }
+    } else {
+      DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+      uint32_t value_high = High32Bits(value);
+      Register first_low = first.AsRegisterPairLow<Register>();
+      Register first_high = first.AsRegisterPairHigh<Register>();
+      Register out_low = out.AsRegisterPairLow<Register>();
+      Register out_high = out.AsRegisterPairHigh<Register>();
+      if (instruction->IsAnd()) {
+        GenerateAndConst(out_low, first_low, value_low);
+        GenerateAndConst(out_high, first_high, value_high);
+      } else if (instruction->IsOr()) {
+        GenerateOrrConst(out_low, first_low, value_low);
+        GenerateOrrConst(out_high, first_high, value_high);
+      } else {
+        DCHECK(instruction->IsXor());
+        GenerateEorConst(out_low, first_low, value_low);
+        GenerateEorConst(out_high, first_high, value_high);
+      }
+    }
+    return;
+  }
 
   if (instruction->GetResultType() == Primitive::kPrimInt) {
-    Register first = locations->InAt(0).AsRegister<Register>();
-    Register second = locations->InAt(1).AsRegister<Register>();
-    Register out = locations->Out().AsRegister<Register>();
+    Register first_reg = first.AsRegister<Register>();
+    ShifterOperand second_reg(second.AsRegister<Register>());
+    Register out_reg = out.AsRegister<Register>();
     if (instruction->IsAnd()) {
-      __ and_(out, first, ShifterOperand(second));
+      __ and_(out_reg, first_reg, second_reg);
     } else if (instruction->IsOr()) {
-      __ orr(out, first, ShifterOperand(second));
+      __ orr(out_reg, first_reg, second_reg);
     } else {
       DCHECK(instruction->IsXor());
-      __ eor(out, first, ShifterOperand(second));
+      __ eor(out_reg, first_reg, second_reg);
     }
   } else {
     DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
-    Location first = locations->InAt(0);
-    Location second = locations->InAt(1);
-    Location out = locations->Out();
+    Register first_low = first.AsRegisterPairLow<Register>();
+    Register first_high = first.AsRegisterPairHigh<Register>();
+    ShifterOperand second_low(second.AsRegisterPairLow<Register>());
+    ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
+    Register out_low = out.AsRegisterPairLow<Register>();
+    Register out_high = out.AsRegisterPairHigh<Register>();
     if (instruction->IsAnd()) {
-      __ and_(out.AsRegisterPairLow<Register>(),
-              first.AsRegisterPairLow<Register>(),
-              ShifterOperand(second.AsRegisterPairLow<Register>()));
-      __ and_(out.AsRegisterPairHigh<Register>(),
-              first.AsRegisterPairHigh<Register>(),
-              ShifterOperand(second.AsRegisterPairHigh<Register>()));
+      __ and_(out_low, first_low, second_low);
+      __ and_(out_high, first_high, second_high);
     } else if (instruction->IsOr()) {
-      __ orr(out.AsRegisterPairLow<Register>(),
-             first.AsRegisterPairLow<Register>(),
-             ShifterOperand(second.AsRegisterPairLow<Register>()));
-      __ orr(out.AsRegisterPairHigh<Register>(),
-             first.AsRegisterPairHigh<Register>(),
-             ShifterOperand(second.AsRegisterPairHigh<Register>()));
+      __ orr(out_low, first_low, second_low);
+      __ orr(out_high, first_high, second_high);
     } else {
       DCHECK(instruction->IsXor());
-      __ eor(out.AsRegisterPairLow<Register>(),
-             first.AsRegisterPairLow<Register>(),
-             ShifterOperand(second.AsRegisterPairLow<Register>()));
-      __ eor(out.AsRegisterPairHigh<Register>(),
-             first.AsRegisterPairHigh<Register>(),
-             ShifterOperand(second.AsRegisterPairHigh<Register>()));
+      __ eor(out_low, first_low, second_low);
+      __ eor(out_high, first_high, second_high);
     }
   }
 }
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 16d1d38..6900933 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -169,11 +169,15 @@
 
  private:
   void HandleInvoke(HInvoke* invoke);
-  void HandleBitwiseOperation(HBinaryOperation* operation);
+  void HandleBitwiseOperation(HBinaryOperation* operation, Opcode opcode);
   void HandleShift(HBinaryOperation* operation);
   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
 
+  Location ArmEncodableConstantOrRegister(HInstruction* constant, Opcode opcode);
+  bool CanEncodeConstantAsImmediate(HConstant* input_cst, Opcode opcode);
+  bool CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode);
+
   CodeGeneratorARM* const codegen_;
   InvokeDexCallingConventionVisitorARM parameter_visitor_;
 
@@ -205,6 +209,9 @@
   // the suspend call.
   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
   void GenerateClassInitializationCheck(SlowPathCode* slow_path, Register class_reg);
+  void GenerateAndConst(Register out, Register first, uint32_t value);
+  void GenerateOrrConst(Register out, Register first, uint32_t value);
+  void GenerateEorConst(Register out, Register first, uint32_t value);
   void HandleBitwiseOperation(HBinaryOperation* operation);
   void HandleShift(HBinaryOperation* operation);
   void GenerateMemoryBarrier(MemBarrierKind kind);
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 5e8f9e7..7799437 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -117,7 +117,7 @@
     return Location::RegisterLocation(A0);
   }
   Location GetReturnLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
-    return Location::RegisterLocation(A0);
+    return Location::RegisterLocation(V0);
   }
   Location GetSetValueLocation(
       Primitive::Type type ATTRIBUTE_UNUSED, bool is_instance) const OVERRIDE {
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index f8be21a..b60eebf 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -521,7 +521,8 @@
       move_resolver_(graph->GetArena(), this),
       isa_features_(isa_features),
       method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
-      relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
+      relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+      fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
   // Use a fake return address register to mimic Quick.
   AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
 }
@@ -5669,6 +5670,51 @@
   }
 }
 
+void LocationsBuilderX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+
+  // Constant area pointer.
+  locations->SetInAt(1, Location::RequiresRegister());
+
+  // And the temporary we need.
+  locations->AddTemp(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
+  int32_t lower_bound = switch_instr->GetStartValue();
+  int32_t num_entries = switch_instr->GetNumEntries();
+  LocationSummary* locations = switch_instr->GetLocations();
+  Register value_reg = locations->InAt(0).AsRegister<Register>();
+  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
+
+  // Optimizing has a jump area.
+  Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
+  Register constant_area = locations->InAt(1).AsRegister<Register>();
+
+  // Remove the bias, if needed.
+  if (lower_bound != 0) {
+    __ leal(temp_reg, Address(value_reg, -lower_bound));
+    value_reg = temp_reg;
+  }
+
+  // Is the value in range?
+  DCHECK_GE(num_entries, 1);
+  __ cmpl(value_reg, Immediate(num_entries - 1));
+  __ j(kAbove, codegen_->GetLabelOf(default_block));
+
+  // We are in the range of the table.
+  // Load (target-constant_area) from the jump table, indexing by the value.
+  __ movl(temp_reg, codegen_->LiteralCaseTable(switch_instr, constant_area, value_reg));
+
+  // Compute the actual target address by adding in constant_area.
+  __ addl(temp_reg, constant_area);
+
+  // And jump.
+  __ jmp(temp_reg);
+}
+
 void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress(
     HX86ComputeBaseMethodAddress* insn) {
   LocationSummary* locations =
@@ -5752,28 +5798,18 @@
   }
 }
 
-void CodeGeneratorX86::Finalize(CodeAllocator* allocator) {
-  // Generate the constant area if needed.
-  X86Assembler* assembler = GetAssembler();
-  if (!assembler->IsConstantAreaEmpty()) {
-    // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
-    // byte values.
-    assembler->Align(4, 0);
-    constant_area_start_ = assembler->CodeSize();
-    assembler->AddConstantArea();
-  }
-
-  // And finish up.
-  CodeGenerator::Finalize(allocator);
-}
-
 /**
  * Class to handle late fixup of offsets into constant area.
  */
 class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
  public:
-  RIPFixup(const CodeGeneratorX86& codegen, int offset)
-      : codegen_(codegen), offset_into_constant_area_(offset) {}
+  RIPFixup(CodeGeneratorX86& codegen, size_t offset)
+      : codegen_(&codegen), offset_into_constant_area_(offset) {}
+
+ protected:
+  void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
+
+  CodeGeneratorX86* codegen_;
 
  private:
   void Process(const MemoryRegion& region, int pos) OVERRIDE {
@@ -5781,19 +5817,77 @@
     // last 4 bytes of the instruction.
     // The value to patch is the distance from the offset in the constant area
     // from the address computed by the HX86ComputeBaseMethodAddress instruction.
-    int32_t constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
-    int32_t relative_position = constant_offset - codegen_.GetMethodAddressOffset();;
+    int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
+    int32_t relative_position = constant_offset - codegen_->GetMethodAddressOffset();;
 
     // Patch in the right value.
     region.StoreUnaligned<int32_t>(pos - 4, relative_position);
   }
 
-  const CodeGeneratorX86& codegen_;
-
   // Location in constant area that the fixup refers to.
-  int offset_into_constant_area_;
+  int32_t offset_into_constant_area_;
 };
 
+/**
+ * Class to handle late fixup of offsets to a jump table that will be created in the
+ * constant area.
+ */
+class JumpTableRIPFixup : public RIPFixup {
+ public:
+  JumpTableRIPFixup(CodeGeneratorX86& codegen, HX86PackedSwitch* switch_instr)
+      : RIPFixup(codegen, static_cast<size_t>(-1)), switch_instr_(switch_instr) {}
+
+  void CreateJumpTable() {
+    X86Assembler* assembler = codegen_->GetAssembler();
+
+    // Ensure that the reference to the jump table has the correct offset.
+    const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
+    SetOffset(offset_in_constant_table);
+
+    // The label values in the jump table are computed relative to the
+    // instruction addressing the constant area.
+    const int32_t relative_offset = codegen_->GetMethodAddressOffset();
+
+    // Populate the jump table with the correct values for the jump table.
+    int32_t num_entries = switch_instr_->GetNumEntries();
+    HBasicBlock* block = switch_instr_->GetBlock();
+    const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
+    // The value that we want is the target offset - the position of the table.
+    for (int32_t i = 0; i < num_entries; i++) {
+      HBasicBlock* b = successors[i];
+      Label* l = codegen_->GetLabelOf(b);
+      DCHECK(l->IsBound());
+      int32_t offset_to_block = l->Position() - relative_offset;
+      assembler->AppendInt32(offset_to_block);
+    }
+  }
+
+ private:
+  const HX86PackedSwitch* switch_instr_;
+};
+
+void CodeGeneratorX86::Finalize(CodeAllocator* allocator) {
+  // Generate the constant area if needed.
+  X86Assembler* assembler = GetAssembler();
+  if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
+    // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
+    // byte values.
+    assembler->Align(4, 0);
+    constant_area_start_ = assembler->CodeSize();
+
+    // Populate any jump tables.
+    for (auto jump_table : fixups_to_jump_tables_) {
+      jump_table->CreateJumpTable();
+    }
+
+    // And now add the constant area to the generated code.
+    assembler->AddConstantArea();
+  }
+
+  // And finish up.
+  CodeGenerator::Finalize(allocator);
+}
+
 Address CodeGeneratorX86::LiteralDoubleAddress(double v, Register reg) {
   AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
   return Address(reg, kDummy32BitOffset, fixup);
@@ -5814,6 +5908,20 @@
   return Address(reg, kDummy32BitOffset, fixup);
 }
 
+Address CodeGeneratorX86::LiteralCaseTable(HX86PackedSwitch* switch_instr,
+                                           Register reg,
+                                           Register value) {
+  // Create a fixup to be used to create and address the jump table.
+  JumpTableRIPFixup* table_fixup =
+      new (GetGraph()->GetArena()) JumpTableRIPFixup(*this, switch_instr);
+
+  // We have to populate the jump tables.
+  fixups_to_jump_tables_.push_back(table_fixup);
+
+  // We want a scaled address, as we are extracting the correct offset from the table.
+  return Address(reg, value, TIMES_4, kDummy32BitOffset, table_fixup);
+}
+
 /**
  * Finds instructions that need the constant area base as an input.
  */
@@ -5864,6 +5972,21 @@
     }
   }
 
+  void VisitPackedSwitch(HPackedSwitch* switch_insn) OVERRIDE {
+    // We need to replace the HPackedSwitch with a HX86PackedSwitch in order to
+    // address the constant area.
+    InitializeConstantAreaPointer(switch_insn);
+    HGraph* graph = GetGraph();
+    HBasicBlock* block = switch_insn->GetBlock();
+    HX86PackedSwitch* x86_switch = new (graph->GetArena()) HX86PackedSwitch(
+        switch_insn->GetStartValue(),
+        switch_insn->GetNumEntries(),
+        switch_insn->InputAt(0),
+        base_,
+        switch_insn->GetDexPc());
+    block->ReplaceAndRemoveInstructionWith(switch_insn, x86_switch);
+  }
+
   void InitializeConstantAreaPointer(HInstruction* user) {
     // Ensure we only initialize the pointer once.
     if (base_ != nullptr) {
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index ae2d84f..fdfc5ab 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -245,6 +245,8 @@
   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86);
 };
 
+class JumpTableRIPFixup;
+
 class CodeGeneratorX86 : public CodeGenerator {
  public:
   CodeGeneratorX86(HGraph* graph,
@@ -385,6 +387,8 @@
   Address LiteralInt32Address(int32_t v, Register reg);
   Address LiteralInt64Address(int64_t v, Register reg);
 
+  Address LiteralCaseTable(HX86PackedSwitch* switch_instr, Register reg, Register value);
+
   void Finalize(CodeAllocator* allocator) OVERRIDE;
 
  private:
@@ -405,6 +409,9 @@
   // Used for fixups to the constant area.
   int32_t constant_area_start_;
 
+  // Fixups for jump tables that need to be patched after the constant table is generated.
+  ArenaVector<JumpTableRIPFixup*> fixups_to_jump_tables_;
+
   // If there is a HX86ComputeBaseMethodAddress instruction in the graph
   // (which shall be the sole instruction of this kind), subtracting this offset
   // from the value contained in the out register of this HX86ComputeBaseMethodAddress
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 21120a0..f0d9420 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -670,7 +670,8 @@
         constant_area_start_(0),
         method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
         relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
-        pc_rel_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
+        pc_rel_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+        fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
   AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
 }
 
@@ -5322,31 +5323,43 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
+  locations->AddTemp(Location::RequiresRegister());
+  locations->AddTemp(Location::RequiresRegister());
 }
 
 void InstructionCodeGeneratorX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) {
   int32_t lower_bound = switch_instr->GetStartValue();
   int32_t num_entries = switch_instr->GetNumEntries();
   LocationSummary* locations = switch_instr->GetLocations();
-  CpuRegister value_reg = locations->InAt(0).AsRegister<CpuRegister>();
+  CpuRegister value_reg_in = locations->InAt(0).AsRegister<CpuRegister>();
+  CpuRegister temp_reg = locations->GetTemp(0).AsRegister<CpuRegister>();
+  CpuRegister base_reg = locations->GetTemp(1).AsRegister<CpuRegister>();
+
+  // Remove the bias, if needed.
+  Register value_reg_out = value_reg_in.AsRegister();
+  if (lower_bound != 0) {
+    __ leal(temp_reg, Address(value_reg_in, -lower_bound));
+    value_reg_out = temp_reg.AsRegister();
+  }
+  CpuRegister value_reg(value_reg_out);
+
+  // Is the value in range?
   HBasicBlock* default_block = switch_instr->GetDefaultBlock();
+  __ cmpl(value_reg, Immediate(num_entries - 1));
+  __ j(kAbove, codegen_->GetLabelOf(default_block));
 
-  // Create a series of compare/jumps.
-  const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
-  for (int i = 0; i < num_entries; i++) {
-    int32_t case_value = lower_bound + i;
-    if (case_value == 0) {
-      __ testl(value_reg, value_reg);
-    } else {
-      __ cmpl(value_reg, Immediate(case_value));
-    }
-    __ j(kEqual, codegen_->GetLabelOf(successors[i]));
-  }
+  // We are in the range of the table.
+  // Load the address of the jump table in the constant area.
+  __ leaq(base_reg, codegen_->LiteralCaseTable(switch_instr));
 
-  // And the default for any other value.
-  if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
-      __ jmp(codegen_->GetLabelOf(default_block));
-  }
+  // Load the (signed) offset from the jump table.
+  __ movsxd(temp_reg, Address(base_reg, value_reg, TIMES_4, 0));
+
+  // Add the offset to the address of the table base.
+  __ addq(temp_reg, base_reg);
+
+  // And jump.
+  __ jmp(temp_reg);
 }
 
 void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
@@ -5372,15 +5385,85 @@
   }
 }
 
+/**
+ * Class to handle late fixup of offsets into constant area.
+ */
+class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
+ public:
+  RIPFixup(CodeGeneratorX86_64& codegen, size_t offset)
+      : codegen_(&codegen), offset_into_constant_area_(offset) {}
+
+ protected:
+  void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
+
+  CodeGeneratorX86_64* codegen_;
+
+ private:
+  void Process(const MemoryRegion& region, int pos) OVERRIDE {
+    // Patch the correct offset for the instruction.  We use the address of the
+    // 'next' instruction, which is 'pos' (patch the 4 bytes before).
+    int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
+    int32_t relative_position = constant_offset - pos;
+
+    // Patch in the right value.
+    region.StoreUnaligned<int32_t>(pos - 4, relative_position);
+  }
+
+  // Location in constant area that the fixup refers to.
+  size_t offset_into_constant_area_;
+};
+
+/**
+ t * Class to handle late fixup of offsets to a jump table that will be created in the
+ * constant area.
+ */
+class JumpTableRIPFixup : public RIPFixup {
+ public:
+  JumpTableRIPFixup(CodeGeneratorX86_64& codegen, HPackedSwitch* switch_instr)
+      : RIPFixup(codegen, -1), switch_instr_(switch_instr) {}
+
+  void CreateJumpTable() {
+    X86_64Assembler* assembler = codegen_->GetAssembler();
+
+    // Ensure that the reference to the jump table has the correct offset.
+    const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
+    SetOffset(offset_in_constant_table);
+
+    // Compute the offset from the start of the function to this jump table.
+    const int32_t current_table_offset = assembler->CodeSize() + offset_in_constant_table;
+
+    // Populate the jump table with the correct values for the jump table.
+    int32_t num_entries = switch_instr_->GetNumEntries();
+    HBasicBlock* block = switch_instr_->GetBlock();
+    const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
+    // The value that we want is the target offset - the position of the table.
+    for (int32_t i = 0; i < num_entries; i++) {
+      HBasicBlock* b = successors[i];
+      Label* l = codegen_->GetLabelOf(b);
+      DCHECK(l->IsBound());
+      int32_t offset_to_block = l->Position() - current_table_offset;
+      assembler->AppendInt32(offset_to_block);
+    }
+  }
+
+ private:
+  const HPackedSwitch* switch_instr_;
+};
+
 void CodeGeneratorX86_64::Finalize(CodeAllocator* allocator) {
   // Generate the constant area if needed.
   X86_64Assembler* assembler = GetAssembler();
-  if (!assembler->IsConstantAreaEmpty()) {
-    // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
-    // byte values.  If used for vectors at a later time, this will need to be
-    // updated to 16 bytes with the appropriate offset.
+  if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
+    // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8 byte values.
     assembler->Align(4, 0);
     constant_area_start_ = assembler->CodeSize();
+
+    // Populate any jump tables.
+    for (auto jump_table : fixups_to_jump_tables_) {
+      jump_table->CreateJumpTable();
+    }
+
+    // And now add the constant area to the generated code.
     assembler->AddConstantArea();
   }
 
@@ -5388,31 +5471,6 @@
   CodeGenerator::Finalize(allocator);
 }
 
-/**
- * Class to handle late fixup of offsets into constant area.
- */
-class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
-  public:
-    RIPFixup(const CodeGeneratorX86_64& codegen, int offset)
-      : codegen_(codegen), offset_into_constant_area_(offset) {}
-
-  private:
-    void Process(const MemoryRegion& region, int pos) OVERRIDE {
-      // Patch the correct offset for the instruction.  We use the address of the
-      // 'next' instruction, which is 'pos' (patch the 4 bytes before).
-      int constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
-      int relative_position = constant_offset - pos;
-
-      // Patch in the right value.
-      region.StoreUnaligned<int32_t>(pos - 4, relative_position);
-    }
-
-    const CodeGeneratorX86_64& codegen_;
-
-    // Location in constant area that the fixup refers to.
-    int offset_into_constant_area_;
-};
-
 Address CodeGeneratorX86_64::LiteralDoubleAddress(double v) {
   AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
   return Address::RIP(fixup);
@@ -5453,6 +5511,16 @@
   GetMoveResolver()->EmitNativeCode(&parallel_move);
 }
 
+Address CodeGeneratorX86_64::LiteralCaseTable(HPackedSwitch* switch_instr) {
+  // Create a fixup to be used to create and address the jump table.
+  JumpTableRIPFixup* table_fixup =
+      new (GetGraph()->GetArena()) JumpTableRIPFixup(*this, switch_instr);
+
+  // We have to populate the jump tables.
+  fixups_to_jump_tables_.push_back(table_fixup);
+  return Address::RIP(table_fixup);
+}
+
 #undef __
 
 }  // namespace x86_64
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index d6a6a7e..dc86a48 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -234,6 +234,9 @@
   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86_64);
 };
 
+// Class for fixups to jump tables.
+class JumpTableRIPFixup;
+
 class CodeGeneratorX86_64 : public CodeGenerator {
  public:
   CodeGeneratorX86_64(HGraph* graph,
@@ -354,6 +357,7 @@
 
   // Load a 64 bit value into a register in the most efficient manner.
   void Load64BitValue(CpuRegister dest, int64_t value);
+  Address LiteralCaseTable(HPackedSwitch* switch_instr);
 
   // Store a 64 bit value into a DoubleStackSlot in the most efficient manner.
   void Store64BitValueToStack(Location dest, int64_t value);
@@ -391,6 +395,9 @@
   // We will fix this up in the linker later to have the right value.
   static constexpr int32_t kDummy32BitOffset = 256;
 
+  // Fixups for jump tables need to be handled specially.
+  ArenaVector<JumpTableRIPFixup*> fixups_to_jump_tables_;
+
   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86_64);
 };
 
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 2793793..58e479a 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -1307,6 +1307,308 @@
   __ Bind(slow_path->GetExitLabel());
 }
 
+void IntrinsicLocationsBuilderARM::VisitSystemArrayCopy(HInvoke* invoke) {
+  CodeGenerator::CreateSystemArrayCopyLocationSummary(invoke);
+  LocationSummary* locations = invoke->GetLocations();
+  if (locations == nullptr) {
+    return;
+  }
+
+  HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
+  HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
+  HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
+
+  if (src_pos != nullptr && !assembler_->ShifterOperandCanAlwaysHold(src_pos->GetValue())) {
+    locations->SetInAt(1, Location::RequiresRegister());
+  }
+  if (dest_pos != nullptr && !assembler_->ShifterOperandCanAlwaysHold(dest_pos->GetValue())) {
+    locations->SetInAt(3, Location::RequiresRegister());
+  }
+  if (length != nullptr && !assembler_->ShifterOperandCanAlwaysHold(length->GetValue())) {
+    locations->SetInAt(4, Location::RequiresRegister());
+  }
+}
+
+static void CheckPosition(ArmAssembler* assembler,
+                          Location pos,
+                          Register input,
+                          Location length,
+                          SlowPathCode* slow_path,
+                          Register input_len,
+                          Register temp,
+                          bool length_is_input_length = false) {
+  // Where is the length in the Array?
+  const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
+
+  if (pos.IsConstant()) {
+    int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
+    if (pos_const == 0) {
+      if (!length_is_input_length) {
+        // Check that length(input) >= length.
+        __ LoadFromOffset(kLoadWord, temp, input, length_offset);
+        if (length.IsConstant()) {
+          __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue()));
+        } else {
+          __ cmp(temp, ShifterOperand(length.AsRegister<Register>()));
+        }
+        __ b(slow_path->GetEntryLabel(), LT);
+      }
+    } else {
+      // Check that length(input) >= pos.
+      __ LoadFromOffset(kLoadWord, input_len, input, length_offset);
+      __ subs(temp, input_len, ShifterOperand(pos_const));
+      __ b(slow_path->GetEntryLabel(), LT);
+
+      // Check that (length(input) - pos) >= length.
+      if (length.IsConstant()) {
+        __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue()));
+      } else {
+        __ cmp(temp, ShifterOperand(length.AsRegister<Register>()));
+      }
+      __ b(slow_path->GetEntryLabel(), LT);
+    }
+  } else if (length_is_input_length) {
+    // The only way the copy can succeed is if pos is zero.
+    Register pos_reg = pos.AsRegister<Register>();
+    __ CompareAndBranchIfNonZero(pos_reg, slow_path->GetEntryLabel());
+  } else {
+    // Check that pos >= 0.
+    Register pos_reg = pos.AsRegister<Register>();
+    __ cmp(pos_reg, ShifterOperand(0));
+    __ b(slow_path->GetEntryLabel(), LT);
+
+    // Check that pos <= length(input).
+    __ LoadFromOffset(kLoadWord, temp, input, length_offset);
+    __ subs(temp, temp, ShifterOperand(pos_reg));
+    __ b(slow_path->GetEntryLabel(), LT);
+
+    // Check that (length(input) - pos) >= length.
+    if (length.IsConstant()) {
+      __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue()));
+    } else {
+      __ cmp(temp, ShifterOperand(length.AsRegister<Register>()));
+    }
+    __ b(slow_path->GetEntryLabel(), LT);
+  }
+}
+
+void IntrinsicCodeGeneratorARM::VisitSystemArrayCopy(HInvoke* invoke) {
+  ArmAssembler* assembler = GetAssembler();
+  LocationSummary* locations = invoke->GetLocations();
+
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+  uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
+  uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
+  uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
+
+  Register src = locations->InAt(0).AsRegister<Register>();
+  Location src_pos = locations->InAt(1);
+  Register dest = locations->InAt(2).AsRegister<Register>();
+  Location dest_pos = locations->InAt(3);
+  Location length = locations->InAt(4);
+  Register temp1 = locations->GetTemp(0).AsRegister<Register>();
+  Register temp2 = locations->GetTemp(1).AsRegister<Register>();
+  Register temp3 = locations->GetTemp(2).AsRegister<Register>();
+
+  SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
+  codegen_->AddSlowPath(slow_path);
+
+  Label ok;
+  SystemArrayCopyOptimizations optimizations(invoke);
+
+  if (!optimizations.GetDestinationIsSource()) {
+    if (!src_pos.IsConstant() || !dest_pos.IsConstant()) {
+      __ cmp(src, ShifterOperand(dest));
+    }
+  }
+
+  // If source and destination are the same, we go to slow path if we need to do
+  // forward copying.
+  if (src_pos.IsConstant()) {
+    int32_t src_pos_constant = src_pos.GetConstant()->AsIntConstant()->GetValue();
+    if (dest_pos.IsConstant()) {
+      // Checked when building locations.
+      DCHECK(!optimizations.GetDestinationIsSource()
+             || (src_pos_constant >= dest_pos.GetConstant()->AsIntConstant()->GetValue()));
+    } else {
+      if (!optimizations.GetDestinationIsSource()) {
+        __ b(&ok, NE);
+      }
+      __ cmp(dest_pos.AsRegister<Register>(), ShifterOperand(src_pos_constant));
+      __ b(slow_path->GetEntryLabel(), GT);
+    }
+  } else {
+    if (!optimizations.GetDestinationIsSource()) {
+      __ b(&ok, NE);
+    }
+    if (dest_pos.IsConstant()) {
+      int32_t dest_pos_constant = dest_pos.GetConstant()->AsIntConstant()->GetValue();
+      __ cmp(src_pos.AsRegister<Register>(), ShifterOperand(dest_pos_constant));
+    } else {
+      __ cmp(src_pos.AsRegister<Register>(), ShifterOperand(dest_pos.AsRegister<Register>()));
+    }
+    __ b(slow_path->GetEntryLabel(), LT);
+  }
+
+  __ Bind(&ok);
+
+  if (!optimizations.GetSourceIsNotNull()) {
+    // Bail out if the source is null.
+    __ CompareAndBranchIfZero(src, slow_path->GetEntryLabel());
+  }
+
+  if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) {
+    // Bail out if the destination is null.
+    __ CompareAndBranchIfZero(dest, slow_path->GetEntryLabel());
+  }
+
+  // If the length is negative, bail out.
+  // We have already checked in the LocationsBuilder for the constant case.
+  if (!length.IsConstant() &&
+      !optimizations.GetCountIsSourceLength() &&
+      !optimizations.GetCountIsDestinationLength()) {
+    __ cmp(length.AsRegister<Register>(), ShifterOperand(0));
+    __ b(slow_path->GetEntryLabel(), LT);
+  }
+
+  // Validity checks: source.
+  CheckPosition(assembler,
+                src_pos,
+                src,
+                length,
+                slow_path,
+                temp1,
+                temp2,
+                optimizations.GetCountIsSourceLength());
+
+  // Validity checks: dest.
+  CheckPosition(assembler,
+                dest_pos,
+                dest,
+                length,
+                slow_path,
+                temp1,
+                temp2,
+                optimizations.GetCountIsDestinationLength());
+
+  if (!optimizations.GetDoesNotNeedTypeCheck()) {
+    // Check whether all elements of the source array are assignable to the component
+    // type of the destination array. We do two checks: the classes are the same,
+    // or the destination is Object[]. If none of these checks succeed, we go to the
+    // slow path.
+    __ LoadFromOffset(kLoadWord, temp1, dest, class_offset);
+    __ LoadFromOffset(kLoadWord, temp2, src, class_offset);
+    bool did_unpoison = false;
+    if (!optimizations.GetDestinationIsNonPrimitiveArray() ||
+        !optimizations.GetSourceIsNonPrimitiveArray()) {
+      // One or two of the references need to be unpoisoned. Unpoisoned them
+      // both to make the identity check valid.
+      __ MaybeUnpoisonHeapReference(temp1);
+      __ MaybeUnpoisonHeapReference(temp2);
+      did_unpoison = true;
+    }
+
+    if (!optimizations.GetDestinationIsNonPrimitiveArray()) {
+      // Bail out if the destination is not a non primitive array.
+      __ LoadFromOffset(kLoadWord, temp3, temp1, component_offset);
+      __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel());
+      __ MaybeUnpoisonHeapReference(temp3);
+      __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset);
+      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
+      __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel());
+    }
+
+    if (!optimizations.GetSourceIsNonPrimitiveArray()) {
+      // Bail out if the source is not a non primitive array.
+      // Bail out if the destination is not a non primitive array.
+      __ LoadFromOffset(kLoadWord, temp3, temp2, component_offset);
+      __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel());
+      __ MaybeUnpoisonHeapReference(temp3);
+      __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset);
+      static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
+      __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel());
+    }
+
+    __ cmp(temp1, ShifterOperand(temp2));
+
+    if (optimizations.GetDestinationIsTypedObjectArray()) {
+      Label do_copy;
+      __ b(&do_copy, EQ);
+      if (!did_unpoison) {
+        __ MaybeUnpoisonHeapReference(temp1);
+      }
+      __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
+      __ MaybeUnpoisonHeapReference(temp1);
+      __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
+      // No need to unpoison the result, we're comparing against null.
+      __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
+      __ Bind(&do_copy);
+    } else {
+      __ b(slow_path->GetEntryLabel(), NE);
+    }
+  } else if (!optimizations.GetSourceIsNonPrimitiveArray()) {
+    DCHECK(optimizations.GetDestinationIsNonPrimitiveArray());
+    // Bail out if the source is not a non primitive array.
+    __ LoadFromOffset(kLoadWord, temp1, src, class_offset);
+    __ MaybeUnpoisonHeapReference(temp1);
+    __ LoadFromOffset(kLoadWord, temp3, temp1, component_offset);
+    __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel());
+    __ MaybeUnpoisonHeapReference(temp3);
+    __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset);
+    static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
+    __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel());
+  }
+
+  // Compute base source address, base destination address, and end source address.
+
+  uint32_t element_size = sizeof(int32_t);
+  uint32_t offset = mirror::Array::DataOffset(element_size).Uint32Value();
+  if (src_pos.IsConstant()) {
+    int32_t constant = src_pos.GetConstant()->AsIntConstant()->GetValue();
+    __ AddConstant(temp1, src, element_size * constant + offset);
+  } else {
+    __ add(temp1, src, ShifterOperand(src_pos.AsRegister<Register>(), LSL, 2));
+    __ AddConstant(temp1, offset);
+  }
+
+  if (dest_pos.IsConstant()) {
+    int32_t constant = dest_pos.GetConstant()->AsIntConstant()->GetValue();
+    __ AddConstant(temp2, dest, element_size * constant + offset);
+  } else {
+    __ add(temp2, dest, ShifterOperand(dest_pos.AsRegister<Register>(), LSL, 2));
+    __ AddConstant(temp2, offset);
+  }
+
+  if (length.IsConstant()) {
+    int32_t constant = length.GetConstant()->AsIntConstant()->GetValue();
+    __ AddConstant(temp3, temp1, element_size * constant);
+  } else {
+    __ add(temp3, temp1, ShifterOperand(length.AsRegister<Register>(), LSL, 2));
+  }
+
+  // Iterate over the arrays and do a raw copy of the objects. We don't need to
+  // poison/unpoison, nor do any read barrier as the next uses of the destination
+  // array will do it.
+  Label loop, done;
+  __ cmp(temp1, ShifterOperand(temp3));
+  __ b(&done, EQ);
+  __ Bind(&loop);
+  __ ldr(IP, Address(temp1, element_size, Address::PostIndex));
+  __ str(IP, Address(temp2, element_size, Address::PostIndex));
+  __ cmp(temp1, ShifterOperand(temp3));
+  __ b(&loop, NE);
+  __ Bind(&done);
+
+  // We only need one card marking on the destination array.
+  codegen_->MarkGCCard(temp1,
+                       temp2,
+                       dest,
+                       Register(kNoRegister),
+                       false);
+
+  __ Bind(slow_path->GetExitLabel());
+}
+
 // Unimplemented intrinsics.
 
 #define UNIMPLEMENTED_INTRINSIC(Name)                                                  \
@@ -1333,7 +1635,6 @@
 UNIMPLEMENTED_INTRINSIC(MathRoundFloat)    // Could be done by changing rounding mode, maybe?
 UNIMPLEMENTED_INTRINSIC(UnsafeCASLong)     // High register pressure.
 UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
-UNIMPLEMENTED_INTRINSIC(SystemArrayCopy)
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
 
diff --git a/compiler/optimizing/intrinsics_arm.h b/compiler/optimizing/intrinsics_arm.h
index 2abb605..127e9a4 100644
--- a/compiler/optimizing/intrinsics_arm.h
+++ b/compiler/optimizing/intrinsics_arm.h
@@ -33,8 +33,10 @@
 
 class IntrinsicLocationsBuilderARM FINAL : public IntrinsicVisitor {
  public:
-  IntrinsicLocationsBuilderARM(ArenaAllocator* arena, const ArmInstructionSetFeatures& features)
-      : arena_(arena), features_(features) {}
+  IntrinsicLocationsBuilderARM(ArenaAllocator* arena,
+                               ArmAssembler* assembler,
+                               const ArmInstructionSetFeatures& features)
+      : arena_(arena), assembler_(assembler), features_(features) {}
 
   // Define visitor methods.
 
@@ -52,6 +54,7 @@
 
  private:
   ArenaAllocator* arena_;
+  ArmAssembler* assembler_;
 
   const ArmInstructionSetFeatures& features_;
 
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 1061aae..e0d88a9 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -914,55 +914,7 @@
 
 
 void IntrinsicLocationsBuilderX86_64::VisitSystemArrayCopy(HInvoke* invoke) {
-  // Check to see if we have known failures that will cause us to have to bail out
-  // to the runtime, and just generate the runtime call directly.
-  HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
-  HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
-
-  // The positions must be non-negative.
-  if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
-      (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
-    // We will have to fail anyways.
-    return;
-  }
-
-  // The length must be > 0.
-  HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
-  if (length != nullptr) {
-    int32_t len = length->GetValue();
-    if (len < 0) {
-      // Just call as normal.
-      return;
-    }
-  }
-
-  SystemArrayCopyOptimizations optimizations(invoke);
-
-  if (optimizations.GetDestinationIsSource()) {
-    if (src_pos != nullptr && dest_pos != nullptr && src_pos->GetValue() < dest_pos->GetValue()) {
-      // We only support backward copying if source and destination are the same.
-      return;
-    }
-  }
-
-  if (optimizations.GetDestinationIsPrimitiveArray() || optimizations.GetSourceIsPrimitiveArray()) {
-    // We currently don't intrinsify primitive copying.
-    return;
-  }
-
-  LocationSummary* locations = new (arena_) LocationSummary(invoke,
-                                                            LocationSummary::kCallOnSlowPath,
-                                                            kIntrinsified);
-  // arraycopy(Object src, int src_pos, Object dest, int dest_pos, int length).
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
-  locations->SetInAt(2, Location::RequiresRegister());
-  locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
-  locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
-
-  locations->AddTemp(Location::RequiresRegister());
-  locations->AddTemp(Location::RequiresRegister());
-  locations->AddTemp(Location::RequiresRegister());
+  CodeGenerator::CreateSystemArrayCopyLocationSummary(invoke);
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitSystemArrayCopy(HInvoke* invoke) {
@@ -990,7 +942,9 @@
   SystemArrayCopyOptimizations optimizations(invoke);
 
   if (!optimizations.GetDestinationIsSource()) {
-    __ cmpl(src, dest);
+    if (!src_pos.IsConstant() || !dest_pos.IsConstant()) {
+      __ cmpl(src, dest);
+    }
   }
 
   // If source and destination are the same, we go to slow path if we need to do
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 24a89bc..ed401b6 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -606,8 +606,23 @@
 void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
                                                   HInstruction* replacement) {
   DCHECK(initial->GetBlock() == this);
-  InsertInstructionBefore(replacement, initial);
-  initial->ReplaceWith(replacement);
+  if (initial->IsControlFlow()) {
+    // We can only replace a control flow instruction with another control flow instruction.
+    DCHECK(replacement->IsControlFlow());
+    DCHECK_EQ(replacement->GetId(), -1);
+    DCHECK_EQ(replacement->GetType(), Primitive::kPrimVoid);
+    DCHECK_EQ(initial->GetBlock(), this);
+    DCHECK_EQ(initial->GetType(), Primitive::kPrimVoid);
+    DCHECK(initial->GetUses().IsEmpty());
+    DCHECK(initial->GetEnvUses().IsEmpty());
+    replacement->SetBlock(this);
+    replacement->SetId(GetGraph()->GetNextInstructionId());
+    instructions_.InsertInstructionBefore(replacement, initial);
+    UpdateInputsUsers(replacement);
+  } else {
+    InsertInstructionBefore(replacement, initial);
+    initial->ReplaceWith(replacement);
+  }
   RemoveInstruction(initial);
 }
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 82909c4..0d668e8 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1074,7 +1074,8 @@
 
 #define FOR_EACH_CONCRETE_INSTRUCTION_X86(M)                            \
   M(X86ComputeBaseMethodAddress, Instruction)                           \
-  M(X86LoadFromConstantTable, Instruction)
+  M(X86LoadFromConstantTable, Instruction)                              \
+  M(X86PackedSwitch, Instruction)
 
 #define FOR_EACH_CONCRETE_INSTRUCTION_X86_64(M)
 
diff --git a/compiler/optimizing/nodes_x86.h b/compiler/optimizing/nodes_x86.h
index f7cc872..556217b 100644
--- a/compiler/optimizing/nodes_x86.h
+++ b/compiler/optimizing/nodes_x86.h
@@ -62,6 +62,45 @@
   DISALLOW_COPY_AND_ASSIGN(HX86LoadFromConstantTable);
 };
 
+// X86 version of HPackedSwitch that holds a pointer to the base method address.
+class HX86PackedSwitch : public HTemplateInstruction<2> {
+ public:
+  HX86PackedSwitch(int32_t start_value,
+                   int32_t num_entries,
+                   HInstruction* input,
+                   HX86ComputeBaseMethodAddress* method_base,
+                   uint32_t dex_pc)
+    : HTemplateInstruction(SideEffects::None(), dex_pc),
+      start_value_(start_value),
+      num_entries_(num_entries) {
+    SetRawInputAt(0, input);
+    SetRawInputAt(1, method_base);
+  }
+
+  bool IsControlFlow() const OVERRIDE { return true; }
+
+  int32_t GetStartValue() const { return start_value_; }
+
+  int32_t GetNumEntries() const { return num_entries_; }
+
+  HX86ComputeBaseMethodAddress* GetBaseMethodAddress() const {
+    return InputAt(1)->AsX86ComputeBaseMethodAddress();
+  }
+
+  HBasicBlock* GetDefaultBlock() const {
+    // Last entry is the default block.
+    return GetBlock()->GetSuccessors()[num_entries_];
+  }
+
+  DECLARE_INSTRUCTION(X86PackedSwitch);
+
+ private:
+  const int32_t start_value_;
+  const int32_t num_entries_;
+
+  DISALLOW_COPY_AND_ASSIGN(HX86PackedSwitch);
+};
+
 }  // namespace art
 
 #endif  // ART_COMPILER_OPTIMIZING_NODES_X86_H_
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index 967b191..d59bc6b 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -470,6 +470,13 @@
     orr(rd, rn, so, cond, kCcSet);
   }
 
+  virtual void orn(Register rd, Register rn, const ShifterOperand& so,
+                   Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
+
+  virtual void orns(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
+    orn(rd, rn, so, cond, kCcSet);
+  }
+
   virtual void mov(Register rd, const ShifterOperand& so,
                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
 
@@ -832,6 +839,8 @@
                                      uint32_t immediate,
                                      ShifterOperand* shifter_op) = 0;
 
+  virtual bool ShifterOperandCanAlwaysHold(uint32_t immediate) = 0;
+
   static bool IsInstructionForExceptionHandling(uintptr_t pc);
 
   virtual void CompareAndBranchIfZero(Register r, Label* label) = 0;
diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc
index f7772ae..6e7c828 100644
--- a/compiler/utils/arm/assembler_arm32.cc
+++ b/compiler/utils/arm/assembler_arm32.cc
@@ -48,6 +48,11 @@
   return false;
 }
 
+bool Arm32Assembler::ShifterOperandCanAlwaysHold(uint32_t immediate) {
+  ShifterOperand shifter_op;
+  return ShifterOperandCanHoldArm32(immediate, &shifter_op);
+}
+
 bool Arm32Assembler::ShifterOperandCanHold(Register rd ATTRIBUTE_UNUSED,
                                            Register rn ATTRIBUTE_UNUSED,
                                            Opcode opcode ATTRIBUTE_UNUSED,
@@ -130,6 +135,15 @@
 }
 
 
+void Arm32Assembler::orn(Register rd ATTRIBUTE_UNUSED,
+                         Register rn ATTRIBUTE_UNUSED,
+                         const ShifterOperand& so ATTRIBUTE_UNUSED,
+                         Condition cond ATTRIBUTE_UNUSED,
+                         SetCc set_cc ATTRIBUTE_UNUSED) {
+  LOG(FATAL) << "orn is not supported on ARM32";
+}
+
+
 void Arm32Assembler::mov(Register rd, const ShifterOperand& so,
                          Condition cond, SetCc set_cc) {
   EmitType01(cond, so.type(), MOV, set_cc, R0, rd, so);
diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h
index 3407369..4646538 100644
--- a/compiler/utils/arm/assembler_arm32.h
+++ b/compiler/utils/arm/assembler_arm32.h
@@ -74,6 +74,9 @@
   virtual void orr(Register rd, Register rn, const ShifterOperand& so,
                    Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
 
+  virtual void orn(Register rd, Register rn, const ShifterOperand& so,
+                   Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
+
   virtual void mov(Register rd, const ShifterOperand& so,
                    Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
 
@@ -294,6 +297,7 @@
                              uint32_t immediate,
                              ShifterOperand* shifter_op) OVERRIDE;
 
+  bool ShifterOperandCanAlwaysHold(uint32_t immediate) OVERRIDE;
 
   static bool IsInstructionForExceptionHandling(uintptr_t pc);
 
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 0f6c4f5..cc87856 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -390,6 +390,10 @@
   EmitLiterals();
 }
 
+bool Thumb2Assembler::ShifterOperandCanAlwaysHold(uint32_t immediate) {
+  return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
+}
+
 bool Thumb2Assembler::ShifterOperandCanHold(Register rd ATTRIBUTE_UNUSED,
                                             Register rn ATTRIBUTE_UNUSED,
                                             Opcode opcode,
@@ -410,6 +414,7 @@
     case MOV:
       // TODO: Support less than or equal to 12bits.
       return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
+
     case MVN:
     default:
       return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
@@ -492,6 +497,12 @@
 }
 
 
+void Thumb2Assembler::orn(Register rd, Register rn, const ShifterOperand& so,
+                          Condition cond, SetCc set_cc) {
+  EmitDataProcessing(cond, ORN, set_cc, rn, rd, so);
+}
+
+
 void Thumb2Assembler::mov(Register rd, const ShifterOperand& so,
                           Condition cond, SetCc set_cc) {
   EmitDataProcessing(cond, MOV, set_cc, R0, rd, so);
@@ -1105,6 +1116,7 @@
       rn_is_valid = false;      // There is no Rn for these instructions.
       break;
     case TEQ:
+    case ORN:
       return true;
     case ADD:
     case SUB:
@@ -1222,6 +1234,7 @@
     case MOV: thumb_opcode =  2U /* 0b0010 */; rn = PC; break;
     case BIC: thumb_opcode =  1U /* 0b0001 */; break;
     case MVN: thumb_opcode =  3U /* 0b0011 */; rn = PC; break;
+    case ORN: thumb_opcode =  3U /* 0b0011 */; break;
     default:
       break;
   }
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index a1a8927..055b137 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -98,6 +98,9 @@
   virtual void orr(Register rd, Register rn, const ShifterOperand& so,
                    Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
 
+  virtual void orn(Register rd, Register rn, const ShifterOperand& so,
+                   Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
+
   virtual void mov(Register rd, const ShifterOperand& so,
                    Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
 
@@ -337,6 +340,8 @@
                              uint32_t immediate,
                              ShifterOperand* shifter_op) OVERRIDE;
 
+  bool ShifterOperandCanAlwaysHold(uint32_t immediate) OVERRIDE;
+
 
   static bool IsInstructionForExceptionHandling(uintptr_t pc);
 
diff --git a/compiler/utils/arm/constants_arm.h b/compiler/utils/arm/constants_arm.h
index 6b4daed..2060064 100644
--- a/compiler/utils/arm/constants_arm.h
+++ b/compiler/utils/arm/constants_arm.h
@@ -148,7 +148,8 @@
   MOV = 13,  // Move
   BIC = 14,  // Bit Clear
   MVN = 15,  // Move Not
-  kMaxOperand = 16
+  ORN = 16,  // Logical OR NOT.
+  kMaxOperand = 17
 };
 std::ostream& operator<<(std::ostream& os, const Opcode& rhs);
 
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index b2a354b..2ae8841 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -238,6 +238,7 @@
   __ sub(R0, R1, ShifterOperand(R2), AL, kCcKeep);
   __ and_(R0, R1, ShifterOperand(R2), AL, kCcKeep);
   __ orr(R0, R1, ShifterOperand(R2), AL, kCcKeep);
+  __ orn(R0, R1, ShifterOperand(R2), AL, kCcKeep);
   __ eor(R0, R1, ShifterOperand(R2), AL, kCcKeep);
   __ bic(R0, R1, ShifterOperand(R2), AL, kCcKeep);
   __ adc(R0, R1, ShifterOperand(R2), AL, kCcKeep);
@@ -371,6 +372,7 @@
   __ sub(R0, R1, ShifterOperand(0x55));
   __ and_(R0, R1, ShifterOperand(0x55));
   __ orr(R0, R1, ShifterOperand(0x55));
+  __ orn(R0, R1, ShifterOperand(0x55));
   __ eor(R0, R1, ShifterOperand(0x55));
   __ bic(R0, R1, ShifterOperand(0x55));
   __ adc(R0, R1, ShifterOperand(0x55));
@@ -403,6 +405,7 @@
   __ sub(R0, R1, ShifterOperand(0x550055));
   __ and_(R0, R1, ShifterOperand(0x550055));
   __ orr(R0, R1, ShifterOperand(0x550055));
+  __ orn(R0, R1, ShifterOperand(0x550055));
   __ eor(R0, R1, ShifterOperand(0x550055));
   __ bic(R0, R1, ShifterOperand(0x550055));
   __ adc(R0, R1, ShifterOperand(0x550055));
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index 82ad642..b79c2e4 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -23,109 +23,110 @@
   "   8:	eba1 0002 	sub.w	r0, r1, r2\n",
   "   c:	ea01 0002 	and.w	r0, r1, r2\n",
   "  10:	ea41 0002 	orr.w	r0, r1, r2\n",
-  "  14:	ea81 0002 	eor.w	r0, r1, r2\n",
-  "  18:	ea21 0002 	bic.w	r0, r1, r2\n",
-  "  1c:	eb41 0002 	adc.w	r0, r1, r2\n",
-  "  20:	eb61 0002 	sbc.w	r0, r1, r2\n",
-  "  24:	ebc1 0002 	rsb	r0, r1, r2\n",
-  "  28:	ea90 0f01 	teq	r0, r1\n",
-  "  2c:	0008      	movs	r0, r1\n",
-  "  2e:	4608      	mov	r0, r1\n",
-  "  30:	43c8      	mvns	r0, r1\n",
-  "  32:	4408      	add	r0, r1\n",
-  "  34:	1888      	adds	r0, r1, r2\n",
-  "  36:	1a88      	subs	r0, r1, r2\n",
-  "  38:	4148      	adcs	r0, r1\n",
-  "  3a:	4188      	sbcs	r0, r1\n",
-  "  3c:	4008      	ands	r0, r1\n",
-  "  3e:	4308      	orrs	r0, r1\n",
-  "  40:	4048      	eors	r0, r1\n",
-  "  42:	4388      	bics	r0, r1\n",
-  "  44:	4208      	tst	r0, r1\n",
-  "  46:	4288      	cmp	r0, r1\n",
-  "  48:	42c8      	cmn	r0, r1\n",
-  "  4a:	4641		mov	r1, r8\n",
-  "  4c:	4681		mov	r9, r0\n",
-  "  4e:	46c8		mov	r8, r9\n",
-  "  50:	4441		add	r1, r8\n",
-  "  52:	4481		add	r9, r0\n",
-  "  54:	44c8		add	r8, r9\n",
-  "  56:	4548		cmp	r0, r9\n",
-  "  58:	4588		cmp	r8, r1\n",
-  "  5a:	45c1		cmp	r9, r8\n",
-  "  5c:	4248   	   	negs	r0, r1\n",
-  "  5e:	4240   	   	negs	r0, r0\n",
-  "  60:	ea5f 0008  	movs.w	r0, r8\n",
-  "  64:	ea7f 0008  	mvns.w	r0, r8\n",
-  "  68:	eb01 0008 	add.w	r0, r1, r8\n",
-  "  6c:	eb11 0008 	adds.w	r0, r1, r8\n",
-  "  70:	ebb1 0008 	subs.w	r0, r1, r8\n",
-  "  74:	eb50 0008 	adcs.w	r0, r0, r8\n",
-  "  78:	eb70 0008 	sbcs.w	r0, r0, r8\n",
-  "  7c:	ea10 0008 	ands.w	r0, r0, r8\n",
-  "  80:	ea50 0008 	orrs.w	r0, r0, r8\n",
-  "  84:	ea90 0008 	eors.w	r0, r0, r8\n",
-  "  88:	ea30 0008 	bics.w	r0, r0, r8\n",
-  "  8c:	ea10 0f08 	tst.w	r0, r8\n",
-  "  90:	eb10 0f08 	cmn.w	r0, r8\n",
-  "  94:	f1d8 0000 	rsbs	r0, r8, #0\n",
-  "  98:	f1d8 0800 	rsbs	r8, r8, #0\n",
-  "  9c:	bf08       	it	eq\n",
-  "  9e:	ea7f 0001  	mvnseq.w	r0, r1\n",
-  "  a2:	bf08       	it	eq\n",
-  "  a4:	eb11 0002 	addseq.w	r0, r1, r2\n",
-  "  a8:	bf08       	it	eq\n",
-  "  aa:	ebb1 0002 	subseq.w	r0, r1, r2\n",
-  "  ae:	bf08       	it	eq\n",
-  "  b0:	eb50 0001 	adcseq.w	r0, r0, r1\n",
-  "  b4:	bf08       	it	eq\n",
-  "  b6:	eb70 0001 	sbcseq.w	r0, r0, r1\n",
-  "  ba:	bf08       	it	eq\n",
-  "  bc:	ea10 0001 	andseq.w	r0, r0, r1\n",
-  "  c0:	bf08       	it	eq\n",
-  "  c2:	ea50 0001 	orrseq.w	r0, r0, r1\n",
-  "  c6:	bf08       	it	eq\n",
-  "  c8:	ea90 0001 	eorseq.w	r0, r0, r1\n",
-  "  cc:	bf08       	it	eq\n",
-  "  ce:	ea30 0001 	bicseq.w	r0, r0, r1\n",
-  "  d2:	bf08       	it	eq\n",
-  "  d4:	43c8      	mvneq	r0, r1\n",
+  "  14:	ea61 0002 	orn	r0, r1, r2\n",
+  "  18:	ea81 0002 	eor.w	r0, r1, r2\n",
+  "  1c:	ea21 0002 	bic.w	r0, r1, r2\n",
+  "  20:	eb41 0002 	adc.w	r0, r1, r2\n",
+  "  24:	eb61 0002 	sbc.w	r0, r1, r2\n",
+  "  28:	ebc1 0002 	rsb	r0, r1, r2\n",
+  "  2c:	ea90 0f01 	teq	r0, r1\n",
+  "  30:	0008      	movs	r0, r1\n",
+  "  32:	4608      	mov	r0, r1\n",
+  "  34:	43c8      	mvns	r0, r1\n",
+  "  36:	4408      	add	r0, r1\n",
+  "  38:	1888      	adds	r0, r1, r2\n",
+  "  3a:	1a88      	subs	r0, r1, r2\n",
+  "  3c:	4148      	adcs	r0, r1\n",
+  "  3e:	4188      	sbcs	r0, r1\n",
+  "  40:	4008      	ands	r0, r1\n",
+  "  42:	4308      	orrs	r0, r1\n",
+  "  44:	4048      	eors	r0, r1\n",
+  "  46:	4388      	bics	r0, r1\n",
+  "  48:	4208      	tst	r0, r1\n",
+  "  4a:	4288      	cmp	r0, r1\n",
+  "  4c:	42c8      	cmn	r0, r1\n",
+  "  4e:	4641		mov	r1, r8\n",
+  "  50:	4681		mov	r9, r0\n",
+  "  52:	46c8		mov	r8, r9\n",
+  "  54:	4441		add	r1, r8\n",
+  "  56:	4481		add	r9, r0\n",
+  "  58:	44c8		add	r8, r9\n",
+  "  5a:	4548		cmp	r0, r9\n",
+  "  5c:	4588		cmp	r8, r1\n",
+  "  5e:	45c1		cmp	r9, r8\n",
+  "  60:	4248   	   	negs	r0, r1\n",
+  "  62:	4240   	   	negs	r0, r0\n",
+  "  64:	ea5f 0008  	movs.w	r0, r8\n",
+  "  68:	ea7f 0008  	mvns.w	r0, r8\n",
+  "  6c:	eb01 0008 	add.w	r0, r1, r8\n",
+  "  70:	eb11 0008 	adds.w	r0, r1, r8\n",
+  "  74:	ebb1 0008 	subs.w	r0, r1, r8\n",
+  "  78:	eb50 0008 	adcs.w	r0, r0, r8\n",
+  "  7c:	eb70 0008 	sbcs.w	r0, r0, r8\n",
+  "  80:	ea10 0008 	ands.w	r0, r0, r8\n",
+  "  84:	ea50 0008 	orrs.w	r0, r0, r8\n",
+  "  88:	ea90 0008 	eors.w	r0, r0, r8\n",
+  "  8c:	ea30 0008 	bics.w	r0, r0, r8\n",
+  "  90:	ea10 0f08 	tst.w	r0, r8\n",
+  "  94:	eb10 0f08 	cmn.w	r0, r8\n",
+  "  98:	f1d8 0000 	rsbs	r0, r8, #0\n",
+  "  9c:	f1d8 0800 	rsbs	r8, r8, #0\n",
+  "  a0:	bf08       	it	eq\n",
+  "  a2:	ea7f 0001  	mvnseq.w	r0, r1\n",
+  "  a6:	bf08       	it	eq\n",
+  "  a8:	eb11 0002 	addseq.w	r0, r1, r2\n",
+  "  ac:	bf08       	it	eq\n",
+  "  ae:	ebb1 0002 	subseq.w	r0, r1, r2\n",
+  "  b2:	bf08       	it	eq\n",
+  "  b4:	eb50 0001 	adcseq.w	r0, r0, r1\n",
+  "  b8:	bf08       	it	eq\n",
+  "  ba:	eb70 0001 	sbcseq.w	r0, r0, r1\n",
+  "  be:	bf08       	it	eq\n",
+  "  c0:	ea10 0001 	andseq.w	r0, r0, r1\n",
+  "  c4:	bf08       	it	eq\n",
+  "  c6:	ea50 0001 	orrseq.w	r0, r0, r1\n",
+  "  ca:	bf08       	it	eq\n",
+  "  cc:	ea90 0001 	eorseq.w	r0, r0, r1\n",
+  "  d0:	bf08       	it	eq\n",
+  "  d2:	ea30 0001 	bicseq.w	r0, r0, r1\n",
   "  d6:	bf08       	it	eq\n",
-  "  d8:	1888      	addeq	r0, r1, r2\n",
+  "  d8:	43c8      	mvneq	r0, r1\n",
   "  da:	bf08       	it	eq\n",
-  "  dc:	1a88      	subeq	r0, r1, r2\n",
+  "  dc:	1888      	addeq	r0, r1, r2\n",
   "  de:	bf08       	it	eq\n",
-  "  e0:	4148      	adceq	r0, r1\n",
+  "  e0:	1a88      	subeq	r0, r1, r2\n",
   "  e2:	bf08       	it	eq\n",
-  "  e4:	4188      	sbceq	r0, r1\n",
+  "  e4:	4148      	adceq	r0, r1\n",
   "  e6:	bf08       	it	eq\n",
-  "  e8:	4008      	andeq	r0, r1\n",
+  "  e8:	4188      	sbceq	r0, r1\n",
   "  ea:	bf08       	it	eq\n",
-  "  ec:	4308      	orreq	r0, r1\n",
+  "  ec:	4008      	andeq	r0, r1\n",
   "  ee:	bf08       	it	eq\n",
-  "  f0:	4048      	eoreq	r0, r1\n",
+  "  f0:	4308      	orreq	r0, r1\n",
   "  f2:	bf08       	it	eq\n",
-  "  f4:	4388      	biceq	r0, r1\n",
-  "  f6:	4608      	mov	r0, r1\n",
-  "  f8:	43c8      	mvns	r0, r1\n",
-  "  fa:	4408      	add	r0, r1\n",
-  "  fc:	1888      	adds	r0, r1, r2\n",
-  "  fe:	1a88      	subs	r0, r1, r2\n",
-  " 100:	4148      	adcs	r0, r1\n",
-  " 102:	4188      	sbcs	r0, r1\n",
-  " 104:	4008      	ands	r0, r1\n",
-  " 106:	4308      	orrs	r0, r1\n",
-  " 108:	4048      	eors	r0, r1\n",
-  " 10a:	4388      	bics	r0, r1\n",
-  " 10c:	4641		mov	r1, r8\n",
-  " 10e:	4681		mov	r9, r0\n",
-  " 110:	46c8		mov	r8, r9\n",
-  " 112:	4441		add	r1, r8\n",
-  " 114:	4481		add	r9, r0\n",
-  " 116:	44c8		add	r8, r9\n",
-  " 118:	4248   	   	negs	r0, r1\n",
-  " 11a:	4240   	   	negs	r0, r0\n",
-  " 11c:	eb01 0c00 	add.w	ip, r1, r0\n",
+  "  f4:	4048      	eoreq	r0, r1\n",
+  "  f6:	bf08       	it	eq\n",
+  "  f8:	4388      	biceq	r0, r1\n",
+  "  fa:	4608      	mov	r0, r1\n",
+  "  fc:	43c8      	mvns	r0, r1\n",
+  "  fe:	4408      	add	r0, r1\n",
+  " 100:	1888      	adds	r0, r1, r2\n",
+  " 102:	1a88      	subs	r0, r1, r2\n",
+  " 104:	4148      	adcs	r0, r1\n",
+  " 106:	4188      	sbcs	r0, r1\n",
+  " 108:	4008      	ands	r0, r1\n",
+  " 10a:	4308      	orrs	r0, r1\n",
+  " 10c:	4048      	eors	r0, r1\n",
+  " 10e:	4388      	bics	r0, r1\n",
+  " 110:	4641		mov	r1, r8\n",
+  " 112:	4681		mov	r9, r0\n",
+  " 114:	46c8		mov	r8, r9\n",
+  " 116:	4441		add	r1, r8\n",
+  " 118:	4481		add	r9, r0\n",
+  " 11a:	44c8		add	r8, r9\n",
+  " 11c:	4248   	   	negs	r0, r1\n",
+  " 11e:	4240   	   	negs	r0, r0\n",
+  " 120:	eb01 0c00 	add.w	ip, r1, r0\n",
   nullptr
 };
 const char* DataProcessingImmediateResults[] = {
@@ -135,21 +136,22 @@
   "   a:	f2a1 0055 	subw	r0, r1, #85	; 0x55\n",
   "   e:	f001 0055 	and.w	r0, r1, #85	; 0x55\n",
   "  12:	f041 0055 	orr.w	r0, r1, #85	; 0x55\n",
-  "  16:	f081 0055 	eor.w	r0, r1, #85	; 0x55\n",
-  "  1a:	f021 0055 	bic.w	r0, r1, #85	; 0x55\n",
-  "  1e:	f141 0055 	adc.w	r0, r1, #85	; 0x55\n",
-  "  22:	f161 0055 	sbc.w	r0, r1, #85	; 0x55\n",
-  "  26:	f1c1 0055 	rsb	r0, r1, #85	; 0x55\n",
-  "  2a:	f010 0f55 	tst.w	r0, #85	; 0x55\n",
-  "  2e:	f090 0f55 	teq	r0, #85	; 0x55\n",
-  "  32:	2855      	cmp	r0, #85	; 0x55\n",
-  "  34:	f110 0f55 	cmn.w	r0, #85	; 0x55\n",
-  "  38:	1d48      	adds	r0, r1, #5\n",
-  "  3a:	1f48      	subs	r0, r1, #5\n",
-  "  3c:	2055      	movs	r0, #85	; 0x55\n",
-  "  3e:	f07f 0055 	mvns.w	r0, #85	; 0x55\n",
-  "  42:	1d48      	adds  r0, r1, #5\n",
-  "  44:	1f48      	subs  r0, r1, #5\n",
+  "  16:	f061 0055 	orn	r0, r1, #85	; 0x55\n",
+  "  1a:	f081 0055 	eor.w	r0, r1, #85	; 0x55\n",
+  "  1e:	f021 0055 	bic.w	r0, r1, #85	; 0x55\n",
+  "  22:	f141 0055 	adc.w	r0, r1, #85	; 0x55\n",
+  "  26:	f161 0055 	sbc.w	r0, r1, #85	; 0x55\n",
+  "  2a:	f1c1 0055 	rsb	r0, r1, #85	; 0x55\n",
+  "  2e:	f010 0f55 	tst.w	r0, #85	; 0x55\n",
+  "  32:	f090 0f55 	teq	r0, #85	; 0x55\n",
+  "  36:	2855      	cmp	r0, #85	; 0x55\n",
+  "  38:	f110 0f55 	cmn.w	r0, #85	; 0x55\n",
+  "  3c:	1d48      	adds	r0, r1, #5\n",
+  "  3e:	1f48      	subs	r0, r1, #5\n",
+  "  40:	2055      	movs	r0, #85	; 0x55\n",
+  "  42:	f07f 0055 	mvns.w	r0, #85	; 0x55\n",
+  "  46:	1d48      	adds	r0, r1, #5\n",
+  "  48:	1f48      	subs	r0, r1, #5\n",
   nullptr
 };
 const char* DataProcessingModifiedImmediateResults[] = {
@@ -159,15 +161,16 @@
   "   c:	f1a1 1055 	sub.w	r0, r1, #5570645	; 0x550055\n",
   "  10:	f001 1055 	and.w	r0, r1, #5570645	; 0x550055\n",
   "  14:	f041 1055 	orr.w	r0, r1, #5570645	; 0x550055\n",
-  "  18:	f081 1055 	eor.w	r0, r1, #5570645	; 0x550055\n",
-  "  1c:	f021 1055 	bic.w	r0, r1, #5570645	; 0x550055\n",
-  "  20:	f141 1055 	adc.w	r0, r1, #5570645	; 0x550055\n",
-  "  24:	f161 1055 	sbc.w	r0, r1, #5570645	; 0x550055\n",
-  "  28:	f1c1 1055 	rsb	r0, r1, #5570645	; 0x550055\n",
-  "  2c:	f010 1f55 	tst.w	r0, #5570645	; 0x550055\n",
-  "  30:	f090 1f55 	teq	r0, #5570645	; 0x550055\n",
-  "  34:	f1b0 1f55 	cmp.w	r0, #5570645	; 0x550055\n",
-  "  38:	f110 1f55 	cmn.w	r0, #5570645	; 0x550055\n",
+  "  18:	f061 1055 	orn	r0, r1, #5570645	; 0x550055\n",
+  "  1c:	f081 1055 	eor.w	r0, r1, #5570645	; 0x550055\n",
+  "  20:	f021 1055 	bic.w	r0, r1, #5570645	; 0x550055\n",
+  "  24:	f141 1055 	adc.w	r0, r1, #5570645	; 0x550055\n",
+  "  28:	f161 1055 	sbc.w	r0, r1, #5570645	; 0x550055\n",
+  "  2c:	f1c1 1055 	rsb	r0, r1, #5570645	; 0x550055\n",
+  "  30:	f010 1f55 	tst.w	r0, #5570645	; 0x550055\n",
+  "  34:	f090 1f55 	teq	r0, #5570645	; 0x550055\n",
+  "  38:	f1b0 1f55 	cmp.w	r0, #5570645	; 0x550055\n",
+  "  3c:	f110 1f55 	cmn.w	r0, #5570645	; 0x550055\n",
   nullptr
 };
 const char* DataProcessingModifiedImmediatesResults[] = {
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 04e815a..5347bf0 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -2369,44 +2369,48 @@
   }
 }
 
-int ConstantArea::AddInt32(int32_t v) {
-  for (size_t i = 0, e = buffer_.size(); i < e; i++) {
-    if (v == buffer_[i]) {
-      return i * kEntrySize;
-    }
-  }
-
-  // Didn't match anything.
-  int result = buffer_.size() * kEntrySize;
+size_t ConstantArea::AppendInt32(int32_t v) {
+  size_t result = buffer_.size() * elem_size_;
   buffer_.push_back(v);
   return result;
 }
 
-int ConstantArea::AddInt64(int64_t v) {
+size_t ConstantArea::AddInt32(int32_t v) {
+  for (size_t i = 0, e = buffer_.size(); i < e; i++) {
+    if (v == buffer_[i]) {
+      return i * elem_size_;
+    }
+  }
+
+  // Didn't match anything.
+  return AppendInt32(v);
+}
+
+size_t ConstantArea::AddInt64(int64_t v) {
   int32_t v_low = Low32Bits(v);
   int32_t v_high = High32Bits(v);
   if (buffer_.size() > 1) {
     // Ensure we don't pass the end of the buffer.
     for (size_t i = 0, e = buffer_.size() - 1; i < e; i++) {
       if (v_low == buffer_[i] && v_high == buffer_[i + 1]) {
-        return i * kEntrySize;
+        return i * elem_size_;
       }
     }
   }
 
   // Didn't match anything.
-  int result = buffer_.size() * kEntrySize;
+  size_t result = buffer_.size() * elem_size_;
   buffer_.push_back(v_low);
   buffer_.push_back(v_high);
   return result;
 }
 
-int ConstantArea::AddDouble(double v) {
+size_t ConstantArea::AddDouble(double v) {
   // Treat the value as a 64-bit integer value.
   return AddInt64(bit_cast<int64_t, double>(v));
 }
 
-int ConstantArea::AddFloat(float v) {
+size_t ConstantArea::AddFloat(float v) {
   // Treat the value as a 32-bit integer value.
   return AddInt32(bit_cast<int32_t, float>(v));
 }
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 93ecdf5..b50fda9 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -166,21 +166,6 @@
     Init(base_in, disp.Int32Value());
   }
 
-  void Init(Register base_in, int32_t disp) {
-    if (disp == 0 && base_in != EBP) {
-      SetModRM(0, base_in);
-      if (base_in == ESP) SetSIB(TIMES_1, ESP, base_in);
-    } else if (disp >= -128 && disp <= 127) {
-      SetModRM(1, base_in);
-      if (base_in == ESP) SetSIB(TIMES_1, ESP, base_in);
-      SetDisp8(disp);
-    } else {
-      SetModRM(2, base_in);
-      if (base_in == ESP) SetSIB(TIMES_1, ESP, base_in);
-      SetDisp32(disp);
-    }
-  }
-
   Address(Register index_in, ScaleFactor scale_in, int32_t disp) {
     CHECK_NE(index_in, ESP);  // Illegal addressing mode.
     SetModRM(0, ESP);
@@ -189,19 +174,15 @@
   }
 
   Address(Register base_in, Register index_in, ScaleFactor scale_in, int32_t disp) {
-    CHECK_NE(index_in, ESP);  // Illegal addressing mode.
-    if (disp == 0 && base_in != EBP) {
-      SetModRM(0, ESP);
-      SetSIB(scale_in, index_in, base_in);
-    } else if (disp >= -128 && disp <= 127) {
-      SetModRM(1, ESP);
-      SetSIB(scale_in, index_in, base_in);
-      SetDisp8(disp);
-    } else {
-      SetModRM(2, ESP);
-      SetSIB(scale_in, index_in, base_in);
-      SetDisp32(disp);
-    }
+    Init(base_in, index_in, scale_in, disp);
+  }
+
+  Address(Register base_in,
+          Register index_in,
+          ScaleFactor scale_in,
+          int32_t disp, AssemblerFixup *fixup) {
+    Init(base_in, index_in, scale_in, disp);
+    SetFixup(fixup);
   }
 
   static Address Absolute(uintptr_t addr) {
@@ -217,6 +198,37 @@
 
  private:
   Address() {}
+
+  void Init(Register base_in, int32_t disp) {
+    if (disp == 0 && base_in != EBP) {
+      SetModRM(0, base_in);
+      if (base_in == ESP) SetSIB(TIMES_1, ESP, base_in);
+    } else if (disp >= -128 && disp <= 127) {
+      SetModRM(1, base_in);
+      if (base_in == ESP) SetSIB(TIMES_1, ESP, base_in);
+      SetDisp8(disp);
+    } else {
+      SetModRM(2, base_in);
+      if (base_in == ESP) SetSIB(TIMES_1, ESP, base_in);
+      SetDisp32(disp);
+    }
+  }
+
+  void Init(Register base_in, Register index_in, ScaleFactor scale_in, int32_t disp) {
+    CHECK_NE(index_in, ESP);  // Illegal addressing mode.
+    if (disp == 0 && base_in != EBP) {
+      SetModRM(0, ESP);
+      SetSIB(scale_in, index_in, base_in);
+    } else if (disp >= -128 && disp <= 127) {
+      SetModRM(1, ESP);
+      SetSIB(scale_in, index_in, base_in);
+      SetDisp8(disp);
+    } else {
+      SetModRM(2, ESP);
+      SetSIB(scale_in, index_in, base_in);
+      SetDisp32(disp);
+    }
+  }
 };
 
 
@@ -252,40 +264,39 @@
 
   // Add a double to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddDouble(double v);
+  size_t AddDouble(double v);
 
   // Add a float to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddFloat(float v);
+  size_t AddFloat(float v);
 
   // Add an int32_t to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddInt32(int32_t v);
+  size_t AddInt32(int32_t v);
+
+  // Add an int32_t to the end of the constant area, returning the offset into
+  // the constant area where the literal resides.
+  size_t AppendInt32(int32_t v);
 
   // Add an int64_t to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddInt64(int64_t v);
+  size_t AddInt64(int64_t v);
 
   bool IsEmpty() const {
     return buffer_.size() == 0;
   }
 
+  size_t GetSize() const {
+    return buffer_.size() * elem_size_;
+  }
+
   const std::vector<int32_t>& GetBuffer() const {
     return buffer_;
   }
 
-  void AddFixup(AssemblerFixup* fixup) {
-    fixups_.push_back(fixup);
-  }
-
-  const std::vector<AssemblerFixup*>& GetFixups() const {
-    return fixups_;
-  }
-
  private:
-  static constexpr size_t kEntrySize = sizeof(int32_t);
+  static constexpr size_t elem_size_ = sizeof(int32_t);
   std::vector<int32_t> buffer_;
-  std::vector<AssemblerFixup*> fixups_;
 };
 
 class X86Assembler FINAL : public Assembler {
@@ -740,26 +751,36 @@
 
   // Add a double to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddDouble(double v) { return constant_area_.AddDouble(v); }
+  size_t AddDouble(double v) { return constant_area_.AddDouble(v); }
 
   // Add a float to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddFloat(float v)   { return constant_area_.AddFloat(v); }
+  size_t AddFloat(float v)   { return constant_area_.AddFloat(v); }
 
   // Add an int32_t to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddInt32(int32_t v) { return constant_area_.AddInt32(v); }
+  size_t AddInt32(int32_t v) {
+    return constant_area_.AddInt32(v);
+  }
+
+  // Add an int32_t to the end of the constant area, returning the offset into
+  // the constant area where the literal resides.
+  size_t AppendInt32(int32_t v) {
+    return constant_area_.AppendInt32(v);
+  }
 
   // Add an int64_t to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddInt64(int64_t v) { return constant_area_.AddInt64(v); }
+  size_t AddInt64(int64_t v) { return constant_area_.AddInt64(v); }
 
   // Add the contents of the constant area to the assembler buffer.
   void AddConstantArea();
 
   // Is the constant area empty? Return true if there are no literals in the constant area.
   bool IsConstantAreaEmpty() const { return constant_area_.IsEmpty(); }
-  void AddConstantAreaFixup(AssemblerFixup* fixup) { constant_area_.AddFixup(fixup); }
+
+  // Return the current size of the constant area.
+  size_t ConstantAreaSize() const { return constant_area_.GetSize(); }
 
  private:
   inline void EmitUint8(uint8_t value);
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 6e7d74d..9eb5e67 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -3122,7 +3122,14 @@
   }
 }
 
-int ConstantArea::AddInt32(int32_t v) {
+size_t ConstantArea::AppendInt32(int32_t v) {
+  size_t result = buffer_.size() * elem_size_;
+  buffer_.push_back(v);
+  return result;
+}
+
+size_t ConstantArea::AddInt32(int32_t v) {
+  // Look for an existing match.
   for (size_t i = 0, e = buffer_.size(); i < e; i++) {
     if (v == buffer_[i]) {
       return i * elem_size_;
@@ -3130,12 +3137,10 @@
   }
 
   // Didn't match anything.
-  int result = buffer_.size() * elem_size_;
-  buffer_.push_back(v);
-  return result;
+  return AppendInt32(v);
 }
 
-int ConstantArea::AddInt64(int64_t v) {
+size_t ConstantArea::AddInt64(int64_t v) {
   int32_t v_low = v;
   int32_t v_high = v >> 32;
   if (buffer_.size() > 1) {
@@ -3148,18 +3153,18 @@
   }
 
   // Didn't match anything.
-  int result = buffer_.size() * elem_size_;
+  size_t result = buffer_.size() * elem_size_;
   buffer_.push_back(v_low);
   buffer_.push_back(v_high);
   return result;
 }
 
-int ConstantArea::AddDouble(double v) {
+size_t ConstantArea::AddDouble(double v) {
   // Treat the value as a 64-bit integer value.
   return AddInt64(bit_cast<int64_t, double>(v));
 }
 
-int ConstantArea::AddFloat(float v) {
+size_t ConstantArea::AddFloat(float v) {
   // Treat the value as a 32-bit integer value.
   return AddInt32(bit_cast<int32_t, float>(v));
 }
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 255f551..01d28e3 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -269,36 +269,40 @@
  * Class to handle constant area values.
  */
 class ConstantArea {
-  public:
-    ConstantArea() {}
+ public:
+  ConstantArea() {}
 
-    // Add a double to the constant area, returning the offset into
-    // the constant area where the literal resides.
-    int AddDouble(double v);
+  // Add a double to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  size_t AddDouble(double v);
 
-    // Add a float to the constant area, returning the offset into
-    // the constant area where the literal resides.
-    int AddFloat(float v);
+  // Add a float to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  size_t AddFloat(float v);
 
-    // Add an int32_t to the constant area, returning the offset into
-    // the constant area where the literal resides.
-    int AddInt32(int32_t v);
+  // Add an int32_t to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  size_t AddInt32(int32_t v);
 
-    // Add an int64_t to the constant area, returning the offset into
-    // the constant area where the literal resides.
-    int AddInt64(int64_t v);
+  // Add an int32_t to the end of the constant area, returning the offset into
+  // the constant area where the literal resides.
+  size_t AppendInt32(int32_t v);
 
-    int GetSize() const {
-      return buffer_.size() * elem_size_;
-    }
+  // Add an int64_t to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  size_t AddInt64(int64_t v);
 
-    const std::vector<int32_t>& GetBuffer() const {
-      return buffer_;
-    }
+  size_t GetSize() const {
+    return buffer_.size() * elem_size_;
+  }
 
-  private:
-    static constexpr size_t elem_size_ = sizeof(int32_t);
-    std::vector<int32_t> buffer_;
+  const std::vector<int32_t>& GetBuffer() const {
+    return buffer_;
+  }
+
+ private:
+  static constexpr size_t elem_size_ = sizeof(int32_t);
+  std::vector<int32_t> buffer_;
 };
 
 
@@ -806,19 +810,27 @@
 
   // Add a double to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddDouble(double v) { return constant_area_.AddDouble(v); }
+  size_t AddDouble(double v) { return constant_area_.AddDouble(v); }
 
   // Add a float to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddFloat(float v)   { return constant_area_.AddFloat(v); }
+  size_t AddFloat(float v)   { return constant_area_.AddFloat(v); }
 
   // Add an int32_t to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddInt32(int32_t v) { return constant_area_.AddInt32(v); }
+  size_t AddInt32(int32_t v) {
+    return constant_area_.AddInt32(v);
+  }
+
+  // Add an int32_t to the end of the constant area, returning the offset into
+  // the constant area where the literal resides.
+  size_t AppendInt32(int32_t v) {
+    return constant_area_.AppendInt32(v);
+  }
 
   // Add an int64_t to the constant area, returning the offset into
   // the constant area where the literal resides.
-  int AddInt64(int64_t v) { return constant_area_.AddInt64(v); }
+  size_t AddInt64(int64_t v) { return constant_area_.AddInt64(v); }
 
   // Add the contents of the constant area to the assembler buffer.
   void AddConstantArea();
@@ -826,6 +838,9 @@
   // Is the constant area empty? Return true if there are no literals in the constant area.
   bool IsConstantAreaEmpty() const { return constant_area_.GetSize() == 0; }
 
+  // Return the current size of the constant area.
+  size_t ConstantAreaSize() const { return constant_area_.GetSize(); }
+
   //
   // Heap poisoning.
   //
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index d09631b..930bb2c 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -891,7 +891,109 @@
 ONE_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
 
 // Generate the allocation entrypoints for each allocator.
-GENERATE_ALL_ALLOC_ENTRYPOINTS
+GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
+ENTRY art_quick_alloc_object_rosalloc
+    // Fast path rosalloc allocation.
+    // r0: type_idx/return value, r1: ArtMethod*, r9: Thread::Current
+    // r2, r3, r12: free.
+    ldr    r2, [r1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_32]    // Load dex cache resolved types array
+                                                              // Load the class (r2)
+    ldr    r2, [r2, r0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
+    cbz    r2, .Lart_quick_alloc_object_rosalloc_slow_path    // Check null class
+                                                              // Check class status.
+    ldr    r3, [r2, #MIRROR_CLASS_STATUS_OFFSET]
+    cmp    r3, #MIRROR_CLASS_STATUS_INITIALIZED
+    bne    .Lart_quick_alloc_object_rosalloc_slow_path
+                                                              // Add a fake dependence from the
+                                                              // following access flag and size
+                                                              // loads to the status load.
+                                                              // This is to prevent those loads
+                                                              // from being reordered above the
+                                                              // status load and reading wrong
+                                                              // values (an alternative is to use
+                                                              // a load-acquire for the status).
+    eor    r3, r3, r3
+    add    r2, r2, r3
+                                                              // Check access flags has
+                                                              // kAccClassIsFinalizable
+    ldr    r3, [r2, #MIRROR_CLASS_ACCESS_FLAGS_OFFSET]
+    tst    r3, #ACCESS_FLAGS_CLASS_IS_FINALIZABLE
+    bne    .Lart_quick_alloc_object_rosalloc_slow_path
+
+    ldr    r3, [r9, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET]     // Check if the thread local
+                                                              // allocation stack has room.
+                                                              // TODO: consider using ldrd.
+    ldr    r12, [r9, #THREAD_LOCAL_ALLOC_STACK_END_OFFSET]
+    cmp    r3, r12
+    bhs    .Lart_quick_alloc_object_rosalloc_slow_path
+
+    ldr    r3, [r2, #MIRROR_CLASS_OBJECT_SIZE_OFFSET]         // Load the object size (r3)
+    cmp    r3, #ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE        // Check if the size is for a thread
+                                                              // local allocation
+    bhs    .Lart_quick_alloc_object_rosalloc_slow_path
+                                                              // Compute the rosalloc bracket index
+                                                              // from the size.
+                                                              // Align up the size by the rosalloc
+                                                              // bracket quantum size and divide
+                                                              // by the quantum size and subtract
+                                                              // by 1. This code is a shorter but
+                                                              // equivalent version.
+    sub    r3, r3, #1
+    lsr    r3, r3, #ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT
+                                                              // Load the rosalloc run (r12)
+    add    r12, r9, r3, lsl #POINTER_SIZE_SHIFT
+    ldr    r12, [r12, #THREAD_ROSALLOC_RUNS_OFFSET]
+                                                              // Load the free list head (r3). This
+                                                              // will be the return val.
+    ldr    r3, [r12, #(ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)]
+    cbz    r3, .Lart_quick_alloc_object_rosalloc_slow_path
+    // "Point of no slow path". Won't go to the slow path from here on. OK to clobber r0 and r1.
+    ldr    r1, [r3, #ROSALLOC_SLOT_NEXT_OFFSET]               // Load the next pointer of the head
+                                                              // and update the list head with the
+                                                              // next pointer.
+    str    r1, [r12, #(ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)]
+                                                              // Store the class pointer in the
+                                                              // header. This also overwrites the
+                                                              // next pointer. The offsets are
+                                                              // asserted to match.
+#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
+#error "Class pointer needs to overwrite next pointer."
+#endif
+    str    r2, [r3, #MIRROR_OBJECT_CLASS_OFFSET]
+                                                              // Push the new object onto the thread
+                                                              // local allocation stack and
+                                                              // increment the thread local
+                                                              // allocation stack top.
+    ldr    r1, [r9, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET]
+    str    r3, [r1], #COMPRESSED_REFERENCE_SIZE               // (Increment r1 as a side effect.)
+    str    r1, [r9, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET]
+                                                              // Decrement the size of the free list
+    ldr    r1, [r12, #(ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)]
+    sub    r1, #1
+                                                              // TODO: consider combining this store
+                                                              // and the list head store above using
+                                                              // strd.
+    str    r1, [r12, #(ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)]
+                                                              // Fence. This is "ish" not "ishst" so
+                                                              // that the code after this allocation
+                                                              // site will see the right values in
+                                                              // the fields of the class.
+                                                              // Alternatively we could use "ishst"
+                                                              // if we use load-acquire for the
+                                                              // class status load.)
+    dmb    ish
+    mov    r0, r3                                             // Set the return value and return.
+    bx     lr
+
+.Lart_quick_alloc_object_rosalloc_slow_path:
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r2, r3  @ save callee saves in case of GC
+    mov    r2, r9                     @ pass Thread::Current
+    bl     artAllocObjectFromCodeRosAlloc     @ (uint32_t type_idx, Method* method, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+    RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+END art_quick_alloc_object_rosalloc
 
     /*
      * Called by managed code when the value in rSUSPEND has been decremented to 0.
diff --git a/runtime/arch/quick_alloc_entrypoints.S b/runtime/arch/quick_alloc_entrypoints.S
index ef5edbb..fbacdbc 100644
--- a/runtime/arch/quick_alloc_entrypoints.S
+++ b/runtime/arch/quick_alloc_entrypoints.S
@@ -113,7 +113,8 @@
 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_dlmalloc_instrumented, DlMallocInstrumented)
 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_dlmalloc_instrumented, DlMallocInstrumented)
 
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc)
+// This is to be separately defined for each architecture to allow a hand-written assembly fast path.
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc)
 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc)
 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc, RosAlloc)
 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_rosalloc, RosAlloc)
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 4a106e4..2f485ae 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -788,6 +788,7 @@
 
 // Generate the allocation entrypoints for each allocator.
 GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc)
 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
 
 ONE_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 5c413d2..95f0ccb 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -809,6 +809,7 @@
 
 // Generate the allocation entrypoints for each allocator.
 GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc)
 // A handle-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB).
 DEFINE_FUNCTION art_quick_alloc_object_tlab
     // Fast path tlab allocation.
diff --git a/runtime/art_code.cc b/runtime/art_code.cc
index b999ec8..ad0b170 100644
--- a/runtime/art_code.cc
+++ b/runtime/art_code.cc
@@ -286,8 +286,10 @@
     return;
   }
 
-  uint32_t code_size = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_;
-  CHECK(PcIsWithinQuickCode(pc))
+  uint32_t code_size = reinterpret_cast<const OatQuickMethodHeader*>(
+      EntryPointToCodePointer(code))[-1].code_size_;
+  uintptr_t code_start = reinterpret_cast<uintptr_t>(code);
+  CHECK(code_start <= pc && pc <= (code_start + code_size))
       << PrettyMethod(method_)
       << " pc=" << std::hex << pc
       << " code=" << code
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index c415073..f741732 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -219,8 +219,9 @@
     case kDirect:
       return !IsDirect() || IsStatic();
     case kVirtual: {
+      // We have an error if we are direct or a non-default, non-miranda interface method.
       mirror::Class* methods_class = GetDeclaringClass();
-      return IsDirect() || (methods_class->IsInterface() && !IsMiranda());
+      return IsDirect() || (methods_class->IsInterface() && !IsDefault() && !IsMiranda());
     }
     case kSuper:
       // Constructors and static methods are called with invoke-direct.
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 3c58644..9743250 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -135,6 +135,11 @@
     return (GetAccessFlags() & kAccMiranda) != 0;
   }
 
+  // This is set by the class linker.
+  bool IsDefault() {
+    return (GetAccessFlags() & kAccDefault) != 0;
+  }
+
   bool IsNative() {
     return (GetAccessFlags() & kAccNative) != 0;
   }
@@ -163,6 +168,11 @@
     SetAccessFlags(GetAccessFlags() | kAccPreverified);
   }
 
+  // Returns true if this method could be overridden by a default method.
+  bool IsOverridableByDefaultMethod() {
+    return IsDefault() || IsAbstract();
+  }
+
   bool CheckIncompatibleClassChange(InvokeType type) SHARED_REQUIRES(Locks::mutator_lock_);
 
   uint16_t GetMethodIndex() SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index d98fc51..69f6fe9 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -19,6 +19,7 @@
 
 #if defined(__cplusplus)
 #include "art_method.h"
+#include "gc/allocator/rosalloc.h"
 #include "lock_word.h"
 #include "mirror/class.h"
 #include "mirror/string.h"
@@ -53,6 +54,14 @@
 #define ADD_TEST_EQ(x, y)
 #endif
 
+#if defined(__LP64__)
+#define POINTER_SIZE_SHIFT 3
+#else
+#define POINTER_SIZE_SHIFT 2
+#endif
+ADD_TEST_EQ(static_cast<size_t>(1U << POINTER_SIZE_SHIFT),
+            static_cast<size_t>(__SIZEOF_POINTER__))
+
 // Size of references to the heap on the stack.
 #define STACK_REFERENCE_SIZE 4
 ADD_TEST_EQ(static_cast<size_t>(STACK_REFERENCE_SIZE), sizeof(art::StackReference<art::mirror::Object>))
@@ -62,6 +71,10 @@
 ADD_TEST_EQ(static_cast<size_t>(COMPRESSED_REFERENCE_SIZE),
             sizeof(art::mirror::CompressedReference<art::mirror::Object>))
 
+#define COMPRESSED_REFERENCE_SIZE_SHIFT 2
+ADD_TEST_EQ(static_cast<size_t>(1U << COMPRESSED_REFERENCE_SIZE_SHIFT),
+            static_cast<size_t>(COMPRESSED_REFERENCE_SIZE))
+
 // Note: these callee save methods loads require read barriers.
 // Offset of field Runtime::callee_save_methods_[kSaveAll]
 #define RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET 0
@@ -120,6 +133,18 @@
 #define THREAD_LOCAL_OBJECTS_OFFSET (THREAD_LOCAL_POS_OFFSET + 2 * __SIZEOF_POINTER__)
 ADD_TEST_EQ(THREAD_LOCAL_OBJECTS_OFFSET,
             art::Thread::ThreadLocalObjectsOffset<__SIZEOF_POINTER__>().Int32Value())
+// Offset of field Thread::tlsPtr_.rosalloc_runs.
+#define THREAD_ROSALLOC_RUNS_OFFSET (THREAD_LOCAL_POS_OFFSET + 3 * __SIZEOF_POINTER__)
+ADD_TEST_EQ(THREAD_ROSALLOC_RUNS_OFFSET,
+            art::Thread::RosAllocRunsOffset<__SIZEOF_POINTER__>().Int32Value())
+// Offset of field Thread::tlsPtr_.thread_local_alloc_stack_top.
+#define THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET (THREAD_ROSALLOC_RUNS_OFFSET + 34 * __SIZEOF_POINTER__)
+ADD_TEST_EQ(THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET,
+            art::Thread::ThreadLocalAllocStackTopOffset<__SIZEOF_POINTER__>().Int32Value())
+// Offset of field Thread::tlsPtr_.thread_local_alloc_stack_end.
+#define THREAD_LOCAL_ALLOC_STACK_END_OFFSET (THREAD_ROSALLOC_RUNS_OFFSET + 35 * __SIZEOF_POINTER__)
+ADD_TEST_EQ(THREAD_LOCAL_ALLOC_STACK_END_OFFSET,
+            art::Thread::ThreadLocalAllocStackEndOffset<__SIZEOF_POINTER__>().Int32Value())
 
 // Offsets within java.lang.Object.
 #define MIRROR_OBJECT_CLASS_OFFSET 0
@@ -236,6 +261,44 @@
 ADD_TEST_EQ(static_cast<uint32_t>(OBJECT_ALIGNMENT_MASK_TOGGLED),
             ~static_cast<uint32_t>(art::kObjectAlignment - 1))
 
+#define ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE 128
+ADD_TEST_EQ(ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE,
+            static_cast<int32_t>(art::gc::allocator::RosAlloc::kMaxThreadLocalBracketSize))
+
+#define ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT 4
+ADD_TEST_EQ(ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT,
+            static_cast<int32_t>(art::gc::allocator::RosAlloc::kBracketQuantumSizeShift))
+
+#define ROSALLOC_BRACKET_QUANTUM_SIZE_MASK 15
+ADD_TEST_EQ(ROSALLOC_BRACKET_QUANTUM_SIZE_MASK,
+            static_cast<int32_t>(art::gc::allocator::RosAlloc::kBracketQuantumSize - 1))
+
+#define ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED32 0xfffffff0
+ADD_TEST_EQ(static_cast<uint32_t>(ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED32),
+            ~static_cast<uint32_t>(art::gc::allocator::RosAlloc::kBracketQuantumSize - 1))
+
+#define ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED64 0xfffffffffffffff0
+ADD_TEST_EQ(static_cast<uint64_t>(ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED64),
+            ~static_cast<uint64_t>(art::gc::allocator::RosAlloc::kBracketQuantumSize - 1))
+
+#define ROSALLOC_RUN_FREE_LIST_OFFSET 8
+ADD_TEST_EQ(ROSALLOC_RUN_FREE_LIST_OFFSET,
+            static_cast<int32_t>(art::gc::allocator::RosAlloc::RunFreeListOffset()))
+
+#define ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET 0
+ADD_TEST_EQ(ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET,
+            static_cast<int32_t>(art::gc::allocator::RosAlloc::RunFreeListHeadOffset()))
+
+#define ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET 16
+ADD_TEST_EQ(ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET,
+            static_cast<int32_t>(art::gc::allocator::RosAlloc::RunFreeListSizeOffset()))
+
+#define ROSALLOC_SLOT_NEXT_OFFSET 0
+ADD_TEST_EQ(ROSALLOC_SLOT_NEXT_OFFSET,
+            static_cast<int32_t>(art::gc::allocator::RosAlloc::RunSlotNextOffset()))
+// Assert this so that we can avoid zeroing the next field by installing the class pointer.
+ADD_TEST_EQ(ROSALLOC_SLOT_NEXT_OFFSET, MIRROR_OBJECT_CLASS_OFFSET)
+
 #if defined(__cplusplus)
 }  // End of CheckAsmSupportOffsets.
 #endif
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 30bfb4a..70bd398 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -51,6 +51,7 @@
 MutatorMutex* Locks::mutator_lock_ = nullptr;
 Mutex* Locks::profiler_lock_ = nullptr;
 ReaderWriterMutex* Locks::oat_file_manager_lock_ = nullptr;
+ReaderWriterMutex* Locks::oat_file_count_lock_ = nullptr;
 Mutex* Locks::reference_processor_lock_ = nullptr;
 Mutex* Locks::reference_queue_cleared_references_lock_ = nullptr;
 Mutex* Locks::reference_queue_finalizer_references_lock_ = nullptr;
@@ -942,6 +943,7 @@
     DCHECK(deoptimization_lock_ != nullptr);
     DCHECK(heap_bitmap_lock_ != nullptr);
     DCHECK(oat_file_manager_lock_ != nullptr);
+    DCHECK(oat_file_count_lock_ != nullptr);
     DCHECK(intern_table_lock_ != nullptr);
     DCHECK(jni_libraries_lock_ != nullptr);
     DCHECK(logging_lock_ != nullptr);
@@ -1034,6 +1036,10 @@
     DCHECK(oat_file_manager_lock_ == nullptr);
     oat_file_manager_lock_ = new ReaderWriterMutex("OatFile manager lock", current_lock_level);
 
+    UPDATE_CURRENT_LOCK_LEVEL(kOatFileCountLock);
+    DCHECK(oat_file_count_lock_ == nullptr);
+    oat_file_count_lock_ = new ReaderWriterMutex("OatFile count lock", current_lock_level);
+
     UPDATE_CURRENT_LOCK_LEVEL(kInternTableLock);
     DCHECK(intern_table_lock_ == nullptr);
     intern_table_lock_ = new Mutex("InternTable lock", current_lock_level);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 17f6a03..d4c9057 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -83,6 +83,7 @@
   kDexFileToMethodInlinerMapLock,
   kInternTableLock,
   kOatFileSecondaryLookupLock,
+  kOatFileCountLock,
   kOatFileManagerLock,
   kTracingUniqueMethodsLock,
   kTracingStreamingLock,
@@ -648,8 +649,11 @@
   // Guards opened oat files in OatFileManager.
   static ReaderWriterMutex* oat_file_manager_lock_ ACQUIRED_AFTER(modify_ldt_lock_);
 
+  // Guards opened oat files in OatFileManager.
+  static ReaderWriterMutex* oat_file_count_lock_ ACQUIRED_AFTER(oat_file_manager_lock_);
+
   // Guards intern table.
-  static Mutex* intern_table_lock_ ACQUIRED_AFTER(oat_file_manager_lock_);
+  static Mutex* intern_table_lock_ ACQUIRED_AFTER(oat_file_count_lock_);
 
   // Guards reference processor.
   static Mutex* reference_processor_lock_ ACQUIRED_AFTER(intern_table_lock_);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 9349fe3..b569f50 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -16,12 +16,15 @@
 
 #include "class_linker.h"
 
+#include <algorithm>
 #include <deque>
 #include <iostream>
 #include <memory>
 #include <queue>
 #include <string>
+#include <tuple>
 #include <unistd.h>
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -41,25 +44,20 @@
 #include "compiler_callbacks.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "entrypoints/entrypoint_utils.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc_root-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/accounting/heap_bitmap.h"
 #include "gc/heap.h"
 #include "gc/space/image_space.h"
-#include "handle_scope.h"
+#include "handle_scope-inl.h"
 #include "intern_table.h"
 #include "interpreter/interpreter.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
 #include "leb128.h"
 #include "linear_alloc.h"
-#include "oat.h"
-#include "oat_file.h"
-#include "oat_file-inl.h"
-#include "oat_file_assistant.h"
-#include "oat_file_manager.h"
-#include "object_lock.h"
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
@@ -73,12 +71,17 @@
 #include "mirror/reference-inl.h"
 #include "mirror/stack_trace_element.h"
 #include "mirror/string-inl.h"
+#include "native/dalvik_system_DexFile.h"
+#include "oat.h"
+#include "oat_file.h"
+#include "oat_file-inl.h"
+#include "oat_file_assistant.h"
+#include "oat_file_manager.h"
+#include "object_lock.h"
 #include "os.h"
 #include "runtime.h"
-#include "entrypoints/entrypoint_utils.h"
 #include "ScopedLocalRef.h"
 #include "scoped_thread_state_change.h"
-#include "handle_scope-inl.h"
 #include "thread-inl.h"
 #include "trace.h"
 #include "utils.h"
@@ -1429,13 +1432,18 @@
             break;
           }
           int32_t long_array_size = long_array->GetLength();
-          for (int32_t j = 0; j < long_array_size; ++j) {
+          // First element is the oat file.
+          for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) {
             const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(
                 long_array->GetWithoutChecks(j)));
             const DexFile::ClassDef* dex_class_def = cp_dex_file->FindClassDef(descriptor, hash);
             if (dex_class_def != nullptr) {
-              mirror::Class* klass = DefineClass(self, descriptor, hash, class_loader,
-                                                 *cp_dex_file, *dex_class_def);
+              mirror::Class* klass = DefineClass(self,
+                                                 descriptor,
+                                                 hash,
+                                                 class_loader,
+                                                 *cp_dex_file,
+                                                 *dex_class_def);
               if (klass == nullptr) {
                 CHECK(self->IsExceptionPending()) << descriptor;
                 self->ClearException();
@@ -3337,6 +3345,18 @@
         return false;
       }
     }
+    // If we are a class we need to initialize all interfaces with default methods when we are
+    // initialized. Check all of them.
+    if (!klass->IsInterface()) {
+      size_t num_interfaces = klass->GetIfTableCount();
+      for (size_t i = 0; i < num_interfaces; i++) {
+        mirror::Class* iface = klass->GetIfTable()->GetInterface(i);
+        if (iface->HasDefaultMethods() &&
+            !CanWeInitializeClass(iface, can_init_statics, can_init_parents)) {
+          return false;
+        }
+      }
+    }
   }
   if (klass->IsInterface() || !klass->HasSuperClass()) {
     return true;
@@ -3463,6 +3483,38 @@
     }
   }
 
+  if (!klass->IsInterface()) {
+    // Initialize interfaces with default methods for the JLS.
+    size_t num_direct_interfaces = klass->NumDirectInterfaces();
+    // Only setup the (expensive) handle scope if we actually need to.
+    if (UNLIKELY(num_direct_interfaces > 0)) {
+      StackHandleScope<1> hs_iface(self);
+      MutableHandle<mirror::Class> handle_scope_iface(hs_iface.NewHandle<mirror::Class>(nullptr));
+      for (size_t i = 0; i < num_direct_interfaces; i++) {
+        handle_scope_iface.Assign(mirror::Class::GetDirectInterface(self, klass, i));
+        CHECK(handle_scope_iface.Get() != nullptr);
+        CHECK(handle_scope_iface->IsInterface());
+        if (handle_scope_iface->HasBeenRecursivelyInitialized()) {
+          // We have already done this for this interface. Skip it.
+          continue;
+        }
+        // We cannot just call initialize class directly because we need to ensure that ALL
+        // interfaces with default methods are initialized. Non-default interface initialization
+        // will not affect other non-default super-interfaces.
+        bool iface_initialized = InitializeDefaultInterfaceRecursive(self,
+                                                                     handle_scope_iface,
+                                                                     can_init_statics,
+                                                                     can_init_parents);
+        if (!iface_initialized) {
+          ObjectLock<mirror::Class> lock(self, klass);
+          // Initialization failed because one of our interfaces with default methods is erroneous.
+          mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self);
+          return false;
+        }
+      }
+    }
+  }
+
   const size_t num_static_fields = klass->NumStaticFields();
   if (num_static_fields > 0) {
     const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
@@ -3552,6 +3604,52 @@
   return success;
 }
 
+// We recursively run down the tree of interfaces. We need to do this in the order they are declared
+// and perform the initialization only on those interfaces that contain default methods.
+bool ClassLinker::InitializeDefaultInterfaceRecursive(Thread* self,
+                                                      Handle<mirror::Class> iface,
+                                                      bool can_init_statics,
+                                                      bool can_init_parents) {
+  CHECK(iface->IsInterface());
+  size_t num_direct_ifaces = iface->NumDirectInterfaces();
+  // Only create the (expensive) handle scope if we need it.
+  if (UNLIKELY(num_direct_ifaces > 0)) {
+    StackHandleScope<1> hs(self);
+    MutableHandle<mirror::Class> handle_super_iface(hs.NewHandle<mirror::Class>(nullptr));
+    // First we initialize all of iface's super-interfaces recursively.
+    for (size_t i = 0; i < num_direct_ifaces; i++) {
+      mirror::Class* super_iface = mirror::Class::GetDirectInterface(self, iface, i);
+      if (!super_iface->HasBeenRecursivelyInitialized()) {
+        // Recursive step
+        handle_super_iface.Assign(super_iface);
+        if (!InitializeDefaultInterfaceRecursive(self,
+                                                 handle_super_iface,
+                                                 can_init_statics,
+                                                 can_init_parents)) {
+          return false;
+        }
+      }
+    }
+  }
+
+  bool result = true;
+  // Then we initialize 'iface' if it has default methods. We do not need to (and in fact must not)
+  // initialize if we don't have default methods.
+  if (iface->HasDefaultMethods()) {
+    result = EnsureInitialized(self, iface, can_init_statics, can_init_parents);
+  }
+
+  // Mark that this interface has undergone recursive default interface initialization so we know we
+  // can skip it on any later class initializations. We do this even if we are not a default
+  // interface since we can still avoid the traversal. This is purely a performance optimization.
+  if (result) {
+    // TODO This should be done in a better way
+    ObjectLock<mirror::Class> lock(self, iface);
+    iface->SetRecursivelyInitialized();
+  }
+  return result;
+}
+
 bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass,
                                          Thread* self,
                                          ObjectLock<mirror::Class>& lock)
@@ -4284,20 +4382,16 @@
                               Handle<mirror::ObjectArray<mirror::Class>> interfaces,
                               ArtMethod** out_imt) {
   self->AllowThreadSuspension();
-  if (klass->IsInterface()) {
-    // No vtable.
-    size_t count = klass->NumVirtualMethods();
-    if (!IsUint<16>(count)) {
-      ThrowClassFormatError(klass.Get(), "Too many methods on interface: %zd", count);
-      return false;
-    }
-    for (size_t i = 0; i < count; ++i) {
-      klass->GetVirtualMethodDuringLinking(i, image_pointer_size_)->SetMethodIndex(i);
-    }
-  } else if (!LinkVirtualMethods(self, klass)) {  // Link virtual methods first.
-    return false;
-  }
-  return LinkInterfaceMethods(self, klass, interfaces, out_imt);  // Link interface method last.
+  // A map from vtable indexes to the method they need to be updated to point to. Used because we
+  // need to have default methods be in the virtuals array of each class but we don't set that up
+  // until LinkInterfaceMethods.
+  std::unordered_map<size_t, ArtMethod*> default_translations;
+  // Link virtual methods then interface methods.
+  // We set up the interface lookup table first because we need it to determine if we need to update
+  // any vtable entries with new default method implementations.
+  return SetupInterfaceLookupTable(self, klass, interfaces)
+          && LinkVirtualMethods(self, klass, /*out*/ &default_translations)
+          && LinkInterfaceMethods(self, klass, default_translations, out_imt);
 }
 
 // Comparator for name and signature of a method, used in finding overriding methods. Implementation
@@ -4421,9 +4515,36 @@
 const uint32_t LinkVirtualHashTable::invalid_index_ = std::numeric_limits<uint32_t>::max();
 const uint32_t LinkVirtualHashTable::removed_index_ = std::numeric_limits<uint32_t>::max() - 1;
 
-bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) {
+bool ClassLinker::LinkVirtualMethods(
+    Thread* self,
+    Handle<mirror::Class> klass,
+    /*out*/std::unordered_map<size_t, ArtMethod*>* default_translations) {
   const size_t num_virtual_methods = klass->NumVirtualMethods();
-  if (klass->HasSuperClass()) {
+  if (klass->IsInterface()) {
+    // No vtable.
+    if (!IsUint<16>(num_virtual_methods)) {
+      ThrowClassFormatError(klass.Get(), "Too many methods on interface: %zu", num_virtual_methods);
+      return false;
+    }
+    bool has_defaults = false;
+    // TODO May need to replace this with real VTable for invoke_super
+    // Assign each method an IMT index and set the default flag.
+    for (size_t i = 0; i < num_virtual_methods; ++i) {
+      ArtMethod* m = klass->GetVirtualMethodDuringLinking(i, image_pointer_size_);
+      m->SetMethodIndex(i);
+      if (!m->IsAbstract()) {
+        m->SetAccessFlags(m->GetAccessFlags() | kAccDefault);
+        has_defaults = true;
+      }
+    }
+    // Mark that we have default methods so that we won't need to scan the virtual_methods_ array
+    // during initialization. This is a performance optimization. We could simply traverse the
+    // virtual_methods_ array again during initialization.
+    if (has_defaults) {
+      klass->SetHasDefaultMethods();
+    }
+    return true;
+  } else if (klass->HasSuperClass()) {
     const size_t super_vtable_length = klass->GetSuperClass()->GetVTableLength();
     const size_t max_count = num_virtual_methods + super_vtable_length;
     StackHandleScope<2> hs(self);
@@ -4439,14 +4560,22 @@
         vtable->SetElementPtrSize(
             i, super_class->GetEmbeddedVTableEntry(i, image_pointer_size_), image_pointer_size_);
       }
-      if (num_virtual_methods == 0) {
+      // We might need to change vtable if we have new virtual methods or new interfaces (since that
+      // might give us new default methods). If no new interfaces then we can skip the rest since
+      // the class cannot override any of the super-class's methods. This is required for
+      // correctness since without it we might not update overridden default method vtable entries
+      // correctly.
+      if (num_virtual_methods == 0 && super_class->GetIfTableCount() == klass->GetIfTableCount()) {
         klass->SetVTable(vtable.Get());
         return true;
       }
     } else {
+      DCHECK(super_class->IsAbstract() && !super_class->IsArrayClass());
       auto* super_vtable = super_class->GetVTable();
       CHECK(super_vtable != nullptr) << PrettyClass(super_class.Get());
-      if (num_virtual_methods == 0) {
+      // We might need to change vtable if we have new virtual methods or new interfaces (since that
+      // might give us new default methods). See comment above.
+      if (num_virtual_methods == 0 && super_class->GetIfTableCount() == klass->GetIfTableCount()) {
         klass->SetVTable(super_vtable);
         return true;
       }
@@ -4467,7 +4596,9 @@
     // the need for the initial vtable which we later shrink back down).
     // 3. Add non overridden methods to the end of the vtable.
     static constexpr size_t kMaxStackHash = 250;
-    const size_t hash_table_size = num_virtual_methods * 3;
+    // + 1 so that even if we only have new default methods we will still be able to use this hash
+    // table (i.e. it will never have 0 size).
+    const size_t hash_table_size = num_virtual_methods * 3 + 1;
     uint32_t* hash_table_ptr;
     std::unique_ptr<uint32_t[]> hash_heap_storage;
     if (hash_table_size <= kMaxStackHash) {
@@ -4484,10 +4615,10 @@
           i, image_pointer_size_)->GetDeclaringClass() != nullptr);
       hash_table.Add(i);
     }
-    // Loop through each super vtable method and see if they are overriden by a method we added to
+    // Loop through each super vtable method and see if they are overridden by a method we added to
     // the hash table.
     for (size_t j = 0; j < super_vtable_length; ++j) {
-      // Search the hash table to see if we are overidden by any method.
+      // Search the hash table to see if we are overridden by any method.
       ArtMethod* super_method = vtable->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_);
       MethodNameAndSignatureComparator super_method_name_comparator(
           super_method->GetInterfaceMethodIfProxy(image_pointer_size_));
@@ -4510,10 +4641,51 @@
                        << " would have incorrectly overridden the package-private method in "
                        << PrettyDescriptor(super_method->GetDeclaringClassDescriptor());
         }
+      } else if (super_method->IsDefault()) {
+        // We didn't directly override this method but we might through default methods...
+        // Check for default method update.
+        ArtMethod* default_method = nullptr;
+        std::string icce_message;
+        if (!FindDefaultMethodImplementation(self,
+                                             super_method,
+                                             klass,
+                                             /*out*/&default_method,
+                                             /*out*/&icce_message)) {
+          // An error occurred while finding default methods.
+          // TODO This should actually be thrown when we attempt to invoke this method.
+          ThrowIncompatibleClassChangeError(klass.Get(), "%s", icce_message.c_str());
+          return false;
+        }
+        // This should always work because we inherit superclass interfaces. We should either get
+        //  1) An IncompatibleClassChangeError because of conflicting default method
+        //     implementations.
+        //  2) The same default method implementation as the superclass.
+        //  3) A default method that overrides the superclass's.
+        // Therefore this check should never fail.
+        CHECK(default_method != nullptr);
+        if (UNLIKELY(default_method->GetDeclaringClass() != super_method->GetDeclaringClass())) {
+          // TODO Refactor this add default methods to virtuals here and not in
+          //      LinkInterfaceMethods maybe.
+          //      The problem is default methods might override previously present default-method or
+          //      miranda-method vtable entries from the superclass. Unfortunately we need these to
+          //      be entries in this class's virtuals. We do not give these entries there until
+          //      LinkInterfaceMethods so we pass this map around to let it know which vtable
+          //      entries need to be updated.
+          // Make a note that vtable entry j must be updated, store what it needs to be updated to.
+          // We will allocate a virtual method slot in LinkInterfaceMethods and fix it up then.
+          default_translations->insert({j, default_method});
+          VLOG(class_linker) << "Method " << PrettyMethod(super_method) << " overridden by default "
+                             << PrettyMethod(default_method) << " in " << PrettyClass(klass.Get());
+        } else {
+          // They are the same method/no override
+          // Cannot do direct comparison because we had to copy the ArtMethod object into the
+          // superclass's vtable.
+          continue;
+        }
       }
     }
-    // Add the non overridden methods at the end.
     size_t actual_count = super_vtable_length;
+    // Add the non-overridden methods at the end.
     for (size_t i = 0; i < num_virtual_methods; ++i) {
       ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i, image_pointer_size_);
       size_t method_idx = local_method->GetMethodIndexDuringLinking();
@@ -4561,20 +4733,223 @@
   return true;
 }
 
-bool ClassLinker::LinkInterfaceMethods(Thread* self,
-                                       Handle<mirror::Class> klass,
-                                       Handle<mirror::ObjectArray<mirror::Class>> interfaces,
-                                       ArtMethod** out_imt) {
-  StackHandleScope<3> hs(self);
-  Runtime* const runtime = Runtime::Current();
-  const bool has_superclass = klass->HasSuperClass();
-  const size_t super_ifcount = has_superclass ? klass->GetSuperClass()->GetIfTableCount() : 0U;
+// Find the default method implementation for 'interface_method' in 'klass'. Stores it into
+// out_default_method and returns true on success. If no default method was found stores nullptr
+// into out_default_method and returns true. If an error occurs (such as a default_method conflict)
+// it will fill the icce_message with an appropriate message for an IncompatibleClassChangeError,
+// which should then be thrown by the caller.
+bool ClassLinker::FindDefaultMethodImplementation(Thread* self,
+                                                  ArtMethod* target_method,
+                                                  Handle<mirror::Class> klass,
+                                                  /*out*/ArtMethod** out_default_method,
+                                                  /*out*/std::string* icce_message) const {
+  DCHECK(self != nullptr);
+  DCHECK(target_method != nullptr);
+  DCHECK(out_default_method != nullptr);
+  DCHECK(icce_message != nullptr);
+
+  *out_default_method = nullptr;
+  mirror::Class* chosen_iface = nullptr;
+
+  // We organize the interface table so that, for interface I any subinterfaces J follow it in the
+  // table. This lets us walk the table backwards when searching for default methods.  The first one
+  // we encounter is the best candidate since it is the most specific. Once we have found it we keep
+  // track of it and then continue checking all other interfaces, since we need to throw an error if
+  // we encounter conflicting default method implementations (one is not a subtype of the other).
+  //
+  // The order of unrelated interfaces does not matter and is not defined.
+  size_t iftable_count = klass->GetIfTableCount();
+  if (iftable_count == 0) {
+    // No interfaces. We have already reset out to null so just return true.
+    return true;
+  }
+
+  StackHandleScope<1> hs(self);
+  MutableHandle<mirror::IfTable> iftable(hs.NewHandle(klass->GetIfTable()));
+  MethodNameAndSignatureComparator target_name_comparator(
+      target_method->GetInterfaceMethodIfProxy(image_pointer_size_));
+  // Iterates over the klass's iftable in reverse
+  // We have a break at the end because size_t is unsigned.
+  for (size_t k = iftable_count - 1; /* break if k == 0 at end */; --k) {
+    DCHECK_LT(k, iftable->Count());
+    mirror::Class* iface = iftable->GetInterface(k);
+    size_t num_instance_methods = iface->NumVirtualMethods();
+    // Iterate through every method on this interface. The order does not matter so we go forwards.
+    for (size_t m = 0; m < num_instance_methods; m++) {
+      ArtMethod* current_method = iface->GetVirtualMethodUnchecked(m, image_pointer_size_);
+      // Skip abstract methods and methods with different names.
+      if (current_method->IsAbstract() ||
+          !target_name_comparator.HasSameNameAndSignature(
+              current_method->GetInterfaceMethodIfProxy(image_pointer_size_))) {
+        continue;
+      }
+      // The verifier should have caught the non-public method.
+      DCHECK(current_method->IsPublic()) << "Interface method is not public!";
+      if (UNLIKELY(chosen_iface != nullptr)) {
+        // We have multiple default impls of the same method. We need to check they do not
+        // conflict and throw an error if they do. Conflicting means that the current iface is not
+        // masked by the chosen interface.
+        if (!iface->IsAssignableFrom(chosen_iface)) {
+          *icce_message = StringPrintf("Conflicting default method implementations: '%s' and '%s'",
+                                       PrettyMethod(current_method).c_str(),
+                                       PrettyMethod(*out_default_method).c_str());
+          return false;
+        } else {
+          break;  // Continue checking at the next interface.
+        }
+      } else {
+        *out_default_method = current_method;
+        chosen_iface = iface;
+        // We should now finish traversing the graph to find if we have default methods that
+        // conflict.
+        break;
+      }
+    }
+    if (k == 0) {
+      break;
+    }
+  }
+  return true;
+}
+
+// Sets imt_ref appropriately for LinkInterfaceMethods.
+// If there is no method in the imt location of imt_ref it will store the given method there.
+// Otherwise it will set the conflict method which will figure out which method to use during
+// runtime.
+static void SetIMTRef(ArtMethod* unimplemented_method,
+                      ArtMethod* conflict_method,
+                      size_t image_pointer_size,
+                      ArtMethod* current_method,
+                      /*out*/ArtMethod** imt_ref)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  // Place method in imt if entry is empty, place conflict otherwise.
+  if (*imt_ref == unimplemented_method) {
+    *imt_ref = current_method;
+  } else if (*imt_ref != conflict_method) {
+    // If we are not a conflict and we have the same signature and name as the imt
+    // entry, it must be that we overwrote a superclass vtable entry.
+    MethodNameAndSignatureComparator imt_comparator(
+        (*imt_ref)->GetInterfaceMethodIfProxy(image_pointer_size));
+    if (imt_comparator.HasSameNameAndSignature(
+          current_method->GetInterfaceMethodIfProxy(image_pointer_size))) {
+      *imt_ref = current_method;
+    } else {
+      *imt_ref = conflict_method;
+    }
+  }
+}
+
+// Simple helper function that checks that no subtypes of 'val' are contained within the 'classes'
+// set.
+static bool NotSubinterfaceOfAny(const std::unordered_set<mirror::Class*>& classes,
+                                 mirror::Class* val)
+    REQUIRES(Roles::uninterruptible_)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  DCHECK(val != nullptr);
+  for (auto c : classes) {
+    if (val->IsAssignableFrom(&*c)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Fills in and flattens the interface inheritance hierarchy.
+//
+// By the end of this function all interfaces in the transitive closure of to_process are added to
+// the iftable and every interface precedes all of its sub-interfaces in this list.
+//
+// all I, J: Interface | I <: J implies J precedes I
+//
+// (note A <: B means that A is a subtype of B)
+//
+// This returns the total number of items in the iftable. The iftable might be resized down after
+// this call.
+//
+// We order this backwards so that we do not need to reorder superclass interfaces when new
+// interfaces are added in subclass's interface tables.
+//
+// Upon entry into this function iftable is a copy of the superclass's iftable with the first
+// super_ifcount entries filled in with the transitive closure of the interfaces of the superclass.
+// The other entries are uninitialized.  We will fill in the remaining entries in this function. The
+// iftable must be large enough to hold all interfaces without changing its size.
+static size_t FillIfTable(mirror::IfTable* iftable,
+                          size_t super_ifcount,
+                          std::vector<mirror::Class*> to_process)
+    REQUIRES(Roles::uninterruptible_)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  // This is the set of all class's already in the iftable. Used to make checking if a class has
+  // already been added quicker.
+  std::unordered_set<mirror::Class*> classes_in_iftable;
+  // The first super_ifcount elements are from the superclass. We note that they are already added.
+  for (size_t i = 0; i < super_ifcount; i++) {
+    mirror::Class* iface = iftable->GetInterface(i);
+    DCHECK(NotSubinterfaceOfAny(classes_in_iftable, iface)) << "Bad ordering.";
+    classes_in_iftable.insert(iface);
+  }
+  size_t filled_ifcount = super_ifcount;
+  for (mirror::Class* interface : to_process) {
+    // Let us call the first filled_ifcount elements of iftable the current-iface-list.
+    // At this point in the loop current-iface-list has the invariant that:
+    //    for every pair of interfaces I,J within it:
+    //      if index_of(I) < index_of(J) then I is not a subtype of J
+
+    // If we have already seen this element then all of its super-interfaces must already be in the
+    // current-iface-list so we can skip adding it.
+    if (!ContainsElement(classes_in_iftable, interface)) {
+      // We haven't seen this interface so add all of its super-interfaces onto the
+      // current-iface-list, skipping those already on it.
+      int32_t ifcount = interface->GetIfTableCount();
+      for (int32_t j = 0; j < ifcount; j++) {
+        mirror::Class* super_interface = interface->GetIfTable()->GetInterface(j);
+        if (!ContainsElement(classes_in_iftable, super_interface)) {
+          DCHECK(NotSubinterfaceOfAny(classes_in_iftable, super_interface)) << "Bad ordering.";
+          classes_in_iftable.insert(super_interface);
+          iftable->SetInterface(filled_ifcount, super_interface);
+          filled_ifcount++;
+        }
+      }
+      DCHECK(NotSubinterfaceOfAny(classes_in_iftable, interface)) << "Bad ordering";
+      // Place this interface onto the current-iface-list after all of its super-interfaces.
+      classes_in_iftable.insert(interface);
+      iftable->SetInterface(filled_ifcount, interface);
+      filled_ifcount++;
+    } else if (kIsDebugBuild) {
+      // Check all super-interfaces are already in the list.
+      int32_t ifcount = interface->GetIfTableCount();
+      for (int32_t j = 0; j < ifcount; j++) {
+        mirror::Class* super_interface = interface->GetIfTable()->GetInterface(j);
+        DCHECK(ContainsElement(classes_in_iftable, super_interface))
+            << "Iftable does not contain " << PrettyClass(super_interface)
+            << ", a superinterface of " << PrettyClass(interface);
+      }
+    }
+  }
+  if (kIsDebugBuild) {
+    // Check that the iftable is ordered correctly.
+    for (size_t i = 0; i < filled_ifcount; i++) {
+      mirror::Class* if_a = iftable->GetInterface(i);
+      for (size_t j = i + 1; j < filled_ifcount; j++) {
+        mirror::Class* if_b = iftable->GetInterface(j);
+        // !(if_a <: if_b)
+        CHECK(!if_b->IsAssignableFrom(if_a))
+            << "Bad interface order: " << PrettyClass(if_a) << " (index " << i << ") extends "
+            << PrettyClass(if_b) << " (index " << j << ") and so should be after it in the "
+            << "interface list.";
+      }
+    }
+  }
+  return filled_ifcount;
+}
+
+bool ClassLinker::SetupInterfaceLookupTable(Thread* self, Handle<mirror::Class> klass,
+                                            Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
+  StackHandleScope<1> hs(self);
+  const size_t super_ifcount =
+      klass->HasSuperClass() ? klass->GetSuperClass()->GetIfTableCount() : 0U;
   const bool have_interfaces = interfaces.Get() != nullptr;
-  const size_t num_interfaces = have_interfaces
-      ? interfaces->GetLength()
-      : klass->NumDirectInterfaces();
-  const size_t method_alignment = ArtMethod::Alignment(image_pointer_size_);
-  const size_t method_size = ArtMethod::Size(image_pointer_size_);
+  const size_t num_interfaces =
+      have_interfaces ? interfaces->GetLength() : klass->NumDirectInterfaces();
   if (num_interfaces == 0) {
     if (super_ifcount == 0) {
       // Class implements no interfaces.
@@ -4598,6 +4973,7 @@
     }
   }
   size_t ifcount = super_ifcount + num_interfaces;
+  // Check that every class being implemented is an interface.
   for (size_t i = 0; i < num_interfaces; i++) {
     mirror::Class* interface = have_interfaces
         ? interfaces->GetWithoutChecks(i)
@@ -4613,11 +4989,13 @@
     }
     ifcount += interface->GetIfTableCount();
   }
+  // Create the interface function table.
   MutableHandle<mirror::IfTable> iftable(hs.NewHandle(AllocIfTable(self, ifcount)));
   if (UNLIKELY(iftable.Get() == nullptr)) {
     self->AssertPendingOOMException();
     return false;
   }
+  // Fill in table with superclass's iftable.
   if (super_ifcount != 0) {
     mirror::IfTable* super_iftable = klass->GetSuperClass()->GetIfTable();
     for (size_t i = 0; i < super_ifcount; i++) {
@@ -4625,56 +5003,59 @@
       iftable->SetInterface(i, super_interface);
     }
   }
+
+  // Note that AllowThreadSuspension is to thread suspension as pthread_testcancel is to pthread
+  // cancellation. That is it will suspend if one has a pending suspend request but otherwise
+  // doesn't really do anything.
   self->AllowThreadSuspension();
-  // Flatten the interface inheritance hierarchy.
-  size_t idx = super_ifcount;
-  for (size_t i = 0; i < num_interfaces; i++) {
-    mirror::Class* interface = have_interfaces ? interfaces->Get(i) :
-        mirror::Class::GetDirectInterface(self, klass, i);
-    // Check if interface is already in iftable
-    bool duplicate = false;
-    for (size_t j = 0; j < idx; j++) {
-      mirror::Class* existing_interface = iftable->GetInterface(j);
-      if (existing_interface == interface) {
-        duplicate = true;
-        break;
-      }
+
+  size_t new_ifcount;
+  {
+    ScopedAssertNoThreadSuspension nts(self, "Copying mirror::Class*'s for FillIfTable");
+    std::vector<mirror::Class*> to_add;
+    for (size_t i = 0; i < num_interfaces; i++) {
+      mirror::Class* interface = have_interfaces ? interfaces->Get(i) :
+          mirror::Class::GetDirectInterface(self, klass, i);
+      to_add.push_back(interface);
     }
-    if (!duplicate) {
-      // Add this non-duplicate interface.
-      iftable->SetInterface(idx++, interface);
-      // Add this interface's non-duplicate super-interfaces.
-      for (int32_t j = 0; j < interface->GetIfTableCount(); j++) {
-        mirror::Class* super_interface = interface->GetIfTable()->GetInterface(j);
-        bool super_duplicate = false;
-        for (size_t k = 0; k < idx; k++) {
-          mirror::Class* existing_interface = iftable->GetInterface(k);
-          if (existing_interface == super_interface) {
-            super_duplicate = true;
-            break;
-          }
-        }
-        if (!super_duplicate) {
-          iftable->SetInterface(idx++, super_interface);
-        }
-      }
-    }
+
+    new_ifcount = FillIfTable(iftable.Get(), super_ifcount, std::move(to_add));
   }
+
   self->AllowThreadSuspension();
+
   // Shrink iftable in case duplicates were found
-  if (idx < ifcount) {
+  if (new_ifcount < ifcount) {
     DCHECK_NE(num_interfaces, 0U);
     iftable.Assign(down_cast<mirror::IfTable*>(
-        iftable->CopyOf(self, idx * mirror::IfTable::kMax)));
+        iftable->CopyOf(self, new_ifcount * mirror::IfTable::kMax)));
     if (UNLIKELY(iftable.Get() == nullptr)) {
       self->AssertPendingOOMException();
       return false;
     }
-    ifcount = idx;
+    ifcount = new_ifcount;
   } else {
-    DCHECK_EQ(idx, ifcount);
+    DCHECK_EQ(new_ifcount, ifcount);
   }
   klass->SetIfTable(iftable.Get());
+  return true;
+}
+
+bool ClassLinker::LinkInterfaceMethods(
+    Thread* self,
+    Handle<mirror::Class> klass,
+    const std::unordered_map<size_t, ArtMethod*>& default_translations,
+    ArtMethod** out_imt) {
+  StackHandleScope<3> hs(self);
+  Runtime* const runtime = Runtime::Current();
+  const bool has_superclass = klass->HasSuperClass();
+  const size_t super_ifcount = has_superclass ? klass->GetSuperClass()->GetIfTableCount() : 0U;
+  const size_t method_alignment = ArtMethod::Alignment(image_pointer_size_);
+  const size_t method_size = ArtMethod::Size(image_pointer_size_);
+  const size_t ifcount = klass->GetIfTableCount();
+
+  MutableHandle<mirror::IfTable> iftable(hs.NewHandle(klass->GetIfTable()));
+
   // If we're an interface, we don't need the vtable pointers, so we're done.
   if (klass->IsInterface()) {
     return true;
@@ -4687,6 +5068,7 @@
   ArenaStack stack(runtime->GetLinearAlloc()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedArenaVector<ArtMethod*> miranda_methods(allocator.Adapter());
+  ScopedArenaVector<ArtMethod*> default_methods(allocator.Adapter());
 
   MutableHandle<mirror::PointerArray> vtable(hs.NewHandle(klass->GetVTableDuringLinking()));
   ArtMethod* const unimplemented_method = runtime->GetImtUnimplementedMethod();
@@ -4716,7 +5098,9 @@
         for (size_t j = 0; j < num_virtuals; ++j) {
           auto method = method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_);
           DCHECK(method != nullptr) << PrettyClass(super_class);
-          if (method->IsMiranda()) {
+          // Miranda methods cannot be used to implement an interface method and defaults should be
+          // skipped in case we override it.
+          if (method->IsDefault() || method->IsMiranda()) {
             continue;
           }
           ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_);
@@ -4737,6 +5121,8 @@
     size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods();
     if (num_methods > 0) {
       const bool is_super = i < super_ifcount;
+      // This is an interface implemented by a super-class. Therefore we can just copy the method
+      // array from the superclass.
       const bool super_interface = is_super && extend_super_iftable;
       mirror::PointerArray* method_array;
       if (super_interface) {
@@ -4780,16 +5166,13 @@
         input_vtable_array = vtable;
         input_array_length = input_vtable_array->GetLength();
       }
-      if (input_array_length == 0) {
-        // If the added virtual methods is empty, do nothing.
-        DCHECK(super_interface);
-        continue;
-      }
+      // For each method in interface
       for (size_t j = 0; j < num_methods; ++j) {
         auto* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j, image_pointer_size_);
         MethodNameAndSignatureComparator interface_name_comparator(
             interface_method->GetInterfaceMethodIfProxy(image_pointer_size_));
-        int32_t k;
+        uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize;
+        ArtMethod** imt_ptr = &out_imt[imt_index];
         // For each method listed in the interface's method list, find the
         // matching method in our class's method list.  We want to favor the
         // subclass over the superclass, which just requires walking
@@ -4798,7 +5181,12 @@
         // it -- otherwise it would use the same vtable slot.  In .dex files
         // those don't end up in the virtual method table, so it shouldn't
         // matter which direction we go.  We walk it backward anyway.)
-        for (k = input_array_length - 1; k >= 0; --k) {
+        //
+        // To find defaults we need to do the same but also go over interfaces.
+        bool found_impl = false;
+        ArtMethod* default_impl = nullptr;
+        bool found_default_impl = false;
+        for (int32_t k = input_array_length - 1; k >= 0; --k) {
           ArtMethod* vtable_method = input_virtual_methods != nullptr ?
               &input_virtual_methods->At(k, method_size, method_alignment) :
               input_vtable_array->GetElementPtrSize<ArtMethod*>(k, image_pointer_size_);
@@ -4814,25 +5202,69 @@
                   "Method '%s' implementing interface method '%s' is not public",
                   PrettyMethod(vtable_method).c_str(), PrettyMethod(interface_method).c_str());
               return false;
+            } else if (vtable_method->IsDefault()) {
+              // We might have a newer, better, default method for this, so we just skip it. If we
+              // are still using this we will select it again when scanning for default methods. To
+              // obviate the need to copy the method again we will make a note that we already found
+              // a default here.
+              // TODO This should be much cleaner.
+              found_default_impl = true;
+              default_impl = vtable_method;
+              break;
+            } else {
+              found_impl = true;
             }
             method_array->SetElementPtrSize(j, vtable_method, image_pointer_size_);
             // Place method in imt if entry is empty, place conflict otherwise.
-            uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize;
-            auto** imt_ref = &out_imt[imt_index];
-            if (*imt_ref == unimplemented_method) {
-              *imt_ref = vtable_method;
-            } else if (*imt_ref != conflict_method) {
-              // If we are not a conflict and we have the same signature and name as the imt entry,
-              // it must be that we overwrote a superclass vtable entry.
-              MethodNameAndSignatureComparator imt_comparator(
-                  (*imt_ref)->GetInterfaceMethodIfProxy(image_pointer_size_));
-              *imt_ref = imt_comparator.HasSameNameAndSignature(vtable_method_for_name_comparison) ?
-                  vtable_method : conflict_method;
-            }
+            SetIMTRef(unimplemented_method,
+                      conflict_method,
+                      image_pointer_size_,
+                      vtable_method,
+                      /*out*/imt_ptr);
             break;
           }
         }
-        if (k < 0 && !super_interface) {
+        // We should only search for default implementations when the class does not implement the
+        // method directly and either (1) the interface is newly implemented on this class and not
+        // on any of its superclasses, (2) the superclass's implementation is a default method, or
+        // (3) the superclass does not have an implementation.
+        if (!found_impl && (!super_interface ||
+                            method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_)
+                                ->IsOverridableByDefaultMethod())) {
+          ArtMethod* current_method = nullptr;
+          std::string icce_message;
+          if (!FindDefaultMethodImplementation(self,
+                                               interface_method,
+                                               klass,
+                                               /*out*/&current_method,
+                                               /*out*/&icce_message)) {
+            // There was a conflict with default method implementations.
+            self->EndAssertNoThreadSuspension(old_cause);
+            // TODO This should actually be thrown when we attempt to invoke this method.
+            ThrowIncompatibleClassChangeError(klass.Get(), "%s", icce_message.c_str());
+            return false;
+          } else if (current_method != nullptr) {
+            if (found_default_impl &&
+                current_method->GetDeclaringClass() == default_impl->GetDeclaringClass()) {
+              // We found a default method but it was the same one we already have from our
+              // superclass. Don't bother adding it to our vtable again.
+              current_method = default_impl;
+            } else {
+              // We found a default method implementation and there were no conflicts.
+              // Save the default method. We need to add it to the vtable.
+              default_methods.push_back(current_method);
+            }
+            method_array->SetElementPtrSize(j, current_method, image_pointer_size_);
+            SetIMTRef(unimplemented_method,
+                      conflict_method,
+                      image_pointer_size_,
+                      current_method,
+                      /*out*/imt_ptr);
+            found_impl = true;
+          }
+        }
+        if (!found_impl && !super_interface) {
+          // It is defined in this class or any of its subclasses.
           ArtMethod* miranda_method = nullptr;
           for (auto& mir_method : miranda_methods) {
             if (interface_name_comparator.HasSameNameAndSignature(mir_method)) {
@@ -4852,9 +5284,10 @@
       }
     }
   }
-  if (!miranda_methods.empty()) {
+  if (!miranda_methods.empty() || !default_methods.empty()) {
     const size_t old_method_count = klass->NumVirtualMethods();
-    const size_t new_method_count = old_method_count + miranda_methods.size();
+    const size_t new_method_count =
+        old_method_count + miranda_methods.size() + default_methods.size();
     // Attempt to realloc to save RAM if possible.
     LengthPrefixedArray<ArtMethod>* old_virtuals = klass->GetVirtualMethodsPtr();
     // The Realloced virtual methods aren't visiblef from the class roots, so there is no issue
@@ -4889,13 +5322,36 @@
         ++out;
       }
     }
-    StrideIterator<ArtMethod> out(virtuals->Begin(method_size, method_alignment) + old_method_count);
+    StrideIterator<ArtMethod> out(virtuals->Begin(method_size, method_alignment)
+                                      + old_method_count);
     // Copy over miranda methods before copying vtable since CopyOf may cause thread suspension and
     // we want the roots of the miranda methods to get visited.
     for (ArtMethod* mir_method : miranda_methods) {
-      out->CopyFrom(mir_method, image_pointer_size_);
-      out->SetAccessFlags(out->GetAccessFlags() | kAccMiranda);
-      move_table.emplace(mir_method, &*out);
+      ArtMethod& new_method = *out;
+      new_method.CopyFrom(mir_method, image_pointer_size_);
+      new_method.SetAccessFlags(new_method.GetAccessFlags() | kAccMiranda);
+      DCHECK_NE(new_method.GetAccessFlags() & kAccAbstract, 0u)
+          << "Miranda method should be abstract!";
+      move_table.emplace(mir_method, &new_method);
+      ++out;
+    }
+    // We need to copy the default methods into our own virtual method table since the runtime
+    // requires that every method on a class's vtable be in that respective class's virtual method
+    // table.
+    // NOTE This means that two classes might have the same implementation of a method from the same
+    // interface but will have different ArtMethod*s for them. This also means we cannot compare a
+    // default method found on a class with one found on the declaring interface directly and must
+    // look at the declaring class to determine if they are the same.
+    for (ArtMethod* def_method : default_methods) {
+      ArtMethod& new_method = *out;
+      new_method.CopyFrom(def_method, image_pointer_size_);
+      new_method.SetAccessFlags(new_method.GetAccessFlags() | kAccDefault);
+      // Clear the preverified flag if it is present. Since this class hasn't been verified yet it
+      // shouldn't have methods that are preverified.
+      // TODO This is rather arbitrary. We should maybe support classes where only some of its
+      // methods are preverified.
+      new_method.SetAccessFlags(new_method.GetAccessFlags() & ~kAccPreverified);
+      move_table.emplace(def_method, &new_method);
       ++out;
     }
     virtuals->SetLength(new_method_count);
@@ -4905,7 +5361,8 @@
     self->EndAssertNoThreadSuspension(old_cause);
 
     const size_t old_vtable_count = vtable->GetLength();
-    const size_t new_vtable_count = old_vtable_count + miranda_methods.size();
+    const size_t new_vtable_count =
+        old_vtable_count + miranda_methods.size() + default_methods.size();
     miranda_methods.clear();
     vtable.Assign(down_cast<mirror::PointerArray*>(vtable->CopyOf(self, new_vtable_count)));
     if (UNLIKELY(vtable.Get() == nullptr)) {
@@ -4922,15 +5379,29 @@
       ++vtable_pos;
     }
     CHECK_EQ(vtable_pos, new_vtable_count);
-    // Update old vtable methods.
+    // Update old vtable methods. We use the default_translations map to figure out what each vtable
+    // entry should be updated to, if they need to be at all.
     for (size_t i = 0; i < old_vtable_count; ++i) {
-      auto* m = vtable->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_);
-      DCHECK(m != nullptr) << PrettyClass(klass.Get());
-      auto it = move_table.find(m);
+      ArtMethod* translated_method = vtable->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_);
+      // Try and find what we need to change this method to.
+      auto translation_it = default_translations.find(i);
+      bool found_translation = false;
+      if (translation_it != default_translations.end()) {
+        size_t vtable_index;
+        std::tie(vtable_index, translated_method) = *translation_it;
+        DCHECK_EQ(vtable_index, i);
+        found_translation = true;
+      }
+      DCHECK(translated_method != nullptr);
+      auto it = move_table.find(translated_method);
       if (it != move_table.end()) {
-        auto* new_m = it->second;
-        DCHECK(new_m != nullptr) << PrettyClass(klass.Get());
-        vtable->SetElementPtrSize(i, new_m, image_pointer_size_);
+        auto* new_method = it->second;
+        DCHECK(new_method != nullptr);
+        vtable->SetElementPtrSize(i, new_method, image_pointer_size_);
+      } else {
+        // If it was not going to be updated we wouldn't have put it into the default_translations
+        // map.
+        CHECK(!found_translation) << "We were asked to update this vtable entry. Must not fail.";
       }
     }
 
@@ -4961,7 +5432,11 @@
       auto* resolved_methods = klass->GetDexCache()->GetResolvedMethods();
       for (size_t i = 0, count = klass->GetDexCache()->NumResolvedMethods(); i < count; ++i) {
         auto* m = mirror::DexCache::GetElementPtrSize(resolved_methods, i, image_pointer_size_);
-        CHECK(move_table.find(m) == move_table.end()) << PrettyMethod(m);
+        // We don't remove default methods from the move table since we need them to update the
+        // vtable. Therefore just skip them for this check.
+        if (!m->IsDefault()) {
+          CHECK(move_table.find(m) == move_table.end()) << PrettyMethod(m);
+        }
       }
     }
     // Put some random garbage in old virtuals to help find stale pointers.
@@ -5794,9 +6269,13 @@
   for (const DexFile* dex_file : dex_files) {
     StackHandleScope<3> hs2(self);
 
-    Handle<mirror::LongArray> h_long_array = hs2.NewHandle(mirror::LongArray::Alloc(self, 1));
+    // CreatePathClassLoader is only used by gtests. Index 0 of h_long_array is supposed to be the
+    // oat file but we can leave it null.
+    Handle<mirror::LongArray> h_long_array = hs2.NewHandle(mirror::LongArray::Alloc(
+        self,
+        kDexFileIndexStart + 1));
     DCHECK(h_long_array.Get() != nullptr);
-    h_long_array->Set(0, reinterpret_cast<intptr_t>(dex_file));
+    h_long_array->Set(kDexFileIndexStart, reinterpret_cast<intptr_t>(dex_file));
 
     Handle<mirror::Object> h_dex_file = hs2.NewHandle(
         cookie_field->GetDeclaringClass()->AllocObject(self));
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 76cb0a6..93161f7 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_CLASS_LINKER_H_
 
 #include <string>
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -648,6 +649,12 @@
                        bool can_init_parents)
       SHARED_REQUIRES(Locks::mutator_lock_)
       REQUIRES(!dex_lock_);
+  bool InitializeDefaultInterfaceRecursive(Thread* self,
+                                           Handle<mirror::Class> klass,
+                                           bool can_run_clinit,
+                                           bool can_init_parents)
+      REQUIRES(!dex_lock_)
+      SHARED_REQUIRES(Locks::mutator_lock_);
   bool WaitForInitializeClass(Handle<mirror::Class> klass,
                               Thread* self,
                               ObjectLock<mirror::Class>& lock);
@@ -687,12 +694,65 @@
                    ArtMethod** out_imt)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
-  bool LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass)
+  // Links the virtual methods for the given class and records any default methods that will need to
+  // be updated later.
+  //
+  // Arguments:
+  // * self - The current thread.
+  // * klass - class, whose vtable will be filled in.
+  // * default_translations - Vtable index to new method map.
+  //                          Any vtable entries that need to be updated with new default methods
+  //                          are stored into the default_translations map. The default_translations
+  //                          map is keyed on the vtable index that needs to be updated. We use this
+  //                          map because if we override a default method with another default
+  //                          method we need to update the vtable to point to the new method.
+  //                          Unfortunately since we copy the ArtMethod* we cannot just do a simple
+  //                          scan, we therefore store the vtable index's that might need to be
+  //                          updated with the method they will turn into.
+  // TODO This whole default_translations thing is very dirty. There should be a better way.
+  bool LinkVirtualMethods(Thread* self,
+                          Handle<mirror::Class> klass,
+                          /*out*/std::unordered_map<size_t, ArtMethod*>* default_translations)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  // Sets up the interface lookup table (IFTable) in the correct order to allow searching for
+  // default methods.
+  bool SetupInterfaceLookupTable(Thread* self,
+                                 Handle<mirror::Class> klass,
+                                 Handle<mirror::ObjectArray<mirror::Class>> interfaces)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
+  // Find the default method implementation for 'interface_method' in 'klass', if one exists.
+  //
+  // Arguments:
+  // * self - The current thread.
+  // * target_method - The method we are trying to find a default implementation for.
+  // * klass - The class we are searching for a definition of target_method.
+  // * out_default_method - The pointer we will store the found default method to on success.
+  // * icce_message - A string we will store an appropriate IncompatibleClassChangeError message
+  //                  into in case of failure. Note we must do it this way since we do not know
+  //                  whether we can allocate the exception object, which could cause us to go to
+  //                  sleep.
+  //
+  // Return value:
+  // * True - There were no conflicting method implementations found in the class while searching
+  //          for target_method. The default method implementation is stored into out_default_method
+  //          if it was found.  Otherwise *out_default_method will be set to nullptr.
+  // * False - Conflicting method implementations were found when searching for target_method. The
+  //           value of *out_default_method is undefined and *icce_message is a string that should
+  //           be used to create an IncompatibleClassChangeError as soon as possible.
+  bool FindDefaultMethodImplementation(Thread* self,
+                                       ArtMethod* target_method,
+                                       Handle<mirror::Class> klass,
+                                       /*out*/ArtMethod** out_default_method,
+                                       /*out*/std::string* icce_message) const
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
+  // Sets the imt entries and fixes up the vtable for the given class by linking all the interface
+  // methods. See LinkVirtualMethods for an explanation of what default_translations is.
   bool LinkInterfaceMethods(Thread* self,
                             Handle<mirror::Class> klass,
-                            Handle<mirror::ObjectArray<mirror::Class>> interfaces,
+                            const std::unordered_map<size_t, ArtMethod*>& default_translations,
                             ArtMethod** out_imt)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 56c5d1a..b6b5141 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -42,6 +42,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mem_map.h"
+#include "native/dalvik_system_DexFile.h"
 #include "noop_compiler_callbacks.h"
 #include "os.h"
 #include "primitive.h"
@@ -516,7 +517,7 @@
           mirror::LongArray* long_array = cookie_field->GetObject(dex_file)->AsLongArray();
           DCHECK(long_array != nullptr);
           int32_t long_array_size = long_array->GetLength();
-          for (int32_t j = 0; j < long_array_size; ++j) {
+          for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) {
             const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(
                 long_array->GetWithoutChecks(j)));
             if (cp_dex_file == nullptr) {
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 09416cc..a5f9d09 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -23,7 +23,9 @@
 
 #include "base/stringprintf.h"
 #include "dex_file-inl.h"
+#include "experimental_flags.h"
 #include "leb128.h"
+#include "runtime.h"
 #include "safe_map.h"
 #include "utf-inl.h"
 #include "utils.h"
@@ -2530,7 +2532,14 @@
   }
 
   // Only the static initializer may have code in an interface.
-  if (((class_access_flags & kAccInterface) != 0) && !is_clinit_by_name) {
+  // TODO We should have some way determine whether to allow this experimental flag without the
+  // runtime being started.
+  // We assume experimental flags are enabled when running without a runtime to enable tools like
+  // dexdump to handle dex files with these features.
+  if (((class_access_flags & kAccInterface) != 0)
+      && !is_clinit_by_name
+      && Runtime::Current() != nullptr
+      && !Runtime::Current()->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) {
     *error_msg = StringPrintf("Non-clinit interface method %" PRIu32 " should not have code",
                               method_index);
     return false;
diff --git a/runtime/experimental_flags.h b/runtime/experimental_flags.h
new file mode 100644
index 0000000..2e674e9
--- /dev/null
+++ b/runtime/experimental_flags.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_EXPERIMENTAL_FLAGS_H_
+#define ART_RUNTIME_EXPERIMENTAL_FLAGS_H_
+
+#include <ostream>
+
+namespace art {
+
+// Possible experimental features that might be enabled.
+struct ExperimentalFlags {
+  // The actual flag values.
+  enum {
+    kNone           = 0x0000,
+    kLambdas        = 0x0001,
+    kDefaultMethods = 0x0002,
+  };
+
+  constexpr ExperimentalFlags() : value_(0x0000) {}
+  constexpr ExperimentalFlags(decltype(kNone) t) : value_(static_cast<uint32_t>(t)) {}
+
+  constexpr operator decltype(kNone)() const {
+    return static_cast<decltype(kNone)>(value_);
+  }
+
+  constexpr explicit operator bool() const {
+    return value_ != kNone;
+  }
+
+  constexpr ExperimentalFlags operator|(const decltype(kNone)& b) const {
+    return static_cast<decltype(kNone)>(value_ | static_cast<uint32_t>(b));
+  }
+  constexpr ExperimentalFlags operator|(const ExperimentalFlags& b) const {
+    return static_cast<decltype(kNone)>(value_ | b.value_);
+  }
+
+  constexpr ExperimentalFlags operator&(const ExperimentalFlags& b) const {
+    return static_cast<decltype(kNone)>(value_ & b.value_);
+  }
+  constexpr ExperimentalFlags operator&(const decltype(kNone)& b) const {
+    return static_cast<decltype(kNone)>(value_ & static_cast<uint32_t>(b));
+  }
+
+  constexpr bool operator==(const ExperimentalFlags& b) const {
+    return value_ == b.value_;
+  }
+
+ private:
+  uint32_t value_;
+};
+
+inline std::ostream& operator<<(std::ostream& stream, const ExperimentalFlags& e) {
+  bool started = false;
+  if (e & ExperimentalFlags::kLambdas) {
+    stream << (started ? "|" : "") << "kLambdas";
+    started = true;
+  }
+  if (e & ExperimentalFlags::kDefaultMethods) {
+    stream << (started ? "|" : "") << "kDefaultMethods";
+    started = true;
+  }
+  if (!started) {
+    stream << "kNone";
+  }
+  return stream;
+}
+
+inline std::ostream& operator<<(std::ostream& stream, const decltype(ExperimentalFlags::kNone)& e) {
+  return stream << ExperimentalFlags(e);
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_EXPERIMENTAL_FLAGS_H_
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 87f1392..3ce3d63 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -131,6 +131,7 @@
 
    private:
     Slot* next_;  // Next slot in the list.
+    friend class RosAlloc;
   };
 
   // We use the tail (kUseTail == true) for the bulk or thread-local free lists to avoid the need to
@@ -302,6 +303,7 @@
     // free without traversing the whole free list.
     uint32_t size_;
     uint32_t padding_ ATTRIBUTE_UNUSED;
+    friend class RosAlloc;
   };
 
   // Represents a run of memory slots of the same size.
@@ -482,7 +484,7 @@
   static constexpr uint8_t kMagicNumFree = 43;
   // The number of size brackets. Sync this with the length of Thread::rosalloc_runs_.
   static constexpr size_t kNumOfSizeBrackets = kNumRosAllocThreadLocalSizeBrackets;
-  // The number of smaller size brackets that are 16 bytes apart.
+  // The number of smaller size brackets that are the quantum size apart.
   static constexpr size_t kNumOfQuantumSizeBrackets = 32;
   // The sizes (the slot sizes, in bytes) of the size brackets.
   static size_t bracketSizes[kNumOfSizeBrackets];
@@ -520,9 +522,7 @@
   }
   // Returns true if the given allocation size is for a thread local allocation.
   static bool IsSizeForThreadLocal(size_t size) {
-    DCHECK_GT(kNumThreadLocalSizeBrackets, 0U);
-    size_t max_thread_local_bracket_idx = kNumThreadLocalSizeBrackets - 1;
-    bool is_size_for_thread_local = size <= bracketSizes[max_thread_local_bracket_idx];
+    bool is_size_for_thread_local = size <= kMaxThreadLocalBracketSize;
     DCHECK(size > kLargeSizeThreshold ||
            (is_size_for_thread_local == (SizeToIndex(size) < kNumThreadLocalSizeBrackets)));
     return is_size_for_thread_local;
@@ -634,6 +634,16 @@
   // are less than this index. We use shared (current) runs for the rest.
   static const size_t kNumThreadLocalSizeBrackets = 8;
 
+  // The size of the largest bracket we use thread-local runs for.
+  // This should be equal to bracketSizes[kNumThreadLocalSizeBrackets - 1].
+  static const size_t kMaxThreadLocalBracketSize = 128;
+
+  // The bracket size increment for the brackets of size <= 512 bytes.
+  static constexpr size_t kBracketQuantumSize = 16;
+
+  // Equal to Log2(kQuantumBracketSizeIncrement).
+  static constexpr size_t kBracketQuantumSizeShift = 4;
+
  private:
   // The base address of the memory region that's managed by this allocator.
   uint8_t* base_;
@@ -770,6 +780,19 @@
            size_t page_release_size_threshold = kDefaultPageReleaseSizeThreshold);
   ~RosAlloc();
 
+  static size_t RunFreeListOffset() {
+    return OFFSETOF_MEMBER(Run, free_list_);
+  }
+  static size_t RunFreeListHeadOffset() {
+    return OFFSETOF_MEMBER(SlotFreeList<false>, head_);
+  }
+  static size_t RunFreeListSizeOffset() {
+    return OFFSETOF_MEMBER(SlotFreeList<false>, size_);
+  }
+  static size_t RunSlotNextOffset() {
+    return OFFSETOF_MEMBER(Slot, next_);
+  }
+
   // If kThreadUnsafe is true then the allocator may avoid acquiring some locks as an optimization.
   // If used, this may cause race conditions if multiple threads are allocating at the same time.
   template<bool kThreadSafe = true>
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index b010504..7c0594a 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -458,10 +458,11 @@
   }
 
   self->PushShadowFrame(shadow_frame);
+  ArtMethod* method = shadow_frame->GetMethod();
   // Ensure static methods are initialized.
-  const bool is_static = shadow_frame->GetMethod()->IsStatic();
+  const bool is_static = method->IsStatic();
   if (is_static) {
-    mirror::Class* declaring_class = shadow_frame->GetMethod()->GetDeclaringClass();
+    mirror::Class* declaring_class = method->GetDeclaringClass();
     if (UNLIKELY(!declaring_class->IsInitialized())) {
       StackHandleScope<1> hs(self);
       HandleWrapper<Class> h_declaring_class(hs.NewHandleWrapper(&declaring_class));
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 4265b50..9766299 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -19,6 +19,7 @@
 
 
 #include "base/stl_util.h"  // MakeUnique
+#include "experimental_flags.h"
 #include "interpreter_common.h"
 #include "safe_math.h"
 
@@ -83,7 +84,7 @@
 #define HANDLE_EXPERIMENTAL_INSTRUCTION_START(opcode)                                             \
   HANDLE_INSTRUCTION_START(opcode);                                                               \
   DCHECK(inst->IsExperimental());                                                                 \
-  if (Runtime::Current()->AreExperimentalLambdasEnabled()) {
+  if (Runtime::Current()->AreExperimentalFlagsEnabled(ExperimentalFlags::kLambdas)) {
 #define HANDLE_EXPERIMENTAL_INSTRUCTION_END()                                                     \
   } else {                                                                                        \
       UnexpectedOpcode(inst, shadow_frame);                                                       \
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 76d4bb0fc..bf95a0e 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -15,6 +15,7 @@
  */
 
 #include "base/stl_util.h"  // MakeUnique
+#include "experimental_flags.h"
 #include "interpreter_common.h"
 #include "safe_math.h"
 
@@ -67,7 +68,7 @@
 
 static bool IsExperimentalInstructionEnabled(const Instruction *inst) {
   DCHECK(inst->IsExperimental());
-  return Runtime::Current()->AreExperimentalLambdasEnabled();
+  return Runtime::Current()->AreExperimentalFlagsEnabled(ExperimentalFlags::kLambdas);
 }
 
 template<bool do_access_check, bool transaction_active>
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 2a019c5..2d3581d 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -134,11 +134,25 @@
 uintptr_t MemMap::next_mem_pos_ = GenerateNextMemPos();
 #endif
 
-// Return true if the address range is contained in a single /proc/self/map entry.
-static bool ContainedWithinExistingMap(uint8_t* ptr, size_t size,
-                                       std::string* error_msg) {
+// Return true if the address range is contained in a single memory map by either reading
+// the maps_ variable or the /proc/self/map entry.
+bool MemMap::ContainedWithinExistingMap(uint8_t* ptr, size_t size, std::string* error_msg) {
   uintptr_t begin = reinterpret_cast<uintptr_t>(ptr);
   uintptr_t end = begin + size;
+
+  // There is a suspicion that BacktraceMap::Create is occasionally missing maps. TODO: Investigate
+  // further.
+  {
+    MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+    for (auto& pair : *maps_) {
+      MemMap* const map = pair.second;
+      if (begin >= reinterpret_cast<uintptr_t>(map->Begin()) &&
+          end <= reinterpret_cast<uintptr_t>(map->End())) {
+        return true;
+      }
+    }
+  }
+
   std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true));
   if (map.get() == nullptr) {
     *error_msg = StringPrintf("Failed to build process map");
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index 196a7f6..7c11ceb 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -161,6 +161,8 @@
       REQUIRES(Locks::mem_maps_lock_);
   static MemMap* GetLargestMemMapAt(void* address)
       REQUIRES(Locks::mem_maps_lock_);
+  static bool ContainedWithinExistingMap(uint8_t* ptr, size_t size, std::string* error_msg)
+      REQUIRES(!Locks::mem_maps_lock_);
 
   const std::string name_;
   uint8_t* const begin_;  // Start of data.
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 93f2aea..a528c3b 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -392,7 +392,8 @@
 }
 
 inline ArtMethod* Class::FindVirtualMethodForVirtual(ArtMethod* method, size_t pointer_size) {
-  DCHECK(!method->GetDeclaringClass()->IsInterface() || method->IsMiranda());
+  // Only miranda or default methods may come from interfaces and be used as a virtual.
+  DCHECK(!method->GetDeclaringClass()->IsInterface() || method->IsDefault() || method->IsMiranda());
   // The argument method may from a super class.
   // Use the index to a potentially overridden one for this instance's class.
   return GetVTableEntry(method->GetMethodIndex(), pointer_size);
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 2668b3d..8219d69 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -30,6 +30,7 @@
 #include "primitive.h"
 #include "read_barrier_option.h"
 #include "stride_iterator.h"
+#include "thread.h"
 #include "utils.h"
 
 #ifndef IMT_SIZE
@@ -229,6 +230,18 @@
     return (GetAccessFlags() & kAccClassIsFinalizable) != 0;
   }
 
+  ALWAYS_INLINE void SetRecursivelyInitialized() SHARED_REQUIRES(Locks::mutator_lock_) {
+    DCHECK_EQ(GetLockOwnerThreadId(), Thread::Current()->GetThreadId());
+    uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
+    SetAccessFlags(flags | kAccRecursivelyInitialized);
+  }
+
+  ALWAYS_INLINE void SetHasDefaultMethods() SHARED_REQUIRES(Locks::mutator_lock_) {
+    DCHECK_EQ(GetLockOwnerThreadId(), Thread::Current()->GetThreadId());
+    uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
+    SetAccessFlags(flags | kAccHasDefaultMethod);
+  }
+
   ALWAYS_INLINE void SetFinalizable() SHARED_REQUIRES(Locks::mutator_lock_) {
     uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
     SetAccessFlags(flags | kAccClassIsFinalizable);
@@ -860,6 +873,14 @@
 
   ArtMethod* FindClassInitializer(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_);
 
+  bool HasDefaultMethods() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return (GetAccessFlags() & kAccHasDefaultMethod) != 0;
+  }
+
+  bool HasBeenRecursivelyInitialized() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return (GetAccessFlags() & kAccRecursivelyInitialized) != 0;
+  }
+
   ALWAYS_INLINE int32_t GetIfTableCount() SHARED_REQUIRES(Locks::mutator_lock_);
 
   ALWAYS_INLINE IfTable* GetIfTable() SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index f7ab10b..116cbe9 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -49,8 +49,13 @@
                                                                   // method (dex only)
 static constexpr uint32_t kAccFastNative =           0x00080000;  // method (dex only)
 static constexpr uint32_t kAccMiranda =              0x00200000;  // method (dex only)
+static constexpr uint32_t kAccDefault =              0x00400000;  // method (runtime)
 
 // Special runtime-only flags.
+// Interface and all its super-interfaces with default methods have been recursively initialized.
+static constexpr uint32_t kAccRecursivelyInitialized    = 0x20000000;
+// Interface declares some default method.
+static constexpr uint32_t kAccHasDefaultMethod          = 0x40000000;
 // class/ancestor overrides finalize()
 static constexpr uint32_t kAccClassIsFinalizable        = 0x80000000;
 
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 4850b6f..e9ce02b 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -40,13 +40,16 @@
 
 namespace art {
 
-static std::unique_ptr<std::vector<const DexFile*>>
-ConvertJavaArrayToNative(JNIEnv* env, jobject arrayObject) {
+static bool ConvertJavaArrayToDexFiles(
+    JNIEnv* env,
+    jobject arrayObject,
+    /*out*/ std::vector<const DexFile*>& dex_files,
+    /*out*/ const OatFile*& oat_file) {
   jarray array = reinterpret_cast<jarray>(arrayObject);
 
   jsize array_size = env->GetArrayLength(array);
   if (env->ExceptionCheck() == JNI_TRUE) {
-    return std::unique_ptr<std::vector<const DexFile*>>();
+    return false;
   }
 
   // TODO: Optimize. On 32bit we can use an int array.
@@ -54,27 +57,24 @@
   jlong* long_data = env->GetLongArrayElements(reinterpret_cast<jlongArray>(array),
                                                &is_long_data_copied);
   if (env->ExceptionCheck() == JNI_TRUE) {
-    return std::unique_ptr<std::vector<const DexFile*>>();
+    return false;
   }
 
-  std::unique_ptr<std::vector<const DexFile*>> ret(new std::vector<const DexFile*>());
-  ret->reserve(array_size);
-  for (jsize i = 0; i < array_size; ++i) {
-    ret->push_back(reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(*(long_data + i))));
+  oat_file = reinterpret_cast<const OatFile*>(static_cast<uintptr_t>(long_data[kOatFileIndex]));
+  dex_files.reserve(array_size - 1);
+  for (jsize i = kDexFileIndexStart; i < array_size; ++i) {
+    dex_files.push_back(reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(long_data[i])));
   }
 
   env->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array), long_data, JNI_ABORT);
-  if (env->ExceptionCheck() == JNI_TRUE) {
-    return std::unique_ptr<std::vector<const DexFile*>>();
-  }
-
-  return ret;
+  return env->ExceptionCheck() != JNI_TRUE;
 }
 
-static jlongArray ConvertNativeToJavaArray(JNIEnv* env,
-                                           std::vector<std::unique_ptr<const DexFile>>& vec) {
-  size_t vec_size = vec.size();
-  jlongArray long_array = env->NewLongArray(static_cast<jsize>(vec_size));
+static jlongArray ConvertDexFilesToJavaArray(JNIEnv* env,
+                                             const OatFile* oat_file,
+                                             std::vector<std::unique_ptr<const DexFile>>& vec) {
+  // Add one for the oat file.
+  jlongArray long_array = env->NewLongArray(static_cast<jsize>(1u + vec.size()));
   if (env->ExceptionCheck() == JNI_TRUE) {
     return nullptr;
   }
@@ -85,10 +85,9 @@
     return nullptr;
   }
 
-  jlong* tmp = long_data;
-  for (auto& dex_file : vec) {
-    *tmp = reinterpret_cast<uintptr_t>(dex_file.get());
-    tmp++;
+  long_data[kOatFileIndex] = reinterpret_cast<uintptr_t>(oat_file);
+  for (size_t i = 0; i < vec.size(); ++i) {
+    long_data[kDexFileIndexStart + i] = reinterpret_cast<uintptr_t>(vec[i].get());
   }
 
   env->ReleaseLongArrayElements(long_array, long_data, 0);
@@ -165,13 +164,15 @@
   ClassLinker* linker = runtime->GetClassLinker();
   std::vector<std::unique_ptr<const DexFile>> dex_files;
   std::vector<std::string> error_msgs;
+  const OatFile* oat_file = nullptr;
 
   dex_files = runtime->GetOatFileManager().OpenDexFilesFromOat(sourceName.c_str(),
                                                                outputName.c_str(),
-                                                               &error_msgs);
+                                                               /*out*/ &oat_file,
+                                                               /*out*/ &error_msgs);
 
   if (!dex_files.empty()) {
-    jlongArray array = ConvertNativeToJavaArray(env, dex_files);
+    jlongArray array = ConvertDexFilesToJavaArray(env, oat_file, dex_files);
     if (array == nullptr) {
       ScopedObjectAccess soa(env);
       for (auto& dex_file : dex_files) {
@@ -197,43 +198,55 @@
 }
 
 static jboolean DexFile_closeDexFile(JNIEnv* env, jclass, jobject cookie) {
-  ScopedObjectAccess soa(env);
-  mirror::Object* dex_files_object = soa.Decode<mirror::Object*>(cookie);
-  if (dex_files_object == nullptr) {
-    ThrowNullPointerException("cookie == null");
+  std::vector<const DexFile*> dex_files;
+  const OatFile* oat_file;
+  if (!ConvertJavaArrayToDexFiles(env, cookie, dex_files, oat_file)) {
+    Thread::Current()->AssertPendingException();
     return JNI_FALSE;
   }
-  mirror::LongArray* dex_files = dex_files_object->AsLongArray();
-
-  // Delete dex files associated with this dalvik.system.DexFile since there should not be running
-  // code using it. dex_files is a vector due to multidex.
-  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+  Runtime* const runtime = Runtime::Current();
   bool all_deleted = true;
-  for (int32_t i = 0, count = dex_files->GetLength(); i < count; ++i) {
-    auto* dex_file = reinterpret_cast<DexFile*>(dex_files->Get(i));
-    if (dex_file == nullptr) {
-      continue;
-    }
-    // Only delete the dex file if the dex cache is not found to prevent runtime crashes if there
-    // are calls to DexFile.close while the ART DexFile is still in use.
-    if (class_linker->FindDexCache(soa.Self(), *dex_file, true) == nullptr) {
-      // Clear the element in the array so that we can call close again.
-      dex_files->Set(i, 0);
-      delete dex_file;
-    } else {
-      all_deleted = false;
+  {
+    ScopedObjectAccess soa(env);
+    mirror::Object* dex_files_object = soa.Decode<mirror::Object*>(cookie);
+    mirror::LongArray* long_dex_files = dex_files_object->AsLongArray();
+    // Delete dex files associated with this dalvik.system.DexFile since there should not be running
+    // code using it. dex_files is a vector due to multidex.
+    ClassLinker* const class_linker = runtime->GetClassLinker();
+    int32_t i = kDexFileIndexStart;  // Oat file is at index 0.
+    for (const DexFile* dex_file : dex_files) {
+      if (dex_file != nullptr) {
+        // Only delete the dex file if the dex cache is not found to prevent runtime crashes if there
+        // are calls to DexFile.close while the ART DexFile is still in use.
+        if (class_linker->FindDexCache(soa.Self(), *dex_file, true) == nullptr) {
+          // Clear the element in the array so that we can call close again.
+          long_dex_files->Set(i, 0);
+          delete dex_file;
+        } else {
+          all_deleted = false;
+        }
+      }
+      ++i;
     }
   }
 
-  // TODO: Also unmap the OatFile for this dalvik.system.DexFile.
-
+  // oat_file can be null if we are running without dex2oat.
+  if (all_deleted && oat_file != nullptr) {
+    // If all of the dex files are no longer in use we can unmap the corresponding oat file.
+    VLOG(class_linker) << "Unregistering " << oat_file;
+    runtime->GetOatFileManager().UnRegisterAndDeleteOatFile(oat_file);
+  }
   return all_deleted ? JNI_TRUE : JNI_FALSE;
 }
 
-static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader,
+static jclass DexFile_defineClassNative(JNIEnv* env,
+                                        jclass,
+                                        jstring javaName,
+                                        jobject javaLoader,
                                         jobject cookie) {
-  std::unique_ptr<std::vector<const DexFile*>> dex_files = ConvertJavaArrayToNative(env, cookie);
-  if (dex_files.get() == nullptr) {
+  std::vector<const DexFile*> dex_files;
+  const OatFile* oat_file;
+  if (!ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)) {
     VLOG(class_linker) << "Failed to find dex_file";
     DCHECK(env->ExceptionCheck());
     return nullptr;
@@ -246,7 +259,7 @@
   }
   const std::string descriptor(DotToDescriptor(class_name.c_str()));
   const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str()));
-  for (auto& dex_file : *dex_files) {
+  for (auto& dex_file : dex_files) {
     const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str(), hash);
     if (dex_class_def != nullptr) {
       ScopedObjectAccess soa(env);
@@ -255,8 +268,12 @@
       StackHandleScope<1> hs(soa.Self());
       Handle<mirror::ClassLoader> class_loader(
           hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
-      mirror::Class* result = class_linker->DefineClass(soa.Self(), descriptor.c_str(), hash,
-                                                        class_loader, *dex_file, *dex_class_def);
+      mirror::Class* result = class_linker->DefineClass(soa.Self(),
+                                                        descriptor.c_str(),
+                                                        hash,
+                                                        class_loader,
+                                                        *dex_file,
+                                                        *dex_class_def);
       if (result != nullptr) {
         VLOG(class_linker) << "DexFile_defineClassNative returning " << result
                            << " for " << class_name.c_str();
@@ -277,8 +294,9 @@
 
 // Note: this can be an expensive call, as we sort out duplicates in MultiDex files.
 static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jobject cookie) {
-  std::unique_ptr<std::vector<const DexFile*>> dex_files = ConvertJavaArrayToNative(env, cookie);
-  if (dex_files.get() == nullptr) {
+  const OatFile* oat_file = nullptr;
+  std::vector<const DexFile*> dex_files;
+  if (!ConvertJavaArrayToDexFiles(env, cookie, /*out */ dex_files, /* out */ oat_file)) {
     DCHECK(env->ExceptionCheck());
     return nullptr;
   }
@@ -286,7 +304,7 @@
   // Push all class descriptors into a set. Use set instead of unordered_set as we want to
   // retrieve all in the end.
   std::set<const char*, CharPointerComparator> descriptors;
-  for (auto& dex_file : *dex_files) {
+  for (auto& dex_file : dex_files) {
     for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
       const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
       const char* descriptor = dex_file->GetClassDescriptor(class_def);
@@ -295,7 +313,8 @@
   }
 
   // Now create output array and copy the set into it.
-  jobjectArray result = env->NewObjectArray(descriptors.size(), WellKnownClasses::java_lang_String,
+  jobjectArray result = env->NewObjectArray(descriptors.size(),
+                                            WellKnownClasses::java_lang_String,
                                             nullptr);
   if (result != nullptr) {
     auto it = descriptors.begin();
@@ -313,9 +332,11 @@
   return result;
 }
 
-static jint GetDexOptNeeded(JNIEnv* env, const char* filename,
-    const char* pkgname, const char* instruction_set, const jboolean defer) {
-
+static jint GetDexOptNeeded(JNIEnv* env,
+                            const char* filename,
+                            const char* pkgname,
+                            const char* instruction_set,
+                            const jboolean defer) {
   if ((filename == nullptr) || !OS::FileExists(filename)) {
     LOG(ERROR) << "DexFile_getDexOptNeeded file '" << filename << "' does not exist";
     ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException"));
@@ -365,8 +386,12 @@
   return oat_file_assistant.GetDexOptNeeded();
 }
 
-static jint DexFile_getDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename,
-    jstring javaPkgname, jstring javaInstructionSet, jboolean defer) {
+static jint DexFile_getDexOptNeeded(JNIEnv* env,
+                                    jclass,
+                                    jstring javaFilename,
+                                    jstring javaPkgname,
+                                    jstring javaInstructionSet,
+                                    jboolean defer) {
   ScopedUtfChars filename(env, javaFilename);
   if (env->ExceptionCheck()) {
     return 0;
@@ -379,8 +404,11 @@
     return 0;
   }
 
-  return GetDexOptNeeded(env, filename.c_str(), pkgname.c_str(),
-                         instruction_set.c_str(), defer);
+  return GetDexOptNeeded(env,
+                         filename.c_str(),
+                         pkgname.c_str(),
+                         instruction_set.c_str(),
+                         defer);
 }
 
 // public API, null pkgname
diff --git a/runtime/native/dalvik_system_DexFile.h b/runtime/native/dalvik_system_DexFile.h
index 7585ab9..77d219d 100644
--- a/runtime/native/dalvik_system_DexFile.h
+++ b/runtime/native/dalvik_system_DexFile.h
@@ -18,9 +18,13 @@
 #define ART_RUNTIME_NATIVE_DALVIK_SYSTEM_DEXFILE_H_
 
 #include <jni.h>
+#include <unistd.h>
 
 namespace art {
 
+constexpr size_t kOatFileIndex = 0;
+constexpr size_t kDexFileIndexStart = 1;
+
 class DexFile;
 
 void register_dalvik_system_DexFile(JNIEnv* env);
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 80f017d..6cbbce9 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -122,21 +122,29 @@
   // and for having dex caches arrays in the .bss section.
   Runtime* const runtime = Runtime::Current();
   OatFileManager* const manager = (runtime != nullptr) ? &runtime->GetOatFileManager() : nullptr;
-  if (kUseDlopen &&
-      (kIsTargetBuild ||
-          (kUseDlopenOnHost &&
-           // Manager may be null if we are running without a runtime.
-           manager != nullptr &&
-           manager->FindOpenedOatFileFromOatLocation(location) == nullptr)) &&
-      executable) {
-    // Try to use dlopen. This may fail for various reasons, outlined below. We try dlopen, as
-    // this will register the oat file with the linker and allows libunwind to find our info.
-    ret.reset(OpenDlopen(filename, location, requested_base, abs_dex_location, error_msg));
-    if (ret.get() != nullptr) {
-      return ret.release();
+  if (kUseDlopen && executable) {
+    bool success = kIsTargetBuild;
+    bool reserved_location = false;
+      // Manager may be null if we are running without a runtime.
+    if (!success && kUseDlopenOnHost && manager != nullptr) {
+      // RegisterOatFileLocation returns false if we are not the first caller to register that
+      // location.
+      reserved_location = manager->RegisterOatFileLocation(location);
+      success = reserved_location;
     }
-    if (kPrintDlOpenErrorMessage) {
-      LOG(ERROR) << "Failed to dlopen: " << *error_msg;
+    if (success) {
+      // Try to use dlopen. This may fail for various reasons, outlined below. We try dlopen, as
+      // this will register the oat file with the linker and allows libunwind to find our info.
+      ret.reset(OpenDlopen(filename, location, requested_base, abs_dex_location, error_msg));
+      if (reserved_location) {
+        manager->UnRegisterOatFileLocation(location);
+      }
+      if (ret != nullptr) {
+        return ret.release();
+      }
+      if (kPrintDlOpenErrorMessage) {
+        LOG(ERROR) << "Failed to dlopen: " << *error_msg;
+      }
     }
   }
 
@@ -217,6 +225,10 @@
       is_executable_(is_executable), dlopen_handle_(nullptr),
       secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) {
   CHECK(!location_.empty());
+  Runtime* const runtime = Runtime::Current();
+  if (runtime != nullptr && !runtime->IsAotCompiler()) {
+    runtime->GetOatFileManager().RegisterOatFileLocation(location);
+  }
 }
 
 OatFile::~OatFile() {
@@ -224,6 +236,10 @@
   if (dlopen_handle_ != nullptr) {
     dlclose(dlopen_handle_);
   }
+  Runtime* const runtime = Runtime::Current();
+  if (runtime != nullptr && !runtime->IsAotCompiler()) {
+    runtime->GetOatFileManager().UnRegisterOatFileLocation(location_);
+  }
 }
 
 bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base,
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index de4e8ec..cef8702 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -961,13 +961,16 @@
     // we can verify only one oat file was loaded for the dex location.
     std::vector<std::unique_ptr<const DexFile>> dex_files;
     std::vector<std::string> error_msgs;
+    const OatFile* oat_file = nullptr;
     dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
         dex_location_.c_str(),
         oat_location_.c_str(),
+        &oat_file,
         &error_msgs);
     CHECK(!dex_files.empty()) << Join(error_msgs, '\n');
     CHECK(dex_files[0]->GetOatDexFile() != nullptr) << dex_files[0]->GetLocation();
     loaded_oat_file_ = dex_files[0]->GetOatDexFile()->GetOatFile();
+    CHECK_EQ(loaded_oat_file_, oat_file);
   }
 
   const OatFile* GetLoadedOatFile() const {
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 73b065f..3371a39 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -33,9 +33,10 @@
 static constexpr bool kDuplicateClassesCheck = false;
 
 const OatFile* OatFileManager::RegisterOatFile(std::unique_ptr<const OatFile> oat_file) {
-  ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
+  WriterMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
   DCHECK(oat_file != nullptr);
   if (kIsDebugBuild) {
+    CHECK(oat_files_.find(oat_file) == oat_files_.end());
     for (const std::unique_ptr<const OatFile>& existing : oat_files_) {
       CHECK_NE(oat_file.get(), existing.get()) << oat_file->GetLocation();
       // Check that we don't have an oat file with the same address. Copies of the same oat file
@@ -44,13 +45,29 @@
     }
   }
   have_non_pic_oat_file_ = have_non_pic_oat_file_ || !oat_file->IsPic();
-  oat_files_.push_back(std::move(oat_file));
-  return oat_files_.back().get();
+  const OatFile* ret = oat_file.get();
+  oat_files_.insert(std::move(oat_file));
+  return ret;
+}
+
+void OatFileManager::UnRegisterAndDeleteOatFile(const OatFile* oat_file) {
+  WriterMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
+  DCHECK(oat_file != nullptr);
+  std::unique_ptr<const OatFile> compare(oat_file);
+  auto it = oat_files_.find(compare);
+  CHECK(it != oat_files_.end());
+  oat_files_.erase(it);
+  compare.release();
 }
 
 const OatFile* OatFileManager::FindOpenedOatFileFromOatLocation(const std::string& oat_location)
     const {
   ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
+  return FindOpenedOatFileFromOatLocationLocked(oat_location);
+}
+
+const OatFile* OatFileManager::FindOpenedOatFileFromOatLocationLocked(
+    const std::string& oat_location) const {
   for (const std::unique_ptr<const OatFile>& oat_file : oat_files_) {
     if (oat_file->GetLocation() == oat_location) {
       return oat_file.get();
@@ -81,6 +98,9 @@
 }
 
 OatFileManager::~OatFileManager() {
+  // Explicitly clear oat_files_ since the OatFile destructor calls back into OatFileManager for
+  // UnRegisterOatFileLocation.
+  oat_files_.clear();
 }
 
 const OatFile* OatFileManager::RegisterImageOatFile(gc::space::ImageSpace* space) {
@@ -95,17 +115,9 @@
        current_class_index_(current_class_index),
        from_loaded_oat_(from_loaded_oat) {}
 
-  DexFileAndClassPair(DexFileAndClassPair&& rhs) {
-    *this = std::move(rhs);
-  }
+  DexFileAndClassPair(DexFileAndClassPair&& rhs) = default;
 
-  DexFileAndClassPair& operator=(DexFileAndClassPair&& rhs) {
-    cached_descriptor_ = rhs.cached_descriptor_;
-    dex_file_ = std::move(rhs.dex_file_);
-    current_class_index_ = rhs.current_class_index_;
-    from_loaded_oat_ = rhs.from_loaded_oat_;
-    return *this;
-  }
+  DexFileAndClassPair& operator=(DexFileAndClassPair&& rhs) = default;
 
   const char* GetCachedDescriptor() const {
     return cached_descriptor_;
@@ -127,6 +139,7 @@
 
   void Next() {
     ++current_class_index_;
+    cached_descriptor_ = nullptr;
   }
 
   size_t GetCurrentClassIndex() const {
@@ -253,6 +266,7 @@
 std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
     const char* dex_location,
     const char* oat_location,
+    const OatFile** out_oat_file,
     std::vector<std::string>* error_msgs) {
   CHECK(dex_location != nullptr);
   CHECK(error_msgs != nullptr);
@@ -311,6 +325,7 @@
     if (accept_oat_file) {
       VLOG(class_linker) << "Registering " << oat_file->GetLocation();
       source_oat_file = RegisterOatFile(std::move(oat_file));
+      *out_oat_file = source_oat_file;
     }
   }
 
@@ -344,4 +359,26 @@
   return dex_files;
 }
 
+bool OatFileManager::RegisterOatFileLocation(const std::string& oat_location) {
+  WriterMutexLock mu(Thread::Current(), *Locks::oat_file_count_lock_);
+  auto it = oat_file_count_.find(oat_location);
+  if (it != oat_file_count_.end()) {
+    ++it->second;
+    return false;
+  }
+  oat_file_count_.insert(std::pair<std::string, size_t>(oat_location, 1u));
+  return true;
+}
+
+void OatFileManager::UnRegisterOatFileLocation(const std::string& oat_location) {
+  WriterMutexLock mu(Thread::Current(), *Locks::oat_file_count_lock_);
+  auto it = oat_file_count_.find(oat_location);
+  if (it != oat_file_count_.end()) {
+    --it->second;
+    if (it->second == 0) {
+      oat_file_count_.erase(it);
+    }
+  }
+}
+
 }  // namespace art
diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h
index 3059cb5..af7efb4 100644
--- a/runtime/oat_file_manager.h
+++ b/runtime/oat_file_manager.h
@@ -18,7 +18,9 @@
 #define ART_RUNTIME_OAT_FILE_MANAGER_H_
 
 #include <memory>
+#include <set>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "base/macros.h"
@@ -49,10 +51,23 @@
   const OatFile* RegisterOatFile(std::unique_ptr<const OatFile> oat_file)
       REQUIRES(!Locks::oat_file_manager_lock_);
 
+  void UnRegisterAndDeleteOatFile(const OatFile* oat_file)
+      REQUIRES(!Locks::oat_file_manager_lock_);
+
   // Find the first opened oat file with the same location, returns null if there are none.
   const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location) const
       REQUIRES(!Locks::oat_file_manager_lock_);
 
+  // Attempt to reserve a location, returns false if it is already reserved or already in used by
+  // an oat file.
+  bool RegisterOatFileLocation(const std::string& oat_location)
+      REQUIRES(!Locks::oat_file_count_lock_);
+
+  // Unreserve oat file location, should only be used for error cases since RegisterOatFile will
+  // remove the reserved location.
+  void UnRegisterOatFileLocation(const std::string& oat_location)
+      REQUIRES(!Locks::oat_file_count_lock_);
+
   // Returns true if we have a non pic oat file.
   bool HaveNonPicOatFile() const {
     return have_non_pic_oat_file_;
@@ -86,7 +101,8 @@
   std::vector<std::unique_ptr<const DexFile>> OpenDexFilesFromOat(
       const char* dex_location,
       const char* oat_location,
-      /*out*/std::vector<std::string>* error_msgs)
+      /*out*/ const OatFile** out_oat_file,
+      /*out*/ std::vector<std::string>* error_msgs)
       REQUIRES(!Locks::oat_file_manager_lock_, !Locks::mutator_lock_);
 
  private:
@@ -95,7 +111,11 @@
   bool HasCollisions(const OatFile* oat_file, /*out*/std::string* error_msg) const
       REQUIRES(!Locks::oat_file_manager_lock_);
 
-  std::vector<std::unique_ptr<const OatFile>> oat_files_ GUARDED_BY(Locks::oat_file_manager_lock_);
+  const OatFile* FindOpenedOatFileFromOatLocationLocked(const std::string& oat_location) const
+      REQUIRES(Locks::oat_file_manager_lock_);
+
+  std::set<std::unique_ptr<const OatFile>> oat_files_ GUARDED_BY(Locks::oat_file_manager_lock_);
+  std::unordered_map<std::string, size_t> oat_file_count_ GUARDED_BY(Locks::oat_file_count_lock_);
   bool have_non_pic_oat_file_;
   DISALLOW_COPY_AND_ASSIGN(OatFileManager);
 };
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 50e2053..ae16c7f 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -269,10 +269,10 @@
       .Define("-Xfingerprint:_")
           .WithType<std::string>()
           .IntoKey(M::Fingerprint)
-      .Define({"-Xexperimental-lambdas", "-Xnoexperimental-lambdas"})
-          .WithType<bool>()
-          .WithValues({true, false})
-          .IntoKey(M::ExperimentalLambdas)
+      .Define("-Xexperimental:_")
+          .WithType<ExperimentalFlags>()
+          .AppendValues()
+          .IntoKey(M::Experimental)
       .Ignore({
           "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
           "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
@@ -557,7 +557,14 @@
     args.Set(M::HeapGrowthLimit, args.GetOrDefault(M::MemoryMaximumSize));
   }
 
-  if (args.GetOrDefault(M::ExperimentalLambdas)) {
+  if (args.GetOrDefault(M::Experimental) & ExperimentalFlags::kDefaultMethods) {
+    LOG(WARNING) << "Default method support has been enabled. The verifier will be less strict "
+                 << "in some cases. All existing invoke opcodes have an unstable updated "
+                 << "specification and are nearly guaranteed to change over time. Do not attempt "
+                 << "to write shipping code against the invoke opcodes with this flag.";
+  }
+
+  if (args.GetOrDefault(M::Experimental) & ExperimentalFlags::kLambdas) {
     LOG(WARNING) << "Experimental lambdas have been enabled. All lambda opcodes have "
                  << "an unstable specification and are nearly guaranteed to change over time. "
                  << "Do not attempt to write shipping code against these opcodes.";
@@ -682,8 +689,8 @@
   UsageMessage(stream, "  -X[no]image-dex2oat (Whether to create and use a boot image)\n");
   UsageMessage(stream, "  -Xno-dex-file-fallback "
                        "(Don't fall back to dex files without oat files)\n");
-  UsageMessage(stream, "  -X[no]experimental-lambdas\n"
-                       "     (Enable new experimental dalvik opcodes, off by default)\n");
+  UsageMessage(stream, "  -Xexperimental:{lambdas,default-methods} "
+                       "(Enable new experimental dalvik opcodes and semantics, off by default)\n");
   UsageMessage(stream, "\n");
 
   UsageMessage(stream, "The following previously supported Dalvik options are ignored:\n");
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7a1f0af..cd09bee 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -64,6 +64,7 @@
 #include "debugger.h"
 #include "elf_file.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
+#include "experimental_flags.h"
 #include "fault_handler.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
@@ -199,7 +200,7 @@
       no_sig_chain_(false),
       is_native_bridge_loaded_(false),
       zygote_max_failed_boots_(0),
-      experimental_lambdas_(false) {
+      experimental_flags_(ExperimentalFlags::kNone) {
   CheckAsmSupportOffsetsAndSizes();
   std::fill(callee_save_methods_, callee_save_methods_ + arraysize(callee_save_methods_), 0u);
 }
@@ -282,10 +283,10 @@
   delete monitor_list_;
   delete monitor_pool_;
   delete class_linker_;
-  oat_file_manager_.reset();
   delete heap_;
   delete intern_table_;
   delete java_vm_;
+  delete oat_file_manager_;
   Thread::Shutdown();
   QuasiAtomic::Shutdown();
   verifier::MethodVerifier::Shutdown();
@@ -833,7 +834,7 @@
 
   QuasiAtomic::Startup();
 
-  oat_file_manager_.reset(new OatFileManager);
+  oat_file_manager_ = new OatFileManager;
 
   Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold),
                 runtime_options.GetOrDefault(Opt::HookIsSensitiveThread));
@@ -884,7 +885,7 @@
   }
 
   zygote_max_failed_boots_ = runtime_options.GetOrDefault(Opt::ZygoteMaxFailedBoots);
-  experimental_lambdas_ = runtime_options.GetOrDefault(Opt::ExperimentalLambdas);
+  experimental_flags_ = runtime_options.GetOrDefault(Opt::Experimental);
 
   XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption);
   ATRACE_BEGIN("CreateHeap");
diff --git a/runtime/runtime.h b/runtime/runtime.h
index abccb44..458f08a 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -28,6 +28,7 @@
 
 #include "arch/instruction_set.h"
 #include "base/macros.h"
+#include "experimental_flags.h"
 #include "gc_root.h"
 #include "instrumentation.h"
 #include "jobject_comparator.h"
@@ -532,8 +533,8 @@
     return zygote_max_failed_boots_;
   }
 
-  bool AreExperimentalLambdasEnabled() const {
-    return experimental_lambdas_;
+  bool AreExperimentalFlagsEnabled(ExperimentalFlags flags) {
+    return (experimental_flags_ & flags) != ExperimentalFlags::kNone;
   }
 
   lambda::BoxTable* GetLambdaBoxTable() const {
@@ -576,7 +577,7 @@
 
   OatFileManager& GetOatFileManager() const {
     DCHECK(oat_file_manager_ != nullptr);
-    return *oat_file_manager_.get();
+    return *oat_file_manager_;
   }
 
  private:
@@ -769,7 +770,7 @@
   // eventually publish them as public-usable opcodes, but they aren't ready yet.
   //
   // Experimental opcodes should not be used by other production code.
-  bool experimental_lambdas_;
+  ExperimentalFlags experimental_flags_;
 
   MethodRefToStringInitRegMap method_ref_string_init_reg_map_;
 
@@ -777,7 +778,7 @@
   std::string fingerprint_;
 
   // Oat file manager, keeps track of what oat files are open.
-  std::unique_ptr<OatFileManager> oat_file_manager_;
+  OatFileManager* oat_file_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(Runtime);
 };
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index d88e84b..7b5bc1a 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -114,7 +114,7 @@
 RUNTIME_OPTIONS_KEY (Unit,                NoDexFileFallback)
 RUNTIME_OPTIONS_KEY (std::string,         CpuAbiList)
 RUNTIME_OPTIONS_KEY (std::string,         Fingerprint)
-RUNTIME_OPTIONS_KEY (bool,                ExperimentalLambdas,            false) // -X[no]experimental-lambdas
+RUNTIME_OPTIONS_KEY (ExperimentalFlags,   Experimental,     ExperimentalFlags::kNone) // -Xexperimental:{, lambdas, default-methods}
 
 // Not parse-able from command line, but can be provided explicitly.
 // (Do not add anything here that is defined in ParsedOptions::MakeParser)
diff --git a/runtime/thread.h b/runtime/thread.h
index 8cea10c..8f3461a 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -626,6 +626,24 @@
     return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values, thread_local_objects));
   }
 
+  template<size_t pointer_size>
+  static ThreadOffset<pointer_size> RosAllocRunsOffset() {
+    return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values,
+                                                                rosalloc_runs));
+  }
+
+  template<size_t pointer_size>
+  static ThreadOffset<pointer_size> ThreadLocalAllocStackTopOffset() {
+    return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values,
+                                                                thread_local_alloc_stack_top));
+  }
+
+  template<size_t pointer_size>
+  static ThreadOffset<pointer_size> ThreadLocalAllocStackEndOffset() {
+    return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values,
+                                                                thread_local_alloc_stack_end));
+  }
+
   // Size of stack less any space reserved for stack overflow
   size_t GetStackSize() const {
     return tlsPtr_.stack_size - (tlsPtr_.stack_end - tlsPtr_.stack_begin);
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index eed3e22..4051a1c 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -30,6 +30,7 @@
 #include "dex_instruction-inl.h"
 #include "dex_instruction_utils.h"
 #include "dex_instruction_visitor.h"
+#include "experimental_flags.h"
 #include "gc/accounting/card_table-inl.h"
 #include "indenter.h"
 #include "intern_table.h"
@@ -560,6 +561,7 @@
 bool MethodVerifier::Verify() {
   // Some older code doesn't correctly mark constructors as such. Test for this case by looking at
   // the name.
+  Runtime* runtime = Runtime::Current();
   const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
   const char* method_name = dex_file_->StringDataByIdx(method_id.name_idx_);
   bool instance_constructor_by_name = strcmp("<init>", method_name) == 0;
@@ -628,9 +630,13 @@
         }
       }
       if ((class_def_->GetJavaAccessFlags() & kAccInterface) != 0) {
-        // Interface methods must be public and abstract.
-        if ((method_access_flags_ & (kAccPublic | kAccAbstract)) != (kAccPublic | kAccAbstract)) {
-          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be public and abstract";
+        // Interface methods must be public and abstract (if default methods are disabled).
+        bool default_methods_supported =
+            runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods);
+        uint32_t kRequired = kAccPublic | (default_methods_supported ? 0 : kAccAbstract);
+        if ((method_access_flags_ & kRequired) != kRequired) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be public"
+                                            << (default_methods_supported ? "" : " and abstract");
           return false;
         }
         // In addition to the above, interface methods must not be protected.
@@ -657,10 +663,22 @@
       return false;
     }
 
-    // Only the static initializer may have code in an interface.
     if ((class_def_->GetJavaAccessFlags() & kAccInterface) != 0) {
-      // Interfaces may have static initializers for their fields.
-      if (!IsConstructor() || !IsStatic()) {
+      // Interfaces may always have static initializers for their fields. If we are running with
+      // default methods enabled we also allow other public, static, non-final methods to have code.
+      // Otherwise that is the only type of method allowed.
+      if (runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) {
+        if (IsInstanceConstructor()) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-static constructor";
+          return false;
+        } else if (method_access_flags_ & kAccFinal) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have final methods";
+          return false;
+        } else if (!(method_access_flags_ & kAccPublic)) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-public members";
+          return false;
+        }
+      } else if (!IsConstructor() || !IsStatic()) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be abstract";
         return false;
       }
@@ -682,6 +700,7 @@
                                       << " regs=" << code_item_->registers_size_;
     return false;
   }
+
   // Allocate and initialize an array to hold instruction data.
   insn_flags_.reset(new InstructionFlags[code_item_->insns_size_in_code_units_]());
   // Run through the instructions and see if the width checks out.
@@ -693,8 +712,8 @@
   // Perform code-flow analysis and return.
   result = result && VerifyCodeFlow();
   // Compute information for compiler.
-  if (result && Runtime::Current()->IsCompiler()) {
-    result = Runtime::Current()->GetCompilerCallbacks()->MethodVerified(this);
+  if (result && runtime->IsCompiler()) {
+    result = runtime->GetCompilerCallbacks()->MethodVerified(this);
   }
   return result;
 }
diff --git a/test/141-class-unload/expected.txt b/test/141-class-unload/expected.txt
index 53d7abe..11de660 100644
--- a/test/141-class-unload/expected.txt
+++ b/test/141-class-unload/expected.txt
@@ -21,3 +21,4 @@
 JNI_OnLoad called
 class null false test
 JNI_OnUnload called
+Number of loaded unload-ex maps 0
diff --git a/test/141-class-unload/src/Main.java b/test/141-class-unload/src/Main.java
index 3cc43ac..0640b36 100644
--- a/test/141-class-unload/src/Main.java
+++ b/test/141-class-unload/src/Main.java
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
@@ -43,11 +46,28 @@
             testStackTrace(constructor);
             // Stress test to make sure we dont leak memory.
             stressTest(constructor);
+            // Test that the oat files are unloaded.
+            testOatFilesUnloaded(getPid());
         } catch (Exception e) {
             System.out.println(e);
         }
     }
 
+    private static void testOatFilesUnloaded(int pid) throws Exception {
+        BufferedReader reader = new BufferedReader(new FileReader ("/proc/" + pid + "/maps"));
+        String line;
+        int count = 0;
+        Runtime.getRuntime().gc();
+        System.runFinalization();
+        while ((line = reader.readLine()) != null) {
+            if (line.contains("@141-class-unload-ex.jar")) {
+                System.out.println(line);
+                ++count;
+            }
+        }
+        System.out.println("Number of loaded unload-ex maps " + count);
+    }
+
     private static void stressTest(Constructor constructor) throws Exception {
         for (int i = 0; i <= 100; ++i) {
             setUpUnloadLoader(constructor, false);
@@ -163,4 +183,8 @@
         loadLibrary.invoke(intHolder, nativeLibraryName);
         return new WeakReference(loader);
     }
+
+    private static int getPid() throws Exception {
+      return Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());
+    }
 }
diff --git a/test/538-checker-embed-constants/expected.txt b/test/538-checker-embed-constants/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/538-checker-embed-constants/expected.txt
diff --git a/test/538-checker-embed-constants/info.txt b/test/538-checker-embed-constants/info.txt
new file mode 100644
index 0000000..5a722ec
--- /dev/null
+++ b/test/538-checker-embed-constants/info.txt
@@ -0,0 +1 @@
+Test embedding of constants in assembler instructions.
diff --git a/test/538-checker-embed-constants/src/Main.java b/test/538-checker-embed-constants/src/Main.java
new file mode 100644
index 0000000..d8618e3
--- /dev/null
+++ b/test/538-checker-embed-constants/src/Main.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+
+  public static void assertIntEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertLongEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  /// CHECK-START-ARM: int Main.and255(int) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK:                and {{r\d+}}, {{r\d+}}, #255
+
+  public static int and255(int arg) {
+    return arg & 255;
+  }
+
+  /// CHECK-START-ARM: int Main.and511(int) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK:                and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+
+  public static int and511(int arg) {
+    return arg & 511;
+  }
+
+  /// CHECK-START-ARM: int Main.andNot15(int) disassembly (after)
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK:                bic {{r\d+}}, {{r\d+}}, #15
+
+  public static int andNot15(int arg) {
+    return arg & ~15;
+  }
+
+  /// CHECK-START-ARM: int Main.or255(int) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK:                orr {{r\d+}}, {{r\d+}}, #255
+
+  public static int or255(int arg) {
+    return arg | 255;
+  }
+
+  /// CHECK-START-ARM: int Main.or511(int) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK:                orr{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+
+  public static int or511(int arg) {
+    return arg | 511;
+  }
+
+  /// CHECK-START-ARM: int Main.orNot15(int) disassembly (after)
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK:                orn {{r\d+}}, {{r\d+}}, #15
+
+  public static int orNot15(int arg) {
+    return arg | ~15;
+  }
+
+  /// CHECK-START-ARM: int Main.xor255(int) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK:                eor {{r\d+}}, {{r\d+}}, #255
+
+  public static int xor255(int arg) {
+    return arg ^ 255;
+  }
+
+  /// CHECK-START-ARM: int Main.xor511(int) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK:                eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+
+  public static int xor511(int arg) {
+    return arg ^ 511;
+  }
+
+  /// CHECK-START-ARM: int Main.xorNot15(int) disassembly (after)
+  /// CHECK:                mvn {{r\d+}}, #15
+  /// CHECK:                eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+
+  public static int xorNot15(int arg) {
+    return arg ^ ~15;
+  }
+
+  /// CHECK-START-ARM: long Main.and255(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+  /// CHECK-DAG:            and {{r\d+}}, {{r\d+}}, #255
+  /// CHECK-DAG:            movs {{r\d+}}, #0
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+
+  public static long and255(long arg) {
+    return arg & 255L;
+  }
+
+  /// CHECK-START-ARM: long Main.and511(long) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+  /// CHECK-DAG:            and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-DAG:            movs {{r\d+}}, #0
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+
+  public static long and511(long arg) {
+    return arg & 511L;
+  }
+
+  /// CHECK-START-ARM: long Main.andNot15(long) disassembly (after)
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+  /// CHECK:                bic {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+
+  public static long andNot15(long arg) {
+    return arg & ~15L;
+  }
+
+  /// CHECK-START-ARM: long Main.and0xfffffff00000000f(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #15
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+  /// CHECK-DAG:            and {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-DAG:            bic {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+
+  public static long and0xfffffff00000000f(long arg) {
+    return arg & 0xfffffff00000000fL;
+  }
+
+  /// CHECK-START-ARM: long Main.or255(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+  /// CHECK:                orr {{r\d+}}, {{r\d+}}, #255
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+
+  public static long or255(long arg) {
+    return arg | 255L;
+  }
+
+  /// CHECK-START-ARM: long Main.or511(long) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+  /// CHECK:                orr{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+
+  public static long or511(long arg) {
+    return arg | 511L;
+  }
+
+  /// CHECK-START-ARM: long Main.orNot15(long) disassembly (after)
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+  /// CHECK-DAG:            orn {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-DAG:            mvn {{r\d+}}, #0
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+
+  public static long orNot15(long arg) {
+    return arg | ~15L;
+  }
+
+  /// CHECK-START-ARM: long Main.or0xfffffff00000000f(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #15
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+  /// CHECK-DAG:            orr {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-DAG:            orn {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+
+  public static long or0xfffffff00000000f(long arg) {
+    return arg | 0xfffffff00000000fL;
+  }
+
+  /// CHECK-START-ARM: long Main.xor255(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK-NOT:            eor
+  /// CHECK:                eor {{r\d+}}, {{r\d+}}, #255
+  /// CHECK-NOT:            eor
+
+  public static long xor255(long arg) {
+    return arg ^ 255L;
+  }
+
+  /// CHECK-START-ARM: long Main.xor511(long) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK-NOT:            eor
+  /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NOT:            eor
+
+  public static long xor511(long arg) {
+    return arg ^ 511L;
+  }
+
+  /// CHECK-START-ARM: long Main.xorNot15(long) disassembly (after)
+  /// CHECK-DAG:            mvn {{r\d+}}, #15
+  /// CHECK-DAG:            mov.w {{r\d+}}, #-1
+  /// CHECK-NOT:            eor
+  /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NOT:            eor
+
+  public static long xorNot15(long arg) {
+    return arg ^ ~15L;
+  }
+
+  // Note: No support for partial long constant embedding.
+  /// CHECK-START-ARM: long Main.xor0xfffffff00000000f(long) disassembly (after)
+  /// CHECK-DAG:            movs {{r\d+}}, #15
+  /// CHECK-DAG:            mvn {{r\d+}}, #15
+  /// CHECK-NOT:            eor
+  /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NOT:            eor
+
+  public static long xor0xfffffff00000000f(long arg) {
+    return arg ^ 0xfffffff00000000fL;
+  }
+
+  /// CHECK-START-ARM: long Main.xor0xf00000000000000f(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #15
+  /// CHECK-NOT:            mov.w {{r\d+}}, #-268435456
+  /// CHECK-NOT:            eor
+  /// CHECK-DAG:            eor {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-DAG:            eor {{r\d+}}, {{r\d+}}, #-268435456
+  /// CHECK-NOT:            eor
+
+  public static long xor0xf00000000000000f(long arg) {
+    return arg ^ 0xf00000000000000fL;
+  }
+
+  public static void main(String[] args) {
+    int arg = 0x87654321;
+    assertIntEquals(and255(arg), 0x21);
+    assertIntEquals(and511(arg), 0x121);
+    assertIntEquals(andNot15(arg), 0x87654320);
+    assertIntEquals(or255(arg), 0x876543ff);
+    assertIntEquals(or511(arg), 0x876543ff);
+    assertIntEquals(orNot15(arg), 0xfffffff1);
+    assertIntEquals(xor255(arg), 0x876543de);
+    assertIntEquals(xor511(arg), 0x876542de);
+    assertIntEquals(xorNot15(arg), 0x789abcd1);
+
+    long longArg = 0x1234567887654321L;
+    assertLongEquals(and255(longArg), 0x21L);
+    assertLongEquals(and511(longArg), 0x121L);
+    assertLongEquals(andNot15(longArg), 0x1234567887654320L);
+    assertLongEquals(and0xfffffff00000000f(longArg), 0x1234567000000001L);
+    assertLongEquals(or255(longArg), 0x12345678876543ffL);
+    assertLongEquals(or511(longArg), 0x12345678876543ffL);
+    assertLongEquals(orNot15(longArg), 0xfffffffffffffff1L);
+    assertLongEquals(or0xfffffff00000000f(longArg), 0xfffffff88765432fL);
+    assertLongEquals(xor255(longArg), 0x12345678876543deL);
+    assertLongEquals(xor511(longArg), 0x12345678876542deL);
+    assertLongEquals(xorNot15(longArg), 0xedcba987789abcd1L);
+    assertLongEquals(xor0xfffffff00000000f(longArg), 0xedcba9888765432eL);
+    assertLongEquals(xor0xf00000000000000f(longArg), 0xe23456788765432eL);
+  }
+}
diff --git a/test/955-lambda-smali/run b/test/955-lambda-smali/run
index 2aeca8c..b754680 100755
--- a/test/955-lambda-smali/run
+++ b/test/955-lambda-smali/run
@@ -15,4 +15,4 @@
 # limitations under the License.
 
 # Ensure that the lambda experimental opcodes are turned on for dalvikvm and dex2oat
-${RUN} "$@" --runtime-option -Xexperimental-lambdas -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental-lambdas
+${RUN} "$@" --runtime-option -Xexperimental:lambdas -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:lambdas
diff --git a/test/960-default-smali/build b/test/960-default-smali/build
new file mode 100755
index 0000000..c786687
--- /dev/null
+++ b/test/960-default-smali/build
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# make us exit on a failure
+set -e
+
+# Generate the smali Main.smali file or fail
+./util-src/generate_smali.py ./smali
+
+if [[ $@ == *"--jvm"* ]]; then
+  # Build the Java files if we are running a --jvm test
+  mkdir -p src
+  mkdir -p classes
+  ${ANDROID_BUILD_TOP}/art/tools/extract-embedded-java ./smali ./src
+  ${JAVAC} -implicit:none -d classes $(find src -name '*.java')
+fi
+
+# Build the smali files and make a dex
+${SMALI} -JXmx256m --experimental --api-level 23 --output classes.dex $(find smali -name '*.smali')
+zip "$TEST_NAME.jar" classes.dex
diff --git a/test/960-default-smali/expected.txt b/test/960-default-smali/expected.txt
new file mode 100644
index 0000000..7671eed
--- /dev/null
+++ b/test/960-default-smali/expected.txt
@@ -0,0 +1,84 @@
+Testing for type A
+A-virtual           A.SayHi()='Hi '
+A-interface   Greeter.SayHi()='Hi '
+A-virtual           A.SayHiTwice()='Hi Hi '
+A-interface   Greeter.SayHiTwice()='Hi Hi '
+End testing for type A
+Testing for type B
+B-virtual           B.SayHi()='Hello '
+B-interface   Greeter.SayHi()='Hello '
+B-interface  Greeter2.SayHi()='Hello '
+B-virtual           B.SayHiTwice()='I say Hello Hello '
+B-interface   Greeter.SayHiTwice()='I say Hello Hello '
+B-interface  Greeter2.SayHiTwice()='I say Hello Hello '
+End testing for type B
+Testing for type C
+C-virtual           A.SayHi()='Hi '
+C-virtual           C.SayHi()='Hi '
+C-interface   Greeter.SayHi()='Hi '
+C-virtual           A.SayHiTwice()='You don't control me'
+C-virtual           C.SayHiTwice()='You don't control me'
+C-interface   Greeter.SayHiTwice()='You don't control me'
+End testing for type C
+Testing for type D
+D-virtual           D.GetName()='Alex '
+D-interface  Greeter3.GetName()='Alex '
+D-virtual           D.SayHi()='Hello Alex '
+D-interface   Greeter.SayHi()='Hello Alex '
+D-interface  Greeter3.SayHi()='Hello Alex '
+D-virtual           D.SayHiTwice()='Hello Alex Hello Alex '
+D-interface   Greeter.SayHiTwice()='Hello Alex Hello Alex '
+D-interface  Greeter3.SayHiTwice()='Hello Alex Hello Alex '
+End testing for type D
+Testing for type E
+E-virtual           A.SayHi()='Hi2 '
+E-virtual           E.SayHi()='Hi2 '
+E-interface   Greeter.SayHi()='Hi2 '
+E-interface  Greeter2.SayHi()='Hi2 '
+E-virtual           A.SayHiTwice()='I say Hi2 Hi2 '
+E-virtual           E.SayHiTwice()='I say Hi2 Hi2 '
+E-interface   Greeter.SayHiTwice()='I say Hi2 Hi2 '
+E-interface  Greeter2.SayHiTwice()='I say Hi2 Hi2 '
+End testing for type E
+Testing for type F
+F-interface Attendant.GetPlace()='android'
+F-virtual           F.GetPlace()='android'
+F-virtual           A.SayHi()='Hi '
+F-interface Attendant.SayHi()='Hi '
+F-virtual           F.SayHi()='Hi '
+F-interface   Greeter.SayHi()='Hi '
+F-virtual           A.SayHiTwice()='We can override both interfaces'
+F-interface Attendant.SayHiTwice()='We can override both interfaces'
+F-virtual           F.SayHiTwice()='We can override both interfaces'
+F-interface   Greeter.SayHiTwice()='We can override both interfaces'
+End testing for type F
+Testing for type G
+G-interface Attendant.GetPlace()='android'
+G-virtual           G.GetPlace()='android'
+G-interface Attendant.SayHi()='welcome to android'
+G-virtual           G.SayHi()='welcome to android'
+G-interface Attendant.SayHiTwice()='welcome to androidwelcome to android'
+G-virtual           G.SayHiTwice()='welcome to androidwelcome to android'
+End testing for type G
+Testing for type H
+H-interface Extension.SayHi()='welcome '
+H-virtual           H.SayHi()='welcome '
+End testing for type H
+Testing for type I
+I-virtual           A.SayHi()='Hi '
+I-interface   Greeter.SayHi()='Hi '
+I-interface  Greeter2.SayHi()='Hi '
+I-virtual           I.SayHi()='Hi '
+I-virtual           A.SayHiTwice()='I say Hi Hi '
+I-interface   Greeter.SayHiTwice()='I say Hi Hi '
+I-interface  Greeter2.SayHiTwice()='I say Hi Hi '
+I-virtual           I.SayHiTwice()='I say Hi Hi '
+End testing for type I
+Testing for type J
+J-virtual           A.SayHi()='Hi '
+J-interface   Greeter.SayHi()='Hi '
+J-virtual           J.SayHi()='Hi '
+J-virtual           A.SayHiTwice()='Hi Hi '
+J-interface   Greeter.SayHiTwice()='Hi Hi '
+J-virtual           J.SayHiTwice()='Hi Hi '
+End testing for type J
diff --git a/test/960-default-smali/info.txt b/test/960-default-smali/info.txt
new file mode 100644
index 0000000..eb596e2
--- /dev/null
+++ b/test/960-default-smali/info.txt
@@ -0,0 +1,19 @@
+Smali-based tests for experimental interface default methods.
+
+Obviously needs to run under ART or a Java 8 Language runtime and compiler.
+
+When run a Main.smali file will be generated by the util-src/generate_smali.py
+script. If we run with --jvm we will use the tools/extract-embedded-java script to
+turn the smali into equivalent Java using the embedded Java code.
+
+When updating be sure to write the equivalent Java code in comments of the smali
+files.
+
+Care should be taken when updating the generate_smali.py script. It must always
+return equivalent output when run multiple times.
+
+To update the test files do the following steps:
+    <Add new classes/interfaces>
+    <Add these classes/interfaces to ./smali/classes.xml>
+    JAVA_HOME="/path/to/java-8-jdk" ../run-test --use-java-home --update --jvm --host 956-default-smali
+    git add ./smali/classes.xml ./expected.txt
diff --git a/test/960-default-smali/run b/test/960-default-smali/run
new file mode 100755
index 0000000..e378b06
--- /dev/null
+++ b/test/960-default-smali/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if echo $@ | grep -q -- "--jvm"; then
+  ${RUN} "$@"
+else
+  ${RUN} "$@" --runtime-option -Xexperimental:default-methods -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:default-methods
+fi
diff --git a/test/960-default-smali/smali/A.smali b/test/960-default-smali/smali/A.smali
new file mode 100644
index 0000000..e755612
--- /dev/null
+++ b/test/960-default-smali/smali/A.smali
@@ -0,0 +1,38 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public LA;
+.super Ljava/lang/Object;
+.implements LGreeter;
+
+# class A implements Greeter {
+#     public String SayHi() {
+#         return "Hi ";
+#     }
+# }
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public SayHi()Ljava/lang/String;
+    .registers 1
+
+    const-string v0, "Hi "
+    return-object v0
+.end method
diff --git a/test/960-default-smali/smali/Attendant.smali b/test/960-default-smali/smali/Attendant.smali
new file mode 100644
index 0000000..ab63aee
--- /dev/null
+++ b/test/960-default-smali/smali/Attendant.smali
@@ -0,0 +1,53 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public abstract interface LAttendant;
+.super Ljava/lang/Object;
+
+# public interface Attendant {
+#     public default String SayHi() {
+#         return "welcome to " + GetPlace();
+#     }
+#     public default String SayHiTwice() {
+#         return SayHi() + SayHi();
+#     }
+#
+#     public String GetPlace();
+# }
+
+.method public SayHi()Ljava/lang/String;
+    .locals 2
+    const-string v0, "welcome to "
+    invoke-interface {p0}, LAttendant;->GetPlace()Ljava/lang/String;
+    move-result-object v1
+    invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String;
+    move-result-object v0
+    return-object v0
+.end method
+
+.method public SayHiTwice()Ljava/lang/String;
+    .locals 2
+    invoke-interface {p0}, LAttendant;->SayHi()Ljava/lang/String;
+    move-result-object v0
+    invoke-interface {p0}, LAttendant;->SayHi()Ljava/lang/String;
+    move-result-object v1
+    invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String;
+    move-result-object v0
+    return-object v0
+.end method
+
+.method public abstract GetPlace()Ljava/lang/String;
+.end method
diff --git a/test/960-default-smali/smali/B.smali b/test/960-default-smali/smali/B.smali
new file mode 100644
index 0000000..d847dd1
--- /dev/null
+++ b/test/960-default-smali/smali/B.smali
@@ -0,0 +1,38 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public LB;
+.super Ljava/lang/Object;
+.implements LGreeter2;
+
+# class B implements Greeter2 {
+#     public String SayHi() {
+#         return "Hello ";
+#     }
+# }
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public SayHi()Ljava/lang/String;
+    .registers 1
+
+    const-string v0, "Hello "
+    return-object v0
+.end method
diff --git a/test/960-default-smali/smali/C.smali b/test/960-default-smali/smali/C.smali
new file mode 100644
index 0000000..08a8508
--- /dev/null
+++ b/test/960-default-smali/smali/C.smali
@@ -0,0 +1,37 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public LC;
+.super LA;
+
+# class C extends A {
+#     public String SayHiTwice() {
+#         return "You don't control me";
+#     }
+# }
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, LA;-><init>()V
+    return-void
+.end method
+
+.method public SayHiTwice()Ljava/lang/String;
+    .registers 1
+
+    const-string v0, "You don't control me"
+    return-object v0
+.end method
diff --git a/test/960-default-smali/smali/D.smali b/test/960-default-smali/smali/D.smali
new file mode 100644
index 0000000..32f3b7e
--- /dev/null
+++ b/test/960-default-smali/smali/D.smali
@@ -0,0 +1,38 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public LD;
+.super Ljava/lang/Object;
+.implements LGreeter3;
+
+# class D implements Greeter3 {
+#     public String GetName() {
+#         return "Alex ";
+#     }
+# }
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public GetName()Ljava/lang/String;
+    .registers 1
+
+    const-string v0, "Alex "
+    return-object v0
+.end method
diff --git a/test/960-default-smali/smali/E.smali b/test/960-default-smali/smali/E.smali
new file mode 100644
index 0000000..bae6250
--- /dev/null
+++ b/test/960-default-smali/smali/E.smali
@@ -0,0 +1,38 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public LE;
+.super LA;
+.implements LGreeter2;
+
+# class E extends A implements Greeter2 {
+#     public String SayHi() {
+#         return "Hi2 ";
+#     }
+# }
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, LA;-><init>()V
+    return-void
+.end method
+
+.method public SayHi()Ljava/lang/String;
+    .registers 1
+
+    const-string v0, "Hi2 "
+    return-object v0
+.end method
diff --git a/test/960-default-smali/smali/Extension.smali b/test/960-default-smali/smali/Extension.smali
new file mode 100644
index 0000000..60ffa26
--- /dev/null
+++ b/test/960-default-smali/smali/Extension.smali
@@ -0,0 +1,30 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public abstract interface LExtension;
+.super Ljava/lang/Object;
+
+# public interface Extension {
+#     public default String SayHi() {
+#         return "welcome ";
+#     }
+# }
+
+.method public SayHi()Ljava/lang/String;
+    .locals 1
+    const-string v0, "welcome "
+    return-object v0
+.end method
diff --git a/test/960-default-smali/smali/F.smali b/test/960-default-smali/smali/F.smali
new file mode 100644
index 0000000..3eaa089
--- /dev/null
+++ b/test/960-default-smali/smali/F.smali
@@ -0,0 +1,47 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public LF;
+.super LA;
+.implements LAttendant;
+
+# class F extends A implements Attendant {
+#     public String GetPlace() {
+#         return "android";
+#     }
+#     public String SayHiTwice() {
+#         return "We can override both interfaces";
+#     }
+# }
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public SayHiTwice()Ljava/lang/String;
+    .registers 1
+
+    const-string v0, "We can override both interfaces"
+    return-object v0
+.end method
+
+.method public GetPlace()Ljava/lang/String;
+    .registers 1
+    const-string v0, "android"
+    return-object v0
+.end method
diff --git a/test/960-default-smali/smali/G.smali b/test/960-default-smali/smali/G.smali
new file mode 100644
index 0000000..446f2a4
--- /dev/null
+++ b/test/960-default-smali/smali/G.smali
@@ -0,0 +1,37 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public LG;
+.super Ljava/lang/Object;
+.implements LAttendant;
+
+# class G implements Attendant {
+#     public String GetPlace() {
+#         return "android";
+#     }
+# }
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public GetPlace()Ljava/lang/String;
+    .registers 1
+    const-string v0, "android"
+    return-object v0
+.end method
diff --git a/test/960-default-smali/smali/Greeter.smali b/test/960-default-smali/smali/Greeter.smali
new file mode 100644
index 0000000..28530ff
--- /dev/null
+++ b/test/960-default-smali/smali/Greeter.smali
@@ -0,0 +1,40 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public abstract interface LGreeter;
+.super Ljava/lang/Object;
+
+# public interface Greeter {
+#     public String SayHi();
+#
+#     public default String SayHiTwice() {
+#         return SayHi() + SayHi();
+#     }
+# }
+
+.method public abstract SayHi()Ljava/lang/String;
+.end method
+
+.method public SayHiTwice()Ljava/lang/String;
+    .locals 2
+    invoke-interface {p0}, LGreeter;->SayHi()Ljava/lang/String;
+    move-result-object v0
+    invoke-interface {p0}, LGreeter;->SayHi()Ljava/lang/String;
+    move-result-object v1
+    invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String;
+    move-result-object v0
+    return-object v0
+.end method
diff --git a/test/960-default-smali/smali/Greeter2.smali b/test/960-default-smali/smali/Greeter2.smali
new file mode 100644
index 0000000..ace1798
--- /dev/null
+++ b/test/960-default-smali/smali/Greeter2.smali
@@ -0,0 +1,39 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public abstract interface LGreeter2;
+.super Ljava/lang/Object;
+.implements LGreeter;
+
+# public interface Greeter2 extends Greeter {
+#     public default String SayHiTwice() {
+#         return "I say " + SayHi() + SayHi();
+#     }
+# }
+
+.method public SayHiTwice()Ljava/lang/String;
+    .locals 3
+    const-string v0, "I say "
+    invoke-interface {p0}, LGreeter;->SayHi()Ljava/lang/String;
+    move-result-object v1
+    invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String;
+    move-result-object v0
+    invoke-interface {p0}, LGreeter;->SayHi()Ljava/lang/String;
+    move-result-object v1
+    invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String;
+    move-result-object v0
+    return-object v0
+.end method
diff --git a/test/960-default-smali/smali/Greeter3.smali b/test/960-default-smali/smali/Greeter3.smali
new file mode 100644
index 0000000..31fc2e7
--- /dev/null
+++ b/test/960-default-smali/smali/Greeter3.smali
@@ -0,0 +1,40 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public abstract interface LGreeter3;
+.super Ljava/lang/Object;
+.implements LGreeter;
+
+# public interface Greeter3 extends Greeter {
+#     public String GetName();
+#
+#     public default String SayHi() {
+#         return "Hello " + GetName();
+#     }
+# }
+
+.method public abstract GetName()Ljava/lang/String;
+.end method
+
+.method public SayHi()Ljava/lang/String;
+    .locals 2
+    const-string v0, "Hello "
+    invoke-interface {p0}, LGreeter3;->GetName()Ljava/lang/String;
+    move-result-object v1
+    invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String;
+    move-result-object v0
+    return-object v0
+.end method
diff --git a/test/960-default-smali/smali/H.smali b/test/960-default-smali/smali/H.smali
new file mode 100644
index 0000000..82065ea
--- /dev/null
+++ b/test/960-default-smali/smali/H.smali
@@ -0,0 +1,28 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public LH;
+.super Ljava/lang/Object;
+.implements LExtension;
+
+# class H implements Extension {
+# }
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
diff --git a/test/960-default-smali/smali/I.smali b/test/960-default-smali/smali/I.smali
new file mode 100644
index 0000000..72fb58a
--- /dev/null
+++ b/test/960-default-smali/smali/I.smali
@@ -0,0 +1,28 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public LI;
+.super LA;
+.implements LGreeter2;
+
+# class I extends A implements Greeter2 {
+# }
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
diff --git a/test/960-default-smali/smali/J.smali b/test/960-default-smali/smali/J.smali
new file mode 100644
index 0000000..93f3d62
--- /dev/null
+++ b/test/960-default-smali/smali/J.smali
@@ -0,0 +1,29 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public LJ;
+.super LA;
+
+# class J extends A {
+# }
+
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, LA;-><init>()V
+    return-void
+.end method
+
diff --git a/test/960-default-smali/smali/classes.xml b/test/960-default-smali/smali/classes.xml
new file mode 100644
index 0000000..0aa41f7
--- /dev/null
+++ b/test/960-default-smali/smali/classes.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<data>
+  <classes>
+    <class name="A" super="java/lang/Object">
+      <implements>
+        <item>Greeter</item>
+      </implements>
+      <methods> </methods>
+    </class>
+
+    <class name="B" super="java/lang/Object">
+      <implements>
+        <item>Greeter2</item>
+      </implements>
+      <methods> </methods>
+    </class>
+
+    <class name="C" super="A">
+      <implements> </implements>
+      <methods> </methods>
+    </class>
+
+    <class name="D" super="java/lang/Object">
+      <implements>
+        <item>Greeter3</item>
+      </implements>
+      <methods> </methods>
+    </class>
+
+    <class name="E" super="A">
+      <implements>
+        <item>Greeter2</item>
+      </implements>
+      <methods> </methods>
+    </class>
+
+    <class name="F" super="A">
+      <implements>
+        <item>Attendant</item>
+      </implements>
+      <methods> </methods>
+    </class>
+
+    <class name="G" super="java/lang/Object">
+      <implements>
+        <item>Attendant</item>
+      </implements>
+      <methods> </methods>
+    </class>
+
+    <class name="H" super="java/lang/Object">
+      <implements>
+        <item>Extension</item>
+      </implements>
+      <methods> </methods>
+    </class>
+
+    <class name="I" super="A">
+      <implements>
+        <item>Greeter2</item>
+      </implements>
+      <methods> </methods>
+    </class>
+
+    <class name="J" super="A">
+      <implements> </implements>
+      <methods> </methods>
+    </class>
+  </classes>
+
+  <interfaces>
+    <interface name="Extension" super="java/lang/Object">
+      <implements> </implements>
+      <methods>
+        <method type="default">SayHi</method>
+      </methods>
+    </interface>
+
+    <interface name="Greeter" super="java/lang/Object">
+      <implements> </implements>
+      <methods>
+        <method type="abstract">SayHi</method>
+        <method type="default">SayHiTwice</method>
+      </methods>
+    </interface>
+
+    <interface name="Greeter2" super="java/lang/Object">
+      <implements>
+        <item>Greeter</item>
+      </implements>
+      <methods> </methods>
+    </interface>
+
+    <interface name="Greeter3" super="java/lang/Object">
+      <implements>
+        <item>Greeter</item>
+      </implements>
+      <methods>
+        <method type="abstract">GetName</method>
+      </methods>
+    </interface>
+
+    <interface name="Attendant" super="java/lang/Object">
+      <implements> </implements>
+      <methods>
+        <method type="default">SayHi</method>
+        <method type="default">SayHiTwice</method>
+        <method type="abstract">GetPlace</method>
+      </methods>
+    </interface>
+  </interfaces>
+</data>
diff --git a/test/960-default-smali/util-src/generate_smali.py b/test/960-default-smali/util-src/generate_smali.py
new file mode 100755
index 0000000..b2bf1f0
--- /dev/null
+++ b/test/960-default-smali/util-src/generate_smali.py
@@ -0,0 +1,376 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Generate Smali Main file for test 960
+"""
+
+import os
+import sys
+from pathlib import Path
+
+BUILD_TOP = os.getenv("ANDROID_BUILD_TOP")
+if BUILD_TOP is None:
+  print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr)
+  sys.exit(1)
+
+# Allow us to import utils and mixins.
+sys.path.append(str(Path(BUILD_TOP)/"art"/"test"/"utils"/"python"))
+
+from testgen.utils import get_copyright
+import testgen.mixins as mixins
+
+from collections import namedtuple
+import itertools
+import functools
+import xml.etree.ElementTree as ET
+
+class MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin):
+  """
+  A mainclass and main method for this test.
+  """
+
+  MAIN_CLASS_TEMPLATE = """{copyright}
+.class public LMain;
+.super Ljava/lang/Object;
+
+# class Main {{
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+{test_groups}
+
+{test_funcs}
+
+{main_func}
+
+# }}
+"""
+
+  MAIN_FUNCTION_TEMPLATE = """
+#   public static void main(String[] args) {{
+.method public static main([Ljava/lang/String;)V
+    .locals 2
+    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+    {test_group_invoke}
+
+    return-void
+.end method
+#   }}
+"""
+
+  TEST_GROUP_INVOKE_TEMPLATE = """
+#     {test_name}();
+    invoke-static {{}}, {test_name}()V
+"""
+
+  def __init__(self):
+    """
+    Initialize this MainClass
+    """
+    self.tests = set()
+    self.global_funcs = set()
+
+  def add_instance(self, it):
+    """
+    Add an instance test for the given class
+    """
+    self.tests.add(it)
+
+  def add_func(self, f):
+    """
+    Add a function to the class
+    """
+    self.global_funcs.add(f)
+
+  def get_name(self):
+    """
+    Get the name of this class
+    """
+    return "Main"
+
+  def __str__(self):
+    """
+    Print this class
+    """
+    all_tests = sorted(self.tests)
+    test_invoke = ""
+    test_groups = ""
+    for t in all_tests:
+      test_groups += str(t)
+    for t in sorted(all_tests):
+      test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name())
+    main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke)
+
+    funcs = ""
+    for f in self.global_funcs:
+      funcs += str(f)
+    return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright('smali'),
+                                           test_groups=test_groups,
+                                           main_func=main_func, test_funcs=funcs)
+
+
+class InstanceTest(mixins.Named, mixins.NameComparableMixin):
+  """
+  A method that runs tests for a particular concrete type, It calls the test
+  cases for running it in all possible ways.
+  """
+
+  INSTANCE_TEST_TEMPLATE = """
+#   public static void {test_name}() {{
+#     System.out.println("Testing for type {ty}");
+#     String s = "{ty}";
+#     {ty} v = new {ty}();
+.method public static {test_name}()V
+    .locals 3
+    sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    const-string v0, "Testing for type {ty}"
+    invoke-virtual {{v2,v0}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+
+    const-string v0, "{ty}"
+    new-instance v1, L{ty};
+    invoke-direct {{v1}}, L{ty};-><init>()V
+
+    {invokes}
+
+    const-string v0, "End testing for type {ty}"
+    invoke-virtual {{v2,v0}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+    return-void
+.end method
+#     System.out.println("End testing for type {ty}");
+#   }}
+"""
+
+  TEST_INVOKE_TEMPLATE = """
+#     {fname}(s, v);
+    invoke-static {{v0, v1}}, {fname}(Ljava/lang/String;L{farg};)V
+"""
+
+  def __init__(self, main, ty):
+    """
+    Initialize this test group for the given type
+    """
+    self.ty = ty
+    self.main = main
+    self.funcs = set()
+    self.main.add_instance(self)
+
+  def get_name(self):
+    """
+    Get the name of this test group
+    """
+    return "TEST_NAME_"+self.ty
+
+  def add_func(self, f):
+    """
+    Add a test function to this test group
+    """
+    self.main.add_func(f)
+    self.funcs.add(f)
+
+  def __str__(self):
+    """
+    Returns the smali code for this function
+    """
+    func_invokes = ""
+    for f in sorted(self.funcs, key=lambda a: (a.func, a.farg)):
+      func_invokes += self.TEST_INVOKE_TEMPLATE.format(fname=f.get_name(),
+                                                       farg=f.farg)
+
+    return self.INSTANCE_TEST_TEMPLATE.format(test_name=self.get_name(), ty=self.ty,
+                                              invokes=func_invokes)
+
+class Func(mixins.Named, mixins.NameComparableMixin):
+  """
+  A single test case that attempts to invoke a function on receiver of a given type.
+  """
+
+  TEST_FUNCTION_TEMPLATE = """
+#   public static void {fname}(String s, {farg} v) {{
+#     try {{
+#       System.out.printf("%s-{invoke_type:<9} {farg:>9}.{callfunc}()='%s'\\n", s, v.{callfunc}());
+#       return;
+#     }} catch (Error e) {{
+#       System.out.printf("%s-{invoke_type} on {farg}: {callfunc}() threw exception!\\n", s);
+#       e.printStackTrace(System.out);
+#     }}
+#   }}
+.method public static {fname}(Ljava/lang/String;L{farg};)V
+    .locals 7
+    :call_{fname}_try_start
+      const/4 v0, 2
+      new-array v1,v0, [Ljava/lang/Object;
+      const/4 v0, 0
+      aput-object p0,v1,v0
+
+      sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+      const-string v3, "%s-{invoke_type:<9} {farg:>9}.{callfunc}()='%s'\\n"
+
+      invoke-{invoke_type} {{p1}}, L{farg};->{callfunc}()Ljava/lang/String;
+      move-result-object v4
+      const/4 v0, 1
+      aput-object v4, v1, v0
+
+      invoke-virtual {{v2,v3,v1}}, Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
+      return-void
+    :call_{fname}_try_end
+    .catch Ljava/lang/Error; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :error_{fname}_start
+    :error_{fname}_start
+      move-exception v3
+      const/4 v0, 1
+      new-array v1,v0, [Ljava/lang/Object;
+      const/4 v0, 0
+      aput-object p0, v1, v0
+      sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+      const-string v4, "%s-{invoke_type} on {farg}: {callfunc}() threw exception!\\n"
+      invoke-virtual {{v2,v4,v1}}, Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
+      invoke-virtual {{v3,v2}}, Ljava/lang/Error;->printStackTrace(Ljava/io/PrintStream;)V
+      return-void
+.end method
+"""
+
+  def __init__(self, func, farg, invoke):
+    """
+    Initialize this test function for the given invoke type and argument
+    """
+    self.func = func
+    self.farg = farg
+    self.invoke = invoke
+
+  def get_name(self):
+    """
+    Get the name of this test
+    """
+    return "Test_Func_{}_{}_{}".format(self.func, self.farg, self.invoke)
+
+  def __str__(self):
+    """
+    Get the smali code for this test function
+    """
+    return self.TEST_FUNCTION_TEMPLATE.format(fname=self.get_name(),
+                                              farg=self.farg,
+                                              invoke_type=self.invoke,
+                                              callfunc=self.func)
+
+def flatten_classes(classes, c):
+  """
+  Iterate over all the classes 'c' can be used as
+  """
+  while c:
+    yield c
+    c = classes.get(c.super_class)
+
+def flatten_class_methods(classes, c):
+  """
+  Iterate over all the methods 'c' can call
+  """
+  for c1 in flatten_classes(classes, c):
+    yield from c1.methods
+
+def flatten_interfaces(dat, c):
+  """
+  Iterate over all the interfaces 'c' transitively implements
+  """
+  def get_ifaces(cl):
+    for i2 in cl.implements:
+      yield dat.interfaces[i2]
+      yield from get_ifaces(dat.interfaces[i2])
+
+  for cl in flatten_classes(dat.classes, c):
+    yield from get_ifaces(cl)
+
+def flatten_interface_methods(dat, i):
+  """
+  Iterate over all the interface methods 'c' can call
+  """
+  yield from i.methods
+  for i2 in flatten_interfaces(dat, i):
+    yield from i2.methods
+
+def make_main_class(dat):
+  """
+  Creates a Main.smali file that runs all the tests
+  """
+  m = MainClass()
+  for c in dat.classes.values():
+    i = InstanceTest(m, c.name)
+    for clazz in flatten_classes(dat.classes, c):
+      for meth in flatten_class_methods(dat.classes, clazz):
+        i.add_func(Func(meth, clazz.name, 'virtual'))
+      for iface in flatten_interfaces(dat, clazz):
+        for meth in flatten_interface_methods(dat, iface):
+          i.add_func(Func(meth, clazz.name, 'virtual'))
+          i.add_func(Func(meth, iface.name, 'interface'))
+  return m
+
+class TestData(namedtuple("TestData", ['classes', 'interfaces'])):
+  """
+  A class representing the classes.xml document.
+  """
+  pass
+
+class Clazz(namedtuple("Clazz", ["name", "methods", "super_class", "implements"])):
+  """
+  A class representing a class element in the classes.xml document.
+  """
+  pass
+
+class IFace(namedtuple("IFace", ["name", "methods", "super_class", "implements"])):
+  """
+  A class representing an interface element in the classes.xml document.
+  """
+  pass
+
+def parse_xml(xml):
+  """
+  Parse the xml description of this test.
+  """
+  classes = dict()
+  ifaces  = dict()
+  root = ET.fromstring(xml)
+  for iface in root.find("interfaces"):
+    name = iface.attrib['name']
+    implements = [a.text for a in iface.find("implements")]
+    methods = [a.text for a in iface.find("methods")]
+    ifaces[name] = IFace(name = name,
+                         super_class = iface.attrib['super'],
+                         methods = methods,
+                         implements = implements)
+  for clazz in root.find('classes'):
+    name = clazz.attrib['name']
+    implements = [a.text for a in clazz.find("implements")]
+    methods = [a.text for a in clazz.find("methods")]
+    classes[name] = Clazz(name = name,
+                          super_class = clazz.attrib['super'],
+                          methods = methods,
+                          implements = implements)
+  return TestData(classes, ifaces)
+
+def main(argv):
+  smali_dir = Path(argv[1])
+  if not smali_dir.exists() or not smali_dir.is_dir():
+    print("{} is not a valid smali dir".format(smali_dir), file=sys.stderr)
+    sys.exit(1)
+  class_data = parse_xml((smali_dir / "classes.xml").open().read())
+  make_main_class(class_data).dump(smali_dir)
+
+if __name__ == '__main__':
+  main(sys.argv)
diff --git a/test/961-default-iface-resolution-generated/build b/test/961-default-iface-resolution-generated/build
new file mode 100755
index 0000000..707c17e
--- /dev/null
+++ b/test/961-default-iface-resolution-generated/build
@@ -0,0 +1,47 @@
+#!/bin/bash
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# make us exit on a failure
+set -e
+
+mkdir -p ./smali
+
+# We will be making more files than the ulimit is set to allow. Remove it temporarily.
+OLD_ULIMIT=`ulimit -S`
+ulimit -S unlimited
+
+restore_ulimit() {
+  ulimit -S "$OLD_ULIMIT"
+}
+trap 'restore_ulimit' ERR
+
+# Generate the smali files and expected.txt or fail
+./util-src/generate_smali.py ./smali ./expected.txt
+
+if [[ $@ == *"--jvm"* ]]; then
+  # Build the Java files if we are running a --jvm test
+  mkdir -p src
+  mkdir -p classes
+  ${ANDROID_BUILD_TOP}/art/tools/extract-embedded-java ./smali ./src
+  ${JAVAC} -implicit:none -d classes $(find src -name '*.java')
+fi
+
+# Build the smali files and make a dex
+${SMALI} -JXmx512m --experimental --api-level 23 --output classes.dex $(find smali -name '*.smali')
+zip $TEST_NAME.jar classes.dex
+
+# Reset the ulimit back to its initial value
+restore_ulimit
diff --git a/test/961-default-iface-resolution-generated/expected.txt b/test/961-default-iface-resolution-generated/expected.txt
new file mode 100644
index 0000000..1ddd65d
--- /dev/null
+++ b/test/961-default-iface-resolution-generated/expected.txt
@@ -0,0 +1 @@
+This file is generated by util-src/generate_smali.py do not directly modify!
diff --git a/test/961-default-iface-resolution-generated/info.txt b/test/961-default-iface-resolution-generated/info.txt
new file mode 100644
index 0000000..2cd2cc7
--- /dev/null
+++ b/test/961-default-iface-resolution-generated/info.txt
@@ -0,0 +1,17 @@
+Smali-based tests for experimental interface default methods.
+
+This tests that interface method resolution order is correct.
+
+Obviously needs to run under ART or a Java 8 Language runtime and compiler.
+
+When run smali test files are generated by the util-src/generate_smali.py
+script.  If we run with --jvm we will use the
+$(ANDROID_BUILD_TOP)/art/tools/extract-embedded-java script to turn the smali
+into equivalent Java using the embedded Java code.
+
+Care should be taken when updating the generate_smali.py script. It should always
+return equivalent output when run multiple times and the expected output should
+be valid.
+
+Do not modify the expected.txt file. It is generated on each run by
+util-src/generate_smali.py.
diff --git a/test/961-default-iface-resolution-generated/run b/test/961-default-iface-resolution-generated/run
new file mode 100755
index 0000000..e378b06
--- /dev/null
+++ b/test/961-default-iface-resolution-generated/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if echo $@ | grep -q -- "--jvm"; then
+  ${RUN} "$@"
+else
+  ${RUN} "$@" --runtime-option -Xexperimental:default-methods -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:default-methods
+fi
diff --git a/test/961-default-iface-resolution-generated/util-src/generate_smali.py b/test/961-default-iface-resolution-generated/util-src/generate_smali.py
new file mode 100755
index 0000000..921a096
--- /dev/null
+++ b/test/961-default-iface-resolution-generated/util-src/generate_smali.py
@@ -0,0 +1,466 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Generate Smali test files for test 961.
+"""
+
+import os
+import sys
+from pathlib import Path
+
+BUILD_TOP = os.getenv("ANDROID_BUILD_TOP")
+if BUILD_TOP is None:
+  print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr)
+  sys.exit(1)
+
+# Allow us to import utils and mixins.
+sys.path.append(str(Path(BUILD_TOP)/"art"/"test"/"utils"/"python"))
+
+from testgen.utils import get_copyright, subtree_sizes, gensym, filter_blanks
+import testgen.mixins as mixins
+
+from functools import total_ordering
+import itertools
+import string
+
+# The max depth the type tree can have. Includes the class object in the tree.
+# Increasing this increases the number of generated files significantly. This
+# value was chosen as it is fairly quick to run and very comprehensive, checking
+# every possible interface tree up to 5 layers deep.
+MAX_IFACE_DEPTH = 5
+
+class MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin):
+  """
+  A Main.smali file containing the Main class and the main function. It will run
+  all the test functions we have.
+  """
+
+  MAIN_CLASS_TEMPLATE = """{copyright}
+
+.class public LMain;
+.super Ljava/lang/Object;
+
+# class Main {{
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+{test_groups}
+
+{main_func}
+
+# }}
+"""
+
+  MAIN_FUNCTION_TEMPLATE = """
+#   public static void main(String[] args) {{
+.method public static main([Ljava/lang/String;)V
+    .locals 2
+    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+    {test_group_invoke}
+
+    return-void
+.end method
+#   }}
+"""
+
+  TEST_GROUP_INVOKE_TEMPLATE = """
+#     {test_name}();
+    invoke-static {{}}, {test_name}()V
+"""
+
+  def __init__(self):
+    """
+    Initialize this MainClass. We start out with no tests.
+    """
+    self.tests = set()
+
+  def get_expected(self):
+    """
+    Get the expected output of this test.
+    """
+    all_tests = sorted(self.tests)
+    return filter_blanks("\n".join(a.get_expected() for a in all_tests))
+
+  def add_test(self, ty):
+    """
+    Add a test for the concrete type 'ty'
+    """
+    self.tests.add(Func(ty))
+
+  def get_name(self):
+    """
+    Get the name of this class
+    """
+    return "Main"
+
+  def __str__(self):
+    """
+    Print the MainClass smali code.
+    """
+    all_tests = sorted(self.tests)
+    test_invoke = ""
+    test_groups = ""
+    for t in all_tests:
+      test_groups += str(t)
+    for t in all_tests:
+      test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name())
+    main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke)
+
+    return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright("smali"),
+                                           test_groups = test_groups,
+                                           main_func = main_func)
+
+class Func(mixins.Named, mixins.NameComparableMixin):
+  """
+  A function that tests the functionality of a concrete type. Should only be
+  constructed by MainClass.add_test.
+  """
+
+  TEST_FUNCTION_TEMPLATE = """
+#   public static void {fname}() {{
+#     try {{
+#       {farg} v = new {farg}();
+#       System.out.printf("%s calls default method on %s\\n",
+#                         v.CalledClassName(),
+#                         v.CalledInterfaceName());
+#       return;
+#     }} catch (Error e) {{
+#       e.printStackTrace(System.out);
+#       return;
+#     }}
+#   }}
+.method public static {fname}()V
+    .locals 7
+    :call_{fname}_try_start
+      new-instance v6, L{farg};
+      invoke-direct {{v6}}, L{farg};-><init>()V
+
+      const/4 v0, 2
+      new-array v1,v0, [Ljava/lang/Object;
+      const/4 v0, 0
+      invoke-virtual {{v6}}, L{farg};->CalledClassName()Ljava/lang/String;
+      move-result-object v4
+      aput-object v4,v1,v0
+
+      sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+      const-string v3, "%s calls default method on %s\\n"
+
+      invoke-virtual {{v6}}, L{farg};->CalledInterfaceName()Ljava/lang/String;
+      move-result-object v4
+      const/4 v0, 1
+      aput-object v4, v1, v0
+
+      invoke-virtual {{v2,v3,v1}}, Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
+      return-void
+    :call_{fname}_try_end
+    .catch Ljava/lang/Error; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :error_{fname}_start
+    :error_{fname}_start
+      move-exception v3
+      sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+      invoke-virtual {{v3,v2}}, Ljava/lang/Error;->printStackTrace(Ljava/io/PrintStream;)V
+      return-void
+.end method
+"""
+
+  def __init__(self, farg):
+    """
+    Initialize a test function for the given argument
+    """
+    self.farg = farg
+
+  def get_expected(self):
+    """
+    Get the expected output calling this function.
+    """
+    return "{tree} calls default method on {iface_tree}".format(
+        tree = self.farg.get_tree(), iface_tree = self.farg.get_called().get_tree())
+
+  def get_name(self):
+    """
+    Get the name of this function
+    """
+    return "TEST_FUNC_{}".format(self.farg.get_name())
+
+  def __str__(self):
+    """
+    Print the smali code of this function.
+    """
+    return self.TEST_FUNCTION_TEMPLATE.format(fname=self.get_name(), farg=self.farg.get_name())
+
+class TestClass(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin):
+  """
+  A class that will be instantiated to test default method resolution order.
+  """
+
+  TEST_CLASS_TEMPLATE = """{copyright}
+
+.class public L{class_name};
+.super Ljava/lang/Object;
+.implements L{iface_name};
+
+# public class {class_name} implements {iface_name} {{
+#   public String CalledClassName() {{
+#     return "{tree}";
+#   }}
+# }}
+
+.method public constructor <init>()V
+  .registers 1
+  invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V
+  return-void
+.end method
+
+.method public CalledClassName()Ljava/lang/String;
+  .locals 1
+  const-string v0, "{tree}"
+  return-object v0
+.end method
+"""
+
+  def __init__(self, iface):
+    """
+    Initialize this test class which implements the given interface
+    """
+    self.iface = iface
+    self.class_name = "CLASS_"+gensym()
+
+  def get_name(self):
+    """
+    Get the name of this class
+    """
+    return self.class_name
+
+  def get_tree(self):
+    """
+    Print out a representation of the type tree of this class
+    """
+    return "[{class_name} {iface_tree}]".format(class_name = self.class_name,
+                                                iface_tree = self.iface.get_tree())
+
+  def __iter__(self):
+    """
+    Step through all interfaces implemented transitively by this class
+    """
+    yield self.iface
+    yield from self.iface
+
+  def get_called(self):
+    """
+    Get the interface whose default method would be called when calling the
+    CalledInterfaceName function.
+    """
+    all_ifaces = set(iface for iface in self if iface.default)
+    for i in all_ifaces:
+      if all(map(lambda j: i not in j.get_super_types(), all_ifaces)):
+        return i
+    raise Exception("UNREACHABLE! Unable to find default method!")
+
+  def __str__(self):
+    """
+    Print the smali code of this class.
+    """
+    return self.TEST_CLASS_TEMPLATE.format(copyright = get_copyright('smali'),
+                                           iface_name = self.iface.get_name(),
+                                           tree = self.get_tree(),
+                                           class_name = self.class_name)
+
+class TestInterface(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin):
+  """
+  An interface that will be used to test default method resolution order.
+  """
+
+  TEST_INTERFACE_TEMPLATE = """{copyright}
+.class public abstract interface L{class_name};
+.super Ljava/lang/Object;
+{implements_spec}
+
+# public interface {class_name} {extends} {ifaces} {{
+#   public String CalledClassName();
+.method public abstract CalledClassName()Ljava/lang/String;
+.end method
+
+{funcs}
+
+# }}
+"""
+
+  DEFAULT_FUNC_TEMPLATE = """
+#   public default String CalledInterfaceName() {{
+#     return "{tree}";
+#   }}
+.method public CalledInterfaceName()Ljava/lang/String;
+  .locals 1
+  const-string v0, "{tree}"
+  return-object v0
+.end method
+"""
+
+  IMPLEMENTS_TEMPLATE = """
+.implements L{iface_name};
+"""
+
+  def __init__(self, ifaces, default):
+    """
+    Initialize interface with the given super-interfaces
+    """
+    self.ifaces = sorted(ifaces)
+    self.default = default
+    end = "_DEFAULT" if default else ""
+    self.class_name = "INTERFACE_"+gensym()+end
+
+  def get_super_types(self):
+    """
+    Returns a set of all the supertypes of this interface
+    """
+    return set(i2 for i2 in self)
+
+  def get_name(self):
+    """
+    Get the name of this class
+    """
+    return self.class_name
+
+  def get_tree(self):
+    """
+    Print out a representation of the type tree of this class
+    """
+    return "[{class_name} {iftree}]".format(class_name = self.get_name(),
+                                            iftree = print_tree(self.ifaces))
+
+  def __iter__(self):
+    """
+    Performs depth-first traversal of the interface tree this interface is the
+    root of. Does not filter out repeats.
+    """
+    for i in self.ifaces:
+      yield i
+      yield from i
+
+  def __str__(self):
+    """
+    Print the smali code of this interface.
+    """
+    s_ifaces = " "
+    j_ifaces = " "
+    for i in self.ifaces:
+      s_ifaces += self.IMPLEMENTS_TEMPLATE.format(iface_name = i.get_name())
+      j_ifaces += " {},".format(i.get_name())
+    j_ifaces = j_ifaces[0:-1]
+    if self.default:
+      funcs = self.DEFAULT_FUNC_TEMPLATE.format(ifaces = j_ifaces,
+                                                tree = self.get_tree(),
+                                                class_name = self.class_name)
+    else:
+      funcs = ""
+    return self.TEST_INTERFACE_TEMPLATE.format(copyright = get_copyright('smali'),
+                                               implements_spec = s_ifaces,
+                                               extends = "extends" if len(self.ifaces) else "",
+                                               ifaces = j_ifaces,
+                                               funcs = funcs,
+                                               tree = self.get_tree(),
+                                               class_name = self.class_name)
+
+def print_tree(ifaces):
+  """
+  Prints a list of iface trees
+  """
+  return " ".join(i.get_tree() for i in  ifaces)
+
+# The deduplicated output of subtree_sizes for each size up to
+# MAX_LEAF_IFACE_PER_OBJECT.
+SUBTREES = [set(tuple(sorted(l)) for l in subtree_sizes(i))
+            for i in range(MAX_IFACE_DEPTH + 1)]
+
+def create_interface_trees():
+  """
+  Return all legal interface trees
+  """
+  def dump_supers(s):
+    """
+    Does depth first traversal of all the interfaces in the list.
+    """
+    for i in s:
+      yield i
+      yield from i
+
+  def create_interface_trees_inner(num, allow_default):
+    for split in SUBTREES[num]:
+      ifaces = []
+      for sub in split:
+        if sub == 1:
+          ifaces.append([TestInterface([], allow_default)])
+          if allow_default:
+            ifaces[-1].append(TestInterface([], False))
+        else:
+          ifaces.append(list(create_interface_trees_inner(sub, allow_default)))
+      for supers in itertools.product(*ifaces):
+        all_supers = sorted(set(dump_supers(supers)) - set(supers))
+        for i in range(len(all_supers) + 1):
+          for combo in itertools.combinations(all_supers, i):
+            yield TestInterface(list(combo) + list(supers), allow_default)
+      if allow_default:
+        for i in range(len(split)):
+          ifaces = []
+          for sub, cs in zip(split, itertools.count()):
+            if sub == 1:
+              ifaces.append([TestInterface([], i == cs)])
+            else:
+              ifaces.append(list(create_interface_trees_inner(sub, i == cs)))
+          for supers in itertools.product(*ifaces):
+            all_supers = sorted(set(dump_supers(supers)) - set(supers))
+            for i in range(len(all_supers) + 1):
+              for combo in itertools.combinations(all_supers, i):
+                yield TestInterface(list(combo) + list(supers), False)
+
+  for num in range(1, MAX_IFACE_DEPTH):
+    yield from create_interface_trees_inner(num, True)
+
+def create_all_test_files():
+  """
+  Creates all the objects representing the files in this test. They just need to
+  be dumped.
+  """
+  mc = MainClass()
+  classes = {mc}
+  for tree in create_interface_trees():
+    classes.add(tree)
+    for i in tree:
+      classes.add(i)
+    test_class = TestClass(tree)
+    mc.add_test(test_class)
+    classes.add(test_class)
+  return mc, classes
+
+def main(argv):
+  smali_dir = Path(argv[1])
+  if not smali_dir.exists() or not smali_dir.is_dir():
+    print("{} is not a valid smali dir".format(smali_dir), file=sys.stderr)
+    sys.exit(1)
+  expected_txt = Path(argv[2])
+  mainclass, all_files = create_all_test_files()
+  with expected_txt.open('w') as out:
+    print(mainclass.get_expected(), file=out)
+  for f in all_files:
+    f.dump(smali_dir)
+
+if __name__ == '__main__':
+  main(sys.argv)
diff --git a/test/962-iface-static/build b/test/962-iface-static/build
new file mode 100755
index 0000000..5ad82f7
--- /dev/null
+++ b/test/962-iface-static/build
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# make us exit on a failure
+set -e
+
+if [[ $@ == *"--jvm"* ]]; then
+  # Build the Java files if we are running a --jvm test
+  mkdir -p src
+  mkdir -p classes
+  ${ANDROID_BUILD_TOP}/art/tools/extract-embedded-java ./smali ./src
+  ${JAVAC} -implicit:none -d classes $(find src -name '*.java')
+fi
+
+# Build the smali files and make a dex
+${SMALI} -JXmx512m --experimental --api-level 23 --output classes.dex $(find smali -name '*.smali')
+zip $TEST_NAME.jar classes.dex
diff --git a/test/962-iface-static/expected.txt b/test/962-iface-static/expected.txt
new file mode 100644
index 0000000..6d98ea1
--- /dev/null
+++ b/test/962-iface-static/expected.txt
@@ -0,0 +1,3 @@
+init
+constructor
+Hello
diff --git a/test/962-iface-static/info.txt b/test/962-iface-static/info.txt
new file mode 100644
index 0000000..d4732e5
--- /dev/null
+++ b/test/962-iface-static/info.txt
@@ -0,0 +1,4 @@
+Smali-based tests for experimental interface static methods.
+
+To run with --jvm you must export JAVA_HOME to a Java 8 Language installation
+and pass the --use-java-home to run-test
diff --git a/test/962-iface-static/run b/test/962-iface-static/run
new file mode 100755
index 0000000..e713708
--- /dev/null
+++ b/test/962-iface-static/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if echo $@ | grep -q -- "--jvm"; then
+  ${RUN} "$@"
+else
+  ${RUN} "$@" --runtime-option -Xexperimental:default-methods -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:default-methods
+fi
diff --git a/test/962-iface-static/smali/Displayer.smali b/test/962-iface-static/smali/Displayer.smali
new file mode 100644
index 0000000..06bec16
--- /dev/null
+++ b/test/962-iface-static/smali/Displayer.smali
@@ -0,0 +1,45 @@
+# /*
+#  * Copyright (C) 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+#
+# public class Displayer {
+#   static {
+#       System.out.println("init");
+#   }
+#
+#   public Displayer() {
+#       System.out.println("constructor");
+#   }
+# }
+
+.class public LDisplayer;
+.super Ljava/lang/Object;
+
+.method public static <clinit>()V
+    .locals 3
+    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    const-string v0, "init"
+    invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public constructor <init>()V
+    .locals 2
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    const-string v0, "constructor"
+    invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+    return-void
+.end method
diff --git a/test/962-iface-static/smali/Main.smali b/test/962-iface-static/smali/Main.smali
new file mode 100644
index 0000000..72fa5e0
--- /dev/null
+++ b/test/962-iface-static/smali/Main.smali
@@ -0,0 +1,40 @@
+# /*
+#  * Copyright (C) 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+#
+# class Main {
+#   public static void main(String[] args) {
+#       System.out.println(iface.SayHi());
+#   }
+# }
+.class public LMain;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public static main([Ljava/lang/String;)V
+    .locals 2
+    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+    invoke-static {}, Liface;->SayHi()Ljava/lang/String;
+    move-result-object v0
+    invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+
+    return-void
+.end method
diff --git a/test/962-iface-static/smali/iface.smali b/test/962-iface-static/smali/iface.smali
new file mode 100644
index 0000000..441aae6
--- /dev/null
+++ b/test/962-iface-static/smali/iface.smali
@@ -0,0 +1,43 @@
+# /*
+#  * Copyright (C) 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+#
+# public interface iface {
+#   public static final Displayer f = new Displayer();
+#
+#   public static String SayHi() {
+#       return "Hello";
+#   }
+# }
+
+.class public abstract interface Liface;
+.super Ljava/lang/Object;
+
+.field public final static f:LDisplayer;
+
+.method public static <clinit>()V
+    .locals 3
+    new-instance v1, LDisplayer;
+    invoke-direct {v1}, LDisplayer;-><init>()V
+    sput-object v1, Liface;->f:LDisplayer;
+    return-void
+.end method
+
+.method public static SayHi()Ljava/lang/String;
+    .locals 1
+    const-string v0, "Hello"
+    return-object v0
+.end method
+
diff --git a/test/963-default-range-smali/build b/test/963-default-range-smali/build
new file mode 100755
index 0000000..5ad82f7
--- /dev/null
+++ b/test/963-default-range-smali/build
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# make us exit on a failure
+set -e
+
+if [[ $@ == *"--jvm"* ]]; then
+  # Build the Java files if we are running a --jvm test
+  mkdir -p src
+  mkdir -p classes
+  ${ANDROID_BUILD_TOP}/art/tools/extract-embedded-java ./smali ./src
+  ${JAVAC} -implicit:none -d classes $(find src -name '*.java')
+fi
+
+# Build the smali files and make a dex
+${SMALI} -JXmx512m --experimental --api-level 23 --output classes.dex $(find smali -name '*.smali')
+zip $TEST_NAME.jar classes.dex
diff --git a/test/963-default-range-smali/expected.txt b/test/963-default-range-smali/expected.txt
new file mode 100644
index 0000000..af17d2f
--- /dev/null
+++ b/test/963-default-range-smali/expected.txt
@@ -0,0 +1,2 @@
+Hello
+Hello
diff --git a/test/963-default-range-smali/info.txt b/test/963-default-range-smali/info.txt
new file mode 100644
index 0000000..d4732e5
--- /dev/null
+++ b/test/963-default-range-smali/info.txt
@@ -0,0 +1,4 @@
+Smali-based tests for experimental interface static methods.
+
+To run with --jvm you must export JAVA_HOME to a Java 8 Language installation
+and pass the --use-java-home to run-test
diff --git a/test/963-default-range-smali/run b/test/963-default-range-smali/run
new file mode 100755
index 0000000..e713708
--- /dev/null
+++ b/test/963-default-range-smali/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if echo $@ | grep -q -- "--jvm"; then
+  ${RUN} "$@"
+else
+  ${RUN} "$@" --runtime-option -Xexperimental:default-methods -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:default-methods
+fi
diff --git a/test/963-default-range-smali/smali/A.smali b/test/963-default-range-smali/smali/A.smali
new file mode 100644
index 0000000..b3d91dd
--- /dev/null
+++ b/test/963-default-range-smali/smali/A.smali
@@ -0,0 +1,29 @@
+# /*
+#  * Copyright 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+
+.class public LA;
+.super Ljava/lang/Object;
+.implements Liface;
+
+# class A implements iface {
+# }
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
diff --git a/test/963-default-range-smali/smali/Main.smali b/test/963-default-range-smali/smali/Main.smali
new file mode 100644
index 0000000..400fba7
--- /dev/null
+++ b/test/963-default-range-smali/smali/Main.smali
@@ -0,0 +1,77 @@
+# /*
+#  * Copyright (C) 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+#
+# class Main {
+#   public static void main(String[] args) {
+#       A a = new A();
+#       System.out.println(a.SayHi("a string 0",
+#                                  "a string 1",
+#                                  "a string 2",
+#                                  "a string 3",
+#                                  "a string 4",
+#                                  "a string 5",
+#                                  "a string 6",
+#                                  "a string 7",
+#                                  "a string 8",
+#                                  "a string 9"));
+#       iface b = (iface)a;
+#       System.out.println(b.SayHi("a string 0",
+#                                  "a string 1",
+#                                  "a string 2",
+#                                  "a string 3",
+#                                  "a string 4",
+#                                  "a string 5",
+#                                  "a string 6",
+#                                  "a string 7",
+#                                  "a string 8",
+#                                  "a string 9"));
+#   }
+# }
+.class public LMain;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public static main([Ljava/lang/String;)V
+    .locals 15
+    sget-object v12, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+    new-instance v1, LA;
+    invoke-direct {v1}, LA;-><init>()V
+    const-string v2, "a string 0"
+    const-string v3, "a string 1"
+    const-string v4, "a string 2"
+    const-string v5, "a string 3"
+    const-string v6, "a string 4"
+    const-string v7, "a string 5"
+    const-string v8, "a string 6"
+    const-string v9, "a string 7"
+    const-string v10, "a string 8"
+    const-string v11, "a string 9"
+    invoke-virtual/range {v1 .. v11}, LA;->SayHi(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+    move-result-object v0
+    invoke-virtual {v12,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+
+    invoke-interface/range {v1 .. v11}, Liface;->SayHi(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+    move-result-object v0
+    invoke-virtual {v12,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+
+    return-void
+.end method
diff --git a/test/963-default-range-smali/smali/iface.smali b/test/963-default-range-smali/smali/iface.smali
new file mode 100644
index 0000000..c2c3ce6
--- /dev/null
+++ b/test/963-default-range-smali/smali/iface.smali
@@ -0,0 +1,40 @@
+# /*
+#  * Copyright (C) 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+#
+# public interface iface {
+#   public default String SayHi(String n1,
+#                               String n2,
+#                               String n3,
+#                               String n4,
+#                               String n5,
+#                               String n6,
+#                               String n7,
+#                               String n8,
+#                               String n9,
+#                               String n0) {
+#       return "Hello";
+#   }
+# }
+
+.class public abstract interface Liface;
+.super Ljava/lang/Object;
+
+.method public SayHi(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+    .locals 1
+    const-string v0, "Hello"
+    return-object v0
+.end method
+
diff --git a/test/964-default-iface-init-generated/build b/test/964-default-iface-init-generated/build
new file mode 100755
index 0000000..deef803
--- /dev/null
+++ b/test/964-default-iface-init-generated/build
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# make us exit on a failure
+set -e
+
+# We will be making more files than the ulimit is set to allow. Remove it temporarily.
+OLD_ULIMIT=`ulimit -S`
+ulimit -S unlimited
+
+restore_ulimit() {
+  ulimit -S "$OLD_ULIMIT"
+}
+trap 'restore_ulimit' ERR
+
+# Generate the smali files and expected.txt or fail
+./util-src/generate_smali.py ./smali ./expected.txt
+
+if [[ $@ == *"--jvm"* ]]; then
+  # Build the Java files if we are running a --jvm test
+  mkdir -p src
+  mkdir -p classes
+  ${ANDROID_BUILD_TOP}/art/tools/extract-embedded-java ./smali ./src
+  ${JAVAC} -implicit:none -d classes $(find src -name '*.java')
+fi
+
+# Build the smali files and make a dex
+${SMALI} -JXmx512m --experimental --api-level 23 --output classes.dex $(find smali -name '*.smali')
+zip $TEST_NAME.jar classes.dex
+
+# Reset the ulimit back to its initial value
+restore_ulimit
diff --git a/test/964-default-iface-init-generated/expected.txt b/test/964-default-iface-init-generated/expected.txt
new file mode 100644
index 0000000..1ddd65d
--- /dev/null
+++ b/test/964-default-iface-init-generated/expected.txt
@@ -0,0 +1 @@
+This file is generated by util-src/generate_smali.py do not directly modify!
diff --git a/test/964-default-iface-init-generated/info.txt b/test/964-default-iface-init-generated/info.txt
new file mode 100644
index 0000000..5805a86
--- /dev/null
+++ b/test/964-default-iface-init-generated/info.txt
@@ -0,0 +1,17 @@
+Smali-based tests for interface initialization.
+
+This tests that interface initialization order is correct.
+
+Obviously needs to run under ART or a Java 8 Language runtime and compiler.
+
+When run smali test files are generated by the util-src/generate_smali.py
+script.  If we run with --jvm we will use the
+$(ANDROID_BUILD_TOP)/art/tools/extract-embedded-java script to turn the smali
+into equivalent Java using the embedded Java code.
+
+Care should be taken when updating the generate_smali.py script. It should always
+return equivalent output when run multiple times and the expected output should
+be valid.
+
+Do not modify the expected.txt file. It is generated on each run by
+util-src/generate_smali.py.
diff --git a/test/964-default-iface-init-generated/run b/test/964-default-iface-init-generated/run
new file mode 100755
index 0000000..e378b06
--- /dev/null
+++ b/test/964-default-iface-init-generated/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if echo $@ | grep -q -- "--jvm"; then
+  ${RUN} "$@"
+else
+  ${RUN} "$@" --runtime-option -Xexperimental:default-methods -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:default-methods
+fi
diff --git a/test/964-default-iface-init-generated/smali/Displayer.smali b/test/964-default-iface-init-generated/smali/Displayer.smali
new file mode 100644
index 0000000..91280a8
--- /dev/null
+++ b/test/964-default-iface-init-generated/smali/Displayer.smali
@@ -0,0 +1,45 @@
+# /*
+#  * Copyright (C) 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+#
+# // This class is b/c java does not allow static {} blocks in interfaces.
+# public class Displayer {
+#   public Displayer(String type) {
+#       System.out.println("initialization of " + type);
+#   }
+#   public void touch() {
+#       return;
+#   }
+# }
+
+.class public LDisplayer;
+.super Ljava/lang/Object;
+
+.method public constructor <init>(Ljava/lang/String;)V
+    .locals 2
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    const-string v0, "initialization of "
+    invoke-virtual {v0, p1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String;
+    move-result-object v0
+    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+    return-void
+.end method
+
+.method public touch()V
+    .locals 0
+    return-void
+.end method
+
diff --git a/test/964-default-iface-init-generated/util-src/generate_smali.py b/test/964-default-iface-init-generated/util-src/generate_smali.py
new file mode 100755
index 0000000..be2d3ba
--- /dev/null
+++ b/test/964-default-iface-init-generated/util-src/generate_smali.py
@@ -0,0 +1,531 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Generate Smali test files for test 964.
+"""
+
+import os
+import sys
+from pathlib import Path
+
+BUILD_TOP = os.getenv("ANDROID_BUILD_TOP")
+if BUILD_TOP is None:
+  print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr)
+  sys.exit(1)
+
+# Allow us to import utils and mixins.
+sys.path.append(str(Path(BUILD_TOP)/"art"/"test"/"utils"/"python"))
+
+from testgen.utils import get_copyright, subtree_sizes, gensym, filter_blanks
+import testgen.mixins as mixins
+
+from functools import total_ordering
+import itertools
+import string
+
+# The max depth the tree can have.
+MAX_IFACE_DEPTH = 3
+
+class MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin):
+  """
+  A Main.smali file containing the Main class and the main function. It will run
+  all the test functions we have.
+  """
+
+  MAIN_CLASS_TEMPLATE = """{copyright}
+
+.class public LMain;
+.super Ljava/lang/Object;
+
+# class Main {{
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+{test_groups}
+
+{main_func}
+
+# }}
+"""
+
+  MAIN_FUNCTION_TEMPLATE = """
+#   public static void main(String[] args) {{
+.method public static main([Ljava/lang/String;)V
+    .locals 2
+
+    {test_group_invoke}
+
+    return-void
+.end method
+#   }}
+"""
+
+  TEST_GROUP_INVOKE_TEMPLATE = """
+#     {test_name}();
+    invoke-static {{}}, {test_name}()V
+"""
+
+  def __init__(self):
+    """
+    Initialize this MainClass. We start out with no tests.
+    """
+    self.tests = set()
+
+  def add_test(self, ty):
+    """
+    Add a test for the concrete type 'ty'
+    """
+    self.tests.add(Func(ty))
+
+  def get_expected(self):
+    """
+    Get the expected output of this test.
+    """
+    all_tests = sorted(self.tests)
+    return filter_blanks("\n".join(a.get_expected() for a in all_tests))
+
+  def get_name(self):
+    """
+    Gets the name of this class
+    """
+    return "Main"
+
+  def __str__(self):
+    """
+    Print the smali code for this test.
+    """
+    all_tests = sorted(self.tests)
+    test_invoke = ""
+    test_groups = ""
+    for t in all_tests:
+      test_groups += str(t)
+    for t in all_tests:
+      test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name())
+    main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke)
+
+    return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright('smali'),
+                                           test_groups = test_groups,
+                                           main_func = main_func)
+
+class Func(mixins.Named, mixins.NameComparableMixin):
+  """
+  A function that tests the functionality of a concrete type. Should only be
+  constructed by MainClass.add_test.
+  """
+
+  TEST_FUNCTION_TEMPLATE = """
+#   public static void {fname}() {{
+#     try {{
+#       System.out.println("About to initialize {tree}");
+#       {farg} v = new {farg}();
+#       System.out.println("Initialized {tree}");
+#       v.touchAll();
+#       System.out.println("All of {tree} hierarchy initialized");
+#       return;
+#     }} catch (Error e) {{
+#       e.printStackTrace(System.out);
+#       return;
+#     }}
+#   }}
+.method public static {fname}()V
+    .locals 7
+    :call_{fname}_try_start
+      sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+      const-string v3, "About to initialize {tree}"
+      invoke-virtual {{v2, v3}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+
+      new-instance v6, L{farg};
+      invoke-direct {{v6}}, L{farg};-><init>()V
+
+      const-string v3, "Initialized {tree}"
+      invoke-virtual {{v2, v3}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+
+      invoke-virtual {{v6}}, L{farg};->touchAll()V
+
+      const-string v3, "All of {tree} hierarchy initialized"
+      invoke-virtual {{v2, v3}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+
+      return-void
+    :call_{fname}_try_end
+    .catch Ljava/lang/Error; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :error_{fname}_start
+    :error_{fname}_start
+      move-exception v3
+      sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+      invoke-virtual {{v3,v2}}, Ljava/lang/Error;->printStackTrace(Ljava/io/PrintStream;)V
+      return-void
+.end method
+"""
+
+  OUTPUT_FORMAT = """
+About to initialize {tree}
+{initialize_output}
+Initialized {tree}
+{touch_output}
+All of {tree} hierarchy initialized
+""".strip()
+
+  def __init__(self, farg):
+    """
+    Initialize a test function for the given argument
+    """
+    self.farg = farg
+
+  def __str__(self):
+    """
+    Print the smali code for this test function.
+    """
+    return self.TEST_FUNCTION_TEMPLATE.format(fname=self.get_name(),
+                                              farg=self.farg.get_name(),
+                                              tree = self.farg.get_tree())
+
+  def get_name(self):
+    """
+    Gets the name of this test function
+    """
+    return "TEST_FUNC_{}".format(self.farg.get_name())
+
+  def get_expected(self):
+    """
+    Get the expected output of this function.
+    """
+    return self.OUTPUT_FORMAT.format(
+        tree = self.farg.get_tree(),
+        initialize_output = self.farg.get_initialize_output().strip(),
+        touch_output = self.farg.get_touch_output().strip())
+
+class TestClass(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin):
+  """
+  A class that will be instantiated to test interface initialization order.
+  """
+
+  TEST_CLASS_TEMPLATE = """{copyright}
+
+.class public L{class_name};
+.super Ljava/lang/Object;
+{implements_spec}
+
+# public class {class_name} implements {ifaces} {{
+#
+#   public {class_name}() {{
+#   }}
+.method public constructor <init>()V
+  .locals 2
+  invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V
+  return-void
+.end method
+
+#   public void marker() {{
+#     return;
+#   }}
+.method public marker()V
+  .locals 0
+  return-void
+.end method
+
+#   public void touchAll() {{
+.method public touchAll()V
+  .locals 2
+  sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+  {touch_calls}
+  return-void
+.end method
+#   }}
+# }}
+"""
+
+  IMPLEMENTS_TEMPLATE = """
+.implements L{iface_name};
+"""
+
+  TOUCH_CALL_TEMPLATE = """
+#     System.out.println("{class_name} touching {iface_name}");
+#     {iface_name}.field.touch();
+      const-string v1, "{class_name} touching {iface_name}"
+      invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+      sget-object v1, L{iface_name};->field:LDisplayer;
+      invoke-virtual {{v1}}, LDisplayer;->touch()V
+"""
+
+  TOUCH_OUTPUT_TEMPLATE = """
+{class_name} touching {iface_name}
+{touch_output}
+""".strip()
+
+  def __init__(self, ifaces):
+    """
+    Initialize this test class which implements the given interfaces
+    """
+    self.ifaces = ifaces
+    self.class_name = "CLASS_"+gensym()
+
+  def get_name(self):
+    """
+    Gets the name of this interface
+    """
+    return self.class_name
+
+  def get_tree(self):
+    """
+    Print out a representation of the type tree of this class
+    """
+    return "[{fname} {iftree}]".format(fname = self.get_name(), iftree = print_tree(self.ifaces))
+
+  def get_initialize_output(self):
+    return "\n".join(map(lambda i: i.get_initialize_output().strip(), dump_tree(self.ifaces)))
+
+  def get_touch_output(self):
+    return "\n".join(map(lambda a: self.TOUCH_OUTPUT_TEMPLATE.format(
+                                      class_name = self.class_name,
+                                      iface_name = a.get_name(),
+                                      touch_output = a.get_touch_output()).strip(),
+                         self.get_all_interfaces()))
+
+  def get_all_interfaces(self):
+    """
+    Returns a set of all interfaces this class transitively implements
+    """
+    return sorted(set(dump_tree(self.ifaces)))
+
+  def __str__(self):
+    """
+    Print the smali code for this class.
+    """
+    s_ifaces = '\n'.join(map(lambda a: self.IMPLEMENTS_TEMPLATE.format(iface_name = a.get_name()),
+                             self.ifaces))
+    j_ifaces = ', '.join(map(lambda a: a.get_name(), self.ifaces))
+    touches  = '\n'.join(map(lambda a: self.TOUCH_CALL_TEMPLATE.format(class_name = self.class_name,
+                                                                       iface_name = a.get_name()),
+                             self.get_all_interfaces()))
+    return self.TEST_CLASS_TEMPLATE.format(copyright = get_copyright('smali'),
+                                           implements_spec = s_ifaces,
+                                           ifaces = j_ifaces,
+                                           class_name = self.class_name,
+                                           touch_calls = touches)
+
+class TestInterface(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin):
+  """
+  An interface that will be used to test default method resolution order.
+  """
+
+  TEST_INTERFACE_TEMPLATE = """{copyright}
+.class public abstract interface L{class_name};
+.super Ljava/lang/Object;
+{implements_spec}
+
+# public interface {class_name} {extends} {ifaces} {{
+#   public static final Displayer field = new Displayer("{tree}");
+.field public final static field:LDisplayer;
+
+.method public static constructor <clinit>()V
+    .locals 3
+    const-string v2, "{tree}"
+    new-instance v1, LDisplayer;
+    invoke-direct {{v1, v2}}, LDisplayer;-><init>(Ljava/lang/String;)V
+    sput-object v1, L{class_name};->field:LDisplayer;
+    return-void
+.end method
+
+#   public void marker();
+.method public abstract marker()V
+.end method
+
+{funcs}
+
+# }}
+"""
+
+  DEFAULT_FUNC_TEMPLATE = """
+#   public default void {class_name}_DEFAULT_FUNC() {{
+#     return;
+#   }}
+.method public {class_name}_DEFAULT_FUNC()V
+  .locals 0
+  return-void
+.end method
+"""
+  IMPLEMENTS_TEMPLATE = """
+.implements L{iface_name};
+"""
+
+  OUTPUT_TEMPLATE = "initialization of {tree}"
+
+  def __init__(self, ifaces, default):
+    """
+    Initialize interface with the given super-interfaces
+    """
+    self.ifaces = ifaces
+    self.default = default
+    end = "_DEFAULT" if default else ""
+    self.class_name = "INTERFACE_"+gensym()+end
+    self.cloned = False
+    self.initialized = False
+
+  def clone(self):
+    """
+    Clones this interface, returning a new one with the same structure but
+    different name.
+    """
+    return TestInterface(tuple(map(lambda a: a.clone(), self.ifaces)), self.default)
+
+  def get_name(self):
+    """
+    Gets the name of this interface
+    """
+    return self.class_name
+
+  def __iter__(self):
+    """
+    Performs depth-first traversal of the interface tree this interface is the
+    root of. Does not filter out repeats.
+    """
+    for i in self.ifaces:
+      yield i
+      yield from i
+
+  def get_tree(self):
+    """
+    Print out a representation of the type tree of this class
+    """
+    return "[{class_name} {iftree}]".format(class_name = self.get_name(),
+                                            iftree = print_tree(self.ifaces))
+
+  def get_initialize_output(self):
+    """
+    Returns the expected output upon the class that implements this interface being initialized.
+    """
+    if self.default and not self.initialized:
+      self.initialized = True
+      return self.OUTPUT_TEMPLATE.format(tree = self.get_tree())
+    else:
+      return ""
+
+  def get_touch_output(self):
+    """
+    Returns the expected output upon this interface being touched.
+    """
+    if not self.default and not self.initialized:
+      self.initialized = True
+      return self.OUTPUT_TEMPLATE.format(tree = self.get_tree())
+    else:
+      return ""
+
+  def __str__(self):
+    """
+    Print the smali code for this interface.
+    """
+    s_ifaces = '\n'.join(map(lambda a: self.IMPLEMENTS_TEMPLATE.format(iface_name = a.get_name()),
+                             self.ifaces))
+    j_ifaces = ', '.join(map(lambda a: a.get_name(), self.ifaces))
+    if self.default:
+      funcs = self.DEFAULT_FUNC_TEMPLATE.format(class_name = self.class_name)
+    else:
+      funcs = ""
+    return self.TEST_INTERFACE_TEMPLATE.format(copyright = get_copyright('smali'),
+                                               implements_spec = s_ifaces,
+                                               extends = "extends" if len(self.ifaces) else "",
+                                               ifaces = j_ifaces,
+                                               funcs = funcs,
+                                               tree = self.get_tree(),
+                                               class_name = self.class_name)
+
+def dump_tree(ifaces):
+  """
+  Yields all the interfaces transitively implemented by the set in
+  reverse-depth-first order
+  """
+  for i in ifaces:
+    yield from dump_tree(i.ifaces)
+    yield i
+
+def print_tree(ifaces):
+  """
+  Prints the tree for the given ifaces.
+  """
+  return " ".join(i.get_tree() for i in  ifaces)
+
+def clone_all(l):
+  return tuple(a.clone() for a in l)
+
+# Cached output of subtree_sizes for speed of access.
+SUBTREES = [set(tuple(l) for l in subtree_sizes(i))
+            for i in range(MAX_IFACE_DEPTH + 1)]
+
+def create_test_classes():
+  """
+  Yield all the test classes with the different interface trees
+  """
+  for num in range(1, MAX_IFACE_DEPTH + 1):
+    for split in SUBTREES[num]:
+      ifaces = []
+      for sub in split:
+        ifaces.append(list(create_interface_trees(sub)))
+    for supers in itertools.product(*ifaces):
+      yield TestClass(clone_all(supers))
+      for i in range(len(set(dump_tree(supers)) - set(supers))):
+        ns = clone_all(supers)
+        selected = sorted(set(dump_tree(ns)) - set(ns))[i]
+        yield TestClass(tuple([selected] + list(ns)))
+
+def create_interface_trees(num):
+  """
+  Yield all the interface trees up to 'num' depth.
+  """
+  if num == 0:
+    yield TestInterface(tuple(), False)
+    yield TestInterface(tuple(), True)
+    return
+  for split in SUBTREES[num]:
+    ifaces = []
+    for sub in split:
+      ifaces.append(list(create_interface_trees(sub)))
+    for supers in itertools.product(*ifaces):
+      yield TestInterface(clone_all(supers), False)
+      yield TestInterface(clone_all(supers), True)
+      # TODO Should add on some from higher up the tree.
+
+def create_all_test_files():
+  """
+  Creates all the objects representing the files in this test. They just need to
+  be dumped.
+  """
+  mc = MainClass()
+  classes = {mc}
+  for clazz in create_test_classes():
+    classes.add(clazz)
+    for i in dump_tree(clazz.ifaces):
+      classes.add(i)
+    mc.add_test(clazz)
+  return mc, classes
+
+def main(argv):
+  smali_dir = Path(argv[1])
+  if not smali_dir.exists() or not smali_dir.is_dir():
+    print("{} is not a valid smali dir".format(smali_dir), file=sys.stderr)
+    sys.exit(1)
+  expected_txt = Path(argv[2])
+  mainclass, all_files = create_all_test_files()
+  with expected_txt.open('w') as out:
+    print(mainclass.get_expected(), file=out)
+  for f in all_files:
+    f.dump(smali_dir)
+
+if __name__ == '__main__':
+  main(sys.argv)
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 537873f..ad64b68 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -214,11 +214,22 @@
   055-enum-performance \
   133-static-invoke-super
 
- # disable timing sensitive tests on "dist" builds.
+# Tests that require python3.
+TEST_ART_PYTHON3_DEPENDENCY_RUN_TESTS := \
+  960-default-smali \
+  961-default-iface-resolution-generated \
+  964-default-iface-init-generated \
+
+# disable timing sensitive tests on "dist" builds.
 ifdef dist_goal
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
         $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
         $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(ALL_ADDRESS_SIZES))
+
+  # Currently disable tsts requiring python3.
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+        $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+        $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_PYTHON3_DEPENDENCY_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 endif
 
 TEST_ART_TIMING_SENSITIVE_RUN_TESTS :=
diff --git a/test/etc/default-build b/test/etc/default-build
index c281bca..c92402b 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -26,6 +26,8 @@
     option="$1"
     DX_FLAGS="${DX_FLAGS} $option"
     shift
+  elif [ "x$1" = "x--jvm" ]; then
+    shift
   elif expr "x$1" : "x--" >/dev/null 2>&1; then
     echo "unknown $0 option: $1" 1>&2
     exit 1
diff --git a/test/run-all-tests b/test/run-all-tests
index 13490c4..76283b7 100755
--- a/test/run-all-tests
+++ b/test/run-all-tests
@@ -41,6 +41,9 @@
     if [ "x$1" = "x--host" ]; then
         run_args="${run_args} --host"
         shift
+    elif [ "x$1" = "x--use-java-home" ]; then
+        run_args="${run_args} --use-java-home"
+        shift
     elif [ "x$1" = "x--jvm" ]; then
         run_args="${run_args} --jvm"
         shift
@@ -133,7 +136,7 @@
         echo "    --debug --dev --host --interpreter --jit --jvm --no-optimize"
         echo "    --no-verify -O --update --valgrind --zygote --64 --relocate"
         echo "    --prebuild --always-clean --gcstress --gcverify --trace"
-        echo "    --no-patchoat --no-dex2oat"
+        echo "    --no-patchoat --no-dex2oat --use-java-home"
         echo "  Specific Runtime Options:"
         echo "    --seq                Run tests one-by-one, avoiding failures caused by busy CPU"
     ) 1>&2
diff --git a/test/run-test b/test/run-test
index 2892ce9..1b71f33 100755
--- a/test/run-test
+++ b/test/run-test
@@ -40,7 +40,6 @@
   tmp_dir="${TMPDIR}/$USER/${test_dir}"
 fi
 checker="${progdir}/../tools/checker/checker.py"
-
 export JAVA="java"
 export JAVAC="javac -g"
 export RUN="${progdir}/etc/run-test-jar"
@@ -155,6 +154,15 @@
         DEX_LOCATION=$tmp_dir
         run_args="${run_args} --host"
         shift
+    elif [ "x$1" = "x--use-java-home" ]; then
+        if [ -n "${JAVA_HOME}" ]; then
+          export JAVA="${JAVA_HOME}/bin/java"
+          export JAVAC="${JAVA_HOME}/bin/javac -g"
+        else
+          echo "Passed --use-java-home without JAVA_HOME variable set!"
+          usage="yes"
+        fi
+        shift
     elif [ "x$1" = "x--jvm" ]; then
         target_mode="no"
         runtime="jvm"
@@ -162,6 +170,7 @@
         NEED_DEX="false"
         USE_JACK="false"
         run_args="${run_args} --jvm"
+        build_args="${build_args} --jvm"
         shift
     elif [ "x$1" = "x-O" ]; then
         lib="libart.so"
@@ -560,6 +569,9 @@
         echo "    --invoke-with         Pass --invoke-with option to runtime."
         echo "    --dalvik              Use Dalvik (off by default)."
         echo "    --jvm                 Use a host-local RI virtual machine."
+        echo "    --use-java-home       Use the JAVA_HOME environment variable"
+        echo "                          to find the java compiler and runtime"
+        echo "                          (if applicable) to run the test with."
         echo "    --output-path [path]  Location where to store the build" \
              "files."
         echo "    --64                  Run the test in 64-bit mode"
diff --git a/test/utils/python/testgen/mixins.py b/test/utils/python/testgen/mixins.py
new file mode 100644
index 0000000..085e51d
--- /dev/null
+++ b/test/utils/python/testgen/mixins.py
@@ -0,0 +1,135 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Common mixins and abstract base classes (ABCs) useful for writing test generators in python
+"""
+
+import abc
+import collections.abc
+import functools
+
+class Named(metaclass=abc.ABCMeta):
+  """
+  An abc that defines a get_name method.
+  """
+
+  @abc.abstractmethod
+  def get_name(self):
+    """
+    Returns a unique name to use as the identity for implementing comparisons.
+    """
+    pass
+
+class FileLike(metaclass=abc.ABCMeta):
+  """
+  An abc that defines get_file_name and get_file_extension methods.
+  """
+
+  @abc.abstractmethod
+  def get_file_name(self):
+    """Returns the filename this object represents"""
+    pass
+
+  @abc.abstractmethod
+  def get_file_extension(self):
+    """Returns the file extension of the file this object represents"""
+    pass
+
+@functools.lru_cache(maxsize=None)
+def get_file_extension_mixin(ext):
+  """
+  Gets a mixin that defines get_file_name(self) in terms of get_name(self) with the
+  given file extension.
+  """
+
+  class FExt(object):
+    """
+    A mixin defining get_file_name(self) in terms of get_name(self)
+    """
+
+    def get_file_name(self):
+      return self.get_name() + ext
+
+    def get_file_extension(self):
+      return ext
+
+  # Register the ABCs
+  Named.register(FExt)
+  FileLike.register(FExt)
+
+  return FExt
+
+class SmaliFileMixin(get_file_extension_mixin(".smali")):
+  """
+  A mixin that defines that the file this class belongs to is get_name() + ".smali".
+  """
+  pass
+
+class NameComparableMixin(object):
+  """
+  A mixin that defines the object comparison and related functionality in terms
+  of a get_name(self) function.
+  """
+
+  def __lt__(self, other):
+    return self.get_name() < other.get_name()
+
+  def __gt__(self, other):
+    return self.get_name() > other.get_name()
+
+  def __eq__(self, other):
+    return self.get_name() == other.get_name()
+
+  def __le__(self, other):
+    return self.get_name() <= other.get_name()
+
+  def __ge__(self, other):
+    return self.get_name() >= other.get_name()
+
+  def __ne__(self, other):
+    return self.get_name() != other.get_name()
+
+  def __hash__(self):
+    return hash(self.get_name())
+
+Named.register(NameComparableMixin)
+collections.abc.Hashable.register(NameComparableMixin)
+
+class DumpMixin(metaclass=abc.ABCMeta):
+  """
+  A mixin to add support for dumping the string representation of an object to a
+  file. Requires the get_file_name(self) method be defined.
+  """
+
+  @abc.abstractmethod
+  def __str__(self):
+    """
+    Returns the data to be printed to a file by dump.
+    """
+    pass
+
+  def dump(self, directory):
+    """
+    Dump this object to a file in the given directory
+    """
+    out_file = directory / self.get_file_name()
+    if out_file.exists():
+      out_file.unlink()
+    with out_file.open('w') as out:
+      print(str(self), file=out)
+
+FileLike.register(DumpMixin)
diff --git a/test/utils/python/testgen/utils.py b/test/utils/python/testgen/utils.py
new file mode 100644
index 0000000..769ad16
--- /dev/null
+++ b/test/utils/python/testgen/utils.py
@@ -0,0 +1,80 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Common functions useful for writing test generators in python
+"""
+
+import itertools
+import os
+import string
+from pathlib import Path
+
+BUILD_TOP = os.getenv("ANDROID_BUILD_TOP")
+if BUILD_TOP is None:
+  print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr)
+  sys.exit(1)
+
+# An iterator which yields strings made from lowercase letters. First yields
+# all 1 length strings, then all 2 and so on. It does this alphabetically.
+NAME_GEN = itertools.chain.from_iterable(
+    map(lambda n: itertools.product(string.ascii_lowercase, repeat=n),
+        itertools.count(1)))
+
+def gensym():
+  """
+  Returns a new, globally unique, identifier name that is a valid Java symbol
+  on each call.
+  """
+  return ''.join(next(NAME_GEN))
+
+def filter_blanks(s):
+  """
+  Takes a string returns the same string sans empty lines
+  """
+  return "\n".join(a for a in s.split("\n") if a.strip() != "")
+
+def get_copyright(filetype = "java"):
+  """
+  Returns the standard copyright header for the given filetype
+  """
+  if filetype == "smali":
+    return "\n".join(map(lambda a: "# " + a, get_copyright("java").split("\n")))
+  else:
+    fname = filetype + ".txt"
+    with (Path(BUILD_TOP)/"development"/"docs"/"copyright-templates"/fname).open() as template:
+      return "".join(template.readlines())
+
+def subtree_sizes(n):
+  """
+  A generator that yields a tuple containing a possible arrangement of subtree
+  nodes for a tree with a total of 'n' leaf nodes.
+  """
+  if n == 0:
+    return
+  elif n == 1:
+    yield (0,)
+  elif n == 2:
+    yield (1, 1)
+  else:
+    for prevt in subtree_sizes(n - 1):
+      prev = list(prevt)
+      yield tuple([1] + prev)
+      for i in range(len(prev)):
+        prev[i] += 1
+        yield tuple(prev)
+        prev[i] -= 1
+
diff --git a/tools/extract-embedded-java b/tools/extract-embedded-java
new file mode 100755
index 0000000..e966552
--- /dev/null
+++ b/tools/extract-embedded-java
@@ -0,0 +1,35 @@
+#!/bin/bash
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [ "$#" -ne "2" ]; then
+  echo "Usage: ./extract_embedded_java.sh smali_dir java_dir"
+  exit 1
+fi
+
+# Check the input and output are directories
+[[ -d "$1" ]] || exit 1
+[[ -d "$2" ]] || exit 1
+
+# For every file which has the file extension smali, set $f to be the name without
+# .smali and then:
+for f in `find "$1" -type f -name "*.smali" | xargs -n 1 -P 0 -i basename -s .smali \{\}`; do
+  # remove all lines except those starting with '# ', remove the '#' then print
+  # it to a file ${name}.java. Do this concurrently.
+  grep "^# " "$1/${f}.smali" | sed "s:# ::" > "${2}/${f}.java" &
+done
+
+# wait for all the files to be written
+wait