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