diff -r fd16c54261b3 -r 90ce3da70b43 jdk/src/share/classes/sun/reflect/AccessorGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/reflect/AccessorGenerator.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,712 @@ +/* + * Copyright 2001 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.reflect; + +import java.lang.reflect.*; +import sun.misc.Unsafe; + +/** Shared functionality for all accessor generators */ + +class AccessorGenerator implements ClassFileConstants { + static final Unsafe unsafe = Unsafe.getUnsafe(); + + // Constants because there's no way to say "short integer constant", + // i.e., "1S" + protected static final short S0 = (short) 0; + protected static final short S1 = (short) 1; + protected static final short S2 = (short) 2; + protected static final short S3 = (short) 3; + protected static final short S4 = (short) 4; + protected static final short S5 = (short) 5; + protected static final short S6 = (short) 6; + + // Instance variables for shared functionality between + // FieldAccessorGenerator and MethodAccessorGenerator + protected ClassFileAssembler asm; + protected int modifiers; + protected short thisClass; + protected short superClass; + protected short targetClass; + // Common constant pool entries to FieldAccessor and MethodAccessor + protected short throwableClass; + protected short classCastClass; + protected short nullPointerClass; + protected short illegalArgumentClass; + protected short invocationTargetClass; + protected short initIdx; + protected short initNameAndTypeIdx; + protected short initStringNameAndTypeIdx; + protected short nullPointerCtorIdx; + protected short illegalArgumentCtorIdx; + protected short illegalArgumentStringCtorIdx; + protected short invocationTargetCtorIdx; + protected short superCtorIdx; + protected short objectClass; + protected short toStringIdx; + protected short codeIdx; + protected short exceptionsIdx; + // Boxing + protected short booleanIdx; + protected short booleanCtorIdx; + protected short booleanUnboxIdx; + protected short byteIdx; + protected short byteCtorIdx; + protected short byteUnboxIdx; + protected short characterIdx; + protected short characterCtorIdx; + protected short characterUnboxIdx; + protected short doubleIdx; + protected short doubleCtorIdx; + protected short doubleUnboxIdx; + protected short floatIdx; + protected short floatCtorIdx; + protected short floatUnboxIdx; + protected short integerIdx; + protected short integerCtorIdx; + protected short integerUnboxIdx; + protected short longIdx; + protected short longCtorIdx; + protected short longUnboxIdx; + protected short shortIdx; + protected short shortCtorIdx; + protected short shortUnboxIdx; + + protected final short NUM_COMMON_CPOOL_ENTRIES = (short) 30; + protected final short NUM_BOXING_CPOOL_ENTRIES = (short) 72; + + // Requires that superClass has been set up + protected void emitCommonConstantPoolEntries() { + // + [UTF-8] "java/lang/Throwable" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "java/lang/ClassCastException" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "java/lang/NullPointerException" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "java/lang/IllegalArgumentException" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "java/lang/InvocationTargetException" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "" + // + [UTF-8] "()V" + // + [CONSTANT_NameAndType_info] for above + // + [CONSTANT_Methodref_info] for NullPointerException's constructor + // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor + // + [UTF-8] "(Ljava/lang/String;)V" + // + [CONSTANT_NameAndType_info] for "(Ljava/lang/String;)V" + // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String + // + [UTF-8] "(Ljava/lang/Throwable;)V" + // + [CONSTANT_NameAndType_info] for "(Ljava/lang/Throwable;)V" + // + [CONSTANT_Methodref_info] for InvocationTargetException's constructor + // + [CONSTANT_Methodref_info] for "super()" + // + [UTF-8] "java/lang/Object" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "toString" + // + [UTF-8] "()Ljava/lang/String;" + // + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;" + // + [CONSTANT_Methodref_info] for Object's toString method + // + [UTF-8] "Code" + // + [UTF-8] "Exceptions" + asm.emitConstantPoolUTF8("java/lang/Throwable"); + asm.emitConstantPoolClass(asm.cpi()); + throwableClass = asm.cpi(); + asm.emitConstantPoolUTF8("java/lang/ClassCastException"); + asm.emitConstantPoolClass(asm.cpi()); + classCastClass = asm.cpi(); + asm.emitConstantPoolUTF8("java/lang/NullPointerException"); + asm.emitConstantPoolClass(asm.cpi()); + nullPointerClass = asm.cpi(); + asm.emitConstantPoolUTF8("java/lang/IllegalArgumentException"); + asm.emitConstantPoolClass(asm.cpi()); + illegalArgumentClass = asm.cpi(); + asm.emitConstantPoolUTF8("java/lang/reflect/InvocationTargetException"); + asm.emitConstantPoolClass(asm.cpi()); + invocationTargetClass = asm.cpi(); + asm.emitConstantPoolUTF8(""); + initIdx = asm.cpi(); + asm.emitConstantPoolUTF8("()V"); + asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + initNameAndTypeIdx = asm.cpi(); + asm.emitConstantPoolMethodref(nullPointerClass, initNameAndTypeIdx); + nullPointerCtorIdx = asm.cpi(); + asm.emitConstantPoolMethodref(illegalArgumentClass, initNameAndTypeIdx); + illegalArgumentCtorIdx = asm.cpi(); + asm.emitConstantPoolUTF8("(Ljava/lang/String;)V"); + asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + initStringNameAndTypeIdx = asm.cpi(); + asm.emitConstantPoolMethodref(illegalArgumentClass, initStringNameAndTypeIdx); + illegalArgumentStringCtorIdx = asm.cpi(); + asm.emitConstantPoolUTF8("(Ljava/lang/Throwable;)V"); + asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolMethodref(invocationTargetClass, asm.cpi()); + invocationTargetCtorIdx = asm.cpi(); + asm.emitConstantPoolMethodref(superClass, initNameAndTypeIdx); + superCtorIdx = asm.cpi(); + asm.emitConstantPoolUTF8("java/lang/Object"); + asm.emitConstantPoolClass(asm.cpi()); + objectClass = asm.cpi(); + asm.emitConstantPoolUTF8("toString"); + asm.emitConstantPoolUTF8("()Ljava/lang/String;"); + asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); + asm.emitConstantPoolMethodref(objectClass, asm.cpi()); + toStringIdx = asm.cpi(); + asm.emitConstantPoolUTF8("Code"); + codeIdx = asm.cpi(); + asm.emitConstantPoolUTF8("Exceptions"); + exceptionsIdx = asm.cpi(); + } + + /** Constant pool entries required to be able to box/unbox primitive + types. Note that we don't emit these if we don't need them. */ + protected void emitBoxingContantPoolEntries() { + // * [UTF-8] "java/lang/Boolean" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(Z)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "booleanValue" + // * [UTF-8] "()Z" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Byte" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(B)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "byteValue" + // * [UTF-8] "()B" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Character" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(C)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "charValue" + // * [UTF-8] "()C" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Double" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(D)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "doubleValue" + // * [UTF-8] "()D" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Float" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(F)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "floatValue" + // * [UTF-8] "()F" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Integer" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(I)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "intValue" + // * [UTF-8] "()I" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Long" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(J)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "longValue" + // * [UTF-8] "()J" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Short" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(S)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "shortValue" + // * [UTF-8] "()S" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // Boolean + asm.emitConstantPoolUTF8("java/lang/Boolean"); + asm.emitConstantPoolClass(asm.cpi()); + booleanIdx = asm.cpi(); + asm.emitConstantPoolUTF8("(Z)V"); + asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); + booleanCtorIdx = asm.cpi(); + asm.emitConstantPoolUTF8("booleanValue"); + asm.emitConstantPoolUTF8("()Z"); + asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); + booleanUnboxIdx = asm.cpi(); + + // Byte + asm.emitConstantPoolUTF8("java/lang/Byte"); + asm.emitConstantPoolClass(asm.cpi()); + byteIdx = asm.cpi(); + asm.emitConstantPoolUTF8("(B)V"); + asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); + byteCtorIdx = asm.cpi(); + asm.emitConstantPoolUTF8("byteValue"); + asm.emitConstantPoolUTF8("()B"); + asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); + byteUnboxIdx = asm.cpi(); + + // Character + asm.emitConstantPoolUTF8("java/lang/Character"); + asm.emitConstantPoolClass(asm.cpi()); + characterIdx = asm.cpi(); + asm.emitConstantPoolUTF8("(C)V"); + asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); + characterCtorIdx = asm.cpi(); + asm.emitConstantPoolUTF8("charValue"); + asm.emitConstantPoolUTF8("()C"); + asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); + characterUnboxIdx = asm.cpi(); + + // Double + asm.emitConstantPoolUTF8("java/lang/Double"); + asm.emitConstantPoolClass(asm.cpi()); + doubleIdx = asm.cpi(); + asm.emitConstantPoolUTF8("(D)V"); + asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); + doubleCtorIdx = asm.cpi(); + asm.emitConstantPoolUTF8("doubleValue"); + asm.emitConstantPoolUTF8("()D"); + asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); + doubleUnboxIdx = asm.cpi(); + + // Float + asm.emitConstantPoolUTF8("java/lang/Float"); + asm.emitConstantPoolClass(asm.cpi()); + floatIdx = asm.cpi(); + asm.emitConstantPoolUTF8("(F)V"); + asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); + floatCtorIdx = asm.cpi(); + asm.emitConstantPoolUTF8("floatValue"); + asm.emitConstantPoolUTF8("()F"); + asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); + floatUnboxIdx = asm.cpi(); + + // Integer + asm.emitConstantPoolUTF8("java/lang/Integer"); + asm.emitConstantPoolClass(asm.cpi()); + integerIdx = asm.cpi(); + asm.emitConstantPoolUTF8("(I)V"); + asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); + integerCtorIdx = asm.cpi(); + asm.emitConstantPoolUTF8("intValue"); + asm.emitConstantPoolUTF8("()I"); + asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); + integerUnboxIdx = asm.cpi(); + + // Long + asm.emitConstantPoolUTF8("java/lang/Long"); + asm.emitConstantPoolClass(asm.cpi()); + longIdx = asm.cpi(); + asm.emitConstantPoolUTF8("(J)V"); + asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); + longCtorIdx = asm.cpi(); + asm.emitConstantPoolUTF8("longValue"); + asm.emitConstantPoolUTF8("()J"); + asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); + longUnboxIdx = asm.cpi(); + + // Short + asm.emitConstantPoolUTF8("java/lang/Short"); + asm.emitConstantPoolClass(asm.cpi()); + shortIdx = asm.cpi(); + asm.emitConstantPoolUTF8("(S)V"); + asm.emitConstantPoolNameAndType(initIdx, asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); + shortCtorIdx = asm.cpi(); + asm.emitConstantPoolUTF8("shortValue"); + asm.emitConstantPoolUTF8("()S"); + asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); + asm.emitConstantPoolMethodref(sub(asm.cpi(), S6), asm.cpi()); + shortUnboxIdx = asm.cpi(); + } + + // Necessary because of Java's annoying promotion rules + protected static short add(short s1, short s2) { + return (short) (s1 + s2); + } + + protected static short sub(short s1, short s2) { + return (short) (s1 - s2); + } + + protected boolean isStatic() { + return Modifier.isStatic(modifiers); + } + + /** Returns class name in "internal" form (i.e., '/' separators + instead of '.') */ + protected static String getClassName + (Class c, boolean addPrefixAndSuffixForNonPrimitiveTypes) + { + if (c.isPrimitive()) { + if (c == Boolean.TYPE) { + return "Z"; + } else if (c == Byte.TYPE) { + return "B"; + } else if (c == Character.TYPE) { + return "C"; + } else if (c == Double.TYPE) { + return "D"; + } else if (c == Float.TYPE) { + return "F"; + } else if (c == Integer.TYPE) { + return "I"; + } else if (c == Long.TYPE) { + return "J"; + } else if (c == Short.TYPE) { + return "S"; + } else if (c == Void.TYPE) { + return "V"; + } + throw new InternalError("Should have found primitive type"); + } else if (c.isArray()) { + return "[" + getClassName(c.getComponentType(), true); + } else { + if (addPrefixAndSuffixForNonPrimitiveTypes) { + return internalize("L" + c.getName() + ";"); + } else { + return internalize(c.getName()); + } + } + } + + private static String internalize(String className) { + return className.replace('.', '/'); + } + + protected void emitConstructor() { + // Generate code into fresh code buffer + ClassFileAssembler cb = new ClassFileAssembler(); + // 0 incoming arguments + cb.setMaxLocals(1); + cb.opc_aload_0(); + cb.opc_invokespecial(superCtorIdx, 0, 0); + cb.opc_return(); + + // Emit method + emitMethod(initIdx, cb.getMaxLocals(), cb, null, null); + } + + // The descriptor's index in the constant pool must be (1 + + // nameIdx). "numArgs" must indicate ALL arguments, including the + // implicit "this" argument; double and long arguments each count + // as 2 in this count. The code buffer must NOT contain the code + // length. The exception table may be null, but if non-null must + // NOT contain the exception table's length. The checked exception + // indices may be null. + protected void emitMethod(short nameIdx, + int numArgs, + ClassFileAssembler code, + ClassFileAssembler exceptionTable, + short[] checkedExceptionIndices) + { + int codeLen = code.getLength(); + int excLen = 0; + if (exceptionTable != null) { + excLen = exceptionTable.getLength(); + if ((excLen % 8) != 0) { + throw new IllegalArgumentException("Illegal exception table"); + } + } + int attrLen = 12 + codeLen + excLen; + excLen = excLen / 8; // No-op if no exception table + + asm.emitShort(ACC_PUBLIC); + asm.emitShort(nameIdx); + asm.emitShort(add(nameIdx, S1)); + if (checkedExceptionIndices == null) { + // Code attribute only + asm.emitShort(S1); + } else { + // Code and Exceptions attributes + asm.emitShort(S2); + } + // Code attribute + asm.emitShort(codeIdx); + asm.emitInt(attrLen); + asm.emitShort(code.getMaxStack()); + asm.emitShort((short) Math.max(numArgs, code.getMaxLocals())); + asm.emitInt(codeLen); + asm.append(code); + asm.emitShort((short) excLen); + if (exceptionTable != null) { + asm.append(exceptionTable); + } + asm.emitShort(S0); // No additional attributes for Code attribute + if (checkedExceptionIndices != null) { + // Exceptions attribute + asm.emitShort(exceptionsIdx); + asm.emitInt(2 + 2 * checkedExceptionIndices.length); + asm.emitShort((short) checkedExceptionIndices.length); + for (int i = 0; i < checkedExceptionIndices.length; i++) { + asm.emitShort(checkedExceptionIndices[i]); + } + } + } + + protected short indexForPrimitiveType(Class type) { + if (type == Boolean.TYPE) { + return booleanIdx; + } else if (type == Byte.TYPE) { + return byteIdx; + } else if (type == Character.TYPE) { + return characterIdx; + } else if (type == Double.TYPE) { + return doubleIdx; + } else if (type == Float.TYPE) { + return floatIdx; + } else if (type == Integer.TYPE) { + return integerIdx; + } else if (type == Long.TYPE) { + return longIdx; + } else if (type == Short.TYPE) { + return shortIdx; + } + throw new InternalError("Should have found primitive type"); + } + + protected short ctorIndexForPrimitiveType(Class type) { + if (type == Boolean.TYPE) { + return booleanCtorIdx; + } else if (type == Byte.TYPE) { + return byteCtorIdx; + } else if (type == Character.TYPE) { + return characterCtorIdx; + } else if (type == Double.TYPE) { + return doubleCtorIdx; + } else if (type == Float.TYPE) { + return floatCtorIdx; + } else if (type == Integer.TYPE) { + return integerCtorIdx; + } else if (type == Long.TYPE) { + return longCtorIdx; + } else if (type == Short.TYPE) { + return shortCtorIdx; + } + throw new InternalError("Should have found primitive type"); + } + + /** Returns true for widening or identity conversions for primitive + types only */ + protected static boolean canWidenTo(Class type, Class otherType) { + if (!type.isPrimitive()) { + return false; + } + + // Widening conversions (from JVM spec): + // byte to short, int, long, float, or double + // short to int, long, float, or double + // char to int, long, float, or double + // int to long, float, or double + // long to float or double + // float to double + + if (type == Boolean.TYPE) { + if (otherType == Boolean.TYPE) { + return true; + } + } else if (type == Byte.TYPE) { + if ( otherType == Byte.TYPE + || otherType == Short.TYPE + || otherType == Integer.TYPE + || otherType == Long.TYPE + || otherType == Float.TYPE + || otherType == Double.TYPE) { + return true; + } + } else if (type == Short.TYPE) { + if ( otherType == Short.TYPE + || otherType == Integer.TYPE + || otherType == Long.TYPE + || otherType == Float.TYPE + || otherType == Double.TYPE) { + return true; + } + } else if (type == Character.TYPE) { + if ( otherType == Character.TYPE + || otherType == Integer.TYPE + || otherType == Long.TYPE + || otherType == Float.TYPE + || otherType == Double.TYPE) { + return true; + } + } else if (type == Integer.TYPE) { + if ( otherType == Integer.TYPE + || otherType == Long.TYPE + || otherType == Float.TYPE + || otherType == Double.TYPE) { + return true; + } + } else if (type == Long.TYPE) { + if ( otherType == Long.TYPE + || otherType == Float.TYPE + || otherType == Double.TYPE) { + return true; + } + } else if (type == Float.TYPE) { + if ( otherType == Float.TYPE + || otherType == Double.TYPE) { + return true; + } + } else if (type == Double.TYPE) { + if (otherType == Double.TYPE) { + return true; + } + } + + return false; + } + + /** Emits the widening bytecode for the given primitive conversion + (or none if the identity conversion). Requires that a primitive + conversion exists; i.e., canWidenTo must have already been + called and returned true. */ + protected static void emitWideningBytecodeForPrimitiveConversion + (ClassFileAssembler cb, + Class fromType, + Class toType) + { + // Note that widening conversions for integral types (i.e., "b2s", + // "s2i") are no-ops since values on the Java stack are + // sign-extended. + + // Widening conversions (from JVM spec): + // byte to short, int, long, float, or double + // short to int, long, float, or double + // char to int, long, float, or double + // int to long, float, or double + // long to float or double + // float to double + + if ( fromType == Byte.TYPE + || fromType == Short.TYPE + || fromType == Character.TYPE + || fromType == Integer.TYPE) { + if (toType == Long.TYPE) { + cb.opc_i2l(); + } else if (toType == Float.TYPE) { + cb.opc_i2f(); + } else if (toType == Double.TYPE) { + cb.opc_i2d(); + } + } else if (fromType == Long.TYPE) { + if (toType == Float.TYPE) { + cb.opc_l2f(); + } else if (toType == Double.TYPE) { + cb.opc_l2d(); + } + } else if (fromType == Float.TYPE) { + if (toType == Double.TYPE) { + cb.opc_f2d(); + } + } + + // Otherwise, was identity or no-op conversion. Fall through. + } + + protected short unboxingMethodForPrimitiveType(Class primType) { + if (primType == Boolean.TYPE) { + return booleanUnboxIdx; + } else if (primType == Byte.TYPE) { + return byteUnboxIdx; + } else if (primType == Character.TYPE) { + return characterUnboxIdx; + } else if (primType == Short.TYPE) { + return shortUnboxIdx; + } else if (primType == Integer.TYPE) { + return integerUnboxIdx; + } else if (primType == Long.TYPE) { + return longUnboxIdx; + } else if (primType == Float.TYPE) { + return floatUnboxIdx; + } else if (primType == Double.TYPE) { + return doubleUnboxIdx; + } + throw new InternalError("Illegal primitive type " + primType.getName()); + } + + protected static final Class[] primitiveTypes = new Class[] { + Boolean.TYPE, + Byte.TYPE, + Character.TYPE, + Short.TYPE, + Integer.TYPE, + Long.TYPE, + Float.TYPE, + Double.TYPE + }; + + /** We don't consider "Void" to be a primitive type */ + protected static boolean isPrimitive(Class c) { + return (c.isPrimitive() && c != Void.TYPE); + } + + protected int typeSizeInStackSlots(Class c) { + if (c == Void.TYPE) { + return 0; + } + if (c == Long.TYPE || c == Double.TYPE) { + return 2; + } + return 1; + } + + private ClassFileAssembler illegalArgumentCodeBuffer; + protected ClassFileAssembler illegalArgumentCodeBuffer() { + if (illegalArgumentCodeBuffer == null) { + illegalArgumentCodeBuffer = new ClassFileAssembler(); + illegalArgumentCodeBuffer.opc_new(illegalArgumentClass); + illegalArgumentCodeBuffer.opc_dup(); + illegalArgumentCodeBuffer.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); + illegalArgumentCodeBuffer.opc_athrow(); + } + + return illegalArgumentCodeBuffer; + } +}