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