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