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