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 
 26 package jdk.internal.reflect;
 27 
 28 import java.lang.reflect.*;
 29 import jdk.internal.misc.Unsafe;
 30 
 31 /** Shared functionality for all accessor generators */
 32 
 33 class 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 c.descriptorString();
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 }