Support directly invoking interface default methods

With the Java 8 Language one is allowed to directly call default
interface methods of interfaces one (directly) implements through the
use of the super keyword. We support this behavior through the
invoke-super opcode with the target being an interface.

We add 3 tests for this behavior.

Currently only supports slow-path interpreter.

Invoke-super is currently extremely slow.

Bug: 24618811

Change-Id: I7e06e17326f7dbae0116bd7dfefca151f0092bd2
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index ba2fb94..9a9f42b 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -416,10 +416,10 @@
     return nullptr;  // Failure.
   } else if (access_check) {
     mirror::Class* methods_class = resolved_method->GetDeclaringClass();
-    mirror::Class* referring_class = referrer->GetDeclaringClass();
     bool can_access_resolved_method =
-        referring_class->CheckResolvedMethodAccess<type>(methods_class, resolved_method,
-                                                         method_idx);
+        referrer->GetDeclaringClass()->CheckResolvedMethodAccess<type>(methods_class,
+                                                                       resolved_method,
+                                                                       method_idx);
     if (UNLIKELY(!can_access_resolved_method)) {
       DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
       return nullptr;  // Failure.
@@ -450,23 +450,56 @@
       return klass->GetVTableEntry(vtable_index, class_linker->GetImagePointerSize());
     }
     case kSuper: {
-      mirror::Class* super_class = referrer->GetDeclaringClass()->GetSuperClass();
-      uint16_t vtable_index = resolved_method->GetMethodIndex();
-      if (access_check) {
-        // Check existence of super class.
-        if (super_class == nullptr || !super_class->HasVTable() ||
-            vtable_index >= static_cast<uint32_t>(super_class->GetVTableLength())) {
-          // Behavior to agree with that of the verifier.
+      // TODO This lookup is quite slow.
+      // NB This is actually quite tricky to do any other way. We cannot use GetDeclaringClass since
+      //    that will actually not be what we want in some cases where there are miranda methods or
+      //    defaults. What we actually need is a GetContainingClass that says which classes virtuals
+      //    this method is coming from.
+      mirror::Class* referring_class = referrer->GetDeclaringClass();
+      uint16_t method_type_idx = referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
+      mirror::Class* method_reference_class = class_linker->ResolveType(method_type_idx, referrer);
+      if (UNLIKELY(method_reference_class == nullptr)) {
+        // Bad type idx.
+        CHECK(self->IsExceptionPending());
+        return nullptr;
+      } else if (!method_reference_class->IsInterface()) {
+        // It is not an interface.
+        mirror::Class* super_class = referring_class->GetSuperClass();
+        uint16_t vtable_index = resolved_method->GetMethodIndex();
+        if (access_check) {
+          // Check existence of super class.
+          if (super_class == nullptr || !super_class->HasVTable() ||
+              vtable_index >= static_cast<uint32_t>(super_class->GetVTableLength())) {
+            // Behavior to agree with that of the verifier.
+            ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
+                                   resolved_method->GetName(), resolved_method->GetSignature());
+            return nullptr;  // Failure.
+          }
+        }
+        DCHECK(super_class != nullptr);
+        DCHECK(super_class->HasVTable());
+        return super_class->GetVTableEntry(vtable_index, class_linker->GetImagePointerSize());
+      } else {
+        // It is an interface.
+        if (access_check) {
+          if (!method_reference_class->IsAssignableFrom((*this_object)->GetClass())) {
+            ThrowIncompatibleClassChangeErrorClassForInterfaceSuper(resolved_method,
+                                                                    method_reference_class,
+                                                                    *this_object,
+                                                                    referrer);
+            return nullptr;  // Failure.
+          }
+        }
+        // TODO We can do better than this for a (compiled) fastpath.
+        ArtMethod* result = method_reference_class->FindVirtualMethodForInterfaceSuper(
+            resolved_method, class_linker->GetImagePointerSize());
+        // Throw an NSME if nullptr;
+        if (result == nullptr) {
           ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
                                  resolved_method->GetName(), resolved_method->GetSignature());
-          return nullptr;  // Failure.
         }
-      } else {
-        // Super class must exist.
-        DCHECK(super_class != nullptr);
+        return result;
       }
-      DCHECK(super_class->HasVTable());
-      return super_class->GetVTableEntry(vtable_index, class_linker->GetImagePointerSize());
     }
     case kInterface: {
       uint32_t imt_index = resolved_method->GetDexMethodIndex() % mirror::Class::kImtSize;
@@ -576,8 +609,9 @@
   if (UNLIKELY(this_object == nullptr && type != kStatic)) {
     return nullptr;
   }
+  mirror::Class* referring_class = referrer->GetDeclaringClass();
   ArtMethod* resolved_method =
-      referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx, sizeof(void*));
+      referring_class->GetDexCache()->GetResolvedMethod(method_idx, sizeof(void*));
   if (UNLIKELY(resolved_method == nullptr)) {
     return nullptr;
   }
@@ -588,7 +622,6 @@
       return nullptr;
     }
     mirror::Class* methods_class = resolved_method->GetDeclaringClass();
-    mirror::Class* referring_class = referrer->GetDeclaringClass();
     if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
                  !referring_class->CanAccessMember(methods_class,
                                                    resolved_method->GetAccessFlags()))) {
@@ -601,12 +634,25 @@
   } else if (type == kStatic || type == kDirect) {
     return resolved_method;
   } else if (type == kSuper) {
-    mirror::Class* super_class = referrer->GetDeclaringClass()->GetSuperClass();
-    if (resolved_method->GetMethodIndex() >= super_class->GetVTableLength()) {
-      // The super class does not have the method.
+    // TODO This lookup is rather slow.
+    uint16_t method_type_idx = referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
+    mirror::Class* method_reference_class =
+        referring_class->GetDexCache()->GetResolvedType(method_type_idx);
+    if (method_reference_class == nullptr) {
+      // Need to do full type resolution...
       return nullptr;
+    } else if (!method_reference_class->IsInterface()) {
+      // It is not an interface.
+      mirror::Class* super_class = referrer->GetDeclaringClass()->GetSuperClass();
+      if (resolved_method->GetMethodIndex() >= super_class->GetVTableLength()) {
+        // The super class does not have the method.
+        return nullptr;
+      }
+      return super_class->GetVTableEntry(resolved_method->GetMethodIndex(), sizeof(void*));
+    } else {
+      return method_reference_class->FindVirtualMethodForInterfaceSuper(
+          resolved_method, sizeof(void*));
     }
-    return super_class->GetVTableEntry(resolved_method->GetMethodIndex(), sizeof(void*));
   } else {
     DCHECK(type == kVirtual);
     return this_object->GetClass()->GetVTableEntry(