bug 584075, r=taustin: use ExecutionContext.prototype.run instead of push/pop
authorDave Herman <dherman@mozilla.com>
Tue, 10 Aug 2010 15:45:04 -0700
changeset 50478 6d977009d79f814b27c755a075737e4e8765a7ba
parent 50477 ed744bdf2aaa48b0b0f39df9e8f5d9ca6f173d24
child 50479 ba24f1f29feb8ade3243634e89c73470b34f32d7
push idunknown
push userunknown
push dateunknown
reviewerstaustin
bugs584075
milestone2.0b4pre
bug 584075, r=taustin: use ExecutionContext.prototype.run instead of push/pop
js/narcissus/jsexec.js
--- a/js/narcissus/jsexec.js
+++ b/js/narcissus/jsexec.js
@@ -57,58 +57,49 @@ Narcissus.interpreter = (function() {
     eval(definitions.consts);
 
     const GLOBAL_CODE = 0, EVAL_CODE = 1, FUNCTION_CODE = 2;
 
     function ExecutionContext(type) {
         this.type = type;
     }
 
+    function isStackOverflow(e) {
+        var re = /InternalError: (script stack space quota is exhausted|too much recursion)/;
+        return re.test(e.toString());
+    }
+
     var global = {
         // Value properties.
         NaN: NaN, Infinity: Infinity, undefined: undefined,
 
         // Function properties.
         eval: function eval(s) {
             if (typeof s !== "string")
                 return s;
 
             var x = ExecutionContext.current;
             var x2 = new ExecutionContext(EVAL_CODE);
             x2.thisObject = x.thisObject;
             x2.caller = x.caller;
             x2.callee = x.callee;
             x2.scope = x.scope;
-            ExecutionContext.current = x2;
             try {
-                execute(parser.parse(new parser.VanillaBuilder, s), x2);
-            } catch (e if e === THROW) {
-                x.result = x2.result;
-                throw e;
-            } catch (e if e instanceof SyntaxError) {
-                x.result = e;
-                throw THROW;
-            } catch (e if e instanceof InternalError) {
+                x2.execute(parser.parse(new parser.VanillaBuilder, s));
+                return x2.result;
+            } catch (e if e instanceof SyntaxError || isStackOverflow(e)) {
                 /*
-                 * If we get too much recursion during parsing we need to re-throw
-                 * it as a narcissus THROW.
+                 * If we get an internal error during parsing we need to reify
+                 * the exception as a Narcissus THROW.
                  *
                  * See bug 152646.
                  */
-                var re = /InternalError: (script stack space quota is exhausted|too much recursion)/;
-                if (re.test(e.toString())) {
-                    x.result = e;
-                    throw THROW;
-                } else {
-                    throw e;
-                }
-            } finally {
-                ExecutionContext.current = x;
+                x.result = e;
+                throw THROW;
             }
-            return x2.result;
         },
         parseInt: parseInt, parseFloat: parseFloat,
         isNaN: isNaN, isFinite: isFinite,
         decodeURI: decodeURI, encodeURI: encodeURI,
         decodeURIComponent: decodeURIComponent,
         encodeURIComponent: encodeURIComponent,
 
         // Class constructors.  Where ECMA-262 requires C.length === 1, we declare
@@ -201,28 +192,29 @@ Narcissus.interpreter = (function() {
     ExecutionContext.prototype = {
         caller: null,
         callee: null,
         scope: {object: global, parent: null},
         thisObject: global,
         result: undefined,
         target: null,
         ecma3OnlyMode: false,
-        // Run a thunk in this execution context and return its result.
-        run: function(thunk) {
+        // Execute a node in this execution context.
+        execute: function(n) {
             var prev = ExecutionContext.current;
             ExecutionContext.current = this;
             try {
-                thunk();
-                return this.result;
+                execute(n, this);
             } catch (e if e === THROW) {
+                // Propagate the throw to the previous context if it exists.
                 if (prev) {
                     prev.result = this.result;
                     throw THROW;
                 }
+                // Otherwise reflect the throw into host JS.
                 throw this.result;
             } finally {
                 ExecutionContext.current = prev;
             }
         }
     };
 
     function Reference(base, propertyName, node) {
@@ -915,26 +907,20 @@ Narcissus.interpreter = (function() {
             var x2 = new ExecutionContext(FUNCTION_CODE);
             x2.thisObject = t || global;
             x2.caller = x;
             x2.callee = this;
             definitions.defineProperty(a, "callee", this, false, false, true);
             var f = this.node;
             x2.scope = {object: new Activation(f, a), parent: this.scope};
 
-            ExecutionContext.current = x2;
             try {
-                execute(f.body, x2);
+                x2.execute(f.body);
             } catch (e if e === RETURN) {
                 return x2.result;
-            } catch (e if e === THROW) {
-                x.result = x2.result;
-                throw THROW;
-            } finally {
-                ExecutionContext.current = x;
             }
             return undefined;
         },
 
         __construct__: function (a, x) {
             var o = new Object;
             var p = this.prototype;
             if (isObject(p))
@@ -1059,31 +1045,19 @@ Narcissus.interpreter = (function() {
     function thunk(f, x) {
         return function () { return f.__call__(this, arguments, x); };
     }
 
     function evaluate(s, f, l) {
         if (typeof s !== "string")
             return s;
 
-        var x = ExecutionContext.current;
-        var x2 = new ExecutionContext(GLOBAL_CODE);
-        ExecutionContext.current = x2;
-        try {
-            execute(parser.parse(new parser.VanillaBuilder, s, f, l), x2);
-        } catch (e if e === THROW) {
-            if (x) {
-                x.result = x2.result;
-                throw THROW;
-            }
-            throw x2.result;
-        } finally {
-            ExecutionContext.current = x;
-        }
-        return x2.result;
+        var x = new ExecutionContext(GLOBAL_CODE);
+        x.execute(parser.parse(new parser.VanillaBuilder, s, f, l));
+        return x.result;
     }
 
     // A read-eval-print-loop that roughly tracks the behavior of the js shell.
     function repl() {
 
         // Display a value similarly to the js shell.
         function display(x) {
             if (typeof x === "object") {
@@ -1111,41 +1085,41 @@ Narcissus.interpreter = (function() {
             } catch (e) {
                 return "unknown (can't convert to string)";
             }
         }
 
         var b = new parser.VanillaBuilder;
         var x = new ExecutionContext(GLOBAL_CODE);
 
-        x.run(function() {
-            for (;;) {
-                x.result = undefined;
-                putstr("njs> ");
-                var line = readline();
-                // If readline receives EOF it returns null.
-                if (line === null) {
-                    print("");
-                    break;
-                }
-                try {
-                    execute(parser.parse(b, line, "stdin", 1), x);
-                    display(x.result);
-                } catch (e if e === THROW) {
-                    print("uncaught exception: " + string(x.result));
-                } catch (e if e === END) {
-                    break;
-                } catch (e if e instanceof SyntaxError) {
-                    print(e.toString());
-                } catch (e) {
-                    print("internal Narcissus error");
-                    throw e;
-                }
+        ExecutionContext.current = x;
+        for (;;) {
+            x.result = undefined;
+            putstr("njs> ");
+            var line = readline();
+            // If readline receives EOF it returns null.
+            if (line === null) {
+                print("");
+                break;
             }
-        });
+            try {
+                execute(parser.parse(b, line, "stdin", 1), x);
+                display(x.result);
+            } catch (e if e === THROW) {
+                print("uncaught exception: " + string(x.result));
+            } catch (e if e === END) {
+                break;
+            } catch (e if e instanceof SyntaxError) {
+                print(e.toString());
+            } catch (e) {
+                print("internal Narcissus error");
+                throw e;
+            }
+        }
+        ExecutionContext.current = null;
     }
 
     return {
         evaluate: evaluate,
         repl: repl
     };
 
 }());