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