--- /dev/null
+JAVAC = javac
+sources = $(shell find src -name '*.java')
+classes = $(sources:src/%.java=build/%.class)
+jar_classes = $(classes)
+
+all: $(classes)
+
+$(classes): $(sources)
+ @mkdir -p build
+ $(JAVAC) -d build $(sources)
+
+test: $(classes)
+ java -cp build org.ibex.classgen.ClassGen
+
+clean:
+ rm -rf build/*
+
+sizecheck:
+ @for c in $(jar_classes); do \
+ for f in `echo $$c|sed 's,\.class$$,,;'`*.class; do gzip -c $$f; done | wc -c | tr -d '\n'; \
+ echo -e "\t`echo $$c | sed 's,build/org/ibex,,;s,\.class$$,,;s,/,.,g;'`"; \
+ done | sort -rn | awk '{ sum += $$1; print } END { print sum,"Total"; }'
--- /dev/null
+package org.ibex.classgen;
+
+import java.io.*;
+import java.util.*;
+
+public class AttrGen {
+ private final CPGen cp;
+ private final Hashtable ht = new Hashtable();
+
+ public AttrGen(CPGen cp) {
+ this.cp = cp;
+ }
+
+ public void add(String s, byte[] data) {
+ cp.addUtf8(s);
+ ht.put(s,data);
+ }
+
+ public boolean contains(String s) { return ht.get(s) != null; }
+
+ public int size() { return ht.size(); }
+
+ public void dump(DataOutput o) throws IOException {
+ for(Enumeration e = ht.keys(); e.hasMoreElements();) {
+ String name = (String) e.nextElement();
+ byte[] val = (byte[]) ht.get(name);
+ o.writeShort(cp.getUtf8(name).index);
+ o.writeInt(val.length);
+ o.write(val);
+ }
+ }
+}
--- /dev/null
+package org.ibex.classgen;
+
+public interface CGConst {
+ public static final int ACC_PUBLIC = (byte) 0x0001;
+ public static final int ACC_FINAL = (byte) 0x0010;
+
+ // Class only
+ public static final int ACC_INTERFACE = (byte) 0x0200;
+ public static final int ACC_SUPER = (byte) 0x0020;
+
+ // Field/Method only
+ public static final int ACC_PRIVATE = (byte) 0x0002;
+ public static final int ACC_PROTECTED = (byte) 0x0004;
+ public static final int ACC_STATIC = (byte) 0x0008;
+
+ // Class/Method only
+ public static final int ACC_ABSTRACT = (byte) 0x0400;
+
+ // Method Only
+ public static final int ACC_SYNCHRONIZED = (byte) 0x0020;
+ public static final int ACC_NATIVE = (byte) 0x0100;
+ public static final int ACC_STRICT = (byte) 0x0800;
+
+ // Field only
+ public static final int ACC_VOLATILE = (byte) 0x0040;
+ public static final int ACC_TRANSIENT = (byte) 0x0080;
+
+ // Instructions
+ public static final byte NOP = (byte) 0x0;
+ public static final byte ACONST_NULL = (byte) 0x01;
+ public static final byte ICONST_M1 = (byte) 0x02;
+ public static final byte ICONST_0 = (byte) 0x03;
+ public static final byte ICONST_1 = (byte) 0x04;
+ public static final byte ICONST_2 = (byte) 0x05;
+ public static final byte ICONST_3 = (byte) 0x06;
+ public static final byte ICONST_4 = (byte) 0x07;
+ public static final byte ICONST_5 = (byte) 0x08;
+ public static final byte LCONST_0 = (byte) 0x09;
+ public static final byte LCONST_1 = (byte) 0x0A;
+ public static final byte FCONST_0 = (byte) 0x0B;
+ public static final byte FCONST_1 = (byte) 0x0C;
+ public static final byte FCONST_2 = (byte) 0x0D;
+ public static final byte DCONST_0 = (byte) 0x0E;
+ public static final byte DCONST_1 = (byte) 0x0F;
+ public static final byte BIPUSH = (byte) 0x10;
+ public static final byte SIPUSH = (byte) 0x11;
+ public static final byte LDC = (byte) 0x12;
+ public static final byte LDC_W = (byte) 0x13;
+ public static final byte LDC2_W = (byte) 0x14;
+ public static final byte ILOAD = (byte) 0x15;
+ public static final byte LLOAD = (byte) 0x16;
+ public static final byte FLOAD = (byte) 0x17;
+ public static final byte DLOAD = (byte) 0x18;
+ public static final byte ALOAD = (byte) 0x19;
+ public static final byte ILOAD_0 = (byte) 0x1A;
+ public static final byte ILOAD_1 = (byte) 0x1B;
+ public static final byte ILOAD_2 = (byte) 0x1C;
+ public static final byte ILOAD_3 = (byte) 0x1D;
+ public static final byte LLOAD_0 = (byte) 0x1E;
+ public static final byte LLOAD_1 = (byte) 0x1F;
+ public static final byte LLOAD_2 = (byte) 0x20;
+ public static final byte LLOAD_3 = (byte) 0x21;
+ public static final byte FLOAD_0 = (byte) 0x22;
+ public static final byte FLOAD_1 = (byte) 0x23;
+ public static final byte FLOAD_2 = (byte) 0x24;
+ public static final byte FLOAD_3 = (byte) 0x25;
+ public static final byte DLOAD_0 = (byte) 0x26;
+ public static final byte DLOAD_1 = (byte) 0x27;
+ public static final byte DLOAD_2 = (byte) 0x28;
+ public static final byte DLOAD_3 = (byte) 0x29;
+ public static final byte ALOAD_0 = (byte) 0x2A;
+ public static final byte ALOAD_1 = (byte) 0x2B;
+ public static final byte ALOAD_2 = (byte) 0x2C;
+ public static final byte ALOAD_3 = (byte) 0x2D;
+ public static final byte IALOAD = (byte) 0x2E;
+ public static final byte LALOAD = (byte) 0x2F;
+ public static final byte FALOAD = (byte) 0x30;
+ public static final byte DALOAD = (byte) 0x31;
+ public static final byte AALOAD = (byte) 0x32;
+ public static final byte BALOAD = (byte) 0x33;
+ public static final byte CALOAD = (byte) 0x34;
+ public static final byte SALOAD = (byte) 0x35;
+ public static final byte ISTORE = (byte) 0x36;
+ public static final byte LSTORE = (byte) 0x37;
+ public static final byte FSTORE = (byte) 0x38;
+ public static final byte DSTORE = (byte) 0x39;
+ public static final byte ASTORE = (byte) 0x3A;
+ public static final byte ISTORE_0 = (byte) 0x3B;
+ public static final byte ISTORE_1 = (byte) 0x3C;
+ public static final byte ISTORE_2 = (byte) 0x3D;
+ public static final byte ISTORE_3 = (byte) 0x3E;
+ public static final byte LSTORE_0 = (byte) 0x3F;
+ public static final byte LSTORE_1 = (byte) 0x40;
+ public static final byte LSTORE_2 = (byte) 0x41;
+ public static final byte LSTORE_3 = (byte) 0x42;
+ public static final byte FSTORE_0 = (byte) 0x43;
+ public static final byte FSTORE_1 = (byte) 0x44;
+ public static final byte FSTORE_2 = (byte) 0x45;
+ public static final byte FSTORE_3 = (byte) 0x46;
+ public static final byte DSTORE_0 = (byte) 0x47;
+ public static final byte DSTORE_1 = (byte) 0x48;
+ public static final byte DSTORE_2 = (byte) 0x49;
+ public static final byte DSTORE_3 = (byte) 0x4A;
+ public static final byte ASTORE_0 = (byte) 0x4B;
+ public static final byte ASTORE_1 = (byte) 0x4C;
+ public static final byte ASTORE_2 = (byte) 0x4D;
+ public static final byte ASTORE_3 = (byte) 0x4E;
+ public static final byte IASTORE = (byte) 0x4F;
+ public static final byte LASTORE = (byte) 0x50;
+ public static final byte FASTORE = (byte) 0x51;
+ public static final byte DASTORE = (byte) 0x52;
+ public static final byte AASTORE = (byte) 0x53;
+ public static final byte BASTORE = (byte) 0x54;
+ public static final byte CASTORE = (byte) 0x55;
+ public static final byte SASTORE = (byte) 0x56;
+ public static final byte POP = (byte) 0x57;
+ public static final byte POP2 = (byte) 0x58;
+ public static final byte DUP = (byte) 0x59;
+ public static final byte DUP_X1 = (byte) 0x5A;
+ public static final byte DUP_X2 = (byte) 0x5B;
+ public static final byte DUP2 = (byte) 0x5C;
+ public static final byte DUP2_X1 = (byte) 0x5D;
+ public static final byte DUP2_X2 = (byte) 0x5E;
+ public static final byte SWAP = (byte) 0x5F;
+ public static final byte IADD = (byte) 0x60;
+ public static final byte LADD = (byte) 0x61;
+ public static final byte FADD = (byte) 0x62;
+ public static final byte DADD = (byte) 0x63;
+ public static final byte ISUB = (byte) 0x64;
+ public static final byte LSUB = (byte) 0x65;
+ public static final byte FSUB = (byte) 0x66;
+ public static final byte DSUB = (byte) 0x67;
+ public static final byte IMUL = (byte) 0x68;
+ public static final byte LMUL = (byte) 0x69;
+ public static final byte FMUL = (byte) 0x6A;
+ public static final byte DMUL = (byte) 0x6B;
+ public static final byte IDIV = (byte) 0x6C;
+ public static final byte LDIV = (byte) 0x6D;
+ public static final byte FDIV = (byte) 0x6E;
+ public static final byte DDIV = (byte) 0x6F;
+ public static final byte IREM = (byte) 0x70;
+ public static final byte LREM = (byte) 0x71;
+ public static final byte FREM = (byte) 0x72;
+ public static final byte DREM = (byte) 0x73;
+ public static final byte INET = (byte) 0x74;
+ public static final byte LNEG = (byte) 0x75;
+ public static final byte FNEG = (byte) 0x76;
+ public static final byte DNEG = (byte) 0x77;
+ public static final byte ISHL = (byte) 0x78;
+ public static final byte LSHL = (byte) 0x79;
+ public static final byte ISHR = (byte) 0x7A;
+ public static final byte LSHR = (byte) 0x7B;
+ public static final byte IUSHR = (byte) 0x7C;
+ public static final byte LUSHR = (byte) 0x7D;
+ public static final byte IAND = (byte) 0x7E;
+ public static final byte LAND = (byte) 0x7F;
+ public static final byte IOR = (byte) 0x80;
+ public static final byte LOR = (byte) 0x81;
+ public static final byte IXOR = (byte) 0x82;
+ public static final byte LXOR = (byte) 0x83;
+ public static final byte IINC = (byte) 0x84;
+ public static final byte I2L = (byte) 0x85;
+ public static final byte I2F = (byte) 0x86;
+ public static final byte I2D = (byte) 0x87;
+ public static final byte L2I = (byte) 0x88;
+ public static final byte L2F = (byte) 0x89;
+ public static final byte L2D = (byte) 0x8A;
+ public static final byte F2I = (byte) 0x8B;
+ public static final byte F2L = (byte) 0x8C;
+ public static final byte F2D = (byte) 0x8D;
+ public static final byte D2I = (byte) 0x8E;
+ public static final byte D2L = (byte) 0x8F;
+ public static final byte D2F = (byte) 0x90;
+ public static final byte I2B = (byte) 0x91;
+ public static final byte I2C = (byte) 0x92;
+ public static final byte I2S = (byte) 0x93;
+ public static final byte LCMP = (byte) 0x94;
+ public static final byte FCMPL = (byte) 0x95;
+ public static final byte FCMPG = (byte) 0x96;
+ public static final byte DCMPL = (byte) 0x97;
+ public static final byte DCMPG = (byte) 0x98;
+ public static final byte IFEQ = (byte) 0x99;
+ public static final byte IFNE = (byte) 0x9A;
+ public static final byte IFLT = (byte) 0x9B;
+ public static final byte IFGE = (byte) 0x9C;
+ public static final byte IFGT = (byte) 0x9D;
+ public static final byte IFLE = (byte) 0x9E;
+ public static final byte IF_ICMPEQ = (byte) 0x9F;
+ public static final byte IF_ICMPNE = (byte) 0xA0;
+ public static final byte IF_ICMPLT = (byte) 0xA1;
+ public static final byte IF_ICMPGE = (byte) 0xA2;
+ public static final byte IF_ICMPGT = (byte) 0xA3;
+ public static final byte IF_ICMPLE = (byte) 0xA4;
+ public static final byte IF_ACMPEQ = (byte) 0xA5;
+ public static final byte IF_ACMPNE = (byte) 0xA6;
+ public static final byte GOTO = (byte) 0xA7;
+ public static final byte JSR = (byte) 0xA8;
+ public static final byte RET = (byte) 0xA9;
+ public static final byte TABLESWITCH = (byte) 0xAA;
+ public static final byte LOOKUPSWITCH = (byte) 0xAB;
+ public static final byte IRETURN = (byte) 0xAC;
+ public static final byte LRETURN = (byte) 0xAD;
+ public static final byte FRETURN = (byte) 0xAE;
+ public static final byte DRETURN = (byte) 0xAF;
+ public static final byte ARETURN = (byte) 0xB0;
+ public static final byte RETURN = (byte) 0xB1;
+ public static final byte GETSTATIC = (byte) 0xB2;
+ public static final byte PUTSTATIC = (byte) 0xB3;
+ public static final byte GETFIELD = (byte) 0xB4;
+ public static final byte PUTFIELD = (byte) 0xB5;
+ public static final byte INVOKEVIRTUAL = (byte) 0xB6;
+ public static final byte INVOKESPECIAL = (byte) 0xB7;
+ public static final byte INVOKESTATIC = (byte) 0xB8;
+ public static final byte INVOKEINTERFACE = (byte) 0xB9;
+ public static final byte NEW = (byte) 0xBB;
+ public static final byte NEWARRAY = (byte) 0xBC;
+ public static final byte ANEWARRAY = (byte) 0xBD;
+ public static final byte ARRAYLENGTH = (byte) 0xBE;
+ public static final byte ATHROW = (byte) 0xBF;
+ public static final byte CHECKCAST = (byte) 0xC0;
+ public static final byte INSTANCEOF = (byte) 0xC1;
+ public static final byte MONITORENTER = (byte) 0xC2;
+ public static final byte MONITOREXIT = (byte) 0xC3;
+ public static final byte WIDE = (byte) 0xC4;
+ public static final byte MULTIANEWARRAY = (byte) 0xC5;
+ public static final byte IFNULL = (byte) 0xC6;
+ public static final byte IFNONNULL = (byte) 0xC7;
+ public static final byte GOTO_W = (byte) 0xC8;
+ public static final byte JSR_W = (byte) 0xC9;
+}
--- /dev/null
+package org.ibex.classgen;
+
+import java.util.*;
+import java.io.*;
+
+import org.ibex.classgen.util.*;
+
+public class CPGen {
+ private Hashtable entries = new Hashtable();
+ private int nextIndex = 1; // 0 is reserved
+ private boolean sealed;
+
+ CPGen() { }
+
+ /*
+ * Entries
+ */
+ abstract static class Ent implements Sort.Comparable {
+ int index;
+ public abstract int tag();
+ public void dump(DataOutput o) throws IOException { o.writeByte(tag()); }
+ public int compareTo(Object o) {
+ if(!(o instanceof Ent)) return 1;
+ int oi = ((Ent)o).index;
+ if(index < oi) return -1;
+ if(index > oi) return 1;
+ return 0;
+ }
+ }
+
+ abstract static class OneU2Ent extends Ent { int i; public void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(i); } }
+ abstract static class OneU4Ent extends Ent { int i; public void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i); } }
+ abstract static class TwoU2Ent extends OneU2Ent { int i2; public void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(i2); } }
+ abstract static class TwoU4Ent extends OneU4Ent { int i2; public void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i2); } }
+
+ static class IntEnt extends OneU4Ent { public int tag() { return 3; } } // word1: bytes
+ static class FloatEnt extends OneU4Ent { public int tag() { return 4; } } // word1: bytes
+ static class LongEnt extends TwoU4Ent { public int tag() { return 5; } } // word1/2: bytes
+ static class DoubleEnt extends TwoU4Ent { public int tag() { return 6; } } // word1/2: bytes
+ static class ClassEnt extends OneU2Ent { public int tag() { return 7; } } // word1: name_index
+ static class StringEnt extends OneU2Ent { public int tag() { return 8; } } // word1: string_index
+ static class FieldRefEnt extends TwoU2Ent { public int tag() { return 9; } } // word1: class_index word2: name_and_type_index
+ static class MethodRefEnt extends TwoU2Ent { public int tag() { return 10; } } // word1: class_index word2: name_and_type_index
+ static class IMethodRefEnt extends TwoU2Ent { public int tag() { return 11; } } // word1: class_index word2: name_and_type_index
+ static class NameAndTypeEnt extends TwoU2Ent { public int tag() { return 12; } } // word1: name_index word2: descriptor_index
+
+ static class Utf8Ent extends Ent {
+ String s;
+ public int tag() { return 1; }
+ public void dump(DataOutput o) throws IOException {
+ super.dump(o);
+ o.writeUTF(s);
+ }
+ public String toString() { return "Utf8: " + s; }
+ }
+
+ /*
+ * Cache Keys
+ */
+ 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 NameAndType {
+ String name;
+ String type;
+ public NameAndType(String name, String type) { this.name = name; this.type = type; }
+ public boolean equals(Object o_) {
+ if(!(o_ instanceof NameAndType)) return false;
+ NameAndType o = (NameAndType) o_;
+ return o.name.equals(name) && o.type.equals(type);
+ }
+ public int hashCode() { return name.hashCode() ^ type.hashCode(); }
+ }
+
+ static abstract class FieldMethodRef {
+ Type.Object klass;
+ NameAndType nameAndType;
+ public FieldMethodRef(Type.Object klass, NameAndType nameAndType) { this.klass = klass; this.nameAndType = nameAndType; }
+ public boolean equals(Object o_) {
+ if(!(o_ instanceof FieldMethodRef)) return false;
+ FieldMethodRef o = (FieldMethodRef) o_;
+ return o.klass.equals(klass) && o.nameAndType.equals(nameAndType);
+ }
+ }
+
+ public static class FieldRef extends FieldMethodRef { public FieldRef (Type.Object c, NameAndType t) { super(c,t); } }
+ public static class MethodRef extends FieldMethodRef { public MethodRef (Type.Object c, NameAndType t) { super(c,t); } }
+ public static class IMethodRef extends FieldMethodRef { public IMethodRef(Type.Object c, NameAndType t) { super(c,t); } }
+
+ /*
+ * Methods
+ */
+ public void seal() { sealed = true; }
+
+ public final Ent get(Object o) { return (Ent) entries.get(o); }
+ public final Ent getUtf8(String s) { return get(new Utf8Key(s)); }
+
+ public final Ent addNameAndType(String name, String descriptor) { return add(new NameAndType(name,descriptor)); }
+ public final Ent addUtf8(String s) { return add(new Utf8Key(s)); }
+
+ public final Ent add(Object o) {
+ if(sealed) throw new IllegalStateException("constant pool is sealed");
+
+ Ent ent = get(o);
+ if(ent != null) return ent;
+
+ if(nextIndex == 65536) throw new ClassGen.Exn("constant pool full");
+
+ if(o instanceof Type.Object) {
+ ClassEnt ce = new ClassEnt();
+ ce.i = addUtf8(((Type.Object)o).internalForm()).index;
+ ent = ce;
+ } else if(o instanceof String) {
+ StringEnt se = new StringEnt();
+ se.i = addUtf8((String)o).index;
+ ent = se;
+ } else if(o instanceof Integer) {
+ IntEnt ie = new IntEnt();
+ ie.i = ((Integer)o).intValue();
+ ent = ie;
+ } else if(o instanceof Float) {
+ FloatEnt fe = new FloatEnt();
+ fe.i = Float.floatToIntBits(((Float)o).floatValue());
+ ent = fe;
+ } else if(o instanceof Long) {
+ LongEnt le = new LongEnt();
+ long l = ((Long)o).longValue();
+ le.i = (int)(l>>>32);
+ le.i2 = (int)l;
+ ent = le;
+ } else if(o instanceof Double) {
+ DoubleEnt de = new DoubleEnt();
+ long l = Double.doubleToLongBits(((Double)o).doubleValue());
+ de.i = (int)(l>>>32);
+ de.i2 = (int)l;
+ ent = de;
+ } else if(o instanceof Utf8Key) {
+ Utf8Ent ue = new Utf8Ent();
+ ue.s = ((Utf8Key)o).s;
+ ent = ue;
+ } else if(o instanceof NameAndType) {
+ NameAndTypeEnt ne = new NameAndTypeEnt();
+ NameAndType key = (NameAndType) o;
+ ne.i = addUtf8(key.name).index;
+ ne.i2 = addUtf8(key.type).index;
+ ent = ne;
+ } else if(o instanceof FieldMethodRef) {
+ FieldMethodRef key = (FieldMethodRef) o;
+ TwoU2Ent fme;
+ if(o instanceof MethodRef) fme = new MethodRefEnt();
+ else if(o instanceof IMethodRef) fme = new IMethodRefEnt();
+ else if(o instanceof FieldRef) fme = new FieldRefEnt();
+ else throw new Error("should never happen");
+ fme.i = add(key.klass).index;
+ fme.i2 = add(key.nameAndType).index;
+ ent = fme;
+ } else {
+ throw new IllegalArgumentException("Unknown type passed to add");
+ }
+
+ ent.index = nextIndex++;
+ entries.put(o,ent);
+ return ent;
+ }
+
+ public int size() { return nextIndex; }
+
+ public void dump(DataOutput o) throws IOException {
+ Ent[] ents = new Ent[nextIndex-1];
+ int i=0;
+ Enumeration e = entries.keys();
+ while(e.hasMoreElements()) ents[i++] = (Ent) entries.get(e.nextElement());
+ Sort.sort(ents);
+ for(i=0;i<ents.length;i++) {
+ //System.err.println("" + (i+1) + ": " + ents[i]);
+ ents[i].dump(o);
+ }
+ }
+}
--- /dev/null
+package org.ibex.classgen;
+
+import java.util.*;
+import java.io.*;
+
+public class ClassGen implements CGConst {
+ private Type.Object thisType;
+ private Type.Object superType;
+ int flags;
+
+ private Vector interfaces = new Vector();
+ private Vector fields = new Vector();
+ private Vector methods = new Vector();
+
+ final CPGen cp;
+ private final AttrGen attributes;
+
+ public ClassGen(String name, String superName, int flags) {
+ this(new Type.Object(name),new Type.Object(superName),flags);
+ }
+
+ public ClassGen(Type.Object thisType,Type.Object superType, int flags) {
+ if((flags & ~(ACC_PUBLIC|ACC_FINAL|ACC_SUPER|ACC_INTERFACE|ACC_ABSTRACT)) != 0)
+ throw new IllegalArgumentException("invalid flags");
+ this.thisType = thisType;
+ this.superType = superType;
+ this.flags = flags;
+
+ cp = new CPGen();
+ attributes = new AttrGen(cp);
+ }
+
+ public final MethodGen addMethod(String name, Type ret, Type[] args, int flags) {
+ MethodGen mg = new MethodGen(this,name,ret,args,flags);
+ methods.addElement(mg);
+ return mg;
+ }
+
+ public void dump(String s) throws IOException { dump(new File(s)); }
+ public void dump(File f) throws IOException {
+ if(f.isDirectory()) {
+ String[] a = thisType.components();
+ int i;
+ for(i=0;i<a.length-1;i++) {
+ f = new File(f,a[i]);
+ f.mkdir();
+ }
+ f = new File(f,a[i] + ".class");
+ }
+ dump(new FileOutputStream(f));
+ }
+ public void dump(OutputStream os) throws IOException {
+ DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(os));
+ _dump(dos);
+ dos.flush();
+ }
+
+ private void _dump(DataOutput o) throws IOException {
+ cp.add(thisType);
+ cp.add(superType);
+ for(int i=0;i<interfaces.size();i++) cp.add((Type.Object)interfaces.elementAt(i));
+ for(int i=0;i<methods.size();i++) ((MethodGen)methods.elementAt(i)).finish();
+ cp.seal();
+
+ o.writeInt(0xcafebabe); // magic
+ o.writeShort(0); // minor_version
+ o.writeShort(46); // major_version
+ o.writeShort(cp.size()); // constant_pool_count
+ cp.dump(o); // constant_pool
+ o.writeShort(flags);
+ o.writeShort(cp.get(thisType).index); // this_class
+ o.writeShort(cp.get(superType).index); // super_class
+ o.writeShort(interfaces.size()); // interfaces_count
+ for(int i=0;i<interfaces.size();i++) o.writeShort(cp.get((Type.Object)interfaces.elementAt(i)).index); // interfaces
+ o.writeShort(fields.size()); // fields_count
+ for(int i=0;i<fields.size();i++) ((FieldGen)fields.elementAt(i)).dump(o); // fields
+ o.writeShort(methods.size()); // methods_count
+ for(int i=0;i<methods.size();i++) ((MethodGen)methods.elementAt(i)).dump(o); // methods
+ o.writeShort(attributes.size()); // attributes_count
+ attributes.dump(o); // attributes
+ }
+
+ // FEATURE: Make some of these checked exceptions?
+ public static class Exn extends RuntimeException {
+ public Exn(String s) { super(s); }
+ }
+
+ public static void main(String[] args) throws Exception {
+ ClassGen cg = new ClassGen("Test","java.lang.Object",ACC_PUBLIC|ACC_SUPER|ACC_FINAL);
+ MethodGen mg = cg.addMethod("main",Type.VOID,new Type[]{Type.arrayType(Type.STRING)},ACC_STATIC|ACC_PUBLIC);
+ mg.setMaxLocals(1);
+ mg.addPushConst(0);
+ mg.add(ISTORE_0);
+ int top = mg.size();
+ mg.add(GETSTATIC,mg.fieldRef(new Type.Object("java.lang.System"),"out",new Type.Object("java.io.PrintStream")));
+ mg.add(ILOAD_0);
+ mg.add(INVOKEVIRTUAL,mg.methodRef(new Type.Object("java.io.PrintStream"),"println",Type.VOID, new Type[]{Type.INT}));
+ mg.add(IINC,new int[]{0,1});
+ mg.add(ILOAD_0);
+ mg.addPushConst(10);
+ mg.add(IF_ICMPLT,top);
+ mg.add(RETURN);
+ cg.dump("Test.class");
+ }
+}
--- /dev/null
+package org.ibex.classgen;
+
+import java.io.*;
+
+public class FieldGen {
+ public void dump(DataOutput o) {
+ throw new Error("FIXME");
+ }
+}
--- /dev/null
+package org.ibex.classgen;
+
+import java.io.*;
+
+public class MethodGen implements CGConst {
+ private final static boolean EMIT_NOPS = true;
+
+ private final CPGen cp;
+ private final String name;
+ private final Type ret;
+ private final Type[] args;
+ private final int flags;
+ private final AttrGen attrs;
+ private final AttrGen codeAttrs;
+
+ private final int nameIndex;
+ private final int descriptorIndex;
+
+ private int maxStack = 16;
+ private int maxLocals=1;
+
+ private int size;
+ private int capacity;
+ private byte[] op;
+ private Object[] arg;
+
+ MethodGen(ClassGen owner, String name, Type ret, Type[] args, int flags) {
+ if((flags & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) != 0)
+ throw new IllegalArgumentException("invalid flags");
+ this.cp = owner.cp;
+ this.name = name;
+ this.ret = ret;
+ this.args = args;
+ this.flags = flags;
+
+ attrs = new AttrGen(cp);
+ codeAttrs = new AttrGen(cp);
+
+ nameIndex = cp.addUtf8(name).index;
+ descriptorIndex = cp.addUtf8(descriptor()).index;
+
+ if((owner.flags & ACC_INTERFACE) != 0 || (flags & (ACC_ABSTRACT|ACC_NATIVE)) != 0) size = capacity = -1;
+ }
+
+ public String descriptor() { return descriptor(ret,args); }
+ public static String descriptor(Type ret, Type[] args) {
+ StringBuffer sb = new StringBuffer(args.length*4);
+ sb.append("(");
+ for(int i=0;i<args.length;i++) sb.append(args[i].getDescriptor());
+ sb.append(")");
+ sb.append(ret.getDescriptor());
+ return sb.toString();
+ }
+
+ private final void grow() { if(size == capacity) grow(size+1); }
+ private final void grow(int newCap) {
+ if(newCap <= capacity) return;
+ newCap = Math.max(newCap,capacity == 0 ? 256 : capacity*2);
+
+ byte[] op2 = new byte[newCap];
+ if(capacity != 0) System.arraycopy(op,0,op2,0,size);
+ op = op2;
+
+ Object[] arg2 = new Object[newCap];
+ if(capacity != 0) System.arraycopy(arg,0,arg2,0,size);
+ arg = arg2;
+
+ capacity = newCap;
+ }
+ public final int size() { return size; }
+
+ public final int addPushConst(int n) { grow(); setPushConst(size,n); return size++; }
+ public final int addPushConst(long n) { grow(); setPushConst(size,n); return size++; }
+ public final int addPushConst(float n) { grow(); setPushConst(size,n); return size++; }
+ public final int addPushConst(double n) { grow(); setPushConst(size,n); return size++; }
+ public final int addPushConst(Object o) { grow(); setPushConst(size,o); return size++; }
+ public final int add(byte op, int arg) { return add(op,N(arg)); }
+ public final int add(byte op, Object arg) { grow(); set(size,op,arg); return size++; }
+ public final int add(byte op) { return add(op,null); }
+
+ public final void set(int pos, byte op) { set(pos,op,null); }
+ public final void set(int pos, byte op, int n) { set(pos,op,N(n)); }
+ public final void set(int pos, byte op, Object arg) {
+ if(capacity == -1) throw new IllegalStateException("method can't have code");
+ if(size == -1) throw new IllegalStateException("method is finalized");
+ int iarg = arg instanceof Integer ? ((Integer)arg).intValue() : -1;
+
+ switch(op) {
+ case LDC: if(iarg >= 256) op = LDC_W; break;
+ }
+ this.op[pos] = op;
+ this.arg[pos] = arg;
+ }
+
+ public final void setPushConst(int pos, int n) {
+ switch(n) {
+ case -1: set(pos,ICONST_M1); break;
+ case 0: set(pos,ICONST_0); break;
+ case 1: set(pos,ICONST_1); break;
+ case 2: set(pos,ICONST_2); break;
+ case 3: set(pos,ICONST_3); break;
+ case 4: set(pos,ICONST_4); break;
+ case 5: set(pos,ICONST_5); break;
+ default:
+ if(n >= -128 && n <= 127) set(pos,BIPUSH,n);
+ if(n >= -32767 && n <= 32767) set(pos,SIPUSH,n);
+ setLDC(pos,N(n));
+ break;
+ }
+ }
+ public final void setPushConst(int pos, long l) {
+ if(l==0) set(pos,LCONST_0);
+ else if(l==1) set(pos,LCONST_1);
+ else setLDC(pos,N(l));
+ }
+
+ public final void setPushConst(int pos, float f) {
+ if(f == 1.0f) set(pos,FCONST_0);
+ else if(f == 1.0f) set(pos,FCONST_1);
+ else if(f == 2.0f) set(pos,FCONST_2);
+ else setLDC(pos,N(f));
+ }
+ public final void setPushConst(int pos, double d) {
+ if(d == 1.0) set(pos,DCONST_0);
+ else if(d == 2.0) set(pos,DCONST_1);
+ else setLDC(pos,N(d));
+ }
+ public final void setPushConst(int pos, Object o) {
+ if(o instanceof Integer) setPushConst(pos,((Integer)o).intValue());
+ else if(o instanceof Long) setPushConst(pos,((Long)o).longValue());
+ else if(o instanceof Float) setPushConst(pos,((Float)o).floatValue());
+ else if(o instanceof Double) setPushConst(pos,((Double)o).doubleValue());
+ else setLDC(pos,o);
+ }
+
+ private void setLDC(int pos, Object o) { set(pos,LDC,cp.add(o)); }
+
+ public final CPGen.Ent methodRef(Type.Object c, String name, Type ret, Type[] args) {
+ return methodRef(c,name,MethodGen.descriptor(ret,args));
+ }
+ public final CPGen.Ent methodRef(Type.Object c, String name, String descriptor) {
+ return cp.add(new CPGen.MethodRef(c,new CPGen.NameAndType(name,descriptor)));
+ }
+ public final CPGen.Ent fieldRef(Type.Object c, String name, Type type) {
+ return fieldRef(c,name,type.getDescriptor());
+ }
+ public final CPGen.Ent fieldRef(Type.Object c, String name, String descriptor) {
+ return cp.add(new CPGen.FieldRef(c,new CPGen.NameAndType(name,descriptor)));
+ }
+
+ public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; }
+ public void setMaxStack(int maxStack) { this.maxStack = maxStack; }
+
+ public void finish() {
+ try {
+ _finish();
+ } catch(IOException e) {
+ throw new Error("should never happen");
+ }
+ }
+
+ private void _finish() throws IOException {
+ if(size == -1) return;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutput o = new DataOutputStream(baos);
+
+ int[] pc = new int[size];
+ int[] maxpc = pc;
+ int p,i;
+
+ // Pass1 - Calculate maximum pc of each bytecode
+ for(i=0,p=0;i<size;i++) {
+ byte op = this.op[i];
+ maxpc[i] = p;
+ switch(op) {
+ case GOTO: p += 3; break;
+ case JSR: p += 3; break;
+ case NOP: if(!EMIT_NOPS) continue; /* fall though */
+ default: p += 1 + opArgLength(op); break;
+ }
+ }
+ // Pass2 - Widen instructions if they can possibly be too short
+ for(i=0;i<size;i++) {
+ switch(op[i]) {
+ case GOTO:
+ case JSR: {
+ int arg = ((Integer)this.arg[i]).intValue();
+ int diff = maxpc[arg] - maxpc[i];
+ if(diff < -32768 || diff > 32767)
+ op[i] = op[i] == GOTO ? GOTO_W : JSR_W;
+ }
+ }
+ }
+ // Pass3 - Calculate actual pc
+ for(i=0,p=0;i<size;i++) {
+ byte op = this.op[i];
+ pc[i] = p;
+ p += op != NOP || EMIT_NOPS ? 1 + opArgLength(op) : 0;
+ }
+
+ o.writeShort(maxStack);
+ o.writeShort(maxLocals);
+ o.writeInt(p);
+
+ // Pass 4 - Actually write the bytecodes
+ for(i=0;i<size;i++) {
+ byte op = this.op[i];
+ System.err.println("" + i + " Writing " + Integer.toHexString(op) + " at " + pc[i]);
+ if(op == NOP && !EMIT_NOPS) continue;
+ int argLength = opArgLength(op);
+ o.writeByte(op&0xff);
+ if(argLength == 0) continue;
+ Object arg = this.arg[i];
+ int iarg = arg instanceof Integer ? ((Integer)arg).intValue() : -1;
+ int outArg = iarg;
+
+ switch(op) {
+ case IINC: {
+ int[] pair = (int[]) arg;
+ if(pair[0] > 255 || pair[1] < -128 || pair[1] > 127) throw new ClassGen.Exn("overflow of iinc arg");
+ o.writeByte(pair[0]);
+ o.writeByte(pair[1]);
+ continue;
+ }
+ case IF_ICMPLT:
+ case GOTO:
+ case GOTO_W:
+ case JSR:
+ case JSR_W:
+ outArg = pc[iarg] - pc[i];
+ if(outArg < -32768 || outArg > 32767) throw new ClassGen.Exn("overflow of s2 offset");
+ break;
+ case INVOKESTATIC:
+ case INVOKESPECIAL:
+ case INVOKEVIRTUAL:
+ case GETSTATIC:
+ case PUTSTATIC:
+ case GETFIELD:
+ case PUTFIELD:
+ case LDC_W:
+ case LDC:
+ outArg = ((CPGen.Ent)arg).index;
+ break;
+ }
+
+ if(argLength == 1) o.writeByte(outArg);
+ else if(argLength == 2) o.writeShort(outArg);
+ else throw new Error("should never happen");
+ }
+
+ o.writeShort(0); // FIXME: Exception table
+ o.writeShort(codeAttrs.size());
+ codeAttrs.dump(o);
+
+ baos.close();
+
+ byte[] codeAttribute = baos.toByteArray();
+ attrs.add("Code",codeAttribute);
+ size = -1;
+ }
+
+ public void dump(DataOutput o) throws IOException {
+ o.writeShort(flags);
+ o.writeShort(nameIndex);
+ o.writeShort(descriptorIndex);
+ o.writeShort(attrs.size());
+ attrs.dump(o);
+ }
+
+ private static int opArgLength(byte op) {
+ switch(op) {
+ case NOP:
+ case ICONST_M1:
+ case ICONST_0:
+ case ICONST_1:
+ case ICONST_2:
+ case ICONST_3:
+ case ICONST_4:
+ case ICONST_5:
+ case LCONST_0:
+ case LCONST_1:
+ case FCONST_0:
+ case FCONST_1:
+ case FCONST_2:
+ case DCONST_0:
+ case DCONST_1:
+ case ILOAD_0:
+ case ILOAD_1:
+ case ILOAD_2:
+ case ILOAD_3:
+ case ISTORE_0:
+ case ISTORE_1:
+ case ISTORE_2:
+ case ISTORE_3:
+ case RETURN:
+ return 0;
+ case LDC:
+ case BIPUSH:
+ case ILOAD:
+ case ISTORE:
+ return 1;
+ case LDC_W:
+ case SIPUSH:
+ case GETSTATIC:
+ case PUTSTATIC:
+ case GETFIELD:
+ case PUTFIELD:
+ case INVOKESTATIC:
+ case INVOKEVIRTUAL:
+ case INVOKESPECIAL:
+ case IINC:
+ case GOTO:
+ case JSR:
+ case IF_ICMPLT:
+ return 2;
+ default:
+ throw new ClassGen.Exn("unknown bytecode " + Integer.toHexString(op&0xff));
+ }
+ }
+
+ private static Integer N(int n) { return new Integer(n); }
+ private static Long N(long n) { return new Long(n); }
+ private static Float N(float f) { return new Float(f); }
+ private static Double N(double d) { return new Double(d); }
+ private static int max(int a, int b) { return a > b ? a : b; }
+}
--- /dev/null
+package org.ibex.classgen;
+
+import java.util.StringTokenizer;
+
+public class Type {
+ public static final Type VOID = new Type("V");
+ public static final Type INT = new Type("I");
+ public static final Type STRING = new Type.Object("java.lang.String");
+ public static final Type[] NO_ARGS = new Type[0];
+
+ String descriptor;
+
+ Type() { }
+ Type(String descriptor) { this.descriptor = descriptor; }
+
+ public final String getDescriptor() { return descriptor; }
+ public int hashCode() { return descriptor.hashCode(); }
+ public boolean equals(Object o) { return o instanceof Type && ((Type)o).descriptor.equals(descriptor); }
+
+ public static Type arrayType(Type base) { return arrayType(base,1); }
+ public static Type arrayType(Type base, int dim) {
+ StringBuffer sb = new StringBuffer(base.descriptor.length() + dim);
+ for(int i=0;i<dim;i++) sb.append("[");
+ sb.append(base.descriptor);
+ return new Type(sb.toString());
+ }
+
+ public static class Object extends Type {
+ public Object(String s) {
+ if(!s.startsWith("L") || !s.endsWith(";")) s = "L" + s.replace('.','/') + ";";
+ if(!validDescriptorString(s)) throw new IllegalArgumentException("invalid descriptor string");
+ descriptor = s;
+ }
+
+ public String[] components() {
+ StringTokenizer st = new StringTokenizer(descriptor.substring(1,descriptor.length()-1),"/");
+ String[] a = new String[st.countTokens()];
+ for(int i=0;st.hasMoreTokens();i++) a[i] = st.nextToken();
+ return a;
+ }
+
+ public String internalForm() { return descriptor.substring(1,descriptor.length()-1); }
+
+ // FEATURE: Do a proper check here (invalid chars, etc)
+ public boolean validDescriptorString(String s) {
+ return s.startsWith("L") && s.endsWith(";");
+ }
+ }
+}
--- /dev/null
+package org.ibex.classgen.util;
+
+// FIXME: Share this with nestedvm somehow
+public final class Sort {
+ private Sort() { }
+
+ public interface Comparable { public int compareTo(Object o); }
+ public interface CompareFunc { public int compare(Object a, Object b); }
+
+ private static final CompareFunc comparableCompareFunc = new CompareFunc() {
+ public int compare(Object a,Object b) { return ((Comparable)a).compareTo(b); }
+ };
+
+ public static void sort(Comparable[] a) { sort(a,comparableCompareFunc); }
+ public static void sort(Object[] a, CompareFunc c) { sort(a,c,0,a.length-1); }
+
+ private static void sort(Object[] a, CompareFunc c, int start, int end) {
+ Object tmp;
+ if(start >= end) return;
+ if(end-start <= 6) {
+ for(int i=start+1;i<=end;i++) {
+ tmp = a[i];
+ int j;
+ for(j=i-1;j>=start;j--) {
+ if(c.compare(a[j],tmp) <= 0) break;
+ a[j+1] = a[j];
+ }
+ a[j+1] = tmp;
+ }
+ return;
+ }
+
+ Object pivot = a[end];
+ int lo = start - 1;
+ int hi = end;
+
+ do {
+ while((lo < hi) && c.compare(a[++lo],pivot) < 0) { }
+ while((hi > lo) && c.compare(a[--hi],pivot) > 0) { }
+ tmp = a[lo]; a[lo] = a[hi]; a[hi] = tmp;
+ } while(lo < hi);
+
+ tmp = a[lo]; a[lo] = a[end]; a[end] = tmp;
+
+ sort(a, c, start, lo-1);
+ sort(a, c, lo+1, end);
+ }
+}