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