package org.ibex.classgen; import java.io.*; import java.util.*; /** * a highly streamlined SSA-form intermediate representation of a * sequence of JVM instructions; all stack manipulation is factored * out. */ public class JSSA extends MethodGen implements CGConst { // Constructor ////////////////////////////////////////////////////////////////////////////// public JSSA(Type.Class c, DataInput in, ConstantPool cp) throws IOException { super(c, in, cp); sp = 0; stacks = new Phi[size()][]; locals = new Phi[size()][]; for(int i=0; i"); } } public class Lt extends PrimitiveComparison { public Lt(Expr e1, Expr e2) { super(e1, e2, "<"); } } public class Ge extends PrimitiveComparison { public Ge(Expr e1, Expr e2) { super(e1, e2, ">="); } } public class Le extends PrimitiveComparison { public Le(Expr e1, Expr e2) { super(e1, e2, "<="); } } // Math Operations ////////////////////////////////////////////////////////////////////////////// public class BinMath extends BinExpr { public BinMath(Expr e1, Expr e2, String show) { super(e2, e1, show); if (e1.getType() != null && e2.getType() != null && e1.getType() != e2.getType()) throw new IllegalArgumentException("types disagree"); } public Type getType() { return e1.getType(); } } public class Add extends BinMath { public Add(Expr e, Expr e2) { super(e, e2, "+"); } } public class Sub extends BinMath { public Sub(Expr e, Expr e2) { super(e, e2, "-"); } } public class Mul extends BinMath { public Mul(Expr e, Expr e2) { super(e, e2, "*"); } } public class Rem extends BinMath { public Rem(Expr e, Expr e2) { super(e, e2, "%"); } } public class Div extends BinMath { public Div(Expr e, Expr e2) { super(e, e2, "/"); } } public class And extends BinMath { public And(Expr e, Expr e2) { super(e, e2, "&"); } } public class Or extends BinMath { public Or(Expr e, Expr e2) { super(e, e2, "|"); } } public class Xor extends BinMath { public Xor(Expr e, Expr e2) { super(e, e2, "^"); } } public class BitShiftExpr extends BinExpr { public BitShiftExpr(Expr e1, Expr e2, String show) { super(e1,e2,show); Type t = e1.getType(); if (t != Type.INT && t != Type.LONG) throw new IllegalArgumentException("type mismatch"); if (e2.getType() != Type.INT) throw new IllegalArgumentException("type mismatch"); } public Type getType() { return e1.getType(); } } public class Shl extends BitShiftExpr { public Shl(Expr e, Expr e2) { super(e, e2, "<<"); } } public class Shr extends BitShiftExpr { public Shr(Expr e, Expr e2) { super(e, e2, ">>"); } } public class Ushr extends BitShiftExpr { public Ushr(Expr e, Expr e2) { super(e, e2, ">>>"); } } // Other operations ////////////////////////////////////////////////////////////////////////////// public class Cast extends Expr { final Expr e; final Type 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.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 Branch extends Op { Expr destination = null; public Branch(Expr destination) { this.destination = destination; } public Branch(MethodGen.Switch s) { /* FIXME */ } public Branch() { } public void branchTo() { if (destination != null) branchTo(destination); } private void branchTo(Expr e) { if (e instanceof Phi) { Phi phi = (Phi)e; for(int i=0; i>"; } } public class New extends Expr { public final Type.Class t; public Type getType() { return t; } public New(Type.Class t) { this.t = t; } public String _toString() { return "new " + 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; } public String _toString() { Type base = t; int totalDims = 0; while(base.isArray()) { totalDims++; base = base.asArray().getElementType(); } StringBuffer sb = new StringBuffer("new " + base); for(int i=0;i0) sb.append(", "); sb.append(arguments[i]+""); } sb.append(")"); } public String _toString() { StringBuffer sb = new StringBuffer(); sb.append(method.getDeclaringClass() == JSSA.this.method.getDeclaringClass() ? method.name : (method.getDeclaringClass() + "." + method.name)); args(sb); return sb.toString(); } } public class InvokeStatic extends Invoke { public InvokeStatic(Type.Class.Method m, Expr[] a) { super(m,a); } } public class InvokeSpecial extends InvokeVirtual { public InvokeSpecial(Type.Class.Method m, Expr[] a, Expr e) { super(m,a,e); } public String _toString() { return _toString(method.name.equals("") ? method.getDeclaringClass().getName() : method.name); } } public class InvokeInterface extends InvokeVirtual{ public InvokeInterface(Type.Class.Method m, Expr[] a, Expr e) { super(m,a,e); } } public class InvokeVirtual extends Invoke { public final Expr instance; public InvokeVirtual(Type.Class.Method m, Expr[] a, Expr e) { super(m, a); instance = e; } public String _toString() { return _toString(method.name); } protected String _toString(String name) { StringBuffer sb = new StringBuffer(); sb.append(instance+"."); sb.append(name); args(sb); return sb.toString(); } } 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 == null ? "null" : o instanceof String ? "\"" + o + "\"" : o.toString(); } public Type getType() { if (o == null) return Type.NULL; if (o instanceof Byte) return Type.BYTE; if (o instanceof Short) return Type.SHORT; if (o instanceof Character) return Type.CHAR; if (o instanceof Boolean) return Type.BOOLEAN; if (o instanceof Long) return Type.LONG; if (o instanceof Double) return Type.DOUBLE; if (o instanceof Float) return Type.FLOAT; if (o instanceof Integer) return Type.INT; if (o instanceof String) return Type.STRING; throw new IllegalStateException("unknown constant type"); } } // Implementation ////////////////////////////////////////////////////////////////////////////// private Object addOp(int op, Object arg) { int i1 = 0; int i2 = 0; if (op==WIDE) { MethodGen.Wide w = (MethodGen.Wide)arg; op = w.op; arg = null; i1 = w.varNum; i2 = w.n; } if (op==IINC) { MethodGen.Pair p = (MethodGen.Pair)arg; arg = null; i1 = p.i1; i2 = p.i2; } if (arg instanceof Number) i1 = ((Integer)arg).intValue(); Label label = (arg instanceof Label) ? (Label)arg : null; switch(op) { case NOP: return null; // Stack manipulations ////////////////////////////////////////////////////////////////////////////// case ACONST_NULL: push(new Constant(null)); return null; case ICONST_M1: push(new Constant(-1)); return null; case ICONST_0: case LCONST_0: case FCONST_0: case DCONST_0: push(new Constant(0)); return null; case ICONST_1: case LCONST_1: case FCONST_1: case DCONST_1: push(new Constant(1)); return null; case ICONST_2: case FCONST_2: push(new Constant(2)); return null; case ICONST_3: push(new Constant(3)); return null; case ICONST_4: push(new Constant(4)); return null; case ICONST_5: push(new Constant(5)); return null; case ILOAD: case LLOAD: case FLOAD: case DLOAD: case ALOAD: push(locals[pc][i1]); return null; case ILOAD_0: case LLOAD_0: case FLOAD_0: case DLOAD_0: case ALOAD_0: push(locals[pc][0]); return null; case ILOAD_1: case LLOAD_1: case FLOAD_1: case DLOAD_1: case ALOAD_1: push(locals[pc][1]); return null; case ALOAD_2: case DLOAD_2: case FLOAD_2: case LLOAD_2: case ILOAD_2: push(locals[pc][2]); return null; case ILOAD_3: case LLOAD_3: case FLOAD_3: case DLOAD_3: case ALOAD_3: push(locals[pc][3]); return null; case ISTORE: case LSTORE: case FSTORE: case DSTORE: case ASTORE: locals[pc+1][i1].merge(pop()); return null; case ISTORE_0: case LSTORE_0: case FSTORE_0: case DSTORE_0: case ASTORE_0: locals[pc+1][0].merge(pop()); return null; case ISTORE_1: case LSTORE_1: case FSTORE_1: case DSTORE_1: case ASTORE_1: locals[pc+1][1].merge(pop()); return null; case ASTORE_2: case DSTORE_2: case FSTORE_2: case LSTORE_2: case ISTORE_2: locals[pc+1][2].merge(pop()); return null; case ISTORE_3: case LSTORE_3: case FSTORE_3: case DSTORE_3: case ASTORE_3: locals[pc+1][3].merge(pop()); return null; case POP: pop(); return null; case POP2: pop(); pop(); return null; case DUP: push(stack[sp-1]); return null; case DUP2: push(stack[sp-2]); push(stack[sp-1]); return null; // Conversions ////////////////////////////////////////////////////////////////////////////// // coercions are added as-needed when converting from JSSA back to bytecode, so we can // simply discard them here (assuming the bytecode we're reading in was valid in the first place) case I2L: case F2L: case D2L: push(new Cast(pop(), Type.LONG)); return null; case I2F: case L2F: case D2F: push(new Cast(pop(), Type.FLOAT)); return null; case I2D: case L2D: case F2D: push(new Cast(pop(), Type.DOUBLE)); return null; case L2I: case F2I: case D2I: push(new Cast(pop(), Type.INT)); return null; case I2B: push(new Cast(pop(), Type.BYTE)); return null; case I2C: push(new Cast(pop(), Type.CHAR)); return null; case I2S: push(new Cast(pop(), Type.SHORT)); return null; case SWAP: { Expr e1 = pop(), e2 = pop(); push(e2); push(e1); return null; } // Math ////////////////////////////////////////////////////////////////////////////// case IADD: case LADD: case FADD: case DADD: push(new Add(pop(), pop())); return null; case ISUB: case LSUB: case FSUB: case DSUB: push(new Sub(pop(), pop())); return null; case IMUL: case LMUL: case FMUL: case DMUL: push(new Mul(pop(), pop())); return null; case IREM: case LREM: case FREM: case DREM: push(new Rem(pop(), pop())); return null; case INEG: case LNEG: case FNEG: case DNEG: push(new Neg(pop())); return null; case IDIV: case LDIV: case FDIV: case DDIV: push(new Div(pop(), pop())); return null; case ISHL: case LSHL: push(new Shl(pop(), pop())); return null; case ISHR: case LSHR: push(new Shr(pop(), pop())); return null; case IUSHR: case LUSHR: push(new Ushr(pop(), pop())); return null; case IAND: case LAND: push(new And(pop(), pop())); return null; case IOR: case LOR: push(new Or(pop(), pop())); return null; case IXOR: case LXOR: push(new Xor(pop(), pop())); return null; case IINC: return locals[pc+1][i1] = phi(new Add(locals[pc][i1], new Constant(i2))); // Control and branching ////////////////////////////////////////////////////////////////////////////// case IFNULL: return new If(new Eq(pop(), new Constant(null)), new Label(i1)); case IFNONNULL: return new If(new Not(new Eq(pop(),new Constant(null))),new Label(i1)); case IFEQ: return new If( new Eq(new Constant(0), pop()), new Label(i1)); case IFNE: return new If(new Not(new Eq(new Constant(0), pop())), new Label(i1)); case IFLT: return new If( new Lt(new Constant(0), pop()), new Label(i1)); case IFGE: return new If(new Not(new Lt(new Constant(0), pop())), new Label(i1)); case IFGT: return new If( new Gt(new Constant(0), pop()), new Label(i1)); case IFLE: return new If(new Not(new Gt(new Constant(0), pop())), new Label(i1)); case IF_ICMPEQ: return new If( new Eq(pop(), pop()), new Label(i1)); case IF_ICMPNE: return new If(new Not(new Eq(pop(), pop())), new Label(i1)); case IF_ICMPLT: return new If( new Lt(pop(), pop()), new Label(i1)); case IF_ICMPGE: return new If(new Not(new Lt(pop(), pop())), new Label(i1)); case IF_ICMPGT: return new If( new Gt(pop(), pop()), new Label(i1)); case IF_ICMPLE: return new If(new Not(new Gt(pop(), pop())), new Label(i1)); case IF_ACMPEQ: return new If( new Eq(pop(), pop()), new Label(i1)); case IF_ACMPNE: return new If(new Not(new Eq(pop(), pop())), new Label(i1)); case ATHROW: return new Throw(pop()); case GOTO: return new Goto(locals[pc][i1]); case JSR: push(new Label(pc)); return new JSR(new Label(i1)); case RET: return new RET(pop()); case RETURN: return new Return(); case IRETURN: case LRETURN: case FRETURN: case DRETURN: case ARETURN: return new Return(pop()); // Array manipulations ////////////////////////////////////////////////////////////////////////////// case IALOAD: case LALOAD: case FALOAD: case DALOAD: case AALOAD: case BALOAD: case CALOAD: case SALOAD: return seqPush(new ArrayGet(pop(), pop())); case IASTORE: case LASTORE: case FASTORE: case DASTORE: case AASTORE: case BASTORE: case CASTORE: case SASTORE: return new ArrayPut(pop(), pop(), pop()); // Invocation ////////////////////////////////////////////////////////////////////////////// case INVOKEVIRTUAL: case INVOKESPECIAL: case INVOKESTATIC: case INVOKEINTERFACE: { Type.Class.Method method = (Type.Class.Method)arg; Expr args[] = new Expr[method.getNumArgs()]; for(int i=0; i