1 /* 2 * Copyright (c) 2001, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.reflect; 27 28 import jdk.internal.misc.SharedSecrets; 29 30 import java.security.AccessController; 31 import java.security.PrivilegedAction; 32 import java.util.HashMap; 33 import java.util.HashSet; 34 import java.util.Map; 35 import java.util.Set; 36 37 /** Generator for sun.reflect.MethodAccessor and 38 sun.reflect.ConstructorAccessor objects using bytecodes to 39 implement reflection. A java.lang.reflect.Method or 40 java.lang.reflect.Constructor object can delegate its invoke or 41 newInstance method to an accessor using native code or to one 42 generated by this class. (Methods and Constructors were merged 43 together in this class to ensure maximum code sharing.) */ 44 45 class MethodAccessorGenerator extends AccessorGenerator { 46 47 private static final short NUM_BASE_CPOOL_ENTRIES = (short) 10; 48 // One for invoke() plus one for constructor 49 private static final short NUM_METHODS = (short) 2; 50 // Only used if forSerialization is true 51 private static final short NUM_SERIALIZATION_CPOOL_ENTRIES = (short) 2; 52 53 private static volatile int methodSymnum; 54 private static volatile int constructorSymnum; 55 private static volatile int serializationConstructorSymnum; 56 57 private Class<?> declaringClass; 58 private Class<?>[] parameterTypes; 59 private Class<?> returnType; 60 private boolean isConstructor; 61 private boolean forSerialization; 62 63 private short targetMethodRef; 64 private short invokeIdx; 65 private short invokeDescriptorIdx; 66 private short valueTypesAttrIdx; 67 private ConstantPoolClassPool cpClassPool; 68 69 MethodAccessorGenerator() { 70 } 71 72 /** This routine is not thread-safe */ 73 public MethodAccessor generateMethod(Class<?> declaringClass, 74 String name, 75 Class<?>[] parameterTypes, 76 Class<?> returnType, 77 Class<?>[] checkedExceptions, 78 int modifiers) 79 { 80 return (MethodAccessor) generate(declaringClass, 81 name, 82 parameterTypes, 83 returnType, 84 checkedExceptions, 85 modifiers, 86 false, 87 false, 88 null); 89 } 90 91 /** This routine is not thread-safe */ 92 public ConstructorAccessor generateConstructor(Class<?> declaringClass, 93 Class<?>[] parameterTypes, 94 Class<?>[] checkedExceptions, 95 int modifiers) 96 { 97 return (ConstructorAccessor) generate(declaringClass, 98 "<init>", 99 parameterTypes, 100 Void.TYPE, 101 checkedExceptions, 102 modifiers, 103 true, 104 false, 105 null); 106 } 107 108 /** This routine is not thread-safe */ 109 public SerializationConstructorAccessorImpl 110 generateSerializationConstructor(Class<?> declaringClass, 111 Class<?>[] parameterTypes, 112 Class<?>[] checkedExceptions, 113 int modifiers, 114 Class<?> targetConstructorClass) 115 { 116 return (SerializationConstructorAccessorImpl) 117 generate(declaringClass, 118 "<init>", 119 parameterTypes, 120 Void.TYPE, 121 checkedExceptions, 122 modifiers, 123 true, 124 true, 125 targetConstructorClass); 126 } 127 128 /** This routine is not thread-safe */ 129 private MagicAccessorImpl generate(final Class<?> declaringClass, 130 String name, 131 Class<?>[] parameterTypes, 132 Class<?> returnType, 133 Class<?>[] checkedExceptions, 134 int modifiers, 135 boolean isConstructor, 136 boolean forSerialization, 137 Class<?> serializationTargetClass) 138 { 139 ByteVector vec = ByteVectorFactory.create(); 140 asm = new ClassFileAssembler(vec); 141 this.declaringClass = declaringClass; 142 this.parameterTypes = parameterTypes; 143 this.returnType = returnType; 144 this.modifiers = modifiers; 145 this.isConstructor = isConstructor; 146 this.forSerialization = forSerialization; 147 148 this.cpClassPool = new ConstantPoolClassPool(); 149 150 asm.emitMagicAndVersion(); 151 152 // Constant pool entries: 153 // ( * = Boxing information: optional) 154 // (+ = Shared entries provided by AccessorGenerator) 155 // (^ = Only present if generating SerializationConstructorAccessor) 156 // [UTF-8] [This class's name] 157 // [CONSTANT_Class_info] for above 158 // [UTF-8] "jdk/internal/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" 159 // [CONSTANT_Class_info] for above 160 // [UTF-8] [Target class's name] 161 // [CONSTANT_Class_info] for above 162 // [UTF-8] descriptor for type of non-primitive parameter 1 163 // [CONSTANT_Class_info] for type of non-primitive parameter 1 164 // ... 165 // [UTF-8] descriptor for type of non-primitive parameter n 166 // [CONSTANT_Class_info] for type of non-primitive parameter n 167 // [UTF-8] descriptor for declared value types if not present in CP 168 // [CONSTANT_Class_info] for declared value types if not present in CP 169 // ... 170 // ^ [UTF-8] [Serialization: Class's name in which to invoke constructor] 171 // ^ [CONSTANT_Class_info] for above 172 // [UTF-8] target method or constructor name 173 // [UTF-8] target method or constructor signature 174 // [CONSTANT_NameAndType_info] for above 175 // [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method 176 // [UTF-8] "invoke" or "newInstance" 177 // [UTF-8] invoke or newInstance descriptor 178 // + [UTF-8] "java/lang/Exception" 179 // + [CONSTANT_Class_info] for above 180 // + [UTF-8] "java/lang/ClassCastException" 181 // + [CONSTANT_Class_info] for above 182 // + [UTF-8] "java/lang/NullPointerException" 183 // + [CONSTANT_Class_info] for above 184 // + [UTF-8] "java/lang/IllegalArgumentException" 185 // + [CONSTANT_Class_info] for above 186 // + [UTF-8] "java/lang/InvocationTargetException" 187 // + [CONSTANT_Class_info] for above 188 // + [UTF-8] "<init>" 189 // + [UTF-8] "()V" 190 // + [CONSTANT_NameAndType_info] for above 191 // + [CONSTANT_Methodref_info] for NullPointerException's constructor 192 // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor 193 // + [UTF-8] "(Ljava/lang/String;)V" 194 // + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/String;)V" 195 // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String 196 // + [UTF-8] "(Ljava/lang/Throwable;)V" 197 // + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/Throwable;)V" 198 // + [CONSTANT_Methodref_info] for InvocationTargetException's constructor 199 // + [CONSTANT_Methodref_info] for "super()" 200 // + [UTF-8] "java/lang/Object" 201 // + [CONSTANT_Class_info] for above 202 // + [UTF-8] "toString" 203 // + [UTF-8] "()Ljava/lang/String;" 204 // + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;" 205 // + [CONSTANT_Methodref_info] for Object's toString method 206 // + [UTF-8] "Code" 207 // + [UTF-8] "Exceptions" 208 // * [UTF-8] "java/lang/Boolean" 209 // * [CONSTANT_Class_info] for above 210 // * [UTF-8] "(Z)V" 211 // * [CONSTANT_NameAndType_info] for above 212 // * [CONSTANT_Methodref_info] for above 213 // * [UTF-8] "booleanValue" 214 // * [UTF-8] "()Z" 215 // * [CONSTANT_NameAndType_info] for above 216 // * [CONSTANT_Methodref_info] for above 217 // * [UTF-8] "java/lang/Byte" 218 // * [CONSTANT_Class_info] for above 219 // * [UTF-8] "(B)V" 220 // * [CONSTANT_NameAndType_info] for above 221 // * [CONSTANT_Methodref_info] for above 222 // * [UTF-8] "byteValue" 223 // * [UTF-8] "()B" 224 // * [CONSTANT_NameAndType_info] for above 225 // * [CONSTANT_Methodref_info] for above 226 // * [UTF-8] "java/lang/Character" 227 // * [CONSTANT_Class_info] for above 228 // * [UTF-8] "(C)V" 229 // * [CONSTANT_NameAndType_info] for above 230 // * [CONSTANT_Methodref_info] for above 231 // * [UTF-8] "charValue" 232 // * [UTF-8] "()C" 233 // * [CONSTANT_NameAndType_info] for above 234 // * [CONSTANT_Methodref_info] for above 235 // * [UTF-8] "java/lang/Double" 236 // * [CONSTANT_Class_info] for above 237 // * [UTF-8] "(D)V" 238 // * [CONSTANT_NameAndType_info] for above 239 // * [CONSTANT_Methodref_info] for above 240 // * [UTF-8] "doubleValue" 241 // * [UTF-8] "()D" 242 // * [CONSTANT_NameAndType_info] for above 243 // * [CONSTANT_Methodref_info] for above 244 // * [UTF-8] "java/lang/Float" 245 // * [CONSTANT_Class_info] for above 246 // * [UTF-8] "(F)V" 247 // * [CONSTANT_NameAndType_info] for above 248 // * [CONSTANT_Methodref_info] for above 249 // * [UTF-8] "floatValue" 250 // * [UTF-8] "()F" 251 // * [CONSTANT_NameAndType_info] for above 252 // * [CONSTANT_Methodref_info] for above 253 // * [UTF-8] "java/lang/Integer" 254 // * [CONSTANT_Class_info] for above 255 // * [UTF-8] "(I)V" 256 // * [CONSTANT_NameAndType_info] for above 257 // * [CONSTANT_Methodref_info] for above 258 // * [UTF-8] "intValue" 259 // * [UTF-8] "()I" 260 // * [CONSTANT_NameAndType_info] for above 261 // * [CONSTANT_Methodref_info] for above 262 // * [UTF-8] "java/lang/Long" 263 // * [CONSTANT_Class_info] for above 264 // * [UTF-8] "(J)V" 265 // * [CONSTANT_NameAndType_info] for above 266 // * [CONSTANT_Methodref_info] for above 267 // * [UTF-8] "longValue" 268 // * [UTF-8] "()J" 269 // * [CONSTANT_NameAndType_info] for above 270 // * [CONSTANT_Methodref_info] for above 271 // * [UTF-8] "java/lang/Short" 272 // * [CONSTANT_Class_info] for above 273 // * [UTF-8] "(S)V" 274 // * [CONSTANT_NameAndType_info] for above 275 // * [CONSTANT_Methodref_info] for above 276 // * [UTF-8] "shortValue" 277 // * [UTF-8] "()S" 278 // * [CONSTANT_NameAndType_info] for above 279 // * [CONSTANT_Methodref_info] for above 280 281 short numCPEntries = NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES; 282 boolean usesPrimitives = usesPrimitiveTypes(); 283 if (usesPrimitives) { 284 numCPEntries += NUM_BOXING_CPOOL_ENTRIES; 285 } 286 if (forSerialization) { 287 numCPEntries += NUM_SERIALIZATION_CPOOL_ENTRIES; 288 } 289 290 numCPEntries += cpClassPool.numConstantPoolEntries(); 291 292 // Add constant pool UTF8 entry for ValueTypes attribute name 293 if (cpClassPool.hasDeclaredValueTypes()) { 294 numCPEntries += 1; 295 } 296 297 asm.emitShort(add(numCPEntries, S1)); 298 299 final String generatedName = generateName(isConstructor, forSerialization); 300 asm.emitConstantPoolUTF8(generatedName); 301 asm.emitConstantPoolClass(asm.cpi()); 302 thisClass = asm.cpi(); 303 if (isConstructor) { 304 if (forSerialization) { 305 asm.emitConstantPoolUTF8 306 ("jdk/internal/reflect/SerializationConstructorAccessorImpl"); 307 } else { 308 asm.emitConstantPoolUTF8("jdk/internal/reflect/ConstructorAccessorImpl"); 309 } 310 } else { 311 asm.emitConstantPoolUTF8("jdk/internal/reflect/MethodAccessorImpl"); 312 } 313 asm.emitConstantPoolClass(asm.cpi()); 314 superClass = asm.cpi(); 315 316 // emit constant pool entries for declaring class, parameter types and return type 317 cpClassPool.emitConstantPoolEntries(); 318 targetClass = cpClassPool.cpIndex(declaringClass); 319 320 short serializationTargetClassIdx = (short) 0; 321 if (forSerialization) { 322 asm.emitConstantPoolUTF8(getClassName(serializationTargetClass, false)); 323 asm.emitConstantPoolClass(asm.cpi()); 324 serializationTargetClassIdx = asm.cpi(); 325 } 326 asm.emitConstantPoolUTF8(name); 327 asm.emitConstantPoolUTF8(buildInternalSignature()); 328 asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); 329 if (isInterface()) { 330 asm.emitConstantPoolInterfaceMethodref(targetClass, asm.cpi()); 331 } else { 332 if (forSerialization) { 333 asm.emitConstantPoolMethodref(serializationTargetClassIdx, asm.cpi()); 334 } else { 335 asm.emitConstantPoolMethodref(targetClass, asm.cpi()); 336 } 337 } 338 targetMethodRef = asm.cpi(); 339 if (isConstructor) { 340 asm.emitConstantPoolUTF8("newInstance"); 341 } else { 342 asm.emitConstantPoolUTF8("invoke"); 343 } 344 invokeIdx = asm.cpi(); 345 if (isConstructor) { 346 asm.emitConstantPoolUTF8("([Ljava/lang/Object;)Ljava/lang/Object;"); 347 } else { 348 asm.emitConstantPoolUTF8 349 ("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); 350 } 351 invokeDescriptorIdx = asm.cpi(); 352 353 // emit name index for "ValueTypes" attribute 354 if (cpClassPool.hasDeclaredValueTypes()) { 355 asm.emitConstantPoolUTF8("ValueTypes"); 356 valueTypesAttrIdx = asm.cpi(); 357 } 358 359 // Entries common to FieldAccessor, MethodAccessor and ConstructorAccessor 360 emitCommonConstantPoolEntries(); 361 362 // Boxing entries 363 if (usesPrimitives) { 364 emitBoxingContantPoolEntries(); 365 } 366 367 if (asm.cpi() != numCPEntries) { 368 throw new InternalError("Adjust this code (cpi = " + asm.cpi() + 369 ", numCPEntries = " + numCPEntries + ")"); 370 } 371 372 // Access flags 373 asm.emitShort(ACC_PUBLIC); 374 375 // This class 376 asm.emitShort(thisClass); 377 378 // Superclass 379 asm.emitShort(superClass); 380 381 // Interfaces count and interfaces 382 asm.emitShort(S0); 383 384 // Fields count and fields 385 asm.emitShort(S0); 386 387 // Methods count and methods 388 asm.emitShort(NUM_METHODS); 389 390 emitConstructor(); 391 emitInvoke(); 392 393 // Additional attributes 394 if (cpClassPool.hasDeclaredValueTypes()) { 395 asm.emitShort(S1); 396 emitValueTypesAttribute(); 397 } else { 398 asm.emitShort(S0); 399 } 400 401 // Load class 402 vec.trim(); 403 final byte[] bytes = vec.getData(); 404 405 // Note: the class loader is the only thing that really matters 406 // here -- it's important to get the generated code into the 407 // same namespace as the target class. Since the generated code 408 // is privileged anyway, the protection domain probably doesn't 409 // matter. 410 return AccessController.doPrivileged( 411 new PrivilegedAction<MagicAccessorImpl>() { 412 @SuppressWarnings("deprecation") // Class.newInstance 413 public MagicAccessorImpl run() { 414 try { 415 return (MagicAccessorImpl) 416 ClassDefiner.defineClass 417 (generatedName, 418 bytes, 419 0, 420 bytes.length, 421 declaringClass.getClassLoader()).newInstance(); 422 } catch (InstantiationException | IllegalAccessException e) { 423 throw new InternalError(e); 424 } 425 } 426 }); 427 } 428 429 private void emitValueTypesAttribute() { 430 short[] valueTypesAttr = cpClassPool.declaredValueTypes(); 431 int attrLen = 2 + 2 * valueTypesAttr.length; 432 asm.emitShort(valueTypesAttrIdx); 433 asm.emitInt(attrLen); 434 asm.emitShort((short) valueTypesAttr.length); 435 for (short cpi : valueTypesAttr) { 436 asm.emitShort(cpi); 437 } 438 } 439 /** This emits the code for either invoke() or newInstance() */ 440 private void emitInvoke() { 441 // NOTE that this code will only handle 65535 parameters since we 442 // use the sipush instruction to get the array index on the 443 // operand stack. 444 if (parameterTypes.length > 65535) { 445 throw new InternalError("Can't handle more than 65535 parameters"); 446 } 447 448 // Generate code into fresh code buffer 449 ClassFileAssembler cb = new ClassFileAssembler(); 450 if (isConstructor) { 451 // 1 incoming argument 452 cb.setMaxLocals(2); 453 } else { 454 // 2 incoming arguments 455 cb.setMaxLocals(3); 456 } 457 458 short illegalArgStartPC = 0; 459 460 if (isConstructor) { 461 // Instantiate target class before continuing 462 // new <target class type> 463 // dup 464 cb.opc_new(targetClass); 465 cb.opc_dup(); 466 } else { 467 // Get target object on operand stack if necessary. 468 469 // We need to do an explicit null check here; we won't see 470 // NullPointerExceptions from the invoke bytecode, since it's 471 // covered by an exception handler. 472 if (!isStatic()) { 473 // aload_1 474 // ifnonnull <checkcast label> 475 // new <NullPointerException> 476 // dup 477 // invokespecial <NullPointerException ctor> 478 // athrow 479 // <checkcast label:> 480 // aload_1 481 // checkcast <target class's type> 482 cb.opc_aload_1(); 483 Label l = new Label(); 484 cb.opc_ifnonnull(l); 485 cb.opc_new(nullPointerClass); 486 cb.opc_dup(); 487 cb.opc_invokespecial(nullPointerCtorIdx, 0, 0); 488 cb.opc_athrow(); 489 l.bind(); 490 illegalArgStartPC = cb.getLength(); 491 cb.opc_aload_1(); 492 cb.opc_checkcast(targetClass); 493 } 494 } 495 496 // Have to check length of incoming array and throw 497 // IllegalArgumentException if not correct. A concession to the 498 // JCK (isn't clearly specified in the spec): we allow null in the 499 // case where the argument list is zero length. 500 // if no-arg: 501 // aload_2 | aload_1 (Method | Constructor) 502 // ifnull <success label> 503 // aload_2 | aload_1 504 // arraylength 505 // sipush <num parameter types> 506 // if_icmpeq <success label> 507 // new <IllegalArgumentException> 508 // dup 509 // invokespecial <IllegalArgumentException ctor> 510 // athrow 511 // <success label:> 512 Label successLabel = new Label(); 513 if (parameterTypes.length == 0) { 514 if (isConstructor) { 515 cb.opc_aload_1(); 516 } else { 517 cb.opc_aload_2(); 518 } 519 cb.opc_ifnull(successLabel); 520 } 521 if (isConstructor) { 522 cb.opc_aload_1(); 523 } else { 524 cb.opc_aload_2(); 525 } 526 cb.opc_arraylength(); 527 cb.opc_sipush((short) parameterTypes.length); 528 cb.opc_if_icmpeq(successLabel); 529 cb.opc_new(illegalArgumentClass); 530 cb.opc_dup(); 531 cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); 532 cb.opc_athrow(); 533 successLabel.bind(); 534 535 // Iterate through incoming actual parameters, ensuring that each 536 // is compatible with the formal parameter type, and pushing the 537 // actual on the operand stack (unboxing and widening if necessary). 538 539 Label nextParamLabel = null; 540 byte count = 1; // both invokeinterface opcode's "count" as well as 541 // num args of other invoke bytecodes 542 for (int i = 0; i < parameterTypes.length; i++) { 543 Class<?> paramType = parameterTypes[i]; 544 count += (byte) typeSizeInStackSlots(paramType); 545 if (nextParamLabel != null) { 546 nextParamLabel.bind(); 547 nextParamLabel = null; 548 } 549 // aload_2 | aload_1 550 // sipush <index> 551 // aaload 552 if (isConstructor) { 553 cb.opc_aload_1(); 554 } else { 555 cb.opc_aload_2(); 556 } 557 cb.opc_sipush((short) i); 558 cb.opc_aaload(); 559 if (isPrimitive(paramType)) { 560 // Unboxing code. 561 // Put parameter into temporary local variable 562 // astore_3 | astore_2 563 if (isConstructor) { 564 cb.opc_astore_2(); 565 } else { 566 cb.opc_astore_3(); 567 } 568 569 // repeat for all possible widening conversions: 570 // aload_3 | aload_2 571 // instanceof <primitive boxing type> 572 // ifeq <next unboxing label> 573 // aload_3 | aload_2 574 // checkcast <primitive boxing type> // Note: this is "redundant", 575 // // but necessary for the verifier 576 // invokevirtual <unboxing method> 577 // <widening conversion bytecode, if necessary> 578 // goto <next parameter label> 579 // <next unboxing label:> ... 580 // last unboxing label: 581 // new <IllegalArgumentException> 582 // dup 583 // invokespecial <IllegalArgumentException ctor> 584 // athrow 585 586 Label l = null; // unboxing label 587 nextParamLabel = new Label(); 588 589 for (int j = 0; j < primitiveTypes.length; j++) { 590 Class<?> c = primitiveTypes[j]; 591 if (canWidenTo(c, paramType)) { 592 if (l != null) { 593 l.bind(); 594 } 595 // Emit checking and unboxing code for this type 596 if (isConstructor) { 597 cb.opc_aload_2(); 598 } else { 599 cb.opc_aload_3(); 600 } 601 cb.opc_instanceof(indexForPrimitiveType(c)); 602 l = new Label(); 603 cb.opc_ifeq(l); 604 if (isConstructor) { 605 cb.opc_aload_2(); 606 } else { 607 cb.opc_aload_3(); 608 } 609 cb.opc_checkcast(indexForPrimitiveType(c)); 610 cb.opc_invokevirtual(unboxingMethodForPrimitiveType(c), 611 0, 612 typeSizeInStackSlots(c)); 613 emitWideningBytecodeForPrimitiveConversion(cb, 614 c, 615 paramType); 616 cb.opc_goto(nextParamLabel); 617 } 618 } 619 620 if (l == null) { 621 throw new InternalError 622 ("Must have found at least identity conversion"); 623 } 624 625 // Fell through; given object is null or invalid. According to 626 // the spec, we can throw IllegalArgumentException for both of 627 // these cases. 628 629 l.bind(); 630 cb.opc_new(illegalArgumentClass); 631 cb.opc_dup(); 632 cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); 633 cb.opc_athrow(); 634 } else { 635 // Emit appropriate checkcast 636 short paramTypeCPIdx = cpClassPool.cpIndex(paramType); 637 cb.opc_checkcast(paramTypeCPIdx); 638 // Fall through to next argument 639 } 640 } 641 // Bind last goto if present 642 if (nextParamLabel != null) { 643 nextParamLabel.bind(); 644 } 645 646 short invokeStartPC = cb.getLength(); 647 648 // OK, ready to perform the invocation. 649 if (isConstructor) { 650 cb.opc_invokespecial(targetMethodRef, count, 0); 651 } else { 652 if (isStatic()) { 653 cb.opc_invokestatic(targetMethodRef, 654 count, 655 typeSizeInStackSlots(returnType)); 656 } else { 657 if (isInterface()) { 658 cb.opc_invokeinterface(targetMethodRef, 659 count, 660 count, 661 typeSizeInStackSlots(returnType)); 662 } else { 663 cb.opc_invokevirtual(targetMethodRef, 664 count, 665 typeSizeInStackSlots(returnType)); 666 } 667 } 668 } 669 670 short invokeEndPC = cb.getLength(); 671 672 if (!isConstructor) { 673 // Box return value if necessary 674 if (isPrimitive(returnType)) { 675 cb.opc_invokestatic(boxingMethodForPrimitiveType(returnType), 676 typeSizeInStackSlots(returnType), 677 0); 678 } else if (returnType == Void.TYPE) { 679 cb.opc_aconst_null(); 680 } 681 } 682 cb.opc_areturn(); 683 684 // We generate two exception handlers; one which is responsible 685 // for catching ClassCastException and NullPointerException and 686 // throwing IllegalArgumentException, and the other which catches 687 // all java/lang/Throwable objects thrown from the target method 688 // and wraps them in InvocationTargetExceptions. 689 690 short classCastHandler = cb.getLength(); 691 692 // ClassCast, etc. exception handler 693 cb.setStack(1); 694 cb.opc_invokespecial(toStringIdx, 0, 1); 695 cb.opc_new(illegalArgumentClass); 696 cb.opc_dup_x1(); 697 cb.opc_swap(); 698 cb.opc_invokespecial(illegalArgumentStringCtorIdx, 1, 0); 699 cb.opc_athrow(); 700 701 short invocationTargetHandler = cb.getLength(); 702 703 // InvocationTargetException exception handler 704 cb.setStack(1); 705 cb.opc_new(invocationTargetClass); 706 cb.opc_dup_x1(); 707 cb.opc_swap(); 708 cb.opc_invokespecial(invocationTargetCtorIdx, 1, 0); 709 cb.opc_athrow(); 710 711 // Generate exception table. We cover the entire code sequence 712 // with an exception handler which catches ClassCastException and 713 // converts it into an IllegalArgumentException. 714 715 ClassFileAssembler exc = new ClassFileAssembler(); 716 717 exc.emitShort(illegalArgStartPC); // start PC 718 exc.emitShort(invokeStartPC); // end PC 719 exc.emitShort(classCastHandler); // handler PC 720 exc.emitShort(classCastClass); // catch type 721 722 exc.emitShort(illegalArgStartPC); // start PC 723 exc.emitShort(invokeStartPC); // end PC 724 exc.emitShort(classCastHandler); // handler PC 725 exc.emitShort(nullPointerClass); // catch type 726 727 exc.emitShort(invokeStartPC); // start PC 728 exc.emitShort(invokeEndPC); // end PC 729 exc.emitShort(invocationTargetHandler); // handler PC 730 exc.emitShort(throwableClass); // catch type 731 732 emitMethod(invokeIdx, cb.getMaxLocals(), cb, exc, 733 new short[] { invocationTargetClass }); 734 } 735 736 private boolean usesPrimitiveTypes() { 737 // We need to emit boxing/unboxing constant pool information if 738 // the method takes a primitive type for any of its parameters or 739 // returns a primitive value (except void) 740 if (returnType.isPrimitive()) { 741 return true; 742 } 743 for (int i = 0; i < parameterTypes.length; i++) { 744 if (parameterTypes[i].isPrimitive()) { 745 return true; 746 } 747 } 748 return false; 749 } 750 751 private boolean isInterface() { 752 return declaringClass.isInterface(); 753 } 754 755 private String buildInternalSignature() { 756 StringBuilder sb = new StringBuilder(); 757 sb.append("("); 758 for (int i = 0; i < parameterTypes.length; i++) { 759 sb.append(getClassName(parameterTypes[i], true)); 760 } 761 sb.append(")"); 762 sb.append(getClassName(returnType, true)); 763 return sb.toString(); 764 } 765 766 private static synchronized String generateName(boolean isConstructor, 767 boolean forSerialization) 768 { 769 if (isConstructor) { 770 if (forSerialization) { 771 int num = ++serializationConstructorSymnum; 772 return "jdk/internal/reflect/GeneratedSerializationConstructorAccessor" + num; 773 } else { 774 int num = ++constructorSymnum; 775 return "jdk/internal/reflect/GeneratedConstructorAccessor" + num; 776 } 777 } else { 778 int num = ++methodSymnum; 779 return "jdk/internal/reflect/GeneratedMethodAccessor" + num; 780 } 781 } 782 783 private static Set<String> getDeclaredValueTypeNames(Class<?> c) { 784 return SharedSecrets.getJavaLangAccess().getDeclaredValueTypeNames(c); 785 } 786 787 /* 788 * CONSTANT_CLASS constant pool entry pool for the declaring class and 789 * parameter types. Add constant pool entry for the return type if 790 * it's a declared value type. 791 */ 792 class ConstantPoolClassPool { 793 final Map<Class<?>, Short> cpEntries = new HashMap<>(); 794 final Set<Class<?>> types = new HashSet<>(); 795 final Set<Class<?>> valueTypes; 796 ConstantPoolClassPool() { 797 Set<String> declaredValueTypes = getDeclaredValueTypeNames(declaringClass); 798 if (declaredValueTypes.isEmpty()) { 799 // no declared value types 800 this.valueTypes = Set.of(); 801 // CP entries for declaring class and parameter types 802 addCPEntry(declaringClass); 803 for (Class<?> paramType : parameterTypes) { 804 addCPEntry(paramType); 805 } 806 } else { 807 this.valueTypes = new HashSet<>(); 808 add(declaredValueTypes, declaringClass); 809 for (Class<?> paramType : parameterTypes) { 810 add(declaredValueTypes, paramType); 811 } 812 // CONSTANT_CLASS entry for return type is referenced 813 // in ValueTypes attribute only 814 addIfDeclaredValueType(declaredValueTypes, returnType); 815 } 816 } 817 818 private void addCPEntry(Class<?> c) { 819 if (!c.isPrimitive()) 820 types.add(c); 821 } 822 823 private void add(Set<String> declaredValueTypes, Class<?> type) { 824 addCPEntry(type); 825 addIfDeclaredValueType(declaredValueTypes, type); 826 } 827 828 // add if this type or its component type is a declared value type 829 private void addIfDeclaredValueType(Set<String> declaredValueTypes, Class<?> type) { 830 Class<?> c = type; 831 while (c.isArray()) c = c.getComponentType(); 832 if (declaredValueTypes.contains(c.getName())) { 833 valueTypes.add(c); 834 addCPEntry(c); 835 } 836 } 837 838 int numConstantPoolEntries() { 839 return types.size() * 2; 840 } 841 842 void emitConstantPoolEntries() { 843 for (Class<?> c : types) { 844 cpEntries.put(c, emitConstantPoolEntries(c)); 845 } 846 } 847 848 private short emitConstantPoolEntries(Class<?> c) { 849 asm.emitConstantPoolUTF8(getClassName(c, false)); 850 asm.emitConstantPoolClass(asm.cpi()); 851 return asm.cpi(); 852 } 853 854 boolean hasDeclaredValueTypes() { 855 return !valueTypes.isEmpty(); 856 } 857 858 short cpIndex(Class<?> c) { 859 return cpEntries.get(c); 860 } 861 862 short[] declaredValueTypes() { 863 short[] idx = new short[valueTypes.size()]; 864 int i=0; 865 for (Class<?> c: valueTypes) { 866 idx[i++] = cpIndex(c); 867 } 868 return idx; 869 } 870 } 871 }