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