1 /*
   2  * Copyright (c) 2001, 2013, 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             // Setup before iterating down argument list
 441             if (isPrimitive(returnType)) {
 442                 // new <boxing type for primitive type>
 443                 // dup
 444                 // ... (see below:)
 445                 // invokespecial <constructor for boxing type for primitive type>
 446                 // areturn
 447                 cb.opc_new(indexForPrimitiveType(returnType));
 448                 cb.opc_dup();
 449             }
 450 
 451             // Get target object on operand stack if necessary.
 452 
 453             // We need to do an explicit null check here; we won't see
 454             // NullPointerExceptions from the invoke bytecode, since it's
 455             // covered by an exception handler.
 456             if (!isStatic()) {
 457                 // aload_1
 458                 // ifnonnull <checkcast label>
 459                 // new <NullPointerException>
 460                 // dup
 461                 // invokespecial <NullPointerException ctor>
 462                 // athrow
 463                 // <checkcast label:>
 464                 // aload_1
 465                 // checkcast <target class's type>
 466                 cb.opc_aload_1();
 467                 Label l = new Label();
 468                 cb.opc_ifnonnull(l);
 469                 cb.opc_new(nullPointerClass);
 470                 cb.opc_dup();
 471                 cb.opc_invokespecial(nullPointerCtorIdx, 0, 0);
 472                 cb.opc_athrow();
 473                 l.bind();
 474                 illegalArgStartPC = cb.getLength();
 475                 cb.opc_aload_1();
 476                 cb.opc_checkcast(targetClass);
 477             }
 478         }
 479 
 480         // Have to check length of incoming array and throw
 481         // IllegalArgumentException if not correct. A concession to the
 482         // JCK (isn't clearly specified in the spec): we allow null in the
 483         // case where the argument list is zero length.
 484         // if no-arg:
 485         //   aload_2 | aload_1 (Method | Constructor)
 486         //   ifnull <success label>
 487         // aload_2 | aload_1
 488         // arraylength
 489         // sipush <num parameter types>
 490         // if_icmpeq <success label>
 491         // new <IllegalArgumentException>
 492         // dup
 493         // invokespecial <IllegalArgumentException ctor>
 494         // athrow
 495         // <success label:>
 496         Label successLabel = new Label();
 497         if (parameterTypes.length == 0) {
 498             if (isConstructor) {
 499                 cb.opc_aload_1();
 500             } else {
 501                 cb.opc_aload_2();
 502             }
 503             cb.opc_ifnull(successLabel);
 504         }
 505         if (isConstructor) {
 506             cb.opc_aload_1();
 507         } else {
 508             cb.opc_aload_2();
 509         }
 510         cb.opc_arraylength();
 511         cb.opc_sipush((short) parameterTypes.length);
 512         cb.opc_if_icmpeq(successLabel);
 513         cb.opc_new(illegalArgumentClass);
 514         cb.opc_dup();
 515         cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0);
 516         cb.opc_athrow();
 517         successLabel.bind();
 518 
 519         // Iterate through incoming actual parameters, ensuring that each
 520         // is compatible with the formal parameter type, and pushing the
 521         // actual on the operand stack (unboxing and widening if necessary).
 522 
 523         short paramTypeCPIdx = nonPrimitiveParametersBaseIdx;
 524         Label nextParamLabel = null;
 525         byte count = 1; // both invokeinterface opcode's "count" as well as
 526         // num args of other invoke bytecodes
 527         for (int i = 0; i < parameterTypes.length; i++) {
 528             Class<?> paramType = parameterTypes[i];
 529             count += (byte) typeSizeInStackSlots(paramType);
 530             if (nextParamLabel != null) {
 531                 nextParamLabel.bind();
 532                 nextParamLabel = null;
 533             }
 534             // aload_2 | aload_1
 535             // sipush <index>
 536             // aaload
 537             if (isConstructor) {
 538                 cb.opc_aload_1();
 539             } else {
 540                 cb.opc_aload_2();
 541             }
 542             cb.opc_sipush((short) i);
 543             cb.opc_aaload();
 544             if (isPrimitive(paramType)) {
 545                 // Unboxing code.
 546                 // Put parameter into temporary local variable
 547                 // astore_3 | astore_2
 548                 if (isConstructor) {
 549                     cb.opc_astore_2();
 550                 } else {
 551                     cb.opc_astore_3();
 552                 }
 553 
 554                 // repeat for all possible widening conversions:
 555                 //   aload_3 | aload_2
 556                 //   instanceof <primitive boxing type>
 557                 //   ifeq <next unboxing label>
 558                 //   aload_3 | aload_2
 559                 //   checkcast <primitive boxing type> // Note: this is "redundant",
 560                 //                                     // but necessary for the verifier
 561                 //   invokevirtual <unboxing method>
 562                 //   <widening conversion bytecode, if necessary>
 563                 //   goto <next parameter label>
 564                 // <next unboxing label:> ...
 565                 // last unboxing label:
 566                 //   new <IllegalArgumentException>
 567                 //   dup
 568                 //   invokespecial <IllegalArgumentException ctor>
 569                 //   athrow
 570 
 571                 Label l = null; // unboxing label
 572                 nextParamLabel = new Label();
 573 
 574                 for (int j = 0; j < primitiveTypes.length; j++) {
 575                     Class<?> c = primitiveTypes[j];
 576                     if (canWidenTo(c, paramType)) {
 577                         if (l != null) {
 578                             l.bind();
 579                         }
 580                         // Emit checking and unboxing code for this type
 581                         if (isConstructor) {
 582                             cb.opc_aload_2();
 583                         } else {
 584                             cb.opc_aload_3();
 585                         }
 586                         cb.opc_instanceof(indexForPrimitiveType(c));
 587                         l = new Label();
 588                         cb.opc_ifeq(l);
 589                         if (isConstructor) {
 590                             cb.opc_aload_2();
 591                         } else {
 592                             cb.opc_aload_3();
 593                         }
 594                         cb.opc_checkcast(indexForPrimitiveType(c));
 595                         cb.opc_invokevirtual(unboxingMethodForPrimitiveType(c),
 596                                              0,
 597                                              typeSizeInStackSlots(c));
 598                         emitWideningBytecodeForPrimitiveConversion(cb,
 599                                                                    c,
 600                                                                    paramType);
 601                         cb.opc_goto(nextParamLabel);
 602                     }
 603                 }
 604 
 605                 if (l == null) {
 606                     throw new InternalError
 607                         ("Must have found at least identity conversion");
 608                 }
 609 
 610                 // Fell through; given object is null or invalid. According to
 611                 // the spec, we can throw IllegalArgumentException for both of
 612                 // these cases.
 613 
 614                 l.bind();
 615                 cb.opc_new(illegalArgumentClass);
 616                 cb.opc_dup();
 617                 cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0);
 618                 cb.opc_athrow();
 619             } else {
 620                 // Emit appropriate checkcast
 621                 cb.opc_checkcast(paramTypeCPIdx);
 622                 paramTypeCPIdx = add(paramTypeCPIdx, S2);
 623                 // Fall through to next argument
 624             }
 625         }
 626         // Bind last goto if present
 627         if (nextParamLabel != null) {
 628             nextParamLabel.bind();
 629         }
 630 
 631         short invokeStartPC = cb.getLength();
 632 
 633         // OK, ready to perform the invocation.
 634         if (isConstructor) {
 635             cb.opc_invokespecial(targetMethodRef, count, 0);
 636         } else {
 637             if (isStatic()) {
 638                 cb.opc_invokestatic(targetMethodRef,
 639                                     count,
 640                                     typeSizeInStackSlots(returnType));
 641             } else {
 642                 if (isInterface()) {
 643                     if (isPrivate()) {
 644                         cb.opc_invokespecial(targetMethodRef, count, 0);
 645                     } else {
 646                         cb.opc_invokeinterface(targetMethodRef,
 647                                                count,
 648                                                count,
 649                                                typeSizeInStackSlots(returnType));
 650                     }
 651                 } else {
 652                     cb.opc_invokevirtual(targetMethodRef,
 653                                          count,
 654                                          typeSizeInStackSlots(returnType));
 655                 }
 656             }
 657         }
 658 
 659         short invokeEndPC = cb.getLength();
 660 
 661         if (!isConstructor) {
 662             // Box return value if necessary
 663             if (isPrimitive(returnType)) {
 664                 cb.opc_invokestatic(boxingMethodForPrimitiveType(returnType),
 665                                     typeSizeInStackSlots(returnType),
 666                                     0);
 667             } else if (returnType == Void.TYPE) {
 668                 cb.opc_aconst_null();
 669             }
 670         }
 671         cb.opc_areturn();
 672 
 673         // We generate two exception handlers; one which is responsible
 674         // for catching ClassCastException and NullPointerException and
 675         // throwing IllegalArgumentException, and the other which catches
 676         // all java/lang/Throwable objects thrown from the target method
 677         // and wraps them in InvocationTargetExceptions.
 678 
 679         short classCastHandler = cb.getLength();
 680 
 681         // ClassCast, etc. exception handler
 682         cb.setStack(1);
 683         cb.opc_invokespecial(toStringIdx, 0, 1);
 684         cb.opc_new(illegalArgumentClass);
 685         cb.opc_dup_x1();
 686         cb.opc_swap();
 687         cb.opc_invokespecial(illegalArgumentStringCtorIdx, 1, 0);
 688         cb.opc_athrow();
 689 
 690         short invocationTargetHandler = cb.getLength();
 691 
 692         // InvocationTargetException exception handler
 693         cb.setStack(1);
 694         cb.opc_new(invocationTargetClass);
 695         cb.opc_dup_x1();
 696         cb.opc_swap();
 697         cb.opc_invokespecial(invocationTargetCtorIdx, 1, 0);
 698         cb.opc_athrow();
 699 
 700         // Generate exception table. We cover the entire code sequence
 701         // with an exception handler which catches ClassCastException and
 702         // converts it into an IllegalArgumentException.
 703 
 704         ClassFileAssembler exc = new ClassFileAssembler();
 705 
 706         exc.emitShort(illegalArgStartPC);       // start PC
 707         exc.emitShort(invokeStartPC);           // end PC
 708         exc.emitShort(classCastHandler);        // handler PC
 709         exc.emitShort(classCastClass);          // catch type
 710 
 711         exc.emitShort(illegalArgStartPC);       // start PC
 712         exc.emitShort(invokeStartPC);           // end PC
 713         exc.emitShort(classCastHandler);        // handler PC
 714         exc.emitShort(nullPointerClass);        // catch type
 715 
 716         exc.emitShort(invokeStartPC);           // start PC
 717         exc.emitShort(invokeEndPC);             // end PC
 718         exc.emitShort(invocationTargetHandler); // handler PC
 719         exc.emitShort(throwableClass);          // catch type
 720 
 721         emitMethod(invokeIdx, cb.getMaxLocals(), cb, exc,
 722                    new short[] { invocationTargetClass });
 723     }
 724 
 725     private boolean usesPrimitiveTypes() {
 726         // We need to emit boxing/unboxing constant pool information if
 727         // the method takes a primitive type for any of its parameters or
 728         // returns a primitive value (except void)
 729         if (returnType.isPrimitive()) {
 730             return true;
 731         }
 732         for (int i = 0; i < parameterTypes.length; i++) {
 733             if (parameterTypes[i].isPrimitive()) {
 734                 return true;
 735             }
 736         }
 737         return false;
 738     }
 739 
 740     private int numNonPrimitiveParameterTypes() {
 741         int num = 0;
 742         for (int i = 0; i < parameterTypes.length; i++) {
 743             if (!parameterTypes[i].isPrimitive()) {
 744                 ++num;
 745             }
 746         }
 747         return num;
 748     }
 749 
 750     private boolean isInterface() {
 751         return declaringClass.isInterface();
 752     }
 753 
 754     private String buildInternalSignature() {
 755         StringBuilder sb = new StringBuilder();
 756         sb.append("(");
 757         for (int i = 0; i < parameterTypes.length; i++) {
 758             sb.append(getClassName(parameterTypes[i], true));
 759         }
 760         sb.append(")");
 761         sb.append(getClassName(returnType, true));
 762         return sb.toString();
 763     }
 764 
 765     private static synchronized String generateName(boolean isConstructor,
 766                                                     boolean forSerialization)
 767     {
 768         if (isConstructor) {
 769             if (forSerialization) {
 770                 int num = ++serializationConstructorSymnum;
 771                 return "jdk/internal/reflect/GeneratedSerializationConstructorAccessor" + num;
 772             } else {
 773                 int num = ++constructorSymnum;
 774                 return "jdk/internal/reflect/GeneratedConstructorAccessor" + num;
 775             }
 776         } else {
 777             int num = ++methodSymnum;
 778             return "jdk/internal/reflect/GeneratedMethodAccessor" + num;
 779         }
 780     }
 781 }