1 /*
2 * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /*
25 * @test
26 * @modules jdk.incubator.code
27 * @library lib
28 * @run junit TestTryNested
29 * @run main Unreflect TestTryNested
30 * @run junit TestTryNested
31 */
32
33 import jdk.incubator.code.Reflect;
34 import jdk.incubator.code.CodeTransformer;
35 import jdk.incubator.code.Op;
36 import jdk.incubator.code.dialect.core.CoreOp;
37 import org.junit.jupiter.api.Assertions;
38 import org.junit.jupiter.api.Test;
39
40 import java.lang.invoke.MethodHandles;
41 import java.lang.reflect.Method;
42 import java.util.ArrayList;
43 import java.util.List;
44 import java.util.Optional;
45 import java.util.function.Consumer;
46 import java.util.function.IntConsumer;
47 import java.util.stream.Stream;
48
49 public class TestTryNested {
50 @Reflect
51 public static void tryCatchFinally(IntConsumer c, int i) {
52 try {
53 try {
54 if (i == 0) {
55 return;
56 }
57 c.accept(0);
58 } catch (IllegalStateException e) {
59 if (i == 1) {
60 return;
61 }
62 c.accept(1);
63 } finally {
64 if (i == 2) {
65 return;
66 }
67 c.accept(2);
68 }
69 if (i == 3) {
70 return;
71 }
72 c.accept(3);
73 } catch (IllegalStateException e) {
74 if (i == 4) {
75 return;
76 }
77 c.accept(4);
78 } finally {
79 if (i == 5) {
80 return;
81 }
82 c.accept(5);
83 }
84 c.accept(6);
85 }
86
87 @Test
88 public void testCatchFinally() {
89 CoreOp.FuncOp f = getFuncOp("tryCatchFinally");
90
91 System.out.println(f.toText());
92
93 CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
94
95 System.out.println(lf.toText());
96
97 for (CoreOp.FuncOp op : List.of(f, lf)) {
98 for (int ra = -1; ra < 6; ra++) {
99 int fra = ra;
100
101 Consumer<IntConsumer> test = testConsumer(
102 c -> Interpreter.invoke(MethodHandles.lookup(), op, c, fra),
103 c -> tryCatchFinally(c, fra)
104 );
105
106 test.accept(i -> {});
107 for (int ea = 0; ea < 6; ea++) {
108 int fea = ea;
109 test.accept(i -> {
110 if (i == fea) throw new IllegalStateException();
111 });
112 test.accept(i -> {
113 if (i == fea) throw new RuntimeException();
114 });
115 }
116 }
117 }
118 }
119
120
121 @Reflect
122 public static void tryCatchBreak(IntConsumer c, int i) {
123 a: try {
124 try {
125 if (i == 0) {
126 break a;
127 }
128 c.accept(0);
129 } catch (IllegalStateException e) {
130 if (i == 1) {
131 break a;
132 }
133 c.accept(1);
134 }
135 if (i == 2) {
136 break a;
137 }
138 c.accept(2);
139 } catch (IllegalStateException e) {
140 if (i == 3) {
141 break a;
142 }
143 c.accept(3);
144 }
145 c.accept(4);
146 }
147
148 @Test
149 public void testCatchBreak() {
150 CoreOp.FuncOp f = getFuncOp("tryCatchBreak");
151
152 System.out.println(f.toText());
153
154 CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
155
156 System.out.println(lf.toText());
157
158 for (CoreOp.FuncOp op : List.of(f, lf)) {
159 for (int ra = -1; ra < 4; ra++) {
160 int fra = ra;
161
162 Consumer<IntConsumer> test = testConsumer(
163 c -> Interpreter.invoke(MethodHandles.lookup(), op, c, fra),
164 c -> tryCatchBreak(c, fra)
165 );
166
167 test.accept(i -> {});
168 for (int ea = 0; ea <= 4; ea++) {
169 int fea = ea;
170 test.accept(i -> {
171 if (i == fea) throw new IllegalStateException();
172 });
173 test.accept(i -> {
174 if (i == fea) throw new RuntimeException();
175 });
176 }
177 }
178 }
179 }
180
181 @Reflect
182 public static void tryCatchFinallyBreak(IntConsumer c, int i) {
183 a: try {
184 try {
185 if (i == 0) {
186 break a;
187 }
188 c.accept(0);
189 } catch (IllegalStateException e) {
190 if (i == 1) {
191 break a;
192 }
193 c.accept(1);
194 } finally {
195 if (i == 2) {
196 break a;
197 }
198 c.accept(2);
199 }
200 if (i == 3) {
201 break a;
202 }
203 c.accept(3);
204 } catch (IllegalStateException e) {
205 if (i == 4) {
206 break a;
207 }
208 c.accept(4);
209 } finally {
210 if (i == 5) {
211 break a;
212 }
213 c.accept(5);
214 }
215 c.accept(6);
216 }
217
218 @Test
219 public void testCatchFinallyBreak() {
220 CoreOp.FuncOp f = getFuncOp("tryCatchFinallyBreak");
221
222 System.out.println(f.toText());
223
224 CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
225
226 System.out.println(lf.toText());
227
228 for (CoreOp.FuncOp op : List.of(f, lf)) {
229 for (int ra = -1; ra < 6; ra++) {
230 int fra = ra;
231
232 Consumer<IntConsumer> test = testConsumer(
233 c -> Interpreter.invoke(MethodHandles.lookup(), op, c, fra),
234 c -> tryCatchFinallyBreak(c, fra)
235 );
236
237 test.accept(i -> {});
238 for (int ea = 0; ea <= 6; ea++) {
239 int fea = ea;
240 test.accept(i -> {
241 if (i == fea) throw new IllegalStateException();
242 });
243 test.accept(i -> {
244 if (i == fea) throw new RuntimeException();
245 });
246 }
247 }
248 }
249 }
250
251
252 @Reflect
253 public static void tryForLoop(IntConsumer c) {
254 for (int i = 0; i < 8; i++) {
255 c.accept(0);
256 try {
257 if (i == 4) {
258 continue;
259 } else if (i == 5) {
260 break;
261 }
262 c.accept(1);
263 } catch (IllegalStateException e) {
264 c.accept(2);
265 }
266 c.accept(3);
267 }
268 c.accept(4);
269 }
270
271 @Test
272 public void testTryForLoop() {
273 CoreOp.FuncOp f = getFuncOp("tryForLoop");
274
275 System.out.println(f.toText());
276
277 CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
278
279 System.out.println(lf.toText());
280
281 for (CoreOp.FuncOp op : List.of(f, lf)) {
282 Consumer<IntConsumer> test = testConsumer(
283 c -> Interpreter.invoke(MethodHandles.lookup(), op, c),
284 TestTryNested::tryForLoop
285 );
286
287 test.accept(i -> {});
288 for (int ea = 0; ea <= 4; ea++) {
289 int fea = ea;
290 test.accept(i -> {
291 if (i == fea) throw new IllegalStateException();
292 });
293 test.accept(i -> {
294 if (i == fea) throw new RuntimeException();
295 });
296 }
297 }
298 }
299
300 @Reflect
301 public static void tryForLoopFinally(IntConsumer c) {
302 for (int i = 0; i < 8; i++) {
303 c.accept(0);
304 try {
305 if (i == 4) {
306 continue;
307 } else if (i == 5) {
308 break;
309 }
310 c.accept(1);
311 } finally {
312 c.accept(2);
313 }
314 c.accept(3);
315 }
316 c.accept(4);
317 }
318
319 @Test
320 public void testTryForLoopFinally() {
321 CoreOp.FuncOp f = getFuncOp("tryForLoopFinally");
322
323 System.out.println(f.toText());
324
325 CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
326
327 System.out.println(lf.toText());
328
329 for (CoreOp.FuncOp op : List.of(f, lf)) {
330 Consumer<IntConsumer> test = testConsumer(
331 c -> Interpreter.invoke(MethodHandles.lookup(), op, c),
332 TestTryNested::tryForLoopFinally
333 );
334
335 test.accept(i -> {});
336 for (int ea = 0; ea <= 4; ea++) {
337 int fea = ea;
338 test.accept(i -> {
339 if (i == fea) throw new IllegalStateException();
340 });
341 test.accept(i -> {
342 if (i == fea) throw new RuntimeException();
343 });
344 }
345 }
346 }
347
348
349 @Reflect
350 public static void tryLabeledForLoop(IntConsumer c) {
351 a: for (int i = 0; i < 8; i++) {
352 c.accept(0);
353 b: {
354 try {
355 if (i == 4) {
356 continue a;
357 } else if (i == 5) {
358 break b;
359 } else if (i == 6) {
360 break a;
361 }
362 c.accept(1);
363 } finally {
364 c.accept(2);
365 }
366 c.accept(3);
367 }
368 c.accept(4);
369 }
370 c.accept(5);
371 }
372
373 @Test
374 public void testTryLabeledForLoop() {
375 CoreOp.FuncOp f = getFuncOp("tryLabeledForLoop");
376
377 System.out.println(f.toText());
378
379 CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
380
381 System.out.println(lf.toText());
382
383 for (CoreOp.FuncOp op : List.of(f, lf)) {
384 Consumer<IntConsumer> test = testConsumer(
385 c -> Interpreter.invoke(MethodHandles.lookup(), op, c),
386 TestTryNested::tryLabeledForLoop
387 );
388 test.accept(i -> { });
389 }
390 }
391
392
393 @Reflect
394 public static void tryLambda(IntConsumer c, int i) {
395 try {
396 c.accept(0);
397 Runnable r = () -> {
398 if (i == 0) {
399 c.accept(1);
400 return;
401 } else {
402 c.accept(2);
403 }
404 c.accept(3);
405 };
406 r.run();
407 c.accept(4);
408 } finally {
409 c.accept(5);
410 }
411 }
412
413 @Test
414 public void testTryLambda() {
415 CoreOp.FuncOp f = getFuncOp("tryLambda");
416
417 System.out.println(f.toText());
418
419 CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
420
421 System.out.println(lf.toText());
422
423 for (CoreOp.FuncOp op : List.of(f, lf)) {
424 for (int ra = 0; ra < 2; ra++) {
425 final int fra = ra;
426 Consumer<IntConsumer> test = testConsumer(
427 c -> Interpreter.invoke(MethodHandles.lookup(), op, c, fra),
428 c -> tryLambda(c, fra)
429 );
430 test.accept(i -> { });
431 }
432 }
433 }
434
435
436 @Reflect
437 public static int multiCatch(int mode) {
438 try {
439 try {
440 if (mode == 0) {
441 throw new IllegalArgumentException();
442 }
443 if (mode == 1) {
444 throw new IllegalStateException();
445 }
446 if (mode == 2) {
447 throw new ArithmeticException();
448 }
449 return 0;
450 } catch (IllegalArgumentException | IllegalStateException e) {
451 return 10;
452 }
453 } catch (RuntimeException e) {
454 return 20;
455 }
456 }
457
458 @Test
459 public void testMultiCatch() {
460 CoreOp.FuncOp f = getFuncOp("multiCatch");
461 CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
462
463 for (CoreOp.FuncOp op : List.of(f, lf)) {
464 for (int mode = 0; mode < 4; mode++) {
465 Assertions.assertEquals(
466 multiCatch(mode),
467 Interpreter.invoke(MethodHandles.lookup(), op, mode));
468 }
469 }
470 }
471
472 static CoreOp.FuncOp getFuncOp(String name) {
473 Optional<Method> om = Stream.of(TestTryNested.class.getDeclaredMethods())
474 .filter(m -> m.getName().equals(name))
475 .findFirst();
476
477 Method m = om.get();
478 return Op.ofMethod(m).get();
479 }
480
481 static Consumer<IntConsumer> testConsumer(Consumer<IntConsumer> actualR, Consumer<IntConsumer> expectedR) {
482 return c -> {
483 List<Integer> actual = new ArrayList<>();
484 IntConsumer actualC = actual::add;
485 Throwable actualT = null;
486 try {
487 actualR.accept(actualC.andThen(c));
488 } catch (Interpreter.InterpreterException e) {
489 throw e;
490 } catch (Throwable t) {
491 actualT = t;
492 if (t instanceof AssertionError) {
493 t.printStackTrace();
494 }
495 }
496
497 List<Integer> expected = new ArrayList<>();
498 IntConsumer expectedC = expected::add;
499 Throwable expectedT = null;
500 try {
501 expectedR.accept(expectedC.andThen(c));
502 } catch (Throwable t) {
503 expectedT = t;
504 }
505
506 Assertions.assertEquals(
507 expectedT != null ? expectedT.getClass() : null, actualT != null ? actualT.getClass() : null
508 );
509 Assertions.assertEquals(expected, actual);
510 };
511 }
512 }