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