|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package jdk.internal.reflect; |
|
|
|
import java.lang.reflect.*; |
|
import jdk.internal.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", |
|
|
|
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 |
|
|
|
protected ClassFileAssembler asm; |
|
protected int modifiers; |
|
protected short thisClass; |
|
protected short superClass; |
|
protected short targetClass; |
|
|
|
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; |
|
|
|
protected short valueOfIdx; |
|
protected short booleanIdx; |
|
protected short booleanBoxIdx; |
|
protected short booleanUnboxIdx; |
|
protected short byteIdx; |
|
protected short byteBoxIdx; |
|
protected short byteUnboxIdx; |
|
protected short characterIdx; |
|
protected short characterBoxIdx; |
|
protected short characterUnboxIdx; |
|
protected short doubleIdx; |
|
protected short doubleBoxIdx; |
|
protected short doubleUnboxIdx; |
|
protected short floatIdx; |
|
protected short floatBoxIdx; |
|
protected short floatUnboxIdx; |
|
protected short integerIdx; |
|
protected short integerBoxIdx; |
|
protected short integerUnboxIdx; |
|
protected short longIdx; |
|
protected short longBoxIdx; |
|
protected short longUnboxIdx; |
|
protected short shortIdx; |
|
protected short shortBoxIdx; |
|
protected short shortUnboxIdx; |
|
|
|
protected final short NUM_COMMON_CPOOL_ENTRIES = (short) 30; |
|
protected final short NUM_BOXING_CPOOL_ENTRIES = (short) 73; |
|
|
|
|
|
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] "<init>" |
|
// + [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 "<init>(Ljava/lang/String;)V" |
|
// + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String |
|
// + [UTF-8] "(Ljava/lang/Throwable;)V" |
|
// + [CONSTANT_NameAndType_info] for "<init>(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" |
|
|
|
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("<init>"); |
|
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(); |
|
} |
|
|
|
|
|
types. Note that we don't emit these if we don't need them. */ |
|
protected void emitBoxingContantPoolEntries() { |
|
// * [UTF-8] "valueOf" |
|
// * [UTF-8] "java/lang/Boolean" |
|
// * [CONSTANT_Class_info] for above |
|
// * [UTF-8] "(Z)Ljava/lang/Boolean;" |
|
// * [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)Ljava/lang/Byte;" |
|
// * [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)Ljava/lang/Character;" |
|
// * [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)Ljava/lang/Double;" |
|
// * [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)Ljava/lang/Float;" |
|
// * [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)Ljava/lang/Integer;" |
|
// * [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)Ljava/lang/Long;" |
|
// * [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)Ljava/lang/Short;" |
|
// * [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 |
|
|
|
|
|
asm.emitConstantPoolUTF8("valueOf"); |
|
valueOfIdx = asm.cpi(); |
|
|
|
|
|
asm.emitConstantPoolUTF8("java/lang/Boolean"); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
booleanIdx = asm.cpi(); |
|
asm.emitConstantPoolUTF8("(Z)Ljava/lang/Boolean;"); |
|
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); |
|
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); |
|
booleanBoxIdx = 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(); |
|
|
|
|
|
asm.emitConstantPoolUTF8("java/lang/Byte"); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
byteIdx = asm.cpi(); |
|
asm.emitConstantPoolUTF8("(B)Ljava/lang/Byte;"); |
|
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); |
|
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); |
|
byteBoxIdx = 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(); |
|
|
|
|
|
asm.emitConstantPoolUTF8("java/lang/Character"); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
characterIdx = asm.cpi(); |
|
asm.emitConstantPoolUTF8("(C)Ljava/lang/Character;"); |
|
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); |
|
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); |
|
characterBoxIdx = 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(); |
|
|
|
|
|
asm.emitConstantPoolUTF8("java/lang/Double"); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
doubleIdx = asm.cpi(); |
|
asm.emitConstantPoolUTF8("(D)Ljava/lang/Double;"); |
|
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); |
|
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); |
|
doubleBoxIdx = 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(); |
|
|
|
|
|
asm.emitConstantPoolUTF8("java/lang/Float"); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
floatIdx = asm.cpi(); |
|
asm.emitConstantPoolUTF8("(F)Ljava/lang/Float;"); |
|
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); |
|
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); |
|
floatBoxIdx = 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(); |
|
|
|
|
|
asm.emitConstantPoolUTF8("java/lang/Integer"); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
integerIdx = asm.cpi(); |
|
asm.emitConstantPoolUTF8("(I)Ljava/lang/Integer;"); |
|
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); |
|
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); |
|
integerBoxIdx = 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(); |
|
|
|
|
|
asm.emitConstantPoolUTF8("java/lang/Long"); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
longIdx = asm.cpi(); |
|
asm.emitConstantPoolUTF8("(J)Ljava/lang/Long;"); |
|
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); |
|
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); |
|
longBoxIdx = 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(); |
|
|
|
|
|
asm.emitConstantPoolUTF8("java/lang/Short"); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
shortIdx = asm.cpi(); |
|
asm.emitConstantPoolUTF8("(S)Ljava/lang/Short;"); |
|
asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi()); |
|
asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi()); |
|
shortBoxIdx = 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(); |
|
} |
|
|
|
|
|
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); |
|
} |
|
|
|
protected boolean isPrivate() { |
|
return Modifier.isPrivate(modifiers); |
|
} |
|
|
|
|
|
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() { |
|
|
|
ClassFileAssembler cb = new ClassFileAssembler(); |
|
|
|
cb.setMaxLocals(1); |
|
cb.opc_aload_0(); |
|
cb.opc_invokespecial(superCtorIdx, 0, 0); |
|
cb.opc_return(); |
|
|
|
|
|
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 |
|
|
|
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; |
|
|
|
asm.emitShort(ACC_PUBLIC); |
|
asm.emitShort(nameIdx); |
|
asm.emitShort(add(nameIdx, S1)); |
|
if (checkedExceptionIndices == null) { |
|
|
|
asm.emitShort(S1); |
|
} else { |
|
|
|
asm.emitShort(S2); |
|
} |
|
|
|
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); |
|
if (checkedExceptionIndices != null) { |
|
|
|
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 boxingMethodForPrimitiveType(Class<?> type) { |
|
if (type == Boolean.TYPE) { |
|
return booleanBoxIdx; |
|
} else if (type == Byte.TYPE) { |
|
return byteBoxIdx; |
|
} else if (type == Character.TYPE) { |
|
return characterBoxIdx; |
|
} else if (type == Double.TYPE) { |
|
return doubleBoxIdx; |
|
} else if (type == Float.TYPE) { |
|
return floatBoxIdx; |
|
} else if (type == Integer.TYPE) { |
|
return integerBoxIdx; |
|
} else if (type == Long.TYPE) { |
|
return longBoxIdx; |
|
} else if (type == Short.TYPE) { |
|
return shortBoxIdx; |
|
} |
|
throw new InternalError("Should have found primitive type"); |
|
} |
|
|
|
|
|
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; |
|
} |
|
|
|
|
|
|
|
|
|
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 |
|
}; |
|
|
|
|
|
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; |
|
} |
|
} |