import org.ibex.classgen.util.*;
-class ConstantPool {
+class ConstantPool implements CGConst {
private final Hashtable entries = new Hashtable();
private Ent[] entriesByIndex; // only valid when stable
public abstract class Ent {
int n; // this is the refcount if state == OPEN, index if >= STABLE
int tag;
+ Object key;
Ent(int tag) { this.tag = tag; }
void dump(DataOutput o) throws IOException { o.writeByte(tag); }
String debugToString() { return toString(); } // so we can remove this method when not debugging
- abstract Object key() throws ClassFile.ClassReadExn; // be careful using this, it drags in a bunch of code
+ abstract Object _key();
+ final Object key() { return key == null ? (key = _key()) : key; }
+ int slots() { return 1; } // number of slots this ent takes up
+ void ref() {
+ if(state != OPEN) throw new IllegalStateException("cp is not open");
+ n++;
+ }
+ void unref() {
+ if(state != OPEN) throw new IllegalStateException("cp is not open");
+ if(--n == 0) entries.remove(key());
+ }
+ }
+
+ class Utf8Ent extends Ent {
+ String s;
+ Utf8Ent() { super(CONSTANT_UTF8); }
+ Utf8Ent(String s) { this(); this.s = s; }
+ String debugToString() { return s; }
+ void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
+ Object _key() { return new Utf8Key(s); }
}
- class IntEnt extends Ent {
+ class IntLitEnt extends Ent {
final int i;
- IntEnt(int i) { super(3); this.i = i; }
+ IntLitEnt(int i) { super(CONSTANT_INTEGER); this.i = i; }
void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i); }
- Object key() { return new Integer(i); }
+ Object _key() { return new Integer(i); }
}
-
- class FloatEnt extends Ent {
+ class FloatLitEnt extends Ent {
final float f;
- FloatEnt(float f) { super(4); this.f = f; }
+ FloatLitEnt(float f) { super(CONSTANT_FLOAT); this.f = f; }
void dump(DataOutput o) throws IOException { super.dump(o); o.writeFloat(f); }
- Object key() { return new Float(f); }
+ Object _key() { return new Float(f); }
}
- class LongEnt extends Ent {
+ class LongLitEnt extends Ent {
final long l;
- LongEnt(long l) { super(5); this.l = l; }
+ LongLitEnt(long l) { super(CONSTANT_LONG); this.l = l; }
void dump(DataOutput o) throws IOException { super.dump(o); o.writeLong(l); }
- Object key() { return new Long(l); }
+ Object _key() { return new Long(l); }
+ int slots() { return 2; }
}
- class DoubleEnt extends Ent {
+ class DoubleLitEnt extends Ent {
final double d;
- DoubleEnt(double d) { super(6); this.d = d; }
+ DoubleLitEnt(double d) { super(CONSTANT_DOUBLE); this.d = d; }
void dump(DataOutput o) throws IOException { super.dump(o); o.writeDouble(d); }
- Object key() { return new Double(d); }
+ Object _key() { return new Double(d); }
+ int slots() { return 2; }
+ }
+ class StringLitEnt extends Ent {
+ Utf8Ent utf8;
+ StringLitEnt() { super(CONSTANT_STRING); }
+ StringLitEnt(String s) { this(); this.utf8 = (Utf8Ent)addUtf8(s); }
+ void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(utf8.n); }
+ Object _key() { return utf8.s; }
+ void unref() { utf8.unref(); super.unref(); }
+ }
+ class ClassEnt extends Ent {
+ Utf8Ent utf8;
+ ClassEnt() { super(CONSTANT_CLASS); }
+ ClassEnt(String s) { this(); this.utf8 = (Utf8Ent) addUtf8(s); }
+ void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(utf8.n); }
+ Type.Class getTypeClass() { return (Type.Class) key(); }
+ Object _key() { return new Type.Class(utf8.s); }
+ void unref() { utf8.unref(); super.unref(); }
+ String debugToString() { return "[Class: " + utf8.s + "]"; }
}
- /* INVARIANTS:
- tag >= 7 && tag <= 12
- if (tag == 7 || tag == 8) e0 instanceof Utf8Ent
- if (tag == 9 || tag == 10 || tag == 11) {
- e0 instanceof CPRefEnt && e0.tag == 7
- e1 instanceof CPRefEnt && e0.tag == 12
- }
- if (tag == 12) {
- e0 instanceof Utf8Ent
- }
- */
- class CPRefEnt extends Ent {
- Ent e1;
- Ent e2;
- CPRefEnt(int tag) { super(tag); }
+ class NameAndTypeEnt extends Ent {
+ Utf8Ent name;
+ Utf8Ent type;
- String debugToString() { return "[" + e1.n + ":" + e1.debugToString() + (e2 == null ? "" : " + " + e2.n + ":" + e2.debugToString()) + "]"; }
+ NameAndTypeEnt() { super(CONSTANT_NAMEANDTYPE); }
+ NameAndTypeEnt(String name, String type) {
+ this();
+ this.name = (Utf8Ent) addUtf8(name);
+ this.type = (Utf8Ent) addUtf8(type);
+ }
+ void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(name.n); o.writeShort(type.n); }
+ Object _key() { return new NameAndTypeKey(name.s, type.s); }
+ void unref() { name.unref(); type.unref(); super.unref(); }
+ }
+
+ class MemberEnt extends Ent {
+ ClassEnt klass;
+ NameAndTypeEnt member;
- void dump(DataOutput o) throws IOException {
- super.dump(o);
- o.writeShort(e1.n);
- if (e2 != null) o.writeShort(e2.n);
+ MemberEnt(int tag) { super(tag); }
+ MemberEnt(int tag, Type.Class klass, String name, String type) {
+ this(tag);
+ this.klass = (ClassEnt) add(klass);
+ this.member = addNameAndType(name,type);
}
- private String fixme() { throw new Error("fixme"); }
- Object key() throws ClassFile.ClassReadExn {
+ void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(klass.n); o.writeShort(member.n); }
+
+ Object _key() {
+ if(member.name == null) throw new Error("should never happen");
switch(tag) {
- case 7: return Type.instance(((Utf8Ent)e1).s);
- case 8: return (((Utf8Ent)e1).s);
- case 9: {
- NameAndTypeKey nt = (NameAndTypeKey) e2.key();
- Type t = Type.instance(nt.type);
- if (t == null) throw new ClassFile.ClassReadExn("invalid type descriptor");
- return ((Type.Class)e1.key()).field(nt.name, t);
- }
- case 10: case 11: {
- NameAndTypeKey nt = (NameAndTypeKey) e2.key();
- if (e1.key() == null) throw new Error(e1.tag + " => " + e1.key());
- return ((Type.Class)e1.key()).method("methodname", Type.VOID, new Type[0]); // FIXME FIXME
- }
- case 12: {
- return new NameAndTypeKey(((Utf8Ent)e1).s, ((Utf8Ent)e2).s);
- }
+ case CONSTANT_FIELDREF:
+ return klass.getTypeClass().field(member.name.s, Type.fromDescriptor(member.type.s));
+ case CONSTANT_METHODREF:
+ case CONSTANT_INTERFACEMETHODREF:
+ Type.Class.Method m = klass.getTypeClass().method(member.name.s,member.type.s);
+ return tag == CONSTANT_INTERFACEMETHODREF ? (Object) new InterfaceMethodKey(m) : (Object) m;
+ default:
+ throw new Error("should never happen");
}
- throw new Error("FIXME " + tag);
- }
- }
-
- class Utf8Ent extends Ent {
- String s;
- Utf8Ent() { super(1); }
- String debugToString() { return s; }
- void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
- Object key() {
- return s;
}
+ void unref() { klass.unref(); member.unref(); super.unref(); }
}
/*
* Cache Keys
*/
- public static class Utf8Key {
+ static class Utf8Key {
String s;
public Utf8Key(String s) { this.s = s; }
public boolean equals(Object o) { return o instanceof Utf8Key && ((Utf8Key)o).s.equals(s); }
public int hashCode() { return ~s.hashCode(); }
}
- public static class NameAndTypeKey {
+ static class NameAndTypeKey {
String name;
String type;
NameAndTypeKey(String name, String type) { this.name = name; this.type = type; }
public int hashCode() { return name.hashCode() ^ type.hashCode(); }
}
+ static class InterfaceMethodKey {
+ Type.Class.Method method;
+ InterfaceMethodKey(Type.Class.Method method) { this.method = method; }
+ public int hashCode() { return ~method.hashCode(); }
+ public boolean equals(Object o) { return o instanceof InterfaceMethodKey && ((InterfaceMethodKey)o).method.equals(method); }
+ }
+
/*
* Methods
*/
- public final Ent get(Object o) { return (Ent) entries.get(o); }
- public final Ent getUtf8(String s) { return get(new Utf8Key(s)); }
- public final int getIndex(Object o) {
+ Ent get(Object o) { return (Ent) entries.get(o); }
+ Utf8Ent getUtf8(String s) { return (Utf8Ent) get(new Utf8Key(s)); }
+
+ int getIndex(Object o) {
Ent e = get(o);
if (e == null) throw new IllegalStateException("entry not found");
return getIndex(e);
}
- public final String getUtf8ByIndex(int i) {
- return ((Utf8Ent)getByIndex(i)).s;
- }
- public final int getUtf8Index(String s) {
+ int getUtf8Index(String s) {
Ent e = getUtf8(s);
if (e == null) throw new IllegalStateException("entry not found");
return getIndex(e);
}
- public final int getIndex(Ent ent) {
+ int getIndex(Ent ent) {
if (state < STABLE) throw new IllegalStateException("constant pool is not stable");
return ent.n;
}
-
- public final Type getType(int index) throws ClassFile.ClassReadExn {
- Ent e = getByIndex(index);
- if (e instanceof Utf8Ent) return Type.instance(((Utf8Ent)e).s);
- else return (Type)e.key();
- }
-
- public final Ent getByIndex(int index) {
+
+ Ent getByIndex(int index) {
if (state < STABLE) throw new IllegalStateException("constant pool is not stable");
Ent e;
if (index >= 65536 || index >= entriesByIndex.length || (e = entriesByIndex[index]) == null)
- throw new IllegalStateException("invalid cp index");
+ throw new IllegalArgumentException("invalid cp index: " + index + "/" + entriesByIndex.length);
return e;
}
- public final Ent addNameAndType(String name, String descriptor) { return add(new NameAndTypeKey(name, descriptor)); }
- public final Ent addUtf8(String s) { return add(new Utf8Key(s)); }
+ String getUtf8KeyByIndex(int index) {
+ Ent e = getByIndex(index);
+ if(!(e instanceof Utf8Ent)) throw new IllegalArgumentException("that isn't a utf8 (" + e.debugToString() + ")");
+ return ((Utf8Ent)e).s;
+ }
+
+ Object getKeyByIndex(int index) {
+ Ent e = getByIndex(index);
+ return e == null ? null : e.key();
+ }
- public final Ent add(Object o) { return add(o, false); }
- public final Ent add(Object o, boolean invokeInterface) {
+ NameAndTypeEnt addNameAndType(String name, String descriptor) { return (NameAndTypeEnt) add(new NameAndTypeKey(name, descriptor)); }
+ Utf8Ent addUtf8(String s) { return (Utf8Ent) add(new Utf8Key(s)); }
+
+ Ent add(Object o) {
+ boolean isInterfaceMethod;
if (state == SEALED) throw new IllegalStateException("constant pool is sealed");
-
+
Ent ent = get(o);
if (ent != null) {
if (state == OPEN) ent.n++;
return ent;
}
- if (o instanceof Type.Class) {
- CPRefEnt ce = new CPRefEnt(7);
- ce.e1 = addUtf8(((Type.Class)o).internalForm());
- ent = ce;
- } else if (o instanceof String) {
- CPRefEnt ce = new CPRefEnt(8);
- ce.e1 = addUtf8((String)o);
- ent = ce;
- } else if (o instanceof Integer) { ent = new IntEnt(((Integer)o).intValue());
- } else if (o instanceof Float) { ent = new FloatEnt(((Float)o).floatValue());
- } else if (o instanceof Long) { ent = new LongEnt(((Long)o).longValue());
- } else if (o instanceof Double) { ent = new DoubleEnt(((Double)o).doubleValue());
- } else if (o instanceof Utf8Key) {
- Utf8Ent ue = new Utf8Ent();
- ue.s = ((Utf8Key)o).s;
- ent = ue;
- } else if (o instanceof NameAndTypeKey) {
- CPRefEnt ce = new CPRefEnt(12);
+ if (o instanceof Type.Class) { ent = new ClassEnt(((Type.Class)o).internalForm()); }
+ else if (o instanceof String) { ent = new StringLitEnt((String)o); }
+ else if (o instanceof Integer) { ent = new IntLitEnt(((Integer)o).intValue()); }
+ else if (o instanceof Float) { ent = new FloatLitEnt(((Float)o).floatValue()); }
+ else if (o instanceof Long) { ent = new LongLitEnt(((Long)o).longValue()); }
+ else if (o instanceof Double) { ent = new DoubleLitEnt(((Double)o).doubleValue()); }
+ else if (o instanceof Utf8Key) { ent = new Utf8Ent(((Utf8Key)o).s); }
+ else if (o instanceof NameAndTypeKey) {
NameAndTypeKey key = (NameAndTypeKey) o;
- ce.e1 = addUtf8(key.name);
- ce.e2 = addUtf8(key.type);
- ent = ce;
- } else if (o instanceof Type.Class.Member) {
- Type.Class.Member key = (Type.Class.Member) o;
- int tag = invokeInterface ? 11 : o instanceof Type.Class.Field ? 9 : o instanceof Type.Class.Method ? 10 : 0;
+ ent = new NameAndTypeEnt(key.name,key.type);
+ }
+ else if ((isInterfaceMethod = o instanceof InterfaceMethodKey) || o instanceof Type.Class.Member) {
+ Type.Class.Member m = isInterfaceMethod ? ((InterfaceMethodKey)o).method : (Type.Class.Member) o;
+ int tag = isInterfaceMethod ? CONSTANT_INTERFACEMETHODREF
+ : m instanceof Type.Class.Field ? CONSTANT_FIELDREF
+ : m instanceof Type.Class.Method ? CONSTANT_METHODREF
+ : 0;
if (tag == 0) throw new Error("should never happen");
- CPRefEnt ce = new CPRefEnt(tag);
- ce.e1 = add(key.getDeclaringClass());
- ce.e2 = addNameAndType(key.name, key.getDescriptor());
- ent = ce;
- } else {
+ ent = new MemberEnt(tag, m.getDeclaringClass(), m.name, m.getTypeDescriptor());
+ }
+ else {
throw new IllegalArgumentException("Unknown type passed to add");
}
- int spaces = ent instanceof LongEnt ? 2 : 1;
+ int spaces = ent.slots();
if (usedSlots + spaces > 65536) throw new ClassFile.Exn("constant pool full");
ent.n = state == OPEN ? 1 : usedSlots; // refcount or index
return ent;
}
- public int slots() { return usedSlots; }
+ int slots() { return usedSlots; }
- public void seal() { state = SEALED; }
+ void seal() { state = SEALED; }
private Ent[] asArray() {
int count = entries.size();
Ent ent = ents[i];
ent.n = index;
entriesByIndex[index] = ent;
- index += ent instanceof LongEnt ? 2 : 1;
+ index += ent.slots();
}
}
- public void stable() {
+ void stable() {
if (state != OPEN) return;
state = STABLE;
assignIndex(asArray());
}
};
- public void optimize() {
+ void optimize() {
if (state != OPEN) throw new IllegalStateException("can't optimize a stable constant pool");
Ent[] ents = asArray();
Sort.sort(ents, reverseCompareFunc);
assignIndex(ents);
}
- public void unsafeReopen() {
- if (state == OPEN) return;
- for(int i=1;i<entriesByIndex.length;i++) {
- Ent e = entriesByIndex[i];
- if (e == null) continue;
- e.n = 0;
- }
- entriesByIndex = null;
- state = OPEN;
- }
-
- public void dump(DataOutput o) throws IOException {
+ void dump(DataOutput o) throws IOException {
Ent[] ents = asArray();
Sort.sort(ents, compareFunc);
o.writeShort(usedSlots);
usedSlots = in.readUnsignedShort();
if (usedSlots==0) throw new ClassFile.ClassReadExn("invalid used slots");
- // these are to remember the CPRefEnt e1 and e2s we have to fix up
+ // these are to remember the descriptor ents we have to fix up
int[] e1s = new int[usedSlots];
int[] e2s = new int[usedSlots];
entriesByIndex = new Ent[usedSlots];
- for(int index=1;index<usedSlots;index++) {
+ for(int i=1;i<usedSlots;) {
byte tag = in.readByte();
Ent e;
switch(tag) {
- case 7: // Object Type
- case 8: // String
- case 9: // Type.Class.Field
- case 10: // Type.Class.Method
- case 11: // Instance Method Ref
- case 12: // NameAndType
- {
- e = new CPRefEnt(tag);
- e1s[index] = in.readUnsignedShort();
- if (tag != 7 && tag != 8) e2s[index] = in.readUnsignedShort();
+ case CONSTANT_CLASS: // Object Type
+ e = new ClassEnt();
+ e1s[i] = in.readUnsignedShort();
break;
- }
- case 3: // Integer
- {
- FloatEnt ie;
- e = ie = new FloatEnt(in.readFloat());
+ case CONSTANT_STRING: // String
+ e = new StringLitEnt();
+ e1s[i] = in.readUnsignedShort();
break;
- }
- case 4: // Float
- {
- IntEnt ie;
- e = ie = new IntEnt(in.readInt());
+ case CONSTANT_FIELDREF: // Type.Class.Field
+ case CONSTANT_METHODREF: // Type.Class.Method
+ case CONSTANT_INTERFACEMETHODREF: // Instance Method Ref
+ case CONSTANT_NAMEANDTYPE:
+ e = tag == CONSTANT_NAMEANDTYPE ? (Ent) new NameAndTypeEnt() : (Ent) new MemberEnt(tag);
+ e1s[i] = in.readUnsignedShort();
+ e2s[i] = in.readUnsignedShort();
break;
- }
- case 5: // Long
- case 6: // Double
- {
- LongEnt le;
- e = le = new LongEnt(tag);
- le.l = in.readLong();
+ case CONSTANT_INTEGER: // Integer
+ e = new IntLitEnt(in.readInt());
break;
- }
- case 1: // Utf8
- {
- Utf8Ent ue;
- e = ue = new Utf8Ent();
- ue.s = in.readUTF();
+ case CONSTANT_FLOAT: // Float
+ e = new FloatLitEnt(in.readFloat());
+ break;
+ case CONSTANT_LONG: // Long
+ e = new LongLitEnt(in.readLong());
+ break;
+ case CONSTANT_DOUBLE: // Double
+ e = new DoubleLitEnt(in.readDouble());
+ break;
+ case CONSTANT_UTF8: // Utf8
+ e = new Utf8Ent(in.readUTF());
break;
- }
default:
- throw new ClassFile.ClassReadExn("invalid cp ent tag");
+ throw new ClassFile.ClassReadExn("invalid cp ent tag: " + tag + " (slot " + i + ")");
}
- entriesByIndex[index] = e;
- if (e instanceof LongEnt) index++;
+ entriesByIndex[i] = e;
+ i += e.slots();
}
- for(int i=1;i<usedSlots;i++) {
+ for(int i=1;i<usedSlots;) {
Ent e = entriesByIndex[i];
if (e == null) throw new Error("should never happen: " + i + "/"+usedSlots);
- if (e instanceof LongEnt) {
- i++;
- continue;
- }
- if (!(e instanceof CPRefEnt)) continue;
- CPRefEnt ce = (CPRefEnt) e;
- if (e1s[i] == 0 || e1s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp i");
- ce.e1 = entriesByIndex[e1s[i]];
- if (ce.e1 == null) throw new ClassFile.ClassReadExn("invalid cp i");
- if (ce.tag != 7 && ce.tag != 8) {
- if (e2s[i] == 0 || e2s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp i");
- ce.e2 = entriesByIndex[e2s[i]];
- if (ce.e2 == null) throw new ClassFile.ClassReadExn("invalid cp i");
- }
- switch(ce.tag) {
- case 7:
- case 8:
- if (!(ce.e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a utf8 ent");
- break;
- case 9:
- case 10:
- case 11:
- if (!(ce.e1 instanceof CPRefEnt) || ((CPRefEnt)ce.e1).tag != 7)
- throw new ClassFile.ClassReadExn("expected a type ent");
- if (!(ce.e2 instanceof CPRefEnt) || ((CPRefEnt)ce.e2).tag != 12)
- throw new ClassFile.ClassReadExn("expected a name and type ent");
- break;
- case 12:
- if (!(ce.e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a utf8 ent");
- if (!(ce.e2 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a utf8 ent");
- break;
+ boolean isMem = e instanceof MemberEnt;
+ boolean isString = e instanceof StringLitEnt;
+ boolean isClass = e instanceof ClassEnt;
+ boolean isNameAndType = e instanceof NameAndTypeEnt;
+ if (isMem || isClass || isString || isNameAndType) {
+ if (e1s[i] == 0 || e1s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp index");
+ Ent e1 = entriesByIndex[e1s[i]];
+ if(e1 == null) throw new ClassFile.ClassReadExn("invalid cp index");
+ if(isClass) {
+ if(!(e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
+ ((ClassEnt)e).utf8 = (Utf8Ent) e1;
+ } else if(isString) {
+ if(!(e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
+ ((StringLitEnt)e).utf8 = (Utf8Ent) e1;
+ } else if(isMem || isNameAndType) {
+ if (e2s[i] == 0 || e2s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp index");
+ Ent e2 = entriesByIndex[e2s[i]];
+ if(isMem) {
+ if(!(e1 instanceof ClassEnt)) throw new ClassFile.ClassReadExn("expected a classent");
+ if(!(e2 instanceof NameAndTypeEnt)) throw new ClassFile.ClassReadExn("expected a nameandtypeent, not " + e2);
+ MemberEnt me = (MemberEnt) e;
+ me.klass = (ClassEnt) e1;
+ me.member = (NameAndTypeEnt) e2;
+ } else if(isNameAndType) {
+ if(!(e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
+ if(!(e2 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
+ NameAndTypeEnt nte = (NameAndTypeEnt) e;
+ nte.name = (Utf8Ent) e1;
+ nte.type = (Utf8Ent) e2;
+ }
+ }
}
+ i += e.slots();
}
- for(int i=1; i<usedSlots; i++) {
+ for(int i=1; i<usedSlots;) {
Ent e = entriesByIndex[i];
entries.put(e.key(), e);
- if (e instanceof LongEnt) i++;
+ i += e.slots();
}
state = STABLE;
}