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 jdk.incubator.code.OpTransformer; 28 import jdk.incubator.code.op.CoreOp; 29 import jdk.incubator.code.Op; 30 import jdk.incubator.code.bytecode.BytecodeGenerator; 31 import jdk.incubator.code.interpreter.Interpreter; 32 import java.lang.invoke.MethodHandle; 33 import java.lang.invoke.MethodHandles; 34 import java.lang.reflect.Method; 35 import jdk.incubator.code.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 * @modules jdk.incubator.code 46 * @run testng 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 f.writeTo(System.out); 198 199 CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER); 200 lf.writeTo(System.out); 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 Assert.assertEquals( 255 actualT != null ? actualT.getClass() : null, 256 expectedT != null ? expectedT.getClass() : null); 257 Assert.assertEquals(actual, expected); 258 }; 259 } 260 }