• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 import dalvik.system.InMemoryDexClassLoader;
18 
19 import java.lang.invoke.CallSite;
20 import java.lang.invoke.MethodType;
21 import java.lang.invoke.MutableCallSite;
22 
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.nio.ByteBuffer;
26 import java.util.Base64;
27 
28 // This test is a stop-gap until we have support for generating invoke-custom
29 // in the Android tree.
30 
31 public class Main {
32 
TestUninitializedCallSite()33   private static void TestUninitializedCallSite() throws Throwable {
34     CallSite callSite = new MutableCallSite(MethodType.methodType(int.class));
35     try {
36       callSite.getTarget().invoke();
37       fail();
38     } catch (IllegalStateException e) {
39       System.out.println("Caught exception from uninitialized call site");
40     }
41 
42     callSite = new MutableCallSite(MethodType.methodType(String.class, int.class, char.class));
43     try {
44       callSite.getTarget().invoke(1535, 'd');
45       fail();
46     } catch (IllegalStateException e) {
47       System.out.println("Caught exception from uninitialized call site");
48     }
49   }
50 
TestLinkerMethodMultipleArgumentTypes()51   private static void TestLinkerMethodMultipleArgumentTypes() throws Throwable {
52     // This is a more comprehensive test of invoke-custom, the linker
53     // method takes additional arguments of types boolean, byte, char,
54     // short, int, float, double, String, Class, and long (in this order)
55     // The test asserts the values passed to the linker method match their
56     // expected values.
57     byte[] base64Data = TestDataLinkerMethodMultipleArgumentTypes.BASE64_DEX_FILE.getBytes();
58     Base64.Decoder decoder = Base64.getDecoder();
59     ByteBuffer dexBuffer = ByteBuffer.wrap(decoder.decode(base64Data));
60 
61     InMemoryDexClassLoader classLoader =
62         new InMemoryDexClassLoader(dexBuffer,
63                                    ClassLoader.getSystemClassLoader());
64     Class<?> testClass =
65         classLoader.loadClass("TestLinkerMethodMultipleArgumentTypes");
66     Method testMethod = testClass.getDeclaredMethod("test", int.class, int.class);
67     // First invocation should link via the bootstrap method (outputs "Linking add" ...).
68     testMethod.invoke(null, 33, 67);
69     // Subsequent invocations use the cached value of the CallSite and do not require linking.
70     testMethod.invoke(null, -10000, +1000);
71     testMethod.invoke(null, -1000, +10000);
72   }
73 
TestLinkerMethodMinimalArguments()74   private static void TestLinkerMethodMinimalArguments() throws Throwable {
75     // This test checks various failures when running the linker
76     // method and during invocation of the method handle.
77     byte[] base64Data = TestDataLinkerMethodMinimalArguments.BASE64_DEX_FILE.getBytes();
78     Base64.Decoder decoder = Base64.getDecoder();
79     ByteBuffer dexBuffer = ByteBuffer.wrap(decoder.decode(base64Data));
80 
81     InMemoryDexClassLoader classLoader =
82         new InMemoryDexClassLoader(dexBuffer,
83                                    ClassLoader.getSystemClassLoader());
84     Class<?> testClass =
85         classLoader.loadClass("TestLinkerMethodMinimalArguments");
86     Method testMethod = testClass.getDeclaredMethod("test", int.class, int.class, int.class);
87 
88     try {
89       testMethod.invoke(null, 1 /* linker method return null */, 10, 10);
90     } catch (InvocationTargetException e) {
91       assertEquals(e.getCause().getClass().getName(), "java.lang.BootstrapMethodError");
92       assertEquals(
93           e.getCause().getCause().getClass().getName(), "java.lang.NullPointerException");
94     }
95 
96     try {
97       testMethod.invoke(null, 2 /* linker method throw InstantiationException */, 10, 11);
98     } catch (InvocationTargetException e) {
99       assertEquals(e.getCause().getClass().getName(), "java.lang.BootstrapMethodError");
100       assertEquals(
101           e.getCause().getCause().getClass().getName(), "java.lang.InstantiationException");
102     }
103     try {
104       // Creating the CallSite works here, but fail invoking the method.
105       testMethod.invoke(null, 3 /* target throw NPE */, 10, 12);
106     } catch (InvocationTargetException e) {
107       assertEquals(e.getCause().getClass().getName(), "java.lang.ArithmeticException");
108     }
109 
110     // This should succeed using already resolved CallSite.
111     testMethod.invoke(null, 0 /* no error */, 10, 13);
112   }
113 
TestInvokeCustomWithConcurrentThreads()114   private static void TestInvokeCustomWithConcurrentThreads() throws Throwable {
115     // This is a concurrency test that attempts to run invoke-custom on the same
116     // call site.
117     byte[] base64Data = TestDataInvokeCustomWithConcurrentThreads.BASE64_DEX_FILE.getBytes();
118     Base64.Decoder decoder = Base64.getDecoder();
119     ByteBuffer dexBuffer = ByteBuffer.wrap(decoder.decode(base64Data));
120 
121     InMemoryDexClassLoader classLoader =
122         new InMemoryDexClassLoader(dexBuffer,
123                                    ClassLoader.getSystemClassLoader());
124     Class<?> testClass =
125         classLoader.loadClass("TestInvokeCustomWithConcurrentThreads");
126     Method testMethod = testClass.getDeclaredMethod("test");
127     testMethod.invoke(null);
128   }
129 
assertEquals(Object o, Object p)130   public static void assertEquals(Object o, Object p) {
131     if (o == p) { return; }
132     if (o != null && p != null && o.equals(p)) { return; }
133     throw new AssertionError("assertEquals: o1: " + o + ", o2: " + p);
134   }
135 
assertEquals(String s1, String s2)136   public static void assertEquals(String s1, String s2) {
137     if (s1 == s2) {
138       return;
139     }
140 
141     if (s1 != null && s2 != null && s1.equals(s2)) {
142       return;
143     }
144 
145     throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2);
146   }
147 
fail()148   private static void fail() {
149     System.out.println("fail");
150     Thread.dumpStack();
151   }
152 
main(String[] args)153   public static void main(String[] args) throws Throwable {
154     TestUninitializedCallSite();
155     TestLinkerMethodMinimalArguments();
156     TestLinkerMethodMultipleArgumentTypes();
157     TestInvokeCustomWithConcurrentThreads();
158   }
159 }