stack overflow checking
[org.ibex.classgen.git] / src / org / ibex / classgen / JSSA.java
index 23c88bc..c16f5e6 100644 (file)
@@ -13,6 +13,8 @@ public class JSSA extends MethodGen implements CGConst {
     
     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++) {
@@ -63,20 +65,30 @@ public class JSSA extends MethodGen implements CGConst {
     // 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
@@ -185,20 +197,33 @@ public class JSSA extends MethodGen implements CGConst {
     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 {
@@ -220,18 +245,27 @@ public class JSSA extends MethodGen implements CGConst {
         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 */
@@ -353,7 +387,6 @@ public class JSSA extends MethodGen implements CGConst {
     // Implementation //////////////////////////////////////////////////////////////////////////////
 
     private Object addOp(int op, Object arg) {
-        Number number = null;
         int i1 = 0;
         int i2 = 0;
         if (op==WIDE) {
@@ -369,7 +402,6 @@ public class JSSA extends MethodGen implements CGConst {
             i1 = p.i1;
             i2 = p.i2;
         }
-        if (arg != null && arg instanceof Number) number = (Number)arg;
         switch(op) {
 
             case NOP: return null;
@@ -485,16 +517,37 @@ public class JSSA extends MethodGen implements CGConst {
 
                 // 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;