1 /*
  2  * Copyright (c) 2024, 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  * @run testng TestTryNested
 28  */
 29 
 30 import jdk.incubator.code.Op;
 31 import org.testng.Assert;
 32 import org.testng.annotations.Test;
 33 
 34 import jdk.incubator.code.OpTransformer;
 35 import jdk.incubator.code.dialect.core.CoreOp;
 36 import jdk.incubator.code.interpreter.Interpreter;
 37 
 38 import java.lang.invoke.MethodHandles;
 39 import java.lang.reflect.Method;
 40 import jdk.incubator.code.CodeReflection;
 41 import java.util.ArrayList;
 42 import java.util.List;
 43 import java.util.Optional;
 44 import java.util.function.Consumer;
 45 import java.util.function.IntConsumer;
 46 import java.util.stream.Stream;
 47 
 48 public class TestTryNested {
 49     @CodeReflection
 50     public static void tryCatchFinally(IntConsumer c, int i) {
 51         try {
 52             try {
 53                 if (i == 0) {
 54                     return;
 55                 }
 56                 c.accept(0);
 57             } catch (IllegalStateException e) {
 58                 if (i == 1) {
 59                     return;
 60                 }
 61                 c.accept(1);
 62             } finally {
 63                 if (i == 2) {
 64                     return;
 65                 }
 66                 c.accept(2);
 67             }
 68             if (i == 3) {
 69                 return;
 70             }
 71             c.accept(3);
 72         } catch (IllegalStateException e) {
 73             if (i == 4) {
 74                 return;
 75             }
 76             c.accept(4);
 77         } finally {
 78             if (i == 5) {
 79                 return;
 80             }
 81             c.accept(5);
 82         }
 83         c.accept(6);
 84     }
 85 
 86     @Test
 87     public void testCatchFinally() {
 88         CoreOp.FuncOp f = getFuncOp("tryCatchFinally");
 89 
 90         System.out.println(f.toText());
 91 
 92         CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
 93 
 94         System.out.println(lf.toText());
 95 
 96         for (int ra = -1; ra < 6; ra++) {
 97             int fra = ra;
 98 
 99             Consumer<IntConsumer> test = testConsumer(
100                     c -> Interpreter.invoke(MethodHandles.lookup(), lf, c, fra),
101                     c -> tryCatchFinally(c, fra)
102             );
103 
104             test.accept(i -> {});
105             for (int ea = 0; ea < 6; ea++) {
106                 int fea = ea;
107                 test.accept(i -> {
108                     if (i == fea) throw new IllegalStateException();
109                 });
110                 test.accept(i -> {
111                     if (i == fea) throw new RuntimeException();
112                 });
113             }
114         }
115     }
116 
117 
118     @CodeReflection
119     public static void tryCatchBreak(IntConsumer c, int i) {
120         a: try {
121             try {
122                 if (i == 0) {
123                     break a;
124                 }
125                 c.accept(0);
126             } catch (IllegalStateException e) {
127                 if (i == 1) {
128                     break a;
129                 }
130                 c.accept(1);
131             }
132             if (i == 2) {
133                 break a;
134             }
135             c.accept(2);
136         } catch (IllegalStateException e) {
137             if (i == 3) {
138                 break a;
139             }
140             c.accept(3);
141         }
142         c.accept(4);
143     }
144 
145     @Test
146     public void testCatchBreak() {
147         CoreOp.FuncOp f = getFuncOp("tryCatchBreak");
148 
149         System.out.println(f.toText());
150 
151         CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
152 
153         System.out.println(lf.toText());
154 
155         for (int ra = -1; ra < 4; ra++) {
156             int fra = ra;
157 
158             Consumer<IntConsumer> test = testConsumer(
159                     c -> Interpreter.invoke(MethodHandles.lookup(), lf, c, fra),
160                     c -> tryCatchBreak(c, fra)
161             );
162 
163             test.accept(i -> {});
164             for (int ea = 0; ea <= 4; ea++) {
165                 int fea = ea;
166                 test.accept(i -> {
167                     if (i == fea) throw new IllegalStateException();
168                 });
169                 test.accept(i -> {
170                     if (i == fea) throw new RuntimeException();
171                 });
172             }
173         }
174     }
175 
176     @CodeReflection
177     public static void tryCatchFinallyBreak(IntConsumer c, int i) {
178         a: try {
179             try {
180                 if (i == 0) {
181                     break a;
182                 }
183                 c.accept(0);
184             } catch (IllegalStateException e) {
185                 if (i == 1) {
186                     break a;
187                 }
188                 c.accept(1);
189             } finally {
190                 if (i == 2) {
191                     break a;
192                 }
193                 c.accept(2);
194             }
195             if (i == 3) {
196                 break a;
197             }
198             c.accept(3);
199         } catch (IllegalStateException e) {
200             if (i == 4) {
201                 break a;
202             }
203             c.accept(4);
204         } finally {
205             if (i == 5) {
206                 break a;
207             }
208             c.accept(5);
209         }
210         c.accept(6);
211     }
212 
213     @Test
214     public void testCatchFinallyBreak() {
215         CoreOp.FuncOp f = getFuncOp("tryCatchFinallyBreak");
216 
217         System.out.println(f.toText());
218 
219         CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
220 
221         System.out.println(lf.toText());
222 
223         for (int ra = -1; ra < 6; ra++) {
224             int fra = ra;
225 
226             Consumer<IntConsumer> test = testConsumer(
227                     c -> Interpreter.invoke(MethodHandles.lookup(), lf, c, fra),
228                     c -> tryCatchFinallyBreak(c, fra)
229             );
230 
231             test.accept(i -> {});
232             for (int ea = 0; ea <= 6; ea++) {
233                 int fea = ea;
234                 test.accept(i -> {
235                     if (i == fea) throw new IllegalStateException();
236                 });
237                 test.accept(i -> {
238                     if (i == fea) throw new RuntimeException();
239                 });
240             }
241         }
242     }
243 
244 
245     @CodeReflection
246     public static void tryForLoop(IntConsumer c) {
247         for (int i = 0; i < 8; i++) {
248             c.accept(0);
249             try {
250                 if (i == 4) {
251                     continue;
252                 } else if (i == 5) {
253                     break;
254                 }
255                 c.accept(1);
256             } catch (IllegalStateException e) {
257                 c.accept(2);
258             }
259             c.accept(3);
260         }
261         c.accept(4);
262     }
263 
264     @Test
265     public void testTryForLoop() {
266         CoreOp.FuncOp f = getFuncOp("tryForLoop");
267 
268         System.out.println(f.toText());
269 
270         CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
271 
272         System.out.println(lf.toText());
273 
274         Consumer<IntConsumer> test = testConsumer(
275                 c -> Interpreter.invoke(MethodHandles.lookup(), lf, c),
276                 TestTryNested::tryForLoop
277         );
278 
279         test.accept(i -> { });
280         for (int ea = 0; ea <= 4; ea++) {
281             int fea = ea;
282             test.accept(i -> {
283                 if (i == fea) throw new IllegalStateException();
284             });
285             test.accept(i -> {
286                 if (i == fea) throw new RuntimeException();
287             });
288         }
289     }
290 
291     @CodeReflection
292     public static void tryForLoopFinally(IntConsumer c) {
293         for (int i = 0; i < 8; i++) {
294             c.accept(0);
295             try {
296                 if (i == 4) {
297                     continue;
298                 } else if (i == 5) {
299                     break;
300                 }
301                 c.accept(1);
302             } finally {
303                 c.accept(2);
304             }
305             c.accept(3);
306         }
307         c.accept(4);
308     }
309 
310     @Test
311     public void testTryForLoopFinally() {
312         CoreOp.FuncOp f = getFuncOp("tryForLoopFinally");
313 
314         System.out.println(f.toText());
315 
316         CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
317 
318         System.out.println(lf.toText());
319 
320         Consumer<IntConsumer> test = testConsumer(
321                 c -> Interpreter.invoke(MethodHandles.lookup(), lf, c),
322                 TestTryNested::tryForLoopFinally
323         );
324 
325         test.accept(i -> { });
326         for (int ea = 0; ea <= 4; ea++) {
327             int fea = ea;
328             test.accept(i -> {
329                 if (i == fea) throw new IllegalStateException();
330             });
331             test.accept(i -> {
332                 if (i == fea) throw new RuntimeException();
333             });
334         }
335     }
336 
337 
338     @CodeReflection
339     public static void tryLabeledForLoop(IntConsumer c) {
340         a: for (int i = 0; i < 8; i++) {
341             c.accept(0);
342             b: {
343                 try {
344                     if (i == 4) {
345                         continue a;
346                     } else if (i == 5) {
347                         break b;
348                     } else if (i == 6) {
349                         break a;
350                     }
351                     c.accept(1);
352                 } finally {
353                     c.accept(2);
354                 }
355                 c.accept(3);
356             }
357             c.accept(4);
358         }
359         c.accept(5);
360     }
361 
362     @Test
363     public void testTryLabeledForLoop() {
364         CoreOp.FuncOp f = getFuncOp("tryLabeledForLoop");
365 
366         System.out.println(f.toText());
367 
368         CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
369 
370         System.out.println(lf.toText());
371 
372         Consumer<IntConsumer> test = testConsumer(
373                 c -> Interpreter.invoke(MethodHandles.lookup(), lf, c),
374                 TestTryNested::tryLabeledForLoop
375         );
376 
377         test.accept(i -> { });
378     }
379 
380 
381     @CodeReflection
382     public static void tryLambda(IntConsumer c, int i) {
383         try {
384             c.accept(0);
385             Runnable r = () -> {
386                 if (i == 0) {
387                     c.accept(1);
388                     return;
389                 } else {
390                     c.accept(2);
391                 }
392                 c.accept(3);
393             };
394             r.run();
395             c.accept(4);
396         } finally {
397             c.accept(5);
398         }
399     }
400 
401     @Test
402     public void testTryLambda() {
403         CoreOp.FuncOp f = getFuncOp("tryLambda");
404 
405         System.out.println(f.toText());
406 
407         CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
408 
409         System.out.println(lf.toText());
410 
411         for (int ra = 0; ra < 2; ra++) {
412             final int fra = ra;
413             Consumer<IntConsumer> test = testConsumer(
414                     c -> Interpreter.invoke(MethodHandles.lookup(), lf, c, fra),
415                     c -> tryLambda(c, fra)
416             );
417             test.accept(i -> { });
418         }
419     }
420 
421 
422     static CoreOp.FuncOp getFuncOp(String name) {
423         Optional<Method> om = Stream.of(TestTryNested.class.getDeclaredMethods())
424                 .filter(m -> m.getName().equals(name))
425                 .findFirst();
426 
427         Method m = om.get();
428         return Op.ofMethod(m).get();
429     }
430 
431     static Consumer<IntConsumer> testConsumer(Consumer<IntConsumer> actualR, Consumer<IntConsumer> expectedR) {
432         return c -> {
433             List<Integer> actual = new ArrayList<>();
434             IntConsumer actualC = actual::add;
435             Throwable actualT = null;
436             try {
437                 actualR.accept(actualC.andThen(c));
438             } catch (Interpreter.InterpreterException e) {
439                 throw e;
440             } catch (Throwable t) {
441                 actualT = t;
442                 if (t instanceof AssertionError) {
443                     t.printStackTrace();
444                 }
445             }
446 
447             List<Integer> expected = new ArrayList<>();
448             IntConsumer expectedC = expected::add;
449             Throwable expectedT = null;
450             try {
451                 expectedR.accept(expectedC.andThen(c));
452             } catch (Throwable t) {
453                 expectedT = t;
454             }
455 
456             Assert.assertEquals(
457                     actualT != null ? actualT.getClass() : null,
458                     expectedT != null ? expectedT.getClass() : null);
459             Assert.assertEquals(actual, expected);
460         };
461     }
462 }