1 /*
  2  * Copyright (c) 2024, 2026, 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  * @library lib
 28  * @run junit TestTry
 29  * @run main Unreflect TestTry
 30  * @run junit TestTry
 31  */
 32 
 33 import jdk.incubator.code.Reflect;
 34 import jdk.incubator.code.CodeTransformer;
 35 import jdk.incubator.code.Op;
 36 import jdk.incubator.code.dialect.core.CoreOp;
 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 TestTry {
 50 
 51     @Reflect
 52     public static void catching(IntConsumer c) {
 53         try {
 54             c.accept(0);
 55             c.accept(-1);
 56         } catch (IllegalStateException e) {
 57             consume(e);
 58             c.accept(1);
 59             c.accept(-1);
 60         } catch (IllegalArgumentException e) {
 61             consume(e);
 62             c.accept(2);
 63             c.accept(-1);
 64         }
 65         c.accept(3);
 66         c.accept(-1);
 67     }
 68 
 69     @Test
 70     public void testCatching() {
 71         CoreOp.FuncOp f = getFuncOp("catching");
 72 
 73         System.out.println(f.toText());
 74 
 75         CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
 76 
 77         System.out.println(lf.toText());
 78 
 79         for (CoreOp.FuncOp op : List.of(f, lf)) {
 80             Consumer<IntConsumer> test = testConsumer(
 81                     c -> Interpreter.invoke(MethodHandles.lookup(), op, c),
 82                     TestTry::catching);
 83 
 84             test.accept(i -> {
 85             });
 86             test.accept(i -> {
 87                 if (i == 0) throw new IllegalStateException();
 88             });
 89             test.accept(i -> {
 90                 if (i == 0) throw new IllegalArgumentException();
 91             });
 92             test.accept(i -> {
 93                 if (i == 0) throw new NullPointerException();
 94             });
 95             test.accept(i -> {
 96                 if (i == 0) throw new IllegalStateException();
 97                 if (i == 1) throw new RuntimeException();
 98             });
 99             test.accept(i -> {
100                 if (i == 0) throw new IllegalArgumentException();
101                 if (i == 2) throw new RuntimeException();
102             });
103             test.accept(i -> {
104                 if (i == 3) throw new IllegalStateException();
105             });
106         }
107     }
108 
109 
110     @Reflect
111     public static void catchThrowable(IntConsumer c) {
112         try {
113             c.accept(0);
114             c.accept(-1);
115         } catch (IllegalStateException e) {
116             consume(e);
117             c.accept(1);
118             c.accept(-1);
119         } catch (Throwable e) {
120             consume(e);
121             c.accept(2);
122             c.accept(-1);
123         }
124         c.accept(3);
125         c.accept(-1);
126     }
127 
128     @Test
129     public void testCatchThrowable() {
130         CoreOp.FuncOp f = getFuncOp("catchThrowable");
131 
132         System.out.println(f.toText());
133 
134         CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
135 
136         System.out.println(lf.toText());
137 
138         for (CoreOp.FuncOp op : List.of(f, lf)) {
139             Consumer<IntConsumer> test = testConsumer(
140                     c -> Interpreter.invoke(MethodHandles.lookup(), op, c),
141                     TestTry::catchThrowable);
142 
143             test.accept(i -> {
144             });
145             test.accept(i -> {
146                 if (i == 0) throw new IllegalStateException();
147             });
148             test.accept(i -> {
149                 if (i == 0) throw new RuntimeException();
150             });
151             test.accept(i -> {
152                 if (i == 0) throw new IllegalStateException();
153                 if (i == 1) throw new RuntimeException();
154             });
155             test.accept(i -> {
156                 if (i == 0) throw new RuntimeException();
157                 if (i == 2) throw new RuntimeException();
158             });
159             test.accept(i -> {
160                 if (i == 3) throw new IllegalStateException();
161             });
162         }
163     }
164 
165 
166     @Reflect
167     public static void catchNested(IntConsumer c) {
168         try {
169             c.accept(0);
170             c.accept(-1);
171             try {
172                 c.accept(1);
173                 c.accept(-1);
174             } catch (IllegalStateException e) {
175                 consume(e);
176                 c.accept(2);
177                 c.accept(-1);
178             }
179             c.accept(3);
180             c.accept(-1);
181         } catch (IllegalArgumentException e) {
182             consume(e);
183             c.accept(4);
184             c.accept(-1);
185         }
186         c.accept(5);
187         c.accept(-1);
188     }
189 
190     @Test
191     public void testCatchNested() {
192         CoreOp.FuncOp f = getFuncOp("catchNested");
193 
194         System.out.println(f.toText());
195 
196         CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
197 
198         System.out.println(lf.toText());
199 
200         for (CoreOp.FuncOp op : List.of(f, lf)) {
201             Consumer<IntConsumer> test = testConsumer(
202                     c -> Interpreter.invoke(MethodHandles.lookup(), op, c),
203                     TestTry::catchNested);
204 
205             test.accept(i -> {
206             });
207             test.accept(i -> {
208                 if (i == 0) throw new IllegalStateException();
209             });
210             test.accept(i -> {
211                 if (i == 0) throw new IllegalArgumentException();
212             });
213             test.accept(i -> {
214                 if (i == 1) throw new IllegalStateException();
215             });
216             test.accept(i -> {
217                 if (i == 1) throw new IllegalArgumentException();
218             });
219             test.accept(i -> {
220                 if (i == 1) throw new IllegalStateException();
221                 if (i == 2) throw new IllegalArgumentException();
222             });
223             test.accept(i -> {
224                 if (i == 1) throw new IllegalStateException();
225                 if (i == 2) throw new RuntimeException();
226             });
227             test.accept(i -> {
228                 if (i == 3) throw new IllegalArgumentException();
229             });
230             test.accept(i -> {
231                 if (i == 3) throw new RuntimeException();
232             });
233             test.accept(i -> {
234                 if (i == 3) throw new IllegalArgumentException();
235                 if (i == 4) throw new RuntimeException();
236             });
237             test.accept(i -> {
238                 if (i == 5) throw new RuntimeException();
239             });
240         }
241     }
242 
243 
244     static CoreOp.FuncOp getFuncOp(String name) {
245         Optional<Method> om = Stream.of(TestTry.class.getDeclaredMethods())
246                 .filter(m -> m.getName().equals(name))
247                 .findFirst();
248 
249         Method m = om.get();
250         return Op.ofMethod(m).get();
251     }
252 
253     static void consume(Throwable e) {
254     }
255 
256     static Consumer<IntConsumer> testConsumer(Consumer<IntConsumer> actualR, Consumer<IntConsumer> expectedR) {
257         return c -> {
258             List<Integer> actual = new ArrayList<>();
259             IntConsumer actualC = actual::add;
260             Throwable actualT = null;
261             try {
262                 actualR.accept(actualC.andThen(c));
263             } catch (Interpreter.InterpreterException e) {
264                 throw e;
265             } catch (Throwable t) {
266                 actualT = t;
267                 if (t instanceof AssertionError) {
268                     t.printStackTrace();
269                 }
270             }
271 
272             List<Integer> expected = new ArrayList<>();
273             IntConsumer expectedC = expected::add;
274             Throwable expectedT = null;
275             try {
276                 expectedR.accept(expectedC.andThen(c));
277             } catch (Throwable t) {
278                 expectedT = t;
279             }
280 
281             Assertions.assertEquals(
282                     expectedT != null ? expectedT.getClass() : null, actualT != null ? actualT.getClass() : null
283             );
284             Assertions.assertEquals(expected, actual);
285         };
286     }
287 }