MethodAccessorGenerator.java revision 14360:03453120a011
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            // Setup before iterating down argument list
441            if (isPrimitive(returnType)) {
442                // new <boxing type for primitive type>
443                // dup
444                // ... (see below:)
445                // invokespecial <constructor for boxing type for primitive type>
446                // areturn
447                cb.opc_new(indexForPrimitiveType(returnType));
448                cb.opc_dup();
449            }
450
451            // Get target object on operand stack if necessary.
452
453            // We need to do an explicit null check here; we won't see
454            // NullPointerExceptions from the invoke bytecode, since it's
455            // covered by an exception handler.
456            if (!isStatic()) {
457                // aload_1
458                // ifnonnull <checkcast label>
459                // new <NullPointerException>
460                // dup
461                // invokespecial <NullPointerException ctor>
462                // athrow
463                // <checkcast label:>
464                // aload_1
465                // checkcast <target class's type>
466                cb.opc_aload_1();
467                Label l = new Label();
468                cb.opc_ifnonnull(l);
469                cb.opc_new(nullPointerClass);
470                cb.opc_dup();
471                cb.opc_invokespecial(nullPointerCtorIdx, 0, 0);
472                cb.opc_athrow();
473                l.bind();
474                illegalArgStartPC = cb.getLength();
475                cb.opc_aload_1();
476                cb.opc_checkcast(targetClass);
477            }
478        }
479
480        // Have to check length of incoming array and throw
481        // IllegalArgumentException if not correct. A concession to the
482        // JCK (isn't clearly specified in the spec): we allow null in the
483        // case where the argument list is zero length.
484        // if no-arg:
485        //   aload_2 | aload_1 (Method | Constructor)
486        //   ifnull <success label>
487        // aload_2 | aload_1
488        // arraylength
489        // sipush <num parameter types>
490        // if_icmpeq <success label>
491        // new <IllegalArgumentException>
492        // dup
493        // invokespecial <IllegalArgumentException ctor>
494        // athrow
495        // <success label:>
496        Label successLabel = new Label();
497        if (parameterTypes.length == 0) {
498            if (isConstructor) {
499                cb.opc_aload_1();
500            } else {
501                cb.opc_aload_2();
502            }
503            cb.opc_ifnull(successLabel);
504        }
505        if (isConstructor) {
506            cb.opc_aload_1();
507        } else {
508            cb.opc_aload_2();
509        }
510        cb.opc_arraylength();
511        cb.opc_sipush((short) parameterTypes.length);
512        cb.opc_if_icmpeq(successLabel);
513        cb.opc_new(illegalArgumentClass);
514        cb.opc_dup();
515        cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0);
516        cb.opc_athrow();
517        successLabel.bind();
518
519        // Iterate through incoming actual parameters, ensuring that each
520        // is compatible with the formal parameter type, and pushing the
521        // actual on the operand stack (unboxing and widening if necessary).
522
523        short paramTypeCPIdx = nonPrimitiveParametersBaseIdx;
524        Label nextParamLabel = null;
525        byte count = 1; // both invokeinterface opcode's "count" as well as
526        // num args of other invoke bytecodes
527        for (int i = 0; i < parameterTypes.length; i++) {
528            Class<?> paramType = parameterTypes[i];
529            count += (byte) typeSizeInStackSlots(paramType);
530            if (nextParamLabel != null) {
531                nextParamLabel.bind();
532                nextParamLabel = null;
533            }
534            // aload_2 | aload_1
535            // sipush <index>
536            // aaload
537            if (isConstructor) {
538                cb.opc_aload_1();
539            } else {
540                cb.opc_aload_2();
541            }
542            cb.opc_sipush((short) i);
543            cb.opc_aaload();
544            if (isPrimitive(paramType)) {
545                // Unboxing code.
546                // Put parameter into temporary local variable
547                // astore_3 | astore_2
548                if (isConstructor) {
549                    cb.opc_astore_2();
550                } else {
551                    cb.opc_astore_3();
552                }
553
554                // repeat for all possible widening conversions:
555                //   aload_3 | aload_2
556                //   instanceof <primitive boxing type>
557                //   ifeq <next unboxing label>
558                //   aload_3 | aload_2
559                //   checkcast <primitive boxing type> // Note: this is "redundant",
560                //                                     // but necessary for the verifier
561                //   invokevirtual <unboxing method>
562                //   <widening conversion bytecode, if necessary>
563                //   goto <next parameter label>
564                // <next unboxing label:> ...
565                // last unboxing label:
566                //   new <IllegalArgumentException>
567                //   dup
568                //   invokespecial <IllegalArgumentException ctor>
569                //   athrow
570
571                Label l = null; // unboxing label
572                nextParamLabel = new Label();
573
574                for (int j = 0; j < primitiveTypes.length; j++) {
575                    Class<?> c = primitiveTypes[j];
576                    if (canWidenTo(c, paramType)) {
577                        if (l != null) {
578                            l.bind();
579                        }
580                        // Emit checking and unboxing code for this type
581                        if (isConstructor) {
582                            cb.opc_aload_2();
583                        } else {
584                            cb.opc_aload_3();
585                        }
586                        cb.opc_instanceof(indexForPrimitiveType(c));
587                        l = new Label();
588                        cb.opc_ifeq(l);
589                        if (isConstructor) {
590                            cb.opc_aload_2();
591                        } else {
592                            cb.opc_aload_3();
593                        }
594                        cb.opc_checkcast(indexForPrimitiveType(c));
595                        cb.opc_invokevirtual(unboxingMethodForPrimitiveType(c),
596                                             0,
597                                             typeSizeInStackSlots(c));
598                        emitWideningBytecodeForPrimitiveConversion(cb,
599                                                                   c,
600                                                                   paramType);
601                        cb.opc_goto(nextParamLabel);
602                    }
603                }
604
605                if (l == null) {
606                    throw new InternalError
607                        ("Must have found at least identity conversion");
608                }
609
610                // Fell through; given object is null or invalid. According to
611                // the spec, we can throw IllegalArgumentException for both of
612                // these cases.
613
614                l.bind();
615                cb.opc_new(illegalArgumentClass);
616                cb.opc_dup();
617                cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0);
618                cb.opc_athrow();
619            } else {
620                // Emit appropriate checkcast
621                cb.opc_checkcast(paramTypeCPIdx);
622                paramTypeCPIdx = add(paramTypeCPIdx, S2);
623                // Fall through to next argument
624            }
625        }
626        // Bind last goto if present
627        if (nextParamLabel != null) {
628            nextParamLabel.bind();
629        }
630
631        short invokeStartPC = cb.getLength();
632
633        // OK, ready to perform the invocation.
634        if (isConstructor) {
635            cb.opc_invokespecial(targetMethodRef, count, 0);
636        } else {
637            if (isStatic()) {
638                cb.opc_invokestatic(targetMethodRef,
639                                    count,
640                                    typeSizeInStackSlots(returnType));
641            } else {
642                if (isInterface()) {
643                    if (isPrivate()) {
644                        cb.opc_invokespecial(targetMethodRef, count, 0);
645                    } else {
646                        cb.opc_invokeinterface(targetMethodRef,
647                                               count,
648                                               count,
649                                               typeSizeInStackSlots(returnType));
650                    }
651                } else {
652                    cb.opc_invokevirtual(targetMethodRef,
653                                         count,
654                                         typeSizeInStackSlots(returnType));
655                }
656            }
657        }
658
659        short invokeEndPC = cb.getLength();
660
661        if (!isConstructor) {
662            // Box return value if necessary
663            if (isPrimitive(returnType)) {
664                cb.opc_invokestatic(boxingMethodForPrimitiveType(returnType),
665                                    typeSizeInStackSlots(returnType),
666                                    0);
667            } else if (returnType == Void.TYPE) {
668                cb.opc_aconst_null();
669            }
670        }
671        cb.opc_areturn();
672
673        // We generate two exception handlers; one which is responsible
674        // for catching ClassCastException and NullPointerException and
675        // throwing IllegalArgumentException, and the other which catches
676        // all java/lang/Throwable objects thrown from the target method
677        // and wraps them in InvocationTargetExceptions.
678
679        short classCastHandler = cb.getLength();
680
681        // ClassCast, etc. exception handler
682        cb.setStack(1);
683        cb.opc_invokespecial(toStringIdx, 0, 1);
684        cb.opc_new(illegalArgumentClass);
685        cb.opc_dup_x1();
686        cb.opc_swap();
687        cb.opc_invokespecial(illegalArgumentStringCtorIdx, 1, 0);
688        cb.opc_athrow();
689
690        short invocationTargetHandler = cb.getLength();
691
692        // InvocationTargetException exception handler
693        cb.setStack(1);
694        cb.opc_new(invocationTargetClass);
695        cb.opc_dup_x1();
696        cb.opc_swap();
697        cb.opc_invokespecial(invocationTargetCtorIdx, 1, 0);
698        cb.opc_athrow();
699
700        // Generate exception table. We cover the entire code sequence
701        // with an exception handler which catches ClassCastException and
702        // converts it into an IllegalArgumentException.
703
704        ClassFileAssembler exc = new ClassFileAssembler();
705
706        exc.emitShort(illegalArgStartPC);       // start PC
707        exc.emitShort(invokeStartPC);           // end PC
708        exc.emitShort(classCastHandler);        // handler PC
709        exc.emitShort(classCastClass);          // catch type
710
711        exc.emitShort(illegalArgStartPC);       // start PC
712        exc.emitShort(invokeStartPC);           // end PC
713        exc.emitShort(classCastHandler);        // handler PC
714        exc.emitShort(nullPointerClass);        // catch type
715
716        exc.emitShort(invokeStartPC);           // start PC
717        exc.emitShort(invokeEndPC);             // end PC
718        exc.emitShort(invocationTargetHandler); // handler PC
719        exc.emitShort(throwableClass);          // catch type
720
721        emitMethod(invokeIdx, cb.getMaxLocals(), cb, exc,
722                   new short[] { invocationTargetClass });
723    }
724
725    private boolean usesPrimitiveTypes() {
726        // We need to emit boxing/unboxing constant pool information if
727        // the method takes a primitive type for any of its parameters or
728        // returns a primitive value (except void)
729        if (returnType.isPrimitive()) {
730            return true;
731        }
732        for (int i = 0; i < parameterTypes.length; i++) {
733            if (parameterTypes[i].isPrimitive()) {
734                return true;
735            }
736        }
737        return false;
738    }
739
740    private int numNonPrimitiveParameterTypes() {
741        int num = 0;
742        for (int i = 0; i < parameterTypes.length; i++) {
743            if (!parameterTypes[i].isPrimitive()) {
744                ++num;
745            }
746        }
747        return num;
748    }
749
750    private boolean isInterface() {
751        return declaringClass.isInterface();
752    }
753
754    private String buildInternalSignature() {
755        StringBuilder sb = new StringBuilder();
756        sb.append("(");
757        for (int i = 0; i < parameterTypes.length; i++) {
758            sb.append(getClassName(parameterTypes[i], true));
759        }
760        sb.append(")");
761        sb.append(getClassName(returnType, true));
762        return sb.toString();
763    }
764
765    private static synchronized String generateName(boolean isConstructor,
766                                                    boolean forSerialization)
767    {
768        if (isConstructor) {
769            if (forSerialization) {
770                int num = ++serializationConstructorSymnum;
771                return "jdk/internal/reflect/GeneratedSerializationConstructorAccessor" + num;
772            } else {
773                int num = ++constructorSymnum;
774                return "jdk/internal/reflect/GeneratedConstructorAccessor" + num;
775            }
776        } else {
777            int num = ++methodSymnum;
778            return "jdk/internal/reflect/GeneratedMethodAccessor" + num;
779        }
780    }
781}
782