1 package org.ibex.classgen;
6 import org.ibex.classgen.util.*;
8 class ConstantPool implements CGConst {
9 private final Hashtable entries = new Hashtable();
10 private Ent[] entriesByIndex; // only valid when stable
12 private int usedSlots = 1; // 0 is reserved
13 private int state = OPEN;
14 private static final int OPEN = 0;
15 private static final int STABLE = 1; // existing entries won't change
16 private static final int SEALED = 2; // no new entries
20 public abstract class Ent {
21 int n; // this is the refcount if state == OPEN, index if >= STABLE
24 Ent(int tag) { this.tag = tag; }
25 void dump(DataOutput o) throws IOException { o.writeByte(tag); }
26 String debugToString() { return toString(); } // so we can remove this method when not debugging
27 abstract Object _key();
28 final Object key() { return key == null ? (key = _key()) : key; }
29 int slots() { return 1; } // number of slots this ent takes up
31 if(state != OPEN) throw new IllegalStateException("cp is not open");
35 if(state != OPEN) throw new IllegalStateException("cp is not open");
36 if(--n == 0) entries.remove(key());
40 class Utf8Ent extends Ent {
42 Utf8Ent() { super(CONSTANT_UTF8); }
43 Utf8Ent(String s) { this(); this.s = s; }
44 String debugToString() { return s; }
45 void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
46 Object _key() { return new Utf8Key(s); }
49 class IntLitEnt extends Ent {
51 IntLitEnt(int i) { super(CONSTANT_INTEGER); this.i = i; }
52 void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i); }
53 Object _key() { return new Integer(i); }
55 class FloatLitEnt extends Ent {
57 FloatLitEnt(float f) { super(CONSTANT_FLOAT); this.f = f; }
58 void dump(DataOutput o) throws IOException { super.dump(o); o.writeFloat(f); }
59 Object _key() { return new Float(f); }
61 class LongLitEnt extends Ent {
63 LongLitEnt(long l) { super(CONSTANT_LONG); this.l = l; }
64 void dump(DataOutput o) throws IOException { super.dump(o); o.writeLong(l); }
65 Object _key() { return new Long(l); }
66 int slots() { return 2; }
68 class DoubleLitEnt extends Ent {
70 DoubleLitEnt(double d) { super(CONSTANT_DOUBLE); this.d = d; }
71 void dump(DataOutput o) throws IOException { super.dump(o); o.writeDouble(d); }
72 Object _key() { return new Double(d); }
73 int slots() { return 2; }
75 class StringLitEnt extends Ent {
77 StringLitEnt() { super(CONSTANT_STRING); }
78 StringLitEnt(String s) { this(); this.utf8 = (Utf8Ent)addUtf8(s); }
79 void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(utf8.n); }
80 Object _key() { return utf8.s; }
81 void unref() { utf8.unref(); super.unref(); }
83 class ClassEnt extends Ent {
85 ClassEnt() { super(CONSTANT_CLASS); }
86 ClassEnt(String s) { this(); this.utf8 = (Utf8Ent) addUtf8(s); }
87 void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(utf8.n); }
88 Type.Class getTypeClass() { return (Type.Class) key(); }
89 Object _key() { return new Type.Class(utf8.s); }
90 void unref() { utf8.unref(); super.unref(); }
91 String debugToString() { return "[Class: " + utf8.s + "]"; }
94 class NameAndTypeEnt extends Ent {
98 NameAndTypeEnt() { super(CONSTANT_NAMEANDTYPE); }
99 NameAndTypeEnt(String name, String type) {
101 this.name = (Utf8Ent) addUtf8(name);
102 this.type = (Utf8Ent) addUtf8(type);
104 void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(name.n); o.writeShort(type.n); }
105 Object _key() { return new NameAndTypeKey(name.s, type.s); }
106 void unref() { name.unref(); type.unref(); super.unref(); }
109 class MemberEnt extends Ent {
111 NameAndTypeEnt member;
113 MemberEnt(int tag) { super(tag); }
114 MemberEnt(int tag, Type.Class klass, String name, String type) {
116 this.klass = (ClassEnt) add(klass);
117 this.member = addNameAndType(name,type);
120 void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(klass.n); o.writeShort(member.n); }
123 if(member.name == null) throw new Error("should never happen");
125 case CONSTANT_FIELDREF:
126 return klass.getTypeClass().field(member.name.s, Type.fromDescriptor(member.type.s));
127 case CONSTANT_METHODREF:
128 case CONSTANT_INTERFACEMETHODREF:
129 Type.Class.Method m = klass.getTypeClass().method(member.name.s,member.type.s);
130 return tag == CONSTANT_INTERFACEMETHODREF ? (Object) new InterfaceMethodKey(m) : (Object) m;
132 throw new Error("should never happen");
135 void unref() { klass.unref(); member.unref(); super.unref(); }
141 static class Utf8Key {
143 public Utf8Key(String s) { this.s = s; }
144 public boolean equals(Object o) { return o instanceof Utf8Key && ((Utf8Key)o).s.equals(s); }
145 public int hashCode() { return ~s.hashCode(); }
148 static class NameAndTypeKey {
151 NameAndTypeKey(String name, String type) { this.name = name; this.type = type; }
152 public boolean equals(Object o_) {
153 if (!(o_ instanceof NameAndTypeKey)) return false;
154 NameAndTypeKey o = (NameAndTypeKey) o_;
155 return o.name.equals(name) && o.type.equals(type);
157 public int hashCode() { return name.hashCode() ^ type.hashCode(); }
160 static class InterfaceMethodKey {
161 Type.Class.Method method;
162 InterfaceMethodKey(Type.Class.Method method) { this.method = method; }
163 public int hashCode() { return ~method.hashCode(); }
164 public boolean equals(Object o) { return o instanceof InterfaceMethodKey && ((InterfaceMethodKey)o).method.equals(method); }
171 Ent get(Object o) { return (Ent) entries.get(o); }
172 Utf8Ent getUtf8(String s) { return (Utf8Ent) get(new Utf8Key(s)); }
174 int getIndex(Object o) {
176 if (e == null) throw new IllegalStateException("entry not found");
179 int getUtf8Index(String s) {
181 if (e == null) throw new IllegalStateException("entry not found");
184 int getIndex(Ent ent) {
185 if (state < STABLE) throw new IllegalStateException("constant pool is not stable");
189 Ent getByIndex(int index) {
190 if (state < STABLE) throw new IllegalStateException("constant pool is not stable");
192 if (index >= 65536 || index >= entriesByIndex.length || (e = entriesByIndex[index]) == null)
193 throw new IllegalArgumentException("invalid cp index: " + index + "/" + entriesByIndex.length);
197 String getUtf8KeyByIndex(int index) {
198 Ent e = getByIndex(index);
199 if(!(e instanceof Utf8Ent)) throw new IllegalArgumentException("that isn't a utf8 (" + e.debugToString() + ")");
200 return ((Utf8Ent)e).s;
203 Object getKeyByIndex(int index) {
204 Ent e = getByIndex(index);
205 return e == null ? null : e.key();
208 NameAndTypeEnt addNameAndType(String name, String descriptor) { return (NameAndTypeEnt) add(new NameAndTypeKey(name, descriptor)); }
209 Utf8Ent addUtf8(String s) { return (Utf8Ent) add(new Utf8Key(s)); }
212 boolean isInterfaceMethod;
213 if (state == SEALED) throw new IllegalStateException("constant pool is sealed");
217 if (state == OPEN) ent.n++;
221 if (o instanceof Type.Class) { ent = new ClassEnt(((Type.Class)o).internalForm()); }
222 else if (o instanceof String) { ent = new StringLitEnt((String)o); }
223 else if (o instanceof Integer) { ent = new IntLitEnt(((Integer)o).intValue()); }
224 else if (o instanceof Float) { ent = new FloatLitEnt(((Float)o).floatValue()); }
225 else if (o instanceof Long) { ent = new LongLitEnt(((Long)o).longValue()); }
226 else if (o instanceof Double) { ent = new DoubleLitEnt(((Double)o).doubleValue()); }
227 else if (o instanceof Utf8Key) { ent = new Utf8Ent(((Utf8Key)o).s); }
228 else if (o instanceof NameAndTypeKey) {
229 NameAndTypeKey key = (NameAndTypeKey) o;
230 ent = new NameAndTypeEnt(key.name,key.type);
232 else if ((isInterfaceMethod = o instanceof InterfaceMethodKey) || o instanceof Type.Class.Member) {
233 Type.Class.Member m = isInterfaceMethod ? ((InterfaceMethodKey)o).method : (Type.Class.Member) o;
234 int tag = isInterfaceMethod ? CONSTANT_INTERFACEMETHODREF
235 : m instanceof Type.Class.Field ? CONSTANT_FIELDREF
236 : m instanceof Type.Class.Method ? CONSTANT_METHODREF
238 if (tag == 0) throw new Error("should never happen");
239 ent = new MemberEnt(tag, m.getDeclaringClass(), m.name, m.getTypeDescriptor());
242 throw new IllegalArgumentException("Unknown type passed to add");
245 int spaces = ent.slots();
246 if (usedSlots + spaces > 65536) throw new ClassFile.Exn("constant pool full");
248 ent.n = state == OPEN ? 1 : usedSlots; // refcount or index
256 int slots() { return usedSlots; }
258 void seal() { state = SEALED; }
260 private Ent[] asArray() {
261 int count = entries.size();
262 Ent[] ents = new Ent[count];
264 Enumeration e = entries.keys();
265 while(e.hasMoreElements()) ents[i++] = (Ent) entries.get(e.nextElement());
266 if (i != count) throw new Error("should never happen");
270 private void assignIndex(Ent[] ents) {
272 entriesByIndex = new Ent[ents.length*2];
273 for(int i=0;i<ents.length;i++) {
276 entriesByIndex[index] = ent;
277 index += ent.slots();
282 if (state != OPEN) return;
284 assignIndex(asArray());
287 private static final Sort.CompareFunc compareFunc = new Sort.CompareFunc() {
288 public int compare(Object a_, Object b_) {
289 return ((Ent)a_).n - ((Ent)b_).n;
293 private static final Sort.CompareFunc reverseCompareFunc = new Sort.CompareFunc() {
294 public int compare(Object a_, Object b_) {
295 return ((Ent)b_).n - ((Ent)a_).n;
300 if (state != OPEN) throw new IllegalStateException("can't optimize a stable constant pool");
301 Ent[] ents = asArray();
302 Sort.sort(ents, reverseCompareFunc);
307 void dump(DataOutput o) throws IOException {
308 Ent[] ents = asArray();
309 Sort.sort(ents, compareFunc);
310 o.writeShort(usedSlots);
311 for(int i=0;i<ents.length;i++) {
312 //System.err.println("" + ents[i].n + ": " + ents[i].debugToString());
317 ConstantPool(DataInput in) throws ClassFile.ClassReadExn, IOException {
318 usedSlots = in.readUnsignedShort();
319 if (usedSlots==0) throw new ClassFile.ClassReadExn("invalid used slots");
321 // these are to remember the descriptor ents we have to fix up
322 int[] e1s = new int[usedSlots];
323 int[] e2s = new int[usedSlots];
325 entriesByIndex = new Ent[usedSlots];
327 for(int i=1;i<usedSlots;) {
328 byte tag = in.readByte();
331 case CONSTANT_CLASS: // Object Type
333 e1s[i] = in.readUnsignedShort();
335 case CONSTANT_STRING: // String
336 e = new StringLitEnt();
337 e1s[i] = in.readUnsignedShort();
339 case CONSTANT_FIELDREF: // Type.Class.Field
340 case CONSTANT_METHODREF: // Type.Class.Method
341 case CONSTANT_INTERFACEMETHODREF: // Instance Method Ref
342 case CONSTANT_NAMEANDTYPE:
343 e = tag == CONSTANT_NAMEANDTYPE ? (Ent) new NameAndTypeEnt() : (Ent) new MemberEnt(tag);
344 e1s[i] = in.readUnsignedShort();
345 e2s[i] = in.readUnsignedShort();
347 case CONSTANT_INTEGER: // Integer
348 e = new IntLitEnt(in.readInt());
350 case CONSTANT_FLOAT: // Float
351 e = new FloatLitEnt(in.readFloat());
353 case CONSTANT_LONG: // Long
354 e = new LongLitEnt(in.readLong());
356 case CONSTANT_DOUBLE: // Double
357 e = new DoubleLitEnt(in.readDouble());
359 case CONSTANT_UTF8: // Utf8
360 e = new Utf8Ent(in.readUTF());
363 throw new ClassFile.ClassReadExn("invalid cp ent tag: " + tag + " (slot " + i + ")");
365 entriesByIndex[i] = e;
369 for(int i=1;i<usedSlots;) {
370 Ent e = entriesByIndex[i];
371 if (e == null) throw new Error("should never happen: " + i + "/"+usedSlots);
372 boolean isMem = e instanceof MemberEnt;
373 boolean isString = e instanceof StringLitEnt;
374 boolean isClass = e instanceof ClassEnt;
375 boolean isNameAndType = e instanceof NameAndTypeEnt;
376 if (isMem || isClass || isString || isNameAndType) {
377 if (e1s[i] == 0 || e1s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp index");
378 Ent e1 = entriesByIndex[e1s[i]];
379 if(e1 == null) throw new ClassFile.ClassReadExn("invalid cp index");
381 if(!(e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
382 ((ClassEnt)e).utf8 = (Utf8Ent) e1;
383 } else if(isString) {
384 if(!(e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
385 ((StringLitEnt)e).utf8 = (Utf8Ent) e1;
386 } else if(isMem || isNameAndType) {
387 if (e2s[i] == 0 || e2s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp index");
388 Ent e2 = entriesByIndex[e2s[i]];
390 if(!(e1 instanceof ClassEnt)) throw new ClassFile.ClassReadExn("expected a classent");
391 if(!(e2 instanceof NameAndTypeEnt)) throw new ClassFile.ClassReadExn("expected a nameandtypeent, not " + e2);
392 MemberEnt me = (MemberEnt) e;
393 me.klass = (ClassEnt) e1;
394 me.member = (NameAndTypeEnt) e2;
395 } else if(isNameAndType) {
396 if(!(e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
397 if(!(e2 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
398 NameAndTypeEnt nte = (NameAndTypeEnt) e;
399 nte.name = (Utf8Ent) e1;
400 nte.type = (Utf8Ent) e2;
406 for(int i=1; i<usedSlots;) {
407 Ent e = entriesByIndex[i];
408 entries.put(e.key(), e);