1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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();
}
}
|