1 package serp.bytecode.lowlevel;
2
3 import java.io.*;
4 import java.util.*;
5
6 import serp.bytecode.visitor.*;
7
8 /***
9 * Base type for all constant pool entries. Entries should generally be
10 * considered immutable; modifying an entry directly can have dire
11 * consequences, and often renders the resulting class file invalid.
12 *
13 * <p>Entries cannot be shared among constant pools.</p>
14 *
15 * @author Abe White
16 */
17 public abstract class Entry implements VisitAcceptor {
18 public static final int UTF8 = 1;
19 public static final int INT = 3;
20 public static final int FLOAT = 4;
21 public static final int LONG = 5;
22 public static final int DOUBLE = 6;
23 public static final int CLASS = 7;
24 public static final int STRING = 8;
25 public static final int FIELD = 9;
26 public static final int METHOD = 10;
27 public static final int INTERFACEMETHOD = 11;
28 public static final int NAMEANDTYPE = 12;
29 private ConstantPool _pool = null;
30 private int _index = 0;
31
32 /***
33 * Read a single entry from the given bytecode stream and returns it.
34 */
35 public static Entry read(DataInput in) throws IOException {
36 Entry entry = create(in.readUnsignedByte());
37 entry.readData(in);
38 return entry;
39 }
40
41 /***
42 * Write the given entry to the given bytecode stream.
43 */
44 public static void write(Entry entry, DataOutput out)
45 throws IOException {
46 out.writeByte(entry.getType());
47 entry.writeData(out);
48 }
49
50 /***
51 * Create an entry based on its type code.
52 */
53 public static Entry create(int type) {
54 switch (type) {
55 case CLASS:
56 return new ClassEntry();
57 case FIELD:
58 return new FieldEntry();
59 case METHOD:
60 return new MethodEntry();
61 case INTERFACEMETHOD:
62 return new InterfaceMethodEntry();
63 case STRING:
64 return new StringEntry();
65 case INT:
66 return new IntEntry();
67 case FLOAT:
68 return new FloatEntry();
69 case LONG:
70 return new LongEntry();
71 case DOUBLE:
72 return new DoubleEntry();
73 case NAMEANDTYPE:
74 return new NameAndTypeEntry();
75 case UTF8:
76 return new UTF8Entry();
77 default:
78 throw new IllegalArgumentException("type = " + type);
79 }
80 }
81
82 /***
83 * Return the type code for this entry type.
84 */
85 public abstract int getType();
86
87 /***
88 * Return true if this is a wide entry -- i.e. if it takes up two
89 * places in the constant pool. Returns false by default.
90 */
91 public boolean isWide() {
92 return false;
93 }
94
95 /***
96 * Returns the constant pool containing this entry, or null if none.
97 */
98 public ConstantPool getPool() {
99 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
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 }