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