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