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