public JSSA(Type.Class c, DataInput in, ConstantPool cp) throws IOException {
super(c, in, cp);
+ local = new Expr[maxLocals];
+ stack = new Expr[maxStack];
for(int i=0; i<this.method.getNumArgs(); i++)
local[i] = new Argument("arg"+i, this.method.getArgType(i));
for(int i=0; i<size(); i++) {
// Instance Data; used ONLY during constructor; then thrown away /////////////////////////////////////////////////
/** this models the JVM locals; it is only used for unwinding stack-ops into an SSA-tree, then thrown away */
- private Expr[] local = new Expr[6];
+ private final Expr[] local;
/** this models the JVM stack; it is only used for unwinding stack-ops into an SSA-tree, then thrown away */
- private Expr[] stack = new Expr[65535];
+ private final Expr[] stack;
/** JVM stack pointer */
private int sp = 0;
- private Expr push(Expr e) { return stack[sp++] = e; }
- private Expr pop() { return stack[--sp]; }
+ private Expr push(Expr e) {
+ if(sp == stack.length-1) throw new IllegalStateException("stack overflow");
+ return stack[sp++] = e;
+ }
+ private Expr pop() {
+ if(sp == 0) throw new IllegalStateException("stack underflow");
+ return stack[--sp];
+ }
// SSA-node classes /////////////////////////////////////////////////////////////////////////////////////////
+ public final Expr VOID_EXPR = new Expr() {
+ public Type getType() { return Type.VOID; }
+ };
+
/** an purely imperative operation which does not generate data */
public abstract class Op {
//public abstract Op[] predecessors(); // not implemented yet
public class Cast extends Expr {
final Expr e;
final Type t;
- public Cast(Expr e, Type t) { this.e = e; this.t = t; }
+ public Cast(Expr e, Type t) {
+ if(e.getType().isRef() != t.isRef()) throw new IllegalArgumentException("invalid cast");
+ // FEATURE: Check that one is a subclass of the other if it is a ref
+ this.e = e;
+ this.t = t;
+ }
public Type getType() { return t; }
}
public class InstanceOf extends Expr {
final Expr e;
- final Type t;
- public InstanceOf(Expr e, Type t) { this.e = e; this.t = t; }
+ final Type.Ref t;
+ public InstanceOf(Expr e, Type.Ref t) {
+ if(!e.getType().isRef()) throw new IllegalArgumentException("can't do an instanceof check on a non-ref");
+ this.e = e;
+ this.t = t;
+ }
public Type getType() { return Type.BOOLEAN; }
}
public class Throw extends Op {
public final Expr e;
- public Throw(Expr e) { this.e = e; }
+ public Throw(Expr e) {
+ if(!e.getType().isRef()) throw new IllegalArgumentException("can't throw a non ref");
+ // FEATURE: CHeck that it is a subclass of Throwable
+ this.e = e;
+ }
}
public class Branch extends Op {
public Label(int i) { this.op = null; /* FIXME */ }
}
- public class Allocate extends Expr {
- public final Type t;
+ public class New extends Expr {
+ public final Type.Class t;
public Type getType() { return t; }
- public Allocate(Type t) { this.t = t; }
- public Allocate(Type.Array t, Expr e) { this.t = t; }
+ public New(Type.Class t) { this.t = t; }
}
+
+ public class NewArray extends Expr {
+ public final Type.Array t;
+ public final Expr[] dims;
+ public NewArray(Type.Array t, Expr[] dims) { this.t = t; this.dims = dims; }
+ public NewArray(Type.Array t, Expr dim) { this(t,new Expr[]{dim}); }
+ public Type getType() { return t; }
+ }
+
+ // FEATURE: Array stuff
public class Return extends Op {
final Expr e;
- public Return() { this(null); }
+ public Return() { this(VOID_EXPR); }
public Return(Expr e) { this.e = e; }
- public String toString() { return e==null?"return":("return "+e.toString()); }
+ public String toString() { return e.getType() == Type.VOID ? "return" : ("return "+e.toString()); }
}
/** GETFIELD and GETSTATIC */
public class Constant extends Expr {
private final Object o;
+ public Constant(int i) { this(new Integer(i)); }
public Constant(Object o) { this.o = o; }
public String toString() { return o.toString(); }
public Type getType() {
// Implementation //////////////////////////////////////////////////////////////////////////////
private Object addOp(int op, Object arg) {
- Number number = null;
int i1 = 0;
int i2 = 0;
if (op==WIDE) {
i1 = p.i1;
i2 = p.i2;
}
- if (arg != null && arg instanceof Number) number = (Number)arg;
switch(op) {
case NOP: return null;
// Allocation //////////////////////////////////////////////////////////////////////////////
- case NEW: push(new Allocate((Type)arg)); return null;
- case NEWARRAY: push(new Allocate((Type.Array)arg, pop())); return null;
- case ANEWARRAY: push(new Allocate(Type.OBJECT.makeArray(), pop())); return null;
- case MULTIANEWARRAY: push(new Allocate(Type.OBJECT.makeArray(i2), null /* FIXME */)); return null;
+ case NEW: push(new New((Type.Class)arg)); return null;
+ case NEWARRAY: {
+ Type base;
+ switch(((Integer)arg).intValue()) {
+ case 4: base = Type.BOOLEAN; break;
+ case 5: base = Type.CHAR; break;
+ case 6: base = Type.FLOAT; break;
+ case 7: base = Type.DOUBLE; break;
+ case 8: base = Type.BYTE; break;
+ case 9: base = Type.SHORT; break;
+ case 10: base = Type.INT; break;
+ case 11: base = Type.LONG; break;
+ default: throw new IllegalStateException("invalid array type");
+ }
+ push(new NewArray(base.makeArray(),pop()));
+ return null;
+ }
+ case ANEWARRAY: push(new NewArray(((Type.Ref)arg).makeArray(), pop())); return null;
+ case MULTIANEWARRAY: {
+ MethodGen.MultiANewArray mana = (MethodGen.MultiANewArray) arg;
+ Expr[] dims = new Expr[mana.dims];
+ for(int i=0;i<dims.length;i++) dims[i] = pop();
+ push(new NewArray(mana.type, dims));
+ return null;
+ }
case ARRAYLENGTH: push(new ArrayLength(pop())); return null;
// Runtime Type information //////////////////////////////////////////////////////////////////////////////
- case CHECKCAST: push(new Cast(pop(), (Type)arg)); return null;
- case INSTANCEOF: push(new InstanceOf(pop(), (Type)arg)); return null;
+ case CHECKCAST: push(new Cast(pop(), (Type.Ref)arg)); return null;
+ case INSTANCEOF: push(new InstanceOf(pop(), (Type.Ref)arg)); return null;
case LDC: case LDC_W: case LDC2_W: push(new Constant(arg)); return null;
public static void main(String[] args) throws Exception {
InputStream is = Class.forName(args[0]).getClassLoader().getResourceAsStream(args[0].replace('.', '/')+".class");
- System.out.println(new ClassFile(new DataInputStream(is), true).debugToString());
+ System.out.println(new ClassFile(new DataInputStream(is), true).toString());
}
}