|
What this is
Other links
The source code/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.lib.jmi.util; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.*; /** * @author Martin Matula, Dusan Balek * @version 0.1 */ public abstract class ClassFileGenerator { /* Class File Constants */ public static final int JAVA_MAGIC = 0xcafebabe; /* Generate class file version for 1.1 by default */ public static final int JAVA_DEFAULT_VERSION = 45; public static final int JAVA_DEFAULT_MINOR_VERSION = 3; /* Constant table */ public static final int CONSTANT_UTF8 = 1; public static final int CONSTANT_INTEGER = 3; public static final int CONSTANT_FLOAT = 4; public static final int CONSTANT_LONG = 5; public static final int CONSTANT_DOUBLE = 6; public static final int CONSTANT_CLASS = 7; public static final int CONSTANT_STRING = 8; public static final int CONSTANT_FIELD = 9; public static final int CONSTANT_METHOD = 10; public static final int CONSTANT_INTERFACEMETHOD = 11; public static final int CONSTANT_NAMEANDTYPE = 12; /* Access and modifier flags */ public static final int ACC_PUBLIC = 0x00000001; public static final int ACC_PRIVATE = 0x00000002; public static final int ACC_PROTECTED = 0x00000004; public static final int ACC_STATIC = 0x00000008; public static final int ACC_FINAL = 0x00000010; public static final int ACC_SUPER = 0x00000020; public static final int ACC_INTERFACE = 0x00000200; public static final int ACC_ABSTRACT = 0x00000400; /* Type codes */ public static final int T_BYTE = 0x00000008; /* Opcodes */ public static final int opc_aconst_null = 1; public static final int opc_iconst_0 = 3; public static final int opc_iconst_1 = 4; public static final int opc_lconst_0 = 9; public static final int opc_fconst_0 = 11; public static final int opc_dconst_0 = 14; public static final int opc_bipush = 16; public static final int opc_sipush = 17; public static final int opc_ldc = 18; public static final int opc_ldc_w = 19; public static final int opc_iload = 21; public static final int opc_lload = 22; public static final int opc_fload = 23; public static final int opc_dload = 24; public static final int opc_aload = 25; public static final int opc_iload_0 = 26; public static final int opc_lload_0 = 30; public static final int opc_fload_0 = 34; public static final int opc_dload_0 = 38; public static final int opc_aload_0 = 42; public static final int opc_aload_1 = 43; public static final int opc_aaload = 50; public static final int opc_istore = 54; public static final int opc_lstore = 55; public static final int opc_fstore = 56; public static final int opc_dstore = 57; public static final int opc_astore = 58; public static final int opc_istore_0 = 59; public static final int opc_lstore_0 = 63; public static final int opc_fstore_0 = 67; public static final int opc_dstore_0 = 71; public static final int opc_astore_0 = 75; public static final int opc_aastore = 83; public static final int opc_bastore = 84; public static final int opc_pop = 87; public static final int opc_dup = 89; public static final int opc_ifeq = 153; public static final int opc_ifne = 154; public static final int opc_ifle = 158; public static final int opc_if_icmpeq = 159; public static final int opc_if_acmpne = 166; public static final int opc_goto = 167; public static final int opc_jsr = 168; public static final int opc_ret = 169; public static final int opc_ireturn = 172; public static final int opc_lreturn = 173; public static final int opc_freturn = 174; public static final int opc_dreturn = 175; public static final int opc_areturn = 176; public static final int opc_return = 177; public static final int opc_getstatic = 178; public static final int opc_putstatic = 179; public static final int opc_getfield = 180; public static final int opc_putfield = 181; public static final int opc_invokevirtual = 182; public static final int opc_invokespecial = 183; public static final int opc_invokestatic = 184; public static final int opc_invokeinterface = 185; public static final int opc_new = 187; public static final int opc_newarray = 188; public static final int opc_anewarray = 189; public static final int opc_arraylength = 190; public static final int opc_athrow = 191; public static final int opc_checkcast = 192; public static final int opc_instanceof = 193; public static final int opc_wide = 196; public static final int opc_ifnull = 198; /** name of generated class */ protected String className; /** access flags */ protected int accessFlags; /** superclass name */ protected String superclassName; /** interface names */ protected String[] ifaceNames; /** constant pool of class being generated */ protected ConstantPool cp = new ConstantPool(); /** * Construct a HandlerGenerator to generate a handler class with the * specified name and for the given interfaces. */ protected ClassFileGenerator(String className, String[] interfaces, String superclass, int accessFlags) { this.className = className; this.ifaceNames = interfaces; this.superclassName = superclass; this.accessFlags = accessFlags; } /** * Generate a class file for the handler. This method drives the * class file generation process. */ final protected void generateClassFile(OutputStream stream) { try { // collect field info and method info structs MethodInfo[] methods = generateMethods(); FieldInfo[] fields = generateFields(); // make sure these classes are in the constant pool cp.getClass(dotToSlash(className)); cp.getClass(dotToSlash(superclassName)); for (int i = 0; i < ifaceNames.length; i++) cp.getClass(dotToSlash(ifaceNames[i])); cp.setReadOnly(); // write the class file DataOutputStream dout = new DataOutputStream(stream); // u4 magic; dout.writeInt(JAVA_MAGIC); // u2 major_version; dout.writeShort(JAVA_DEFAULT_MINOR_VERSION); // u2 minor_version; dout.writeShort(JAVA_DEFAULT_VERSION); // constant pool cp.write(dout); // u2 access_flags; dout.writeShort(accessFlags); // u2 this_class; dout.writeShort(cp.getClass(dotToSlash(className))); // u2 super_class; dout.writeShort(cp.getClass(dotToSlash(superclassName))); // u2 interfaces_count; dout.writeShort(ifaceNames.length); // u2 interfaces[interfaces_count]; for (int i = 0; i < ifaceNames.length; i++) dout.writeShort(cp.getClass(dotToSlash(ifaceNames[i]))); // u2 fields_count; dout.writeShort(fields.length); // field_info fields[fields_count]; for (int i = 0; i < fields.length; i++) fields[i].write(dout); // u2 methods_count; dout.writeShort(methods.length); // method_info methods[methods_count]; for (int i = 0 ; i < methods.length; i++) methods[i].write(dout); // u2 attributes_count; dout.writeShort(0); dout.close(); } catch (IOException e) { throw new InternalError("unexpected I/O Exception"); //NOI18N } } protected abstract MethodInfo[] generateMethods() throws IOException; protected abstract FieldInfo[] generateFields() throws IOException; /** * A FieldInfo object contains information about a particular field * in the class being generated. The class mirrors the data items of * the "field_info" structure of the class file format (see JVMS 4.5). */ final protected class FieldInfo { private int accessFlags; private String name; private String descriptor; private Object constValue; public FieldInfo(String name, String descriptor, int accessFlags) { this.name = name; this.descriptor = descriptor; this.accessFlags = accessFlags; /* * Make sure that constant pool indexes are reserved for the * following items before starting to write the final class file. */ cp.getUtf8(name); cp.getUtf8(descriptor); } public void setConstValue(Object value) { if ((accessFlags & ACC_STATIC) != 0) { constValue = value; cp.getUtf8("ConstantValue"); //NOI18N cp.getUnknownValue(constValue); } } final public void write(DataOutputStream out) throws IOException { /* * Write all the items of the "field_info" structure. * See JVMS section 4.5. */ // u2 access_flags; out.writeShort(accessFlags); // u2 name_index; out.writeShort(cp.getUtf8(name)); // u2 descriptor_index; out.writeShort(cp.getUtf8(descriptor)); // u2 attributes_count; if (constValue == null) out.writeShort(0); // (no field_info attributes for proxy classes) else { out.writeShort(1); // u2 attribute_name_index; out.writeShort(cp.getUtf8("ConstantValue")); //NOI18N // u4 attribute_length; out.writeInt(2); // u2 constantvalue_index out.writeShort(cp.getUnknownValue(constValue)); } } public boolean equals(Object o) { if (o instanceof FieldInfo) { return ((FieldInfo) o).name.equalsIgnoreCase(name); } else { return false; } } public int hashCode() { return name.toUpperCase().hashCode(); } } /** * An ExceptionTableEntry object holds values for the data items of * an entry in the "exception_table" item of the "Code" attribute of * "method_info" structures (see JVMS 4.7.3). */ final protected static class ExceptionTableEntry { public short startPc; public short endPc; public short handlerPc; public short catchType; public ExceptionTableEntry(short startPc, short endPc, short handlerPc, short catchType) { this.startPc = startPc; this.endPc = endPc; this.handlerPc = handlerPc; this.catchType = catchType; } }; /** * A MethodInfo object contains information about a particular method * in the class being generated. This class mirrors the data items of * the "method_info" structure of the class file format (see JVMS 4.6). */ final protected class MethodInfo { private int accessFlags; private String name; private String descriptor; private ByteArrayOutputStream code = new ByteArrayOutputStream(); private short maxStack; private short maxLocals; private short[] declaredExceptions; private List exceptionTable = new ArrayList(); public MethodInfo(String name, String descriptor, int accessFlags) { this.name = name; this.descriptor = descriptor; this.accessFlags = accessFlags; /* * Make sure that constant pool indexes are reserved for the * following items before starting to write the final class file. */ cp.getUtf8(name); cp.getUtf8(descriptor); } public void setDeclaredExceptions(short[] exceptions) { cp.getUtf8("Exceptions"); //NOI18N declaredExceptions = exceptions; } public ByteArrayOutputStream getCodeStream() { cp.getUtf8("Code"); //NOI18N return code; } public void setMaxStack(short max) { maxStack = max; } public void setMaxLocals(short max) { maxLocals = max; } public List getExceptionTable() { return exceptionTable; } public void write(DataOutputStream out) throws IOException { /* * Write all the items of the "method_info" structure. * See JVMS section 4.6. */ // u2 access_flags; out.writeShort(accessFlags); // u2 name_index; out.writeShort(cp.getUtf8(name)); // u2 descriptor_index; out.writeShort(cp.getUtf8(descriptor)); // u2 attributes_count; short count = 0; if (code.size() > 0) count++; if (declaredExceptions != null && declaredExceptions.length > 0) count++; out.writeShort(count); // Write "Code" attribute. See JVMS section 4.7.3. if (code.size() > 0) { // u2 attribute_name_index; out.writeShort(cp.getUtf8("Code")); //NOI18N // u4 attribute_length; out.writeInt(12 + code.size() + 8 * exceptionTable.size()); // u2 max_stack; out.writeShort(maxStack); // u2 max_locals; out.writeShort(maxLocals); // u2 code_length; out.writeInt(code.size()); // u1 code[code_length]; code.writeTo(out); // u2 exception_table_length; out.writeShort(exceptionTable.size()); for (Iterator iter = exceptionTable.iterator(); iter.hasNext();) { ExceptionTableEntry e = (ExceptionTableEntry) iter.next(); // u2 start_pc; out.writeShort(e.startPc); // u2 end_pc; out.writeShort(e.endPc); // u2 handler_pc; out.writeShort(e.handlerPc); // u2 catch_type; out.writeShort(e.catchType); } // u2 attributes_count; out.writeShort(0); } // write "Exceptions" attribute. See JVMS section 4.7.4. if (declaredExceptions != null && declaredExceptions.length > 0) { // u2 attribute_name_index; out.writeShort(cp.getUtf8("Exceptions")); //NOI18N // u4 attributes_length; out.writeInt(2 + 2 * declaredExceptions.length); // u2 number_of_exceptions; out.writeShort(declaredExceptions.length); // u2 exception_index_table[number_of_exceptions]; for (int i = 0; i < declaredExceptions.length; i++) out.writeShort(declaredExceptions[i]); } } } /* * =============== Code Generation Utility Methods =============== */ /* * The following methods generate code for the load or store operation * indicated by their name for the given local variable. The code is * written to the supplied stream. */ protected void code_iload(int lvar, DataOutputStream out) throws IOException { codeLocalLoadStore(lvar, opc_iload, opc_iload_0, out); } protected void code_lload(int lvar, DataOutputStream out) throws IOException { codeLocalLoadStore(lvar, opc_lload, opc_lload_0, out); } protected void code_fload(int lvar, DataOutputStream out) throws IOException { codeLocalLoadStore(lvar, opc_fload, opc_fload_0, out); } protected void code_dload(int lvar, DataOutputStream out) throws IOException { codeLocalLoadStore(lvar, opc_dload, opc_dload_0, out); } protected void code_aload(int lvar, DataOutputStream out) throws IOException { codeLocalLoadStore(lvar, opc_aload, opc_aload_0, out); } protected void code_istore(int lvar, DataOutputStream out) throws IOException { codeLocalLoadStore(lvar, opc_istore, opc_istore_0, out); } protected void code_lstore(int lvar, DataOutputStream out) throws IOException { codeLocalLoadStore(lvar, opc_lstore, opc_lstore_0, out); } protected void code_fstore(int lvar, DataOutputStream out) throws IOException { codeLocalLoadStore(lvar, opc_fstore, opc_fstore_0, out); } protected void code_dstore(int lvar, DataOutputStream out) throws IOException { codeLocalLoadStore(lvar, opc_dstore, opc_dstore_0, out); } protected void code_astore(int lvar, DataOutputStream out) throws IOException { codeLocalLoadStore(lvar, opc_astore, opc_astore_0, out); } /** * Generate code for a load or store instruction for the given local * variable. The code is written to the supplied stream. * * "opcode" indicates the opcode form of the desired load or store * instruction that takes an explicit local variable index, and * "opcode_0" indicates the corresponding form of the instruction * with the implicit index 0. */ protected void codeLocalLoadStore(int lvar, int opcode, int opcode_0, DataOutputStream out) throws IOException { _assert(lvar >= 0 && lvar <= 0xFFFF); if (lvar <= 3) { out.writeByte(opcode_0 + lvar); } else if (lvar <= 0xFF) { out.writeByte(opcode); out.writeByte(lvar & 0xFF); } else { /* * Use the "wide" instruction modifier for local variable * indexes that do not fit into an unsigned byte. */ out.writeByte(opc_wide); out.writeByte(opcode); out.writeShort(lvar & 0xFFFF); } } /** * Generate code for an "ldc" instruction for the given constant pool * index (the "ldc_w" instruction is used if the index does not fit * into an unsigned byte). The code is written to the supplied stream. */ protected void code_ldc(int index, DataOutputStream out) throws IOException { _assert(index >= 0 && index <= 0xFFFF); if (index <= 0xFF) { out.writeByte(opc_ldc); out.writeByte(index & 0xFF); } else { out.writeByte(opc_ldc_w); out.writeShort(index & 0xFFFF); } } /** * Generate code to push a constant integer value on to the operand * stack, using the "iconst_", "bipush", or "sipush" instructions * depending on the size of the value. The code is written to the * supplied stream. */ protected void code_ipush(int value, DataOutputStream out) throws IOException { if (value >= -1 && value <= 5) { out.writeByte(opc_iconst_0 + value); } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { out.writeByte(opc_bipush); out.writeByte(value & 0xFF); } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { out.writeByte(opc_sipush); out.writeShort(value & 0xFFFF); } else { _assert(false); } } protected void codeReturnFieldValue(String className, String fieldName, String descriptor, boolean isStatic, DataOutputStream out) throws IOException { short index = cp.getFieldRef(dotToSlash(className), fieldName, descriptor); _assert(index >= 0); if (isStatic) out.writeByte(opc_getstatic); else { code_aload(0, out); out.writeByte(opc_getfield); } out.writeShort(index); if (descriptor.equals("I") || descriptor.equals("S") || descriptor.equals("C") || //NOI18N descriptor.equals("B") || descriptor.equals("Z")) //NOI18N out.writeByte(opc_ireturn); else if (descriptor.equals("J")) //NOI18N out.writeByte(opc_lreturn); else if (descriptor.equals("F")) //NOI18N out.writeByte(opc_freturn); else if (descriptor.equals("D")) //NOI18N out.writeByte(opc_dreturn); else out.writeByte(opc_areturn); } /** * Generate code to invoke the Class.forName with the name of the given * class to get its Class object at runtime. The code is written to * the supplied stream. Note that the code generated by this method * may caused the checked ClassNotFoundException to be thrown. */ protected void codeClassForName(Class cl, DataOutputStream out) throws IOException { code_ldc(cp.getString(cl.getName()), out); out.writeByte(opc_invokestatic); out.writeShort(cp.getMethodRef( "java/lang/Class", //NOI18N "forName", "(Ljava/lang/String;)Ljava/lang/Class;")); //NOI18N } /* * ==================== General Utility Methods ==================== */ protected static String firstUpper(String text) { try { return text.substring(0, 1).toUpperCase() + text.substring(1); } catch (IndexOutOfBoundsException e) { return ""; //NOI18N } } protected static String firstLower(String text) { try { return text.substring(0, 1).toLowerCase() + text.substring(1); } catch (IndexOutOfBoundsException e) { return ""; //NOI18N } } /** * Assert that an assertion is true: throw InternalError if it is not. */ protected static void _assert(boolean assertion) { if (assertion != true) { throw new InternalError("assertion failure"); //NOI18N } } /** * Convert a fully qualified class name that uses '.' as the package * separator, the external representation used by the Java language * and APIs, to a fully qualified class name that uses '/' as the * package separator, the representation used in the class file * format (see JVMS section 4.2). */ protected static String dotToSlash(String name) { return name.replace('.', '/'); } /** * Return the "method descriptor" string for a method with the given * parameter types and return type. See JVMS section 4.3.3. */ protected static String getMethodDescriptor(String[] parameterTypeNames, String returnTypeName) { return getParameterDescriptors(parameterTypeNames) + ((returnTypeName.equals("void")) ? "V" : getFieldType(returnTypeName)); //NOI18N } /** * Return the list of "parameter descriptor" strings enclosed in * parentheses corresponding to the given parameter types (in other * words, a method descriptor without a return descriptor). This * string is useful for constructing string keys for methods without * regard to their return type. */ protected static String getParameterDescriptors(String[] parameterTypeNames) { StringBuffer desc = new StringBuffer("("); //NOI18N for (int i = 0; i < parameterTypeNames.length; i++) { desc.append(getFieldType(parameterTypeNames[i])); } desc.append(')'); return desc.toString(); } /** * Return the "field type" string for the given type, appropriate for * a field descriptor, a parameter descriptor, or a return descriptor * other than "void". See JVMS section 4.3.2. */ protected static String getFieldType(String typeName) { PrimitiveTypeInfo ptInfo = PrimitiveTypeInfo.get(typeName); if (ptInfo != null) return ptInfo.baseTypeString; else if (typeName.endsWith("[]")) //NOI18N return "[" + getFieldType(typeName.substring(0, typeName.length()-2).trim()); //NOI18N else return "L" + dotToSlash(typeName) + ";"; //NOI18N } /** * Return the number of abstract "words", or consecutive local variable * indexes, required to contain a value of the given type. See JVMS * section 3.6.1. * * Note that the original version of the JVMS contained a definition of * this abstract notion of a "word" in section 3.4, but that definition * was removed for the second edition. */ protected static int getWordsPerType(String typeName) { if (typeName.equals("long") || typeName.equals("double")) //NOI18N return 2; return 1; } /** * A PrimitiveTypeInfo object contains assorted information about * a primitive type in its public fields. The struct for a particular * primitive type can be obtained using the static "get" method. */ protected static class PrimitiveTypeInfo { /** "base type" used in various descriptors (see JVMS section 4.3.2) */ public String baseTypeString; /** name of corresponding wrapper class */ public String wrapperClassName; /** method descriptor for wrapper class constructor */ public String wrapperConstructorDesc; /** name of wrapper class method for retrieving primitive value */ public String unwrapMethodName; /** descriptor of same method */ public String unwrapMethodDesc; private static Map table = new HashMap(11); static { table.put("int", new PrimitiveTypeInfo( //NOI18N "I", "java/lang/Integer", "(I)V", "intValue", "()I")); //NOI18N table.put("boolean", new PrimitiveTypeInfo( //NOI18N "Z", "java/lang/Boolean", "(Z)V", "booleanValue", "()Z")); //NOI18N table.put("byte", new PrimitiveTypeInfo( //NOI18N "B", "java/lang/Byte", "(B)V", "byteValue", "()B")); //NOI18N table.put("char", new PrimitiveTypeInfo( //NOI18N "C", "java/lang/Char", "(C)V", "charValue", "()C")); //NOI18N table.put("short", new PrimitiveTypeInfo( //NOI18N "S", "java/lang/Short", "(S)V", "shortValue", "()S")); //NOI18N table.put("long", new PrimitiveTypeInfo( //NOI18N "J", "java/lang/Long", "(J)V", "longValue", "()J")); //NOI18N table.put("float", new PrimitiveTypeInfo( //NOI18N "F", "java/lang/Float", "(F)V", "floatValue", "()F")); //NOI18N table.put("double", new PrimitiveTypeInfo( //NOI18N "D", "java/lang/Double", "(D)V", "doubleValue", "()D")); //NOI18N } private PrimitiveTypeInfo(String baseTypeString, String wrapperClassName, String wrapperConstructorDesc, String unwrapMethodName, String unwrapMethodDesc) { this.baseTypeString = baseTypeString; this.wrapperClassName = wrapperClassName; this.wrapperConstructorDesc = wrapperConstructorDesc; this.unwrapMethodName = unwrapMethodName; this.unwrapMethodDesc = unwrapMethodDesc; } public static PrimitiveTypeInfo get(String name) { return (PrimitiveTypeInfo) table.get(name); } } /** * A ConstantPool object represents the constant pool of a class file * being generated. This representation of a constant pool is designed * specifically for use by ProxyGenerator; in particular, it assumes * that constant pool entries will not need to be resorted (for example, * by their type, as the Java compiler does), so that the final index * value can be assigned and used when an entry is first created. * * Note that new entries cannot be created after the constant pool has * been written to a class file. To prevent such logic errors, a * ConstantPool instance can be marked "read only", so that further * attempts to add new entries will fail with a runtime exception. * * See JVMS section 4.4 for more information about the constant pool * of a class file. */ protected static class ConstantPool { /** * list of constant pool entries, in constant pool index order. * * This list is used when writing the constant pool to a stream * and for assigning the next index value. Note that element 0 * of this list corresponds to constant pool index 1. */ private List pool = new ArrayList(32); /** * maps constant pool data of all types to constant pool indexes. * * This map is used to look up the index of an existing entry for * values of all types. */ private Map map = new HashMap(16); /** true if no new constant pool entries may be added */ private boolean readOnly = false; /** * Get or assign the index for a CONSTANT_Utf8 entry. */ public short getUtf8(String s) { if (s == null) { throw new NullPointerException(); } return getValue(s); } /** * Get or assign the index for a CONSTANT_Integer entry. */ public short getInteger(int i) { return getValue(new Integer(i)); } /** * Get or assign the index for a CONSTANT_Float entry. */ public short getFloat(float f) { return getValue(new Float(f)); } /** * Get or assign the index for a CONSTANT_Long entry. */ public short getLong(long l) { return getValue(new Long(l)); } /** * Get or assign the index for a CONSTANT_Double entry. */ public short getDouble(double d) { return getValue(new Double(d)); } /** * Get or assign the index for a CONSTANT_Class entry. */ public short getClass(String name) { short utf8Index = getUtf8(name); return getIndirect(new IndirectEntry( CONSTANT_CLASS, utf8Index)); } /** * Get or assign the index for a CONSTANT_String entry. */ public short getString(String s) { short utf8Index = getUtf8(s); return getIndirect(new IndirectEntry( CONSTANT_STRING, utf8Index)); } /** * Get or assign the index for a CONSTANT_FieldRef entry. */ public short getFieldRef(String className, String name, String descriptor) { short classIndex = getClass(className); short nameAndTypeIndex = getNameAndType(name, descriptor); return getIndirect(new IndirectEntry( CONSTANT_FIELD, classIndex, nameAndTypeIndex)); } /** * Get or assign the index for a CONSTANT_MethodRef entry. */ public short getMethodRef(String className, String name, String descriptor) { short classIndex = getClass(className); short nameAndTypeIndex = getNameAndType(name, descriptor); return getIndirect(new IndirectEntry( CONSTANT_METHOD, classIndex, nameAndTypeIndex)); } /** * Get or assign the index for a CONSTANT_InterfaceMethodRef entry. */ public short getInterfaceMethodRef(String className, String name, String descriptor) { short classIndex = getClass(className); short nameAndTypeIndex = getNameAndType(name, descriptor); return getIndirect(new IndirectEntry( CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex)); } /** * Get or assign the index for a CONSTANT_NameAndType entry. */ public short getNameAndType(String name, String descriptor) { short nameIndex = getUtf8(name); short descriptorIndex = getUtf8(descriptor); return getIndirect(new IndirectEntry( CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex)); } public short getUnknownValue(Object value) { if (value == null) throw new NullPointerException(); if (value instanceof String) return getString((String)value); if (value instanceof Integer || value instanceof Float || value instanceof Long || value instanceof Double) return getValue(value); throw new InternalError("bogus value entry: " + value); //NOI18N } /** * Set this ConstantPool instance to be "read only". * * After this method has been called, further requests to get * an index for a non-existent entry will cause an InternalError * to be thrown instead of creating of the entry. */ public void setReadOnly() { readOnly = true; } /** * Write this constant pool to a stream as part of * the class file format. * * This consists of writing the "constant_pool_count" and * "constant_pool[]" items of the "ClassFile" structure, as * described in JVMS section 4.1. */ public void write(OutputStream out) throws IOException { DataOutputStream dataOut = new DataOutputStream(out); // constant_pool_count: number of entries plus one dataOut.writeShort(pool.size() + 1); for (Iterator iter = pool.iterator(); iter.hasNext();) { Entry e = (Entry) iter.next(); e.write(dataOut); } } /** * Add a new constant pool entry and return its index. */ private short addEntry(Entry entry) { pool.add(entry); return (short) pool.size(); } /** * Get or assign the index for an entry of a type that contains * a direct value. The type of the given object determines the * type of the desired entry as follows: * * java.lang.String CONSTANT_Utf8 * java.lang.Integer CONSTANT_Integer * java.lang.Float CONSTANT_Float * java.lang.Long CONSTANT_Long * java.lang.Double CONSTANT_DOUBLE */ private short getValue(Object key) { Short index = (Short) map.get(key); if (index != null) { return index.shortValue(); } else { if (readOnly) { throw new InternalError( "late constant pool addition: " + key); //NOI18N } short i = addEntry(new ValueEntry(key)); map.put(key, new Short(i)); return i; } } /** * Get or assign the index for an entry of a type that contains * references to other constant pool entries. */ private short getIndirect(IndirectEntry e) { Short index = (Short) map.get(e); if (index != null) { return index.shortValue(); } else { if (readOnly) { throw new InternalError("late constant pool addition"); //NOI18N } short i = addEntry(e); map.put(e, new Short(i)); return i; } } /** * Entry is the abstact superclass of all constant pool entry types * that can be stored in the "pool" list; its purpose is to define a * common method for writing constant pool entries to a class file. */ private static abstract class Entry { public abstract void write(DataOutputStream out) throws IOException; } /** * ValueEntry represents a constant pool entry of a type that * contains a direct value (see the comments for the "getValue" * method for a list of such types). * * ValueEntry objects are not used as keys for their entries in the * Map "map", so no useful hashCode or equals methods are defined. */ private static class ValueEntry extends Entry { private Object value; public ValueEntry(Object value) { this.value = value; } public void write(DataOutputStream out) throws IOException { if (value instanceof String) { out.writeByte(CONSTANT_UTF8); out.writeUTF((String) value); } else if (value instanceof Integer) { out.writeByte(CONSTANT_INTEGER); out.writeInt(((Integer) value).intValue()); } else if (value instanceof Float) { out.writeByte(CONSTANT_FLOAT); out.writeFloat(((Float) value).floatValue()); } else if (value instanceof Long) { out.writeByte(CONSTANT_LONG); out.writeLong(((Long) value).longValue()); } else if (value instanceof Double) { out.writeDouble(CONSTANT_DOUBLE); out.writeDouble(((Double) value).doubleValue()); } else { throw new InternalError("bogus value entry: " + value); //NOI18N } } } /** * IndirectEntry represents a constant pool entry of a type that * references other constant pool entries, i.e., the following types: * * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref, * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and * CONSTANT_NameAndType. * * Each of these entry types contains either one or two indexes of * other constant pool entries. * * IndirectEntry objects are used as the keys for their entries in * the Map "map", so the hashCode and equals methods are overridden * to allow matching. */ private static class IndirectEntry extends Entry { private int tag; private short index0; private short index1; /** * Construct an IndirectEntry for a constant pool entry type * that contains one index of another entry. */ public IndirectEntry(int tag, short index) { this.tag = tag; this.index0 = index; this.index1 = 0; } /** * Construct an IndirectEntry for a constant pool entry type * that contains two indexes for other entries. */ public IndirectEntry(int tag, short index0, short index1) { this.tag = tag; this.index0 = index0; this.index1 = index1; } public void write(DataOutputStream out) throws IOException { out.writeByte(tag); out.writeShort(index0); /* * If this entry type contains two indexes, write * out the second, too. */ if (tag == CONSTANT_FIELD || tag == CONSTANT_METHOD || tag == CONSTANT_INTERFACEMETHOD || tag == CONSTANT_NAMEANDTYPE) { out.writeShort(index1); } } public int hashCode() { return tag + index0 + index1; } public boolean equals(Object obj) { if (obj instanceof IndirectEntry) { IndirectEntry other = (IndirectEntry) obj; if (tag == other.tag && index0 == other.index0 && index1 == other.index1) { return true; } } return false; } } } } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.