1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import annotations.BootstrapMethod; 18 import annotations.CalledByIndy; 19 import annotations.Constant; 20 import java.lang.invoke.CallSite; 21 import java.lang.invoke.ConstantCallSite; 22 import java.lang.invoke.MethodHandle; 23 import java.lang.invoke.MethodHandles; 24 import java.lang.invoke.MethodType; 25 import java.util.Arrays; 26 27 public class TestVariableArityLinkerMethod extends TestBase { printBsmArgs(String method, Object... args)28 private static void printBsmArgs(String method, Object... args) { 29 System.out.print(method); 30 System.out.print("("); 31 for (int i = 0; i < args.length; ++i) { 32 if (i != 0) { 33 System.out.print(", "); 34 } 35 if (args[i] != null && args[i].getClass().isArray()) { 36 Object array = args[i]; 37 if (array.getClass() == int[].class) { 38 System.out.print(Arrays.toString((int[]) array)); 39 } else if (array.getClass() == long[].class) { 40 System.out.print(Arrays.toString((long[]) array)); 41 } else if (array.getClass() == float[].class) { 42 System.out.print(Arrays.toString((float[]) array)); 43 } else if (array.getClass() == double[].class) { 44 System.out.print(Arrays.toString((double[]) array)); 45 } else { 46 System.out.print(Arrays.toString((Object[]) array)); 47 } 48 } else { 49 System.out.print(args[i]); 50 } 51 } 52 System.out.println(");"); 53 } 54 bsmWithStringArray( MethodHandles.Lookup lookup, String methodName, MethodType methodType, String... arityArgs)55 private static CallSite bsmWithStringArray( 56 MethodHandles.Lookup lookup, 57 String methodName, 58 MethodType methodType, 59 String... arityArgs) 60 throws Throwable { 61 printBsmArgs("bsmWithStringArray", lookup, methodName, methodType, arityArgs); 62 MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); 63 return new ConstantCallSite(mh); 64 } 65 66 @CalledByIndy( 67 bootstrapMethod = 68 @BootstrapMethod( 69 enclosingType = TestVariableArityLinkerMethod.class, 70 name = "bsmWithStringArray", 71 parameterTypes = { 72 MethodHandles.Lookup.class, 73 String.class, 74 MethodType.class, 75 String[].class 76 } 77 ), 78 fieldOrMethodName = "methodA", 79 constantArgumentsForBootstrapMethod = { 80 @Constant(stringValue = "Aachen"), 81 @Constant(stringValue = "Aalborg"), 82 @Constant(stringValue = "Aalto") 83 } 84 ) methodA()85 private static void methodA() { 86 System.out.println("methodA"); 87 } 88 89 @CalledByIndy( 90 bootstrapMethod = 91 @BootstrapMethod( 92 enclosingType = TestVariableArityLinkerMethod.class, 93 name = "bsmWithStringArray", 94 parameterTypes = { 95 MethodHandles.Lookup.class, 96 String.class, 97 MethodType.class, 98 String[].class 99 } 100 ), 101 fieldOrMethodName = "methodB", 102 constantArgumentsForBootstrapMethod = {@Constant(stringValue = "barium")} 103 ) methodB()104 private static void methodB() { 105 System.out.println("methodB"); 106 } 107 108 @CalledByIndy( 109 bootstrapMethod = 110 @BootstrapMethod( 111 enclosingType = TestVariableArityLinkerMethod.class, 112 name = "bsmWithStringArray", 113 parameterTypes = { 114 MethodHandles.Lookup.class, 115 String.class, 116 MethodType.class, 117 String[].class 118 } 119 ), 120 fieldOrMethodName = "methodC" 121 ) methodC()122 private static void methodC() { 123 System.out.println("methodC"); 124 } 125 bsmWithIntAndStringArray( MethodHandles.Lookup lookup, String methodName, MethodType methodType, int extraInt, String... extraArityArgs)126 private static CallSite bsmWithIntAndStringArray( 127 MethodHandles.Lookup lookup, 128 String methodName, 129 MethodType methodType, 130 int extraInt, 131 String... extraArityArgs) 132 throws Throwable { 133 printBsmArgs( 134 "bsmWithIntAndStringArray", 135 lookup, 136 methodName, 137 methodType, 138 extraInt, 139 extraArityArgs); 140 MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); 141 return new ConstantCallSite(mh); 142 } 143 144 @CalledByIndy( 145 bootstrapMethod = 146 @BootstrapMethod( 147 enclosingType = TestVariableArityLinkerMethod.class, 148 name = "bsmWithIntAndStringArray", 149 parameterTypes = { 150 MethodHandles.Lookup.class, 151 String.class, 152 MethodType.class, 153 int.class, 154 String[].class 155 } 156 ), 157 fieldOrMethodName = "methodD", 158 constantArgumentsForBootstrapMethod = { 159 @Constant(intValue = 101), 160 @Constant(stringValue = "zoo"), 161 @Constant(stringValue = "zoogene"), 162 @Constant(stringValue = "zoogenic") 163 } 164 ) methodD()165 private static void methodD() { 166 System.out.println("methodD"); 167 } 168 169 @CalledByIndy( 170 bootstrapMethod = 171 @BootstrapMethod( 172 enclosingType = TestVariableArityLinkerMethod.class, 173 name = "bsmWithIntAndStringArray", 174 parameterTypes = { 175 MethodHandles.Lookup.class, 176 String.class, 177 MethodType.class, 178 int.class, 179 String[].class 180 } 181 ), 182 fieldOrMethodName = "methodE", 183 constantArgumentsForBootstrapMethod = { 184 @Constant(intValue = 102), 185 @Constant(stringValue = "zonic") 186 } 187 ) methodE()188 private static void methodE() { 189 System.out.println("methodE"); 190 } 191 192 @CalledByIndy( 193 bootstrapMethod = 194 @BootstrapMethod( 195 enclosingType = TestVariableArityLinkerMethod.class, 196 name = "bsmWithIntAndStringArray", 197 parameterTypes = { 198 MethodHandles.Lookup.class, 199 String.class, 200 MethodType.class, 201 int.class, 202 String[].class 203 } 204 ), 205 fieldOrMethodName = "methodF", 206 constantArgumentsForBootstrapMethod = {@Constant(intValue = 103)} 207 ) methodF()208 private static void methodF() { 209 System.out.println("methodF"); 210 } 211 bsmWithLongAndIntArray( MethodHandles.Lookup lookup, String methodName, MethodType methodType, long extraArg, int... arityArgs)212 private static CallSite bsmWithLongAndIntArray( 213 MethodHandles.Lookup lookup, 214 String methodName, 215 MethodType methodType, 216 long extraArg, 217 int... arityArgs) 218 throws Throwable { 219 printBsmArgs("bsmWithLongAndIntArray", lookup, methodName, methodType, extraArg, arityArgs); 220 MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); 221 return new ConstantCallSite(mh); 222 } 223 224 @CalledByIndy( 225 bootstrapMethod = 226 @BootstrapMethod( 227 enclosingType = TestVariableArityLinkerMethod.class, 228 name = "bsmWithLongAndIntArray", 229 parameterTypes = { 230 MethodHandles.Lookup.class, 231 String.class, 232 MethodType.class, 233 long.class, 234 int[].class 235 } 236 ), 237 fieldOrMethodName = "methodG", 238 constantArgumentsForBootstrapMethod = { 239 @Constant(longValue = 0x123456789abcdefl), 240 @Constant(intValue = +1), 241 @Constant(intValue = -1), 242 @Constant(intValue = +2), 243 @Constant(intValue = -2) 244 } 245 ) methodG()246 private static void methodG() { 247 System.out.println("methodG"); 248 } 249 bsmWithFloatAndLongArray( MethodHandles.Lookup lookup, String methodName, MethodType methodType, float extraArg, long... arityArgs)250 private static CallSite bsmWithFloatAndLongArray( 251 MethodHandles.Lookup lookup, 252 String methodName, 253 MethodType methodType, 254 float extraArg, 255 long... arityArgs) 256 throws Throwable { 257 printBsmArgs( 258 "bsmWithFloatAndLongArray", lookup, methodName, methodType, extraArg, arityArgs); 259 MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); 260 return new ConstantCallSite(mh); 261 } 262 263 @CalledByIndy( 264 bootstrapMethod = 265 @BootstrapMethod( 266 enclosingType = TestVariableArityLinkerMethod.class, 267 name = "bsmWithFloatAndLongArray", 268 parameterTypes = { 269 MethodHandles.Lookup.class, 270 String.class, 271 MethodType.class, 272 float.class, 273 long[].class 274 } 275 ), 276 fieldOrMethodName = "methodH", 277 constantArgumentsForBootstrapMethod = { 278 @Constant(floatValue = (float) -Math.E), 279 @Constant(longValue = 999999999999l), 280 @Constant(longValue = -8888888888888l) 281 } 282 ) methodH()283 private static void methodH() { 284 System.out.println("methodH"); 285 } 286 bsmWithClassAndFloatArray( MethodHandles.Lookup lookup, String methodName, MethodType methodType, Class<?> extraArg, float... arityArgs)287 private static CallSite bsmWithClassAndFloatArray( 288 MethodHandles.Lookup lookup, 289 String methodName, 290 MethodType methodType, 291 Class<?> extraArg, 292 float... arityArgs) 293 throws Throwable { 294 printBsmArgs( 295 "bsmWithClassAndFloatArray", lookup, methodName, methodType, extraArg, arityArgs); 296 MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); 297 return new ConstantCallSite(mh); 298 } 299 300 @CalledByIndy( 301 bootstrapMethod = 302 @BootstrapMethod( 303 enclosingType = TestVariableArityLinkerMethod.class, 304 name = "bsmWithClassAndFloatArray", 305 parameterTypes = { 306 MethodHandles.Lookup.class, 307 String.class, 308 MethodType.class, 309 Class.class, 310 float[].class 311 } 312 ), 313 fieldOrMethodName = "methodI", 314 constantArgumentsForBootstrapMethod = { 315 @Constant(classValue = Throwable.class), 316 @Constant(floatValue = Float.MAX_VALUE), 317 @Constant(floatValue = Float.MIN_VALUE), 318 @Constant(floatValue = (float) Math.PI), 319 @Constant(floatValue = (float) -Math.PI) 320 } 321 ) methodI()322 private static void methodI() { 323 System.out.println("methodI"); 324 } 325 bsmWithDoubleArray( MethodHandles.Lookup lookup, String methodName, MethodType methodType, double... arityArgs)326 private static CallSite bsmWithDoubleArray( 327 MethodHandles.Lookup lookup, 328 String methodName, 329 MethodType methodType, 330 double... arityArgs) 331 throws Throwable { 332 printBsmArgs("bsmWithDoubleArray", lookup, methodName, methodType, arityArgs); 333 MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); 334 return new ConstantCallSite(mh); 335 } 336 337 @CalledByIndy( 338 bootstrapMethod = 339 @BootstrapMethod( 340 enclosingType = TestVariableArityLinkerMethod.class, 341 name = "bsmWithDoubleArray", 342 parameterTypes = { 343 MethodHandles.Lookup.class, 344 String.class, 345 MethodType.class, 346 double[].class 347 } 348 ), 349 fieldOrMethodName = "methodJ", 350 constantArgumentsForBootstrapMethod = { 351 @Constant(doubleValue = Double.MAX_VALUE), 352 @Constant(doubleValue = Double.MIN_VALUE), 353 @Constant(doubleValue = Math.E), 354 @Constant(doubleValue = -Math.PI) 355 } 356 ) methodJ()357 private static void methodJ() { 358 System.out.println("methodJ"); 359 } 360 bsmWithClassArray( MethodHandles.Lookup lookup, String methodName, MethodType methodType, Class... arityArgs)361 private static CallSite bsmWithClassArray( 362 MethodHandles.Lookup lookup, 363 String methodName, 364 MethodType methodType, 365 Class... arityArgs) 366 throws Throwable { 367 printBsmArgs("bsmWithClassArray", lookup, methodName, methodType, arityArgs); 368 MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); 369 return new ConstantCallSite(mh); 370 } 371 372 @CalledByIndy( 373 bootstrapMethod = 374 @BootstrapMethod( 375 enclosingType = TestVariableArityLinkerMethod.class, 376 name = "bsmWithClassArray", 377 parameterTypes = { 378 MethodHandles.Lookup.class, 379 String.class, 380 MethodType.class, 381 Class[].class 382 } 383 ), 384 fieldOrMethodName = "methodK", 385 constantArgumentsForBootstrapMethod = { 386 @Constant(classValue = Integer.class), 387 @Constant(classValue = MethodHandles.class), 388 @Constant(classValue = Arrays.class) 389 } 390 ) methodK()391 private static void methodK() { 392 System.out.println("methodK"); 393 } 394 395 @CalledByIndy( 396 bootstrapMethod = 397 @BootstrapMethod( 398 enclosingType = TestVariableArityLinkerMethod.class, 399 name = "bsmWithIntAndStringArray", 400 parameterTypes = { 401 MethodHandles.Lookup.class, 402 String.class, 403 MethodType.class, 404 int.class, 405 String[].class 406 } 407 ), 408 fieldOrMethodName = "methodO", 409 constantArgumentsForBootstrapMethod = {@Constant(intValue = 103), @Constant(intValue = 104)} 410 ) methodO()411 private static void methodO() { 412 // Arguments are not compatible 413 assertNotReached(); 414 } 415 416 @CalledByIndy( 417 bootstrapMethod = 418 @BootstrapMethod( 419 enclosingType = TestVariableArityLinkerMethod.class, 420 name = "bsmWithIntAndStringArray", 421 parameterTypes = { 422 MethodHandles.Lookup.class, 423 String.class, 424 MethodType.class, 425 int.class, 426 String[].class 427 } 428 ), 429 fieldOrMethodName = "methodP", 430 constantArgumentsForBootstrapMethod = { 431 @Constant(intValue = 103), 432 @Constant(stringValue = "A"), 433 @Constant(stringValue = "B"), 434 @Constant(intValue = 42) 435 } 436 ) methodP()437 private static void methodP() { 438 // Arguments are not compatible - specifically, the third 439 // component of potential collector array is an integer 440 // argument (42). 441 assertNotReached(); 442 } 443 bsmWithWiderArray( MethodHandles.Lookup lookup, String methodName, MethodType methodType, long[] extraArgs)444 private static CallSite bsmWithWiderArray( 445 MethodHandles.Lookup lookup, String methodName, MethodType methodType, long[] extraArgs) 446 throws Throwable { 447 printBsmArgs("bsmWithWiderArray", lookup, methodName, methodType, extraArgs); 448 MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); 449 return new ConstantCallSite(mh); 450 } 451 452 @CalledByIndy( 453 bootstrapMethod = 454 @BootstrapMethod( 455 enclosingType = TestVariableArityLinkerMethod.class, 456 name = "bsmWithWiderArray", 457 parameterTypes = { 458 MethodHandles.Lookup.class, 459 String.class, 460 MethodType.class, 461 long[].class 462 } 463 ), 464 fieldOrMethodName = "methodQ", 465 constantArgumentsForBootstrapMethod = {@Constant(intValue = 103), @Constant(intValue = 42)} 466 ) methodQ()467 private static void methodQ() { 468 assertNotReached(); 469 } 470 bsmWithBoxedArray( MethodHandles.Lookup lookup, String methodName, MethodType methodType, Integer[] extraArgs)471 private static CallSite bsmWithBoxedArray( 472 MethodHandles.Lookup lookup, 473 String methodName, 474 MethodType methodType, 475 Integer[] extraArgs) 476 throws Throwable { 477 printBsmArgs("bsmWithBoxedArray", lookup, methodName, methodType, extraArgs); 478 MethodHandle mh = lookup.findStatic(lookup.lookupClass(), methodName, methodType); 479 return new ConstantCallSite(mh); 480 } 481 482 @CalledByIndy( 483 bootstrapMethod = 484 @BootstrapMethod( 485 enclosingType = TestVariableArityLinkerMethod.class, 486 name = "bsmWithBoxedArray", 487 parameterTypes = { 488 MethodHandles.Lookup.class, 489 String.class, 490 MethodType.class, 491 Integer[].class 492 } 493 ), 494 fieldOrMethodName = "methodR", 495 constantArgumentsForBootstrapMethod = { 496 @Constant(intValue = 1030), 497 @Constant(intValue = 420) 498 } 499 ) methodR()500 private static void methodR() { 501 assertNotReached(); 502 } 503 test()504 static void test() { 505 // Happy cases 506 for (int i = 0; i < 2; ++i) { 507 methodA(); 508 methodB(); 509 methodC(); 510 } 511 for (int i = 0; i < 2; ++i) { 512 methodD(); 513 methodE(); 514 methodF(); 515 } 516 methodG(); 517 methodH(); 518 methodI(); 519 methodJ(); 520 methodK(); 521 522 // Broken cases 523 try { 524 // bsm has incompatible static methods. Collector 525 // component type is String, the corresponding static 526 // arguments are int values. 527 methodO(); 528 assertNotReached(); 529 } catch (BootstrapMethodError expected) { 530 System.out.print("methodO => "); 531 System.out.print(expected.getClass()); 532 System.out.print(" => "); 533 System.out.println(expected.getCause().getClass()); 534 } 535 try { 536 // bsm has a trailing String array for the collector array. 537 // There is an int value amongst the String values. 538 methodP(); 539 assertNotReached(); 540 } catch (BootstrapMethodError expected) { 541 System.out.print("methodP => "); 542 System.out.print(expected.getClass()); 543 System.out.print(" => "); 544 System.out.println(expected.getCause().getClass()); 545 } 546 try { 547 // bsm has as trailing long[] element for the collector array. 548 // The corresponding static bsm arguments are of type int. 549 methodQ(); 550 assertNotReached(); 551 } catch (BootstrapMethodError expected) { 552 System.out.print("methodQ => "); 553 System.out.print(expected.getClass()); 554 System.out.print(" => "); 555 System.out.println(expected.getCause().getClass()); 556 } 557 try { 558 // bsm has as trailing Integer[] element for the collector array. 559 // The corresponding static bsm arguments are of type int. 560 methodR(); 561 assertNotReached(); 562 } catch (BootstrapMethodError expected) { 563 System.out.print("methodR => "); 564 System.out.print(expected.getClass()); 565 System.out.print(" => "); 566 System.out.println(expected.getCause().getClass()); 567 } 568 } 569 } 570