summaryrefslogtreecommitdiff
path: root/test/952-invoke-custom/src/Main.java
diff options
context:
space:
mode:
Diffstat (limited to 'test/952-invoke-custom/src/Main.java')
-rw-r--r--test/952-invoke-custom/src/Main.java159
1 files changed, 159 insertions, 0 deletions
diff --git a/test/952-invoke-custom/src/Main.java b/test/952-invoke-custom/src/Main.java
new file mode 100644
index 0000000000..2abc3122fa
--- /dev/null
+++ b/test/952-invoke-custom/src/Main.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2017 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 dalvik.system.InMemoryDexClassLoader;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MutableCallSite;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.util.Base64;
+
+// This test is a stop-gap until we have support for generating invoke-custom
+// in the Android tree.
+
+public class Main {
+
+ private static void TestUninitializedCallSite() throws Throwable {
+ CallSite callSite = new MutableCallSite(MethodType.methodType(int.class));
+ try {
+ callSite.getTarget().invoke();
+ fail();
+ } catch (IllegalStateException e) {
+ System.out.println("Caught exception from uninitialized call site");
+ }
+
+ callSite = new MutableCallSite(MethodType.methodType(String.class, int.class, char.class));
+ try {
+ callSite.getTarget().invoke(1535, 'd');
+ fail();
+ } catch (IllegalStateException e) {
+ System.out.println("Caught exception from uninitialized call site");
+ }
+ }
+
+ private static void TestLinkerMethodMultipleArgumentTypes() throws Throwable {
+ // This is a more comprehensive test of invoke-custom, the linker
+ // method takes additional arguments of types boolean, byte, char,
+ // short, int, float, double, String, Class, and long (in this order)
+ // The test asserts the values passed to the linker method match their
+ // expected values.
+ byte[] base64Data = TestDataLinkerMethodMultipleArgumentTypes.BASE64_DEX_FILE.getBytes();
+ Base64.Decoder decoder = Base64.getDecoder();
+ ByteBuffer dexBuffer = ByteBuffer.wrap(decoder.decode(base64Data));
+
+ InMemoryDexClassLoader classLoader =
+ new InMemoryDexClassLoader(dexBuffer,
+ ClassLoader.getSystemClassLoader());
+ Class<?> testClass =
+ classLoader.loadClass("TestLinkerMethodMultipleArgumentTypes");
+ Method testMethod = testClass.getDeclaredMethod("test", int.class, int.class);
+ // First invocation should link via the bootstrap method (outputs "Linking add" ...).
+ testMethod.invoke(null, 33, 67);
+ // Subsequent invocations use the cached value of the CallSite and do not require linking.
+ testMethod.invoke(null, -10000, +1000);
+ testMethod.invoke(null, -1000, +10000);
+ }
+
+ private static void TestLinkerMethodMinimalArguments() throws Throwable {
+ // This test checks various failures when running the linker
+ // method and during invocation of the method handle.
+ byte[] base64Data = TestDataLinkerMethodMinimalArguments.BASE64_DEX_FILE.getBytes();
+ Base64.Decoder decoder = Base64.getDecoder();
+ ByteBuffer dexBuffer = ByteBuffer.wrap(decoder.decode(base64Data));
+
+ InMemoryDexClassLoader classLoader =
+ new InMemoryDexClassLoader(dexBuffer,
+ ClassLoader.getSystemClassLoader());
+ Class<?> testClass =
+ classLoader.loadClass("TestLinkerMethodMinimalArguments");
+ Method testMethod = testClass.getDeclaredMethod("test", int.class, int.class, int.class);
+
+ try {
+ testMethod.invoke(null, 1 /* linker method return null */, 10, 10);
+ } catch (InvocationTargetException e) {
+ assertEquals(e.getCause().getClass().getName(), "java.lang.BootstrapMethodError");
+ assertEquals(
+ e.getCause().getCause().getClass().getName(), "java.lang.NullPointerException");
+ }
+
+ try {
+ testMethod.invoke(null, 2 /* linker method throw InstantiationException */, 10, 11);
+ } catch (InvocationTargetException e) {
+ assertEquals(e.getCause().getClass().getName(), "java.lang.BootstrapMethodError");
+ assertEquals(
+ e.getCause().getCause().getClass().getName(), "java.lang.InstantiationException");
+ }
+ try {
+ // Creating the CallSite works here, but fail invoking the method.
+ testMethod.invoke(null, 3 /* target throw NPE */, 10, 12);
+ } catch (InvocationTargetException e) {
+ assertEquals(e.getCause().getClass().getName(), "java.lang.ArithmeticException");
+ }
+
+ // This should succeed using already resolved CallSite.
+ testMethod.invoke(null, 0 /* no error */, 10, 13);
+ }
+
+ private static void TestInvokeCustomWithConcurrentThreads() throws Throwable {
+ // This is a concurrency test that attempts to run invoke-custom on the same
+ // call site.
+ byte[] base64Data = TestDataInvokeCustomWithConcurrentThreads.BASE64_DEX_FILE.getBytes();
+ Base64.Decoder decoder = Base64.getDecoder();
+ ByteBuffer dexBuffer = ByteBuffer.wrap(decoder.decode(base64Data));
+
+ InMemoryDexClassLoader classLoader =
+ new InMemoryDexClassLoader(dexBuffer,
+ ClassLoader.getSystemClassLoader());
+ Class<?> testClass =
+ classLoader.loadClass("TestInvokeCustomWithConcurrentThreads");
+ Method testMethod = testClass.getDeclaredMethod("test");
+ testMethod.invoke(null);
+ }
+
+ public static void assertEquals(Object o, Object p) {
+ if (o == p) { return; }
+ if (o != null && p != null && o.equals(p)) { return; }
+ throw new AssertionError("assertEquals: o1: " + o + ", o2: " + p);
+ }
+
+ public static void assertEquals(String s1, String s2) {
+ if (s1 == s2) {
+ return;
+ }
+
+ if (s1 != null && s2 != null && s1.equals(s2)) {
+ return;
+ }
+
+ throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2);
+ }
+
+ private static void fail() {
+ System.out.println("fail");
+ Thread.dumpStack();
+ }
+
+ public static void main(String[] args) throws Throwable {
+ TestUninitializedCallSite();
+ TestLinkerMethodMinimalArguments();
+ TestLinkerMethodMultipleArgumentTypes();
+ TestInvokeCustomWithConcurrentThreads();
+ }
+} \ No newline at end of file