blob: 4a27086924ecf6a5e3bde93513cd1d3271fa187f [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
93 // Invalid argument location, should not be allowed.
94 try {
95 MethodHandles.dropArguments(delegate, -1, int.class, Object.class);
96 fail();
97 } catch (IllegalArgumentException expected) {
98 }
99
100 // Invalid argument location, should not be allowed.
101 try {
102 MethodHandles.dropArguments(delegate, 3, int.class, Object.class);
103 fail();
104 } catch (IllegalArgumentException expected) {
105 }
106
107 try {
108 MethodHandles.dropArguments(delegate, 1, void.class);
109 fail();
110 } catch (IllegalArgumentException expected) {
111 }
112 }
113
114 public static String testCatchException_target(String arg1, long arg2, String exceptionMessage)
115 throws Throwable {
116 if (exceptionMessage != null) {
117 throw new IllegalArgumentException(exceptionMessage);
118 }
119
120 System.out.println("Target: Arg1: " + arg1 + ", Arg2: " + arg2);
121 return "target";
122 }
123
124 public static String testCatchException_handler(IllegalArgumentException iae, String arg1, long arg2,
125 String exMsg) {
126 System.out.println("Handler: " + iae + ", Arg1: " + arg1 + ", Arg2: " + arg2 + ", ExMsg: " + exMsg);
127 return "handler1";
128 }
129
130 public static String testCatchException_handler2(IllegalArgumentException iae, String arg1) {
131 System.out.println("Handler: " + iae + ", Arg1: " + arg1);
132 return "handler2";
133 }
134
135 public static void testCatchException() throws Throwable {
136 MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
137 "testCatchException_target",
138 MethodType.methodType(String.class, new Class<?>[] { String.class, long.class, String.class }));
139
140 MethodHandle handler = MethodHandles.lookup().findStatic(Main.class,
141 "testCatchException_handler",
142 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class,
143 String.class, long.class, String.class }));
144
145 MethodHandle adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
146 handler);
147
148 String returnVal = null;
149
150 // These two should end up calling the target always. We're passing a null exception
151 // message here, which means the target will not throw.
152 returnVal = (String) adapter.invoke("foo", 42, null);
153 assertEquals("target", returnVal);
154 returnVal = (String) adapter.invokeExact("foo", 42l, (String) null);
155 assertEquals("target", returnVal);
156
157 // We're passing a non-null exception message here, which means the target will throw,
158 // which in turn means that the handler must be called for the next two invokes.
159 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
160 assertEquals("handler1", returnVal);
161 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
162 assertEquals("handler1", returnVal);
163
164 handler = MethodHandles.lookup().findStatic(Main.class,
165 "testCatchException_handler2",
166 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class,
167 String.class }));
168 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
169
170 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
171 assertEquals("handler2", returnVal);
172 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
173 assertEquals("handler2", returnVal);
174
175 // Test that the type of the invoke doesn't matter. Here we call
176 // IllegalArgumentException.toString() on the exception that was thrown by
177 // the target.
178 handler = MethodHandles.lookup().findVirtual(IllegalArgumentException.class,
179 "toString", MethodType.methodType(String.class));
180 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
181
182 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
183 assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
184 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage2");
185 assertEquals("java.lang.IllegalArgumentException: exceptionMessage2", returnVal);
186 }
187
188 public static boolean testGuardWithTest_test(String arg1, long arg2) {
189 return "target".equals(arg1) && 42 == arg2;
190 }
191
192 public static String testGuardWithTest_target(String arg1, long arg2, int arg3) {
193 System.out.println("target: " + arg1 + ", " + arg2 + ", " + arg3);
194 return "target";
195 }
196
197 public static String testGuardWithTest_fallback(String arg1, long arg2, int arg3) {
198 System.out.println("fallback: " + arg1 + ", " + arg2 + ", " + arg3);
199 return "fallback";
200 }
201
202 public static void testGuardWithTest() throws Throwable {
203 MethodHandle test = MethodHandles.lookup().findStatic(Main.class,
204 "testGuardWithTest_test",
205 MethodType.methodType(boolean.class, new Class<?>[] { String.class, long.class }));
206
207 final MethodType type = MethodType.methodType(String.class,
208 new Class<?>[] { String.class, long.class, int.class });
209
210 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class,
211 "testGuardWithTest_target", type);
212 final MethodHandle fallback = MethodHandles.lookup().findStatic(Main.class,
213 "testGuardWithTest_fallback", type);
214
215 MethodHandle adapter = MethodHandles.guardWithTest(test, target, fallback);
216
217 String returnVal = null;
218
219 returnVal = (String) adapter.invoke("target", 42, 56);
220 assertEquals("target", returnVal);
221 returnVal = (String) adapter.invokeExact("target", 42l, 56);
222 assertEquals("target", returnVal);
223
224 returnVal = (String) adapter.invoke("fallback", 42l, 56);
225 assertEquals("fallback", returnVal);
226 returnVal = (String) adapter.invokeExact("target", 42l, 56);
227 assertEquals("target", returnVal);
228 }
229
230 public static void fail() {
231 System.out.println("FAIL");
232 Thread.dumpStack();
233 }
234
235 public static void assertEquals(String s1, String s2) {
236 if (s1 == s2) {
237 return;
238 }
239
240 if (s1 != null && s2 != null && s1.equals(s2)) {
241 return;
242 }
243
244 throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2);
245 }
Narayan Kamath000e1882016-10-24 17:14:25 +0100246}
247
248