1 package org.ibex.classgen;
6 import org.ibex.classgen.util.*;
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
23 Ent(int tag) { this.tag = tag; }
24 void dump(DataOutput o) throws IOException { o.writeByte(tag); }
25 String debugToString() { return toString(); } // so we can remove this method when not debugging
26 abstract Object key() throws ClassFile.ClassReadExn; // be careful using this, it drags in a bunch of code
29 class IntEnt extends Ent {
31 IntEnt(int i) { super(3); this.i = i; }
32 void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i); }
33 Object key() { return new Integer(i); }
36 class FloatEnt extends Ent {
38 FloatEnt(float f) { super(4); this.f = f; }
39 void dump(DataOutput o) throws IOException { super.dump(o); o.writeFloat(f); }
40 Object key() { return new Float(f); }
42 class LongEnt extends Ent {
44 LongEnt(long l) { super(5); this.l = l; }
45 void dump(DataOutput o) throws IOException { super.dump(o); o.writeLong(l); }
46 Object key() { return new Long(l); }
48 class DoubleEnt extends Ent {
50 DoubleEnt(double d) { super(6); this.d = d; }
51 void dump(DataOutput o) throws IOException { super.dump(o); o.writeDouble(d); }
52 Object key() { return new Double(d); }
57 if (tag == 7 || tag == 8) e0 instanceof Utf8Ent
58 if (tag == 9 || tag == 10 || tag == 11) {
59 e0 instanceof CPRefEnt && e0.tag == 7
60 e1 instanceof CPRefEnt && e0.tag == 12
66 class CPRefEnt extends Ent {
69 CPRefEnt(int tag) { super(tag); }
71 String debugToString() { return "[" + e1.n + ":" + e1.debugToString() + (e2 == null ? "" : " + " + e2.n + ":" + e2.debugToString()) + "]"; }
73 void dump(DataOutput o) throws IOException {
76 if (e2 != null) o.writeShort(e2.n);
79 private String fixme() { throw new Error("fixme"); }
80 Object key() throws ClassFile.ClassReadExn {
82 case 7: return Type.instance(((Utf8Ent)e1).s);
83 case 8: return (((Utf8Ent)e1).s);
85 NameAndTypeKey nt = (NameAndTypeKey) e2.key();
86 Type t = Type.instance(nt.type);
87 if (t == null) throw new ClassFile.ClassReadExn("invalid type descriptor");
88 return ((Type.Class)e1.key()).field(nt.name, t);
91 NameAndTypeKey nt = (NameAndTypeKey) e2.key();
92 if (e1.key() == null) throw new Error(e1.tag + " => " + e1.key());
93 return ((Type.Class)e1.key()).method("methodname", Type.VOID, new Type[0]); // FIXME FIXME
96 return new NameAndTypeKey(((Utf8Ent)e1).s, ((Utf8Ent)e2).s);
99 throw new Error("FIXME " + tag);
103 class Utf8Ent extends Ent {
105 Utf8Ent() { super(1); }
106 String debugToString() { return s; }
107 void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
116 public static class Utf8Key {
118 public Utf8Key(String s) { this.s = s; }
119 public boolean equals(Object o) { return o instanceof Utf8Key && ((Utf8Key)o).s.equals(s); }
120 public int hashCode() { return ~s.hashCode(); }
123 public static class NameAndTypeKey {
126 NameAndTypeKey(String name, String type) { this.name = name; this.type = type; }
127 public boolean equals(Object o_) {
128 if (!(o_ instanceof NameAndTypeKey)) return false;
129 NameAndTypeKey o = (NameAndTypeKey) o_;
130 return o.name.equals(name) && o.type.equals(type);
132 public int hashCode() { return name.hashCode() ^ type.hashCode(); }
139 public final Ent get(Object o) { return (Ent) entries.get(o); }
140 public final Ent getUtf8(String s) { return get(new Utf8Key(s)); }
141 public final int getIndex(Object o) {
143 if (e == null) throw new IllegalStateException("entry not found");
146 public final String getUtf8ByIndex(int i) {
147 return ((Utf8Ent)getByIndex(i)).s;
149 public final int getUtf8Index(String s) {
151 if (e == null) throw new IllegalStateException("entry not found");
154 public final int getIndex(Ent ent) {
155 if (state < STABLE) throw new IllegalStateException("constant pool is not stable");
159 public final Type getType(int index) throws ClassFile.ClassReadExn {
160 Ent e = getByIndex(index);
161 if (e instanceof Utf8Ent) return Type.instance(((Utf8Ent)e).s);
162 else return (Type)e.key();
165 public final Ent getByIndex(int index) {
166 if (state < STABLE) throw new IllegalStateException("constant pool is not stable");
168 if (index >= 65536 || index >= entriesByIndex.length || (e = entriesByIndex[index]) == null)
169 throw new IllegalStateException("invalid cp index");
173 public final Ent addNameAndType(String name, String descriptor) { return add(new NameAndTypeKey(name, descriptor)); }
174 public final Ent addUtf8(String s) { return add(new Utf8Key(s)); }
176 public final Ent add(Object o) { return add(o, false); }
177 public final Ent add(Object o, boolean invokeInterface) {
178 if (state == SEALED) throw new IllegalStateException("constant pool is sealed");
182 if (state == OPEN) ent.n++;
186 if (o instanceof Type.Class) {
187 CPRefEnt ce = new CPRefEnt(7);
188 ce.e1 = addUtf8(((Type.Class)o).internalForm());
190 } else if (o instanceof String) {
191 CPRefEnt ce = new CPRefEnt(8);
192 ce.e1 = addUtf8((String)o);
194 } else if (o instanceof Integer) { ent = new IntEnt(((Integer)o).intValue());
195 } else if (o instanceof Float) { ent = new FloatEnt(((Float)o).floatValue());
196 } else if (o instanceof Long) { ent = new LongEnt(((Long)o).longValue());
197 } else if (o instanceof Double) { ent = new DoubleEnt(((Double)o).doubleValue());
198 } else if (o instanceof Utf8Key) {
199 Utf8Ent ue = new Utf8Ent();
200 ue.s = ((Utf8Key)o).s;
202 } else if (o instanceof NameAndTypeKey) {
203 CPRefEnt ce = new CPRefEnt(12);
204 NameAndTypeKey key = (NameAndTypeKey) o;
205 ce.e1 = addUtf8(key.name);
206 ce.e2 = addUtf8(key.type);
208 } else if (o instanceof Type.Class.Member) {
209 Type.Class.Member key = (Type.Class.Member) o;
210 int tag = invokeInterface ? 11 : o instanceof Type.Class.Field ? 9 : o instanceof Type.Class.Method ? 10 : 0;
211 if (tag == 0) throw new Error("should never happen");
212 CPRefEnt ce = new CPRefEnt(tag);
213 ce.e1 = add(key.getDeclaringClass());
214 ce.e2 = addNameAndType(key.name, key.getDescriptor());
217 throw new IllegalArgumentException("Unknown type passed to add");
220 int spaces = ent instanceof LongEnt ? 2 : 1;
221 if (usedSlots + spaces > 65536) throw new ClassFile.Exn("constant pool full");
223 ent.n = state == OPEN ? 1 : usedSlots; // refcount or index
231 public int slots() { return usedSlots; }
233 public void seal() { state = SEALED; }
235 private Ent[] asArray() {
236 int count = entries.size();
237 Ent[] ents = new Ent[count];
239 Enumeration e = entries.keys();
240 while(e.hasMoreElements()) ents[i++] = (Ent) entries.get(e.nextElement());
241 if (i != count) throw new Error("should never happen");
245 private void assignIndex(Ent[] ents) {
247 entriesByIndex = new Ent[ents.length*2];
248 for(int i=0;i<ents.length;i++) {
251 entriesByIndex[index] = ent;
252 index += ent instanceof LongEnt ? 2 : 1;
256 public void stable() {
257 if (state != OPEN) return;
259 assignIndex(asArray());
262 private static final Sort.CompareFunc compareFunc = new Sort.CompareFunc() {
263 public int compare(Object a_, Object b_) {
264 return ((Ent)a_).n - ((Ent)b_).n;
268 private static final Sort.CompareFunc reverseCompareFunc = new Sort.CompareFunc() {
269 public int compare(Object a_, Object b_) {
270 return ((Ent)b_).n - ((Ent)a_).n;
274 public void optimize() {
275 if (state != OPEN) throw new IllegalStateException("can't optimize a stable constant pool");
276 Ent[] ents = asArray();
277 Sort.sort(ents, reverseCompareFunc);
282 public void unsafeReopen() {
283 if (state == OPEN) return;
284 for(int i=1;i<entriesByIndex.length;i++) {
285 Ent e = entriesByIndex[i];
286 if (e == null) continue;
289 entriesByIndex = null;
293 public void dump(DataOutput o) throws IOException {
294 Ent[] ents = asArray();
295 Sort.sort(ents, compareFunc);
296 o.writeShort(usedSlots);
297 for(int i=0;i<ents.length;i++) {
298 //System.err.println("" + ents[i].n + ": " + ents[i].debugToString());
303 ConstantPool(DataInput in) throws ClassFile.ClassReadExn, IOException {
304 usedSlots = in.readUnsignedShort();
305 if (usedSlots==0) throw new ClassFile.ClassReadExn("invalid used slots");
307 // these are to remember the CPRefEnt e1 and e2s we have to fix up
308 int[] e1s = new int[usedSlots];
309 int[] e2s = new int[usedSlots];
311 entriesByIndex = new Ent[usedSlots];
313 for(int index=1;index<usedSlots;index++) {
314 byte tag = in.readByte();
317 case 7: // Object Type
319 case 9: // Type.Class.Field
320 case 10: // Type.Class.Method
321 case 11: // Instance Method Ref
322 case 12: // NameAndType
324 e = new CPRefEnt(tag);
325 e1s[index] = in.readUnsignedShort();
326 if (tag != 7 && tag != 8) e2s[index] = in.readUnsignedShort();
332 e = ie = new FloatEnt(in.readFloat());
338 e = ie = new IntEnt(in.readInt());
345 e = le = new LongEnt(tag);
346 le.l = in.readLong();
352 e = ue = new Utf8Ent();
357 throw new ClassFile.ClassReadExn("invalid cp ent tag");
359 entriesByIndex[index] = e;
360 if (e instanceof LongEnt) index++;
363 for(int i=1;i<usedSlots;i++) {
364 Ent e = entriesByIndex[i];
365 if (e == null) throw new Error("should never happen: " + i + "/"+usedSlots);
366 if (e instanceof LongEnt) {
370 if (!(e instanceof CPRefEnt)) continue;
371 CPRefEnt ce = (CPRefEnt) e;
372 if (e1s[i] == 0 || e1s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp i");
373 ce.e1 = entriesByIndex[e1s[i]];
374 if (ce.e1 == null) throw new ClassFile.ClassReadExn("invalid cp i");
375 if (ce.tag != 7 && ce.tag != 8) {
376 if (e2s[i] == 0 || e2s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp i");
377 ce.e2 = entriesByIndex[e2s[i]];
378 if (ce.e2 == null) throw new ClassFile.ClassReadExn("invalid cp i");
383 if (!(ce.e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a utf8 ent");
388 if (!(ce.e1 instanceof CPRefEnt) || ((CPRefEnt)ce.e1).tag != 7)
389 throw new ClassFile.ClassReadExn("expected a type ent");
390 if (!(ce.e2 instanceof CPRefEnt) || ((CPRefEnt)ce.e2).tag != 12)
391 throw new ClassFile.ClassReadExn("expected a name and type ent");
394 if (!(ce.e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a utf8 ent");
395 if (!(ce.e2 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a utf8 ent");
399 for(int i=1; i<usedSlots; i++) {
400 Ent e = entriesByIndex[i];
401 entries.put(e.key(), e);
402 if (e instanceof LongEnt) i++;