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 }