1 import jdk.incubator.code.Block;
  2 import jdk.incubator.code.CodeTransformer;
  3 import jdk.incubator.code.Op;
  4 import jdk.incubator.code.Reflect;
  5 import jdk.incubator.code.Value;
  6 import jdk.incubator.code.dialect.core.CoreOp;
  7 import jdk.incubator.code.dialect.core.Inliner;
  8 import jdk.incubator.code.dialect.java.JavaOp;
  9 import org.junit.jupiter.api.Assertions;
 10 import org.junit.jupiter.api.Test;
 11 
 12 import java.lang.invoke.MethodHandles;
 13 import java.util.ArrayList;
 14 import java.util.List;
 15 import java.util.function.BiConsumer;
 16 import java.util.function.Consumer;
 17 import java.util.function.IntConsumer;
 18 
 19 /*
 20  * @test
 21  * @modules jdk.incubator.code
 22  * @library lib
 23  * @run junit TestTryOpWithExceptionRegion
 24  * @run main Unreflect TestTryOpWithExceptionRegion
 25  * @run junit TestTryOpWithExceptionRegion
 26  */
 27 public class TestTryOpWithExceptionRegion {
 28     @Reflect
 29     static void m(IntConsumer c) {
 30         try {
 31             c.accept(0);
 32             n(c);
 33         } catch (IllegalArgumentException ex) {
 34             c.accept(4);
 35         } finally {
 36             c.accept(5);
 37         }
 38     }
 39 
 40     @Reflect
 41     private static void n(IntConsumer c) {
 42         try {
 43             c.accept(1);
 44         } catch (IllegalStateException ex) {
 45             c.accept(2);
 46         } finally {
 47             c.accept(3);
 48         }
 49     }
 50 
 51     @Test
 52     void testTryOpEnclosingExceptionRegion() throws NoSuchMethodException {
 53         // lower n + inline it in m
 54         CoreOp.FuncOp n = Op.ofMethod(this.getClass().getDeclaredMethod("n", IntConsumer.class)).get();
 55         CoreOp.FuncOp ln = n.transform(CodeTransformer.LOWERING_TRANSFORMER);
 56         CoreOp.FuncOp m = Op.ofMethod(this.getClass().getDeclaredMethod("m", IntConsumer.class)).get();
 57         CoreOp.FuncOp m2 = m.transform((b, o) -> {
 58             if (o instanceof JavaOp.InvokeOp iop && iop.invokeReference().name().equals("n")) {
 59                 return Inliner.inline(b, ln, b.context().getValues(m.parameters()));
 60             } else {
 61                 b.add(o);
 62                 return b;
 63             }
 64         });
 65         System.out.println(m2.toText());
 66 
 67         Consumer<IntConsumer> test = testConsumer(
 68                 c -> Interpreter.invoke(MethodHandles.lookup(), m2, c),
 69                 TestTryOpWithExceptionRegion::m
 70         );
 71         test.accept(i -> {
 72             if (i == 1) throw new IllegalStateException();
 73         });
 74 
 75         test.accept(i -> {
 76             if (i == 1) throw new IllegalArgumentException();
 77         });
 78     }
 79 
 80     @Test
 81     void testTryOpEnclosedByExceptionRegion() throws NoSuchMethodException {
 82         // lower m + inline n
 83         CoreOp.FuncOp m = Op.ofMethod(this.getClass().getDeclaredMethod("m", IntConsumer.class)).get();
 84         CoreOp.FuncOp lm = m.transform(CodeTransformer.LOWERING_TRANSFORMER);
 85         CoreOp.FuncOp n = Op.ofMethod(this.getClass().getDeclaredMethod("n", IntConsumer.class)).get();
 86         CoreOp.FuncOp lm2 = lm.transform((b, o) -> {
 87             if (o instanceof JavaOp.InvokeOp iop && iop.invokeReference().name().equals("n")) {
 88                 return Inliner.inline(b, n, b.context().getValues(lm.parameters()));
 89             } else {
 90                 b.add(o);
 91                 return b;
 92             }
 93         });
 94 
 95         Consumer<IntConsumer> test = testConsumer(
 96                 c -> Interpreter.invoke(MethodHandles.lookup(), lm2, c),
 97                 TestTryOpWithExceptionRegion::m
 98         );
 99         test.accept(i -> {
100             if (i == 1) throw new IllegalStateException();
101         });
102 
103         test.accept(i -> {
104             if (i == 1) throw new IllegalArgumentException();
105         });
106     }
107 
108     static Consumer<IntConsumer> testConsumer(Consumer<IntConsumer> actualR, Consumer<IntConsumer> expectedR) {
109         return c -> {
110             List<Integer> actual = new ArrayList<>();
111             IntConsumer actualC = actual::add;
112             Throwable actualT = null;
113             try {
114                 actualR.accept(actualC.andThen(c));
115             } catch (Interpreter.InterpreterException e) {
116                 throw e;
117             } catch (Throwable t) {
118                 actualT = t;
119                 if (t instanceof AssertionError) {
120                     t.printStackTrace();
121                 }
122             }
123 
124             List<Integer> expected = new ArrayList<>();
125             IntConsumer expectedC = expected::add;
126             Throwable expectedT = null;
127             try {
128                 expectedR.accept(expectedC.andThen(c));
129             } catch (Throwable t) {
130                 expectedT = t;
131             }
132 
133             Assertions.assertEquals(
134                     expectedT != null ? expectedT.getClass() : null, actualT != null ? actualT.getClass() : null
135             );
136             Assertions.assertEquals(expected, actual);
137         };
138     }
139 }