Add initial default method support to Art

This commit starts the process of adding default methods and their
associated pieces to ART.

This adds full support for calling default methods using
invoke-interface and invoke-virtual on objects implementing the
interfaces. Verifier is changed to allow this when the runtime is
started with -Xexperimental:default-methods.

This also adds support for defining and calling static methods on
interface classes with invoke-static.

Directly calling overridden default methods using invoke-super is not
yet supported.

This adds 5 new run-tests for this functionality.

Bug: 24618811

Change-Id: I35ca800d99d3329348b277789b70ceeeba6e7f03
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/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/class_linker.cc b/runtime/class_linker.cc
index 9349fe3..8448c0a 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>
 
@@ -3337,6 +3340,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 +3478,35 @@
     }
   }
 
+  if (!klass->IsInterface()) {
+    // Initialize interfaces with default methods for the JLS.
+    size_t num_direct_interfaces = klass->NumDirectInterfaces();
+    for (size_t i = 0; i < num_direct_interfaces; i++) {
+      StackHandleScope<1> hs_iface(self);
+      Handle<mirror::Class> handle_scope_iface(
+          hs_iface.NewHandle(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 once 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 +3596,48 @@
   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();
+  // 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
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Class> handle_super_iface(hs.NewHandle(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 +4370,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 +4503,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 +4548,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 +4584,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 +4603,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 +4629,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 +4721,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 +4961,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 +4977,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 +4991,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 +5056,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 +5086,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 +5109,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 +5154,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 +5169,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 +5190,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 +5272,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 +5310,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 +5349,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 +5367,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 +5420,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.
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/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/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/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/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..41a174c 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);
 }
@@ -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..97d5a5e 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 {
@@ -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_;
 
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/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/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/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