Optimizing compiler support for directly calling interface methods

This teaches the optimizing compiler how to perform invoke-super on
interfaces. This should make the invokes generally faster.

Bug: 24618811

Change-Id: I7f9b0fb1209775c1c8837ab5d21f8acba3cc72a5
diff --git a/test/563-checker-invoke-super/build b/test/563-checker-invoke-super/build
new file mode 100755
index 0000000..e06193b
--- /dev/null
+++ b/test/563-checker-invoke-super/build
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# Copyright 2016 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
+
+# Hard-wired use of experimental jack.
+# TODO: fix this temporary work-around for lambdas, see b/19467889
+export USE_JACK=true
+export JACK_SERVER=false
+export JACK_REPOSITORY="${ANDROID_BUILD_TOP}/prebuilts/sdk/tools/jacks"
+
+# e.g. /foo/bar/jack-3.10.ALPHA.jar -> 3.10.ALPHA
+export JACK_VERSION="$(find "$JACK_REPOSITORY" -name '*ALPHA*' | sed 's/.*jack-//g' | sed 's/[.]jar//g')"
+./default-build "$@" --experimental default-methods
diff --git a/test/563-checker-invoke-super/expected.txt b/test/563-checker-invoke-super/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/563-checker-invoke-super/expected.txt
diff --git a/test/563-checker-invoke-super/info.txt b/test/563-checker-invoke-super/info.txt
new file mode 100644
index 0000000..23c0d2f
--- /dev/null
+++ b/test/563-checker-invoke-super/info.txt
@@ -0,0 +1,2 @@
+Tests that invoke-super's to interface methods are optimized to direct method
+calls when in the same dex file.
diff --git a/test/563-checker-invoke-super/src/Main.java b/test/563-checker-invoke-super/src/Main.java
new file mode 100644
index 0000000..8554dbd
--- /dev/null
+++ b/test/563-checker-invoke-super/src/Main.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+interface IFace {
+  public default void $noinline$aMethod() { throw new RuntimeException("Should not be called"); }
+}
+
+class ClassImplA implements IFace {
+  /// CHECK-START: void ClassImplA.testSuperInvoke() builder (after)
+  /// CHECK:                       InvokeStaticOrDirect
+  public void testSuperInvoke() {
+    IFace.super.$noinline$aMethod();
+  }
+}
+
+class ClassImplB extends ClassImplA {
+  /// CHECK-START: void ClassImplB.testSuperInvoke2() builder (after)
+  /// CHECK:                       InvokeStaticOrDirect
+  public void testSuperInvoke2() {
+    super.$noinline$aMethod();
+  }
+}
+
+public class Main {
+  public static void main(String[] args) { }
+}
diff --git a/test/972-iface-super-multidex/expected.txt b/test/972-iface-super-multidex/expected.txt
new file mode 100644
index 0000000..a9d31a5
--- /dev/null
+++ b/test/972-iface-super-multidex/expected.txt
@@ -0,0 +1,2 @@
+SuperInterface default method called
+Expected ICCE caught
diff --git a/test/972-iface-super-multidex/info.txt b/test/972-iface-super-multidex/info.txt
new file mode 100644
index 0000000..f7948ad
--- /dev/null
+++ b/test/972-iface-super-multidex/info.txt
@@ -0,0 +1,3 @@
+Smali-based tests for experimental interface default methods.
+
+Obviously needs to run under ART or a Java 8 Language runtime and compiler.
diff --git a/test/972-iface-super-multidex/smali-multidex/conflictinterface.smali b/test/972-iface-super-multidex/smali-multidex/conflictinterface.smali
new file mode 100644
index 0000000..2c76213
--- /dev/null
+++ b/test/972-iface-super-multidex/smali-multidex/conflictinterface.smali
@@ -0,0 +1,23 @@
+#
+# Copyright (C) 2016 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 LConflictInterface;
+.super Ljava/lang/Object;
+.implements LOneConflict;
+.implements LTwoConflict;
+
+# public interface ConflictInterface extends OneConflict, TwoConflict {
+# }
diff --git a/test/972-iface-super-multidex/smali-multidex/oneconflict.smali b/test/972-iface-super-multidex/smali-multidex/oneconflict.smali
new file mode 100644
index 0000000..7001f02
--- /dev/null
+++ b/test/972-iface-super-multidex/smali-multidex/oneconflict.smali
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2016 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 LOneConflict;
+.super Ljava/lang/Object;
+
+# public interface OneConflict {
+#     public String runDefault() {
+#         return "OneConflict default method called";
+#     }
+# }
+
+.method public runDefault()Ljava/lang/String;
+.registers 2
+    # Do an invoke super on this class, to confuse runtime/compiler.
+    const-string v0, "OneConflict default method called"
+    return-object v0
+.end method
diff --git a/test/972-iface-super-multidex/smali-multidex/superinterface.smali b/test/972-iface-super-multidex/smali-multidex/superinterface.smali
new file mode 100644
index 0000000..d45ecea
--- /dev/null
+++ b/test/972-iface-super-multidex/smali-multidex/superinterface.smali
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2016 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 LSuperInterface;
+.super Ljava/lang/Object;
+
+# public interface SuperInterface {
+#     public String runDefault() {
+#         return "SuperInterface default method called";
+#     }
+# }
+
+.method public runDefault()Ljava/lang/String;
+.registers 2
+    # Do an invoke super on this class, to confuse runtime/compiler.
+    const-string v0, "SuperInterface default method called"
+    return-object v0
+.end method
diff --git a/test/972-iface-super-multidex/smali-multidex/twoconflict.smali b/test/972-iface-super-multidex/smali-multidex/twoconflict.smali
new file mode 100644
index 0000000..b971b74
--- /dev/null
+++ b/test/972-iface-super-multidex/smali-multidex/twoconflict.smali
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2016 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 LTwoConflict;
+.super Ljava/lang/Object;
+
+# public interface TwoConflict {
+#     public String runDefault() {
+#         return "TwoConflict default method called";
+#     }
+# }
+
+.method public runDefault()Ljava/lang/String;
+.registers 2
+    # Do an invoke super on this class, to confuse runtime/compiler.
+    const-string v0, "TwoConflict default method called"
+    return-object v0
+.end method
diff --git a/test/972-iface-super-multidex/smali/concreteclass.smali b/test/972-iface-super-multidex/smali/concreteclass.smali
new file mode 100644
index 0000000..703da94
--- /dev/null
+++ b/test/972-iface-super-multidex/smali/concreteclass.smali
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2016 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 LConcreteClass;
+.super Ljava/lang/Object;
+.implements LSuperInterface;
+.implements LConflictInterface;
+
+# public class ConcreteClass implements SuperInterface, ConflictInterface {
+#     public String runReal() {
+#         return SuperInterface.super.runDefault();
+#     }
+#     public String runConflict() {
+#         return ConflictInterface.super.runDefault();
+#     }
+#     public String runDefault() {
+#         return "This is the wrong class to invoke";
+#     }
+# }
+
+.method public constructor <init>()V
+    .registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public runConflict()Ljava/lang/String;
+.registers 2
+    # Do an invoke super on this class, to confuse runtime/compiler.
+    invoke-super {p0}, LConflictInterface;->runDefault()Ljava/lang/String;
+    move-result-object v0
+    return-object v0
+.end method
+
+
+
+.method public runReal()Ljava/lang/String;
+.registers 2
+    # Do an invoke super on this class, to confuse runtime/compiler.
+    invoke-super {p0}, LSuperInterface;->runDefault()Ljava/lang/String;
+    move-result-object v0
+    return-object v0
+.end method
+
+.method public runDefault()Ljava/lang/String;
+.registers 2
+    const-string v0, "This is the wrong class to invoke!"
+    return-object v0
+.end method
diff --git a/test/972-iface-super-multidex/src/Main.java b/test/972-iface-super-multidex/src/Main.java
new file mode 100644
index 0000000..3fb3f45
--- /dev/null
+++ b/test/972-iface-super-multidex/src/Main.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 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.
+ */
+
+import java.lang.reflect.*;
+public class Main {
+  public static void main(String[] args) {
+    Class<?> c = null;
+    try {
+      c = Class.forName("ConcreteClass");
+    } catch (Exception e) {
+      System.out.println("Could not load class");
+      e.printStackTrace();
+      return;
+    }
+    try {
+      Method m = c.getMethod("runReal");
+      System.out.println((String)m.invoke(c.newInstance(), new Object[0]));
+    } catch (Exception e) {
+      System.out.println("Unknown exception occurred");
+      e.printStackTrace();
+    }
+    try {
+      Method m = c.getMethod("runConflict");
+      try {
+        System.out.println((String)m.invoke(c.newInstance(), new Object[0]));
+      } catch (InvocationTargetException e) {
+        throw e.getCause();
+      }
+    } catch (AbstractMethodError e) {
+      System.out.println("Unexpected AME caught");
+      e.printStackTrace();
+    } catch (NoSuchMethodError e) {
+      System.out.println("Unexpected NSME caught");
+      e.printStackTrace();
+    } catch (IncompatibleClassChangeError e) {
+      System.out.println("Expected ICCE caught");
+    } catch (Throwable e) {
+      System.out.println("Unknown exception caught!");
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/test/etc/default-build b/test/etc/default-build
index 7242428..6e855ec 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -42,6 +42,12 @@
   HAS_SRC_MULTIDEX=false
 fi
 
+if [ -d smali-multidex ]; then
+  HAS_SMALI_MULTIDEX=true
+else
+  HAS_SMALI_MULTIDEX=false
+fi
+
 if [ -d src-ex ]; then
   HAS_SRC_EX=true
 else
@@ -74,6 +80,9 @@
   elif [ "x$1" = "x--no-src-multidex" ]; then
     HAS_SRC_MULTIDEX=false
     shift
+  elif [ "x$1" = "x--no-smali-multidex" ]; then
+    HAS_SMALI_MULTIDEX=false
+    shift
   elif [ "x$1" = "x--no-src-ex" ]; then
     HAS_SRC_EX=false
     shift
@@ -171,6 +180,19 @@
   fi
 fi
 
+if [ "${HAS_SMALI_MULTIDEX}" = "true" ]; then
+  # Compile Smali classes
+  ${SMALI} -JXmx512m ${SMALI_ARGS} --output smali_classes2.dex `find smali-multidex -name '*.smali'`
+
+  # Don't bother with dexmerger if we provide our own main function in a smali file.
+  if [ ${HAS_SRC_MULTIDEX} = "true" ]; then
+    ${DXMERGER} classes2.dex classes2.dex smali_classes2.dex
+  else
+    mv smali_classes2.dex classes2.dex
+  fi
+fi
+
+
 if [ ${HAS_SRC_EX} = "true" ]; then
   if [ ${USE_JACK} = "true" ]; then
       # Rename previous "classes.dex" so it is not overwritten.
@@ -198,7 +220,7 @@
 fi
 
 # Create a single jar with two dex files for multidex.
-if [ ${HAS_SRC_MULTIDEX} = "true" ]; then
+if [ ${HAS_SRC_MULTIDEX} = "true" ] || [ ${HAS_SMALI_MULTIDEX} = "true" ]; then
   zip $TEST_NAME.jar classes.dex classes2.dex
 elif [ ${NEED_DEX} = "true" ]; then
   zip $TEST_NAME.jar classes.dex