diff options
Diffstat (limited to 'test/952-invoke-custom/src/Main.java')
-rw-r--r-- | test/952-invoke-custom/src/Main.java | 159 |
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 |