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