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