Basic implementation of invoke / invoke-polymorphic.
Basic switch interpreter support for invoke-polymorphic. This change
allows for virtual/interface and static invokes on method handles.
Support for direct invokes (including constructors) and field
getters and setters will be added in follow up changes.
Bug: 30550796
Test: make test-art-host
Change-Id: Ieb3a991d974060d930d56467908d5c7c11d0e38e
diff --git a/test/955-methodhandles-smali/build b/test/955-methodhandles-smali/build
new file mode 100755
index 0000000..a423ca6
--- /dev/null
+++ b/test/955-methodhandles-smali/build
@@ -0,0 +1,25 @@
+#!/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
+
+if [[ $@ != *"--jvm"* ]]; then
+ # Don't do anything with jvm.
+ export USE_JACK=true
+fi
+
+./default-build "$@" --experimental method-handles
diff --git a/test/955-methodhandles-smali/expected.txt b/test/955-methodhandles-smali/expected.txt
new file mode 100644
index 0000000..07d2422
--- /dev/null
+++ b/test/955-methodhandles-smali/expected.txt
@@ -0,0 +1,2 @@
+[String1]+[String2]
+[String1]
diff --git a/test/955-methodhandles-smali/info.txt b/test/955-methodhandles-smali/info.txt
new file mode 100644
index 0000000..d10d3eb
--- /dev/null
+++ b/test/955-methodhandles-smali/info.txt
@@ -0,0 +1,3 @@
+Smali-based tests for method handle invocations.
+
+NOTE: needs to run under ART or a Java 8 Language runtime and compiler.
diff --git a/test/955-methodhandles-smali/run b/test/955-methodhandles-smali/run
new file mode 100755
index 0000000..a9f1822
--- /dev/null
+++ b/test/955-methodhandles-smali/run
@@ -0,0 +1,20 @@
+#!/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
+
+./default-run "$@" --experimental method-handles
diff --git a/test/955-methodhandles-smali/smali/Main.smali b/test/955-methodhandles-smali/smali/Main.smali
new file mode 100644
index 0000000..2fc92f8
--- /dev/null
+++ b/test/955-methodhandles-smali/smali/Main.smali
@@ -0,0 +1,117 @@
+# 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.
+
+.class LMain;
+.super Ljava/lang/Object;
+
+# MethodHandle Main.getHandleForVirtual(Class<?> defc, String name, MethodType type);
+#
+# Returns a handle to a virtual method on |defc| named name with type |type| using
+# the public lookup object.
+.method public static getHandleForVirtual(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
+.registers 5
+
+ # Get a reference to the public lookup object (MethodHandles.publicLookup()).
+ invoke-static {}, Ljava/lang/invoke/MethodHandles;->publicLookup()Ljava/lang/invoke/MethodHandles$Lookup;
+ move-result-object v0
+
+ # Call Lookup.findVirtual(defc, name, type);
+ invoke-virtual {v0, p0, p1, p2}, Ljava/lang/invoke/MethodHandles$Lookup;->findVirtual(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
+ move-result-object v1
+ return-object v1
+.end method
+
+# MethodHandle Main.getHandleForStatic(Class<?> defc, String name, MethodType type);
+#
+# Returns a handle to a static method on |defc| named name with type |type| using
+# the public lookup object.
+.method public static getHandleForStatic(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
+.registers 5
+
+ # Get a reference to the public lookup object (MethodHandles.publicLookup()).
+ invoke-static {}, Ljava/lang/invoke/MethodHandles;->publicLookup()Ljava/lang/invoke/MethodHandles$Lookup;
+ move-result-object v0
+
+ # Call Lookup.findStatic(defc, name, type);
+ invoke-virtual {v0, p0, p1, p2}, Ljava/lang/invoke/MethodHandles$Lookup;->findStatic(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
+ move-result-object v1
+ return-object v1
+.end method
+
+# Returns a method handle to String java.lang.String.concat(String);
+.method public static getStringConcatHandle()Ljava/lang/invoke/MethodHandle;
+.registers 3
+ const-string v0, "concat"
+ invoke-virtual {v0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+ move-result-object v1
+
+ # Call MethodType.methodType(rtype=String.class, ptype[0] = String.class)
+ invoke-static {v1, v1}, Ljava/lang/invoke/MethodType;->methodType(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
+ move-result-object v2
+
+ # Call Main.getHandleForVirtual(String.class, "concat", methodType);
+ invoke-static {v1, v0, v2}, LMain;->getHandleForVirtual(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
+ move-result-object v0
+ return-object v0
+.end method
+
+# Returns a method handle to static String java.lang.String.valueOf(String);
+.method public static getStringValueOfHandle()Ljava/lang/invoke/MethodHandle;
+.registers 4
+ # set v0 to java.lang.Object.class
+ new-instance v0, Ljava/lang/Object;
+ invoke-direct {v0}, Ljava/lang/Object;-><init>()V
+ invoke-virtual {v0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+ move-result-object v0
+
+ # set v1 to the name of the method ("valueOf") and v2 to java.lang.String.class;
+ const-string v1, "valueOf"
+ invoke-virtual {v1}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+ move-result-object v2
+
+ # Call MethodType.methodType(rtype=String.class, ptype[0]=Object.class)
+ invoke-static {v2, v0}, Ljava/lang/invoke/MethodType;->methodType(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
+ move-result-object v3
+
+ # Call Main.getHandleForStatic(String.class, "valueOf", methodType);
+ invoke-static {v2, v1, v3}, LMain;->getHandleForStatic(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
+ move-result-object v0
+ return-object v0
+.end method
+
+
+.method public static main([Ljava/lang/String;)V
+.registers 5
+
+ # Test case 1: Exercise String.concat(String, String) which is a virtual method.
+ invoke-static {}, LMain;->getStringConcatHandle()Ljava/lang/invoke/MethodHandle;
+ move-result-object v0
+ const-string v1, "[String1]"
+ const-string v2, "+[String2]"
+ invoke-polymorphic {v0, v1, v2}, Ljava/lang/invoke/MethodHandle;->invokeExact([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+ move-result-object v3
+ sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v4, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+ # Test case 2: Exercise String.valueOf(Object);
+ invoke-static {}, LMain;->getStringValueOfHandle()Ljava/lang/invoke/MethodHandle;
+ move-result-object v0
+ const-string v1, "[String1]"
+ invoke-polymorphic {v0, v1}, Ljava/lang/invoke/MethodHandle;->invokeExact([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/Object;)Ljava/lang/String;
+ move-result-object v3
+ sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v4, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+ return-void
+.end method
diff --git a/test/etc/default-build b/test/etc/default-build
index 37ce0f2..e663496 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -71,13 +71,16 @@
declare -A JACK_EXPERIMENTAL_ARGS
JACK_EXPERIMENTAL_ARGS["default-methods"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24"
JACK_EXPERIMENTAL_ARGS["lambdas"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24"
+JACK_EXPERIMENTAL_ARGS["method-handles"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=26"
declare -A SMALI_EXPERIMENTAL_ARGS
SMALI_EXPERIMENTAL_ARGS["default-methods"]="--api-level 24"
+SMALI_EXPERIMENTAL_ARGS["method-handles"]="--api-level 26"
declare -A JAVAC_EXPERIMENTAL_ARGS
JAVAC_EXPERIMENTAL_ARGS["default-methods"]="-source 1.8 -target 1.8"
JAVAC_EXPERIMENTAL_ARGS["lambdas"]="-source 1.8 -target 1.8"
+JAVAC_EXPERIMENTAL_ARGS["method-handles"]="-source 1.8 -target 1.8"
JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.7 -target 1.7"
while true; do