blob: e50391b29965a70d29c2295ae1b60fc69f29dbe2 [file] [log] [blame]
Narayan Kamath000e1882016-10-24 17:14:25 +01001/*
2 * Copyright (C) 2016 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
17import java.lang.invoke.MethodHandle;
18import java.lang.invoke.MethodHandles;
19import java.lang.invoke.MethodHandles.Lookup;
20import java.lang.invoke.MethodType;
21import java.lang.invoke.WrongMethodTypeException;
Narayan Kamath000e1882016-10-24 17:14:25 +010022
23public class Main {
Narayan Kamath000e1882016-10-24 17:14:25 +010024 public static void main(String[] args) throws Throwable {
25 testThrowException();
Narayan Kamath96120f42016-11-01 09:40:23 +000026 testDropArguments();
27 testCatchException();
28 testGuardWithTest();
Narayan Kamath000e1882016-10-24 17:14:25 +010029 }
30
31 public static void testThrowException() throws Throwable {
32 MethodHandle handle = MethodHandles.throwException(String.class,
33 IllegalArgumentException.class);
34
35 if (handle.type().returnType() != String.class) {
36 System.out.println("Unexpected return type for handle: " + handle +
37 " [ " + handle.type() + "]");
38 }
39
Narayan Kamath96120f42016-11-01 09:40:23 +000040 final IllegalArgumentException iae = new IllegalArgumentException("boo!");
Narayan Kamath000e1882016-10-24 17:14:25 +010041 try {
Narayan Kamath96120f42016-11-01 09:40:23 +000042 handle.invoke(iae);
Narayan Kamath000e1882016-10-24 17:14:25 +010043 System.out.println("Expected an exception of type: java.lang.IllegalArgumentException");
44 } catch (IllegalArgumentException expected) {
Narayan Kamath96120f42016-11-01 09:40:23 +000045 if (expected != iae) {
46 System.out.println("Wrong exception: expected " + iae + " but was " + expected);
47 }
Narayan Kamath000e1882016-10-24 17:14:25 +010048 }
49 }
Narayan Kamath96120f42016-11-01 09:40:23 +000050
51 public static void dropArguments_delegate(String message, long message2) {
52 System.out.println("Message: " + message + ", Message2: " + message2);
53 }
54
55 public static void testDropArguments() throws Throwable {
56 MethodHandle delegate = MethodHandles.lookup().findStatic(Main.class,
57 "dropArguments_delegate",
58 MethodType.methodType(void.class, new Class<?>[] { String.class, long.class }));
59
60 MethodHandle transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class);
61
62 // The transformer will accept two additional arguments at position zero.
63 try {
64 transform.invokeExact("foo", 42l);
65 fail();
66 } catch (WrongMethodTypeException expected) {
67 }
68
69 transform.invokeExact(45, new Object(), "foo", 42l);
70 transform.invoke(45, new Object(), "foo", 42l);
71
72 // Additional arguments at position 1.
73 transform = MethodHandles.dropArguments(delegate, 1, int.class, Object.class);
74 transform.invokeExact("foo", 45, new Object(), 42l);
75 transform.invoke("foo", 45, new Object(), 42l);
76
77 // Additional arguments at position 2.
78 transform = MethodHandles.dropArguments(delegate, 2, int.class, Object.class);
79 transform.invokeExact("foo", 42l, 45, new Object());
80 transform.invoke("foo", 42l, 45, new Object());
81
82 // Note that we still perform argument conversions even for the arguments that
83 // are subsequently dropped.
84 try {
85 transform.invoke("foo", 42l, 45l, new Object());
86 fail();
87 } catch (WrongMethodTypeException expected) {
88 } catch (IllegalArgumentException expected) {
89 // TODO(narayan): We currently throw the wrong type of exception here,
90 // it's IAE and should be WMTE instead.
91 }
92
Narayan Kamath0a8485e2016-11-02 18:47:11 +000093 // Check that asType works as expected.
94 transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class);
95 transform = transform.asType(MethodType.methodType(void.class,
96 new Class<?>[] { short.class, Object.class, String.class, long.class }));
97 transform.invokeExact((short) 45, new Object(), "foo", 42l);
98
Narayan Kamath96120f42016-11-01 09:40:23 +000099 // Invalid argument location, should not be allowed.
100 try {
101 MethodHandles.dropArguments(delegate, -1, int.class, Object.class);
102 fail();
103 } catch (IllegalArgumentException expected) {
104 }
105
106 // Invalid argument location, should not be allowed.
107 try {
108 MethodHandles.dropArguments(delegate, 3, int.class, Object.class);
109 fail();
110 } catch (IllegalArgumentException expected) {
111 }
112
113 try {
114 MethodHandles.dropArguments(delegate, 1, void.class);
115 fail();
116 } catch (IllegalArgumentException expected) {
117 }
118 }
119
120 public static String testCatchException_target(String arg1, long arg2, String exceptionMessage)
121 throws Throwable {
122 if (exceptionMessage != null) {
123 throw new IllegalArgumentException(exceptionMessage);
124 }
125
126 System.out.println("Target: Arg1: " + arg1 + ", Arg2: " + arg2);
127 return "target";
128 }
129
130 public static String testCatchException_handler(IllegalArgumentException iae, String arg1, long arg2,
131 String exMsg) {
132 System.out.println("Handler: " + iae + ", Arg1: " + arg1 + ", Arg2: " + arg2 + ", ExMsg: " + exMsg);
133 return "handler1";
134 }
135
136 public static String testCatchException_handler2(IllegalArgumentException iae, String arg1) {
137 System.out.println("Handler: " + iae + ", Arg1: " + arg1);
138 return "handler2";
139 }
140
141 public static void testCatchException() throws Throwable {
142 MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
143 "testCatchException_target",
144 MethodType.methodType(String.class, new Class<?>[] { String.class, long.class, String.class }));
145
146 MethodHandle handler = MethodHandles.lookup().findStatic(Main.class,
147 "testCatchException_handler",
148 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class,
149 String.class, long.class, String.class }));
150
151 MethodHandle adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
152 handler);
153
154 String returnVal = null;
155
156 // These two should end up calling the target always. We're passing a null exception
157 // message here, which means the target will not throw.
158 returnVal = (String) adapter.invoke("foo", 42, null);
159 assertEquals("target", returnVal);
160 returnVal = (String) adapter.invokeExact("foo", 42l, (String) null);
161 assertEquals("target", returnVal);
162
163 // We're passing a non-null exception message here, which means the target will throw,
164 // which in turn means that the handler must be called for the next two invokes.
165 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
166 assertEquals("handler1", returnVal);
167 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
168 assertEquals("handler1", returnVal);
169
170 handler = MethodHandles.lookup().findStatic(Main.class,
171 "testCatchException_handler2",
172 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class,
173 String.class }));
174 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
175
176 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
177 assertEquals("handler2", returnVal);
178 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
179 assertEquals("handler2", returnVal);
180
181 // Test that the type of the invoke doesn't matter. Here we call
182 // IllegalArgumentException.toString() on the exception that was thrown by
183 // the target.
184 handler = MethodHandles.lookup().findVirtual(IllegalArgumentException.class,
185 "toString", MethodType.methodType(String.class));
186 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
187
188 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
189 assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
190 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage2");
191 assertEquals("java.lang.IllegalArgumentException: exceptionMessage2", returnVal);
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000192
193 // Check that asType works as expected.
194 adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
195 handler);
196 adapter = adapter.asType(MethodType.methodType(String.class,
197 new Class<?>[] { String.class, int.class, String.class }));
198 returnVal = (String) adapter.invokeExact("foo", 42, "exceptionMessage");
199 assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
Narayan Kamath96120f42016-11-01 09:40:23 +0000200 }
201
202 public static boolean testGuardWithTest_test(String arg1, long arg2) {
203 return "target".equals(arg1) && 42 == arg2;
204 }
205
206 public static String testGuardWithTest_target(String arg1, long arg2, int arg3) {
207 System.out.println("target: " + arg1 + ", " + arg2 + ", " + arg3);
208 return "target";
209 }
210
211 public static String testGuardWithTest_fallback(String arg1, long arg2, int arg3) {
212 System.out.println("fallback: " + arg1 + ", " + arg2 + ", " + arg3);
213 return "fallback";
214 }
215
216 public static void testGuardWithTest() throws Throwable {
217 MethodHandle test = MethodHandles.lookup().findStatic(Main.class,
218 "testGuardWithTest_test",
219 MethodType.methodType(boolean.class, new Class<?>[] { String.class, long.class }));
220
221 final MethodType type = MethodType.methodType(String.class,
222 new Class<?>[] { String.class, long.class, int.class });
223
224 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
225 "testGuardWithTest_target", type);
226 final MethodHandle fallback = MethodHandles.lookup().findStatic(Main.class,
227 "testGuardWithTest_fallback", type);
228
229 MethodHandle adapter = MethodHandles.guardWithTest(test, target, fallback);
230
231 String returnVal = null;
232
233 returnVal = (String) adapter.invoke("target", 42, 56);
234 assertEquals("target", returnVal);
235 returnVal = (String) adapter.invokeExact("target", 42l, 56);
236 assertEquals("target", returnVal);
237
238 returnVal = (String) adapter.invoke("fallback", 42l, 56);
239 assertEquals("fallback", returnVal);
240 returnVal = (String) adapter.invokeExact("target", 42l, 56);
241 assertEquals("target", returnVal);
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000242
243 // Check that asType works as expected.
244 adapter = adapter.asType(MethodType.methodType(String.class,
245 new Class<?>[] { String.class, int.class, int.class }));
246 returnVal = (String) adapter.invokeExact("target", 42, 56);
247 assertEquals("target", returnVal);
Narayan Kamath96120f42016-11-01 09:40:23 +0000248 }
249
250 public static void fail() {
251 System.out.println("FAIL");
252 Thread.dumpStack();
253 }
254
255 public static void assertEquals(String s1, String s2) {
256 if (s1 == s2) {
257 return;
258 }
259
260 if (s1 != null && s2 != null && s1.equals(s2)) {
261 return;
262 }
263
264 throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2);
265 }
Narayan Kamath000e1882016-10-24 17:14:25 +0100266}
267
268