jsexn on stack overflow
[org.ibex.core.git] / src / org / ibex / js / Interpreter.java
index 504bbd2..6fc2859 100644 (file)
@@ -6,7 +6,7 @@ import java.util.*;
 
 /** Encapsulates a single JS interpreter (ie call stack) */
 class Interpreter implements ByteCodes, Tokens {
-
+    private static final int MAX_STACK_SIZE = 512;
 
     // Thread-Interpreter Mapping /////////////////////////////////////////////////////////////////////////
 
@@ -236,9 +236,6 @@ class Interpreter implements ByteCodes, Tokens {
                     while (t != null && t.f.numFormalArgs == 0) t = t.next;
                     if (t == null) { target = ts.t.trapee; key = ts.t.name; }
 
-                } else if (target instanceof Trap.TrapScope && key.equals(((Trap.TrapScope)target).t.name)) {
-                    throw je("tried to put to " + key + " inside a trap it owns; use cascade instead"); 
-
                 } else if (target instanceof JS) {
                     if (target instanceof JSScope) {
                         JSScope p = (JSScope)target; // search the scope-path for the trap
@@ -251,6 +248,7 @@ class Interpreter implements ByteCodes, Tokens {
                 }
                 if (t != null) {
                     stack.push(new CallMarker(this));
+                    if(stack.size() > MAX_STACK_SIZE) throw new JSExn("stack overflow");
                     JSArray args = new JSArray();
                     args.addElement(val);
                     stack.push(args);
@@ -302,6 +300,7 @@ class Interpreter implements ByteCodes, Tokens {
                     }
                     if (t != null) {
                         stack.push(new CallMarker(this));
+                        if(stack.size() > MAX_STACK_SIZE) throw new JSExn("stack overflow");
                         JSArray args = new JSArray();
                         stack.push(args);
                         f = t.f;
@@ -352,6 +351,7 @@ class Interpreter implements ByteCodes, Tokens {
                     JSArray arguments = new JSArray();
                     for(int i=0; i<numArgs; i++) arguments.addElement(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
                     stack.push(new CallMarker(this));
+                    if(stack.size() > MAX_STACK_SIZE) throw new JSExn("stack overflow");
                     stack.push(arguments);
                     f = (JSFunction)object;
                     scope = new JSScope(f.parentScope);
@@ -402,7 +402,17 @@ class Interpreter implements ByteCodes, Tokens {
                 Object key = stack.pop();
                 Object obj = stack.peek();
                 // A trap addition/removal
-                JS js = obj instanceof JSScope ? ((JSScope)obj).top() : (JS) obj;
+                JS js = (JS) obj;
+                if(js instanceof JSScope) {
+                    JSScope s = (JSScope) js;
+                    while(s.getParentScope() != null) {
+                        if(s.has(key)) throw new JSExn("cannot trap a variable that isn't at the top level scope");
+                        s = s.getParentScope();
+                    }
+                    js = s;
+                }
+                // might want this?
+                // if(!js.has(key)) throw new JSExn("tried to add/remove a trap from an uninitialized variable");
                 if(op == ADD_TRAP) js.addTrap(key, (JSFunction)val);
                 else js.delTrap(key, (JSFunction)val);
                 break;
@@ -486,7 +496,7 @@ class Interpreter implements ByteCodes, Tokens {
                     if (right == null) right = JS.N(0);
                     int result = 0;
                     if (left instanceof String || right instanceof String) {
-                        result = left.toString().compareTo(right.toString());
+                        result = JS.toString(left).compareTo(JS.toString(right));
                     } else {
                         result = (int)java.lang.Math.ceil(JS.toDouble(left) - JS.toDouble(right));
                     }
@@ -497,6 +507,7 @@ class Interpreter implements ByteCodes, Tokens {
                     
                 case EQ:
                 case NE: {
+                    // FIXME: This is not correct, see ECMA-262 11.9.3
                     Object l = left;
                     Object r = right;
                     boolean ret;
@@ -505,7 +516,7 @@ class Interpreter implements ByteCodes, Tokens {
                     else if (r == null) ret = false; // l != null, so its false
                     else if (l instanceof Boolean) ret = JS.B(JS.toBoolean(r)).equals(l);
                     else if (l instanceof Number) ret = JS.toNumber(r).doubleValue() == JS.toNumber(l).doubleValue();
-                    else if (l instanceof String) ret = r != null && l.equals(r.toString());
+                    else if (l instanceof String) ret = r != null && l.equals(JS.toString(r));
                     else ret = l.equals(r);
                     stack.push(JS.B(op == EQ ? ret : !ret)); break;
                 }
@@ -652,13 +663,13 @@ class Interpreter implements ByteCodes, Tokens {
             return sb.toString();
         }
         case "indexOf": {
-            String search = alength >= 1 ? arg0.toString() : "null";
+            String search = alength >= 1 ? JS.toString(arg0) : "null";
             int start = alength >= 2 ? JS.toInt(arg1) : 0;
             // Java's indexOf handles an out of bounds start index, it'll return -1
             return JS.N(s.indexOf(search,start));
         }
         case "lastIndexOf": {
-            String search = alength >= 1 ? arg0.toString() : "null";
+            String search = alength >= 1 ? JS.toString(arg0) : "null";
             int start = alength >= 2 ? JS.toInt(arg1) : 0;
             // Java's indexOf handles an out of bounds start index, it'll return -1
             return JS.N(s.lastIndexOf(search,start));            
@@ -696,7 +707,7 @@ class Interpreter implements ByteCodes, Tokens {
         }
         if (!returnJS) {
             // the string stuff applies to everything
-            String s = o.toString();
+            String s = JS.toString(o);
             
             // this is sort of ugly, but this list should never change
             // These should provide a complete (enough) implementation of the ECMA-262 String object
@@ -722,7 +733,7 @@ class Interpreter implements ByteCodes, Tokens {
         }
         if (returnJS) {
             final Object target = o;
-            final String method = key.toString();
+            final String method = JS.toString(o);
             return new JS() {
                     public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
                         if (nargs > 2) throw new JSExn("cannot call that method with that many arguments");