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 TestTry 47 */ 48 49 public class TestTry { 50 51 @CodeReflection 52 public static void catching(IntConsumer c) { 53 try { 54 c.accept(0); 55 c.accept(-1); 56 } catch (IllegalStateException e) { 57 consume(e); 58 c.accept(1); 59 c.accept(-1); 60 } catch (IllegalArgumentException e) { 61 consume(e); 62 c.accept(2); 63 c.accept(-1); 64 } 65 c.accept(3); 66 c.accept(-1); 67 } 68 69 @Test 70 public void testCatching() { 71 CoreOp.FuncOp f = getFuncOp("catching"); 72 73 MethodHandle mh = generate(f); 74 75 Consumer<IntConsumer> test = testConsumer( 76 asConsumer(mh), 77 TestTry::catching); 78 79 test.accept(i -> { 80 }); 81 test.accept(i -> { 82 if (i == 0) throw new IllegalStateException(); 83 }); 84 test.accept(i -> { 85 if (i == 0) throw new IllegalArgumentException(); 86 }); 87 test.accept(i -> { 88 if (i == 0) throw new NullPointerException(); 89 }); 90 test.accept(i -> { 91 if (i == 0) throw new IllegalStateException(); 92 if (i == 1) throw new RuntimeException(); 93 }); 94 test.accept(i -> { 95 if (i == 0) throw new IllegalArgumentException(); 96 if (i == 2) throw new RuntimeException(); 97 }); 98 test.accept(i -> { 99 if (i == 3) throw new IllegalStateException(); 100 }); 101 } 102 103 @CodeReflection 104 public static void catchThrowable(IntConsumer c) { 105 try { 106 c.accept(0); 107 c.accept(-1); 108 } catch (IllegalStateException e) { 109 consume(e); 110 c.accept(1); 111 c.accept(-1); 112 } catch (Throwable e) { 113 consume(e); 114 c.accept(2); 115 c.accept(-1); 116 } 117 c.accept(3); 118 c.accept(-1); 119 } 120 121 @Test 122 public void testCatchThrowable() { 123 CoreOp.FuncOp f = getFuncOp("catchThrowable"); 124 125 MethodHandle mh = generate(f); 126 127 Consumer<IntConsumer> test = testConsumer( 128 asConsumer(mh), 129 TestTry::catchThrowable); 130 131 test.accept(i -> { 132 }); 133 test.accept(i -> { 134 if (i == 0) throw new IllegalStateException(); 135 }); 136 test.accept(i -> { 137 if (i == 0) throw new RuntimeException(); 138 }); 139 test.accept(i -> { 140 if (i == 0) throw new IllegalStateException(); 141 if (i == 1) throw new RuntimeException(); 142 }); 143 test.accept(i -> { 144 if (i == 0) throw new RuntimeException(); 145 if (i == 2) throw new RuntimeException(); 146 }); 147 test.accept(i -> { 148 if (i == 3) throw new IllegalStateException(); 149 }); 150 } 151 152 153 @CodeReflection 154 public static void catchNested(IntConsumer c) { 155 try { 156 c.accept(0); 157 c.accept(-1); 158 try { 159 c.accept(1); 160 c.accept(-1); 161 } catch (IllegalStateException e) { 162 consume(e); 163 c.accept(2); 164 c.accept(-1); 165 } 166 c.accept(3); 167 c.accept(-1); 168 } catch (IllegalArgumentException e) { 169 consume(e); 170 c.accept(4); 171 c.accept(-1); 172 } 173 c.accept(5); 174 c.accept(-1); 175 } 176 177 @Test 178 public void testCatchNested() { 179 CoreOp.FuncOp f = getFuncOp("catchNested"); 180 181 MethodHandle mh = generate(f); 182 183 Consumer<IntConsumer> test = testConsumer( 184 asConsumer(mh), 185 TestTry::catchNested); 186 187 test.accept(i -> { 188 }); 189 test.accept(i -> { 190 if (i == 0) throw new IllegalStateException(); 191 }); 192 test.accept(i -> { 193 if (i == 0) throw new IllegalArgumentException(); 194 }); 195 test.accept(i -> { 196 if (i == 1) throw new IllegalStateException(); 197 }); 198 test.accept(i -> { 199 if (i == 1) throw new IllegalArgumentException(); 200 }); 201 test.accept(i -> { 202 if (i == 1) throw new IllegalStateException(); 203 if (i == 2) throw new IllegalArgumentException(); 204 }); 205 test.accept(i -> { 206 if (i == 1) throw new IllegalStateException(); 207 if (i == 2) throw new RuntimeException(); 208 }); 209 test.accept(i -> { 210 if (i == 3) throw new IllegalArgumentException(); 211 }); 212 test.accept(i -> { 213 if (i == 3) throw new RuntimeException(); 214 }); 215 test.accept(i -> { 216 if (i == 3) throw new IllegalArgumentException(); 217 if (i == 4) throw new RuntimeException(); 218 }); 219 test.accept(i -> { 220 if (i == 5) throw new RuntimeException(); 221 }); 222 } 223 224 225 static void consume(Throwable e) { 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 260 static MethodHandle generate(CoreOp.FuncOp f) { 261 f.writeTo(System.out); 262 263 CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER); 264 lf.writeTo(System.out); 265 266 return BytecodeGenerator.generate(MethodHandles.lookup(), lf); 267 } 268 269 static <T> Consumer<T> asConsumer(MethodHandle mh) { 270 return c -> { 271 try { 272 mh.invoke(c); 273 } catch (Throwable e) { 274 throw erase(e); 275 } 276 }; 277 } 278 279 @SuppressWarnings("unchecked") 280 public static <E extends Throwable> E erase(Throwable e) throws E { 281 return (E) e; 282 } 283 284 static CoreOp.FuncOp getFuncOp(String name) { 285 Optional<Method> om = Stream.of(TestTry.class.getDeclaredMethods()) 286 .filter(m -> m.getName().equals(name)) 287 .findFirst(); 288 289 Method m = om.get(); 290 return Op.ofMethod(m).get(); 291 } 292 }