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