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