Merge "Fix invoke-virtual not throwing ICCE in some cases"
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 73c6cf1..1aa6a00 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -227,9 +227,10 @@
     case kDirect:
       return !IsDirect() || IsStatic();
     case kVirtual: {
-      // We have an error if we are direct or a non-default, non-miranda interface method.
+      // We have an error if we are direct or a non-copied (i.e. not part of a real class) interface
+      // method.
       mirror::Class* methods_class = GetDeclaringClass();
-      return IsDirect() || (methods_class->IsInterface() && !IsDefault() && !IsMiranda());
+      return IsDirect() || (methods_class->IsInterface() && !IsCopied());
     }
     case kSuper:
       // Constructors and static methods are called with invoke-direct.
diff --git a/test/978-virtual-interface/build b/test/978-virtual-interface/build
new file mode 100755
index 0000000..14230c2
--- /dev/null
+++ b/test/978-virtual-interface/build
@@ -0,0 +1,20 @@
+#!/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
+
+./default-build "$@" --experimental default-methods
diff --git a/test/978-virtual-interface/expected.txt b/test/978-virtual-interface/expected.txt
new file mode 100644
index 0000000..99071b1
--- /dev/null
+++ b/test/978-virtual-interface/expected.txt
@@ -0,0 +1 @@
+Recieved expected ICCE error!
diff --git a/test/978-virtual-interface/info.txt b/test/978-virtual-interface/info.txt
new file mode 100644
index 0000000..0b8a39f
--- /dev/null
+++ b/test/978-virtual-interface/info.txt
@@ -0,0 +1,7 @@
+Smali-based regression test for b/32201623
+
+This test cannot be run with --jvm.
+
+This test checks that we correctly detect when one attempts to invoke an
+interface method via the invoke-virtual opcode and that correct exceptions are
+sent.
diff --git a/test/978-virtual-interface/smali/Iface.smali b/test/978-virtual-interface/smali/Iface.smali
new file mode 100644
index 0000000..9c3ef7a
--- /dev/null
+++ b/test/978-virtual-interface/smali/Iface.smali
@@ -0,0 +1,110 @@
+# /*
+#  * 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.
+#  */
+#
+# // Methods are sorted in alphabetical order in dex file. We need 10 padding
+# // methods to ensure the 11'th target lines up to the same vtable slot as the
+# // first Subtype virtual method (the other 10 are the java/lang/Object;
+# // methods).
+# interface Iface {
+#   public default void fakeMethod_A() {}
+#   public default void fakeMethod_B() {}
+#   public default void fakeMethod_C() {}
+#   public default void fakeMethod_D() {}
+#   public default void fakeMethod_E() {}
+#   public default void fakeMethod_F() {}
+#   public default void fakeMethod_G() {}
+#   public default void fakeMethod_H() {}
+#   public default void fakeMethod_I() {}
+#   public default void fakeMethod_J() {}
+#   public default void fakeMethod_K() {}
+#   public default void fakeMethod_Target() {}
+# }
+
+.class public abstract interface LIface;
+
+.super Ljava/lang/Object;
+
+# // 1
+.method public fakeMethod_A()V
+  .locals 0
+  return-void
+.end method
+
+# // 2
+.method public fakeMethod_B()V
+  .locals 0
+  return-void
+.end method
+
+# // 3
+.method public fakeMethod_C()V
+  .locals 0
+  return-void
+.end method
+
+# // 4
+.method public fakeMethod_D()V
+  .locals 0
+  return-void
+.end method
+
+# // 5
+.method public fakeMethod_E()V
+  .locals 0
+  return-void
+.end method
+
+# // 5
+.method public fakeMethod_F()V
+  .locals 0
+  return-void
+.end method
+
+# // 6
+.method public fakeMethod_G()V
+  .locals 0
+  return-void
+.end method
+
+# // 7
+.method public fakeMethod_H()V
+  .locals 0
+  return-void
+.end method
+
+# // 8
+.method public fakeMethod_I()V
+  .locals 0
+  return-void
+.end method
+
+# // 9
+.method public fakeMethod_J()V
+  .locals 0
+  return-void
+.end method
+
+# // 10
+.method public fakeMethod_K()V
+  .locals 0
+  return-void
+.end method
+
+# // 11
+.method public fakeMethod_Target()V
+  .locals 0
+  return-void
+.end method
diff --git a/test/978-virtual-interface/smali/Main.smali b/test/978-virtual-interface/smali/Main.smali
new file mode 100644
index 0000000..61b82f3
--- /dev/null
+++ b/test/978-virtual-interface/smali/Main.smali
@@ -0,0 +1,50 @@
+# /*
+#  * Copyright (C) 2015 The Android Open Source Project
+#  *
+#  * Licensed under the Apache License, Version 2.0 (the "License");
+#  * you may not use this file except in compliance with the License.
+#  * You may obtain a copy of the License at
+#  *
+#  *      http://www.apache.org/licenses/LICENSE-2.0
+#  *
+#  * Unless required by applicable law or agreed to in writing, software
+#  * distributed under the License is distributed on an "AS IS" BASIS,
+#  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  * See the License for the specific language governing permissions and
+#  * limitations under the License.
+#  */
+#
+# public class Main {
+#   public static void main(String[] s) {
+#     Subtype s = new Subtype();
+#     try {
+#       s.callPackage();
+#       System.out.println("No error thrown!");
+#     } catch (IncompatibleClassChangeError e) {
+#       System.out.println("Recieved expected ICCE error!");
+#     }
+#   }
+# }
+
+.class public LMain;
+
+.super Ljava/lang/Object;
+
+.method public static main([Ljava/lang/String;)V
+    .locals 3
+
+    new-instance v0, LSubtype;
+    invoke-direct {v0}, LSubtype;-><init>()V
+    sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    :try_start
+        invoke-virtual {v0}, LSubtype;->callPackage()V
+        const-string v1, "No error thrown!"
+        invoke-virtual {v2, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+        return-void
+    :try_end
+    .catch Ljava/lang/IncompatibleClassChangeError; {:try_start .. :try_end} :error_start
+    :error_start
+        const-string v1, "Recieved expected ICCE error!"
+        invoke-virtual {v2, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+        return-void
+.end method
diff --git a/test/978-virtual-interface/smali/Subtype.smali b/test/978-virtual-interface/smali/Subtype.smali
new file mode 100644
index 0000000..f876cf9
--- /dev/null
+++ b/test/978-virtual-interface/smali/Subtype.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 class Subtype extends pkg.Target implements Iface{
+#    public void callPackage() {
+#      // Fake into a virtual call.
+#      // ((Iface)this).fakeMethod_Target();
+#    }
+#  }
+
+.class public LSubtype;
+
+.super Lpkg/Target;
+
+.implements LIface;
+
+.method public constructor <init>()V
+    .locals 0
+    invoke-direct {p0}, Lpkg/Target;-><init>()V
+    return-void
+.end method
+
+.method public callPackage()V
+    .locals 0
+    invoke-virtual {p0}, LIface;->fakeMethod_Target()V
+    return-void
+.end method
diff --git a/test/978-virtual-interface/smali/Target.smali b/test/978-virtual-interface/smali/Target.smali
new file mode 100644
index 0000000..70108fb
--- /dev/null
+++ b/test/978-virtual-interface/smali/Target.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.
+#  */
+#
+#  package pkg;
+#  public class Target {
+#    public void packageMethod() {
+#      System.out.println("Package method called!");
+#    }
+#  }
+
+.class public Lpkg/Target;
+
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+    .locals 0
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method packageMethod()V
+    .locals 2
+    const-string v1, "Package method called!"
+    sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+    return-void
+.end method