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 junit TestTryFinally
28 */
29
30 import jdk.incubator.code.CodeReflection;
31 import jdk.incubator.code.Op;
32 import jdk.incubator.code.OpTransformer;
33 import jdk.incubator.code.dialect.core.CoreOp;
34 import jdk.incubator.code.interpreter.Interpreter;
35 import org.junit.jupiter.api.Assertions;
36 import org.junit.jupiter.api.Test;
37
38 import java.lang.invoke.MethodHandles;
39 import java.lang.reflect.Method;
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 System.out.println(f.toText());
70
71 CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
72
73 System.out.println(lf.toText());
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 System.out.println(f.toText());
106
107 CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
108
109 System.out.println(lf.toText());
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 System.out.println(f.toText());
142
143 CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
144
145 System.out.println(lf.toText());
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 System.out.println(f.toText());
176
177 CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
178
179 System.out.println(lf.toText());
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 Assertions.assertEquals(
245 expectedT != null ? expectedT.getClass() : null, actualT != null ? actualT.getClass() : null
246 );
247 Assertions.assertEquals(expected, actual);
248 };
249 }
250 }