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
23 public abstract static class Ent {
24 CPGen owner; // don't need this yet, but we will to implement ref() and unref()
25 int n; // this is the refcount if state == OPEN, index if >= STABLE
28 Ent(CPGen owner, int tag) { this.owner = owner; this.tag = tag; }
30 void dump(DataOutput o) throws IOException { o.writeByte(tag); }
31 String debugToString() { return toString(); } // so we can remove this method when not debugging
32 abstract Object key() throws ClassGen.ClassReadExn; // be careful using this, it drags in a bunch of code
35 // INVARIANTS: tag == 3 || tag == 4
36 static class IntEnt extends Ent {
38 IntEnt(CPGen owner, int tag) { super(owner, tag); }
39 void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i); }
42 case 3: return new Integer(i);
43 case 4: return new Float(Float.intBitsToFloat(i));
44 default: throw new Error("should never happen");
49 // INVARIANTS: tag == 5 || tag == 6
50 static class LongEnt extends Ent {
52 LongEnt(CPGen owner, int tag) { super(owner, tag); }
53 void dump(DataOutput o) throws IOException { super.dump(o); o.writeLong(l); }
56 case 5: return new Long(l);
57 case 6: return new Double(Double.longBitsToDouble(l));
58 default: throw new Error("should never happen");
65 if(tag == 7 || tag == 8) e0 instanceof Utf8Ent
66 if(tag == 9 || tag == 10 || tag == 11) {
67 e0 instanceof CPRefEnt && e0.tag == 7
68 e1 instanceof CPRefEnt && e0.tag == 12
74 static class CPRefEnt extends Ent {
77 CPRefEnt(CPGen owner, int tag) { super(owner, tag); }
79 String debugToString() { return "[" + e1.n + ":" + e1.debugToString() + (e2 == null ? "" : " + " + e2.n + ":" + e2.debugToString()) + "]"; }
81 void dump(DataOutput o) throws IOException {
84 if(e2 != null) o.writeShort(e2.n);
87 private String fixme() { throw new Error("fixme"); }
88 Object key() throws ClassGen.ClassReadExn {
90 case 7: return Type.instance(((Utf8Ent)e1).s);
91 case 8: return (((Utf8Ent)e1).s);
93 NameAndTypeKey nt = (NameAndTypeKey) e2.key();
94 Type t = Type.instance(nt.type);
95 if(t == null) throw new ClassGen.ClassReadExn("invalid type descriptor");
96 return new FieldRef((Type.Class)e1.key(), nt.name, t);
99 NameAndTypeKey nt = (NameAndTypeKey) e2.key();
100 if (e1.key() == null) throw new Error(e1.tag + " => " + e1.key());
101 return new MethodRef((Type.Class)e1.key(), "methodname", Type.VOID, new Type[0]); // FIXME FIXME
104 return new NameAndTypeKey(((Utf8Ent)e1).s, ((Utf8Ent)e2).s);
107 throw new Error("FIXME " + tag);
111 static class Utf8Ent extends Ent {
113 Utf8Ent(CPGen owner) { super(owner, 1); }
114 String debugToString() { return s; }
115 void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
124 public static class Utf8Key {
126 public Utf8Key(String s) { this.s = s; }
127 public boolean equals(Object o) { return o instanceof Utf8Key && ((Utf8Key)o).s.equals(s); }
128 public int hashCode() { return ~s.hashCode(); }
131 public static class NameAndTypeKey {
134 NameAndTypeKey(String name, String type) { this.name = name; this.type = type; }
135 public boolean equals(Object o_) {
136 if(!(o_ instanceof NameAndTypeKey)) return false;
137 NameAndTypeKey o = (NameAndTypeKey) o_;
138 return o.name.equals(name) && o.type.equals(type);
140 public int hashCode() { return name.hashCode() ^ type.hashCode(); }
147 public final Ent get(Object o) { return (Ent) entries.get(o); }
148 public final Ent getUtf8(String s) { return get(new Utf8Key(s)); }
149 public final int getIndex(Object o) {
151 if(e == null) throw new IllegalStateException("entry not found");
154 public final String getUtf8ByIndex(int i) {
155 return ((Utf8Ent)getByIndex(i)).s;
157 public final int getUtf8Index(String s) {
159 if(e == null) throw new IllegalStateException("entry not found");
162 public final int getIndex(Ent ent) {
163 if(state < STABLE) throw new IllegalStateException("constant pool is not stable");
167 public final Type getType(int index) throws ClassGen.ClassReadExn {
168 Ent e = getByIndex(index);
169 if (e instanceof Utf8Ent) return Type.instance(((Utf8Ent)e).s);
170 else return (Type)e.key();
173 public final Ent getByIndex(int index) {
174 if(state < STABLE) throw new IllegalStateException("constant pool is not stable");
176 if(index >= 65536 || index >= entriesByIndex.length || (e = entriesByIndex[index]) == null)
177 throw new IllegalStateException("invalid cp index");
181 public final Ent addNameAndType(String name, String descriptor) { return add(new NameAndTypeKey(name, descriptor)); }
182 public final Ent addUtf8(String s) { return add(new Utf8Key(s)); }
184 public final Ent add(Object o) {
185 if(state == SEALED) throw new IllegalStateException("constant pool is sealed");
189 if(state == OPEN) ent.n++;
193 if(o instanceof Type.Class) {
194 CPRefEnt ce = new CPRefEnt(this, 7);
195 ce.e1 = addUtf8(((Type.Class)o).internalForm());
197 } else if(o instanceof String) {
198 CPRefEnt ce = new CPRefEnt(this, 8);
199 ce.e1 = addUtf8((String)o);
201 } else if(o instanceof Integer) {
202 IntEnt ue = new IntEnt(this, 3);
203 ue.i = ((Integer)o).intValue();
205 } else if(o instanceof Float) {
206 IntEnt ue = new IntEnt(this, 4);
207 ue.i = Float.floatToIntBits(((Float)o).floatValue());
209 } else if(o instanceof Long) {
210 LongEnt le = new LongEnt(this, 5);
211 le.l = ((Long)o).longValue();
213 } else if(o instanceof Double) {
214 LongEnt le = new LongEnt(this, 6);
215 le.l = Double.doubleToLongBits(((Double)o).doubleValue());
217 } else if(o instanceof Utf8Key) {
218 Utf8Ent ue = new Utf8Ent(this);
219 ue.s = ((Utf8Key)o).s;
221 } else if(o instanceof NameAndTypeKey) {
222 CPRefEnt ce = new CPRefEnt(this, 12);
223 NameAndTypeKey key = (NameAndTypeKey) o;
224 ce.e1 = addUtf8(key.name);
225 ce.e2 = addUtf8(key.type);
227 } else if(o instanceof ClassGen.FieldOrMethodRef) {
228 ClassGen.FieldOrMethodRef key = (ClassGen.FieldOrMethodRef) o;
229 int tag = o instanceof FieldRef ? 9 : o instanceof MethodRef ? 10 : o instanceof MethodRef.I ? 11 : 0;
230 if(tag == 0) throw new Error("should never happen");
231 CPRefEnt ce = new CPRefEnt(this, tag);
232 ce.e1 = add(key.klass);
233 ce.e2 = addNameAndType(key.name, key.descriptor);
236 throw new IllegalArgumentException("Unknown type passed to add");
239 int spaces = ent instanceof LongEnt ? 2 : 1;
240 if(usedSlots + spaces > 65536) throw new ClassGen.Exn("constant pool full");
242 ent.n = state == OPEN ? 1 : usedSlots; // refcount or index
250 public int slots() { return usedSlots; }
252 public void seal() { state = SEALED; }
254 private Ent[] asArray() {
255 int count = entries.size();
256 Ent[] ents = new Ent[count];
258 Enumeration e = entries.keys();
259 while(e.hasMoreElements()) ents[i++] = (Ent) entries.get(e.nextElement());
260 if(i != count) throw new Error("should never happen");
264 private void assignIndex(Ent[] ents) {
266 entriesByIndex = new Ent[ents.length*2];
267 for(int i=0;i<ents.length;i++) {
270 entriesByIndex[index] = ent;
271 index += ent instanceof LongEnt ? 2 : 1;
275 public void stable() {
276 if(state != OPEN) return;
278 assignIndex(asArray());
281 private static final Sort.CompareFunc compareFunc = new Sort.CompareFunc() {
282 public int compare(Object a_, Object b_) {
283 return ((Ent)a_).n - ((Ent)b_).n;
287 private static final Sort.CompareFunc reverseCompareFunc = new Sort.CompareFunc() {
288 public int compare(Object a_, Object b_) {
289 return ((Ent)b_).n - ((Ent)a_).n;
293 public void optimize() {
294 if(state != OPEN) throw new IllegalStateException("can't optimize a stable constant pool");
295 Ent[] ents = asArray();
296 Sort.sort(ents, reverseCompareFunc);
301 public void unsafeReopen() {
302 if(state == OPEN) return;
303 for(int i=1;i<entriesByIndex.length;i++) {
304 Ent e = entriesByIndex[i];
305 if(e == null) continue;
308 entriesByIndex = null;
312 public void dump(DataOutput o) throws IOException {
313 Ent[] ents = asArray();
314 Sort.sort(ents, compareFunc);
315 o.writeShort(usedSlots);
316 for(int i=0;i<ents.length;i++) {
317 //System.err.println("" + ents[i].n + ": " + ents[i].debugToString());
322 CPGen(DataInput in) throws ClassGen.ClassReadExn, IOException {
323 usedSlots = in.readUnsignedShort();
324 if(usedSlots==0) throw new ClassGen.ClassReadExn("invalid used slots");
326 // these are to remember the CPRefEnt e1 and e2s we have to fix up
327 int[] e1s = new int[usedSlots];
328 int[] e2s = new int[usedSlots];
330 entriesByIndex = new Ent[usedSlots];
332 for(int index=1;index<usedSlots;index++) {
333 byte tag = in.readByte();
336 case 7: // Object Type
339 case 10: // MethodRef
340 case 11: // Instance Method Ref
341 case 12: // NameAndType
343 e = new CPRefEnt(this, tag);
344 e1s[index] = in.readUnsignedShort();
345 if(tag != 7 && tag != 8) e2s[index] = in.readUnsignedShort();
352 e = ie = new IntEnt(this, tag);
360 e = le = new LongEnt(this, tag);
361 le.l = in.readLong();
367 e = ue = new Utf8Ent(this);
372 throw new ClassGen.ClassReadExn("invalid cp ent tag");
374 entriesByIndex[index] = e;
375 if (e instanceof LongEnt) index++;
378 for(int index=1;index<usedSlots;index++) {
380 Ent e = entriesByIndex[index];
381 if (e == null) throw new Error("should never happen: " + i + "/"+usedSlots);
382 if (e instanceof LongEnt) {
386 if (!(e instanceof CPRefEnt)) continue;
387 CPRefEnt ce = (CPRefEnt) e;
388 if(e1s[i] == 0 || e1s[i] >= usedSlots) throw new ClassGen.ClassReadExn("invalid cp index");
389 ce.e1 = entriesByIndex[e1s[i]];
390 if(ce.e1 == null) throw new ClassGen.ClassReadExn("invalid cp index");
391 if(ce.tag != 7 && ce.tag != 8) {
392 if(e2s[i] == 0 || e2s[i] >= usedSlots) throw new ClassGen.ClassReadExn("invalid cp index");
393 ce.e2 = entriesByIndex[e2s[i]];
394 if(ce.e2 == null) throw new ClassGen.ClassReadExn("invalid cp index");
399 if(!(ce.e1 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
404 if(!(ce.e1 instanceof CPRefEnt) || ((CPRefEnt)ce.e1).tag != 7)
405 throw new ClassGen.ClassReadExn("expected a type ent");
406 if(!(ce.e2 instanceof CPRefEnt) || ((CPRefEnt)ce.e2).tag != 12)
407 throw new ClassGen.ClassReadExn("expected a name and type ent");
410 if(!(ce.e1 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
411 if(!(ce.e2 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
415 for(int i=1; i<usedSlots; i++) {
416 Ent e = entriesByIndex[i];
417 entries.put(e.key(), e);
418 if (e instanceof LongEnt) i++;