| /* |
| * Copyright (c) 2001, 2013, Oracle and/or its affiliates. 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. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| 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", |
| // 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 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; |
| |
| // 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] "<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" |
| // + [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("<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(); |
| } |
| |
| /** 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] "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 |
| |
| // valueOf-method name |
| asm.emitConstantPoolUTF8("valueOf"); |
| valueOfIdx = asm.cpi(); |
| |
| // Boolean |
| 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(); |
| |
| // Byte |
| 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(); |
| |
| // Character |
| 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(); |
| |
| // Double |
| 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(); |
| |
| // Float |
| 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(); |
| |
| // Integer |
| 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(); |
| |
| // Long |
| 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(); |
| |
| // Short |
| 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(); |
| } |
| |
| // 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); |
| } |
| |
| protected boolean isPrivate() { |
| return Modifier.isPrivate(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 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"); |
| } |
| |
| /** 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; |
| } |
| } |