001package serp.bytecode.lowlevel; 002 003import java.io.DataInput; 004import java.io.DataOutput; 005import java.io.IOException; 006 007import serp.bytecode.visitor.VisitAcceptor; 008 009/** 010 * Base type for all constant pool entries. Entries should generally be 011 * considered immutable; modifying an entry directly can have dire 012 * consequences, and often renders the resulting class file invalid. 013 * 014 * <p>Entries cannot be shared among constant pools.</p> 015 * 016 * @author Abe White 017 */ 018public abstract class Entry implements VisitAcceptor { 019 public static final int UTF8 = 1; 020 public static final int INT = 3; 021 public static final int FLOAT = 4; 022 public static final int LONG = 5; 023 public static final int DOUBLE = 6; 024 public static final int CLASS = 7; 025 public static final int STRING = 8; 026 public static final int FIELD = 9; 027 public static final int METHOD = 10; 028 public static final int INTERFACEMETHOD = 11; 029 public static final int NAMEANDTYPE = 12; 030 public static final int METHODHANDLE = 15; 031 public static final int METHODTYPE = 16; 032 public static final int INVOKEDYNAMIC = 18; 033 034 private ConstantPool _pool = null; 035 private int _index = 0; 036 037 /** 038 * Read a single entry from the given bytecode stream and returns it. 039 */ 040 public static Entry read(DataInput in) throws IOException { 041 Entry entry = create(in.readUnsignedByte()); 042 entry.readData(in); 043 return entry; 044 } 045 046 /** 047 * Write the given entry to the given bytecode stream. 048 */ 049 public static void write(Entry entry, DataOutput out) 050 throws IOException { 051 out.writeByte(entry.getType()); 052 entry.writeData(out); 053 } 054 055 /** 056 * Create an entry based on its type code. 057 */ 058 public static Entry create(int type) { 059 switch (type) { 060 case CLASS: 061 return new ClassEntry(); 062 case FIELD: 063 return new FieldEntry(); 064 case METHOD: 065 return new MethodEntry(); 066 case INTERFACEMETHOD: 067 return new InterfaceMethodEntry(); 068 case STRING: 069 return new StringEntry(); 070 case INT: 071 return new IntEntry(); 072 case FLOAT: 073 return new FloatEntry(); 074 case LONG: 075 return new LongEntry(); 076 case DOUBLE: 077 return new DoubleEntry(); 078 case NAMEANDTYPE: 079 return new NameAndTypeEntry(); 080 case UTF8: 081 return new UTF8Entry(); 082 case METHODHANDLE: 083 return new MethodHandleEntry(); 084 case METHODTYPE: 085 return new MethodTypeEntry(); 086 case INVOKEDYNAMIC: 087 return new InvokeDynamicEntry(); 088 default: 089 throw new IllegalArgumentException("type = " + type); 090 } 091 } 092 093 /** 094 * Return the type code for this entry type. 095 */ 096 public abstract int getType(); 097 098 /** 099 * Return true if this is a wide entry -- i.e. if it takes up two 100 * places in the constant pool. Returns false by default. 101 */ 102 public boolean isWide() { 103 return false; 104 } 105 106 /** 107 * Returns the constant pool containing this entry, or null if none. 108 */ 109 public ConstantPool getPool() { 110 return _pool; 111 } 112 113 /** 114 * Returns the index of the entry in the owning constant pool, or 0. 115 */ 116 public int getIndex() { 117 return _index; 118 } 119 120 /** 121 * This method is called after reading the entry type from bytecode. 122 * It should read all the data for this entry from the given stream. 123 */ 124 abstract void readData(DataInput in) throws IOException; 125 126 /** 127 * This method is called after writing the entry type to bytecode. 128 * It should write all data for this entry to the given stream. 129 */ 130 abstract void writeData(DataOutput out) throws IOException; 131 132 /** 133 * Subclasses must call this method before their state is mutated. 134 */ 135 Object beforeModify() { 136 if (_pool == null) 137 return null; 138 return _pool.getKey(this); 139 } 140 141 /** 142 * Subclasses must call this method when their state is mutated. 143 */ 144 void afterModify(Object key) { 145 if (_pool != null) 146 _pool.modifyEntry(key, this); 147 } 148 149 /** 150 * Sets the owning pool of the entry. 151 */ 152 void setPool(ConstantPool pool) { 153 // attempting to overwrite current pool? 154 if (_pool != null && pool != null && _pool != pool) 155 throw new IllegalStateException("Entry already belongs to a pool"); 156 _pool = pool; 157 } 158 159 /** 160 * Set the index of this entry within the pool. 161 */ 162 void setIndex(int index) { 163 _index = index; 164 } 165}