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