1 /* 2 * Copyright (c) 2011, 2012, 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 /* @test 25 * @summary unit tests for method handles which permute their arguments 26 * @run testng test.java.lang.invoke.ThrowExceptionsTest 27 */ 28 29 package test.java.lang.invoke; 30 31 import org.testng.*; 32 import org.testng.annotations.*; 33 34 import java.util.*; 35 import java.lang.reflect.*; 36 37 import java.lang.invoke.*; 38 import static java.lang.invoke.MethodHandles.*; 39 import static java.lang.invoke.MethodType.*; 40 41 public class ThrowExceptionsTest { 42 private static final Class<?> CLASS = ThrowExceptionsTest.class; 43 private static final Lookup LOOKUP = lookup(); 44 45 public static void main(String argv[]) throws Throwable { 46 new ThrowExceptionsTest().testAll((argv.length == 0 ? null : Arrays.asList(argv).toString())); 47 } 48 49 @Test 50 public void testWMT() throws Throwable { 51 // mostly call testWMTCallee, but sometimes call its void-returning variant 52 MethodHandle mh = testWMTCallee(); 53 MethodHandle mh1 = mh.asType(mh.type().changeReturnType(void.class)); 54 assert(mh1 != mh); 55 testWMT(mh, mh1, 1000); 56 } 57 58 @Test 59 public void testBoundWMT() throws Throwable { 60 // mostly call exactInvoker.bindTo(testWMTCallee), but sometimes call its void-returning variant 61 MethodHandle callee = testWMTCallee(); 62 MethodHandle callee1 = callee.asType(callee.type().changeReturnType(void.class)); 63 MethodHandle invoker = exactInvoker(callee.type()); 64 MethodHandle mh = invoker.bindTo(callee); 65 MethodHandle mh1 = invoker.bindTo(callee1); 66 testWMT(mh, mh1, 1000); 67 } 68 69 @Test 70 public void testFoldWMT() throws Throwable { 71 // mostly call exactInvoker.fold(constant(testWMTCallee)), but sometimes call its void-returning variant 72 MethodHandle callee = testWMTCallee(); 73 MethodHandle callee1 = callee.asType(callee.type().changeReturnType(void.class)); 74 MethodHandle invoker = exactInvoker(callee.type()); 75 MethodHandle mh = foldArguments(invoker, constant(MethodHandle.class, callee)); 76 MethodHandle mh1 = foldArguments(invoker, constant(MethodHandle.class, callee1)); 77 testWMT(mh, mh1, 1000); 78 } 79 80 @Test 81 public void testFoldCCE() throws Throwable { 82 MethodHandle callee = testWMTCallee(); 83 MethodHandle callee1 = callee.asType(callee.type().changeParameterType(1, Number.class)).asType(callee.type()); 84 MethodHandle invoker = exactInvoker(callee.type()); 85 MethodHandle mh = foldArguments(invoker, constant(MethodHandle.class, callee)); 86 MethodHandle mh1 = foldArguments(invoker, constant(MethodHandle.class, callee1)); 87 testWMT(mh, mh1, 1000); 88 } 89 90 @Test 91 public void testStackOverflow() throws Throwable { 92 MethodHandle callee = testWMTCallee(); 93 MethodHandle callee1 = makeStackOverflow().asType(callee.type()); 94 MethodHandle invoker = exactInvoker(callee.type()); 95 MethodHandle mh = foldArguments(invoker, constant(MethodHandle.class, callee)); 96 MethodHandle mh1 = foldArguments(invoker, constant(MethodHandle.class, callee1)); 97 for (int i = 0; i < REPEAT; i++) { 98 try { 99 testWMT(mh, mh1, 1000); 100 } catch (StackOverflowError ex) { 101 // OK, try again 102 } 103 } 104 } 105 106 private static MethodHandle makeStackOverflow() { 107 MethodType cellType = methodType(void.class); 108 MethodHandle[] cell = { null }; // recursion point 109 MethodHandle getCell = insertArguments(arrayElementGetter(cell.getClass()), 0, cell, 0); 110 MethodHandle invokeCell = foldArguments(exactInvoker(cellType), getCell); 111 assert(invokeCell.type() == cellType); 112 cell[0] = invokeCell; 113 // make it conformable to any type: 114 invokeCell = dropArguments(invokeCell, 0, Object[].class).asVarargsCollector(Object[].class); 115 return invokeCell; 116 } 117 118 static int testCases; 119 120 private void testAll(String match) throws Throwable { 121 testCases = 0; 122 Lookup lookup = lookup(); 123 for (Method m : CLASS.getDeclaredMethods()) { 124 String name = m.getName(); 125 if (name.startsWith("test") && 126 (match == null || match.contains(name.substring("test".length()))) && 127 m.getParameterTypes().length == 0 && 128 Modifier.isPublic(m.getModifiers()) && 129 !Modifier.isStatic(m.getModifiers())) { 130 System.out.println("["+name+"]"); 131 int tc = testCases; 132 try { 133 m.invoke(this); 134 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { 135 System.out.println("*** "+ex); 136 ex.printStackTrace(System.out); 137 } 138 if (testCases == tc) testCases++; 139 } 140 } 141 if (testCases == 0) throw new RuntimeException("no test cases found"); 142 System.out.println("ran a total of "+testCases+" test cases"); 143 } 144 145 private static MethodHandle findStatic(String name) { 146 return findMethod(name, true); 147 } 148 private static MethodHandle findVirtual(String name) { 149 return findMethod(name, false); 150 } 151 private static MethodHandle findMethod(String name, boolean isStatic) { 152 MethodHandle mh = null; 153 for (Method m : CLASS.getDeclaredMethods()) { 154 if (m.getName().equals(name) && 155 Modifier.isStatic(m.getModifiers()) == isStatic) { 156 if (mh != null) 157 throw new RuntimeException("duplicate methods: "+name); 158 try { 159 mh = LOOKUP.unreflect(m); 160 } catch (ReflectiveOperationException ex) { 161 throw new RuntimeException(ex); 162 } 163 } 164 } 165 if (mh == null) 166 throw new RuntimeException("no method: "+name); 167 return mh; 168 } 169 170 int testWMTCallee; 171 private int testWMTCallee(String x) { 172 return testWMTCallee++; 173 } 174 private static MethodHandle testWMTCallee() { 175 MethodHandle callee = findVirtual("testWMTCallee"); 176 // FIXME: should not have to retype callee 177 callee = callee.asType(callee.type().changeParameterType(0, Object.class)); 178 return callee; 179 } 180 181 private Exception testWMT(MethodHandle[] mhs, int reps) throws Throwable { 182 testCases += 1; 183 testWMTCallee = 0; 184 int catches = 0; 185 Exception savedEx = null; 186 for (int i = 0; i < reps; i++) { 187 MethodHandle mh = mhs[i % mhs.length]; 188 int n; 189 try { 190 // FIXME: should not have to retype this 191 n = (int) mh.invokeExact((Object)this, "x"); 192 assertEquals(n, i - catches); 193 // Using the exact type for this causes endless deopt due to 194 // 'non_cached_result' in SystemDictionary::find_method_handle_invoke. 195 // The problem is that the compiler thread needs to access a cached 196 // invoke method, but invoke methods are not cached if one of the 197 // component types is not on the BCP. 198 } catch (Exception ex) { 199 savedEx = ex; 200 catches++; 201 } 202 } 203 //VERBOSE: System.out.println("reps="+reps+" catches="+catches); 204 return savedEx; 205 } 206 207 private static final int REPEAT = Integer.getInteger(CLASS.getSimpleName()+".REPEAT", 10); 208 209 private Exception testWMT(MethodHandle mh, MethodHandle mh1, int reps) throws Throwable { 210 //VERBOSE: System.out.println("mh="+mh+" mh1="+mh1); 211 MethodHandle[] mhs = new MethodHandle[100]; 212 Arrays.fill(mhs, mh); 213 int patch = mhs.length-1; 214 Exception savedEx = null; 215 for (int i = 0; i < REPEAT; i++) { 216 mhs[patch] = mh; 217 testWMT(mhs, 10000); 218 mhs[patch] = mh1; 219 savedEx = testWMT(mhs, reps); 220 } 221 return savedEx; 222 } 223 224 private static void assertEquals(Object x, Object y) { 225 if (x == y || x != null && x.equals(y)) return; 226 throw new RuntimeException(x+" != "+y); 227 } 228 }