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