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.lang.reflect.*;
29import jdk.internal.misc.Unsafe;
30
31/** Shared functionality for all accessor generators */
32
33class AccessorGenerator implements ClassFileConstants {
34    static final Unsafe unsafe = Unsafe.getUnsafe();
35
36    // Constants because there's no way to say "short integer constant",
37    // i.e., "1S"
38    protected static final short S0 = (short) 0;
39    protected static final short S1 = (short) 1;
40    protected static final short S2 = (short) 2;
41    protected static final short S3 = (short) 3;
42    protected static final short S4 = (short) 4;
43    protected static final short S5 = (short) 5;
44    protected static final short S6 = (short) 6;
45
46    // Instance variables for shared functionality between
47    // FieldAccessorGenerator and MethodAccessorGenerator
48    protected ClassFileAssembler asm;
49    protected int   modifiers;
50    protected short thisClass;
51    protected short superClass;
52    protected short targetClass;
53    // Common constant pool entries to FieldAccessor and MethodAccessor
54    protected short throwableClass;
55    protected short classCastClass;
56    protected short nullPointerClass;
57    protected short illegalArgumentClass;
58    protected short invocationTargetClass;
59    protected short initIdx;
60    protected short initNameAndTypeIdx;
61    protected short initStringNameAndTypeIdx;
62    protected short nullPointerCtorIdx;
63    protected short illegalArgumentCtorIdx;
64    protected short illegalArgumentStringCtorIdx;
65    protected short invocationTargetCtorIdx;
66    protected short superCtorIdx;
67    protected short objectClass;
68    protected short toStringIdx;
69    protected short codeIdx;
70    protected short exceptionsIdx;
71    // Boxing
72    protected short valueOfIdx;
73    protected short booleanIdx;
74    protected short booleanBoxIdx;
75    protected short booleanUnboxIdx;
76    protected short byteIdx;
77    protected short byteBoxIdx;
78    protected short byteUnboxIdx;
79    protected short characterIdx;
80    protected short characterBoxIdx;
81    protected short characterUnboxIdx;
82    protected short doubleIdx;
83    protected short doubleBoxIdx;
84    protected short doubleUnboxIdx;
85    protected short floatIdx;
86    protected short floatBoxIdx;
87    protected short floatUnboxIdx;
88    protected short integerIdx;
89    protected short integerBoxIdx;
90    protected short integerUnboxIdx;
91    protected short longIdx;
92    protected short longBoxIdx;
93    protected short longUnboxIdx;
94    protected short shortIdx;
95    protected short shortBoxIdx;
96    protected short shortUnboxIdx;
97
98    protected final short NUM_COMMON_CPOOL_ENTRIES = (short) 30;
99    protected final short NUM_BOXING_CPOOL_ENTRIES = (short) 73;
100
101    // Requires that superClass has been set up
102    protected void emitCommonConstantPoolEntries() {
103        // +   [UTF-8] "java/lang/Throwable"
104        // +   [CONSTANT_Class_info] for above
105        // +   [UTF-8] "java/lang/ClassCastException"
106        // +   [CONSTANT_Class_info] for above
107        // +   [UTF-8] "java/lang/NullPointerException"
108        // +   [CONSTANT_Class_info] for above
109        // +   [UTF-8] "java/lang/IllegalArgumentException"
110        // +   [CONSTANT_Class_info] for above
111        // +   [UTF-8] "java/lang/InvocationTargetException"
112        // +   [CONSTANT_Class_info] for above
113        // +   [UTF-8] "<init>"
114        // +   [UTF-8] "()V"
115        // +   [CONSTANT_NameAndType_info] for above
116        // +   [CONSTANT_Methodref_info] for NullPointerException's constructor
117        // +   [CONSTANT_Methodref_info] for IllegalArgumentException's constructor
118        // +   [UTF-8] "(Ljava/lang/String;)V"
119        // +   [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/String;)V"
120        // +   [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String
121        // +   [UTF-8] "(Ljava/lang/Throwable;)V"
122        // +   [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/Throwable;)V"
123        // +   [CONSTANT_Methodref_info] for InvocationTargetException's constructor
124        // +   [CONSTANT_Methodref_info] for "super()"
125        // +   [UTF-8] "java/lang/Object"
126        // +   [CONSTANT_Class_info] for above
127        // +   [UTF-8] "toString"
128        // +   [UTF-8] "()Ljava/lang/String;"
129        // +   [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;"
130        // +   [CONSTANT_Methodref_info] for Object's toString method
131        // +   [UTF-8] "Code"
132        // +   [UTF-8] "Exceptions"
133        asm.emitConstantPoolUTF8("java/lang/Throwable");
134        asm.emitConstantPoolClass(asm.cpi());
135        throwableClass = asm.cpi();
136        asm.emitConstantPoolUTF8("java/lang/ClassCastException");
137        asm.emitConstantPoolClass(asm.cpi());
138        classCastClass = asm.cpi();
139        asm.emitConstantPoolUTF8("java/lang/NullPointerException");
140        asm.emitConstantPoolClass(asm.cpi());
141        nullPointerClass = asm.cpi();
142        asm.emitConstantPoolUTF8("java/lang/IllegalArgumentException");
143        asm.emitConstantPoolClass(asm.cpi());
144        illegalArgumentClass = asm.cpi();
145        asm.emitConstantPoolUTF8("java/lang/reflect/InvocationTargetException");
146        asm.emitConstantPoolClass(asm.cpi());
147        invocationTargetClass = asm.cpi();
148        asm.emitConstantPoolUTF8("<init>");
149        initIdx = asm.cpi();
150        asm.emitConstantPoolUTF8("()V");
151        asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
152        initNameAndTypeIdx = asm.cpi();
153        asm.emitConstantPoolMethodref(nullPointerClass, initNameAndTypeIdx);
154        nullPointerCtorIdx = asm.cpi();
155        asm.emitConstantPoolMethodref(illegalArgumentClass, initNameAndTypeIdx);
156        illegalArgumentCtorIdx = asm.cpi();
157        asm.emitConstantPoolUTF8("(Ljava/lang/String;)V");
158        asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
159        initStringNameAndTypeIdx = asm.cpi();
160        asm.emitConstantPoolMethodref(illegalArgumentClass, initStringNameAndTypeIdx);
161        illegalArgumentStringCtorIdx = asm.cpi();
162        asm.emitConstantPoolUTF8("(Ljava/lang/Throwable;)V");
163        asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
164        asm.emitConstantPoolMethodref(invocationTargetClass, asm.cpi());
165        invocationTargetCtorIdx = asm.cpi();
166        asm.emitConstantPoolMethodref(superClass, initNameAndTypeIdx);
167        superCtorIdx = asm.cpi();
168        asm.emitConstantPoolUTF8("java/lang/Object");
169        asm.emitConstantPoolClass(asm.cpi());
170        objectClass = asm.cpi();
171        asm.emitConstantPoolUTF8("toString");
172        asm.emitConstantPoolUTF8("()Ljava/lang/String;");
173        asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
174        asm.emitConstantPoolMethodref(objectClass, asm.cpi());
175        toStringIdx = asm.cpi();
176        asm.emitConstantPoolUTF8("Code");
177        codeIdx = asm.cpi();
178        asm.emitConstantPoolUTF8("Exceptions");
179        exceptionsIdx = asm.cpi();
180    }
181
182    /** Constant pool entries required to be able to box/unbox primitive
183        types. Note that we don't emit these if we don't need them. */
184    protected void emitBoxingContantPoolEntries() {
185        //  *  [UTF-8] "valueOf"
186        //  *  [UTF-8] "java/lang/Boolean"
187        //  *  [CONSTANT_Class_info] for above
188        //  *  [UTF-8] "(Z)Ljava/lang/Boolean;"
189        //  *  [CONSTANT_NameAndType_info] for above
190        //  *  [CONSTANT_Methodref_info] for above
191        //  *  [UTF-8] "booleanValue"
192        //  *  [UTF-8] "()Z"
193        //  *  [CONSTANT_NameAndType_info] for above
194        //  *  [CONSTANT_Methodref_info] for above
195        //  *  [UTF-8] "java/lang/Byte"
196        //  *  [CONSTANT_Class_info] for above
197        //  *  [UTF-8] "(B)Ljava/lang/Byte;"
198        //  *  [CONSTANT_NameAndType_info] for above
199        //  *  [CONSTANT_Methodref_info] for above
200        //  *  [UTF-8] "byteValue"
201        //  *  [UTF-8] "()B"
202        //  *  [CONSTANT_NameAndType_info] for above
203        //  *  [CONSTANT_Methodref_info] for above
204        //  *  [UTF-8] "java/lang/Character"
205        //  *  [CONSTANT_Class_info] for above
206        //  *  [UTF-8] "(C)Ljava/lang/Character;"
207        //  *  [CONSTANT_NameAndType_info] for above
208        //  *  [CONSTANT_Methodref_info] for above
209        //  *  [UTF-8] "charValue"
210        //  *  [UTF-8] "()C"
211        //  *  [CONSTANT_NameAndType_info] for above
212        //  *  [CONSTANT_Methodref_info] for above
213        //  *  [UTF-8] "java/lang/Double"
214        //  *  [CONSTANT_Class_info] for above
215        //  *  [UTF-8] "(D)Ljava/lang/Double;"
216        //  *  [CONSTANT_NameAndType_info] for above
217        //  *  [CONSTANT_Methodref_info] for above
218        //  *  [UTF-8] "doubleValue"
219        //  *  [UTF-8] "()D"
220        //  *  [CONSTANT_NameAndType_info] for above
221        //  *  [CONSTANT_Methodref_info] for above
222        //  *  [UTF-8] "java/lang/Float"
223        //  *  [CONSTANT_Class_info] for above
224        //  *  [UTF-8] "(F)Ljava/lang/Float;"
225        //  *  [CONSTANT_NameAndType_info] for above
226        //  *  [CONSTANT_Methodref_info] for above
227        //  *  [UTF-8] "floatValue"
228        //  *  [UTF-8] "()F"
229        //  *  [CONSTANT_NameAndType_info] for above
230        //  *  [CONSTANT_Methodref_info] for above
231        //  *  [UTF-8] "java/lang/Integer"
232        //  *  [CONSTANT_Class_info] for above
233        //  *  [UTF-8] "(I)Ljava/lang/Integer;"
234        //  *  [CONSTANT_NameAndType_info] for above
235        //  *  [CONSTANT_Methodref_info] for above
236        //  *  [UTF-8] "intValue"
237        //  *  [UTF-8] "()I"
238        //  *  [CONSTANT_NameAndType_info] for above
239        //  *  [CONSTANT_Methodref_info] for above
240        //  *  [UTF-8] "java/lang/Long"
241        //  *  [CONSTANT_Class_info] for above
242        //  *  [UTF-8] "(J)Ljava/lang/Long;"
243        //  *  [CONSTANT_NameAndType_info] for above
244        //  *  [CONSTANT_Methodref_info] for above
245        //  *  [UTF-8] "longValue"
246        //  *  [UTF-8] "()J"
247        //  *  [CONSTANT_NameAndType_info] for above
248        //  *  [CONSTANT_Methodref_info] for above
249        //  *  [UTF-8] "java/lang/Short"
250        //  *  [CONSTANT_Class_info] for above
251        //  *  [UTF-8] "(S)Ljava/lang/Short;"
252        //  *  [CONSTANT_NameAndType_info] for above
253        //  *  [CONSTANT_Methodref_info] for above
254        //  *  [UTF-8] "shortValue"
255        //  *  [UTF-8] "()S"
256        //  *  [CONSTANT_NameAndType_info] for above
257        //  *  [CONSTANT_Methodref_info] for above
258
259        // valueOf-method name
260        asm.emitConstantPoolUTF8("valueOf");
261        valueOfIdx = asm.cpi();
262
263        // Boolean
264        asm.emitConstantPoolUTF8("java/lang/Boolean");
265        asm.emitConstantPoolClass(asm.cpi());
266        booleanIdx = asm.cpi();
267        asm.emitConstantPoolUTF8("(Z)Ljava/lang/Boolean;");
268        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
269        asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
270        booleanBoxIdx = asm.cpi();
271        asm.emitConstantPoolUTF8("booleanValue");
272        asm.emitConstantPoolUTF8("()Z");
273        asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
274        asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
275        booleanUnboxIdx = asm.cpi();
276
277        // Byte
278        asm.emitConstantPoolUTF8("java/lang/Byte");
279        asm.emitConstantPoolClass(asm.cpi());
280        byteIdx = asm.cpi();
281        asm.emitConstantPoolUTF8("(B)Ljava/lang/Byte;");
282        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
283        asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
284        byteBoxIdx = asm.cpi();
285        asm.emitConstantPoolUTF8("byteValue");
286        asm.emitConstantPoolUTF8("()B");
287        asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
288        asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
289        byteUnboxIdx = asm.cpi();
290
291        // Character
292        asm.emitConstantPoolUTF8("java/lang/Character");
293        asm.emitConstantPoolClass(asm.cpi());
294        characterIdx = asm.cpi();
295        asm.emitConstantPoolUTF8("(C)Ljava/lang/Character;");
296        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
297        asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
298        characterBoxIdx = asm.cpi();
299        asm.emitConstantPoolUTF8("charValue");
300        asm.emitConstantPoolUTF8("()C");
301        asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
302        asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
303        characterUnboxIdx = asm.cpi();
304
305        // Double
306        asm.emitConstantPoolUTF8("java/lang/Double");
307        asm.emitConstantPoolClass(asm.cpi());
308        doubleIdx = asm.cpi();
309        asm.emitConstantPoolUTF8("(D)Ljava/lang/Double;");
310        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
311        asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
312        doubleBoxIdx = asm.cpi();
313        asm.emitConstantPoolUTF8("doubleValue");
314        asm.emitConstantPoolUTF8("()D");
315        asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
316        asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
317        doubleUnboxIdx = asm.cpi();
318
319        // Float
320        asm.emitConstantPoolUTF8("java/lang/Float");
321        asm.emitConstantPoolClass(asm.cpi());
322        floatIdx = asm.cpi();
323        asm.emitConstantPoolUTF8("(F)Ljava/lang/Float;");
324        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
325        asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
326        floatBoxIdx = asm.cpi();
327        asm.emitConstantPoolUTF8("floatValue");
328        asm.emitConstantPoolUTF8("()F");
329        asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
330        asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
331        floatUnboxIdx = asm.cpi();
332
333        // Integer
334        asm.emitConstantPoolUTF8("java/lang/Integer");
335        asm.emitConstantPoolClass(asm.cpi());
336        integerIdx = asm.cpi();
337        asm.emitConstantPoolUTF8("(I)Ljava/lang/Integer;");
338        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
339        asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
340        integerBoxIdx = asm.cpi();
341        asm.emitConstantPoolUTF8("intValue");
342        asm.emitConstantPoolUTF8("()I");
343        asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
344        asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
345        integerUnboxIdx = asm.cpi();
346
347        // Long
348        asm.emitConstantPoolUTF8("java/lang/Long");
349        asm.emitConstantPoolClass(asm.cpi());
350        longIdx = asm.cpi();
351        asm.emitConstantPoolUTF8("(J)Ljava/lang/Long;");
352        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
353        asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
354        longBoxIdx = asm.cpi();
355        asm.emitConstantPoolUTF8("longValue");
356        asm.emitConstantPoolUTF8("()J");
357        asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
358        asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
359        longUnboxIdx = asm.cpi();
360
361        // Short
362        asm.emitConstantPoolUTF8("java/lang/Short");
363        asm.emitConstantPoolClass(asm.cpi());
364        shortIdx = asm.cpi();
365        asm.emitConstantPoolUTF8("(S)Ljava/lang/Short;");
366        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
367        asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
368        shortBoxIdx = asm.cpi();
369        asm.emitConstantPoolUTF8("shortValue");
370        asm.emitConstantPoolUTF8("()S");
371        asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
372        asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi());
373        shortUnboxIdx = asm.cpi();
374    }
375
376    // Necessary because of Java's annoying promotion rules
377    protected static short add(short s1, short s2) {
378        return (short) (s1 + s2);
379    }
380
381    protected static short sub(short s1, short s2) {
382        return (short) (s1 - s2);
383    }
384
385    protected boolean isStatic() {
386        return Modifier.isStatic(modifiers);
387    }
388
389    protected boolean isPrivate() {
390        return Modifier.isPrivate(modifiers);
391    }
392
393    /** Returns class name in "internal" form (i.e., '/' separators
394        instead of '.') */
395    protected static String getClassName
396        (Class<?> c, boolean addPrefixAndSuffixForNonPrimitiveTypes)
397    {
398        if (c.isPrimitive()) {
399            if (c == Boolean.TYPE) {
400                return "Z";
401            } else if (c == Byte.TYPE) {
402                return "B";
403            } else if (c == Character.TYPE) {
404                return "C";
405            } else if (c == Double.TYPE) {
406                return "D";
407            } else if (c == Float.TYPE) {
408                return "F";
409            } else if (c == Integer.TYPE) {
410                return "I";
411            } else if (c == Long.TYPE) {
412                return "J";
413            } else if (c == Short.TYPE) {
414                return "S";
415            } else if (c == Void.TYPE) {
416                return "V";
417            }
418            throw new InternalError("Should have found primitive type");
419        } else if (c.isArray()) {
420            return "[" + getClassName(c.getComponentType(), true);
421        } else {
422            if (addPrefixAndSuffixForNonPrimitiveTypes) {
423                return internalize("L" + c.getName() + ";");
424            } else {
425                return internalize(c.getName());
426            }
427        }
428    }
429
430    private static String internalize(String className) {
431        return className.replace('.', '/');
432    }
433
434    protected void emitConstructor() {
435        // Generate code into fresh code buffer
436        ClassFileAssembler cb = new ClassFileAssembler();
437        // 0 incoming arguments
438        cb.setMaxLocals(1);
439        cb.opc_aload_0();
440        cb.opc_invokespecial(superCtorIdx, 0, 0);
441        cb.opc_return();
442
443        // Emit method
444        emitMethod(initIdx, cb.getMaxLocals(), cb, null, null);
445    }
446
447    // The descriptor's index in the constant pool must be (1 +
448    // nameIdx). "numArgs" must indicate ALL arguments, including the
449    // implicit "this" argument; double and long arguments each count
450    // as 2 in this count. The code buffer must NOT contain the code
451    // length. The exception table may be null, but if non-null must
452    // NOT contain the exception table's length. The checked exception
453    // indices may be null.
454    protected void emitMethod(short nameIdx,
455                              int numArgs,
456                              ClassFileAssembler code,
457                              ClassFileAssembler exceptionTable,
458                              short[] checkedExceptionIndices)
459    {
460        int codeLen = code.getLength();
461        int excLen  = 0;
462        if (exceptionTable != null) {
463            excLen = exceptionTable.getLength();
464            if ((excLen % 8) != 0) {
465                throw new IllegalArgumentException("Illegal exception table");
466            }
467        }
468        int attrLen = 12 + codeLen + excLen;
469        excLen = excLen / 8; // No-op if no exception table
470
471        asm.emitShort(ACC_PUBLIC);
472        asm.emitShort(nameIdx);
473        asm.emitShort(add(nameIdx, S1));
474        if (checkedExceptionIndices == null) {
475            // Code attribute only
476            asm.emitShort(S1);
477        } else {
478            // Code and Exceptions attributes
479            asm.emitShort(S2);
480        }
481        // Code attribute
482        asm.emitShort(codeIdx);
483        asm.emitInt(attrLen);
484        asm.emitShort(code.getMaxStack());
485        asm.emitShort((short) Math.max(numArgs, code.getMaxLocals()));
486        asm.emitInt(codeLen);
487        asm.append(code);
488        asm.emitShort((short) excLen);
489        if (exceptionTable != null) {
490            asm.append(exceptionTable);
491        }
492        asm.emitShort(S0); // No additional attributes for Code attribute
493        if (checkedExceptionIndices != null) {
494            // Exceptions attribute
495            asm.emitShort(exceptionsIdx);
496            asm.emitInt(2 + 2 * checkedExceptionIndices.length);
497            asm.emitShort((short) checkedExceptionIndices.length);
498            for (int i = 0; i < checkedExceptionIndices.length; i++) {
499                asm.emitShort(checkedExceptionIndices[i]);
500            }
501        }
502    }
503
504    protected short indexForPrimitiveType(Class<?> type) {
505        if (type == Boolean.TYPE) {
506            return booleanIdx;
507        } else if (type == Byte.TYPE) {
508            return byteIdx;
509        } else if (type == Character.TYPE) {
510            return characterIdx;
511        } else if (type == Double.TYPE) {
512            return doubleIdx;
513        } else if (type == Float.TYPE) {
514            return floatIdx;
515        } else if (type == Integer.TYPE) {
516            return integerIdx;
517        } else if (type == Long.TYPE) {
518            return longIdx;
519        } else if (type == Short.TYPE) {
520            return shortIdx;
521        }
522        throw new InternalError("Should have found primitive type");
523    }
524
525    protected short boxingMethodForPrimitiveType(Class<?> type) {
526        if (type == Boolean.TYPE) {
527            return booleanBoxIdx;
528        } else if (type == Byte.TYPE) {
529            return byteBoxIdx;
530        } else if (type == Character.TYPE) {
531            return characterBoxIdx;
532        } else if (type == Double.TYPE) {
533            return doubleBoxIdx;
534        } else if (type == Float.TYPE) {
535            return floatBoxIdx;
536        } else if (type == Integer.TYPE) {
537            return integerBoxIdx;
538        } else if (type == Long.TYPE) {
539            return longBoxIdx;
540        } else if (type == Short.TYPE) {
541            return shortBoxIdx;
542        }
543        throw new InternalError("Should have found primitive type");
544    }
545
546    /** Returns true for widening or identity conversions for primitive
547        types only */
548    protected static boolean canWidenTo(Class<?> type, Class<?> otherType) {
549        if (!type.isPrimitive()) {
550            return false;
551        }
552
553        // Widening conversions (from JVM spec):
554        //  byte to short, int, long, float, or double
555        //  short to int, long, float, or double
556        //  char to int, long, float, or double
557        //  int to long, float, or double
558        //  long to float or double
559        //  float to double
560
561        if (type == Boolean.TYPE) {
562            if (otherType == Boolean.TYPE) {
563                return true;
564            }
565        } else if (type == Byte.TYPE) {
566            if (   otherType == Byte.TYPE
567                   || otherType == Short.TYPE
568                   || otherType == Integer.TYPE
569                   || otherType == Long.TYPE
570                   || otherType == Float.TYPE
571                   || otherType == Double.TYPE) {
572                return true;
573            }
574        } else if (type == Short.TYPE) {
575            if (   otherType == Short.TYPE
576                   || otherType == Integer.TYPE
577                   || otherType == Long.TYPE
578                   || otherType == Float.TYPE
579                   || otherType == Double.TYPE) {
580                return true;
581            }
582        } else if (type == Character.TYPE) {
583            if (   otherType == Character.TYPE
584                   || otherType == Integer.TYPE
585                   || otherType == Long.TYPE
586                   || otherType == Float.TYPE
587                   || otherType == Double.TYPE) {
588                return true;
589            }
590        } else if (type == Integer.TYPE) {
591            if (   otherType == Integer.TYPE
592                   || otherType == Long.TYPE
593                   || otherType == Float.TYPE
594                   || otherType == Double.TYPE) {
595                return true;
596            }
597        } else if (type == Long.TYPE) {
598            if (   otherType == Long.TYPE
599                   || otherType == Float.TYPE
600                   || otherType == Double.TYPE) {
601                return true;
602            }
603        } else if (type == Float.TYPE) {
604            if (   otherType == Float.TYPE
605                   || otherType == Double.TYPE) {
606                return true;
607            }
608        } else if (type == Double.TYPE) {
609            if (otherType == Double.TYPE) {
610                return true;
611            }
612        }
613
614        return false;
615    }
616
617    /** Emits the widening bytecode for the given primitive conversion
618        (or none if the identity conversion). Requires that a primitive
619        conversion exists; i.e., canWidenTo must have already been
620        called and returned true. */
621    protected static void emitWideningBytecodeForPrimitiveConversion
622        (ClassFileAssembler cb,
623         Class<?> fromType,
624         Class<?> toType)
625    {
626        // Note that widening conversions for integral types (i.e., "b2s",
627        // "s2i") are no-ops since values on the Java stack are
628        // sign-extended.
629
630        // Widening conversions (from JVM spec):
631        //  byte to short, int, long, float, or double
632        //  short to int, long, float, or double
633        //  char to int, long, float, or double
634        //  int to long, float, or double
635        //  long to float or double
636        //  float to double
637
638        if (   fromType == Byte.TYPE
639               || fromType == Short.TYPE
640               || fromType == Character.TYPE
641               || fromType == Integer.TYPE) {
642            if (toType == Long.TYPE) {
643                cb.opc_i2l();
644            } else if (toType == Float.TYPE) {
645                cb.opc_i2f();
646            } else if (toType == Double.TYPE) {
647                cb.opc_i2d();
648            }
649        } else if (fromType == Long.TYPE) {
650            if (toType == Float.TYPE) {
651                cb.opc_l2f();
652            } else if (toType == Double.TYPE) {
653                cb.opc_l2d();
654            }
655        } else if (fromType == Float.TYPE) {
656            if (toType == Double.TYPE) {
657                cb.opc_f2d();
658            }
659        }
660
661        // Otherwise, was identity or no-op conversion. Fall through.
662    }
663
664    protected short unboxingMethodForPrimitiveType(Class<?> primType) {
665        if (primType == Boolean.TYPE) {
666            return booleanUnboxIdx;
667        } else if (primType == Byte.TYPE) {
668            return byteUnboxIdx;
669        } else if (primType == Character.TYPE) {
670            return characterUnboxIdx;
671        } else if (primType == Short.TYPE) {
672            return shortUnboxIdx;
673        } else if (primType == Integer.TYPE) {
674            return integerUnboxIdx;
675        } else if (primType == Long.TYPE) {
676            return longUnboxIdx;
677        } else if (primType == Float.TYPE) {
678            return floatUnboxIdx;
679        } else if (primType == Double.TYPE) {
680            return doubleUnboxIdx;
681        }
682        throw new InternalError("Illegal primitive type " + primType.getName());
683    }
684
685    protected static final Class<?>[] primitiveTypes = new Class<?>[] {
686        Boolean.TYPE,
687        Byte.TYPE,
688        Character.TYPE,
689        Short.TYPE,
690        Integer.TYPE,
691        Long.TYPE,
692        Float.TYPE,
693        Double.TYPE
694    };
695
696    /** We don't consider "Void" to be a primitive type */
697    protected static boolean isPrimitive(Class<?> c) {
698        return (c.isPrimitive() && c != Void.TYPE);
699    }
700
701    protected int typeSizeInStackSlots(Class<?> c) {
702        if (c == Void.TYPE) {
703            return 0;
704        }
705        if (c == Long.TYPE || c == Double.TYPE) {
706            return 2;
707        }
708        return 1;
709    }
710
711    private ClassFileAssembler illegalArgumentCodeBuffer;
712    protected ClassFileAssembler illegalArgumentCodeBuffer() {
713        if (illegalArgumentCodeBuffer == null) {
714            illegalArgumentCodeBuffer = new ClassFileAssembler();
715            illegalArgumentCodeBuffer.opc_new(illegalArgumentClass);
716            illegalArgumentCodeBuffer.opc_dup();
717            illegalArgumentCodeBuffer.opc_invokespecial(illegalArgumentCtorIdx, 0, 0);
718            illegalArgumentCodeBuffer.opc_athrow();
719        }
720
721        return illegalArgumentCodeBuffer;
722    }
723}
724