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