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