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