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 }