1 /* 2 * Copyright (c) 2018, 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 java.lang.invoke.MethodHandles 26 * @library /lib/testlibrary /java/lang/invoke/common 27 * @compile MethodHandlesTest.java MethodHandlesGeneralTest.java remote/RemoteExample.java 28 * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions 29 * -XX:-VerifyDependencies 30 * -esa 31 * test.java.lang.invoke.MethodHandlesGeneralTest 32 */ 33 34 package test.java.lang.invoke; 35 36 import org.junit.*; 37 38 // Android-removed: CodeCacheOverflowProcessor is not available 39 // import test.java.lang.invoke.lib.CodeCacheOverflowProcessor; 40 import test.java.lang.invoke.remote.RemoteExample; 41 42 import java.lang.invoke.MethodHandle; 43 // Android-removed: not supported 44 // import java.lang.invoke.MethodHandleProxies; 45 import java.lang.invoke.MethodHandles; 46 import java.lang.invoke.MethodType; 47 import java.lang.invoke.WrongMethodTypeException; 48 import java.lang.invoke.MethodHandles.Lookup; 49 import java.lang.reflect.Array; 50 import java.lang.reflect.Field; 51 import java.lang.reflect.Method; 52 import java.lang.reflect.Modifier; 53 import java.lang.reflect.UndeclaredThrowableException; 54 import java.util.ArrayList; 55 import java.util.Arrays; 56 import java.util.Collections; 57 import java.util.Formatter; 58 import java.util.HashMap; 59 import java.util.List; 60 import java.util.Map; 61 62 import static java.lang.invoke.MethodType.methodType; 63 import static org.junit.Assert.*; 64 65 public class MethodHandlesGeneralTest extends MethodHandlesTest { 66 67 @Test testFirst()68 public void testFirst() throws Throwable { 69 verbosity += 9; 70 try { 71 // left blank for debugging 72 } finally { printCounts(); verbosity -= 9; } 73 } 74 75 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 76 // Android-changed: test temporarily skipped due to b/236822435 77 @Ignore testFindStatic()78 public void testFindStatic() throws Throwable { 79 if (CAN_SKIP_WORKING) return; 80 startTest("findStatic"); 81 testFindStatic(PubExample.class, void.class, "s0"); 82 testFindStatic(Example.class, void.class, "s0"); 83 testFindStatic(Example.class, void.class, "pkg_s0"); 84 testFindStatic(Example.class, void.class, "pri_s0"); 85 testFindStatic(Example.class, void.class, "pro_s0"); 86 testFindStatic(PubExample.class, void.class, "Pub/pro_s0"); 87 88 testFindStatic(Example.class, Object.class, "s1", Object.class); 89 testFindStatic(Example.class, Object.class, "s2", int.class); 90 testFindStatic(Example.class, Object.class, "s3", long.class); 91 testFindStatic(Example.class, Object.class, "s4", int.class, int.class); 92 testFindStatic(Example.class, Object.class, "s5", long.class, int.class); 93 testFindStatic(Example.class, Object.class, "s6", int.class, long.class); 94 testFindStatic(Example.class, Object.class, "s7", float.class, double.class); 95 96 testFindStatic(false, PRIVATE, Example.class, void.class, "bogus"); 97 testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", int.class); 98 testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", Void.class); 99 testFindStatic(false, PRIVATE, Example.class, void.class, "v0"); 100 } 101 testFindStatic(Class<?> defc, Class<?> ret, String name, Class<?>... params)102 void testFindStatic(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 103 for (Object[] ac : accessCases(defc, name)) { 104 testFindStatic((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params); 105 } 106 } 107 testFindStatic(Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params)108 void testFindStatic(Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 109 testFindStatic(true, lookup, defc, ret, name, params); 110 } 111 testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params)112 void testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 113 countTest(positive); 114 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 115 MethodType type = MethodType.methodType(ret, params); 116 MethodHandle target = null; 117 Exception noAccess = null; 118 try { 119 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 120 target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type); 121 } catch (ReflectiveOperationException ex) { 122 noAccess = ex; 123 assertExceptionClass( 124 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 125 ? NoSuchMethodException.class 126 : IllegalAccessException.class, 127 noAccess); 128 if (verbosity >= 5) ex.printStackTrace(System.out); 129 } 130 if (verbosity >= 3) 131 System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target 132 +(noAccess == null ? "" : " !! "+noAccess)); 133 if (positive && noAccess != null) throw noAccess; 134 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 135 if (!positive) return; // negative test failed as expected 136 assertEquals(type, target.type()); 137 assertNameStringContains(target, methodName); 138 Object[] args = randomArgs(params); 139 printCalled(target, name, args); 140 target.invokeWithArguments(args); 141 assertCalled(name, args); 142 if (verbosity >= 1) 143 System.out.print(':'); 144 } 145 146 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 147 // Android-changed: test temporarily skipped due to b/236817416 148 @Ignore testFindVirtual()149 public void testFindVirtual() throws Throwable { 150 if (CAN_SKIP_WORKING) return; 151 startTest("findVirtual"); 152 testFindVirtual(Example.class, void.class, "v0"); 153 testFindVirtual(Example.class, void.class, "pkg_v0"); 154 testFindVirtual(Example.class, void.class, "pri_v0"); 155 testFindVirtual(Example.class, Object.class, "v1", Object.class); 156 testFindVirtual(Example.class, Object.class, "v2", Object.class, Object.class); 157 testFindVirtual(Example.class, Object.class, "v2", Object.class, int.class); 158 testFindVirtual(Example.class, Object.class, "v2", int.class, Object.class); 159 testFindVirtual(Example.class, Object.class, "v2", int.class, int.class); 160 testFindVirtual(Example.class, void.class, "pro_v0"); 161 testFindVirtual(PubExample.class, void.class, "Pub/pro_v0"); 162 163 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus"); 164 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", int.class); 165 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", Void.class); 166 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "s0"); 167 168 // test dispatch 169 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/v0"); 170 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/v0"); 171 testFindVirtual(SubExample.class, IntExample.class, void.class, "Sub/v0"); 172 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/pkg_v0"); 173 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/pkg_v0"); 174 testFindVirtual(Example.class, IntExample.class, void.class, "v0"); 175 testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0"); 176 } 177 178 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 179 // Android-changed: test temporarily skipped due to b/236822443 180 @Ignore testFindVirtualClone()181 public void testFindVirtualClone() throws Throwable { 182 if (CAN_SKIP_WORKING) return; 183 // test some ad hoc system methods 184 testFindVirtual(false, PUBLIC, Object.class, Object.class, "clone"); 185 186 // ##### FIXME - disable tests for clone until we figure out how they should work with modules 187 188 /* 189 testFindVirtual(true, PUBLIC, Object[].class, Object.class, "clone"); 190 testFindVirtual(true, PUBLIC, int[].class, Object.class, "clone"); 191 for (Class<?> cls : new Class<?>[]{ boolean[].class, long[].class, float[].class, char[].class }) 192 testFindVirtual(true, PUBLIC, cls, Object.class, "clone"); 193 */ 194 } 195 testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params)196 void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 197 Class<?> rcvc = defc; 198 testFindVirtual(rcvc, defc, ret, name, params); 199 } 200 testFindVirtual(Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params)201 void testFindVirtual(Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 202 for (Object[] ac : accessCases(defc, name)) { 203 testFindVirtual((Boolean)ac[0], (Lookup)ac[1], rcvc, defc, ret, name, params); 204 } 205 } 206 testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params)207 void testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 208 testFindVirtual(true, lookup, rcvc, defc, ret, name, params); 209 } 210 testFindVirtual(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params)211 void testFindVirtual(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 212 testFindVirtual(positive, lookup, defc, defc, ret, name, params); 213 } 214 testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params)215 void testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 216 countTest(positive); 217 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 218 MethodType type = MethodType.methodType(ret, params); 219 MethodHandle target = null; 220 Exception noAccess = null; 221 try { 222 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 223 target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type); 224 } catch (ReflectiveOperationException ex) { 225 noAccess = ex; 226 assertExceptionClass( 227 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 228 ? NoSuchMethodException.class 229 : IllegalAccessException.class, 230 noAccess); 231 if (verbosity >= 5) ex.printStackTrace(System.out); 232 } 233 if (verbosity >= 3) 234 System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target 235 +(noAccess == null ? "" : " !! "+noAccess)); 236 if (positive && noAccess != null) throw noAccess; 237 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 238 if (!positive) return; // negative test failed as expected 239 Class<?> selfc = defc; 240 // predict receiver type narrowing: 241 if (lookup == SUBCLASS && 242 name.contains("pro_") && 243 selfc.isAssignableFrom(lookup.lookupClass())) { 244 selfc = lookup.lookupClass(); 245 if (name.startsWith("Pub/")) name = "Rem/"+name.substring(4); 246 } 247 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)selfc), params); 248 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf); 249 assertEquals(typeWithSelf, target.type()); 250 assertNameStringContains(target, methodName); 251 Object[] argsWithSelf = randomArgs(paramsWithSelf); 252 if (selfc.isAssignableFrom(rcvc) && rcvc != selfc) argsWithSelf[0] = randomArg(rcvc); 253 printCalled(target, name, argsWithSelf); 254 Object res = target.invokeWithArguments(argsWithSelf); 255 if (Example.class.isAssignableFrom(defc) || IntExample.class.isAssignableFrom(defc)) { 256 assertCalled(name, argsWithSelf); 257 } else if (name.equals("clone")) { 258 // Ad hoc method call outside Example. For Object[].clone. 259 printCalled(target, name, argsWithSelf); 260 assertEquals(MethodType.methodType(Object.class, rcvc), target.type()); 261 Object orig = argsWithSelf[0]; 262 assertEquals(orig.getClass(), res.getClass()); 263 if (res instanceof Object[]) 264 assertArrayEquals((Object[])res, (Object[])argsWithSelf[0]); 265 assert(Arrays.deepEquals(new Object[]{res}, new Object[]{argsWithSelf[0]})); 266 } else { 267 assert(false) : Arrays.asList(positive, lookup, rcvc, defc, ret, name, deepToString(params)); 268 } 269 if (verbosity >= 1) 270 System.out.print(':'); 271 } 272 273 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 274 // Android-changed: test temporarily skipped due to b/77634459 275 @Ignore testFindSpecial()276 public void testFindSpecial() throws Throwable { 277 if (CAN_SKIP_WORKING) return; 278 startTest("findSpecial"); 279 testFindSpecial(SubExample.class, Example.class, void.class, false, "v0"); 280 testFindSpecial(SubExample.class, Example.class, void.class, false, "pkg_v0"); 281 testFindSpecial(RemoteExample.class, PubExample.class, void.class, false, "Pub/pro_v0"); 282 testFindSpecial(Example.class, IntExample.class, void.class, true, "vd"); 283 // Do some negative testing: 284 for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) { 285 testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0"); 286 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus"); 287 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class); 288 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class); 289 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0"); 290 testFindSpecial(false, lookup, Example.class, IntExample.class, void.class, "v0"); 291 } 292 } 293 testFindSpecial(Class<?> specialCaller, Class<?> defc, Class<?> ret, boolean dflt, String name, Class<?>... params)294 void testFindSpecial(Class<?> specialCaller, 295 Class<?> defc, Class<?> ret, boolean dflt, String name, Class<?>... params) throws Throwable { 296 if (specialCaller == RemoteExample.class) { 297 testFindSpecial(false, EXAMPLE, specialCaller, defc, ret, name, params); 298 testFindSpecial(false, PRIVATE, specialCaller, defc, ret, name, params); 299 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params); 300 testFindSpecial(true, SUBCLASS, specialCaller, defc, ret, name, params); 301 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params); 302 return; 303 } 304 testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params); 305 testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params); 306 testFindSpecial(false || dflt, PACKAGE, specialCaller, defc, ret, name, params); 307 testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params); 308 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params); 309 } 310 testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller, Class<?> defc, Class<?> ret, String name, Class<?>... params)311 void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller, 312 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 313 countTest(positive); 314 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 315 MethodType type = MethodType.methodType(ret, params); 316 Lookup specialLookup = maybeMoveIn(lookup, specialCaller); 317 boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller && 318 (specialLookup.lookupModes() & Lookup.PRIVATE) != 0); 319 MethodHandle target = null; 320 Exception noAccess = null; 321 try { 322 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 323 if (verbosity >= 5) System.out.println(" lookup => "+specialLookup); 324 target = specialLookup.findSpecial(defc, methodName, type, specialCaller); 325 } catch (ReflectiveOperationException ex) { 326 noAccess = ex; 327 assertExceptionClass( 328 (!specialAccessOK) // this check should happen first 329 ? IllegalAccessException.class 330 : (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 331 ? NoSuchMethodException.class 332 : IllegalAccessException.class, 333 noAccess); 334 if (verbosity >= 5) ex.printStackTrace(System.out); 335 } 336 if (verbosity >= 3) 337 System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target 338 +(target == null ? "" : target.type()) 339 +(noAccess == null ? "" : " !! "+noAccess)); 340 if (positive && noAccess != null) throw noAccess; 341 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 342 if (!positive) return; // negative test failed as expected 343 assertEquals(specialCaller, target.type().parameterType(0)); 344 assertEquals(type, target.type().dropParameterTypes(0,1)); 345 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params); 346 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf); 347 assertNameStringContains(target, methodName); 348 Object[] args = randomArgs(paramsWithSelf); 349 printCalled(target, name, args); 350 target.invokeWithArguments(args); 351 assertCalled(name, args); 352 } 353 354 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 355 @Test testFindConstructor()356 public void testFindConstructor() throws Throwable { 357 if (CAN_SKIP_WORKING) return; 358 startTest("findConstructor"); 359 testFindConstructor(true, EXAMPLE, Example.class); 360 testFindConstructor(true, EXAMPLE, Example.class, int.class); 361 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class); 362 testFindConstructor(true, EXAMPLE, Example.class, int.class, long.class); 363 testFindConstructor(true, EXAMPLE, Example.class, int.class, float.class); 364 testFindConstructor(true, EXAMPLE, Example.class, int.class, double.class); 365 testFindConstructor(true, EXAMPLE, Example.class, String.class); 366 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class); 367 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class, int.class); 368 } 369 testFindConstructor(boolean positive, Lookup lookup, Class<?> defc, Class<?>... params)370 void testFindConstructor(boolean positive, Lookup lookup, 371 Class<?> defc, Class<?>... params) throws Throwable { 372 countTest(positive); 373 MethodType type = MethodType.methodType(void.class, params); 374 MethodHandle target = null; 375 Exception noAccess = null; 376 try { 377 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" <init>"+type); 378 target = lookup.findConstructor(defc, type); 379 } catch (ReflectiveOperationException ex) { 380 noAccess = ex; 381 assertTrue(noAccess.getClass().getName(), noAccess instanceof IllegalAccessException); 382 } 383 if (verbosity >= 3) 384 System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target 385 +(target == null ? "" : target.type()) 386 +(noAccess == null ? "" : " !! "+noAccess)); 387 if (positive && noAccess != null) throw noAccess; 388 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 389 if (!positive) return; // negative test failed as expected 390 assertEquals(type.changeReturnType(defc), target.type()); 391 Object[] args = randomArgs(params); 392 printCalled(target, defc.getSimpleName(), args); 393 Object obj = target.invokeWithArguments(args); 394 if (!(defc == Example.class && params.length < 2)) 395 assertCalled(defc.getSimpleName()+".<init>", args); 396 assertTrue("instance of "+defc.getName(), defc.isInstance(obj)); 397 } 398 399 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 400 @Test testBind()401 public void testBind() throws Throwable { 402 if (CAN_SKIP_WORKING) return; 403 startTest("bind"); 404 testBind(Example.class, void.class, "v0"); 405 testBind(Example.class, void.class, "pkg_v0"); 406 testBind(Example.class, void.class, "pri_v0"); 407 testBind(Example.class, Object.class, "v1", Object.class); 408 testBind(Example.class, Object.class, "v2", Object.class, Object.class); 409 testBind(Example.class, Object.class, "v2", Object.class, int.class); 410 testBind(Example.class, Object.class, "v2", int.class, Object.class); 411 testBind(Example.class, Object.class, "v2", int.class, int.class); 412 testBind(false, PRIVATE, Example.class, void.class, "bogus"); 413 testBind(false, PRIVATE, Example.class, void.class, "<init>", int.class); 414 testBind(false, PRIVATE, Example.class, void.class, "<init>", Void.class); 415 testBind(SubExample.class, void.class, "Sub/v0"); 416 testBind(SubExample.class, void.class, "Sub/pkg_v0"); 417 testBind(IntExample.Impl.class, void.class, "Int/v0"); 418 } 419 testBind(Class<?> defc, Class<?> ret, String name, Class<?>... params)420 void testBind(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 421 for (Object[] ac : accessCases(defc, name)) { 422 testBind((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params); 423 } 424 } 425 testBind(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params)426 void testBind(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 427 countTest(positive); 428 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 429 MethodType type = MethodType.methodType(ret, params); 430 Object receiver = randomArg(defc); 431 MethodHandle target = null; 432 Exception noAccess = null; 433 try { 434 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 435 target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type); 436 } catch (ReflectiveOperationException ex) { 437 noAccess = ex; 438 assertExceptionClass( 439 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 440 ? NoSuchMethodException.class 441 : IllegalAccessException.class, 442 noAccess); 443 if (verbosity >= 5) ex.printStackTrace(System.out); 444 } 445 if (verbosity >= 3) 446 System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target 447 +(noAccess == null ? "" : " !! "+noAccess)); 448 if (positive && noAccess != null) throw noAccess; 449 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 450 if (!positive) return; // negative test failed as expected 451 assertEquals(type, target.type()); 452 Object[] args = randomArgs(params); 453 printCalled(target, name, args); 454 target.invokeWithArguments(args); 455 Object[] argsWithReceiver = cat(array(Object[].class, receiver), args); 456 assertCalled(name, argsWithReceiver); 457 if (verbosity >= 1) 458 System.out.print(':'); 459 } 460 461 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 462 @Test testUnreflect()463 public void testUnreflect() throws Throwable { 464 if (CAN_SKIP_WORKING) return; 465 startTest("unreflect"); 466 testUnreflect(Example.class, true, void.class, "s0"); 467 testUnreflect(Example.class, true, void.class, "pro_s0"); 468 testUnreflect(Example.class, true, void.class, "pkg_s0"); 469 testUnreflect(Example.class, true, void.class, "pri_s0"); 470 471 testUnreflect(Example.class, true, Object.class, "s1", Object.class); 472 testUnreflect(Example.class, true, Object.class, "s2", int.class); 473 testUnreflect(Example.class, true, Object.class, "s3", long.class); 474 testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class); 475 testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class); 476 testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class); 477 478 testUnreflect(Example.class, false, void.class, "v0"); 479 testUnreflect(Example.class, false, void.class, "pkg_v0"); 480 testUnreflect(Example.class, false, void.class, "pri_v0"); 481 testUnreflect(Example.class, false, Object.class, "v1", Object.class); 482 testUnreflect(Example.class, false, Object.class, "v2", Object.class, Object.class); 483 testUnreflect(Example.class, false, Object.class, "v2", Object.class, int.class); 484 testUnreflect(Example.class, false, Object.class, "v2", int.class, Object.class); 485 testUnreflect(Example.class, false, Object.class, "v2", int.class, int.class); 486 487 // Test a public final member in another package: 488 testUnreflect(RemoteExample.class, false, void.class, "Rem/fin_v0"); 489 } 490 testUnreflect(Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params)491 void testUnreflect(Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable { 492 for (Object[] ac : accessCases(defc, name)) { 493 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, (isStatic ? null : defc), ret, name, params); 494 } 495 } 496 testUnreflect(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params)497 void testUnreflect(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 498 for (Object[] ac : accessCases(defc, name)) { 499 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params); 500 } 501 } 502 testUnreflectMaybeSpecial(Class<?> specialCaller, boolean positive, Lookup lookup, Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params)503 void testUnreflectMaybeSpecial(Class<?> specialCaller, 504 boolean positive, Lookup lookup, 505 Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 506 countTest(positive); 507 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 508 MethodType type = MethodType.methodType(ret, params); 509 Lookup specialLookup = (specialCaller != null ? maybeMoveIn(lookup, specialCaller) : null); 510 boolean specialAccessOK = (specialCaller != null && 511 specialLookup.lookupClass() == specialCaller && 512 (specialLookup.lookupModes() & Lookup.PRIVATE) != 0); 513 Method rmethod = defc.getDeclaredMethod(methodName, params); 514 MethodHandle target = null; 515 Exception noAccess = null; 516 boolean isStatic = (rcvc == null); 517 boolean isSpecial = (specialCaller != null); 518 try { 519 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 520 if (isSpecial) 521 target = specialLookup.unreflectSpecial(rmethod, specialCaller); 522 else 523 target = maybeMoveIn(lookup, defc).unreflect(rmethod); 524 } catch (ReflectiveOperationException ex) { 525 noAccess = ex; 526 assertExceptionClass( 527 IllegalAccessException.class, // NSME is impossible, since it was already reflected 528 noAccess); 529 if (verbosity >= 5) ex.printStackTrace(System.out); 530 } 531 if (verbosity >= 3) 532 System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type 533 +(!isSpecial ? "" : " specialCaller="+specialCaller) 534 +( isStatic ? "" : " receiver="+rcvc) 535 +" => "+target 536 +(noAccess == null ? "" : " !! "+noAccess)); 537 if (positive && noAccess != null) throw noAccess; 538 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 539 if (!positive) return; // negative test failed as expected 540 assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers())); 541 Class<?>[] paramsMaybeWithSelf = params; 542 if (!isStatic) { 543 paramsMaybeWithSelf = cat(array(Class[].class, (Class)rcvc), params); 544 } 545 MethodType typeMaybeWithSelf = MethodType.methodType(ret, paramsMaybeWithSelf); 546 if (isStatic) { 547 assertEquals(typeMaybeWithSelf, target.type()); 548 } else { 549 if (isSpecial) 550 assertEquals(specialCaller, target.type().parameterType(0)); 551 else 552 assertEquals(defc, target.type().parameterType(0)); 553 assertEquals(typeMaybeWithSelf, target.type().changeParameterType(0, rcvc)); 554 } 555 Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf); 556 printCalled(target, name, argsMaybeWithSelf); 557 target.invokeWithArguments(argsMaybeWithSelf); 558 assertCalled(name, argsMaybeWithSelf); 559 if (verbosity >= 1) 560 System.out.print(':'); 561 } 562 testUnreflectSpecial(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params)563 void testUnreflectSpecial(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 564 for (Object[] ac : accessCases(defc, name, true)) { 565 Class<?> specialCaller = rcvc; 566 testUnreflectMaybeSpecial(specialCaller, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params); 567 } 568 } 569 570 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 571 @Test testUnreflectSpecial()572 public void testUnreflectSpecial() throws Throwable { 573 if (CAN_SKIP_WORKING) return; 574 startTest("unreflectSpecial"); 575 testUnreflectSpecial(Example.class, Example.class, void.class, "v0"); 576 testUnreflectSpecial(Example.class, SubExample.class, void.class, "v0"); 577 testUnreflectSpecial(Example.class, Example.class, void.class, "pkg_v0"); 578 testUnreflectSpecial(Example.class, SubExample.class, void.class, "pkg_v0"); 579 testUnreflectSpecial(Example.class, Example.class, Object.class, "v2", int.class, int.class); 580 testUnreflectSpecial(Example.class, SubExample.class, Object.class, "v2", int.class, int.class); 581 testUnreflectMaybeSpecial(Example.class, false, PRIVATE, Example.class, Example.class, void.class, "s0"); 582 } 583 584 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 585 @Test testUnreflectGetter()586 public void testUnreflectGetter() throws Throwable { 587 if (CAN_SKIP_WORKING) return; 588 startTest("unreflectGetter"); 589 testGetter(TEST_UNREFLECT); 590 } 591 592 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 593 @Test testFindGetter()594 public void testFindGetter() throws Throwable { 595 if (CAN_SKIP_WORKING) return; 596 startTest("findGetter"); 597 testGetter(TEST_FIND_FIELD); 598 testGetter(TEST_FIND_FIELD | TEST_BOUND); 599 } 600 601 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 602 @Test testFindStaticGetter()603 public void testFindStaticGetter() throws Throwable { 604 if (CAN_SKIP_WORKING) return; 605 startTest("findStaticGetter"); 606 testGetter(TEST_FIND_STATIC); 607 } 608 testGetter(int testMode)609 public void testGetter(int testMode) throws Throwable { 610 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one 611 for (Object[] c : HasFields.CASES) { 612 boolean positive = (c[1] != Error.class); 613 testGetter(positive, lookup, c[0], c[1], testMode); 614 if (positive) 615 testGetter(positive, lookup, c[0], c[1], testMode | TEST_NPE); 616 } 617 testGetter(true, lookup, 618 new Object[]{ true, System.class, "out", java.io.PrintStream.class }, 619 System.out, testMode); 620 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { 621 testGetter(false, lookup, 622 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class }, 623 null, testMode); 624 } 625 } 626 testGetter(boolean positive, MethodHandles.Lookup lookup, Object fieldRef, Object value, int testMode)627 public void testGetter(boolean positive, MethodHandles.Lookup lookup, 628 Object fieldRef, Object value, int testMode) throws Throwable { 629 testAccessor(positive, lookup, fieldRef, value, testMode); 630 } 631 testAccessor(boolean positive0, MethodHandles.Lookup lookup, Object fieldRef, Object value, int testMode0)632 public void testAccessor(boolean positive0, MethodHandles.Lookup lookup, 633 Object fieldRef, Object value, int testMode0) throws Throwable { 634 if (verbosity >= 4) 635 System.out.println("testAccessor"+Arrays.deepToString(new Object[]{positive0, lookup, fieldRef, value, testMode0})); 636 boolean isGetter = ((testMode0 & TEST_SETTER) == 0); 637 boolean doBound = ((testMode0 & TEST_BOUND) != 0); 638 boolean testNPE = ((testMode0 & TEST_NPE) != 0); 639 int testMode = testMode0 & ~(TEST_SETTER | TEST_BOUND | TEST_NPE); 640 boolean positive = positive0 && !testNPE; 641 boolean isStatic; 642 Class<?> fclass; 643 String fname; 644 Class<?> ftype; 645 Field f = (fieldRef instanceof Field ? (Field)fieldRef : null); 646 if (f != null) { 647 isStatic = Modifier.isStatic(f.getModifiers()); 648 fclass = f.getDeclaringClass(); 649 fname = f.getName(); 650 ftype = f.getType(); 651 } else { 652 Object[] scnt = (Object[]) fieldRef; 653 isStatic = (Boolean) scnt[0]; 654 fclass = (Class<?>) scnt[1]; 655 fname = (String) scnt[2]; 656 ftype = (Class<?>) scnt[3]; 657 try { 658 f = fclass.getDeclaredField(fname); 659 } catch (ReflectiveOperationException ex) { 660 f = null; 661 } 662 } 663 if (!testModeMatches(testMode, isStatic)) return; 664 if (f == null && testMode == TEST_UNREFLECT) return; 665 if (testNPE && isStatic) return; 666 countTest(positive); 667 MethodType expType; 668 if (isGetter) 669 expType = MethodType.methodType(ftype, HasFields.class); 670 else 671 expType = MethodType.methodType(void.class, HasFields.class, ftype); 672 if (isStatic) expType = expType.dropParameterTypes(0, 1); 673 Exception noAccess = null; 674 MethodHandle mh; 675 try { 676 switch (testMode0 & ~(TEST_BOUND | TEST_NPE)) { 677 case TEST_UNREFLECT: mh = lookup.unreflectGetter(f); break; 678 case TEST_FIND_FIELD: mh = lookup.findGetter(fclass, fname, ftype); break; 679 case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype); break; 680 case TEST_SETTER| 681 TEST_UNREFLECT: mh = lookup.unreflectSetter(f); break; 682 case TEST_SETTER| 683 TEST_FIND_FIELD: mh = lookup.findSetter(fclass, fname, ftype); break; 684 case TEST_SETTER| 685 TEST_FIND_STATIC: mh = lookup.findStaticSetter(fclass, fname, ftype); break; 686 default: 687 throw new InternalError("testMode="+testMode); 688 } 689 } catch (ReflectiveOperationException ex) { 690 mh = null; 691 noAccess = ex; 692 assertExceptionClass( 693 (fname.contains("bogus")) 694 ? NoSuchFieldException.class 695 : IllegalAccessException.class, 696 noAccess); 697 if (verbosity >= 5) ex.printStackTrace(System.out); 698 } 699 if (verbosity >= 3) 700 System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype 701 +" => "+mh 702 +(noAccess == null ? "" : " !! "+noAccess)); 703 if (positive && !testNPE && noAccess != null) throw new RuntimeException(noAccess); 704 assertEquals(positive0 ? "positive test" : "negative test erroneously passed", positive0, mh != null); 705 if (!positive && !testNPE) return; // negative access test failed as expected 706 assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount()); 707 708 709 assertSame(mh.type(), expType); 710 //assertNameStringContains(mh, fname); // This does not hold anymore with LFs 711 HasFields fields = new HasFields(); 712 HasFields fieldsForMH = fields; 713 if (testNPE) fieldsForMH = null; // perturb MH argument to elicit expected error 714 if (doBound) 715 mh = mh.bindTo(fieldsForMH); 716 Object sawValue; 717 Class<?> vtype = ftype; 718 if (ftype != int.class) vtype = Object.class; 719 if (isGetter) { 720 mh = mh.asType(mh.type().generic() 721 .changeReturnType(vtype)); 722 } else { 723 int last = mh.type().parameterCount() - 1; 724 mh = mh.asType(mh.type().generic() 725 .changeReturnType(void.class) 726 .changeParameterType(last, vtype)); 727 } 728 if (f != null && f.getDeclaringClass() == HasFields.class) { 729 assertEquals(f.get(fields), value); // clean to start with 730 } 731 Throwable caughtEx = null; 732 if (isGetter) { 733 Object expValue = value; 734 for (int i = 0; i <= 1; i++) { 735 sawValue = null; // make DA rules happy under try/catch 736 try { 737 if (isStatic || doBound) { 738 if (ftype == int.class) 739 sawValue = (int) mh.invokeExact(); // do these exactly 740 else 741 sawValue = mh.invokeExact(); 742 } else { 743 if (ftype == int.class) 744 sawValue = (int) mh.invokeExact((Object) fieldsForMH); 745 else 746 sawValue = mh.invokeExact((Object) fieldsForMH); 747 } 748 } catch (RuntimeException ex) { 749 if (ex instanceof NullPointerException && testNPE) { 750 caughtEx = ex; 751 break; 752 } 753 } 754 assertEquals(sawValue, expValue); 755 if (f != null && f.getDeclaringClass() == HasFields.class 756 && !Modifier.isFinal(f.getModifiers())) { 757 Object random = randomArg(ftype); 758 f.set(fields, random); 759 expValue = random; 760 } else { 761 break; 762 } 763 } 764 } else { 765 for (int i = 0; i <= 1; i++) { 766 Object putValue = randomArg(ftype); 767 try { 768 if (isStatic || doBound) { 769 if (ftype == int.class) 770 mh.invokeExact((int)putValue); // do these exactly 771 else 772 mh.invokeExact(putValue); 773 } else { 774 if (ftype == int.class) 775 mh.invokeExact((Object) fieldsForMH, (int)putValue); 776 else 777 mh.invokeExact((Object) fieldsForMH, putValue); 778 } 779 } catch (RuntimeException ex) { 780 if (ex instanceof NullPointerException && testNPE) { 781 caughtEx = ex; 782 break; 783 } 784 } 785 if (f != null && f.getDeclaringClass() == HasFields.class) { 786 assertEquals(f.get(fields), putValue); 787 } 788 } 789 } 790 if (f != null && f.getDeclaringClass() == HasFields.class) { 791 f.set(fields, value); // put it back 792 } 793 if (testNPE) { 794 if (caughtEx == null || !(caughtEx instanceof NullPointerException)) 795 throw new RuntimeException("failed to catch NPE exception"+(caughtEx == null ? " (caughtEx=null)" : ""), caughtEx); 796 caughtEx = null; // nullify expected exception 797 } 798 if (caughtEx != null) { 799 throw new RuntimeException("unexpected exception", caughtEx); 800 } 801 } 802 803 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 804 @Test testUnreflectSetter()805 public void testUnreflectSetter() throws Throwable { 806 if (CAN_SKIP_WORKING) return; 807 startTest("unreflectSetter"); 808 testSetter(TEST_UNREFLECT); 809 } 810 811 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 812 @Test testFindSetter()813 public void testFindSetter() throws Throwable { 814 if (CAN_SKIP_WORKING) return; 815 startTest("findSetter"); 816 testSetter(TEST_FIND_FIELD); 817 testSetter(TEST_FIND_FIELD | TEST_BOUND); 818 } 819 820 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 821 @Test testFindStaticSetter()822 public void testFindStaticSetter() throws Throwable { 823 if (CAN_SKIP_WORKING) return; 824 startTest("findStaticSetter"); 825 testSetter(TEST_FIND_STATIC); 826 } 827 testSetter(int testMode)828 public void testSetter(int testMode) throws Throwable { 829 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one 830 startTest("unreflectSetter"); 831 for (Object[] c : HasFields.CASES) { 832 boolean positive = (c[1] != Error.class); 833 testSetter(positive, lookup, c[0], c[1], testMode); 834 if (positive) 835 testSetter(positive, lookup, c[0], c[1], testMode | TEST_NPE); 836 } 837 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { 838 testSetter(false, lookup, 839 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class }, 840 null, testMode); 841 } 842 } 843 testSetter(boolean positive, MethodHandles.Lookup lookup, Object fieldRef, Object value, int testMode)844 public void testSetter(boolean positive, MethodHandles.Lookup lookup, 845 Object fieldRef, Object value, int testMode) throws Throwable { 846 testAccessor(positive, lookup, fieldRef, value, testMode | TEST_SETTER); 847 } 848 849 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 850 @Test testArrayElementGetter()851 public void testArrayElementGetter() throws Throwable { 852 if (CAN_SKIP_WORKING) return; 853 startTest("arrayElementGetter"); 854 testArrayElementGetterSetter(false); 855 } 856 857 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 858 @Test testArrayElementSetter()859 public void testArrayElementSetter() throws Throwable { 860 if (CAN_SKIP_WORKING) return; 861 startTest("arrayElementSetter"); 862 testArrayElementGetterSetter(true); 863 } 864 865 private static final int TEST_ARRAY_NONE = 0, TEST_ARRAY_NPE = 1, TEST_ARRAY_OOB = 2, TEST_ARRAY_ASE = 3; 866 testArrayElementGetterSetter(boolean testSetter)867 public void testArrayElementGetterSetter(boolean testSetter) throws Throwable { 868 testArrayElementGetterSetter(testSetter, TEST_ARRAY_NONE); 869 } 870 871 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 872 @Test testArrayElementErrors()873 public void testArrayElementErrors() throws Throwable { 874 if (CAN_SKIP_WORKING) return; 875 startTest("arrayElementErrors"); 876 testArrayElementGetterSetter(false, TEST_ARRAY_NPE); 877 testArrayElementGetterSetter(true, TEST_ARRAY_NPE); 878 testArrayElementGetterSetter(false, TEST_ARRAY_OOB); 879 testArrayElementGetterSetter(true, TEST_ARRAY_OOB); 880 testArrayElementGetterSetter(new Object[10], true, TEST_ARRAY_ASE); 881 testArrayElementGetterSetter(new Example[10], true, TEST_ARRAY_ASE); 882 testArrayElementGetterSetter(new IntExample[10], true, TEST_ARRAY_ASE); 883 } 884 testArrayElementGetterSetter(boolean testSetter, int negTest)885 public void testArrayElementGetterSetter(boolean testSetter, int negTest) throws Throwable { 886 testArrayElementGetterSetter(new String[10], testSetter, negTest); 887 testArrayElementGetterSetter(new Iterable<?>[10], testSetter, negTest); 888 testArrayElementGetterSetter(new Example[10], testSetter, negTest); 889 testArrayElementGetterSetter(new IntExample[10], testSetter, negTest); 890 testArrayElementGetterSetter(new Object[10], testSetter, negTest); 891 testArrayElementGetterSetter(new boolean[10], testSetter, negTest); 892 testArrayElementGetterSetter(new byte[10], testSetter, negTest); 893 testArrayElementGetterSetter(new char[10], testSetter, negTest); 894 testArrayElementGetterSetter(new short[10], testSetter, negTest); 895 testArrayElementGetterSetter(new int[10], testSetter, negTest); 896 testArrayElementGetterSetter(new float[10], testSetter, negTest); 897 testArrayElementGetterSetter(new long[10], testSetter, negTest); 898 testArrayElementGetterSetter(new double[10], testSetter, negTest); 899 } 900 testArrayElementGetterSetter(Object array, boolean testSetter, int negTest)901 public void testArrayElementGetterSetter(Object array, boolean testSetter, int negTest) throws Throwable { 902 boolean positive = (negTest == TEST_ARRAY_NONE); 903 int length = Array.getLength(array); 904 Class<?> arrayType = array.getClass(); 905 Class<?> elemType = arrayType.getComponentType(); 906 Object arrayToMH = array; 907 // this stanza allows negative tests to make argument perturbations: 908 switch (negTest) { 909 case TEST_ARRAY_NPE: 910 arrayToMH = null; 911 break; 912 case TEST_ARRAY_OOB: 913 assert(length > 0); 914 arrayToMH = Array.newInstance(elemType, 0); 915 break; 916 case TEST_ARRAY_ASE: 917 assert(testSetter && !elemType.isPrimitive()); 918 if (elemType == Object.class) 919 arrayToMH = new StringBuffer[length]; // very random subclass of Object! 920 else if (elemType == Example.class) 921 arrayToMH = new SubExample[length]; 922 else if (elemType == IntExample.class) 923 arrayToMH = new SubIntExample[length]; 924 else 925 return; // can't make an ArrayStoreException test 926 assert(arrayType.isInstance(arrayToMH)) 927 : Arrays.asList(arrayType, arrayToMH.getClass(), testSetter, negTest); 928 break; 929 } 930 countTest(positive); 931 if (verbosity > 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+length+"]"+(positive ? "" : " negative test #"+negTest+" using "+Arrays.deepToString(new Object[]{arrayToMH}))); 932 MethodType expType = !testSetter 933 ? MethodType.methodType(elemType, arrayType, int.class) 934 : MethodType.methodType(void.class, arrayType, int.class, elemType); 935 MethodHandle mh = !testSetter 936 ? MethodHandles.arrayElementGetter(arrayType) 937 : MethodHandles.arrayElementSetter(arrayType); 938 assertSame(mh.type(), expType); 939 if (elemType != int.class && elemType != boolean.class) { 940 MethodType gtype = mh.type().generic().changeParameterType(1, int.class); 941 if (testSetter) gtype = gtype.changeReturnType(void.class); 942 mh = mh.asType(gtype); 943 } 944 Object sawValue, expValue; 945 List<Object> model = array2list(array); 946 Throwable caughtEx = null; 947 for (int i = 0; i < length; i++) { 948 // update array element 949 Object random = randomArg(elemType); 950 model.set(i, random); 951 if (testSetter) { 952 try { 953 if (elemType == int.class) 954 mh.invokeExact((int[]) arrayToMH, i, (int)random); 955 else if (elemType == boolean.class) 956 mh.invokeExact((boolean[]) arrayToMH, i, (boolean)random); 957 else 958 mh.invokeExact(arrayToMH, i, random); 959 } catch (RuntimeException ex) { 960 caughtEx = ex; 961 break; 962 } 963 assertEquals(model, array2list(array)); 964 } else { 965 Array.set(array, i, random); 966 } 967 if (verbosity >= 5) { 968 List<Object> array2list = array2list(array); 969 System.out.println("a["+i+"]="+random+" => "+array2list); 970 if (!array2list.equals(model)) 971 System.out.println("*** != "+model); 972 } 973 // observe array element 974 sawValue = Array.get(array, i); 975 if (!testSetter) { 976 expValue = sawValue; 977 try { 978 if (elemType == int.class) 979 sawValue = (int) mh.invokeExact((int[]) arrayToMH, i); 980 else if (elemType == boolean.class) 981 sawValue = (boolean) mh.invokeExact((boolean[]) arrayToMH, i); 982 else 983 sawValue = mh.invokeExact(arrayToMH, i); 984 } catch (RuntimeException ex) { 985 caughtEx = ex; 986 break; 987 } 988 assertEquals(sawValue, expValue); 989 assertEquals(model, array2list(array)); 990 } 991 } 992 if (!positive) { 993 if (caughtEx == null) 994 throw new RuntimeException("failed to catch exception for negTest="+negTest); 995 // test the kind of exception 996 Class<?> reqType = null; 997 switch (negTest) { 998 case TEST_ARRAY_ASE: reqType = ArrayStoreException.class; break; 999 case TEST_ARRAY_OOB: reqType = ArrayIndexOutOfBoundsException.class; break; 1000 case TEST_ARRAY_NPE: reqType = NullPointerException.class; break; 1001 default: assert(false); 1002 } 1003 if (reqType.isInstance(caughtEx)) { 1004 caughtEx = null; // nullify expected exception 1005 } 1006 } 1007 if (caughtEx != null) { 1008 throw new RuntimeException("unexpected exception", caughtEx); 1009 } 1010 } 1011 array2list(Object array)1012 List<Object> array2list(Object array) { 1013 int length = Array.getLength(array); 1014 ArrayList<Object> model = new ArrayList<>(length); 1015 for (int i = 0; i < length; i++) 1016 model.add(Array.get(array, i)); 1017 return model; 1018 } 1019 1020 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1021 @Test testConvertArguments()1022 public void testConvertArguments() throws Throwable { 1023 if (CAN_SKIP_WORKING) return; 1024 startTest("convertArguments"); 1025 testConvert(Callee.ofType(1), null, "id", int.class); 1026 testConvert(Callee.ofType(1), null, "id", String.class); 1027 testConvert(Callee.ofType(1), null, "id", Integer.class); 1028 testConvert(Callee.ofType(1), null, "id", short.class); 1029 testConvert(Callee.ofType(1), null, "id", char.class); 1030 testConvert(Callee.ofType(1), null, "id", byte.class); 1031 } 1032 testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params)1033 void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable { 1034 testConvert(true, id, rtype, name, params); 1035 } 1036 testConvert(boolean positive, MethodHandle id, Class<?> rtype, String name, Class<?>... params)1037 void testConvert(boolean positive, 1038 MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable { 1039 countTest(positive); 1040 MethodType idType = id.type(); 1041 if (rtype == null) rtype = idType.returnType(); 1042 for (int i = 0; i < params.length; i++) { 1043 if (params[i] == null) params[i] = idType.parameterType(i); 1044 } 1045 // simulate the pairwise conversion 1046 MethodType newType = MethodType.methodType(rtype, params); 1047 Object[] args = randomArgs(newType.parameterArray()); 1048 Object[] convArgs = args.clone(); 1049 for (int i = 0; i < args.length; i++) { 1050 Class<?> src = newType.parameterType(i); 1051 Class<?> dst = idType.parameterType(i); 1052 if (src != dst) 1053 convArgs[i] = castToWrapper(convArgs[i], dst); 1054 } 1055 Object convResult = id.invokeWithArguments(convArgs); 1056 { 1057 Class<?> dst = newType.returnType(); 1058 Class<?> src = idType.returnType(); 1059 if (src != dst) 1060 convResult = castToWrapper(convResult, dst); 1061 } 1062 MethodHandle target = null; 1063 RuntimeException error = null; 1064 try { 1065 target = id.asType(newType); 1066 } catch (WrongMethodTypeException ex) { 1067 error = ex; 1068 } 1069 if (verbosity >= 3) 1070 System.out.println("convert "+id+ " to "+newType+" => "+target 1071 +(error == null ? "" : " !! "+error)); 1072 if (positive && error != null) throw error; 1073 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 1074 if (!positive) return; // negative test failed as expected 1075 assertEquals(newType, target.type()); 1076 printCalled(target, id.toString(), args); 1077 Object result = target.invokeWithArguments(args); 1078 assertCalled(name, convArgs); 1079 assertEquals(convResult, result); 1080 if (verbosity >= 1) 1081 System.out.print(':'); 1082 } 1083 1084 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1085 @Test testVarargsCollector()1086 public void testVarargsCollector() throws Throwable { 1087 if (CAN_SKIP_WORKING) return; 1088 startTest("varargsCollector"); 1089 MethodHandle vac0 = PRIVATE.findStatic(MethodHandlesTest.class, "called", 1090 MethodType.methodType(Object.class, String.class, Object[].class)); 1091 vac0 = vac0.bindTo("vac"); 1092 MethodHandle vac = vac0.asVarargsCollector(Object[].class); 1093 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); 1094 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); 1095 for (Class<?> at : new Class<?>[] { Object.class, String.class, Integer.class }) { 1096 testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at); 1097 testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at); 1098 } 1099 } 1100 1101 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1102 @Test testFilterReturnValue()1103 public void testFilterReturnValue() throws Throwable { 1104 if (CAN_SKIP_WORKING) return; 1105 startTest("filterReturnValue"); 1106 Class<?> classOfVCList = varargsList(1).invokeWithArguments(0).getClass(); 1107 assertTrue(List.class.isAssignableFrom(classOfVCList)); 1108 for (int nargs = 0; nargs <= 3; nargs++) { 1109 for (Class<?> rtype : new Class<?>[] { Object.class, 1110 List.class, 1111 int.class, 1112 byte.class, 1113 long.class, 1114 CharSequence.class, 1115 String.class }) { 1116 testFilterReturnValue(nargs, rtype); 1117 } 1118 } 1119 } 1120 testFilterReturnValue(int nargs, Class<?> rtype)1121 void testFilterReturnValue(int nargs, Class<?> rtype) throws Throwable { 1122 countTest(); 1123 MethodHandle target = varargsList(nargs, rtype); 1124 MethodHandle filter; 1125 if (List.class.isAssignableFrom(rtype) || rtype.isAssignableFrom(List.class)) 1126 filter = varargsList(1); // add another layer of list-ness 1127 else 1128 filter = MethodHandles.identity(rtype); 1129 filter = filter.asType(MethodType.methodType(target.type().returnType(), rtype)); 1130 Object[] argsToPass = randomArgs(nargs, Object.class); 1131 if (verbosity >= 3) 1132 System.out.println("filter "+target+" to "+rtype.getSimpleName()+" with "+filter); 1133 MethodHandle target2 = MethodHandles.filterReturnValue(target, filter); 1134 if (verbosity >= 4) 1135 System.out.println("filtered target: "+target2); 1136 // Simulate expected effect of filter on return value: 1137 Object unfiltered = target.invokeWithArguments(argsToPass); 1138 Object expected = filter.invokeWithArguments(unfiltered); 1139 if (verbosity >= 4) 1140 System.out.println("unfiltered: "+unfiltered+" : "+unfiltered.getClass().getSimpleName()); 1141 if (verbosity >= 4) 1142 System.out.println("expected: "+expected+" : "+expected.getClass().getSimpleName()); 1143 Object result = target2.invokeWithArguments(argsToPass); 1144 if (verbosity >= 3) 1145 System.out.println("result: "+result+" : "+result.getClass().getSimpleName()); 1146 if (!expected.equals(result)) 1147 System.out.println("*** fail at n/rt = "+nargs+"/"+rtype.getSimpleName()+": "+ 1148 Arrays.asList(argsToPass)+" => "+result+" != "+expected); 1149 assertEquals(expected, result); 1150 } 1151 1152 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1153 @Test testFilterArguments()1154 public void testFilterArguments() throws Throwable { 1155 if (CAN_SKIP_WORKING) return; 1156 startTest("filterArguments"); 1157 for (int nargs = 1; nargs <= 6; nargs++) { 1158 for (int pos = 0; pos < nargs; pos++) { 1159 testFilterArguments(nargs, pos); 1160 } 1161 } 1162 } 1163 testFilterArguments(int nargs, int pos)1164 void testFilterArguments(int nargs, int pos) throws Throwable { 1165 countTest(); 1166 MethodHandle target = varargsList(nargs); 1167 MethodHandle filter = varargsList(1); 1168 filter = filter.asType(filter.type().generic()); 1169 Object[] argsToPass = randomArgs(nargs, Object.class); 1170 if (verbosity >= 3) 1171 System.out.println("filter "+target+" at "+pos+" with "+filter); 1172 MethodHandle target2 = MethodHandles.filterArguments(target, pos, filter); 1173 // Simulate expected effect of filter on arglist: 1174 Object[] filteredArgs = argsToPass.clone(); 1175 filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]); 1176 List<Object> expected = Arrays.asList(filteredArgs); 1177 Object result = target2.invokeWithArguments(argsToPass); 1178 if (verbosity >= 3) 1179 System.out.println("result: "+result); 1180 if (!expected.equals(result)) 1181 System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected); 1182 assertEquals(expected, result); 1183 } 1184 1185 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1186 @Test testCollectArguments()1187 public void testCollectArguments() throws Throwable { 1188 if (CAN_SKIP_WORKING) return; 1189 startTest("collectArguments"); 1190 testFoldOrCollectArguments(true, false); 1191 } 1192 1193 @Test testFoldArguments()1194 public void testFoldArguments() throws Throwable { 1195 // Android-changed: call test directly 1196 // CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments0); 1197 testFoldArguments0(); 1198 1199 // Android-changed: call test directly 1200 // CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments1); 1201 testFoldArguments1(); 1202 1203 } 1204 1205 // Android-changed: method does not need to be public. testFoldArguments0()1206 /*public*/ void testFoldArguments0() throws Throwable { 1207 if (CAN_SKIP_WORKING) return; 1208 startTest("foldArguments"); 1209 testFoldOrCollectArguments(false, false); 1210 } 1211 1212 // Android-changed: method does not need to be public. testFoldArguments1()1213 /*public*/ void testFoldArguments1() throws Throwable { 1214 if (CAN_SKIP_WORKING) return; 1215 startTest("foldArguments/pos"); 1216 testFoldOrCollectArguments(false, true); 1217 } 1218 testFoldOrCollectArguments(boolean isCollect, boolean withFoldPos)1219 void testFoldOrCollectArguments(boolean isCollect, boolean withFoldPos) throws Throwable { 1220 assert !(isCollect && withFoldPos); // exclude illegal argument combination 1221 for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) { 1222 for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) { 1223 int maxArity = 10; 1224 if (collectType != String.class) maxArity = 5; 1225 if (lastType != Object.class) maxArity = 4; 1226 for (int nargs = 0; nargs <= maxArity; nargs++) { 1227 ArrayList<Class<?>> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class)); 1228 int maxMix = 20; 1229 if (collectType != Object.class) maxMix = 0; 1230 Map<Object,Integer> argTypesSeen = new HashMap<>(); 1231 for (int mix = 0; mix <= maxMix; mix++) { 1232 if (!mixArgs(argTypes, mix, argTypesSeen)) continue; 1233 for (int collect = 0; collect <= nargs; collect++) { 1234 for (int pos = 0; pos <= nargs - collect; pos++) { 1235 testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect, withFoldPos); 1236 } 1237 } 1238 } 1239 } 1240 } 1241 } 1242 } 1243 mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen)1244 boolean mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen) { 1245 assert(mix >= 0); 1246 if (mix == 0) return true; // no change 1247 if ((mix >>> argTypes.size()) != 0) return false; 1248 for (int i = 0; i < argTypes.size(); i++) { 1249 if (i >= 31) break; 1250 boolean bit = (mix & (1 << i)) != 0; 1251 if (bit) { 1252 Class<?> type = argTypes.get(i); 1253 if (type == Object.class) 1254 type = String.class; 1255 else if (type == String.class) 1256 type = int.class; 1257 else 1258 type = Object.class; 1259 argTypes.set(i, type); 1260 } 1261 } 1262 Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix); 1263 if (prev != null) { 1264 if (verbosity >= 4) System.out.println("mix "+prev+" repeated "+mix+": "+argTypes); 1265 return false; 1266 } 1267 if (verbosity >= 3) System.out.println("mix "+mix+" = "+argTypes); 1268 return true; 1269 } 1270 testFoldOrCollectArguments(List<Class<?>> argTypes, int pos, int fold, Class<?> combineType, Class<?> lastType, boolean isCollect, boolean withFoldPos)1271 void testFoldOrCollectArguments(List<Class<?>> argTypes, // argument types minus the inserted combineType 1272 int pos, int fold, // position and length of the folded arguments 1273 Class<?> combineType, // type returned from the combiner 1274 Class<?> lastType, // type returned from the target 1275 boolean isCollect, 1276 boolean withFoldPos) throws Throwable { 1277 int nargs = argTypes.size(); 1278 if (pos != 0 && !isCollect && !withFoldPos) return; // test MethodHandles.foldArguments(MH,MH) only for pos=0 1279 countTest(); 1280 List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold); 1281 List<Class<?>> targetArgTypes = new ArrayList<>(argTypes); 1282 if (isCollect) // does target see arg[pos..pos+cc-1]? 1283 targetArgTypes.subList(pos, pos + fold).clear(); 1284 if (combineType != void.class) 1285 targetArgTypes.add(pos, combineType); 1286 MethodHandle target = varargsList(targetArgTypes, lastType); 1287 MethodHandle combine = varargsList(combineArgTypes, combineType); 1288 List<Object> argsToPass = Arrays.asList(randomArgs(argTypes)); 1289 if (verbosity >= 3) 1290 System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine); 1291 MethodHandle target2; 1292 if (isCollect) 1293 target2 = MethodHandles.collectArguments(target, pos, combine); 1294 else 1295 target2 = withFoldPos ? MethodHandles.foldArguments(target, pos, combine) : MethodHandles.foldArguments(target, combine); 1296 // Simulate expected effect of combiner on arglist: 1297 List<Object> expectedList = new ArrayList<>(argsToPass); 1298 List<Object> argsToFold = expectedList.subList(pos, pos + fold); 1299 if (verbosity >= 3) 1300 System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2); 1301 Object foldedArgs = combine.invokeWithArguments(argsToFold); 1302 if (isCollect) 1303 argsToFold.clear(); 1304 if (combineType != void.class) 1305 argsToFold.add(0, foldedArgs); 1306 Object result = target2.invokeWithArguments(argsToPass); 1307 if (verbosity >= 3) 1308 System.out.println("result: "+result); 1309 Object expected = target.invokeWithArguments(expectedList); 1310 if (!expected.equals(result)) 1311 System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected); 1312 assertEquals(expected, result); 1313 } 1314 1315 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1316 @Test testDropArguments()1317 public void testDropArguments() throws Throwable { 1318 if (CAN_SKIP_WORKING) return; 1319 startTest("dropArguments"); 1320 for (int nargs = 0; nargs <= 4; nargs++) { 1321 for (int drop = 1; drop <= 4; drop++) { 1322 for (int pos = 0; pos <= nargs; pos++) { 1323 testDropArguments(nargs, pos, drop); 1324 } 1325 } 1326 } 1327 } 1328 testDropArguments(int nargs, int pos, int drop)1329 void testDropArguments(int nargs, int pos, int drop) throws Throwable { 1330 countTest(); 1331 MethodHandle target = varargsArray(nargs); 1332 Object[] args = randomArgs(target.type().parameterArray()); 1333 MethodHandle target2 = MethodHandles.dropArguments(target, pos, 1334 Collections.nCopies(drop, Object.class).toArray(new Class<?>[0])); 1335 List<Object> resList = Arrays.asList(args); 1336 List<Object> argsToDrop = new ArrayList<>(resList); 1337 for (int i = drop; i > 0; i--) { 1338 argsToDrop.add(pos, "blort#"+i); 1339 } 1340 Object res2 = target2.invokeWithArguments(argsToDrop); 1341 Object res2List = Arrays.asList((Object[])res2); 1342 //if (!resList.equals(res2List)) 1343 // System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List); 1344 assertEquals(resList, res2List); 1345 } 1346 1347 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1348 @Test testGuardWithTest()1349 public void testGuardWithTest() throws Throwable { 1350 if (CAN_SKIP_WORKING) return; 1351 startTest("guardWithTest"); 1352 for (int nargs = 0; nargs <= 50; nargs++) { 1353 if (CAN_TEST_LIGHTLY && nargs > 7) break; 1354 testGuardWithTest(nargs, Object.class); 1355 testGuardWithTest(nargs, String.class); 1356 } 1357 } 1358 testGuardWithTest(int nargs, Class<?> argClass)1359 void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable { 1360 testGuardWithTest(nargs, 0, argClass); 1361 if (nargs <= 5 || nargs % 10 == 3) { 1362 for (int testDrops = 1; testDrops <= nargs; testDrops++) 1363 testGuardWithTest(nargs, testDrops, argClass); 1364 } 1365 } 1366 testGuardWithTest(int nargs, int testDrops, Class<?> argClass)1367 void testGuardWithTest(int nargs, int testDrops, Class<?> argClass) throws Throwable { 1368 countTest(); 1369 int nargs1 = Math.min(3, nargs); 1370 MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class)); 1371 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs1)); 1372 MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs1)); 1373 while (test.type().parameterCount() > nargs) 1374 // 0: test = constant(MISSING_ARG.equals(MISSING_ARG)) 1375 // 1: test = lambda (_) MISSING_ARG.equals(_) 1376 test = MethodHandles.insertArguments(test, 0, MISSING_ARG); 1377 if (argClass != Object.class) { 1378 test = changeArgTypes(test, argClass); 1379 target = changeArgTypes(target, argClass); 1380 fallback = changeArgTypes(fallback, argClass); 1381 } 1382 int testArgs = nargs - testDrops; 1383 assert(testArgs >= 0); 1384 test = addTrailingArgs(test, Math.min(testArgs, nargs), argClass); 1385 target = addTrailingArgs(target, nargs, argClass); 1386 fallback = addTrailingArgs(fallback, nargs, argClass); 1387 Object[][] argLists = { 1388 { }, 1389 { "foo" }, { MethodHandlesTest.MISSING_ARG }, 1390 { "foo", "foo" }, { "foo", "bar" }, 1391 { "foo", "foo", "baz" }, { "foo", "bar", "baz" } 1392 }; 1393 for (Object[] argList : argLists) { 1394 Object[] argList1 = argList; 1395 if (argList.length != nargs) { 1396 if (argList.length != nargs1) continue; 1397 argList1 = Arrays.copyOf(argList, nargs); 1398 Arrays.fill(argList1, nargs1, nargs, MethodHandlesTest.MISSING_ARG_2); 1399 } 1400 MethodHandle test1 = test; 1401 if (test1.type().parameterCount() > testArgs) { 1402 int pc = test1.type().parameterCount(); 1403 test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc)); 1404 } 1405 MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback); 1406 assertEquals(target.type(), mh.type()); 1407 boolean equals; 1408 switch (nargs) { 1409 case 0: equals = true; break; 1410 case 1: equals = MethodHandlesTest.MISSING_ARG.equals(argList[0]); break; 1411 default: equals = argList[0].equals(argList[1]); break; 1412 } 1413 String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals"); 1414 if (verbosity >= 3) 1415 System.out.println(logEntry(willCall, argList)); 1416 Object result = mh.invokeWithArguments(argList1); 1417 assertCalled(willCall, argList); 1418 } 1419 } 1420 1421 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1422 @Test testGenericLoopCombinator()1423 public void testGenericLoopCombinator() throws Throwable { 1424 if (CAN_SKIP_WORKING) return; 1425 startTest("loop"); 1426 // Test as follows: 1427 // * Have an increasing number of loop-local state. Local state type diversity grows with the number. 1428 // * Initializers set the starting value of loop-local state from the corresponding loop argument. 1429 // * For each local state element, there is a predicate - for all state combinations, exercise all predicates. 1430 // * Steps modify each local state element in each iteration. 1431 // * Finalizers group all local state elements into a resulting array. Verify end values. 1432 // * Exercise both pre- and post-checked loops. 1433 // Local state types, start values, predicates, and steps: 1434 // * int a, 0, a < 7, a = a + 1 1435 // * double b, 7.0, b > 0.5, b = b / 2.0 1436 // * String c, "start", c.length <= 9, c = c + a 1437 final Class<?>[] argTypes = new Class<?>[] {int.class, double.class, String.class}; 1438 final Object[][] args = new Object[][] { 1439 new Object[]{0 }, 1440 new Object[]{0, 7.0 }, 1441 new Object[]{0, 7.0, "start"} 1442 }; 1443 // These are the expected final state tuples for argument type tuple / predicate combinations, for pre- and 1444 // post-checked loops: 1445 final Object[][] preCheckedResults = new Object[][] { 1446 new Object[]{7 }, // (int) / int 1447 new Object[]{7, 0.0546875 }, // (int,double) / int 1448 new Object[]{5, 0.4375 }, // (int,double) / double 1449 new Object[]{7, 0.0546875, "start1234567"}, // (int,double,String) / int 1450 new Object[]{5, 0.4375, "start1234" }, // (int,double,String) / double 1451 new Object[]{6, 0.109375, "start12345" } // (int,double,String) / String 1452 }; 1453 final Object[][] postCheckedResults = new Object[][] { 1454 new Object[]{7 }, // (int) / int 1455 new Object[]{7, 0.109375 }, // (int,double) / int 1456 new Object[]{4, 0.4375 }, // (int,double) / double 1457 new Object[]{7, 0.109375, "start123456"}, // (int,double,String) / int 1458 new Object[]{4, 0.4375, "start123" }, // (int,double,String) / double 1459 new Object[]{5, 0.21875, "start12345" } // (int,double,String) / String 1460 }; 1461 final Lookup l = MethodHandles.lookup(); 1462 final Class<?> MHT = MethodHandlesTest.class; 1463 final Class<?> B = boolean.class; 1464 final Class<?> I = int.class; 1465 final Class<?> D = double.class; 1466 final Class<?> S = String.class; 1467 final MethodHandle hip = l.findStatic(MHT, "loopIntPred", methodType(B, I)); 1468 final MethodHandle hdp = l.findStatic(MHT, "loopDoublePred", methodType(B, I, D)); 1469 final MethodHandle hsp = l.findStatic(MHT, "loopStringPred", methodType(B, I, D, S)); 1470 final MethodHandle his = l.findStatic(MHT, "loopIntStep", methodType(I, I)); 1471 final MethodHandle hds = l.findStatic(MHT, "loopDoubleStep", methodType(D, I, D)); 1472 final MethodHandle hss = l.findStatic(MHT, "loopStringStep", methodType(S, I, D, S)); 1473 final MethodHandle[] preds = new MethodHandle[] {hip, hdp, hsp}; 1474 final MethodHandle[] steps = new MethodHandle[] {his, hds, hss}; 1475 for (int nargs = 1, useResultsStart = 0; nargs <= argTypes.length; useResultsStart += nargs++) { 1476 Class<?>[] useArgTypes = Arrays.copyOf(argTypes, nargs, Class[].class); 1477 MethodHandle[] usePreds = Arrays.copyOf(preds, nargs, MethodHandle[].class); 1478 MethodHandle[] useSteps = Arrays.copyOf(steps, nargs, MethodHandle[].class); 1479 Object[] useArgs = args[nargs - 1]; 1480 Object[][] usePreCheckedResults = new Object[nargs][]; 1481 Object[][] usePostCheckedResults = new Object[nargs][]; 1482 System.arraycopy(preCheckedResults, useResultsStart, usePreCheckedResults, 0, nargs); 1483 System.arraycopy(postCheckedResults, useResultsStart, usePostCheckedResults, 0, nargs); 1484 testGenericLoopCombinator(nargs, useArgTypes, usePreds, useSteps, useArgs, usePreCheckedResults, 1485 usePostCheckedResults); 1486 } 1487 } 1488 testGenericLoopCombinator(int nargs, Class<?>[] argTypes, MethodHandle[] preds, MethodHandle[] steps, Object[] args, Object[][] preCheckedResults, Object[][] postCheckedResults)1489 void testGenericLoopCombinator(int nargs, Class<?>[] argTypes, MethodHandle[] preds, MethodHandle[] steps, 1490 Object[] args, Object[][] preCheckedResults, Object[][] postCheckedResults) 1491 throws Throwable { 1492 List<Class<?>> lArgTypes = Arrays.asList(argTypes); 1493 // Predicate and step handles are passed in as arguments, initializer and finalizer handles are constructed here 1494 // from the available information. 1495 MethodHandle[] inits = new MethodHandle[nargs]; 1496 for (int i = 0; i < nargs; ++i) { 1497 MethodHandle h; 1498 // Initializers are meant to return whatever they are passed at a given argument position. This means that 1499 // additional arguments may have to be appended and prepended. 1500 h = MethodHandles.identity(argTypes[i]); 1501 if (i < nargs - 1) { 1502 h = MethodHandles.dropArguments(h, 1, lArgTypes.subList(i + 1, nargs)); 1503 } 1504 if (i > 0) { 1505 h = MethodHandles.dropArguments(h, 0, lArgTypes.subList(0, i)); 1506 } 1507 inits[i] = h; 1508 } 1509 // Finalizers are all meant to collect all of the loop-local state in a single array and return that. Local 1510 // state is passed before the loop args. Construct such a finalizer by first taking a varargsArray collector for 1511 // the number of local state arguments, and then appending the loop args as to-be-dropped arguments. 1512 MethodHandle[] finis = new MethodHandle[nargs]; 1513 MethodHandle genericFini = MethodHandles.dropArguments( 1514 varargsArray(nargs).asType(methodType(Object[].class, lArgTypes)), nargs, lArgTypes); 1515 Arrays.fill(finis, genericFini); 1516 // The predicate and step handles' signatures need to be extended. They currently just accept local state args; 1517 // append possibly missing local state args and loop args using dropArguments. 1518 for (int i = 0; i < nargs; ++i) { 1519 List<Class<?>> additionalLocalStateArgTypes = lArgTypes.subList(i + 1, nargs); 1520 preds[i] = MethodHandles.dropArguments( 1521 MethodHandles.dropArguments(preds[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes); 1522 steps[i] = MethodHandles.dropArguments( 1523 MethodHandles.dropArguments(steps[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes); 1524 } 1525 // Iterate over all of the predicates, using only one of them at a time. 1526 for (int i = 0; i < nargs; ++i) { 1527 MethodHandle[] usePreds; 1528 if (nargs == 1) { 1529 usePreds = preds; 1530 } else { 1531 // Create an all-null preds array, and only use one predicate in this iteration. The null entries will 1532 // be substituted with true predicates by the loop combinator. 1533 usePreds = new MethodHandle[nargs]; 1534 usePreds[i] = preds[i]; 1535 } 1536 // Go for it. 1537 if (verbosity >= 3) { 1538 System.out.println("calling loop for argument types " + lArgTypes + " with predicate at index " + i); 1539 if (verbosity >= 5) { 1540 System.out.println("predicates: " + Arrays.asList(usePreds)); 1541 } 1542 } 1543 MethodHandle[] preInits = new MethodHandle[nargs + 1]; 1544 MethodHandle[] prePreds = new MethodHandle[nargs + 1]; 1545 MethodHandle[] preSteps = new MethodHandle[nargs + 1]; 1546 MethodHandle[] preFinis = new MethodHandle[nargs + 1]; 1547 System.arraycopy(inits, 0, preInits, 1, nargs); 1548 System.arraycopy(usePreds, 0, prePreds, 0, nargs); // preds are offset by 1 for pre-checked loops 1549 System.arraycopy(steps, 0, preSteps, 1, nargs); 1550 System.arraycopy(finis, 0, preFinis, 0, nargs); // finis are also offset by 1 for pre-checked loops 1551 // Convert to clause-major form. 1552 MethodHandle[][] preClauses = new MethodHandle[nargs + 1][4]; 1553 MethodHandle[][] postClauses = new MethodHandle[nargs][4]; 1554 toClauseMajor(preClauses, preInits, preSteps, prePreds, preFinis); 1555 toClauseMajor(postClauses, inits, steps, usePreds, finis); 1556 MethodHandle pre = MethodHandles.loop(preClauses); 1557 MethodHandle post = MethodHandles.loop(postClauses); 1558 if (verbosity >= 6) { 1559 System.out.println("pre-handle: " + pre); 1560 } 1561 Object[] preResults = (Object[]) pre.invokeWithArguments(args); 1562 if (verbosity >= 4) { 1563 System.out.println("pre-checked: expected " + Arrays.asList(preCheckedResults[i]) + ", actual " + 1564 Arrays.asList(preResults)); 1565 } 1566 if (verbosity >= 6) { 1567 System.out.println("post-handle: " + post); 1568 } 1569 Object[] postResults = (Object[]) post.invokeWithArguments(args); 1570 if (verbosity >= 4) { 1571 System.out.println("post-checked: expected " + Arrays.asList(postCheckedResults[i]) + ", actual " + 1572 Arrays.asList(postResults)); 1573 } 1574 assertArrayEquals(preCheckedResults[i], preResults); 1575 assertArrayEquals(postCheckedResults[i], postResults); 1576 } 1577 } 1578 toClauseMajor(MethodHandle[][] clauses, MethodHandle[] init, MethodHandle[] step, MethodHandle[] pred, MethodHandle[] fini)1579 static void toClauseMajor(MethodHandle[][] clauses, MethodHandle[] init, MethodHandle[] step, MethodHandle[] pred, MethodHandle[] fini) { 1580 for (int i = 0; i < clauses.length; ++i) { 1581 clauses[i][0] = init[i]; 1582 clauses[i][1] = step[i]; 1583 clauses[i][2] = pred[i]; 1584 clauses[i][3] = fini[i]; 1585 } 1586 } 1587 1588 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1589 @Test testThrowException()1590 public void testThrowException() throws Throwable { 1591 if (CAN_SKIP_WORKING) return; 1592 startTest("throwException"); 1593 testThrowException(int.class, new ClassCastException("testing")); 1594 testThrowException(void.class, new java.io.IOException("testing")); 1595 testThrowException(String.class, new LinkageError("testing")); 1596 } 1597 testThrowException(Class<?> returnType, Throwable thrown)1598 void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable { 1599 countTest(); 1600 Class<? extends Throwable> exType = thrown.getClass(); 1601 MethodHandle target = MethodHandles.throwException(returnType, exType); 1602 //System.out.println("throwing with "+target+" : "+thrown); 1603 MethodType expectedType = MethodType.methodType(returnType, exType); 1604 assertEquals(expectedType, target.type()); 1605 target = target.asType(target.type().generic()); 1606 Throwable caught = null; 1607 try { 1608 Object res = target.invokeExact((Object) thrown); 1609 fail("got "+res+" instead of throwing "+thrown); 1610 } catch (Throwable ex) { 1611 if (ex != thrown) { 1612 if (ex instanceof Error) throw (Error)ex; 1613 if (ex instanceof RuntimeException) throw (RuntimeException)ex; 1614 } 1615 caught = ex; 1616 } 1617 assertSame(thrown, caught); 1618 } 1619 1620 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1621 // Android-changed: test temporarily skipped due to b/236823506 1622 @Ignore testTryFinally()1623 public void testTryFinally() throws Throwable { 1624 if (CAN_SKIP_WORKING) return; 1625 startTest("tryFinally"); 1626 String inputMessage = "returned"; 1627 String augmentedMessage = "augmented"; 1628 String thrownMessage = "thrown"; 1629 String rethrownMessage = "rethrown"; 1630 // Test these cases: 1631 // * target returns, cleanup passes through 1632 // * target returns, cleanup augments 1633 // * target throws, cleanup augments and returns 1634 // * target throws, cleanup augments and rethrows 1635 MethodHandle target = MethodHandles.identity(String.class); 1636 MethodHandle targetThrow = MethodHandles.dropArguments( 1637 MethodHandles.throwException(String.class, Exception.class).bindTo(new Exception(thrownMessage)), 0, String.class); 1638 MethodHandle cleanupPassThrough = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, 1639 Throwable.class, String.class); 1640 MethodHandle cleanupAugment = MethodHandles.dropArguments(MethodHandles.constant(String.class, augmentedMessage), 1641 0, Throwable.class, String.class, String.class); 1642 MethodHandle cleanupCatch = MethodHandles.dropArguments(MethodHandles.constant(String.class, thrownMessage), 0, 1643 Throwable.class, String.class, String.class); 1644 MethodHandle cleanupThrow = MethodHandles.dropArguments(MethodHandles.throwException(String.class, Exception.class). 1645 bindTo(new Exception(rethrownMessage)), 0, Throwable.class, String.class, String.class); 1646 testTryFinally(target, cleanupPassThrough, inputMessage, inputMessage, false); 1647 testTryFinally(target, cleanupAugment, inputMessage, augmentedMessage, false); 1648 testTryFinally(targetThrow, cleanupCatch, inputMessage, thrownMessage, true); 1649 testTryFinally(targetThrow, cleanupThrow, inputMessage, rethrownMessage, true); 1650 // Test the same cases as above for void targets and cleanups. 1651 MethodHandles.Lookup lookup = MethodHandles.lookup(); 1652 Class<?> C = this.getClass(); 1653 MethodType targetType = methodType(void.class, String[].class); 1654 MethodType cleanupType = methodType(void.class, Throwable.class, String[].class); 1655 MethodHandle vtarget = lookup.findStatic(C, "vtarget", targetType); 1656 MethodHandle vtargetThrow = lookup.findStatic(C, "vtargetThrow", targetType); 1657 MethodHandle vcleanupPassThrough = lookup.findStatic(C, "vcleanupPassThrough", cleanupType); 1658 MethodHandle vcleanupAugment = lookup.findStatic(C, "vcleanupAugment", cleanupType); 1659 MethodHandle vcleanupCatch = lookup.findStatic(C, "vcleanupCatch", cleanupType); 1660 MethodHandle vcleanupThrow = lookup.findStatic(C, "vcleanupThrow", cleanupType); 1661 testTryFinally(vtarget, vcleanupPassThrough, inputMessage, inputMessage, false); 1662 testTryFinally(vtarget, vcleanupAugment, inputMessage, augmentedMessage, false); 1663 testTryFinally(vtargetThrow, vcleanupCatch, inputMessage, thrownMessage, true); 1664 testTryFinally(vtargetThrow, vcleanupThrow, inputMessage, rethrownMessage, true); 1665 } 1666 testTryFinally(MethodHandle target, MethodHandle cleanup, String input, String msg, boolean mustCatch)1667 void testTryFinally(MethodHandle target, MethodHandle cleanup, String input, String msg, boolean mustCatch) 1668 throws Throwable { 1669 countTest(); 1670 MethodHandle tf = MethodHandles.tryFinally(target, cleanup); 1671 String result = null; 1672 boolean isVoid = target.type().returnType() == void.class; 1673 String[] argArray = new String[]{input}; 1674 try { 1675 if (isVoid) { 1676 tf.invoke(argArray); 1677 } else { 1678 result = (String) tf.invoke(input); 1679 } 1680 } catch (Throwable t) { 1681 assertTrue(mustCatch); 1682 assertEquals(msg, t.getMessage()); 1683 return; 1684 } 1685 assertFalse(mustCatch); 1686 if (isVoid) { 1687 assertEquals(msg, argArray[0]); 1688 } else { 1689 assertEquals(msg, result); 1690 } 1691 } 1692 1693 // BEGIN Android-removed: MethodHandleProxies are not supported. 1694 /* 1695 @Test 1696 public void testAsInterfaceInstance() throws Throwable { 1697 // Android-changed: call test directly 1698 // CodeCacheOverflowProcessor.runMHTest(this::testAsInterfaceInstance0); 1699 testAsInterfaceInstance0(); 1700 1701 } 1702 1703 public void testAsInterfaceInstance0() throws Throwable { 1704 if (CAN_SKIP_WORKING) return; 1705 startTest("asInterfaceInstance"); 1706 Lookup lookup = MethodHandles.lookup(); 1707 // test typical case: Runnable.run 1708 { 1709 countTest(); 1710 if (verbosity >= 2) System.out.println("Runnable"); 1711 MethodType mt = MethodType.methodType(void.class); 1712 MethodHandle mh = lookup.findStatic(MethodHandlesGeneralTest.class, "runForRunnable", mt); 1713 Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh); 1714 proxy.run(); 1715 assertCalled("runForRunnable"); 1716 } 1717 // well known single-name overloaded interface: Appendable.append 1718 { 1719 countTest(); 1720 if (verbosity >= 2) System.out.println("Appendable"); 1721 ArrayList<List<?>> appendResults = new ArrayList<>(); 1722 MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class)); 1723 append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type 1724 MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class)); 1725 MethodHandle mh = MethodHandles.filterReturnValue(asList, append).asVarargsCollector(Object[].class); 1726 Appendable proxy = MethodHandleProxies.asInterfaceInstance(Appendable.class, mh); 1727 proxy.append("one"); 1728 proxy.append("two", 3, 4); 1729 proxy.append('5'); 1730 assertEquals(Arrays.asList(Arrays.asList("one"), 1731 Arrays.asList("two", 3, 4), 1732 Arrays.asList('5')), 1733 appendResults); 1734 if (verbosity >= 3) System.out.println("appendResults="+appendResults); 1735 appendResults.clear(); 1736 Formatter formatter = new Formatter(proxy); 1737 String fmt = "foo str=%s char='%c' num=%d"; 1738 Object[] fmtArgs = { "str!", 'C', 42 }; 1739 String expect = String.format(fmt, fmtArgs); 1740 formatter.format(fmt, fmtArgs); 1741 String actual = ""; 1742 if (verbosity >= 3) System.out.println("appendResults="+appendResults); 1743 for (List<?> l : appendResults) { 1744 Object x = l.get(0); 1745 switch (l.size()) { 1746 case 1: actual += x; continue; 1747 case 3: actual += ((String)x).substring((int)(Object)l.get(1), (int)(Object)l.get(2)); continue; 1748 } 1749 actual += l; 1750 } 1751 if (verbosity >= 3) System.out.println("expect="+expect); 1752 if (verbosity >= 3) System.out.println("actual="+actual); 1753 assertEquals(expect, actual); 1754 } 1755 // test case of an single name which is overloaded: Fooable.foo(...) 1756 { 1757 if (verbosity >= 2) System.out.println("Fooable"); 1758 MethodHandle mh = lookup.findStatic(MethodHandlesGeneralTest.class, "fooForFooable", 1759 MethodType.methodType(Object.class, String.class, Object[].class)); 1760 Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh); 1761 for (Method m : Fooable.class.getDeclaredMethods()) { 1762 countTest(); 1763 assertSame("foo", m.getName()); 1764 if (verbosity > 3) 1765 System.out.println("calling "+m); 1766 MethodHandle invoker = lookup.unreflect(m); 1767 MethodType mt = invoker.type(); 1768 Class<?>[] types = mt.parameterArray(); 1769 types[0] = int.class; // placeholder 1770 Object[] args = randomArgs(types); 1771 args[0] = proxy; 1772 if (verbosity > 3) 1773 System.out.println("calling "+m+" on "+Arrays.asList(args)); 1774 Object result = invoker.invokeWithArguments(args); 1775 if (verbosity > 4) 1776 System.out.println("result = "+result); 1777 String name = "fooForFooable/"+args[1]; 1778 Object[] argTail = Arrays.copyOfRange(args, 2, args.length); 1779 assertCalled(name, argTail); 1780 assertEquals(result, logEntry(name, argTail)); 1781 } 1782 } 1783 // test processing of thrown exceptions: 1784 for (Throwable ex : new Throwable[] { new NullPointerException("ok"), 1785 new InternalError("ok"), 1786 new Throwable("fail"), 1787 new Exception("fail"), 1788 new MyCheckedException() 1789 }) { 1790 MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class); 1791 mh = MethodHandles.insertArguments(mh, 0, ex); 1792 WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh); 1793 try { 1794 countTest(); 1795 proxy.willThrow(); 1796 System.out.println("Failed to throw: "+ex); 1797 assertTrue(false); 1798 } catch (Throwable ex1) { 1799 if (verbosity > 3) { 1800 System.out.println("throw "+ex); 1801 System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1)); 1802 } 1803 if (ex instanceof RuntimeException || 1804 ex instanceof Error) { 1805 assertSame("must pass unchecked exception out without wrapping", ex, ex1); 1806 } else if (ex instanceof MyCheckedException) { 1807 assertSame("must pass declared exception out without wrapping", ex, ex1); 1808 } else { 1809 assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1); 1810 if (!(ex1 instanceof UndeclaredThrowableException) || ex1.getCause() != ex) { 1811 ex1.printStackTrace(System.out); 1812 } 1813 assertSame(ex, ex1.getCause()); 1814 UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1; 1815 } 1816 } 1817 } 1818 // Test error checking on bad interfaces: 1819 for (Class<?> nonSMI : new Class<?>[] { Object.class, 1820 String.class, 1821 CharSequence.class, 1822 java.io.Serializable.class, 1823 PrivateRunnable.class, 1824 Example.class }) { 1825 if (verbosity > 2) System.out.println(nonSMI.getName()); 1826 try { 1827 countTest(false); 1828 MethodHandleProxies.asInterfaceInstance(nonSMI, varargsArray(0)); 1829 assertTrue("Failed to throw on "+nonSMI.getName(), false); 1830 } catch (IllegalArgumentException ex) { 1831 if (verbosity > 2) System.out.println(nonSMI.getSimpleName()+": "+ex); 1832 // Object: java.lang.IllegalArgumentException: 1833 // not a public interface: java.lang.Object 1834 // String: java.lang.IllegalArgumentException: 1835 // not a public interface: java.lang.String 1836 // CharSequence: java.lang.IllegalArgumentException: 1837 // not a single-method interface: java.lang.CharSequence 1838 // Serializable: java.lang.IllegalArgumentException: 1839 // not a single-method interface: java.io.Serializable 1840 // PrivateRunnable: java.lang.IllegalArgumentException: 1841 // not a public interface: test.java.lang.invoke.MethodHandlesTest$PrivateRunnable 1842 // Example: java.lang.IllegalArgumentException: 1843 // not a public interface: test.java.lang.invoke.MethodHandlesTest$Example 1844 } 1845 } 1846 // Test error checking on interfaces with the wrong method type: 1847 for (Class<?> intfc : new Class<?>[] { Runnable.class, // arity 0 1848 Fooable.class // arity 1 & 2 1849 }) { 1850 int badArity = 1; // known to be incompatible 1851 if (verbosity > 2) System.out.println(intfc.getName()); 1852 try { 1853 countTest(false); 1854 MethodHandleProxies.asInterfaceInstance(intfc, varargsArray(badArity)); 1855 assertTrue("Failed to throw on "+intfc.getName(), false); 1856 } catch (WrongMethodTypeException ex) { 1857 if (verbosity > 2) System.out.println(intfc.getSimpleName()+": "+ex); 1858 // Runnable: java.lang.invoke.WrongMethodTypeException: 1859 // cannot convert MethodHandle(Object)Object[] to ()void 1860 // Fooable: java.lang.invoke.WrongMethodTypeException: 1861 // cannot convert MethodHandle(Object)Object[] to (Object,String)Object 1862 } 1863 } 1864 } 1865 */ 1866 // END Android-removed: MethodHandleProxies are not supported. 1867 1868 1869 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1870 @Test testInterfaceCast()1871 public void testInterfaceCast() throws Throwable { 1872 if (CAN_SKIP_WORKING) return; 1873 startTest("interfaceCast"); 1874 assert( (((Object)"foo") instanceof CharSequence)); 1875 assert(!(((Object)"foo") instanceof Iterable)); 1876 for (MethodHandle mh : new MethodHandle[]{ 1877 MethodHandles.identity(String.class), 1878 MethodHandles.identity(CharSequence.class), 1879 MethodHandles.identity(Iterable.class) 1880 }) { 1881 if (verbosity > 0) System.out.println("-- mh = "+mh); 1882 for (Class<?> ctype : new Class<?>[]{ 1883 Object.class, String.class, CharSequence.class, 1884 Number.class, Iterable.class 1885 }) { 1886 if (verbosity > 0) System.out.println("---- ctype = "+ctype.getName()); 1887 // doret docast 1888 testInterfaceCast(mh, ctype, false, false); 1889 testInterfaceCast(mh, ctype, true, false); 1890 testInterfaceCast(mh, ctype, false, true); 1891 testInterfaceCast(mh, ctype, true, true); 1892 } 1893 } 1894 } 1895 i2o(Class<?> c)1896 private static Class<?> i2o(Class<?> c) { 1897 return (c.isInterface() ? Object.class : c); 1898 } 1899 1900 // Android-changed: method does not need to be public. testInterfaceCast(MethodHandle mh, Class<?> ctype, boolean doret, boolean docast)1901 /*public*/ void testInterfaceCast(MethodHandle mh, Class<?> ctype, 1902 boolean doret, boolean docast) throws Throwable { 1903 MethodHandle mh0 = mh; 1904 if (verbosity > 1) 1905 System.out.println("mh="+mh+", ctype="+ctype.getName()+", doret="+doret+", docast="+docast); 1906 String normalRetVal = "normal return value"; 1907 MethodType mt = mh.type(); 1908 MethodType mt0 = mt; 1909 if (doret) mt = mt.changeReturnType(ctype); 1910 else mt = mt.changeParameterType(0, ctype); 1911 if (docast) mh = MethodHandles.explicitCastArguments(mh, mt); 1912 else mh = mh.asType(mt); 1913 assertEquals(mt, mh.type()); 1914 MethodType mt1 = mt; 1915 // this bit is needed to make the interface types disappear for invokeWithArguments: 1916 mh = MethodHandles.explicitCastArguments(mh, mt.generic()); 1917 Class<?>[] step = { 1918 mt1.parameterType(0), // param as passed to mh at first 1919 mt0.parameterType(0), // param after incoming cast 1920 mt0.returnType(), // return value before cast 1921 mt1.returnType(), // return value after outgoing cast 1922 }; 1923 // where might a checkCast occur? 1924 boolean[] checkCast = new boolean[step.length]; 1925 // the string value must pass each step without causing an exception 1926 if (!docast) { 1927 if (!doret) { 1928 if (step[0] != step[1]) 1929 checkCast[1] = true; // incoming value is cast 1930 } else { 1931 if (step[2] != step[3]) 1932 checkCast[3] = true; // outgoing value is cast 1933 } 1934 } 1935 boolean expectFail = false; 1936 for (int i = 0; i < step.length; i++) { 1937 Class<?> c = step[i]; 1938 if (!checkCast[i]) c = i2o(c); 1939 if (!c.isInstance(normalRetVal)) { 1940 if (verbosity > 3) 1941 System.out.println("expect failure at step "+i+" in "+Arrays.toString(step)+Arrays.toString(checkCast)); 1942 expectFail = true; 1943 break; 1944 } 1945 } 1946 countTest(!expectFail); 1947 if (verbosity > 2) 1948 System.out.println("expectFail="+expectFail+", mt="+mt); 1949 Object res; 1950 try { 1951 res = mh.invokeWithArguments(normalRetVal); 1952 } catch (Exception ex) { 1953 res = ex; 1954 } 1955 boolean sawFail = !(res instanceof String); 1956 if (sawFail != expectFail) { 1957 System.out.println("*** testInterfaceCast: mh0 = "+mh0); 1958 System.out.println(" retype using "+(docast ? "explicitCastArguments" : "asType")+" to "+mt+" => "+mh); 1959 System.out.println(" call returned "+res); 1960 System.out.println(" expected "+(expectFail ? "an exception" : normalRetVal)); 1961 } 1962 if (!expectFail) { 1963 assertFalse(res.toString(), sawFail); 1964 assertEquals(normalRetVal, res); 1965 } else { 1966 assertTrue(res.toString(), sawFail); 1967 } 1968 } 1969 userMethod(Object o, String s, int i)1970 static Example userMethod(Object o, String s, int i) { 1971 called("userMethod", o, s, i); 1972 return null; 1973 } 1974 1975 // Android-removed: remove CodeCacheOverflowProcessor wrapper (not supported). 1976 @Test testUserClassInSignature()1977 public void testUserClassInSignature() throws Throwable { 1978 if (CAN_SKIP_WORKING) return; 1979 startTest("testUserClassInSignature"); 1980 Lookup lookup = MethodHandles.lookup(); 1981 String name; MethodType mt; MethodHandle mh; 1982 Object[] args; 1983 1984 // Try a static method. 1985 name = "userMethod"; 1986 mt = MethodType.methodType(Example.class, Object.class, String.class, int.class); 1987 mh = lookup.findStatic(lookup.lookupClass(), name, mt); 1988 assertEquals(mt, mh.type()); 1989 assertEquals(Example.class, mh.type().returnType()); 1990 args = randomArgs(mh.type().parameterArray()); 1991 mh.invokeWithArguments(args); 1992 assertCalled(name, args); 1993 1994 // Try a virtual method. 1995 name = "v2"; 1996 mt = MethodType.methodType(Object.class, Object.class, int.class); 1997 mh = lookup.findVirtual(Example.class, name, mt); 1998 assertEquals(mt, mh.type().dropParameterTypes(0,1)); 1999 assertTrue(mh.type().parameterList().contains(Example.class)); 2000 args = randomArgs(mh.type().parameterArray()); 2001 mh.invokeWithArguments(args); 2002 assertCalled(name, args); 2003 } 2004 runForRunnable()2005 static void runForRunnable() { 2006 called("runForRunnable"); 2007 } 2008 2009 public interface Fooable { 2010 // overloads: foo(Object x, String y)2011 Object foo(Object x, String y); foo(String x, int y)2012 List<?> foo(String x, int y); foo(String x)2013 Object foo(String x); 2014 } 2015 fooForFooable(String x, Object... y)2016 static Object fooForFooable(String x, Object... y) { 2017 return called("fooForFooable/"+x, y); 2018 } 2019 2020 @SuppressWarnings("serial") // not really a public API, just a test case 2021 public static class MyCheckedException extends Exception { 2022 } 2023 2024 public interface WillThrow { willThrow()2025 void willThrow() throws MyCheckedException; 2026 } 2027 2028 /*non-public*/ interface PrivateRunnable { run()2029 public void run(); 2030 } 2031 2032 // BEGIN Android-removed: MethodHandleProxies are not supported. 2033 /* 2034 @Test 2035 public void testRunnableProxy() throws Throwable { 2036 // Android-changed: call test directly 2037 // CodeCacheOverflowProcessor.runMHTest(this::testRunnableProxy0); 2038 testRunnableProxy0(); 2039 2040 } 2041 2042 public void testRunnableProxy0() throws Throwable { 2043 if (CAN_SKIP_WORKING) return; 2044 startTest("testRunnableProxy"); 2045 MethodHandles.Lookup lookup = MethodHandles.lookup(); 2046 MethodHandle run = lookup.findStatic(lookup.lookupClass(), "runForRunnable", MethodType.methodType(void.class)); 2047 Runnable r = MethodHandleProxies.asInterfaceInstance(Runnable.class, run); 2048 testRunnableProxy(r); 2049 assertCalled("runForRunnable"); 2050 } 2051 2052 private static void testRunnableProxy(Runnable r) { 2053 //7058630: JSR 292 method handle proxy violates contract for Object methods 2054 r.run(); 2055 Object o = r; 2056 r = null; 2057 boolean eq = (o == o); 2058 int hc = System.identityHashCode(o); 2059 String st = o.getClass().getName() + "@" + Integer.toHexString(hc); 2060 Object expect = Arrays.asList(st, eq, hc); 2061 if (verbosity >= 2) System.out.println("expect st/eq/hc = "+expect); 2062 Object actual = Arrays.asList(o.toString(), o.equals(o), o.hashCode()); 2063 if (verbosity >= 2) System.out.println("actual st/eq/hc = "+actual); 2064 assertEquals(expect, actual); 2065 } 2066 */ 2067 // END Android-removed: MethodHandleProxies are not supported. 2068 } 2069