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