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