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