changeset 265:eeed4db61215

Merge
author jlaskey
date Tue, 14 May 2013 11:16:52 -0300
parents 80d4db063d5a 264bb0af9e4e
children fc20983ef38e
files src/jdk/nashorn/internal/ir/LineNumberNode.java src/jdk/nashorn/internal/ir/Location.java test/script/trusted/logcoverage.js
diffstat 106 files changed, 3275 insertions(+), 1818 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue May 14 11:15:12 2013 -0300
+++ b/.hgignore	Tue May 14 11:16:52 2013 -0300
@@ -8,6 +8,7 @@
 private.properties
 webrev/*
 webrev.zip
+.classpath
 *.class
 *.clazz
 *.log
--- a/.hgtags	Tue May 14 11:15:12 2013 -0300
+++ b/.hgtags	Tue May 14 11:16:52 2013 -0300
@@ -196,3 +196,5 @@
 999cc1bf55203f51b2985feae6378932667ecff2 jdk8-b84
 e0378f0a50dafdcfb7b04f6401d320f89884baa1 jdk8-b85
 002ad9d6735f36d1204e133324c73058c8abb1b0 jdk8-b86
+774aeaa89bc15f4365e3c2fc36f6a3a0da70ba28 jdk8-b87
+40c107d1ae6f81a62e35dfe618b827897405e9b2 jdk8-b88
--- a/bin/jjs	Tue May 14 11:15:12 2013 -0300
+++ b/bin/jjs	Tue May 14 11:16:52 2013 -0300
@@ -26,4 +26,4 @@
 
 [ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1;
 
-$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
+$JAVA_HOME/bin/java -server -XX:+TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
--- a/make/project.properties	Tue May 14 11:15:12 2013 -0300
+++ b/make/project.properties	Tue May 14 11:16:52 2013 -0300
@@ -194,6 +194,8 @@
 test262-test-sys-prop.test.js.exclude.dir=\
     ${test262.suite.dir}/intl402/
 
+test262-test-sys-prop.test.failed.list.file=${build.dir}/test/failedTests
+
 # test262 test frameworks
 test262-test-sys-prop.test.js.framework=\
     -timezone=PST \
@@ -214,7 +216,7 @@
 
 #  -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods
 # add '-Dtest.js.outofprocess' to run each test in a new sub-process
-run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
+run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
 #-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M  
 run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main}
 
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Tue May 14 11:16:52 2013 -0300
@@ -78,7 +78,6 @@
         this(factory, DEFAULT_OPTIONS, appLoader);
     }
 
-    @SuppressWarnings("LeakingThisInConstructor")
     NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args, final ClassLoader appLoader) {
         this.factory = factory;
         final Options options = new Options("nashorn");
@@ -102,7 +101,7 @@
         });
 
         // create new global object
-        this.global =  createNashornGlobal();
+        this.global = createNashornGlobal();
         // set the default engine scope for the default context
         context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
 
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Tue May 14 11:16:52 2013 -0300
@@ -31,7 +31,6 @@
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineFactory;
 import jdk.nashorn.internal.runtime.Version;
-import sun.reflect.Reflection;
 
 /**
  * JSR-223 compliant script engine factory for Nashorn. The engine answers for:
--- a/src/jdk/nashorn/internal/codegen/Attr.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/Attr.java	Tue May 14 11:16:52 2013 -0300
@@ -29,11 +29,13 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.EXCEPTION_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.ITERATOR_PREFIX;
+import static jdk.nashorn.internal.codegen.CompilerConstants.LITERAL_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
+import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT;
 import static jdk.nashorn.internal.ir.Symbol.IS_FUNCTION_SELF;
 import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
 import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
@@ -73,8 +75,10 @@
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
+import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.ir.TemporarySymbols;
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.TryNode;
 import jdk.nashorn.internal.ir.UnaryNode;
@@ -90,7 +94,6 @@
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.PropertyMap;
-import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
 
 /**
@@ -129,13 +132,16 @@
     private static final DebugLogger LOG   = new DebugLogger("attr");
     private static final boolean     DEBUG = LOG.isEnabled();
 
+    private final TemporarySymbols temporarySymbols;
+
     /**
      * Constructor.
      */
-    Attr() {
-        localDefs = new ArrayDeque<>();
-        localUses = new ArrayDeque<>();
-        returnTypes = new ArrayDeque<>();
+    Attr(final TemporarySymbols temporarySymbols) {
+        this.temporarySymbols = temporarySymbols;
+        this.localDefs   = new ArrayDeque<>();
+        this.localUses   = new ArrayDeque<>();
+        this.returnTypes = new ArrayDeque<>();
     }
 
     @Override
@@ -150,67 +156,50 @@
 
     @Override
     public Node leaveAccessNode(final AccessNode accessNode) {
-        ensureSymbol(Type.OBJECT, accessNode);  //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this
-        end(accessNode);
-        return accessNode;
+        //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this, that
+        //is why we can't set the access node base to be an object here, that will ruin access specialization
+        //for example for a.x | 17.
+        return end(ensureSymbol(Type.OBJECT, accessNode));
     }
 
-    private void enterFunctionBody() {
+    private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) {
+        initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL, FunctionNode.FUNCTION_TYPE);
+        initCompileConstant(THIS, body, IS_PARAM | IS_THIS, Type.OBJECT);
 
-        final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
-        final Block body = getLexicalContext().getCurrentBlock();
-        initCallee(body);
-        initThis(body);
         if (functionNode.isVarArg()) {
-            initVarArg(body, functionNode.needsArguments());
+            initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL, Type.OBJECT_ARRAY);
+            if (functionNode.needsArguments()) {
+                initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL, Type.typeFor(ScriptObject.class));
+                addLocalDef(ARGUMENTS.symbolName());
+            }
         }
 
         initParameters(functionNode, body);
-        initScope(body);
-        initReturn(body);
+        initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL, Type.typeFor(ScriptObject.class));
+        initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL, Type.OBJECT);
+    }
 
-        if (functionNode.isProgram()) {
-            initFromPropertyMap(body);
-        } else if(!functionNode.isDeclared()) {
-            // It's neither declared nor program - it's a function expression then; assign it a self-symbol.
 
-            if (functionNode.getSymbol() != null) {
-                // a temporary left over from an earlier pass when the function was lazy
-                assert functionNode.getSymbol().isTemp();
-                // remove it
-                functionNode.setSymbol(null);
-            }
-            final boolean anonymous = functionNode.isAnonymous();
-            final String name = anonymous ? null : functionNode.getIdent().getName();
-            if (anonymous || body.getExistingSymbol(name) != null) {
-                // The function is either anonymous, or another local identifier already trumps its name on entry:
-                // either it has the same name as one of its parameters, or is named "arguments" and also references the
-                // "arguments" identifier in its body.
-                ensureSymbol(functionNode, Type.typeFor(ScriptFunction.class), functionNode);
-            } else {
-                final Symbol selfSymbol = defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF, functionNode);
-                assert selfSymbol.isFunctionSelf();
-                newType(selfSymbol, Type.OBJECT);
-            }
-        }
-
-        /*
-         * This pushes all declarations (except for non-statements, i.e. for
-         * node temporaries) to the top of the function scope. This way we can
-         * get around problems like
-         *
-         * while (true) {
-         *   break;
-         *   if (true) {
-         *     var s;
-         *   }
-         * }
-         *
-         * to an arbitrary nesting depth.
-         *
-         * @see NASHORN-73
-         */
-
+    /**
+     * This pushes all declarations (except for non-statements, i.e. for
+     * node temporaries) to the top of the function scope. This way we can
+     * get around problems like
+     *
+     * while (true) {
+     *   break;
+     *   if (true) {
+     *     var s;
+     *   }
+     * }
+     *
+     * to an arbitrary nesting depth.
+     *
+     * see NASHORN-73
+     *
+     * @param functionNode the FunctionNode we are entering
+     * @param body the body of the FunctionNode we are entering
+     */
+    private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
         // This visitor will assign symbol to all declared variables, except function declarations (which are taken care
         // in a separate step above) and "var" declarations in for loop initializers.
         body.accept(new NodeOperatorVisitor() {
@@ -220,27 +209,52 @@
             }
 
             @Override
-            public boolean enterVarNode(final VarNode varNode) {
-
+            public Node leaveVarNode(final VarNode varNode) {
                 // any declared symbols that aren't visited need to be typed as well, hence the list
-
                 if (varNode.isStatement()) {
-
-                    final IdentNode ident = varNode.getName();
-                    final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR, new IdentNode(ident));
+                    final IdentNode ident  = varNode.getName();
+                    final Symbol    symbol = defineSymbol(body, ident.getName(), IS_VAR);
                     functionNode.addDeclaredSymbol(symbol);
                     if (varNode.isFunctionDeclaration()) {
                         newType(symbol, FunctionNode.FUNCTION_TYPE);
                     }
+                    return varNode.setName((IdentNode)ident.setSymbol(getLexicalContext(), symbol));
                 }
-                return false;
+                return varNode;
             }
         });
     }
 
+    private void enterFunctionBody() {
+
+        final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
+        final Block body = getLexicalContext().getCurrentBlock();
+
+        initFunctionWideVariables(functionNode, body);
+
+        if (functionNode.isProgram()) {
+            initFromPropertyMap(body);
+        } else if (!functionNode.isDeclared()) {
+            // It's neither declared nor program - it's a function expression then; assign it a self-symbol.
+            assert functionNode.getSymbol() == null;
+
+            final boolean anonymous = functionNode.isAnonymous();
+            final String  name      = anonymous ? null : functionNode.getIdent().getName();
+            if (!(anonymous || body.getExistingSymbol(name) != null)) {
+                assert !anonymous && name != null;
+                newType(defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF), Type.OBJECT);
+            }
+        }
+
+        acceptDeclarations(functionNode, body);
+    }
+
     @Override
     public boolean enterBlock(final Block block) {
         start(block);
+        //ensure that we don't use information from a previous compile. This is very ugly TODO
+        //the symbols in the block should really be stateless
+        block.clearSymbols();
 
         if (getLexicalContext().isFunctionBody()) {
             enterFunctionBody();
@@ -257,14 +271,13 @@
     }
 
     @Override
-    public Node leaveCallNode(final CallNode callNode) {
-        ensureSymbol(callNode.getType(), callNode);
-        return end(callNode);
+    public boolean enterCallNode(final CallNode callNode) {
+        return start(callNode);
     }
 
     @Override
-    public boolean enterCallNode(final CallNode callNode) {
-        return start(callNode);
+    public Node leaveCallNode(final CallNode callNode) {
+        return end(ensureSymbol(callNode.getType(), callNode));
     }
 
     @Override
@@ -275,23 +288,31 @@
         start(catchNode);
 
         // define block-local exception variable
-        final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception);
+        final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET);
         newType(def, Type.OBJECT);
         addLocalDef(exception.getName());
 
         return true;
     }
 
+    @Override
+    public Node leaveCatchNode(final CatchNode catchNode) {
+        final IdentNode exception = catchNode.getException();
+        final Block  block        = getLexicalContext().getCurrentBlock();
+        final Symbol symbol       = findSymbol(block, exception.getName());
+        assert symbol != null;
+        return end(catchNode.setException((IdentNode)exception.setSymbol(getLexicalContext(), symbol)));
+    }
+
     /**
      * Declare the definition of a new symbol.
      *
      * @param name         Name of symbol.
      * @param symbolFlags  Symbol flags.
-     * @param node         Defining Node.
      *
      * @return Symbol for given name or null for redefinition.
      */
-    private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) {
+    private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) {
         int    flags  = symbolFlags;
         Symbol symbol = findSymbol(block, name); // Locate symbol.
 
@@ -337,7 +358,7 @@
 
             // Create and add to appropriate block.
             symbol = new Symbol(name, flags);
-            symbolBlock.putSymbol(name, symbol);
+            symbolBlock.putSymbol(getLexicalContext(), symbol);
 
             if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
                 symbol.setNeedsSlot(true);
@@ -346,10 +367,6 @@
             symbol.setFlags(flags);
         }
 
-        if (node != null) {
-            node.setSymbol(symbol);
-        }
-
         return symbol;
     }
 
@@ -357,30 +374,22 @@
     public boolean enterFunctionNode(final FunctionNode functionNode) {
         start(functionNode, false);
 
+        if (functionNode.isLazy()) {
+            return false;
+        }
+
+        //an outermost function in our lexical context that is not a program (runScript)
+        //is possible - it is a function being compiled lazily
         if (functionNode.isDeclared()) {
             final Iterator<Block> blocks = getLexicalContext().getBlocks();
             if (blocks.hasNext()) {
-                defineSymbol(
-                    blocks.next(),
-                    functionNode.getIdent().getName(),
-                    IS_VAR,
-                    functionNode);
-            } else {
-                // Q: What's an outermost function in a lexical context that is not a program?
-                // A: It's a function being compiled lazily!
-                assert getLexicalContext().getOutermostFunction() == functionNode && !functionNode.isProgram();
+                defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR);
             }
         }
 
-        if (functionNode.isLazy()) {
-            LOG.info("LAZY: ", functionNode.getName(), " => Promoting to OBJECT");
-            ensureSymbol(getLexicalContext().getCurrentFunction(), Type.OBJECT, functionNode);
-            end(functionNode);
-            return false;
-        }
-
         returnTypes.push(functionNode.getReturnType());
         pushLocalsFunction();
+
         return true;
     }
 
@@ -390,9 +399,30 @@
 
         final LexicalContext lc = getLexicalContext();
 
+        final Block body = newFunctionNode.getBody();
+
+        //look for this function in the parent block
+        if (functionNode.isDeclared()) {
+            final Iterator<Block> blocks = getLexicalContext().getBlocks();
+            if (blocks.hasNext()) {
+                newFunctionNode = (FunctionNode)newFunctionNode.setSymbol(lc, findSymbol(blocks.next(), functionNode.getIdent().getName()));
+            }
+        } else if (!functionNode.isProgram()) {
+            final boolean anonymous = functionNode.isAnonymous();
+            final String  name      = anonymous ? null : functionNode.getIdent().getName();
+            if (anonymous || body.getExistingSymbol(name) != null) {
+                newFunctionNode = (FunctionNode)ensureSymbol(lc, FunctionNode.FUNCTION_TYPE, newFunctionNode);
+            } else {
+                assert name != null;
+                final Symbol self = body.getExistingSymbol(name);
+                assert self != null && self.isFunctionSelf();
+                newFunctionNode = (FunctionNode)newFunctionNode.setSymbol(lc, body.getExistingSymbol(name));
+            }
+        }
+
         //unknown parameters are promoted to object type.
-        finalizeParameters(newFunctionNode);
-        finalizeTypes(newFunctionNode);
+        newFunctionNode = finalizeParameters(newFunctionNode);
+        newFunctionNode = finalizeTypes(newFunctionNode);
         for (final Symbol symbol : newFunctionNode.getDeclaredSymbols()) {
             if (symbol.getSymbolType().isUnknown()) {
                 symbol.setType(Type.OBJECT);
@@ -400,8 +430,6 @@
             }
         }
 
-        final Block body = newFunctionNode.getBody();
-
         if (newFunctionNode.hasLazyChildren()) {
             //the final body has already been assigned as we have left the function node block body by now
             objectifySymbols(body);
@@ -409,9 +437,9 @@
 
         if (body.getFlag(Block.NEEDS_SELF_SYMBOL)) {
             final IdentNode callee = compilerConstant(CALLEE);
-            final VarNode selfInit =
+            VarNode selfInit =
                 new VarNode(
-                    newFunctionNode.getSource(),
+                    newFunctionNode.getLineNumber(),
                     newFunctionNode.getToken(),
                     newFunctionNode.getFinish(),
                     newFunctionNode.getIdent(),
@@ -419,8 +447,7 @@
 
             LOG.info("Accepting self symbol init ", selfInit, " for ", newFunctionNode.getName());
 
-            final List<Node> newStatements = new ArrayList<>();
-            newStatements.add(selfInit);
+            final List<Statement> newStatements = new ArrayList<>();
             assert callee.getSymbol() != null && callee.getSymbol().hasSlot();
 
             final IdentNode name       = selfInit.getName();
@@ -428,9 +455,10 @@
 
             assert nameSymbol != null;
 
-            name.setSymbol(nameSymbol);
-            selfInit.setSymbol(nameSymbol);
+            selfInit = selfInit.setName((IdentNode)name.setSymbol(lc, nameSymbol));
+            selfInit = (VarNode)selfInit.setSymbol(lc, nameSymbol);
 
+            newStatements.add(selfInit);
             newStatements.addAll(body.getStatements());
             newFunctionNode = newFunctionNode.setBody(lc, body.setStatements(lc, newStatements));
         }
@@ -447,34 +475,32 @@
 
         end(newFunctionNode, false);
 
-        return newFunctionNode; //.setFlag(lc, lc.getFlags(functionNode));
+        return newFunctionNode;
     }
 
     @Override
     public Node leaveCONVERT(final UnaryNode unaryNode) {
         assert false : "There should be no convert operators in IR during Attribution";
-        end(unaryNode);
-        return unaryNode;
+        return end(unaryNode);
     }
 
     @Override
-    public boolean enterIdentNode(final IdentNode identNode) {
+    public Node leaveIdentNode(final IdentNode identNode) {
         final String name = identNode.getName();
 
         start(identNode);
 
+        final LexicalContext lc = getLexicalContext();
+
         if (identNode.isPropertyName()) {
             // assign a pseudo symbol to property name
             final Symbol pseudoSymbol = pseudoSymbol(name);
             LOG.info("IdentNode is property name -> assigning pseudo symbol ", pseudoSymbol);
             LOG.unindent();
-            identNode.setSymbol(pseudoSymbol);
-            return false;
+            return end(identNode.setSymbol(lc, pseudoSymbol));
         }
 
-        final LexicalContext lc        = getLexicalContext();
-        final Block          block     = lc.getCurrentBlock();
-        final Symbol         oldSymbol = identNode.getSymbol();
+        final Block block = lc.getCurrentBlock();
 
         Symbol symbol = findSymbol(block, name);
 
@@ -495,12 +521,11 @@
                 }
             }
 
-            identNode.setSymbol(symbol);
             // if symbol is non-local or we're in a with block, we need to put symbol in scope (if it isn't already)
             maybeForceScope(symbol);
         } else {
             LOG.info("No symbol exists. Declare undefined: ", symbol);
-            symbol = defineSymbol(block, name, IS_GLOBAL, identNode);
+            symbol = defineSymbol(block, name, IS_GLOBAL);
             // we have never seen this before, it can be undefined
             newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway?
             symbol.setCanBeUndefined();
@@ -509,14 +534,12 @@
 
         setBlockScope(name, symbol);
 
-        if (symbol != oldSymbol && !identNode.isInitializedHere()) {
+        if (!identNode.isInitializedHere()) {
             symbol.increaseUseCount();
         }
         addLocalUse(identNode.getName());
 
-        end(identNode);
-
-        return false;
+        return end(identNode.setSymbol(lc, symbol));
     }
 
     /**
@@ -525,7 +548,7 @@
      * @param symbol the symbol that might be scoped
      */
     private void maybeForceScope(final Symbol symbol) {
-        if(!symbol.isScope() && symbolNeedsToBeScope(symbol)) {
+        if (!symbol.isScope() && symbolNeedsToBeScope(symbol)) {
             Symbol.setSymbolIsScope(getLexicalContext(), symbol);
         }
     }
@@ -612,11 +635,11 @@
     private Symbol findSymbol(final Block block, final String name) {
         // Search up block chain to locate symbol.
 
-        for(final Iterator<Block> blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) {
+        for (final Iterator<Block> blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) {
             // Find name.
             final Symbol symbol = blocks.next().getExistingSymbol(name);
             // If found then we are good.
-            if(symbol != null) {
+            if (symbol != null) {
                 return symbol;
             }
         }
@@ -625,39 +648,19 @@
 
     @Override
     public Node leaveIndexNode(final IndexNode indexNode) {
-        ensureSymbol(Type.OBJECT, indexNode); //TODO
-        return indexNode;
+        return end(ensureSymbol(Type.OBJECT, indexNode));
     }
 
     @SuppressWarnings("rawtypes")
     @Override
-    public boolean enterLiteralNode(final LiteralNode literalNode) {
-        try {
-            start(literalNode);
-            assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens
-
-            if (literalNode instanceof ArrayLiteralNode) {
-                final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
-                final Node[]           array            = arrayLiteralNode.getValue();
-
-                for (int i = 0; i < array.length; i++) {
-                    final Node element = array[i];
-                    if (element != null) {
-                        array[i] = element.accept(this);
-                    }
-                }
-                arrayLiteralNode.analyze();
-                //array literal node now has an element type and all elements are attributed
-            } else {
-                assert !(literalNode.getValue() instanceof Node) : "literals with Node values not supported";
-            }
-
-            getLexicalContext().getCurrentFunction().newLiteral(literalNode);
-        } finally {
-            end(literalNode);
+    public Node leaveLiteralNode(final LiteralNode literalNode) {
+        assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens
+        assert literalNode instanceof ArrayLiteralNode || !(literalNode.getValue() instanceof Node) : "literals with Node values not supported";
+        final Symbol symbol = new Symbol(getLexicalContext().getCurrentFunction().uniqueName(LITERAL_PREFIX.symbolName()), IS_CONSTANT, literalNode.getType());
+        if (literalNode instanceof ArrayLiteralNode) {
+            ((ArrayLiteralNode)literalNode).analyze();
         }
-
-        return false;
+        return end(literalNode.setSymbol(getLexicalContext(), symbol));
     }
 
     @Override
@@ -667,18 +670,13 @@
 
     @Override
     public Node leaveObjectNode(final ObjectNode objectNode) {
-        ensureSymbol(Type.OBJECT, objectNode);
-        return end(objectNode);
+        return end(ensureSymbol(Type.OBJECT, objectNode));
     }
 
-    //TODO is this correct why not leave?
     @Override
-    public boolean enterPropertyNode(final PropertyNode propertyNode) {
+    public Node leavePropertyNode(final PropertyNode propertyNode) {
         // assign a pseudo symbol to property name, see NASHORN-710
-        start(propertyNode);
-        propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
-        end(propertyNode);
-        return true;
+        return propertyNode.setSymbol(getLexicalContext(), new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
     }
 
     @Override
@@ -763,12 +761,9 @@
         final IdentNode ident = varNode.getName();
         final String    name  = ident.getName();
 
-        final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR, ident);
+        final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR);
         assert symbol != null;
 
-        LOG.info("VarNode ", varNode, " set symbol ", symbol);
-        varNode.setSymbol(symbol);
-
         // NASHORN-467 - use before definition of vars - conservative
         if (isLocalUse(ident.getName())) {
             newType(symbol, Type.OBJECT);
@@ -780,22 +775,32 @@
 
     @Override
     public Node leaveVarNode(final VarNode varNode) {
-        final Node      init  = varNode.getInit();
-        final IdentNode ident = varNode.getName();
+        VarNode newVarNode = varNode;
+
+        final Node      init  = newVarNode.getInit();
+        final IdentNode ident = newVarNode.getName();
         final String    name  = ident.getName();
 
+        final LexicalContext lc = getLexicalContext();
+        final Symbol  symbol = findSymbol(lc.getCurrentBlock(), ident.getName());
+
         if (init == null) {
             // var x; with no init will be treated like a use of x by
-            // visit(IdentNode) unless we remove the name
-            // from the localdef list.
+            // leaveIdentNode unless we remove the name from the localdef list.
             removeLocalDef(name);
-            return varNode;
+            return end(newVarNode.setSymbol(lc, symbol));
         }
 
         addLocalDef(name);
 
-        final Symbol  symbol   = varNode.getSymbol();
-        final boolean isScript = getLexicalContext().getDefiningFunction(symbol).isProgram(); //see NASHORN-56
+        assert symbol != null;
+
+        final IdentNode newIdent = (IdentNode)ident.setSymbol(lc, symbol);
+
+        newVarNode = newVarNode.setName(newIdent);
+        newVarNode = (VarNode)newVarNode.setSymbol(lc, symbol);
+
+        final boolean isScript = lc.getDefiningFunction(symbol).isProgram(); //see NASHORN-56
         if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) {
             // Forbid integers as local vars for now as we have no way to treat them as undefined
             newType(symbol, init.getType());
@@ -803,36 +808,28 @@
             newType(symbol, Type.OBJECT);
         }
 
-        assert varNode.hasType() : varNode;
+        assert newVarNode.hasType() : newVarNode + " has no type";
 
-        end(varNode);
-
-        return varNode;
+        return end(newVarNode);
     }
 
     @Override
     public Node leaveADD(final UnaryNode unaryNode) {
-        ensureSymbol(arithType(), unaryNode);
-        end(unaryNode);
-        return unaryNode;
+        return end(ensureSymbol(arithType(), unaryNode));
     }
 
     @Override
     public Node leaveBIT_NOT(final UnaryNode unaryNode) {
-        ensureSymbol(Type.INT, unaryNode);
-        end(unaryNode);
-        return unaryNode;
+        return end(ensureSymbol(Type.INT, unaryNode));
     }
 
     @Override
     public Node leaveDECINC(final UnaryNode unaryNode) {
         // @see assignOffset
-        ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), unaryNode.rhs());
+        final UnaryNode newUnaryNode = unaryNode.setRHS(ensureAssignmentSlots(unaryNode.rhs()));
         final Type type = arithType();
-        newType(unaryNode.rhs().getSymbol(), type);
-        ensureSymbol(type, unaryNode);
-        end(unaryNode);
-        return unaryNode;
+        newType(newUnaryNode.rhs().getSymbol(), type);
+        return end(ensureSymbol(type, newUnaryNode));
     }
 
     @Override
@@ -908,23 +905,24 @@
 
     @Override
     public Node leaveNEW(final UnaryNode unaryNode) {
-        ensureSymbol(Type.OBJECT, unaryNode);
-        end(unaryNode);
-        return unaryNode;
+        return end(ensureSymbol(Type.OBJECT, unaryNode));
     }
 
     @Override
     public Node leaveNOT(final UnaryNode unaryNode) {
-        ensureSymbol(Type.BOOLEAN, unaryNode);
-        end(unaryNode);
-        return unaryNode;
+        return end(ensureSymbol(Type.BOOLEAN, unaryNode));
     }
 
     private IdentNode compilerConstant(CompilerConstants cc) {
         final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
-        final IdentNode node = new IdentNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
-        node.setSymbol(functionNode.compilerConstant(cc));
-        return node;
+        return (IdentNode)
+            new IdentNode(
+                functionNode.getToken(),
+                functionNode.getFinish(),
+                cc.symbolName()).
+                setSymbol(
+                    getLexicalContext(),
+                    functionNode.compilerConstant(cc));
     }
 
     @Override
@@ -952,15 +950,12 @@
 
     @Override
     public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
-        ensureSymbol(runtimeNode.getRequest().getReturnType(), runtimeNode);
-        return runtimeNode;
+        return end(ensureSymbol(runtimeNode.getRequest().getReturnType(), runtimeNode));
     }
 
     @Override
     public Node leaveSUB(final UnaryNode unaryNode) {
-        ensureSymbol(arithType(), unaryNode);
-        end(unaryNode);
-        return unaryNode;
+        return end(ensureSymbol(arithType(), unaryNode));
     }
 
     @Override
@@ -982,18 +977,16 @@
 
         ensureTypeNotUnknown(lhs);
         ensureTypeNotUnknown(rhs);
-        ensureSymbol(Type.widest(lhs.getType(), rhs.getType()), binaryNode);
-
-        end(binaryNode);
-
-        return binaryNode;
+        //even if we are adding two known types, this can overflow. i.e.
+        //int and number -> number.
+        //int and int are also number though.
+        //something and object is object
+        return end(ensureSymbol(Type.widest(arithType(), Type.widest(lhs.getType(), rhs.getType())), binaryNode));
     }
 
     @Override
     public Node leaveAND(final BinaryNode binaryNode) {
-        ensureSymbol(Type.OBJECT, binaryNode);
-        end(binaryNode);
-        return binaryNode;
+        return end(ensureSymbol(Type.OBJECT, binaryNode));
     }
 
     /**
@@ -1013,8 +1006,7 @@
             Symbol symbol = findSymbol(block, name);
 
             if (symbol == null) {
-                symbol = defineSymbol(block, name, IS_GLOBAL, ident);
-                binaryNode.setSymbol(symbol);
+                symbol = defineSymbol(block, name, IS_GLOBAL);
             } else {
                 maybeForceScope(symbol);
             }
@@ -1025,6 +1017,31 @@
         return true;
     }
 
+
+    /**
+     * This assign helper is called after an assignment, when all children of
+     * the assign has been processed. It fixes the types and recursively makes
+     * sure that everyhing has slots that should have them in the chain.
+     *
+     * @param binaryNode assignment node
+     */
+    private Node leaveAssignmentNode(final BinaryNode binaryNode) {
+        BinaryNode newBinaryNode = binaryNode;
+
+        final Node lhs = binaryNode.lhs();
+        final Node rhs = binaryNode.rhs();
+        final Type type;
+
+        if (rhs.getType().isNumeric()) {
+            type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
+        } else {
+            type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too.
+        }
+
+        newType(lhs.getSymbol(), type);
+        return end(ensureSymbol(type, newBinaryNode));
+    }
+
     private boolean isLocal(FunctionNode function, Symbol symbol) {
         final FunctionNode definingFn = getLexicalContext().getDefiningFunction(symbol);
         // Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local
@@ -1173,14 +1190,12 @@
 
     @Override
     public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
-        ensureSymbol(binaryNode.rhs().getType(), binaryNode);
-        return binaryNode;
+        return end(ensureSymbol(binaryNode.rhs().getType(), binaryNode));
     }
 
     @Override
     public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
-        ensureSymbol(binaryNode.lhs().getType(), binaryNode);
-        return binaryNode;
+        return end(ensureSymbol(binaryNode.lhs().getType(), binaryNode));
     }
 
     @Override
@@ -1189,15 +1204,10 @@
     }
 
     private Node leaveCmp(final BinaryNode binaryNode) {
-        final Node lhs = binaryNode.lhs();
-        final Node rhs = binaryNode.rhs();
+        ensureTypeNotUnknown(binaryNode.lhs());
+        ensureTypeNotUnknown(binaryNode.rhs());
 
-        ensureSymbol(Type.BOOLEAN, binaryNode);
-        ensureTypeNotUnknown(lhs);
-        ensureTypeNotUnknown(rhs);
-
-        end(binaryNode);
-        return binaryNode;
+        return end(ensureSymbol(Type.BOOLEAN, binaryNode));
     }
 
     private Node coerce(final BinaryNode binaryNode, final Type operandType, final Type destType) {
@@ -1207,11 +1217,9 @@
         // as, say, an int : function(x) { return x & 4711 }, and x is not defined in
         // the function. to make this work, uncomment the following two type inferences
         // and debug.
-
         //newType(binaryNode.lhs().getSymbol(), operandType);
         //newType(binaryNode.rhs().getSymbol(), operandType);
-        ensureSymbol(destType, binaryNode);
-        return binaryNode;
+        return ensureSymbol(destType, binaryNode);
     }
 
     private Node coerce(final BinaryNode binaryNode, final Type type) {
@@ -1295,9 +1303,7 @@
 
     @Override
     public Node leaveOR(final BinaryNode binaryNode) {
-        ensureSymbol(Type.OBJECT, binaryNode);
-        end(binaryNode);
-        return binaryNode;
+        return end(ensureSymbol(Type.OBJECT, binaryNode));
     }
 
     @Override
@@ -1346,50 +1352,13 @@
         ensureTypeNotUnknown(rhs);
 
         final Type type = Type.widest(lhs.getType(), rhs.getType());
-        ensureSymbol(type, ternaryNode);
-
-        end(ternaryNode);
-        assert ternaryNode.getSymbol() != null;
-
-        return ternaryNode;
+        return end(ensureSymbol(type, ternaryNode));
     }
 
-    private void initThis(final Block block) {
-        final Symbol thisSymbol = defineSymbol(block, THIS.symbolName(), IS_PARAM | IS_THIS, null);
-        newType(thisSymbol, Type.OBJECT);
-        thisSymbol.setNeedsSlot(true);
-    }
-
-    private void initScope(final Block block) {
-        final Symbol scopeSymbol = defineSymbol(block, SCOPE.symbolName(), IS_VAR | IS_INTERNAL, null);
-        newType(scopeSymbol, Type.typeFor(ScriptObject.class));
-        scopeSymbol.setNeedsSlot(true);
-    }
-
-    private void initReturn(final Block block) {
-        final Symbol returnSymbol = defineSymbol(block, RETURN.symbolName(), IS_VAR | IS_INTERNAL, null);
-        newType(returnSymbol, Type.OBJECT);
-        returnSymbol.setNeedsSlot(true);
-        //return symbol is always object as it's the __return__ thing. What returnType is is another matter though
-    }
-
-    private void initVarArg(final Block block, final boolean needsArguments) {
-        final Symbol varArgsSymbol = defineSymbol(block, VARARGS.symbolName(), IS_PARAM | IS_INTERNAL, null);
-        varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY);
-        varArgsSymbol.setNeedsSlot(true);
-
-        if (needsArguments) {
-            final Symbol    argumentsSymbol = defineSymbol(block, ARGUMENTS.symbolName(), IS_VAR | IS_INTERNAL, null);
-            newType(argumentsSymbol, Type.typeFor(ScriptObject.class));
-            argumentsSymbol.setNeedsSlot(true);
-            addLocalDef(ARGUMENTS.symbolName());
-        }
-    }
-
-    private void initCallee(final Block block) {
-        final Symbol calleeSymbol = defineSymbol(block, CALLEE.symbolName(), IS_PARAM | IS_INTERNAL, null);
-        newType(calleeSymbol, FunctionNode.FUNCTION_TYPE);
-        calleeSymbol.setNeedsSlot(true);
+    private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags, final Type type) {
+        final Symbol symbol = defineSymbol(block, cc.symbolName(), flags);
+        newType(symbol, type);
+        symbol.setNeedsSlot(true);
     }
 
     /**
@@ -1399,19 +1368,26 @@
      * @param functionNode the function node
      */
     private void initParameters(final FunctionNode functionNode, final Block body) {
+        int pos = 0;
         for (final IdentNode param : functionNode.getParameters()) {
             addLocalDef(param.getName());
-            final Symbol paramSymbol = defineSymbol(body, param.getName(), IS_PARAM, param);
-            if (paramSymbol != null) {
-                final Type callSiteParamType = functionNode.getSpecializedType(param);
-                if (callSiteParamType != null) {
-                    LOG.info("Param ", paramSymbol, " has a callsite type ", callSiteParamType, ". Using that.");
-                }
-                newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType);
+
+            final Type callSiteParamType = functionNode.getHints().getParameterType(pos);
+            int flags = IS_PARAM;
+            if (callSiteParamType != null) {
+                LOG.info("Param ", param, " has a callsite type ", callSiteParamType, ". Using that.");
+                flags |= Symbol.IS_SPECIALIZED_PARAM;
             }
 
-            LOG.info("Initialized param ", paramSymbol);
+            final Symbol paramSymbol = defineSymbol(body, param.getName(), flags);
+            assert paramSymbol != null;
+
+            newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType);
+
+            LOG.info("Initialized param ", pos, "=", paramSymbol);
+            pos++;
         }
+
     }
 
     /**
@@ -1420,23 +1396,34 @@
      *
      * @param functionNode functionNode
      */
-    private static void finalizeParameters(final FunctionNode functionNode) {
+    private FunctionNode finalizeParameters(final FunctionNode functionNode) {
+        final List<IdentNode> newParams = new ArrayList<>();
         final boolean isVarArg = functionNode.isVarArg();
+        final int nparams = functionNode.getParameters().size();
 
-        for (final IdentNode ident : functionNode.getParameters()) {
-            final Symbol paramSymbol = ident.getSymbol();
+        int specialize = 0;
+        int pos = 0;
+        for (final IdentNode param : functionNode.getParameters()) {
+            final Symbol paramSymbol = functionNode.getBody().getExistingSymbol(param.getName());
+            assert paramSymbol != null;
+            assert paramSymbol.isParam();
+            newParams.add((IdentNode)param.setSymbol(getLexicalContext(), paramSymbol));
 
             assert paramSymbol != null;
-            Type type = functionNode.getSpecializedType(ident);
+            Type type = functionNode.getHints().getParameterType(pos);
             if (type == null) {
                 type = Type.OBJECT;
             }
 
             // if we know that a parameter is only used as a certain type throughout
             // this function, we can tell the runtime system that no matter what the
-            // call site is, use this information. TODO
-            if (!paramSymbol.getSymbolType().isObject()) {
-                LOG.finest("Parameter ", ident, " could profit from specialization to ", paramSymbol.getSymbolType());
+            // call site is, use this information:
+            // we also need more than half of the parameters to be specializable
+            // for the heuristic to be worth it, and we need more than one use of
+            // the parameter to consider it, i.e. function(x) { call(x); } doens't count
+            if (paramSymbol.getUseCount() > 1 && !paramSymbol.getSymbolType().isObject()) {
+                LOG.finest("Parameter ", param, " could profit from specialization to ", paramSymbol.getSymbolType());
+                specialize++;
             }
 
             newType(paramSymbol, Type.widest(type, paramSymbol.getSymbolType()));
@@ -1445,7 +1432,17 @@
             if (isVarArg) {
                 paramSymbol.setNeedsSlot(false);
             }
+
+            pos++;
         }
+
+        FunctionNode newFunctionNode = functionNode;
+
+        if (nparams == 0 || (specialize * 2) < nparams) {
+            newFunctionNode = newFunctionNode.clearSnapshot(getLexicalContext());
+        }
+
+        return newFunctionNode.setParameters(getLexicalContext(), newParams);
     }
 
     /**
@@ -1459,7 +1456,7 @@
 
         for (final Property property : map.getProperties()) {
             final String key    = property.getKey();
-            final Symbol symbol = defineSymbol(block, key, IS_GLOBAL, null);
+            final Symbol symbol = defineSymbol(block, key, IS_GLOBAL);
             newType(symbol, Type.OBJECT);
             LOG.info("Added global symbol from property map ", symbol);
         }
@@ -1498,7 +1495,7 @@
          * objects as parameters, for example +, but not *, which is known
          * to coerce types into doubles
          */
-        if (node.getType().isUnknown() || symbol.isParam()) {
+        if (node.getType().isUnknown() || (symbol.isParam() && !symbol.isSpecializedParam())) {
             newType(symbol, Type.OBJECT);
             symbol.setCanBeUndefined();
          }
@@ -1520,19 +1517,25 @@
      *
      * see NASHORN-258
      *
-     * @param functionNode   the current function node (has to be passed as it changes in the visitor below)
      * @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes
      */
-    private static void ensureAssignmentSlots(final FunctionNode functionNode, final Node assignmentDest) {
-        assignmentDest.accept(new NodeVisitor() {
+    private Node ensureAssignmentSlots(final Node assignmentDest) {
+        final LexicalContext attrLexicalContext = getLexicalContext();
+        return assignmentDest.accept(new NodeVisitor() {
             @Override
             public Node leaveIndexNode(final IndexNode indexNode) {
                 assert indexNode.getSymbol().isTemp();
                 final Node index = indexNode.getIndex();
                 //only temps can be set as needing slots. the others will self resolve
                 //it is illegal to take a scope var and force it to be a slot, that breaks
-                if (index.getSymbol().isTemp() && !index.getSymbol().isConstant()) {
-                     index.getSymbol().setNeedsSlot(true);
+                Symbol indexSymbol = index.getSymbol();
+                if (indexSymbol.isTemp() && !indexSymbol.isConstant() && !indexSymbol.hasSlot()) {
+                    if(indexSymbol.isShared()) {
+                        indexSymbol = temporarySymbols.createUnshared(indexSymbol);
+                    }
+                    indexSymbol.setNeedsSlot(true);
+                    attrLexicalContext.getCurrentBlock().putSymbol(attrLexicalContext, indexSymbol);
+                    return indexNode.setIndex(index.setSymbol(attrLexicalContext, indexSymbol));
                 }
                 return indexNode;
             }
@@ -1557,22 +1560,30 @@
      *
      * @param functionNode
      */
-    private static void finalizeTypes(final FunctionNode functionNode) {
+    private FunctionNode finalizeTypes(final FunctionNode functionNode) {
         final Set<Node> changed = new HashSet<>();
+        FunctionNode currentFunctionNode = functionNode;
         do {
             changed.clear();
-            functionNode.accept(new NodeVisitor() {
+            final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor() {
 
-                private void widen(final Node node, final Type to) {
+                private Node widen(final Node node, final Type to) {
                     if (node instanceof LiteralNode) {
-                        return;
+                        return node;
                     }
                     Type from = node.getType();
                     if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) {
-                        LOG.fine("Had to post pass widen '", node, "' " + Debug.id(node), " from ", node.getType(), " to ", to);
-                        newType(node.getSymbol(), to);
-                        changed.add(node);
+                        LOG.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to);
+                        Symbol symbol = node.getSymbol();
+                        if(symbol.isShared() && symbol.wouldChangeType(to)) {
+                            symbol = temporarySymbols.getTypedTemporarySymbol(to);
+                        }
+                        newType(symbol, to);
+                        final Node newNode = node.setSymbol(getLexicalContext(), symbol);
+                        changed.add(newNode);
+                        return newNode;
                     }
+                    return node;
                 }
 
                 @Override
@@ -1598,43 +1609,23 @@
                 @Override
                 public Node leaveBinaryNode(final BinaryNode binaryNode) {
                     final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
+                    BinaryNode newBinaryNode = binaryNode;
                     switch (binaryNode.tokenType()) {
                     default:
                         if (!binaryNode.isAssignment() || binaryNode.isSelfModifying()) {
                             break;
                         }
-                        widen(binaryNode.lhs(), widest);
+                        newBinaryNode = newBinaryNode.setLHS(widen(newBinaryNode.lhs(), widest));
                     case ADD:
-                        widen(binaryNode, widest);
-                        break;
+                        newBinaryNode = (BinaryNode)widen(newBinaryNode, widest);
                     }
-                    return binaryNode;
+                    return newBinaryNode;
                 }
             });
+            getLexicalContext().replace(currentFunctionNode, newFunctionNode);
+            currentFunctionNode = newFunctionNode;
         } while (!changed.isEmpty());
-    }
-
-    /**
-     * This assign helper is called after an assignment, when all children of
-     * the assign has been processed. It fixes the types and recursively makes
-     * sure that everyhing has slots that should have them in the chain.
-     *
-     * @param binaryNode assignment node
-     */
-    private Node leaveAssignmentNode(final BinaryNode binaryNode) {
-        final Node lhs = binaryNode.lhs();
-        final Node rhs = binaryNode.rhs();
-
-        final Type type;
-        if (rhs.getType().isNumeric()) {
-            type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
-        } else {
-            type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too.
-        }
-        ensureSymbol(type, binaryNode);
-        newType(lhs.getSymbol(), type);
-        end(binaryNode);
-        return binaryNode;
+        return currentFunctionNode;
     }
 
     private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode) {
@@ -1646,25 +1637,18 @@
         final Node lhs = binaryNode.lhs();
 
         newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType
-        ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
+//        ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
 
-        ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), binaryNode);
-
-        end(binaryNode);
-        return binaryNode;
+        return end(ensureSymbol(destType, ensureAssignmentSlots(binaryNode)));
     }
 
-    private Symbol ensureSymbol(final FunctionNode functionNode, final Type type, final Node node) {
-        LOG.info("New TEMPORARY added to ", functionNode.getName(), " type=", type);
-        return functionNode.ensureSymbol(getLexicalContext().getCurrentBlock(), type, node);
-    }
-
-    private Symbol ensureSymbol(final Type type, final Node node) {
-        return ensureSymbol(getLexicalContext().getCurrentFunction(), type, node);
+    private Node ensureSymbol(final Type type, final Node node) {
+        LOG.info("New TEMPORARY added to ", getLexicalContext().getCurrentFunction().getName(), " type=", type);
+        return ensureSymbol(getLexicalContext(), type, node);
     }
 
     private Symbol newInternal(final String name, final Type type) {
-        final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL, null);
+        final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL);
         iter.setType(type); // NASHORN-73
         return iter;
     }
@@ -1721,6 +1705,10 @@
         localUses.peek().add(name);
     }
 
+    private Node ensureSymbol(final LexicalContext lc, final Type type, final Node node) {
+        return temporarySymbols.ensureSymbol(lc, type, node);
+    }
+
     /**
      * Pessimistically promote all symbols in current function node to Object types
      * This is done when the function contains unevaluated black boxes such as
@@ -1731,8 +1719,7 @@
     private static void objectifySymbols(final Block body) {
         body.accept(new NodeVisitor() {
             private void toObject(final Block block) {
-                for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext();) {
-                    final Symbol symbol = iter.next();
+                for (final Symbol symbol : block.getSymbols()) {
                     if (!symbol.isTemp()) {
                         newType(symbol, Type.OBJECT);
                     }
@@ -1788,6 +1775,10 @@
     }
 
     private Node end(final Node node, final boolean printNode) {
+        if(node instanceof Statement) {
+            // If we're done with a statement, all temporaries can be reused.
+            temporarySymbols.reuse();
+        }
         if (DEBUG) {
             final StringBuilder sb = new StringBuilder();
 
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue May 14 11:16:52 2013 -0300
@@ -63,6 +63,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
+
 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode;
@@ -88,7 +89,6 @@
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LexicalContextNode;
-import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
@@ -100,6 +100,7 @@
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
 import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.TernaryNode;
@@ -191,6 +192,8 @@
     /** Current compile unit */
     private CompileUnit unit;
 
+    private int lastLineNumber = -1;
+
     /** When should we stop caching regexp expressions in fields to limit bytecode size? */
     private static final int MAX_REGEX_FIELDS = 2 * 1024;
 
@@ -261,14 +264,15 @@
             return method.load(symbol);
         }
 
-        final String name = symbol.getName();
+        final String name   = symbol.getName();
+        final Source source = getLexicalContext().getCurrentFunction().getSource();
 
         if (CompilerConstants.__FILE__.name().equals(name)) {
-            return method.load(identNode.getSource().getName());
+            return method.load(source.getName());
         } else if (CompilerConstants.__DIR__.name().equals(name)) {
-            return method.load(identNode.getSource().getBase());
+            return method.load(source.getBase());
         } else if (CompilerConstants.__LINE__.name().equals(name)) {
-            return method.load(identNode.getSource().getLine(identNode.position())).convert(Type.OBJECT);
+            return method.load(source.getLine(identNode.position())).convert(Type.OBJECT);
         } else {
             assert identNode.getSymbol().isScope() : identNode + " is not in scope!";
 
@@ -568,8 +572,7 @@
      * @param block block containing symbols.
      */
     private void symbolInfo(final Block block) {
-        for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
-            final Symbol symbol = iter.next();
+        for (final Symbol symbol : block.getSymbols()) {
             if (symbol.hasSlot()) {
                 method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel());
             }
@@ -619,6 +622,8 @@
 
     @Override
     public boolean enterBreakNode(final BreakNode breakNode) {
+        lineNumber(breakNode);
+
         final BreakableNode breakFrom = getLexicalContext().getBreakable(breakNode.getLabel());
         for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(breakFrom); i++) {
             closeWith();
@@ -663,6 +668,8 @@
 
     @Override
     public boolean enterCallNode(final CallNode callNode) {
+        lineNumber(callNode);
+
         final List<Node>   args            = callNode.getArgs();
         final Node         function        = callNode.getFunction();
         final Block        currentBlock    = getLexicalContext().getCurrentBlock();
@@ -836,6 +843,8 @@
 
     @Override
     public boolean enterContinueNode(final ContinueNode continueNode) {
+        lineNumber(continueNode);
+
         final LoopNode continueTo = getLexicalContext().getContinueTo(continueNode.getLabel());
         for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(continueTo); i++) {
             closeWith();
@@ -847,11 +856,15 @@
 
     @Override
     public boolean enterEmptyNode(final EmptyNode emptyNode) {
+        lineNumber(emptyNode);
+
         return false;
     }
 
     @Override
     public boolean enterExecuteNode(final ExecuteNode executeNode) {
+        lineNumber(executeNode);
+
         final Node expression = executeNode.getExpression();
         expression.accept(this);
 
@@ -860,6 +873,8 @@
 
     @Override
     public boolean enterForNode(final ForNode forNode) {
+        lineNumber(forNode);
+
         final Node  test   = forNode.getTest();
         final Block body   = forNode.getBody();
         final Node  modify = forNode.getModify();
@@ -937,11 +952,10 @@
 
     private static int assignSlots(final Block block, final int firstSlot) {
         int nextSlot = firstSlot;
-        for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
-            final Symbol next = iter.next();
-            if (next.hasSlot()) {
-                next.setSlot(nextSlot);
-                nextSlot += next.slotCount();
+        for (final Symbol symbol : block.getSymbols()) {
+            if (symbol.hasSlot()) {
+                symbol.setSlot(nextSlot);
+                nextSlot += symbol.slotCount();
             }
         }
         return nextSlot;
@@ -1002,10 +1016,7 @@
 
             final boolean hasArguments = function.needsArguments();
 
-            final Iterator<Symbol> symbols = block.symbolIterator();
-
-            while (symbols.hasNext()) {
-                final Symbol symbol = symbols.next();
+            for (final Symbol symbol : block.getSymbols()) {
 
                 if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) {
                     continue;
@@ -1076,12 +1087,7 @@
                 }
             }
 
-            final Iterator<Symbol> iter = block.symbolIterator();
-            final List<Symbol> symbols = new ArrayList<>();
-            while (iter.hasNext()) {
-                symbols.add(iter.next());
-            }
-            initSymbols(symbols);
+            initSymbols(block.getSymbols());
         }
 
         // Debugging: print symbols? @see --print-symbols flag
@@ -1157,6 +1163,8 @@
 
     @Override
     public boolean enterIfNode(final IfNode ifNode) {
+        lineNumber(ifNode);
+
         final Node  test = ifNode.getTest();
         final Block pass = ifNode.getPass();
         final Block fail = ifNode.getFail();
@@ -1196,12 +1204,12 @@
         return false;
     }
 
-    @Override
-    public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
-        final Label label = new Label((String)null);
-        method.label(label);
-        method.lineNumber(lineNumberNode.getLineNumber(), label);
-        return false;
+    private void lineNumber(final Statement statement) {
+        final int lineNumber = statement.getLineNumber();
+        if (lineNumber != lastLineNumber) {
+            method.lineNumber(statement.getLineNumber());
+        }
+        lastLineNumber = lineNumber;
     }
 
     /**
@@ -1533,6 +1541,8 @@
 
     @Override
     public boolean enterReturnNode(final ReturnNode returnNode) {
+        lineNumber(returnNode);
+
         method.registerReturn();
 
         final Type returnType = getLexicalContext().getCurrentFunction().getReturnType();
@@ -1742,6 +1752,8 @@
 
     @Override
     public boolean enterSplitNode(final SplitNode splitNode) {
+        lineNumber(splitNode);
+
         final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
 
         final FunctionNode fn   = getLexicalContext().getCurrentFunction();
@@ -1885,6 +1897,8 @@
 
     @Override
     public boolean enterSwitchNode(final SwitchNode switchNode) {
+        lineNumber(switchNode);
+
         final Node           expression  = switchNode.getExpression();
         final Symbol         tag         = switchNode.getTag();
         final boolean        allInteger  = tag.getSymbolType().isInteger();
@@ -1967,7 +1981,6 @@
                 method.tableswitch(lo, hi, defaultLabel, table);
             } else {
                 final int[] ints = new int[size];
-
                 for (int i = 0; i < size; i++) {
                     ints[i] = values[i];
                 }
@@ -2013,10 +2026,13 @@
 
     @Override
     public boolean enterThrowNode(final ThrowNode throwNode) {
+        lineNumber(throwNode);
+
         method._new(ECMAException.class).dup();
 
+        final Source source     = getLexicalContext().getCurrentFunction().getSource();
+
         final Node   expression = throwNode.getExpression();
-        final Source source     = throwNode.getSource();
         final int    position   = throwNode.position();
         final int    line       = source.getLine(position);
         final int    column     = source.getColumn(position);
@@ -2036,6 +2052,8 @@
 
     @Override
     public boolean enterTryNode(final TryNode tryNode) {
+        lineNumber(tryNode);
+
         final Block       body        = tryNode.getBody();
         final List<Block> catchBlocks = tryNode.getCatchBlocks();
         final Symbol      symbol      = tryNode.getException();
@@ -2132,12 +2150,15 @@
 
     @Override
     public boolean enterVarNode(final VarNode varNode) {
+
         final Node init = varNode.getInit();
 
         if (init == null) {
             return false;
         }
 
+        lineNumber(varNode);
+
         final Symbol varSymbol = varNode.getSymbol();
         assert varSymbol != null : "variable node " + varNode + " requires a symbol";
 
@@ -2170,6 +2191,8 @@
 
     @Override
     public boolean enterWhileNode(final WhileNode whileNode) {
+        lineNumber(whileNode);
+
         final Node  test          = whileNode.getTest();
         final Block body          = whileNode.getBody();
         final Label breakLabel    = whileNode.getBreakLabel();
@@ -2192,7 +2215,7 @@
     }
 
     private void closeWith() {
-        if(method.hasScope()) {
+        if (method.hasScope()) {
             method.loadCompilerConstant(SCOPE);
             method.invoke(ScriptRuntime.CLOSE_WITH);
             method.storeCompilerConstant(SCOPE);
@@ -2235,7 +2258,7 @@
         // Always process body
         body.accept(this);
 
-        if(hasScope) {
+        if (hasScope) {
             // Ensure we always close the WithObject
             final Label endLabel   = new Label("with_end");
             final Label catchLabel = new Label("with_catch");
@@ -2364,7 +2387,6 @@
     public boolean enterDISCARD(final UnaryNode unaryNode) {
         final Node rhs = unaryNode.rhs();
 
-       // System.err.println("**** Enter discard " + unaryNode);
         discard.push(rhs);
         load(rhs);
 
@@ -2373,7 +2395,7 @@
             method.pop();
             discard.pop();
         }
-       // System.err.println("**** Leave discard " + unaryNode);
+
         return false;
     }
 
@@ -3019,12 +3041,12 @@
      * @param block the block we are in
      * @param ident identifier for block or function where applicable
      */
+    @SuppressWarnings("resource")
     private void printSymbols(final Block block, final String ident) {
         if (!compiler.getEnv()._print_symbols) {
             return;
         }
 
-        @SuppressWarnings("resource")
         final PrintWriter out = compiler.getEnv().getErr();
         out.println("[BLOCK in '" + ident + "']");
         if (!block.printSymbols(out)) {
@@ -3200,9 +3222,6 @@
                 return;
             }
 
-            //System.err.println("Store with out discard that shouldn't just return " + assignNode);
-            //new Throwable().printStackTrace();
-
             final Symbol symbol = assignNode.getSymbol();
             if (symbol.hasSlot()) {
                 method.dup().store(symbol);
@@ -3298,7 +3317,7 @@
         //    Such immediately-called functions are invoked using INVOKESTATIC (see enterFunctionNode() of the embedded
         //    visitor of enterCallNode() for details), and if they don't need a callee, they don't have it on their
         //    static method's parameter list.
-        if(lc.getOutermostFunction() == functionNode ||
+        if (lc.getOutermostFunction() == functionNode ||
                 (!functionNode.needsCallee()) && lc.isFunctionDefinedInCurrentCall(originalFunctionNode)) {
             return;
         }
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Tue May 14 11:16:52 2013 -0300
@@ -21,6 +21,7 @@
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.TemporarySymbols;
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.debug.PrintVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
@@ -42,7 +43,7 @@
      */
     LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) {
         @Override
-        FunctionNode transform(final Compiler compiler, final FunctionNode fn0) {
+        FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
 
             /*
              * For lazy compilation, we might be given a node previously marked
@@ -58,8 +59,7 @@
              * function from a trampoline
              */
 
-            final FunctionNode outermostFunctionNode = compiler.getFunctionNode();
-            assert outermostFunctionNode == fn0;
+            final FunctionNode outermostFunctionNode = fn;
 
             final Set<FunctionNode> neverLazy = new HashSet<>();
             final Set<FunctionNode> lazy      = new HashSet<>();
@@ -172,20 +172,31 @@
     ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) {
         @Override
         FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
-            return (FunctionNode)initReturnTypes(fn).accept(new Attr());
+            final TemporarySymbols ts = compiler.getTemporarySymbols();
+            final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(ts));
+            if(compiler.getEnv()._print_mem_usage) {
+                Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount());
+            }
+            return newFunctionNode;
         }
 
         /**
          * Pessimistically set all lazy functions' return types to Object
+         * and the function symbols to object
          * @param functionNode node where to start iterating
          */
-        private FunctionNode initReturnTypes(final FunctionNode functionNode) {
+        private FunctionNode enterAttr(final FunctionNode functionNode, final TemporarySymbols ts) {
             return (FunctionNode)functionNode.accept(new NodeVisitor() {
                 @Override
                 public Node leaveFunctionNode(final FunctionNode node) {
-                    return node.isLazy() ?
-                           node.setReturnType(getLexicalContext(), Type.OBJECT) :
-                           node.setReturnType(getLexicalContext(), Type.UNKNOWN);
+                    final LexicalContext lc = getLexicalContext();
+                    if (node.isLazy()) {
+                        FunctionNode newNode = node.setReturnType(getLexicalContext(), Type.OBJECT);
+                        return ts.ensureSymbol(lc, Type.OBJECT, newNode);
+                    }
+                    //node may have a reference here that needs to be nulled if it was referred to by
+                    //its outer context, if it is lazy and not attributed
+                    return node.setReturnType(lc, Type.UNKNOWN).setSymbol(lc, null);
                 }
             });
         }
@@ -207,6 +218,7 @@
         FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
             final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName());
 
+//            assert fn.isProgram() ;
             final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn);
 
             assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
@@ -216,15 +228,6 @@
                 compiler.setStrictMode(true);
             }
 
-            /*
-            newFunctionNode.accept(new NodeVisitor() {
-                @Override
-                public boolean enterFunctionNode(final FunctionNode functionNode) {
-                    assert functionNode.getCompileUnit() != null : functionNode.getName() + " " + Debug.id(functionNode) + " has no compile unit";
-                    return true;
-                }
-            });*/
-
             return newFunctionNode;
         }
 
@@ -252,7 +255,7 @@
         FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
             final ScriptEnvironment env = compiler.getEnv();
 
-            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes());
+            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes(compiler.getTemporarySymbols()));
 
             if (env._print_lower_ast) {
                 env.getErr().println(new ASTWriter(newFunctionNode));
--- a/src/jdk/nashorn/internal/codegen/Compiler.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Tue May 14 11:16:52 2013 -0300
@@ -36,26 +36,32 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
 
+import jdk.nashorn.internal.ir.TemporarySymbols;
+
 import java.io.File;
 import java.lang.reflect.Field;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.logging.Level;
-
 import jdk.internal.dynalink.support.NameCodec;
 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
+import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
 import jdk.nashorn.internal.runtime.CodeInstaller;
 import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
@@ -77,6 +83,8 @@
     /** Name of the objects package */
     public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects";
 
+    private Source source;
+
     private final Map<String, byte[]> bytecode;
 
     private final Set<CompileUnit> compileUnits;
@@ -87,13 +95,13 @@
 
     private final ScriptEnvironment env;
 
-    private final String scriptName;
+    private String scriptName;
 
     private boolean strict;
 
-    private FunctionNode functionNode;
+    private CodeInstaller<ScriptEnvironment> installer;
 
-    private CodeInstaller<ScriptEnvironment> installer;
+    private final TemporarySymbols temporarySymbols = new TemporarySymbols();
 
     /** logger for compiler, trampolines, splits and related code generation events
      *  that affect classes */
@@ -168,6 +176,41 @@
     }
 
     /**
+     * Environment information known to the compile, e.g. params
+     */
+    public static class Hints {
+        private final Type[] paramTypes;
+
+        /** singleton empty hints */
+        public static final Hints EMPTY = new Hints();
+
+        private Hints() {
+            this.paramTypes = null;
+        }
+
+        /**
+         * Constructor
+         * @param paramTypes known parameter types for this callsite
+         */
+        public Hints(final Type[] paramTypes) {
+            this.paramTypes = paramTypes;
+        }
+
+        /**
+         * Get the parameter type for this parameter position, or
+         * null if now known
+         * @param pos position
+         * @return parameter type for this callsite if known
+         */
+        public Type getParameterType(final int pos) {
+            if (paramTypes != null && pos < paramTypes.length) {
+                return paramTypes[pos];
+            }
+            return null;
+        }
+    }
+
+    /**
      * Standard (non-lazy) compilation, that basically will take an entire script
      * and JIT it at once. This can lead to long startup time and fewer type
      * specializations
@@ -207,21 +250,22 @@
      * @param strict       should this compilation use strict mode semantics
      */
     //TODO support an array of FunctionNodes for batch lazy compilation
-    Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final CompilationSequence sequence, final boolean strict) {
+    Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final CompilationSequence sequence, final boolean strict) {
         this.env           = env;
-        this.functionNode  = functionNode;
         this.sequence      = sequence;
         this.installer     = installer;
-        this.strict        = strict || functionNode.isStrict();
         this.constantData  = new ConstantData();
         this.compileUnits  = new HashSet<>();
         this.bytecode      = new HashMap<>();
+    }
 
+    private void initCompiler(final FunctionNode functionNode) {
+        this.strict        = strict || functionNode.isStrict();
         final StringBuilder sb = new StringBuilder();
         sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.symbolName() + lazyTag(functionNode))).
                 append('$').
                 append(safeSourceName(functionNode.getSource()));
-
+        this.source = functionNode.getSource();
         this.scriptName = sb.toString();
     }
 
@@ -229,52 +273,79 @@
      * Constructor
      *
      * @param installer    code installer
-     * @param functionNode function node (in any available {@link CompilationState}) to compile
      * @param strict       should this compilation use strict mode semantics
      */
-    public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final boolean strict) {
-        this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), strict);
+    public Compiler(final CodeInstaller<ScriptEnvironment> installer, final boolean strict) {
+        this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), strict);
     }
 
     /**
      * Constructor - compilation will use the same strict semantics as in script environment
      *
      * @param installer    code installer
-     * @param functionNode function node (in any available {@link CompilationState}) to compile
      */
-    public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode) {
-        this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict);
+    public Compiler(final CodeInstaller<ScriptEnvironment> installer) {
+        this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict);
     }
 
     /**
      * Constructor - compilation needs no installer, but uses a script environment
      * Used in "compile only" scenarios
      * @param env a script environment
-     * @param functionNode functionNode to compile
      */
-    public Compiler(final ScriptEnvironment env, final FunctionNode functionNode) {
-        this(env, null, functionNode, sequence(env._lazy_compilation), env._strict);
+    public Compiler(final ScriptEnvironment env) {
+        this(env, null, sequence(env._lazy_compilation), env._strict);
+    }
+
+    private static void printMemoryUsage(final String phaseName, final FunctionNode functionNode) {
+        LOG.info(phaseName + " finished. Doing IR size calculation...");
+
+        final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification());
+        osc.calculateObjectSize(functionNode);
+
+        final List<ClassHistogramElement> list = osc.getClassHistogram();
+
+        final StringBuilder sb = new StringBuilder();
+        final long totalSize = osc.calculateObjectSize(functionNode);
+        sb.append(phaseName).append(" Total size = ").append(totalSize / 1024 / 1024).append("MB");
+        LOG.info(sb);
+
+        Collections.sort(list, new Comparator<ClassHistogramElement>() {
+            @Override
+            public int compare(ClassHistogramElement o1, ClassHistogramElement o2) {
+                final long diff = o1.getBytes() - o2.getBytes();
+                if (diff < 0) {
+                    return 1;
+                } else if (diff > 0) {
+                    return -1;
+                } else {
+                    return 0;
+                }
+            }
+        });
+        for (final ClassHistogramElement e : list) {
+            final String line = String.format("    %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances());
+            LOG.info(line);
+            if (e.getBytes() < totalSize / 200) {
+                LOG.info("    ...");
+                break; // never mind, so little memory anyway
+            }
+        }
     }
 
     /**
      * Execute the compilation this Compiler was created with
-     * @params param types if known, for specialization
+     * @param functionNode function node to compile from its current state
      * @throws CompilationException if something goes wrong
      * @return function node that results from code transforms
      */
-    public FunctionNode compile() throws CompilationException {
-        return compile(null);
-    }
+    public FunctionNode compile(final FunctionNode functionNode) throws CompilationException {
+        FunctionNode newFunctionNode = functionNode;
 
-    /**
-     * Execute the compilation this Compiler was created with
-     * @param paramTypes param types if known, for specialization
-     * @throws CompilationException if something goes wrong
-     * @return function node that results from code transforms
-     */
-    public FunctionNode compile(final Class<?> paramTypes) throws CompilationException {
+        initCompiler(newFunctionNode); //TODO move this state into functionnode?
+
         for (final String reservedName : RESERVED_NAMES) {
-            functionNode.uniqueName(reservedName);
+            newFunctionNode.uniqueName(reservedName);
         }
 
         final boolean fine = !LOG.levelAbove(Level.FINE);
@@ -283,7 +354,11 @@
         long time = 0L;
 
         for (final CompilationPhase phase : sequence) {
-            this.functionNode = phase.apply(this, functionNode);
+            newFunctionNode = phase.apply(this, newFunctionNode);
+
+            if (env._print_mem_usage) {
+                printMemoryUsage(phase.toString(), newFunctionNode);
+            }
 
             final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L;
             time += duration;
@@ -293,7 +368,7 @@
 
                 sb.append(phase.toString()).
                     append(" done for function '").
-                    append(functionNode.getName()).
+                    append(newFunctionNode.getName()).
                     append('\'');
 
                 if (duration > 0L) {
@@ -309,7 +384,7 @@
         if (info) {
             final StringBuilder sb = new StringBuilder();
             sb.append("Compile job for '").
-                append(functionNode.getName()).
+                append(newFunctionNode.getName()).
                 append("' finished");
 
             if (time > 0L) {
@@ -321,7 +396,7 @@
             LOG.info(sb);
         }
 
-        return functionNode;
+        return newFunctionNode;
     }
 
     private Class<?> install(final String className, final byte[] code) {
@@ -330,7 +405,6 @@
         final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
 
         try {
-            final Source   source    = getSource();
             final Object[] constants = getConstantData().toArray();
             // Need doPrivileged because these fields are private
             AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@@ -355,9 +429,10 @@
 
     /**
      * Install compiled classes into a given loader
+     * @param functionNode function node to install - must be in {@link CompilationState#EMITTED} state
      * @return root script class - if there are several compile units they will also be installed
      */
-    public Class<?> install() {
+    public Class<?> install(final FunctionNode functionNode) {
         final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L;
 
         assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed";
@@ -430,10 +505,6 @@
         this.strict = strict;
     }
 
-    FunctionNode getFunctionNode() {
-        return functionNode;
-    }
-
     ConstantData getConstantData() {
         return constantData;
     }
@@ -442,8 +513,8 @@
         return installer;
     }
 
-    Source getSource() {
-        return functionNode.getSource();
+    TemporarySymbols getTemporarySymbols() {
+        return temporarySymbols;
     }
 
     void addClass(final String name, final byte[] code) {
@@ -496,7 +567,7 @@
     }
 
     private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) {
-        final ClassEmitter classEmitter = new ClassEmitter(env, functionNode.getSource().getName(), unitClassName, strict);
+        final ClassEmitter classEmitter = new ClassEmitter(env, source.getName(), unitClassName, strict);
         final CompileUnit  compileUnit  = new CompileUnit(unitClassName, classEmitter, initialWeight);
 
         classEmitter.begin();
@@ -550,6 +621,4 @@
         USE_INT_ARITH  =  Options.getBooleanProperty("nashorn.compiler.intarithmetic");
         assert !USE_INT_ARITH : "Integer arithmetic is not enabled";
     }
-
-
 }
--- a/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Tue May 14 11:16:52 2013 -0300
@@ -105,25 +105,25 @@
     ARGUMENTS("arguments", Object.class, 2),
 
     /** prefix for iterators for for (x in ...) */
-    ITERATOR_PREFIX(":iter"),
+    ITERATOR_PREFIX(":i"),
 
     /** prefix for tag variable used for switch evaluation */
-    SWITCH_TAG_PREFIX(":tag"),
+    SWITCH_TAG_PREFIX(":s"),
 
     /** prefix for all exceptions */
-    EXCEPTION_PREFIX(":exception"),
+    EXCEPTION_PREFIX(":e"),
 
     /** prefix for quick slots generated in Store */
-    QUICK_PREFIX(":quick"),
+    QUICK_PREFIX(":q"),
 
     /** prefix for temporary variables */
-    TEMP_PREFIX(":temp"),
+    TEMP_PREFIX(":t"),
 
     /** prefix for literals */
-    LITERAL_PREFIX(":lit"),
+    LITERAL_PREFIX(":l"),
 
     /** prefix for regexps */
-    REGEX_PREFIX(":regex"),
+    REGEX_PREFIX(":r"),
 
     /** "this" used in non-static Java methods; always in slot 0 */
     JAVA_THIS(null, 0),
--- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Tue May 14 11:16:52 2013 -0300
@@ -30,7 +30,6 @@
 
 import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.AccessNode;
@@ -56,6 +55,7 @@
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.ir.TemporarySymbols;
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.ThrowNode;
 import jdk.nashorn.internal.ir.TypeOverride;
@@ -88,7 +88,10 @@
 
     private static final DebugLogger LOG = new DebugLogger("finalize");
 
-    FinalizeTypes() {
+    private final TemporarySymbols temporarySymbols;
+
+    FinalizeTypes(final TemporarySymbols temporarySymbols) {
+        this.temporarySymbols = temporarySymbols;
     }
 
     @Override
@@ -228,21 +231,27 @@
         return leaveASSIGN(binaryNode);
     }
 
+    private boolean symbolIsInteger(Node node) {
+        final Symbol symbol = node.getSymbol();
+        assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + getLexicalContext().getCurrentFunction().getSource();
+        return true;
+    }
+
     @Override
-    public Node leaveBIT_AND(BinaryNode binaryNode) {
-        assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
+    public Node leaveBIT_AND(final BinaryNode binaryNode) {
+        assert symbolIsInteger(binaryNode);
         return leaveBinary(binaryNode, Type.INT, Type.INT);
     }
 
     @Override
-    public Node leaveBIT_OR(BinaryNode binaryNode) {
-        assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
+    public Node leaveBIT_OR(final BinaryNode binaryNode) {
+        assert symbolIsInteger(binaryNode);
         return leaveBinary(binaryNode, Type.INT, Type.INT);
     }
 
     @Override
-    public Node leaveBIT_XOR(BinaryNode binaryNode) {
-        assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
+    public Node leaveBIT_XOR(final BinaryNode binaryNode) {
+        assert symbolIsInteger(binaryNode);
         return leaveBinary(binaryNode, Type.INT, Type.INT);
     }
 
@@ -252,8 +261,7 @@
         final BinaryNode newBinaryNode = binaryNode.setRHS(discard(binaryNode.rhs()));
         // AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed
         // in that case, update the node type as well
-        propagateType(newBinaryNode, newBinaryNode.lhs().getType());
-        return newBinaryNode;
+        return propagateType(newBinaryNode, newBinaryNode.lhs().getType());
     }
 
     @Override
@@ -262,8 +270,7 @@
         final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs()));
         // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed
         // in that case, update the node type as well
-        propagateType(newBinaryNode, newBinaryNode.rhs().getType());
-        return newBinaryNode;
+        return propagateType(newBinaryNode, newBinaryNode.rhs().getType());
     }
 
     @Override
@@ -354,13 +361,6 @@
         return true;
     }
 
-    /*
-    @Override
-    public Node leaveBlock(final Block block) {
-        final LexicalContext lc = getLexicalContext();
-        return block;//.setFlag(lc, lc.getFlags(block));
-    }*/
-
     @Override
     public Node leaveCatchNode(final CatchNode catchNode) {
         final Node exceptionCondition = catchNode.getExceptionCondition();
@@ -372,6 +372,7 @@
 
     @Override
     public Node leaveExecuteNode(final ExecuteNode executeNode) {
+        temporarySymbols.reuse();
         return executeNode.setExpression(discard(executeNode.getExpression()));
     }
 
@@ -497,8 +498,8 @@
 
     @Override
     public Node leaveVarNode(final VarNode varNode) {
-        final Node rhs = varNode.getInit();
-        if (rhs != null) {
+        final Node init = varNode.getInit();
+        if (init != null) {
             final SpecializedNode specialized = specialize(varNode);
             final VarNode specVarNode = (VarNode)specialized.node;
             Type destType = specialized.type;
@@ -506,8 +507,11 @@
                 destType = specVarNode.getType();
             }
             assert specVarNode.hasType() : specVarNode + " doesn't have a type";
-            return specVarNode.setInit(convert(rhs, destType));
+            final Node convertedInit = convert(init, destType);
+            temporarySymbols.reuse();
+            return specVarNode.setInit(convertedInit);
         }
+        temporarySymbols.reuse();
         return varNode;
     }
 
@@ -551,8 +555,7 @@
         final boolean        allVarsInScope = functionNode.allVarsInScope();
         final boolean        isVarArg       = functionNode.isVarArg();
 
-        for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
-            final Symbol symbol = iter.next();
+        for (final Symbol symbol : block.getSymbols()) {
             if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) {
                 continue;
             }
@@ -687,7 +690,7 @@
         }
     }
 
-    private static <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) {
+    <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) {
         final Node node = ((Node)assignment);
         final T lhs = assignment.getAssignmentDest();
         final Node rhs = assignment.getAssignmentSource();
@@ -709,9 +712,9 @@
         }
 
         final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to));
-        propagateType(newNode, to);
+        final Node typePropagatedNode = propagateType(newNode, to);
 
-        return new SpecializedNode(newNode, to);
+        return new SpecializedNode(typePropagatedNode, to);
     }
 
 
@@ -750,7 +753,7 @@
      * @param to      new type
      */
     @SuppressWarnings("unchecked")
-    private static <T extends Node> T setTypeOverride(final T node, final Type to) {
+    <T extends Node> T setTypeOverride(final T node, final Type to) {
         final Type from = node.getType();
         if (!node.getType().equals(to)) {
             LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", to);
@@ -759,7 +762,7 @@
             }
         }
         LOG.info("Type override for lhs in '", node, "' => ", to);
-        return ((TypeOverride<T>)node).setType(to);
+        return ((TypeOverride<T>)node).setType(temporarySymbols, getLexicalContext(), to);
     }
 
     /**
@@ -782,7 +785,7 @@
     private Node convert(final Node node, final Type to) {
         assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass();
         assert node != null : "node is null";
-        assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + getLexicalContext().getCurrentFunction() + " " + node.getSource();
+        assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + getLexicalContext().getCurrentFunction();
         assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getLexicalContext().getCurrentFunction();
 
         final Type from = node.getType();
@@ -807,24 +810,22 @@
                 assert node instanceof TypeOverride;
                 return setTypeOverride(node, to);
             }
-            resultNode = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.CONVERT), node);
+            resultNode = new UnaryNode(Token.recast(node.getToken(), TokenType.CONVERT), node);
         }
 
         LOG.info("CONVERT('", node, "', ", to, ") => '", resultNode, "'");
 
+        assert !node.isTerminal();
+
         final LexicalContext lc = getLexicalContext();
         //This is the only place in this file that can create new temporaries
         //FinalizeTypes may not introduce ANY node that is not a conversion.
-        lc.getCurrentFunction().ensureSymbol(lc.getCurrentBlock(), to, resultNode);
-
-        assert !node.isTerminal();
-
-        return resultNode;
+        return temporarySymbols.ensureSymbol(lc, to, resultNode);
     }
 
     private static Node discard(final Node node) {
         if (node.getSymbol() != null) {
-            final Node discard = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.DISCARD), node);
+            final Node discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node);
             //discard never has a symbol in the discard node - then it would be a nop
             assert !node.isTerminal();
             return discard;
@@ -847,12 +848,13 @@
      * @param node
      * @param to
      */
-    private static void propagateType(final Node node, final Type to) {
-        final Symbol symbol = node.getSymbol();
-        if (symbol.isTemp()) {
-            symbol.setTypeOverride(to);
+    private Node propagateType(final Node node, final Type to) {
+        Symbol symbol = node.getSymbol();
+        if (symbol.isTemp() && symbol.getSymbolType() != to) {
+            symbol = symbol.setTypeOverrideShared(to, temporarySymbols);
             LOG.info("Type override for temporary in '", node, "' => ", to);
         }
+        return node.setSymbol(getLexicalContext(), symbol);
     }
 
     /**
@@ -877,7 +879,7 @@
      * Whenever an explicit conversion is needed and the convertee is a literal, we can
      * just change the literal
      */
-    static class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> {
+    class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> {
         private final Type type;
 
         LiteralNodeConstantEvaluator(final LiteralNode<?> parent, final Type type) {
@@ -892,20 +894,20 @@
             LiteralNode<?> literalNode = null;
 
             if (type.isString()) {
-                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toString(value));
+                literalNode = LiteralNode.newInstance(token, finish, JSType.toString(value));
             } else if (type.isBoolean()) {
-                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toBoolean(value));
+                literalNode = LiteralNode.newInstance(token, finish, JSType.toBoolean(value));
             } else if (type.isInteger()) {
-                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toInt32(value));
+                literalNode = LiteralNode.newInstance(token, finish, JSType.toInt32(value));
             } else if (type.isLong()) {
-                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toLong(value));
+                literalNode = LiteralNode.newInstance(token, finish, JSType.toLong(value));
             } else if (type.isNumber() || parent.getType().isNumeric() && !parent.getType().isNumber()) {
-                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toNumber(value));
+                literalNode = LiteralNode.newInstance(token, finish, JSType.toNumber(value));
             }
 
             if (literalNode != null) {
                 //inherit literal symbol for attr.
-                literalNode.setSymbol(parent.getSymbol());
+                literalNode = (LiteralNode<?>)literalNode.setSymbol(getLexicalContext(), parent.getSymbol());
             }
 
             return literalNode;
--- a/src/jdk/nashorn/internal/codegen/FoldConstants.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java	Tue May 14 11:16:52 2013 -0300
@@ -41,7 +41,6 @@
 import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * Simple constant folding pass, executed before IR is starting to be lowered.
@@ -89,7 +88,7 @@
         if (test instanceof LiteralNode) {
             final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
             if (shortCut != null) {
-                return new ExecuteNode(shortCut);
+                return new ExecuteNode(shortCut.getLineNumber(), shortCut.getToken(), shortCut.getFinish(), shortCut);
             }
             return new EmptyNode(ifNode);
         }
@@ -112,13 +111,11 @@
      */
     abstract static class ConstantEvaluator<T extends Node> {
         protected T            parent;
-        protected final Source source;
         protected final long   token;
         protected final int    finish;
 
         protected ConstantEvaluator(final T parent) {
             this.parent = parent;
-            this.source = parent.getSource();
             this.token  = parent.getToken();
             this.finish = parent.getFinish();
         }
@@ -152,23 +149,23 @@
             switch (parent.tokenType()) {
             case ADD:
                 if (rhsInteger) {
-                    literalNode = LiteralNode.newInstance(source, token, finish, rhs.getInt32());
+                    literalNode = LiteralNode.newInstance(token, finish, rhs.getInt32());
                 } else {
-                    literalNode = LiteralNode.newInstance(source, token, finish, rhs.getNumber());
+                    literalNode = LiteralNode.newInstance(token, finish, rhs.getNumber());
                 }
                 break;
             case SUB:
                 if (rhsInteger && rhs.getInt32() != 0) { // @see test/script/basic/minuszero.js
-                    literalNode = LiteralNode.newInstance(source, token, finish, -rhs.getInt32());
+                    literalNode = LiteralNode.newInstance(token, finish, -rhs.getInt32());
                 } else {
-                    literalNode = LiteralNode.newInstance(source, token, finish, -rhs.getNumber());
+                    literalNode = LiteralNode.newInstance(token, finish, -rhs.getNumber());
                 }
                 break;
             case NOT:
-                literalNode = LiteralNode.newInstance(source, token, finish, !rhs.getBoolean());
+                literalNode = LiteralNode.newInstance(token, finish, !rhs.getBoolean());
                 break;
             case BIT_NOT:
-                literalNode = LiteralNode.newInstance(source, token, finish, ~rhs.getInt32());
+                literalNode = LiteralNode.newInstance(token, finish, ~rhs.getInt32());
                 break;
             default:
                 return null;
@@ -234,7 +231,7 @@
                         break;
                     }
                     assert res instanceof CharSequence : res + " was not a CharSequence, it was a " + res.getClass();
-                    return LiteralNode.newInstance(source, token, finish, res.toString());
+                    return LiteralNode.newInstance(token, finish, res.toString());
                 }
                 return null;
             case MUL:
@@ -247,33 +244,33 @@
                 value = lhs.getNumber() - rhs.getNumber();
                 break;
             case SHR:
-                return LiteralNode.newInstance(source, token, finish, (lhs.getInt32() >>> rhs.getInt32()) & JSType.MAX_UINT);
+                return LiteralNode.newInstance(token, finish, (lhs.getInt32() >>> rhs.getInt32()) & JSType.MAX_UINT);
             case SAR:
-                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() >> rhs.getInt32());
+                return LiteralNode.newInstance(token, finish, lhs.getInt32() >> rhs.getInt32());
             case SHL:
-                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() << rhs.getInt32());
+                return LiteralNode.newInstance(token, finish, lhs.getInt32() << rhs.getInt32());
             case BIT_XOR:
-                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() ^ rhs.getInt32());
+                return LiteralNode.newInstance(token, finish, lhs.getInt32() ^ rhs.getInt32());
             case BIT_AND:
-                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() & rhs.getInt32());
+                return LiteralNode.newInstance(token, finish, lhs.getInt32() & rhs.getInt32());
             case BIT_OR:
-                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() | rhs.getInt32());
+                return LiteralNode.newInstance(token, finish, lhs.getInt32() | rhs.getInt32());
             case GE:
-                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.GE(lhs.getObject(), rhs.getObject()));
+                return LiteralNode.newInstance(token, finish, ScriptRuntime.GE(lhs.getObject(), rhs.getObject()));
             case LE:
-                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.LE(lhs.getObject(), rhs.getObject()));
+                return LiteralNode.newInstance(token, finish, ScriptRuntime.LE(lhs.getObject(), rhs.getObject()));
             case GT:
-                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.GT(lhs.getObject(), rhs.getObject()));
+                return LiteralNode.newInstance(token, finish, ScriptRuntime.GT(lhs.getObject(), rhs.getObject()));
             case LT:
-                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.LT(lhs.getObject(), rhs.getObject()));
+                return LiteralNode.newInstance(token, finish, ScriptRuntime.LT(lhs.getObject(), rhs.getObject()));
             case NE:
-                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.NE(lhs.getObject(), rhs.getObject()));
+                return LiteralNode.newInstance(token, finish, ScriptRuntime.NE(lhs.getObject(), rhs.getObject()));
             case NE_STRICT:
-                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.NE_STRICT(lhs.getObject(), rhs.getObject()));
+                return LiteralNode.newInstance(token, finish, ScriptRuntime.NE_STRICT(lhs.getObject(), rhs.getObject()));
             case EQ:
-                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.EQ(lhs.getObject(), rhs.getObject()));
+                return LiteralNode.newInstance(token, finish, ScriptRuntime.EQ(lhs.getObject(), rhs.getObject()));
             case EQ_STRICT:
-                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.EQ_STRICT(lhs.getObject(), rhs.getObject()));
+                return LiteralNode.newInstance(token, finish, ScriptRuntime.EQ_STRICT(lhs.getObject(), rhs.getObject()));
             default:
                 return null;
             }
@@ -282,12 +279,12 @@
             isLong    &= value != 0.0 && JSType.isRepresentableAsLong(value);
 
             if (isInteger) {
-                return LiteralNode.newInstance(source, token, finish, JSType.toInt32(value));
+                return LiteralNode.newInstance(token, finish, JSType.toInt32(value));
             } else if (isLong) {
-                return LiteralNode.newInstance(source, token, finish, JSType.toLong(value));
+                return LiteralNode.newInstance(token, finish, JSType.toLong(value));
             }
 
-            return LiteralNode.newInstance(source, token, finish, value);
+            return LiteralNode.newInstance(token, finish, value);
         }
     }
 }
--- a/src/jdk/nashorn/internal/codegen/Label.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/Label.java	Tue May 14 11:16:52 2013 -0300
@@ -24,9 +24,8 @@
  */
 package jdk.nashorn.internal.codegen;
 
-import java.util.ArrayDeque;
-
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.runtime.Debug;
 
 /**
  * Abstraction for labels, separating a label from the underlying
@@ -35,12 +34,87 @@
  *
  * see -Dnashorn.codegen.debug, --log=codegen
  */
-public class Label extends jdk.internal.org.objectweb.asm.Label {
+public final class Label {
+    //byte code generation evaluation type stack for consistency check
+    //and correct opcode selection. one per label as a label may be a
+    //join point
+    static final class Stack {
+        Type[] data = new Type[8];
+        int sp = 0;
+
+        Stack() {
+        }
+
+        private Stack(final Type[] type, final int sp) {
+            this();
+            this.data = new Type[type.length];
+            this.sp   = sp;
+            for (int i = 0; i < sp; i++) {
+                data[i] = type[i];
+            }
+        }
+
+        boolean isEmpty() {
+            return sp == 0;
+        }
+
+        int size() {
+            return sp;
+        }
+
+        boolean isEquivalentTo(final Stack other) {
+            if (sp != other.sp) {
+                return false;
+            }
+            for (int i = 0; i < sp; i++) {
+                if (!data[i].isEquivalentTo(other.data[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        void clear() {
+            sp = 0;
+        }
+
+        void push(final Type type) {
+            if (data.length == sp) {
+                final Type[] newData = new Type[sp * 2];
+                for (int i = 0; i < sp; i++) {
+                    newData[i] = data[i];
+                }
+                data = newData;
+            }
+            data[sp++] = type;
+        }
+
+        Type peek() {
+            return peek(0);
+        }
+
+        Type peek(final int n) {
+            int pos = sp - 1 - n;
+            return pos < 0 ? null : data[pos];
+        }
+
+        Type pop() {
+            return data[--sp];
+        }
+
+        Stack copy() {
+            return new Stack(data, sp);
+        }
+    }
+
     /** Name of this label */
     private final String name;
 
     /** Type stack at this label */
-    private ArrayDeque<Type> stack;
+    private Label.Stack stack;
+
+    /** ASM representation of this label */
+    private jdk.internal.org.objectweb.asm.Label label;
 
     /**
      * Constructor
@@ -62,22 +136,24 @@
         this.name = label.name;
     }
 
-    ArrayDeque<Type> getStack() {
+
+    jdk.internal.org.objectweb.asm.Label getLabel() {
+        if (this.label == null) {
+            this.label = new jdk.internal.org.objectweb.asm.Label();
+        }
+        return label;
+    }
+
+    Label.Stack getStack() {
         return stack;
     }
 
-    void setStack(final ArrayDeque<Type> stack) {
+    void setStack(final Label.Stack stack) {
         this.stack = stack;
     }
 
     @Override
     public String toString() {
-        final StringBuilder sb = new StringBuilder();
-        String s = super.toString();
-        s = s.substring(1, s.length());
-        sb.append(name).append('_').append(Long.toHexString(Long.parseLong(s)));
-
-        return sb.toString();
+        return name + '_' + Debug.id(this);
     }
 }
-
--- a/src/jdk/nashorn/internal/codegen/Lower.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/Lower.java	Tue May 14 11:16:52 2013 -0300
@@ -32,6 +32,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+
 import jdk.nashorn.internal.ir.BaseNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
@@ -49,16 +50,15 @@
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.LabelNode;
 import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LoopNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ReturnNode;
+import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.ThrowNode;
 import jdk.nashorn.internal.ir.TryNode;
-import jdk.nashorn.internal.ir.UnaryNode;
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.WhileNode;
 import jdk.nashorn.internal.ir.WithNode;
@@ -93,21 +93,25 @@
         super(new BlockLexicalContext() {
 
             @Override
-            public List<Node> popStatements() {
-                List<Node> newStatements = new ArrayList<>();
+            public List<Statement> popStatements() {
+                final List<Statement> newStatements = new ArrayList<>();
                 boolean terminated = false;
 
-                final List<Node> statements = super.popStatements();
-                for (final Node statement : statements) {
+                final List<Statement> statements = super.popStatements();
+                for (final Statement statement : statements) {
                     if (!terminated) {
                         newStatements.add(statement);
-                        if (statement.isTerminal()) {
+                        if (statement.isTerminal() || statement instanceof BreakNode || statement instanceof ContinueNode) { //TODO hasGoto? But some Loops are hasGoto too - why?
                             terminated = true;
                         }
                     } else {
-                        if (statement instanceof VarNode) {
-                            newStatements.add(((VarNode)statement).setInit(null));
-                        }
+                        statement.accept(new NodeVisitor() {
+                            @Override
+                            public boolean enterVarNode(final VarNode varNode) {
+                                newStatements.add(varNode.setInit(null));
+                                return false;
+                            }
+                        });
                     }
                 }
                 return newStatements;
@@ -118,8 +122,9 @@
     @Override
     public boolean enterBlock(final Block block) {
         final LexicalContext lc = getLexicalContext();
-        if (lc.isFunctionBody() && lc.getCurrentFunction().isProgram() && !lc.getCurrentFunction().hasDeclaredFunctions()) {
-            new ExecuteNode(block.getSource(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
+        final FunctionNode   function = lc.getCurrentFunction();
+        if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) {
+            new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
         }
         return true;
     }
@@ -131,20 +136,20 @@
 
         final BlockLexicalContext lc = (BlockLexicalContext)getLexicalContext();
 
-        Node last = lc.getLastStatement();
+        Statement last = lc.getLastStatement();
 
         if (lc.isFunctionBody()) {
             final FunctionNode currentFunction = getLexicalContext().getCurrentFunction();
             final boolean isProgram = currentFunction.isProgram();
             final ReturnNode returnNode = new ReturnNode(
-                currentFunction.getSource(),
+                last == null ? block.getLineNumber() : last.getLineNumber(), //TODO?
                 currentFunction.getToken(),
                 currentFunction.getFinish(),
                 isProgram ?
                     compilerConstant(RETURN) :
                     LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED));
 
-            last = returnNode.accept(this);
+            last = (Statement)returnNode.accept(this);
         }
 
         if (last != null && last.isTerminal()) {
@@ -193,7 +198,6 @@
                 if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
                     node = executeNode.setExpression(
                         new BinaryNode(
-                            executeNode.getSource(),
                             Token.recast(
                                 executeNode.getToken(),
                                 TokenType.ASSIGN),
@@ -240,12 +244,6 @@
     }
 
     @Override
-    public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
-        addStatement(lineNumberNode); // don't put it in lastStatement cache
-        return false;
-    }
-
-    @Override
     public Node leaveReturnNode(final ReturnNode returnNode) {
         addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor
         return returnNode;
@@ -272,10 +270,10 @@
         });
     }
 
-    private static List<Node> copyFinally(final Block finallyBody) {
-        final List<Node> newStatements = new ArrayList<>();
-        for (final Node statement : finallyBody.getStatements()) {
-            newStatements.add(ensureUniqueLabelsIn(statement));
+    private static List<Statement> copyFinally(final Block finallyBody) {
+        final List<Statement> newStatements = new ArrayList<>();
+        for (final Statement statement : finallyBody.getStatements()) {
+            newStatements.add((Statement)ensureUniqueLabelsIn(statement));
             if (statement.hasTerminalFlags()) {
                 return newStatements;
             }
@@ -284,17 +282,17 @@
     }
 
     private Block catchAllBlock(final TryNode tryNode) {
-        final Source source = tryNode.getSource();
-        final long   token  = tryNode.getToken();
-        final int    finish = tryNode.getFinish();
+        final int  lineNumber = tryNode.getLineNumber();
+        final long token      = tryNode.getToken();
+        final int  finish     = tryNode.getFinish();
 
-        final IdentNode exception = new IdentNode(source, token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all"));
+        final IdentNode exception = new IdentNode(token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all"));
 
-        final Block catchBody = new Block(source, token, finish, new ThrowNode(source, token, finish, new IdentNode(exception))).
+        final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception))).
                 setIsTerminal(getLexicalContext(), true); //ends with throw, so terminal
 
-        final CatchNode catchAllNode  = new CatchNode(source, token, finish, new IdentNode(exception), null, catchBody);
-        final Block     catchAllBlock = new Block(source, token, finish, catchAllNode);
+        final CatchNode catchAllNode  = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody);
+        final Block     catchAllBlock = new Block(lineNumber, token, finish, catchAllNode);
 
         //catchallblock -> catchallnode (catchnode) -> exception -> throw
 
@@ -303,10 +301,10 @@
 
     private IdentNode compilerConstant(final CompilerConstants cc) {
         final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
-        return new IdentNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
+        return new IdentNode(functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
     }
 
-    private static boolean isTerminal(final List<Node> statements) {
+    private static boolean isTerminal(final List<Statement> statements) {
         return !statements.isEmpty() && statements.get(statements.size() - 1).hasTerminalFlags();
     }
 
@@ -318,8 +316,7 @@
      * @return new try node after splicing finally code (same if nop)
      */
     private Node spliceFinally(final TryNode tryNode, final List<ThrowNode> rethrows, final Block finallyBody) {
-        final Source source = tryNode.getSource();
-        final int    finish = tryNode.getFinish();
+        final int finish = tryNode.getFinish();
 
         assert tryNode.getFinallyBody() == null;
 
@@ -341,11 +338,11 @@
             @Override
             public Node leaveThrowNode(final ThrowNode throwNode) {
                 if (rethrows.contains(throwNode)) {
-                    final List<Node> newStatements = copyFinally(finallyBody);
+                    final List<Statement> newStatements = copyFinally(finallyBody);
                     if (!isTerminal(newStatements)) {
                         newStatements.add(throwNode);
                     }
-                    return new Block(source, throwNode.getToken(), throwNode.getFinish(), newStatements);
+                    return new Block(throwNode.getLineNumber(), throwNode.getToken(), throwNode.getFinish(), newStatements);
                 }
                 return throwNode;
             }
@@ -363,14 +360,14 @@
             @Override
             public Node leaveReturnNode(final ReturnNode returnNode) {
                 final Node  expr  = returnNode.getExpression();
-                final List<Node> newStatements = new ArrayList<>();
+                final List<Statement> newStatements = new ArrayList<>();
 
                 final Node resultNode;
                 if (expr != null) {
                     //we need to evaluate the result of the return in case it is complex while
                     //still in the try block, store it in a result value and return it afterwards
                     resultNode = new IdentNode(Lower.this.compilerConstant(RETURN));
-                    newStatements.add(new ExecuteNode(new BinaryNode(source, Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
+                    newStatements.add(new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
                 } else {
                     resultNode = null;
                 }
@@ -380,16 +377,16 @@
                     newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode));
                 }
 
-                return new ExecuteNode(new Block(source, returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements));
+                return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements));
             }
 
-            private Node copy(final Node endpoint, final Node targetNode) {
+            private Node copy(final Statement endpoint, final Node targetNode) {
                 if (!insideTry.contains(targetNode)) {
-                    final List<Node> newStatements = copyFinally(finallyBody);
+                    final List<Statement> newStatements = copyFinally(finallyBody);
                     if (!isTerminal(newStatements)) {
                         newStatements.add(endpoint);
                     }
-                    return new ExecuteNode(new Block(source, endpoint.getToken(), finish, newStatements));
+                    return new ExecuteNode(endpoint.getLineNumber(), endpoint.getToken(), endpoint.getFinish(), new Block(endpoint.getLineNumber(), endpoint.getToken(), finish, newStatements));
                 }
                 return endpoint;
             }
@@ -397,7 +394,7 @@
 
         addStatement(newTryNode);
         for (final Node statement : finallyBody.getStatements()) {
-            addStatement(statement);
+            addStatement((Statement)statement);
         }
 
         return newTryNode;
@@ -451,7 +448,7 @@
         if (tryNode.getCatchBlocks().isEmpty()) {
             newTryNode = tryNode.setFinallyBody(null);
         } else {
-            Block outerBody = new Block(tryNode.getSource(), tryNode.getToken(), tryNode.getFinish(), new ArrayList<Node>(Arrays.asList(tryNode.setFinallyBody(null))));
+            Block outerBody = new Block(tryNode.getLineNumber(), tryNode.getToken(), tryNode.getFinish(), new ArrayList<Statement>(Arrays.asList(tryNode.setFinallyBody(null))));
             newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null);
         }
 
@@ -468,19 +465,19 @@
     public Node leaveVarNode(final VarNode varNode) {
         addStatement(varNode);
         if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) {
-            new ExecuteNode(varNode.getSource(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
+            new ExecuteNode(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
         }
         return varNode;
     }
 
     @Override
     public Node leaveWhileNode(final WhileNode whileNode) {
-        final Node test = whileNode.getTest();
+        final Node test  = whileNode.getTest();
         final Block body = whileNode.getBody();
 
         if (conservativeAlwaysTrue(test)) {
             //turn it into a for node without a test.
-            final ForNode forNode = (ForNode)new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this);
+            final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this);
             getLexicalContext().replace(whileNode, forNode);
             return forNode;
         }
@@ -493,16 +490,6 @@
         return addStatement(withNode);
     }
 
-    @Override
-    public Node leaveDELETE(final UnaryNode unaryNode) {
-        final Node rhs = unaryNode.rhs();
-        if (rhs instanceof IdentNode || rhs instanceof BaseNode) {
-            return unaryNode;
-        }
-        addStatement(new ExecuteNode(rhs));
-        return LiteralNode.newInstance(unaryNode, true);
-    }
-
     /**
      * Given a function node that is a callee in a CallNode, replace it with
      * the appropriate marker function. This is used by {@link CodeGenerator}
@@ -525,11 +512,12 @@
      * @param node a node
      * @return eval location
      */
-    private static String evalLocation(final IdentNode node) {
+    private String evalLocation(final IdentNode node) {
+        final Source source = getLexicalContext().getCurrentFunction().getSource();
         return new StringBuilder().
-            append(node.getSource().getName()).
+            append(source.getName()).
             append('#').
-            append(node.getSource().getLine(node.position())).
+            append(source.getLine(node.position())).
             append("<eval>").
             toString();
     }
@@ -618,7 +606,7 @@
     }
 
 
-    private Node addStatement(final Node statement) {
+    private Node addStatement(final Statement statement) {
         ((BlockLexicalContext)getLexicalContext()).appendStatement(statement);
         return statement;
     }
--- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue May 14 11:16:52 2013 -0300
@@ -67,10 +67,9 @@
 
 import java.io.PrintStream;
 import java.lang.reflect.Array;
-import java.util.ArrayDeque;
 import java.util.EnumSet;
-import java.util.Iterator;
 import java.util.List;
+
 import jdk.internal.dynalink.support.NameCodec;
 import jdk.internal.org.objectweb.asm.Handle;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -114,7 +113,7 @@
     private final MethodVisitor method;
 
     /** Current type stack for current evaluation */
-    private ArrayDeque<Type> stack;
+    private Label.Stack stack;
 
     /** Parent classEmitter representing the class of this method */
     private final ClassEmitter classEmitter;
@@ -189,7 +188,7 @@
     @Override
     public void begin() {
         classEmitter.beginMethod(this);
-        stack = new ArrayDeque<>();
+        newStack();
         method.visitCode();
     }
 
@@ -205,6 +204,10 @@
         classEmitter.endMethod(this);
     }
 
+    private void newStack() {
+        stack = new Label.Stack();
+    }
+
     @Override
     public String toString() {
         return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this);
@@ -288,11 +291,7 @@
      * @return the type at position "pos" on the stack
      */
     final Type peekType(final int pos) {
-        final Iterator<Type> iter = stack.iterator();
-        for (int i = 0; i < pos; i++) {
-            iter.next();
-        }
-        return iter.next();
+        return stack.peek(pos);
     }
 
     /**
@@ -484,7 +483,7 @@
             name = THIS_DEBUGGER.symbolName();
         }
 
-        method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start, end, symbol.getSlot());
+        method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start.getLabel(), end.getLabel(), symbol.getSlot());
     }
 
     /**
@@ -509,17 +508,6 @@
     }
 
     /**
-     * Associate a variable with a given range
-     *
-     * @param name  name of the variable
-     * @param start start
-     * @param end   end
-     */
-    void markerVariable(final String name, final Label start, final Label end) {
-        method.visitLocalVariable(name, Type.OBJECT.getDescriptor(), null, start, end, 0);
-    }
-
-    /**
      * Pops two integer types from the stack, performs a bitwise and and pushes
      * the result
      *
@@ -626,7 +614,7 @@
      * @param typeDescriptor type descriptor for exception
      */
     void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor) {
-        method.visitTryCatchBlock(entry, exit, recovery, typeDescriptor);
+        method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), typeDescriptor);
     }
 
     /**
@@ -638,7 +626,7 @@
      * @param clazz    exception class
      */
     void _try(final Label entry, final Label exit, final Label recovery, final Class<?> clazz) {
-        method.visitTryCatchBlock(entry, exit, recovery, CompilerConstants.className(clazz));
+        method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), CompilerConstants.className(clazz));
     }
 
     /**
@@ -871,7 +859,7 @@
     }
 
     private boolean isThisSlot(final int slot) {
-        if(functionNode == null) {
+        if (functionNode == null) {
             return slot == CompilerConstants.JAVA_THIS.slot();
         }
         final int thisSlot = compilerConstant(THIS).getSlot();
@@ -915,7 +903,6 @@
             dup();
             return this;
         }
-        debug("load compiler constant ", symbol);
         return load(symbol);
     }
 
@@ -1228,6 +1215,14 @@
         return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true);
     }
 
+    static jdk.internal.org.objectweb.asm.Label[] getLabels(final Label... table) {
+        final jdk.internal.org.objectweb.asm.Label[] internalLabels = new jdk.internal.org.objectweb.asm.Label[table.length];
+        for (int i = 0; i < table.length; i++) {
+            internalLabels[i] = table[i].getLabel();
+        }
+        return internalLabels;
+    }
+
     /**
      * Generate a lookup switch, popping the switch value from the stack
      *
@@ -1235,10 +1230,10 @@
      * @param values       case values for the table
      * @param table        default label
      */
-    void lookupswitch(final Label defaultLabel, final int[] values, final Label[] table) {
+    void lookupswitch(final Label defaultLabel, final int[] values, final Label... table) {//Collection<Label> table) {
         debug("lookupswitch", peekType());
         popType(Type.INT);
-        method.visitLookupSwitchInsn(defaultLabel, values, table);
+        method.visitLookupSwitchInsn(defaultLabel.getLabel(), values, getLabels(table));
     }
 
     /**
@@ -1248,10 +1243,10 @@
      * @param defaultLabel  default label
      * @param table         label table
      */
-    void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label[] table) {
+    void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label... table) {
         debug("tableswitch", peekType());
         popType(Type.INT);
-        method.visitTableSwitchInsn(lo, hi, defaultLabel, table);
+        method.visitTableSwitchInsn(lo, hi, defaultLabel.getLabel(), getLabels(table));
     }
 
     /**
@@ -1358,7 +1353,7 @@
             popType();
         }
         mergeStackTo(label);
-        method.visitJumpInsn(opcode, label);
+        method.visitJumpInsn(opcode, label.getLabel());
     }
 
     /**
@@ -1487,9 +1482,9 @@
      * @param label destination label
      */
     void _goto(final Label label) {
-        debug("goto", label);
+        //debug("goto", label);
         jump(GOTO, label, 0);
-        stack = null;
+        stack = null; //whoever reaches the point after us provides the stack, because we don't
     }
 
     /**
@@ -1500,38 +1495,31 @@
      *
      * @return true if stacks are equivalent, false otherwise
      */
-    private boolean stacksEquivalent(final ArrayDeque<Type> s0, final ArrayDeque<Type> s1) {
-        if (s0.size() != s1.size()) {
-            debug("different stack sizes", s0, s1);
-            return false;
-        }
-
-        final Type[] s0a = s0.toArray(new Type[s0.size()]);
-        final Type[] s1a = s1.toArray(new Type[s1.size()]);
-        for (int i = 0; i < s0.size(); i++) {
-            if (!s0a[i].isEquivalentTo(s1a[i])) {
-                debug("different stack element", s0a[i], s1a[i]);
-                return false;
-            }
-        }
-
-        return true;
-    }
-
     /**
      * A join in control flow - helper function that makes sure all entry stacks
      * discovered for the join point so far are equivalent
-     * @param label
+     *
+     * MergeStack: we are about to enter a label. If its stack, label.getStack() is null
+     * we have never been here before. Then we are expected to carry a stack with us.
+     *
+     * @param label label
      */
     private void mergeStackTo(final Label label) {
-        final ArrayDeque<Type> labelStack = label.getStack();
-        //debug(labelStack == null ? " >> Control flow - first visit ", label : " >> Control flow - JOIN with ", labelStack, " at ", label);
+        //sometimes we can do a merge stack without having a stack - i.e. when jumping ahead to dead code
+        //see NASHORN-73. So far we had been saved by the line number nodes. This should have been fixed
+        //by Lower removing everything after an unconditionally executed terminating statement OR a break
+        //or continue in a block. Previously code left over after breaks and continues was still there
+        //and caused bytecode to be generated - which crashed on stack not being there, as the merge
+        //was not in fact preceeded by a visit. Furthermore, this led to ASM putting out its NOP NOP NOP
+        //ATHROW sequences instead of no code being generated at all. This should now be fixed.
+        assert stack != null : label + " entered with no stack. deadcode that remains?";
+
+        final Label.Stack labelStack = label.getStack();
         if (labelStack == null) {
-            assert stack != null;
-            label.setStack(stack.clone());
+            label.setStack(stack.copy());
             return;
         }
-        assert stacksEquivalent(stack, labelStack) : "stacks " + stack + " is not equivalent with " + labelStack + " at join point";
+        assert stack.isEquivalentTo(labelStack) : "stacks " + stack + " is not equivalent with " + labelStack + " at join point";
     }
 
     /**
@@ -1548,14 +1536,14 @@
         if (stack == null) {
             stack = label.getStack();
             if (stack == null) {
-                stack = new ArrayDeque<>(); //we don't have a stack at this point.
+                newStack();
             }
         }
         debug_label(label);
 
         mergeStackTo(label); //we have to merge our stack to whatever is in the label
 
-        method.visitLabel(label);
+        method.visitLabel(label.getLabel());
     }
 
     /**
@@ -1675,11 +1663,10 @@
      * @return array of Types
      */
     protected Type[] getTypesFromStack(final int count) {
-        final Iterator<Type> iter  = stack.iterator();
-        final Type[]         types = new Type[count];
-
+        final Type[] types = new Type[count];
+        int pos = 0;
         for (int i = count - 1; i >= 0; i--) {
-            types[i] = iter.next();
+            types[i] = stack.peek(pos++);
         }
 
         return types;
@@ -1695,11 +1682,11 @@
      * @return function signature for stack contents
      */
     private String getDynamicSignature(final Type returnType, final int argCount) {
-        final Iterator<Type> iter       = stack.iterator();
         final Type[]         paramTypes = new Type[argCount];
 
+        int pos = 0;
         for (int i = argCount - 1; i >= 0; i--) {
-            paramTypes[i] = iter.next();
+            paramTypes[i] = stack.peek(pos++);
         }
         final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
         for (int i = 0; i < argCount; i++) {
@@ -2018,8 +2005,13 @@
      * @param line  line number
      * @param label label
      */
-    void lineNumber(final int line, final Label label) {
-        method.visitLineNumber(line, label);
+    void lineNumber(final int line) {
+        if (env._debug_lines) {
+            debug_label("[LINE]", line);
+            final jdk.internal.org.objectweb.asm.Label l = new jdk.internal.org.objectweb.asm.Label();
+            method.visitLabel(l);
+            method.visitLineNumber(line, l);
+        }
     }
 
     /*
@@ -2116,12 +2108,12 @@
                 pad--;
             }
 
-            if (!stack.isEmpty()) {
+            if (stack != null && !stack.isEmpty()) {
                 sb.append("{");
                 sb.append(stack.size());
                 sb.append(":");
-                for (final Iterator<Type> iter = stack.iterator(); iter.hasNext();) {
-                    final Type t = iter.next();
+                for (int pos = 0; pos < stack.size(); pos++) {
+                    final Type t = stack.peek(pos);
 
                     if (t == Type.SCOPE) {
                         sb.append("scope");
@@ -2147,7 +2139,7 @@
                         sb.append(t.getDescriptor());
                     }
 
-                    if (iter.hasNext()) {
+                    if (pos + 1 < stack.size()) {
                         sb.append(' ');
                     }
                 }
--- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Tue May 14 11:16:52 2013 -0300
@@ -27,7 +27,6 @@
 
 import java.util.List;
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_PADDING;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_ROUNDING;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.PropertyMap;
--- a/src/jdk/nashorn/internal/codegen/Splitter.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/codegen/Splitter.java	Tue May 14 11:16:52 2013 -0300
@@ -31,6 +31,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -40,9 +41,9 @@
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.DebugLogger;
-import jdk.nashorn.internal.runtime.Source;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -75,7 +76,7 @@
      */
     public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) {
         this.compiler             = compiler;
-        this.outermost = functionNode;
+        this.outermost            = functionNode;
         this.outermostCompileUnit = outermostCompileUnit;
     }
 
@@ -95,7 +96,7 @@
         final LexicalContext lc = getLexicalContext();
 
         long weight = WeighNodes.weigh(functionNode);
-        final boolean top = compiler.getFunctionNode() == outermost;
+        final boolean top = fn.isProgram(); //compiler.getFunctionNode() == outermost;
 
         if (weight >= SPLIT_THRESHOLD) {
             LOG.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD);
@@ -127,18 +128,18 @@
         final List<FunctionNode> dc = directChildren(functionNode);
 
         final Block newBody = (Block)body.accept(new NodeVisitor() {
-                @Override
-                public boolean enterFunctionNode(final FunctionNode nestedFunction) {
-                    return dc.contains(nestedFunction);
-                }
+            @Override
+            public boolean enterFunctionNode(final FunctionNode nestedFunction) {
+                return dc.contains(nestedFunction);
+            }
 
-                @Override
-                public Node leaveFunctionNode(final FunctionNode nestedFunction) {
-                    FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction);
-                    getLexicalContext().replace(nestedFunction, split);
-                    return split;
-                }
-            });
+            @Override
+            public Node leaveFunctionNode(final FunctionNode nestedFunction) {
+                FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction);
+                getLexicalContext().replace(nestedFunction, split);
+                return split;
+            }
+        });
         functionNode = functionNode.setBody(lc, newBody);
 
         assert functionNode.getCompileUnit() != null;
@@ -182,11 +183,11 @@
     private Block splitBlock(final Block block, final FunctionNode function) {
         getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT);
 
-        final List<Node> splits = new ArrayList<>();
-        List<Node> statements = new ArrayList<>();
+        final List<Statement> splits = new ArrayList<>();
+        List<Statement> statements = new ArrayList<>();
         long statementsWeight = 0;
 
-        for (final Node statement : block.getStatements()) {
+        for (final Statement statement : block.getStatements()) {
             final long weight = WeighNodes.weigh(statement, weightCache);
 
             if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) {
@@ -220,15 +221,15 @@
      *
      * @return New split node.
      */
-    private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Node> statements, final long weight) {
-        final Source source = parent.getSource();
-        final long   token  = parent.getToken();
-        final int    finish = parent.getFinish();
-        final String name   = function.uniqueName(SPLIT_PREFIX.symbolName());
+    private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Statement> statements, final long weight) {
+        final int    lineNumber = parent.getLineNumber();
+        final long   token      = parent.getToken();
+        final int    finish     = parent.getFinish();
+        final String name       = function.uniqueName(SPLIT_PREFIX.symbolName());
 
-        final Block newBlock = new Block(source, token, finish, statements);
+        final Block newBlock = new Block(lineNumber, token, finish, statements);
 
-        return new SplitNode(name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
+        return new SplitNode(lineNumber, name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
     }
 
     @Override
@@ -273,7 +274,9 @@
             return literal;
         }
 
-        getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT);
+        final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
+
+        getLexicalContext().setFlag(functionNode, FunctionNode.IS_SPLIT);
 
         if (literal instanceof ArrayLiteralNode) {
             final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
--- a/src/jdk/nashorn/internal/ir/AccessNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/AccessNode.java	Tue May 14 11:16:52 2013 -0300
@@ -28,7 +28,6 @@
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of a property access (period operator.)
@@ -41,14 +40,13 @@
     /**
      * Constructor
      *
-     * @param source    source code
      * @param token     token
      * @param finish    finish
      * @param base      base node
      * @param property  property
      */
-    public AccessNode(final Source source, final long token, final int finish, final Node base, final IdentNode property) {
-        super(source, token, finish, base, false, false);
+    public AccessNode(final long token, final int finish, final Node base, final IdentNode property) {
+        super(token, finish, base, false, false);
         this.property = property.setIsPropertyName();
     }
 
@@ -121,10 +119,10 @@
     }
 
     @Override
-    public AccessNode setType(final Type type) {
+    public AccessNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
         logTypeChange(type);
-        getSymbol().setTypeOverride(type); //always a temp so this is fine.
-        return new AccessNode(this, base, property.setType(type), isFunction(), hasCallSiteType());
+        final AccessNode newAccessNode = (AccessNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
+        return new AccessNode(newAccessNode, base, property.setType(ts, lc, type), isFunction(), hasCallSiteType());
     }
 
     @Override
--- a/src/jdk/nashorn/internal/ir/BaseNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/BaseNode.java	Tue May 14 11:16:52 2013 -0300
@@ -29,7 +29,6 @@
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Immutable;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR base for accessing/indexing nodes.
@@ -50,15 +49,14 @@
     /**
      * Constructor
      *
-     * @param source source code
      * @param token  token
      * @param finish finish
      * @param base   base node
      * @param isFunction is this a function
      * @param hasCallSiteType does this access have a callsite type
      */
-    public BaseNode(final Source source, final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
-        super(source, token, base.getStart(), finish);
+    public BaseNode(final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
+        super(token, base.getStart(), finish);
         this.base            = base;
         this.isFunction      = isFunction;
         this.hasCallSiteType = hasCallSiteType;
--- a/src/jdk/nashorn/internal/ir/BinaryNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/BinaryNode.java	Tue May 14 11:16:52 2013 -0300
@@ -29,7 +29,6 @@
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * BinaryNode nodes represent two operand operations.
@@ -44,13 +43,12 @@
     /**
      * Constructor
      *
-     * @param source source code
      * @param token  token
      * @param lhs    left hand side
      * @param rhs    right hand side
      */
-    public BinaryNode(final Source source, final long token, final Node lhs, final Node rhs) {
-        super(source, token, lhs.getStart(), rhs.getFinish());
+    public BinaryNode(final long token, final Node lhs, final Node rhs) {
+        super(token, lhs.getStart(), rhs.getFinish());
         this.lhs   = lhs;
         this.rhs   = rhs;
     }
--- a/src/jdk/nashorn/internal/ir/Block.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/Block.java	Tue May 14 11:16:52 2013 -0300
@@ -30,14 +30,12 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import jdk.nashorn.internal.codegen.Label;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for a list of statements and functions. All provides the
@@ -46,7 +44,7 @@
 @Immutable
 public class Block extends BreakableNode implements Flags<Block> {
     /** List of statements */
-    protected final List<Node> statements;
+    protected final List<Statement> statements;
 
     /** Symbol table - keys must be returned in the order they were put in. */
     protected final Map<String, Symbol> symbols;
@@ -78,13 +76,13 @@
     /**
      * Constructor
      *
-     * @param source     source code
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param statements statements
      */
-    public Block(final Source source, final long token, final int finish, final Node... statements) {
-        super(source, token, finish, new Label("block_break"));
+    public Block(final int lineNumber, final long token, final int finish, final Statement... statements) {
+        super(lineNumber, token, finish, new Label("block_break"));
 
         this.statements = Arrays.asList(statements);
         this.symbols    = new LinkedHashMap<>();
@@ -95,27 +93,35 @@
     /**
      * Constructor
      *
-     * @param source     source code
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param statements statements
      */
-    public Block(final Source source, final long token, final int finish, final List<Node> statements) {
-        this(source, token, finish, statements.toArray(new Node[statements.size()]));
+    public Block(final int lineNumber, final long token, final int finish, final List<Statement> statements) {
+        this(lineNumber, token, finish, statements.toArray(new Statement[statements.size()]));
     }
 
-    private Block(final Block block, final int finish, final List<Node> statements, final int flags) {
+    private Block(final Block block, final int finish, final List<Statement> statements, final int flags, final Map<String, Symbol> symbols) {
         super(block);
         this.statements = statements;
         this.flags      = flags;
-        this.symbols    = block.symbols; //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
+        this.symbols    = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
         this.entryLabel = new Label(block.entryLabel);
-        this.finish = finish;
+        this.finish     = finish;
+    }
+
+    /**
+     * Clear the symbols in a block
+     * TODO: make this immutable
+     */
+    public void clearSymbols() {
+        symbols.clear();
     }
 
     @Override
     public Node ensureUniqueLabels(final LexicalContext lc) {
-        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags));
+        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols));
     }
 
     /**
@@ -127,7 +133,7 @@
     @Override
     public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
         if (visitor.enterBlock(this)) {
-            return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Node.class, statements)));
+            return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Statement.class, statements)));
         }
 
         return this;
@@ -137,15 +143,15 @@
      * Get an iterator for all the symbols defined in this block
      * @return symbol iterator
      */
-    public Iterator<Symbol> symbolIterator() {
-        return symbols.values().iterator();
+    public List<Symbol> getSymbols() {
+        return Collections.unmodifiableList(new ArrayList<>(symbols.values()));
     }
 
     /**
      * Retrieves an existing symbol defined in the current block.
      * @param name the name of the symbol
      * @return an existing symbol with the specified name defined in the current block, or null if this block doesn't
-     * define a symbol with this name.
+     * define a symbol with this name.T
      */
     public Symbol getExistingSymbol(final String name) {
         return symbols.get(name);
@@ -222,7 +228,7 @@
      *
      * @return a list of statements
      */
-    public List<Node> getStatements() {
+    public List<Statement> getStatements() {
         return Collections.unmodifiableList(statements);
     }
 
@@ -233,7 +239,7 @@
      * @param statements new statement list
      * @return new block if statements changed, identity of statements == block.statements
      */
-    public Block setStatements(final LexicalContext lc, final List<Node> statements) {
+    public Block setStatements(final LexicalContext lc, final List<Statement> statements) {
         if (this.statements == statements) {
             return this;
         }
@@ -241,17 +247,17 @@
         if (!statements.isEmpty()) {
             lastFinish = statements.get(statements.size() - 1).getFinish();
         }
-        return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags));
+        return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags, symbols));
     }
 
     /**
      * Add or overwrite an existing symbol in the block
      *
-     * @param name   name of symbol
+     * @param lc     get lexical context
      * @param symbol symbol
      */
-    public void putSymbol(final String name, final Symbol symbol) {
-        symbols.put(name, symbol);
+    public void putSymbol(final LexicalContext lc, final Symbol symbol) {
+        symbols.put(symbol.getName(), symbol);
     }
 
     /**
@@ -268,7 +274,7 @@
         if (this.flags == flags) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags));
+        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols));
     }
 
     @Override
@@ -296,7 +302,7 @@
             return this;
         }
 
-        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE));
+        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE, symbols));
     }
 
     /**
@@ -306,13 +312,11 @@
      * @return next slot
      */
     public int nextSlot() {
-        final Iterator<Symbol> iter = symbolIterator();
         int next = 0;
-        while (iter.hasNext()) {
-        final Symbol symbol = iter.next();
-        if (symbol.hasSlot()) {
-            next += symbol.slotCount();
-        }
+        for (final Symbol symbol : getSymbols()) {
+            if (symbol.hasSlot()) {
+                next += symbol.slotCount();
+            }
         }
         return next;
     }
--- a/src/jdk/nashorn/internal/ir/BlockLexicalContext.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/BlockLexicalContext.java	Tue May 14 11:16:52 2013 -0300
@@ -41,16 +41,16 @@
 public class BlockLexicalContext extends LexicalContext {
     /** statement stack, each block on the lexical context maintains one of these, which is
      *  committed to the block on pop */
-    private Deque<List<Node>> sstack = new ArrayDeque<>();
+    private Deque<List<Statement>> sstack = new ArrayDeque<>();
 
     /** Last non debug statement emitted in this context */
-    protected Node lastStatement;
+    protected Statement lastStatement;
 
     @Override
     public <T extends LexicalContextNode> T push(final T node) {
         T pushed = super.push(node);
         if (node instanceof Block) {
-            sstack.push(new ArrayList<Node>());
+            sstack.push(new ArrayList<Statement>());
         }
         return pushed;
     }
@@ -59,16 +59,16 @@
      * Get the statement list from the stack, possibly filtered
      * @return statement list
      */
-    protected List<Node> popStatements() {
+    protected List<Statement> popStatements() {
         return sstack.pop();
     }
 
+    @SuppressWarnings("unchecked")
     @Override
-    @SuppressWarnings("unchecked")
     public <T extends LexicalContextNode> T pop(final T node) {
         T expected = node;
         if (node instanceof Block) {
-            final List<Node> newStatements = popStatements();
+            final List<Statement> newStatements = popStatements();
             expected = (T)((Block)node).setStatements(this, newStatements);
             if (!sstack.isEmpty()) {
                 lastStatement = lastStatement(sstack.peek());
@@ -81,12 +81,10 @@
      * Append a statement to the block being generated
      * @param statement statement to add
      */
-    public void appendStatement(final Node statement) {
+    public void appendStatement(final Statement statement) {
         assert statement != null;
         sstack.peek().add(statement);
-        if (!statement.isDebug()) {
-            lastStatement = statement;
-        }
+        lastStatement = statement;
     }
 
     /**
@@ -94,26 +92,24 @@
      * @param statement statement to prepend
      * @return the prepended statement
      */
-    public Node prependStatement(final Node statement) {
+    public Node prependStatement(final Statement statement) {
         assert statement != null;
         sstack.peek().add(0, statement);
         return statement;
     }
 
     /**
-     * Get the last (non debug) statement that was emitted into a block
+     * Get the last statement that was emitted into a block
      * @return the last statement emitted
      */
-    public Node getLastStatement() {
+    public Statement getLastStatement() {
         return lastStatement;
     }
 
-    private static Node lastStatement(final List<Node> statements) {
-        for (final ListIterator<Node> iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) {
-            final Node node = iter.previous();
-            if (!node.isDebug()) {
-                return node;
-            }
+    private static Statement lastStatement(final List<Statement> statements) {
+        for (final ListIterator<Statement> iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) {
+            final Statement node = iter.previous();
+            return node;
         }
         return null;
     }
--- a/src/jdk/nashorn/internal/ir/BreakNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/BreakNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,26 +27,25 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for {@code break} statements.
  */
 @Immutable
-public final class BreakNode extends Node {
+public final class BreakNode extends Statement {
 
     private final IdentNode label;
 
     /**
      * Constructor
      *
-     * @param source source code
-     * @param token  token
-     * @param finish finish
-     * @param label  label for break or null if none
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
+     * @param label      label for break or null if none
      */
-    public BreakNode(final Source source, final long token, final int finish, final IdentNode label) {
-        super(source, token, finish);
+    public BreakNode(final int lineNumber, final long token, final int finish, final IdentNode label) {
+        super(lineNumber, token, finish);
         this.label = label;
     }
 
--- a/src/jdk/nashorn/internal/ir/BreakableNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/BreakableNode.java	Tue May 14 11:16:52 2013 -0300
@@ -30,7 +30,6 @@
 
 import jdk.nashorn.internal.codegen.Label;
 import jdk.nashorn.internal.ir.annotations.Immutable;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * This class represents a node from which control flow can execute
@@ -45,13 +44,13 @@
     /**
      * Constructor
      *
-     * @param source     source code
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param breakLabel break label
      */
-    protected BreakableNode(final Source source, final long token, final int finish, final Label breakLabel) {
-        super(source, token, finish);
+    protected BreakableNode(final int lineNumber, final long token, final int finish, final Label breakLabel) {
+        super(lineNumber, token, finish);
         this.breakLabel = breakLabel;
     }
 
--- a/src/jdk/nashorn/internal/ir/CallNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/CallNode.java	Tue May 14 11:16:52 2013 -0300
@@ -31,7 +31,6 @@
 import jdk.nashorn.internal.ir.annotations.Ignore;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for a function call.
@@ -137,14 +136,14 @@
     /**
      * Constructors
      *
-     * @param source   the source
-     * @param token    token
-     * @param finish   finish
-     * @param function the function to call
-     * @param args     args to the call
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
+     * @param function   the function to call
+     * @param args       args to the call
      */
-    public CallNode(final Source source, final long token, final int finish, final Node function, final List<Node> args) {
-        super(source, token, finish);
+    public CallNode(final int lineNumber, final long token, final int finish, final Node function, final List<Node> args) {
+        super(lineNumber, token, finish);
 
         this.function = function;
         this.args     = args;
@@ -171,7 +170,7 @@
     }
 
     @Override
-    public CallNode setType(final Type type) {
+    public CallNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
         if (this.type == type) {
             return this;
         }
@@ -201,7 +200,7 @@
                     setFunction(function.accept(visitor)).
                     setArgs(Node.accept(visitor, Node.class, args)).
                     setFlags(flags).
-                    setType(type).
+                    setType(null, lc, type).
                     setEvalArgs(evalArgs == null ?
                             null :
                             evalArgs.setCode(evalArgs.getCode().accept(visitor)).
--- a/src/jdk/nashorn/internal/ir/CaseNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/CaseNode.java	Tue May 14 11:16:52 2013 -0300
@@ -28,7 +28,6 @@
 import jdk.nashorn.internal.codegen.Label;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of CASE clause.
@@ -48,14 +47,13 @@
     /**
      * Constructors
      *
-     * @param source   the source
      * @param token    token
      * @param finish   finish
      * @param test     case test node, can be any node in JavaScript
      * @param body     case body
      */
-    public CaseNode(final Source source, final long token, final int finish, final Node test, final Block body) {
-        super(source, token, finish);
+    public CaseNode(final long token, final int finish, final Node test, final Block body) {
+        super(token, finish);
 
         this.test  = test;
         this.body  = body;
--- a/src/jdk/nashorn/internal/ir/CatchNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/CatchNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,13 +27,12 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of a catch clause.
  */
 @Immutable
-public final class CatchNode extends Node {
+public final class CatchNode extends Statement {
     /** Exception identifier. */
     private final IdentNode exception;
 
@@ -46,16 +45,15 @@
     /**
      * Constructors
      *
-     * @param source             the source
+     * @param lineNumber         lineNumber
      * @param token              token
      * @param finish             finish
      * @param exception          variable name of exception
      * @param exceptionCondition exception condition
      * @param body               catch body
      */
-    public CatchNode(final Source source, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) {
-        super(source, token, finish);
-
+    public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) {
+        super(lineNumber, token, finish);
         this.exception          = exception;
         this.exceptionCondition = exceptionCondition;
         this.body               = body;
@@ -63,7 +61,6 @@
 
     private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body) {
         super(catchNode);
-
         this.exception          = exception;
         this.exceptionCondition = exceptionCondition;
         this.body               = body;
@@ -138,7 +135,12 @@
         return body;
     }
 
-    private CatchNode setException(final IdentNode exception) {
+    /**
+     * Resets the exception of a catch block
+     * @param exception new exception
+     * @return new catch node if changed, same otherwise
+     */
+    public CatchNode setException(final IdentNode exception) {
         if (this.exception == exception) {
             return this;
         }
--- a/src/jdk/nashorn/internal/ir/ContinueNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/ContinueNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,26 +27,25 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for CONTINUE statements.
  */
 @Immutable
-public class ContinueNode extends Node {
+public class ContinueNode extends Statement {
 
     private IdentNode label;
 
     /**
      * Constructor
      *
-     * @param source source code
-     * @param token  token
-     * @param finish finish
-     * @param label  label for break or null if none
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
+     * @param label      label for break or null if none
      */
-    public ContinueNode(final Source source, final long token, final int finish, final IdentNode label) {
-        super(source, token, finish);
+    public ContinueNode(final int lineNumber, final long token, final int finish, final IdentNode label) {
+        super(lineNumber, token, finish);
         this.label = label;
     }
 
--- a/src/jdk/nashorn/internal/ir/EmptyNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/EmptyNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,32 +27,31 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for an empty statement.
  */
 @Immutable
-public final class EmptyNode extends Node {
+public final class EmptyNode extends Statement {
 
     /**
      * Constructor
      *
      * @param node node to wrap
      */
-    public EmptyNode(final Node node) {
+    public EmptyNode(final Statement node) {
         super(node);
     }
 
     /**
      * Constructor
      *
-     * @param source     the source
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      */
-    public EmptyNode(final Source source, final long token, final int finish) {
-        super(source, token, finish);
+    public EmptyNode(final int lineNumber, final long token, final int finish) {
+        super(lineNumber, token, finish);
     }
 
 
--- a/src/jdk/nashorn/internal/ir/ExecuteNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/ExecuteNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,7 +27,6 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for executing bare expressions. Basically, an expression
@@ -35,20 +34,20 @@
  * statements being added to the IR
  */
 @Immutable
-public final class ExecuteNode extends Node {
+public final class ExecuteNode extends Statement {
     /** Expression to execute. */
     private final Node expression;
 
     /**
      * Constructor
      *
-     * @param source     the source
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param expression the expression to execute
      */
-    public ExecuteNode(final Source source, final long token, final int finish, final Node expression) {
-        super(source, token, finish);
+    public ExecuteNode(final int lineNumber, final long token, final int finish, final Node expression) {
+        super(lineNumber, token, finish);
         this.expression = expression;
     }
 
@@ -57,16 +56,6 @@
         this.expression = expression;
     }
 
-    /**
-     * Constructor
-     *
-     * @param expression an expression to wrap, from which source, tokens and finish are also inherited
-     */
-    public ExecuteNode(final Node expression) {
-        super(expression.getSource(), expression.getToken(), expression.getFinish());
-        this.expression = expression;
-    }
-
     @Override
     public boolean isTerminal() {
         return expression.isTerminal();
--- a/src/jdk/nashorn/internal/ir/ForNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/ForNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,7 +27,6 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representing a FOR statement.
@@ -57,17 +56,17 @@
     /**
      * Constructor
      *
-     * @param source the source
-     * @param token  token
-     * @param finish finish
-     * @param init   init
-     * @param test   test
-     * @param body   body
-     * @param modify modify
-     * @param flags  flags
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
+     * @param init       initialization expression
+     * @param test       test
+     * @param body       body
+     * @param modify     modify
+     * @param flags      flags
      */
-    public ForNode(final Source source, final long token, final int finish, final Node init, final Node test, final Block body, final Node modify, final int flags) {
-        super(source, token, finish, test, body, false);
+    public ForNode(final int lineNumber, final long token, final int finish, final Node init, final Node test, final Block body, final Node modify, final int flags) {
+        super(lineNumber, token, finish, test, body, false);
         this.init   = init;
         this.modify = modify;
         this.flags  = flags;
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Tue May 14 11:16:52 2013 -0300
@@ -25,16 +25,12 @@
 
 package jdk.nashorn.internal.ir;
 
-import static jdk.nashorn.internal.codegen.CompilerConstants.LITERAL_PREFIX;
-import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX;
-import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT;
-import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
-
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+
 import jdk.nashorn.internal.codegen.CompileUnit;
 import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.CompilerConstants;
@@ -90,11 +86,17 @@
         /** method has been emitted to bytecode */
         EMITTED
     }
+    /** Source of entity. */
+    private final Source source;
 
     /** External function identifier. */
     @Ignore
     private final IdentNode ident;
 
+    /** Parsed version of functionNode */
+    @Ignore
+    private final FunctionNode snapshot;
+
     /** The body of the function node */
     private final Block body;
 
@@ -127,6 +129,9 @@
     @Ignore
     private final EnumSet<CompilationState> compilationState;
 
+    @Ignore
+    private final Compiler.Hints hints;
+
     /** Function flags. */
     private final int flags;
 
@@ -176,6 +181,9 @@
     /** Does this function have nested declarations? */
     public static final int HAS_FUNCTION_DECLARATIONS   = 1 << 13;
 
+    /** Can this function be specialized? */
+    public static final int CAN_SPECIALIZE              = 1 << 14;
+
     /** Does this function or any nested functions contain an eval? */
     private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
 
@@ -196,6 +204,7 @@
      * Constructor
      *
      * @param source     the source
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param firstToken first token of the funtion node (including the function declaration)
@@ -208,6 +217,7 @@
      */
     public FunctionNode(
         final Source source,
+        final int lineNumber,
         final long token,
         final int finish,
         final long firstToken,
@@ -217,39 +227,56 @@
         final List<IdentNode> parameters,
         final FunctionNode.Kind kind,
         final int flags) {
-        super(source, token, finish);
+        super(lineNumber, token, finish);
 
-        this.ident             = ident;
-        this.name              = name;
-        this.kind              = kind;
-        this.parameters        = parameters;
-        this.firstToken        = firstToken;
-        this.lastToken         = token;
-        this.namespace         = namespace;
-        this.compilationState  = EnumSet.of(CompilationState.INITIALIZED);
-        this.declaredSymbols   = new HashSet<>();
-        this.flags             = flags;
-        this.compileUnit       = null;
-        this.body              = null;
+        this.source           = source;
+        this.ident            = ident;
+        this.name             = name;
+        this.kind             = kind;
+        this.parameters       = parameters;
+        this.firstToken       = firstToken;
+        this.lastToken        = token;
+        this.namespace        = namespace;
+        this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
+        this.declaredSymbols  = new HashSet<>();
+        this.flags            = flags;
+        this.compileUnit      = null;
+        this.body             = null;
+        this.snapshot         = null;
+        this.hints            = null;
     }
 
-    private FunctionNode(final FunctionNode functionNode, final long lastToken, final int flags, final Type returnType, final CompileUnit compileUnit, final EnumSet<CompilationState> compilationState, final Block body) {
+    private FunctionNode(
+        final FunctionNode functionNode,
+        final long lastToken,
+        final int flags,
+        final Type returnType,
+        final CompileUnit compileUnit,
+        final EnumSet<CompilationState> compilationState,
+        final Block body,
+        final List<IdentNode> parameters,
+        final FunctionNode snapshot,
+        final Compiler.Hints hints) {
         super(functionNode);
-        this.flags = flags;
-        this.returnType = returnType;
-        this.compileUnit = compileUnit;
-        this.lastToken = lastToken;
+
+        this.flags            = flags;
+        this.returnType       = returnType;
+        this.compileUnit      = compileUnit;
+        this.lastToken        = lastToken;
         this.compilationState = compilationState;
-        this.body  = body;
+        this.body             = body;
+        this.parameters       = parameters;
+        this.snapshot         = snapshot;
+        this.hints            = hints;
 
         // the fields below never change - they are final and assigned in constructor
-        this.name = functionNode.name;
-        this.ident = functionNode.ident;
-        this.namespace = functionNode.namespace;
+        this.source          = functionNode.source;
+        this.name            = functionNode.name;
+        this.ident           = functionNode.ident;
+        this.namespace       = functionNode.namespace;
         this.declaredSymbols = functionNode.declaredSymbols;
-        this.kind  = functionNode.kind;
-        this.parameters = functionNode.parameters;
-        this.firstToken = functionNode.firstToken;
+        this.kind            = functionNode.kind;
+        this.firstToken      = functionNode.firstToken;
     }
 
     @Override
@@ -261,6 +288,61 @@
     }
 
     /**
+     * Get the source for this function
+     * @return the source
+     */
+    public Source getSource() {
+        return source;
+    }
+
+    /**
+     * Get the version of this function node's code as it looked upon construction
+     * i.e typically parsed and nothing else
+     * @return initial version of function node
+     */
+    public FunctionNode getSnapshot() {
+        return snapshot;
+    }
+
+    /**
+     * Throw away the snapshot, if any, to save memory. Used when heuristic
+     * determines that a method is not worth specializing
+     *
+     * @param lc lexical context
+     * @return new function node if a snapshot was present, now with snapsnot null
+     */
+    public FunctionNode clearSnapshot(final LexicalContext lc) {
+        if (this.snapshot == null) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, null, hints));
+    }
+
+    /**
+     * Take a snapshot of this function node at a given point in time
+     * and store it in the function node
+     * @param lc lexical context
+     * @return function node
+     */
+    public FunctionNode snapshot(final LexicalContext lc) {
+        if (this.snapshot == this) {
+            return this;
+        }
+        if (isProgram() || parameters.isEmpty()) {
+            return this; //never specialize anything that won't be recompiled
+        }
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, this, hints));
+    }
+
+    /**
+     * Can this function node be regenerated with more specific type args?
+     * @return true if specialization is possible
+     */
+    public boolean canSpecialize() {
+        return getFlag(CAN_SPECIALIZE);
+    }
+
+    /**
      * Get the compilation state of this function
      * @return the compilation state
      */
@@ -307,7 +389,28 @@
         }
         final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
         newState.add(state);
-        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body));
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body, parameters, snapshot, hints));
+    }
+
+    /**
+     * Get any compiler hints that may associated with the function
+     * @return compiler hints
+     */
+    public Compiler.Hints getHints() {
+        return this.hints == null ? Compiler.Hints.EMPTY : hints;
+    }
+
+    /**
+     * Set compiler hints for this function
+     * @param lc    lexical context
+     * @param hints compiler hints
+     * @return new function if hints changed
+     */
+    public FunctionNode setHints(final LexicalContext lc, final Compiler.Hints hints) {
+        if (this.hints == hints) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
     }
 
     /**
@@ -319,20 +422,6 @@
         return namespace.uniqueName(base);
     }
 
-    /**
-     * Create a virtual symbol for a literal.
-     *
-     * @param literalNode Primary node to use symbol.
-     *
-     * @return Symbol used.
-     */
-    public Symbol newLiteral(final LiteralNode<?> literalNode) {
-        final String uname = uniqueName(LITERAL_PREFIX.symbolName());
-        final Symbol symbol = new Symbol(uname, IS_CONSTANT, literalNode.getType());
-        literalNode.setSymbol(symbol);
-
-        return symbol;
-    }
 
     @Override
     public void toString(final StringBuilder sb) {
@@ -374,7 +463,7 @@
         if (this.flags == flags) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
     }
 
     @Override
@@ -483,7 +572,7 @@
         if(this.body == body) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
     }
 
     /**
@@ -551,7 +640,7 @@
         if (this.lastToken == lastToken) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
     }
 
     /**
@@ -599,13 +688,17 @@
     }
 
     /**
-     * Get a specialized type for an identity, if one exists
-     * @param node node to check specialized type for
-     * @return null if no specialization exists, otherwise type
+     * Reset the compile unit used to compile this function
+     * @see Compiler
+     * @param  lc lexical context
+     * @param  parameters the compile unit
+     * @return function node or a new one if state was changed
      */
-    @SuppressWarnings("static-method")
-    public Type getSpecializedType(final IdentNode node) {
-        return null; //TODO implement specialized types later
+    public FunctionNode setParameters(final LexicalContext lc, final List<IdentNode> parameters) {
+        if (this.parameters == parameters) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
     }
 
     /**
@@ -674,7 +767,10 @@
                     returnType),
                 compileUnit,
                 compilationState,
-                body));
+                body,
+                parameters,
+                snapshot,
+                hints));
     }
 
     /**
@@ -705,7 +801,7 @@
         if (this.compileUnit == compileUnit) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
     }
 
     /**
@@ -717,19 +813,6 @@
      *
      * @return Symbol used.
      */
-    public Symbol ensureSymbol(final Block block, final Type type, final Node node) {
-        Symbol symbol = node.getSymbol();
-
-        // If no symbol already present.
-        if (symbol == null) {
-            final String uname = uniqueName(TEMP_PREFIX.symbolName());
-            symbol = new Symbol(uname, IS_TEMP, type);
-            block.putSymbol(uname, symbol);
-            node.setSymbol(symbol);
-        }
-
-        return symbol;
-    }
 
     /**
      * Get the symbol for a compiler constant, or null if not available (yet)
@@ -739,5 +822,4 @@
     public Symbol compilerConstant(final CompilerConstants cc) {
         return body.getExistingSymbol(cc.symbolName());
     }
-
 }
--- a/src/jdk/nashorn/internal/ir/IdentNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/IdentNode.java	Tue May 14 11:16:52 2013 -0300
@@ -34,7 +34,6 @@
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for an identifier.
@@ -56,14 +55,13 @@
     /**
      * Constructor
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish position
      * @param name    name of identifier
      */
-    public IdentNode(final Source source, final long token, final int finish, final String name) {
-        super(source, token, finish);
-        this.name = name;
+    public IdentNode(final long token, final int finish, final String name) {
+        super(token, finish);
+        this.name = name.intern();
         this.callSiteType = null;
         this.flags = 0;
     }
@@ -103,7 +101,7 @@
     }
 
     @Override
-    public IdentNode setType(final Type type) {
+    public IdentNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
         // do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't
         if (this.callSiteType == type) {
             return this;
--- a/src/jdk/nashorn/internal/ir/IfNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/IfNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,13 +27,12 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for an IF statement.
  */
 @Immutable
-public final class IfNode extends Node {
+public final class IfNode extends Statement {
     /** Test expression. */
     private final Node test;
 
@@ -46,15 +45,15 @@
     /**
      * Constructor
      *
-     * @param source  the source
-     * @param token   token
-     * @param finish  finish
-     * @param test    test
-     * @param pass    block to execute when test passes
-     * @param fail    block to execute when test fails or null
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
+     * @param test       test
+     * @param pass       block to execute when test passes
+     * @param fail       block to execute when test fails or null
      */
-    public IfNode(final Source source, final long token, final int finish, final Node test, final Block pass, final Block fail) {
-        super(source, token, finish);
+    public IfNode(final int lineNumber, final long token, final int finish, final Node test, final Block pass, final Block fail) {
+        super(lineNumber, token, finish);
         this.test = test;
         this.pass = pass;
         this.fail = fail;
--- a/src/jdk/nashorn/internal/ir/IndexNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/IndexNode.java	Tue May 14 11:16:52 2013 -0300
@@ -28,7 +28,6 @@
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of an indexed access (brackets operator.)
@@ -41,14 +40,13 @@
     /**
      * Constructors
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param base    base node for access
      * @param index   index for access
      */
-    public IndexNode(final Source source, final long token, final int finish, final Node base, final Node index) {
-        super(source, token, finish, base, false, false);
+    public IndexNode(final long token, final int finish, final Node base, final Node index) {
+        super(token, finish, base, false, false);
         this.index = index;
     }
 
@@ -108,6 +106,18 @@
         return index;
     }
 
+    /**
+     * Set the index expression for this node
+     * @param index new index expression
+     * @return a node equivalent to this one except for the requested change.
+     */
+    public IndexNode setIndex(Node index) {
+        if(this.index == index) {
+            return this;
+        }
+        return new IndexNode(this, base, index, isFunction(), hasCallSiteType());
+    }
+
     @Override
     public BaseNode setIsFunction() {
         if (isFunction()) {
@@ -117,10 +127,10 @@
     }
 
     @Override
-    public IndexNode setType(final Type type) {
+    public IndexNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
         logTypeChange(type);
-        getSymbol().setTypeOverride(type); //always a temp so this is fine.
-        return new IndexNode(this, base, index, isFunction(), true);
+        final IndexNode newIndexNode = (IndexNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
+        return new IndexNode(newIndexNode, base, index, isFunction(), true);
     }
 
 }
--- a/src/jdk/nashorn/internal/ir/LabelNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/LabelNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,7 +27,6 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for a labeled statement.
@@ -43,14 +42,14 @@
     /**
      * Constructor
      *
-     * @param source the source
-     * @param token  token
-     * @param finish finish
-     * @param label  label identifier
-     * @param body   body of label node
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
+     * @param label      label identifier
+     * @param body       body of label node
      */
-    public LabelNode(final Source source, final long token, final int finish, final IdentNode label, final Block body) {
-        super(source, token, finish);
+    public LabelNode(final int lineNumber, final long token, final int finish, final IdentNode label, final Block body) {
+        super(lineNumber, token, finish);
 
         this.label = label;
         this.body  = body;
--- a/src/jdk/nashorn/internal/ir/LexicalContext.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/LexicalContext.java	Tue May 14 11:16:52 2013 -0300
@@ -64,7 +64,6 @@
             for (int i = sp - 1; i >= 0; i--) {
                 if (stack[i] == node) {
                     flags[i] |= flag;
-                    //System.err.println("Setting flag " + node + " " + flag);
                     return;
                 }
             }
@@ -117,8 +116,6 @@
         return (FunctionNode)stack[0];
     }
 
-
-
     /**
      * Pushes a new block on top of the context, making it the innermost open block.
      * @param node the new node
@@ -395,8 +392,7 @@
      */
     public boolean isFunctionDefinedInCurrentCall(FunctionNode functionNode) {
         final LexicalContextNode parent = stack[sp - 2];
-        if(parent instanceof CallNode && ((CallNode)parent).getFunction() == functionNode) {
-            assert functionNode.getSource() == peek().getSource();
+        if (parent instanceof CallNode && ((CallNode)parent).getFunction() == functionNode) {
             return true;
         }
         return false;
@@ -543,13 +539,16 @@
             sb.append('@');
             sb.append(Debug.id(node));
             sb.append(':');
-            final Source source = node.getSource();
-            String src = source.toString();
-            if (src.indexOf(File.pathSeparator) != -1) {
-                src = src.substring(src.lastIndexOf(File.pathSeparator));
+            if (node instanceof FunctionNode) {
+                final Source source = ((FunctionNode)node).getSource();
+                String src = source.toString();
+                if (src.indexOf(File.pathSeparator) != -1) {
+                    src = src.substring(src.lastIndexOf(File.pathSeparator));
+                }
+                src += ' ';
+                src += source.getLine(node.getStart());
+                sb.append(src);
             }
-            src += ' ';
-            src += source.getLine(node.getStart());
             sb.append(' ');
         }
         sb.append(" ==> ]");
--- a/src/jdk/nashorn/internal/ir/LexicalContextNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/LexicalContextNode.java	Tue May 14 11:16:52 2013 -0300
@@ -25,22 +25,21 @@
 package jdk.nashorn.internal.ir;
 
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * Superclass for nodes that can be part of the lexical context
  * @see LexicalContext
  */
-public abstract class LexicalContextNode extends Node {
+public abstract class LexicalContextNode extends Statement {
     /**
      * Constructor
      *
-     * @param source source
-     * @param token  token
-     * @param finish finish
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
      */
-    protected LexicalContextNode(final Source source, final long token, final int finish) {
-        super(source, token, finish);
+    protected LexicalContextNode(final int lineNumber, final long token, final int finish) {
+        super(lineNumber, token, finish);
     }
 
     /**
@@ -70,4 +69,16 @@
         final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor);
         return lc.pop(newNode);
     }
+
+    /**
+     * Set the symbol and replace in lexical context if applicable
+     * @param lc     lexical context
+     * @param symbol symbol
+     * @return new node if symbol changed
+     */
+    @Override
+    public Node setSymbol(final LexicalContext lc, final Symbol symbol) {
+        return Node.replaceInLexicalContext(lc, this, (LexicalContextNode)super.setSymbol(null, symbol));
+    }
+
 }
--- a/src/jdk/nashorn/internal/ir/LineNumberNode.java	Tue May 14 11:15:12 2013 -0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.ir;
-
-import jdk.nashorn.internal.ir.annotations.Immutable;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.parser.Token;
-import jdk.nashorn.internal.runtime.Source;
-
-/**
- * IR Node representing a line number
- */
-@Immutable
-public final class LineNumberNode extends Node {
-    /** Line number */
-    private final int lineNumber;
-
-    /**
-     * Constructor
-     *
-     * @param source     the source
-     * @param token      token
-     * @param lineNumber the line number
-     */
-    public LineNumberNode(final Source source, final long token, final int lineNumber) {
-        super(source, token, Token.descPosition(token));
-        this.lineNumber = lineNumber;
-    }
-
-    private LineNumberNode(final LineNumberNode lineNumberNode) {
-        super(lineNumberNode);
-        this.lineNumber = lineNumberNode.getLineNumber();
-    }
-
-    @Override
-    public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterLineNumberNode(this)) {
-            return visitor.leaveLineNumberNode(this);
-        }
-
-        return this;
-    }
-
-    @Override
-    public void toString(final StringBuilder sb) {
-        sb.append("[|");
-        sb.append(lineNumber);
-        sb.append("|]");
-    }
-
-    @Override
-    public boolean isAtom() {
-        return true;
-    }
-
-    /**
-     * Get the line number
-     * @return line number
-     */
-    public int getLineNumber() {
-        return lineNumber;
-    }
-
-    @Override
-    public boolean isDebug() {
-        return true;
-    }
-}
--- a/src/jdk/nashorn/internal/ir/LiteralNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/LiteralNode.java	Tue May 14 11:16:52 2013 -0300
@@ -37,7 +37,6 @@
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.Source;
 import jdk.nashorn.internal.runtime.Undefined;
 
 /**
@@ -50,16 +49,15 @@
     /** Literal value */
     protected final T value;
 
-     /**
+    /**
      * Constructor
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param value   the value of the literal
      */
-    protected LiteralNode(final Source source, final long token, final int finish, final T value) {
-        super(source, token, finish);
+    protected LiteralNode(final long token, final int finish, final T value) {
+        super(token, finish);
         this.value = value;
     }
 
@@ -238,14 +236,13 @@
     /**
      * Create a new null literal
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      *
      * @return the new literal node
      */
-    public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish) {
-        return new NodeLiteralNode(source, token, finish);
+    public static LiteralNode<Node> newInstance(final long token, final int finish) {
+        return new NodeLiteralNode(token, finish);
     }
 
     /**
@@ -256,14 +253,14 @@
      * @return the new literal node
      */
     public static LiteralNode<?> newInstance(final Node parent) {
-        return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish());
+        return new NodeLiteralNode(parent.getToken(), parent.getFinish());
     }
 
     @Immutable
     private static final class BooleanLiteralNode extends LiteralNode<Boolean> {
 
-        private BooleanLiteralNode(final Source source, final long token, final int finish, final boolean value) {
-            super(source, Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
+        private BooleanLiteralNode(final long token, final int finish, final boolean value) {
+            super(Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
         }
 
         private BooleanLiteralNode(final BooleanLiteralNode literalNode) {
@@ -289,15 +286,14 @@
     /**
      * Create a new boolean literal
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param value   true or false
      *
      * @return the new literal node
      */
-    public static LiteralNode<Boolean> newInstance(final Source source, final long token, final int finish, final boolean value) {
-        return new BooleanLiteralNode(source, token,  finish, value);
+    public static LiteralNode<Boolean> newInstance(final long token, final int finish, final boolean value) {
+        return new BooleanLiteralNode(token, finish, value);
     }
 
     /**
@@ -309,7 +305,7 @@
      * @return the new literal node
      */
     public static LiteralNode<?> newInstance(final Node parent, final boolean value) {
-        return new BooleanLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
+        return new BooleanLiteralNode(parent.getToken(), parent.getFinish(), value);
     }
 
     @Immutable
@@ -317,8 +313,8 @@
 
         private final Type type = numberGetType(value);
 
-        private NumberLiteralNode(final Source source, final long token, final int finish, final Number value) {
-            super(source, Token.recast(token, TokenType.DECIMAL), finish, value);
+        private NumberLiteralNode(final long token, final int finish, final Number value) {
+            super(Token.recast(token, TokenType.DECIMAL), finish, value);
         }
 
         private NumberLiteralNode(final NumberLiteralNode literalNode) {
@@ -353,15 +349,14 @@
     /**
      * Create a new number literal
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param value   literal value
      *
      * @return the new literal node
      */
-    public static LiteralNode<Number> newInstance(final Source source, final long token, final int finish, final Number value) {
-        return new NumberLiteralNode(source, token, finish, value);
+    public static LiteralNode<Number> newInstance(final long token, final int finish, final Number value) {
+        return new NumberLiteralNode(token, finish, value);
     }
 
     /**
@@ -373,12 +368,12 @@
      * @return the new literal node
      */
     public static LiteralNode<?> newInstance(final Node parent, final Number value) {
-        return new NumberLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
+        return new NumberLiteralNode(parent.getToken(), parent.getFinish(), value);
     }
 
     private static class UndefinedLiteralNode extends LiteralNode<Undefined> {
-        private UndefinedLiteralNode(final Source source, final long token, final int finish) {
-            super(source, Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
+        private UndefinedLiteralNode(final long token, final int finish) {
+            super(Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
         }
 
         private UndefinedLiteralNode(final UndefinedLiteralNode literalNode) {
@@ -389,15 +384,14 @@
     /**
      * Create a new undefined literal
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param value   undefined value, passed only for polymorphisism discrimination
      *
      * @return the new literal node
      */
-    public static LiteralNode<Undefined> newInstance(final Source source, final long token, final int finish, final Undefined value) {
-        return new UndefinedLiteralNode(source, token, finish);
+    public static LiteralNode<Undefined> newInstance(final long token, final int finish, final Undefined value) {
+        return new UndefinedLiteralNode(token, finish);
     }
 
     /**
@@ -409,13 +403,13 @@
      * @return the new literal node
      */
     public static LiteralNode<?> newInstance(final Node parent, final Undefined value) {
-        return new UndefinedLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish());
+        return new UndefinedLiteralNode(parent.getToken(), parent.getFinish());
     }
 
     @Immutable
     private static class StringLiteralNode extends LiteralNode<String> {
-        private StringLiteralNode(final Source source, final long token, final int finish, final String value) {
-            super(source, Token.recast(token, TokenType.STRING), finish, value);
+        private StringLiteralNode(final long token, final int finish, final String value) {
+            super(Token.recast(token, TokenType.STRING), finish, value);
         }
 
         private StringLiteralNode(final StringLiteralNode literalNode) {
@@ -433,15 +427,14 @@
     /**
      * Create a new string literal
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param value   string value
      *
      * @return the new literal node
      */
-    public static LiteralNode<String> newInstance(final Source source, final long token, final int finish, final String value) {
-        return new StringLiteralNode(source, token, finish, value);
+    public static LiteralNode<String> newInstance(final long token, final int finish, final String value) {
+        return new StringLiteralNode(token, finish, value);
     }
 
     /**
@@ -453,13 +446,13 @@
      * @return the new literal node
      */
     public static LiteralNode<?> newInstance(final Node parent, final String value) {
-        return new StringLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
+        return new StringLiteralNode(parent.getToken(), parent.getFinish(), value);
     }
 
     @Immutable
     private static class LexerTokenLiteralNode extends LiteralNode<LexerToken> {
-        private LexerTokenLiteralNode(final Source source, final long token, final int finish, final LexerToken value) {
-            super(source, Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here?
+        private LexerTokenLiteralNode(final long token, final int finish, final LexerToken value) {
+            super(Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here?
         }
 
         private LexerTokenLiteralNode(final LexerTokenLiteralNode literalNode) {
@@ -480,15 +473,14 @@
     /**
      * Create a new literal node for a lexer token
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param value   lexer token value
      *
      * @return the new literal node
      */
-    public static LiteralNode<LexerToken> newInstance(final Source source, final long token, final int finish, final LexerToken value) {
-        return new LexerTokenLiteralNode(source, token, finish, value);
+    public static LiteralNode<LexerToken> newInstance(final long token, final int finish, final LexerToken value) {
+        return new LexerTokenLiteralNode(token, finish, value);
     }
 
     /**
@@ -500,17 +492,17 @@
      * @return the new literal node
      */
     public static LiteralNode<?> newInstance(final Node parent, final LexerToken value) {
-        return new LexerTokenLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
+        return new LexerTokenLiteralNode(parent.getToken(), parent.getFinish(), value);
     }
 
     private static final class NodeLiteralNode extends LiteralNode<Node> {
 
-        private NodeLiteralNode(final Source source, final long token, final int finish) {
-            this(source, token, finish, null);
+        private NodeLiteralNode(final long token, final int finish) {
+            this(token, finish, null);
         }
 
-        private NodeLiteralNode(final Source source, final long token, final int finish, final Node value) {
-            super(source, Token.recast(token, TokenType.OBJECT), finish, value);
+        private NodeLiteralNode(final long token, final int finish, final Node value) {
+            super(Token.recast(token, TokenType.OBJECT), finish, value);
         }
 
         private NodeLiteralNode(final LiteralNode<Node> literalNode) {
@@ -550,15 +542,14 @@
     /**
      * Create a new node literal for an arbitrary node
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param value   the literal value node
      *
      * @return the new literal node
      */
-    public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish, final Node value) {
-        return new NodeLiteralNode(source, token, finish, value);
+    public static LiteralNode<Node> newInstance(final long token, final int finish, final Node value) {
+        return new NodeLiteralNode(token, finish, value);
     }
 
     /**
@@ -570,7 +561,7 @@
      * @return the new literal node
      */
     public static LiteralNode<?> newInstance(final Node parent, final Node value) {
-        return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
+        return new NodeLiteralNode(parent.getToken(), parent.getFinish(), value);
     }
 
     /**
@@ -645,13 +636,12 @@
         /**
          * Constructor
          *
-         * @param source  the source
          * @param token   token
          * @param finish  finish
          * @param value   array literal value, a Node array
          */
-        protected ArrayLiteralNode(final Source source, final long token, final int finish, final Node[] value) {
-            super(source, Token.recast(token, TokenType.ARRAY), finish, value);
+        protected ArrayLiteralNode(final long token, final int finish, final Node[] value) {
+            super(Token.recast(token, TokenType.ARRAY), finish, value);
             this.elementType = Type.UNKNOWN;
         }
 
@@ -659,9 +649,12 @@
          * Copy constructor
          * @param node source array literal node
          */
-        protected ArrayLiteralNode(final ArrayLiteralNode node) {
-            super(node);
+        private ArrayLiteralNode(final ArrayLiteralNode node, final Node[] value) {
+            super(node, value);
             this.elementType = node.elementType;
+            this.presets     = node.presets;
+            this.postsets    = node.postsets;
+            this.units       = node.units;
         }
 
         /**
@@ -750,9 +743,8 @@
                     break;
                 }
 
-                final Symbol symbol = node.getSymbol();
-                assert symbol != null; //don't run this on unresolved nodes or you are in trouble
-                Type symbolType = symbol.getSymbolType();
+                assert node.getSymbol() != null; //don't run this on unresolved nodes or you are in trouble
+                Type symbolType = node.getSymbol().getSymbolType();
                 if (symbolType.isUnknown()) {
                     symbolType = Type.OBJECT;
                 }
@@ -813,7 +805,8 @@
         }
 
         /**
-         * Get indices of arrays containing computed post sets
+         * Get indices of arrays containing computed post sets. post sets
+         * are things like non literals e.g. "x+y" instead of i or 17
          * @return post set indices
          */
         public int[] getPostsets() {
@@ -849,17 +842,17 @@
         @Override
         public Node accept(final NodeVisitor visitor) {
             if (visitor.enterLiteralNode(this)) {
-                for (int i = 0; i < value.length; i++) {
-                    final Node element = value[i];
-                    if (element != null) {
-                        value[i] = element.accept(visitor);
-                    }
-                }
-                return visitor.leaveLiteralNode(this);
+                final List<Node> oldValue = Arrays.asList(value);
+                final List<Node> newValue = Node.accept(visitor, Node.class, oldValue);
+                return visitor.leaveLiteralNode(oldValue != newValue ? setValue(newValue) : this);
             }
             return this;
         }
 
+        private ArrayLiteralNode setValue(final List<Node> value) {
+            return new ArrayLiteralNode(this, value.toArray(new Node[value.size()]));
+        }
+
         @Override
         public void toString(final StringBuilder sb) {
             sb.append('[');
@@ -883,15 +876,14 @@
     /**
      * Create a new array literal of Nodes from a list of Node values
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param value   literal value list
      *
      * @return the new literal node
      */
-    public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final List<Node> value) {
-        return new ArrayLiteralNode(source, token, finish, value.toArray(new Node[value.size()]));
+    public static LiteralNode<Node[]> newInstance(final long token, final int finish, final List<Node> value) {
+        return new ArrayLiteralNode(token, finish, value.toArray(new Node[value.size()]));
     }
 
 
@@ -904,20 +896,19 @@
      * @return the new literal node
      */
     public static LiteralNode<?> newInstance(final Node parent, final List<Node> value) {
-        return new ArrayLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value.toArray(new Node[value.size()]));
+        return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), value.toArray(new Node[value.size()]));
     }
 
     /**
      * Create a new array literal of Nodes
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param value   literal value array
      *
      * @return the new literal node
      */
-    public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final Node[] value) {
-        return new ArrayLiteralNode(source, token, finish, value);
+    public static LiteralNode<Node[]> newInstance(final long token, final int finish, final Node[] value) {
+        return new ArrayLiteralNode(token, finish, value);
     }
 }
--- a/src/jdk/nashorn/internal/ir/Location.java	Tue May 14 11:15:12 2013 -0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.ir;
-
-import jdk.nashorn.internal.parser.Token;
-import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.Source;
-
-/**
- * Used to locate an entity back to it's source file.
- */
-public class Location implements Cloneable {
-    /** Source of entity. */
-    private final Source source;
-
-    /** Token descriptor. */
-    private final long token;
-
-    /**
-     * Constructor
-     *
-     * @param source the source
-     * @param token  token
-     */
-    public Location(final Source source, final long token) {
-        this.source = source;
-        this.token = token;
-    }
-
-    /**
-     * Copy constructor
-     *
-     * @param location source node
-     */
-    protected Location(final Location location) {
-        this.source = location.source;
-        this.token = location.token;
-    }
-
-    @Override
-    protected Object clone() {
-        try {
-            return super.clone();
-        } catch(CloneNotSupportedException e) {
-            throw new AssertionError(e);
-        }
-    }
-
-    @Override
-    public final boolean equals(final Object other) {
-        return super.equals(other);
-    }
-
-    @Override
-    public final int hashCode() {
-        return super.hashCode();
-    }
-
-    /**
-     * Return token position from a token descriptor.
-     *
-     * @return Start position of the token in the source.
-     */
-    public int position() {
-        return Token.descPosition(token);
-    }
-
-    /**
-     * Return token length from a token descriptor.
-     *
-     * @return Length of the token.
-     */
-    public int length() {
-        return Token.descLength(token);
-    }
-
-    /**
-     * Return token tokenType from a token descriptor.
-     *
-     * @return Type of token.
-     */
-    public TokenType tokenType() {
-        return Token.descType(token);
-    }
-
-    /**
-     * Test token tokenType.
-     *
-     * @param type a type to check this token against
-     * @return true if token types match.
-     */
-    public boolean isTokenType(final TokenType type) {
-        return Token.descType(token) == type;
-    }
-
-    /**
-     * Get the source for this location
-     * @return the source
-     */
-    public Source getSource() {
-        return source;
-    }
-
-    /**
-     * Get the token for this location
-     * @return the token
-     */
-    public long getToken() {
-        return token;
-    }
-}
--- a/src/jdk/nashorn/internal/ir/LoopNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/LoopNode.java	Tue May 14 11:16:52 2013 -0300
@@ -29,7 +29,6 @@
 import java.util.List;
 
 import jdk.nashorn.internal.codegen.Label;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * A loop node, for example a while node, do while node or for node
@@ -50,15 +49,15 @@
     /**
      * Constructor
      *
-     * @param source  source
-     * @param token   token
-     * @param finish  finish
-     * @param test    test, or null if infinite loop
-     * @param body    loop body
+     * @param lineNumber         lineNumber
+     * @param token              token
+     * @param finish             finish
+     * @param test               test, or null if infinite loop
+     * @param body               loop body
      * @param controlFlowEscapes controlFlowEscapes
      */
-    protected LoopNode(final Source source, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
-        super(source, token, finish, new Label("while_break"));
+    protected LoopNode(final int lineNumber, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
+        super(lineNumber, token, finish, new Label("while_break"));
         this.continueLabel = new Label("while_continue");
         this.test = test;
         this.body = body;
--- a/src/jdk/nashorn/internal/ir/Node.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/Node.java	Tue May 14 11:16:52 2013 -0300
@@ -27,16 +27,15 @@
 
 import java.util.ArrayList;
 import java.util.List;
-
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.parser.Token;
-import jdk.nashorn.internal.runtime.Source;
+import jdk.nashorn.internal.parser.TokenType;
 
 /**
  * Nodes are used to compose Abstract Syntax Trees.
  */
-public abstract class Node extends Location {
+public abstract class Node implements Cloneable {
     /** Node symbol. */
     private Symbol symbol;
 
@@ -46,16 +45,17 @@
     /** End of source range. */
     protected int finish;
 
+    /** Token descriptor. */
+    private final long token;
+
     /**
      * Constructor
      *
-     * @param source the source
      * @param token  token
      * @param finish finish
      */
-    public Node(final Source source, final long token, final int finish) {
-        super(source, token);
-
+    public Node(final long token, final int finish) {
+        this.token  = token;
         this.start  = Token.descPosition(token);
         this.finish = finish;
     }
@@ -63,16 +63,14 @@
     /**
      * Constructor
      *
-     * @param source  source
      * @param token   token
      * @param start   start
      * @param finish  finish
      */
-    protected Node(final Source source, final long token, final int start, final int finish) {
-        super(source, token);
-
+    protected Node(final long token, final int start, final int finish) {
         this.start = start;
         this.finish = finish;
+        this.token = token;
     }
 
     /**
@@ -81,8 +79,7 @@
      * @param node source node
      */
     protected Node(final Node node) {
-        super(node);
-
+        this.token  = node.token;
         this.symbol = node.symbol;
         this.start  = node.start;
         this.finish = node.finish;
@@ -156,15 +153,6 @@
     }
 
     /**
-     * Is this a debug info node like LineNumberNode etc?
-     *
-     * @return true if this is a debug node
-     */
-    public boolean isDebug() {
-        return false;
-    }
-
-    /**
      * For reference copies - ensure that labels in the copy node are unique
      * using an appropriate copy constructor
      * @param lc lexical context
@@ -248,14 +236,86 @@
         return symbol;
     }
 
+    @Override
+    protected Object clone() {
+        try {
+            return super.clone();
+        } catch (final CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
+    }
+
     /**
      * Assign a symbol to this node. See {@link Node#getSymbol()} for explanation
      * of what a symbol is
      *
+     * @param lc lexical context
      * @param symbol the symbol
+     * @return new node
      */
-    public void setSymbol(final Symbol symbol) {
-        this.symbol = symbol;
+    public Node setSymbol(final LexicalContext lc, final Symbol symbol) {
+        if (this.symbol == symbol) {
+            return this;
+        }
+        final Node newNode = (Node)clone();
+        newNode.symbol = symbol;
+        return newNode;
+    }
+
+
+    @Override
+    public final boolean equals(final Object other) {
+        return super.equals(other);
+    }
+
+    @Override
+    public final int hashCode() {
+        return super.hashCode();
+    }
+
+    /**
+     * Return token position from a token descriptor.
+     *
+     * @return Start position of the token in the source.
+     */
+    public int position() {
+        return Token.descPosition(token);
+    }
+
+    /**
+     * Return token length from a token descriptor.
+     *
+     * @return Length of the token.
+     */
+    public int length() {
+        return Token.descLength(token);
+    }
+
+    /**
+     * Return token tokenType from a token descriptor.
+     *
+     * @return Type of token.
+     */
+    public TokenType tokenType() {
+        return Token.descType(token);
+    }
+
+    /**
+     * Test token tokenType.
+     *
+     * @param type a type to check this token against
+     * @return true if token types match.
+     */
+    public boolean isTokenType(final TokenType type) {
+        return Token.descType(token) == type;
+    }
+
+    /**
+     * Get the token for this location
+     * @return the token
+     */
+    public long getToken() {
+        return token;
     }
 
     /**
@@ -274,7 +334,7 @@
         final List<T> newList = new ArrayList<>();
 
         for (final Node node : list) {
-            final T newNode = clazz.cast(node.accept(visitor));
+            final T newNode = node == null ? null : clazz.cast(node.accept(visitor));
             if (newNode != node) {
                 changed = true;
             }
--- a/src/jdk/nashorn/internal/ir/ObjectNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/ObjectNode.java	Tue May 14 11:16:52 2013 -0300
@@ -30,7 +30,6 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of an object literal.
@@ -44,13 +43,12 @@
     /**
      * Constructor
      *
-     * @param source   the source
      * @param token    token
      * @param finish   finish
      * @param elements the elements used to initialize this ObjectNode
      */
-    public ObjectNode(final Source source, final long token, final int finish, final List<Node> elements) {
-        super(source, token, finish);
+    public ObjectNode(final long token, final int finish, final List<Node> elements) {
+        super(token, finish);
         this.elements = elements;
     }
 
--- a/src/jdk/nashorn/internal/ir/PropertyNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/PropertyNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,7 +27,6 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of an object literal property.
@@ -50,7 +49,6 @@
     /**
      * Constructor
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param key     the key of this property
@@ -58,8 +56,8 @@
      * @param getter  getter function body
      * @param setter  setter function body
      */
-    public PropertyNode(final Source source, final long token, final int finish, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
-        super(source, token, finish);
+    public PropertyNode(final long token, final int finish, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
+        super(token, finish);
         this.key    = key;
         this.value  = value;
         this.getter = getter;
--- a/src/jdk/nashorn/internal/ir/ReturnNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/ReturnNode.java	Tue May 14 11:16:52 2013 -0300
@@ -29,26 +29,25 @@
 import static jdk.nashorn.internal.parser.TokenType.YIELD;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for RETURN or YIELD statements.
  */
 @Immutable
-public class ReturnNode extends Node {
+public class ReturnNode extends Statement {
     /** Optional expression. */
     private final Node expression;
 
     /**
      * Constructor
      *
-     * @param source     the source
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param expression expression to return
      */
-    public ReturnNode(final Source source, final long token, final int finish, final Node expression) {
-        super(source, token, finish);
+    public ReturnNode(final int lineNumber, final long token, final int finish, final Node expression) {
+        super(lineNumber, token, finish);
         this.expression = expression;
     }
 
@@ -101,9 +100,9 @@
 
     @Override
     public void toString(final StringBuilder sb) {
-        sb.append(isYield() ? "yield" : "return ");
-
+        sb.append(isYield() ? "yield" : "return");
         if (expression != null) {
+            sb.append(' ');
             expression.toString(sb);
         }
     }
--- a/src/jdk/nashorn/internal/ir/RuntimeNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java	Tue May 14 11:16:52 2013 -0300
@@ -33,7 +33,6 @@
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for a runtime call.
@@ -280,14 +279,13 @@
     /**
      * Constructor
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param request the request
      * @param args    arguments to request
      */
-    public RuntimeNode(final Source source, final long token, final int finish, final Request request, final List<Node> args) {
-        super(source, token, finish);
+    public RuntimeNode(final long token, final int finish, final Request request, final List<Node> args) {
+        super(token, finish);
 
         this.request      = request;
         this.args         = args;
@@ -307,14 +305,13 @@
     /**
      * Constructor
      *
-     * @param source  the source
      * @param token   token
      * @param finish  finish
      * @param request the request
      * @param args    arguments to request
      */
-    public RuntimeNode(final Source source, final long token, final int finish, final Request request, final Node... args) {
-        this(source, token, finish, request, Arrays.asList(args));
+    public RuntimeNode(final long token, final int finish, final Request request, final Node... args) {
+        this(token, finish, request, Arrays.asList(args));
     }
 
     /**
@@ -393,7 +390,7 @@
     }
 
     @Override
-    public RuntimeNode setType(final Type type) {
+    public RuntimeNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
         if (this.callSiteType == type) {
             return this;
         }
--- a/src/jdk/nashorn/internal/ir/SplitNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/SplitNode.java	Tue May 14 11:16:52 2013 -0300
@@ -46,12 +46,13 @@
     /**
      * Constructor
      *
+     * @param lineNumber  lineNumber
      * @param name        name of split node
      * @param body        body of split code
      * @param compileUnit compile unit to use for the body
      */
-    public SplitNode(final String name, final Node body, final CompileUnit compileUnit) {
-        super(body.getSource(), body.getToken(), body.getFinish());
+    public SplitNode(final int lineNumber, final String name, final Node body, final CompileUnit compileUnit) {
+        super(lineNumber, body.getToken(), body.getFinish());
         this.name        = name;
         this.body        = body;
         this.compileUnit = compileUnit;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/ir/Statement.java	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir;
+
+/**
+ * Statement is something that becomes code and can be stepped past. A block is
+ * made up of statements. The only node subclass that needs to keep token and
+ * location information is the Statement
+ */
+public abstract class Statement extends Node {
+
+    private final int lineNumber;
+
+    /**
+     * Constructor
+     *
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
+     */
+    public Statement(final int lineNumber, final long token, final int finish) {
+        super(token, finish);
+        this.lineNumber = lineNumber;
+    }
+
+    /**
+     * Constructor
+     *
+     * @param lineNumber line number
+     * @param token      token
+     * @param start      start
+     * @param finish     finish
+     */
+    protected Statement(final int lineNumber, final long token, final int start, final int finish) {
+        super(token, start, finish);
+        this.lineNumber = lineNumber;
+    }
+
+    /**
+     * Copy constructor
+     *
+     * @param node source node
+     */
+    protected Statement(final Statement node) {
+        super(node);
+        this.lineNumber = node.lineNumber;
+    }
+
+    /**
+     * Return the line number
+     * @return line number
+     */
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+}
--- a/src/jdk/nashorn/internal/ir/SwitchNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/SwitchNode.java	Tue May 14 11:16:52 2013 -0300
@@ -32,7 +32,6 @@
 import jdk.nashorn.internal.codegen.Label;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of a SWITCH statement.
@@ -54,15 +53,15 @@
     /**
      * Constructor
      *
-     * @param source      the source
+     * @param lineNumber  lineNumber
      * @param token       token
      * @param finish      finish
      * @param expression  switch expression
      * @param cases       cases
      * @param defaultCase the default case node - null if none, otherwise has to be present in cases list
      */
-    public SwitchNode(final Source source, final long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) {
-        super(source, token, finish, new Label("switch_break"));
+    public SwitchNode(final int lineNumber, final long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) {
+        super(lineNumber, token, finish, new Label("switch_break"));
         this.expression       = expression;
         this.cases            = cases;
         this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);
--- a/src/jdk/nashorn/internal/ir/Symbol.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/Symbol.java	Tue May 14 11:16:52 2013 -0300
@@ -29,7 +29,6 @@
 import java.util.HashSet;
 import java.util.Set;
 import java.util.StringTokenizer;
-
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.Debug;
@@ -67,6 +66,10 @@
     public static final int IS_INTERNAL      = 1 << 9;
     /** Is this a function self-reference symbol */
     public static final int IS_FUNCTION_SELF = 1 << 10;
+    /** Is this a specialized param? */
+    public static final int IS_SPECIALIZED_PARAM = 1 << 11;
+    /** Is this symbol a shared temporary? */
+    public static final int IS_SHARED = 1 << 12;
 
     /** Null or name identifying symbol. */
     private final String name;
@@ -152,6 +155,16 @@
         this(name, flags, type, -1);
     }
 
+    private Symbol(final Symbol base, final String name, final int flags) {
+        this.flags = flags;
+        this.name = name;
+
+        this.fieldIndex = base.fieldIndex;
+        this.slot = base.slot;
+        this.type = base.type;
+        this.useCount = base.useCount;
+    }
+
     private static String align(final String string, final int max) {
         final StringBuilder sb = new StringBuilder();
         sb.append(string.substring(0, Math.min(string.length(), max)));
@@ -261,32 +274,14 @@
         return type.isCategory2() ? 2 : 1;
     }
 
-    private static String type(final String desc) {
-        switch (desc.charAt(desc.length() - 1)) {
-        case ';':
-            return desc;//"obj";
-        case 'D':
-            return "double";
-        case 'I':
-            return "int";
-        case 'J':
-            return "long";
-        case 'Z':
-            return "boolean";
-        default:
-            return "UNKNOWN";
-        }
-    }
-
     @Override
     public String toString() {
         final StringBuilder sb   = new StringBuilder();
-        final String        desc = getSymbolType().getDescriptor();
 
         sb.append(name).
             append(' ').
             append('(').
-            append(type(desc)).
+            append(getSymbolType().getTypeClass().getSimpleName()).
             append(')');
 
         if (hasSlot()) {
@@ -347,6 +342,24 @@
     }
 
     /**
+     * Returns true if this symbol is a temporary that is being shared across expressions.
+     * @return true if this symbol is a temporary that is being shared across expressions.
+     */
+    public boolean isShared() {
+        return (flags & IS_SHARED) == IS_SHARED;
+    }
+
+    /**
+     * Creates an unshared copy of a symbol. The symbol must be currently shared.
+     * @param newName the name for the new symbol.
+     * @return a new, unshared symbol.
+     */
+    public Symbol createUnshared(final String newName) {
+        assert isShared();
+        return new Symbol(this, newName, flags & ~IS_SHARED);
+    }
+
+    /**
      * Flag this symbol as scope as described in {@link Symbol#isScope()}
      */
     /**
@@ -355,10 +368,23 @@
      public void setIsScope() {
         if (!isScope()) {
             trace("SET IS SCOPE");
+            assert !isShared();
+            flags |= IS_SCOPE;
         }
-        flags |= IS_SCOPE;
     }
 
+     /**
+      * Mark this symbol as one being shared by multiple expressions. The symbol must be a temporary.
+      */
+     public void setIsShared() {
+         if(!isShared()) {
+             assert isTemp();
+             trace("SET IS SHARED");
+             flags |= IS_SHARED;
+         }
+     }
+
+
     /**
      * Check if this symbol is a variable
      * @return true if variable
@@ -384,6 +410,15 @@
     }
 
     /**
+     * Check if this symbol is a function parameter of known
+     * narrowest type
+     * @return true if parameter
+     */
+    public boolean isSpecializedParam() {
+        return (flags & IS_SPECIALIZED_PARAM) == IS_SPECIALIZED_PARAM;
+    }
+
+    /**
      * Check whether this symbol ever has primitive assignments. Conservative
      * @return true if primitive assignments exist
      */
@@ -404,7 +439,10 @@
      */
     public void setCanBeUndefined() {
         assert type.isObject() : type;
-        flags |= CAN_BE_UNDEFINED;
+        if(!canBeUndefined()) {
+            assert !isShared();
+            flags |= CAN_BE_UNDEFINED;
+        }
     }
 
     /**
@@ -412,7 +450,10 @@
      * @param type the primitive type it occurs with, currently unused but can be used for width guesses
      */
     public void setCanBePrimitive(final Type type) {
-        flags |= CAN_BE_PRIMITIVE;
+        if(!canBePrimitive()) {
+            assert !isShared();
+            flags |= CAN_BE_PRIMITIVE;
+        }
     }
 
     /**
@@ -452,7 +493,10 @@
      * Flag this symbol as a let
      */
     public void setIsLet() {
-        flags |= IS_LET;
+        if(!isLet()) {
+            assert !isShared();
+            flags |= IS_LET;
+        }
     }
 
     /**
@@ -481,7 +525,10 @@
      * @param fieldIndex field index - a positive integer
      */
     public void setFieldIndex(final int fieldIndex) {
-        this.fieldIndex = fieldIndex;
+        if(this.fieldIndex != fieldIndex) {
+            assert !isShared();
+            this.fieldIndex = fieldIndex;
+        }
     }
 
     /**
@@ -497,7 +544,10 @@
      * @param flags flags
      */
     public void setFlags(final int flags) {
-        this.flags = flags;
+        if(this.flags != flags) {
+            assert !isShared();
+            this.flags = flags;
+        }
     }
 
     /**
@@ -537,6 +587,7 @@
      */
     public void setSlot(final int slot) {
         if (slot != this.slot) {
+            assert !isShared();
             trace("SET SLOT " + slot);
             this.slot = slot;
         }
@@ -562,6 +613,15 @@
     }
 
     /**
+     * Returns true if calling {@link #setType(Type)} on this symbol would effectively change its type.
+     * @param newType the new type to test for
+     * @return true if setting this symbols type to a new value would effectively change its type.
+     */
+    public boolean wouldChangeType(final Type newType) {
+        return Type.widest(this.type, newType) != this.type;
+    }
+
+    /**
      * Only use this if you know about an existing type
      * constraint - otherwise a type can only be
      * widened
@@ -571,12 +631,33 @@
     public void setTypeOverride(final Type type) {
         final Type old = this.type;
         if (old != type) {
+            assert !isShared();
             trace("TYPE CHANGE: " + old + "=>" + type + " == " + type);
             this.type = type;
         }
     }
 
     /**
+     * Sets the type of the symbol to the specified type. If the type would be changed, but this symbol is a shared
+     * temporary, it will instead return a different temporary symbol of the requested type from the passed temporary
+     * symbols. That way, it never mutates the type of a shared temporary.
+     * @param type the new type for the symbol
+     * @param ts a holder of temporary symbols
+     * @return either this symbol, or a different symbol if this symbol is a shared temporary and it type would have to
+     * be changed.
+     */
+    public Symbol setTypeOverrideShared(final Type type, final TemporarySymbols ts) {
+        if(getSymbolType() != type) {
+            if(isShared()) {
+                assert !hasSlot();
+                return ts.getTypedTemporarySymbol(type);
+            }
+            setTypeOverride(type);
+        }
+        return this;
+    }
+
+    /**
      * From a lexical context, set this symbol as needing scope, which
      * will set flags for the defining block that will be written when
      * block is popped from the lexical context stack, used by codegen
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/ir/TemporarySymbols.java	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX;
+import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
+
+import java.util.HashMap;
+import java.util.Map;
+import jdk.nashorn.internal.codegen.types.Type;
+
+/**
+ * Class that holds reusable temporary symbols by type.
+ *
+ */
+public class TemporarySymbols {
+    private static final String prefix = TEMP_PREFIX.symbolName() + "$";
+
+    private int totalSymbolCount;
+    private final Map<Type, TypedTemporarySymbols> temporarySymbolsByType = new HashMap<>();
+
+    /**
+     * Associates a temporary symbol of a given type with a node, if the node doesn't already have any symbol.
+     * @param lc the current lexical context
+     * @param type the type of the temporary symbol
+     * @param node the node
+     * @return the node that is guaranteed to have a symbol.
+     */
+    public Node ensureSymbol(final LexicalContext lc, final Type type, final Node node) {
+        final Symbol symbol = node.getSymbol();
+        if (symbol != null) {
+            return node;
+        }
+        return node.setSymbol(lc, getTypedTemporarySymbol(type));
+    }
+
+    /**
+     * Given a type, returns a temporary symbol of that type.
+     * @param type the required type of the symbol.
+     * @return a temporary symbol of the required type.
+     */
+    public Symbol getTypedTemporarySymbol(final Type type) {
+        return getTypedTemporarySymbols(type).getTemporarySymbol(type);
+    }
+
+    private TypedTemporarySymbols getTypedTemporarySymbols(final Type type) {
+        TypedTemporarySymbols temporarySymbols = temporarySymbolsByType.get(type);
+        if(temporarySymbols == null) {
+            temporarySymbols = new TypedTemporarySymbols();
+            temporarySymbolsByType.put(type, temporarySymbols);
+        }
+        return temporarySymbols;
+    }
+
+    /**
+     * This method is called to signal to this object that all the symbols it holds can be reused now.
+     */
+    public void reuse() {
+        for(TypedTemporarySymbols ts: temporarySymbolsByType.values()) {
+            ts.reuse();
+        }
+    }
+
+    /**
+     * Given a shared symbol, creates an unshared copy of it with a unique name.
+     * @param symbol the shared symbol
+     * @return the unshared, uniquely named copy of the symbol
+     */
+    public Symbol createUnshared(Symbol symbol) {
+        return symbol.createUnshared(getUniqueName());
+    }
+
+    private String getUniqueName() {
+        return prefix + (++totalSymbolCount);
+    }
+
+    /**
+     * Returns the total number of symbols this object created during its lifetime.
+     * @return the total number of symbols this object created during its lifetime.
+     */
+    public int getTotalSymbolCount() {
+        return totalSymbolCount;
+    }
+
+    private class TypedTemporarySymbols {
+        private Symbol[] symbols = new Symbol[16];
+        private int nextFreeSymbol = 0;
+        private int symbolCount = 0;
+
+        Symbol getTemporarySymbol(final Type type) {
+            while(nextFreeSymbol < symbolCount) {
+                final Symbol nextSymbol = symbols[nextFreeSymbol];
+                assert nextSymbol != null;
+                // If it has a slot, we can't reuse it.
+                if(!nextSymbol.hasSlot()) {
+                    final Type symbolType = nextSymbol.getSymbolType();
+                    if(symbolType == type) {
+                        assert nextSymbol.isTemp();
+                        assert !nextSymbol.isScope();
+                        // If types match, we can reuse it.
+                        nextSymbol.setIsShared();
+                        nextFreeSymbol++;
+                        return nextSymbol;
+                    }
+                    // If its type changed, but it doesn't have a slot then move it to its new home according to its
+                    // new type.
+                    getTypedTemporarySymbols(symbolType).addSymbol(nextSymbol);
+                }
+                // If we can move another symbol into its place, do that and repeat the analysis for this symbol.
+                --symbolCount;
+                if(symbolCount != nextFreeSymbol) {
+                    final Symbol lastFreeSymbol = symbols[symbolCount];
+                    symbols[nextFreeSymbol] = lastFreeSymbol;
+                }
+                symbols[symbolCount] = null;
+            }
+            return createNewSymbol(type);
+        }
+
+        private Symbol createNewSymbol(final Type type) {
+            ensureCapacity();
+            final Symbol symbol = symbols[nextFreeSymbol] = new Symbol(getUniqueName(), IS_TEMP, type);
+            nextFreeSymbol++;
+            symbolCount++;
+            return symbol;
+        }
+
+        private void addSymbol(Symbol symbol) {
+            ensureCapacity();
+            symbols[symbolCount++] = symbol;
+        }
+
+        void reuse() {
+            nextFreeSymbol = 0;
+        }
+
+        private void ensureCapacity() {
+            if(symbolCount == symbols.length) {
+                final Symbol[] newSymbols = new Symbol[symbolCount * 2];
+                System.arraycopy(symbols, 0, newSymbols, 0, symbolCount);
+                symbols = newSymbols;
+            }
+        }
+    }
+
+}
--- a/src/jdk/nashorn/internal/ir/TernaryNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/TernaryNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,7 +27,6 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * TernaryNode nodes represent three operand operations (?:).
@@ -44,14 +43,13 @@
     /**
      * Constructor
      *
-     * @param source the source
      * @param token  token
      * @param lhs    left hand side node
      * @param rhs    right hand side node
      * @param third  third node
      */
-    public TernaryNode(final Source source, final long token, final Node lhs, final Node rhs, final Node third) {
-        super(source, token, third.getFinish());
+    public TernaryNode(final long token, final Node lhs, final Node rhs, final Node third) {
+        super(token, third.getFinish());
         this.lhs = lhs;
         this.rhs = rhs;
         this.third = third;
--- a/src/jdk/nashorn/internal/ir/ThrowNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/ThrowNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,31 +27,29 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for THROW statements.
  */
 @Immutable
-public final class ThrowNode extends Node {
+public final class ThrowNode extends Statement {
     /** Exception expression. */
     private final Node expression;
 
     /**
      * Constructor
      *
-     * @param source     the source
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param expression expression to throw
      */
-    public ThrowNode(final Source source, final long token, final int finish, final Node expression) {
-        super(source, token, finish);
-
+    public ThrowNode(final int lineNumber, final long token, final int finish, final Node expression) {
+        super(lineNumber, token, finish);
         this.expression = expression;
     }
 
-    private ThrowNode(final Node node, final Node expression) {
+    private ThrowNode(final ThrowNode node, final Node expression) {
         super(node);
         this.expression = expression;
     }
--- a/src/jdk/nashorn/internal/ir/TryNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/TryNode.java	Tue May 14 11:16:52 2013 -0300
@@ -32,13 +32,12 @@
 import jdk.nashorn.internal.codegen.Label;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of a TRY statement.
  */
 @Immutable
-public final class TryNode extends Node {
+public final class TryNode extends Statement {
     /** Try statements. */
     private final Block body;
 
@@ -60,27 +59,27 @@
     /**
      * Constructor
      *
-     * @param source      the source
+     * @param lineNumber  lineNumber
      * @param token       token
      * @param finish      finish
      * @param body        try node body
      * @param catchBlocks list of catch blocks in order
      * @param finallyBody body of finally block or null if none
      */
-    public TryNode(final Source source, final long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
-        super(source, token, finish);
-        this.body = body;
+    public TryNode(final int lineNumber, final long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
+        super(lineNumber, token, finish);
+        this.body        = body;
         this.catchBlocks = catchBlocks;
         this.finallyBody = finallyBody;
-        this.exit = new Label("exit");
+        this.exit        = new Label("exit");
     }
 
     private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
         super(tryNode);
-        this.body = body;
+        this.body        = body;
         this.catchBlocks = catchBlocks;
         this.finallyBody = finallyBody;
-        this.exit = new Label(tryNode.exit);
+        this.exit        = new Label(tryNode.exit);
     }
 
     @Override
--- a/src/jdk/nashorn/internal/ir/TypeOverride.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/TypeOverride.java	Tue May 14 11:16:52 2013 -0300
@@ -43,10 +43,12 @@
     /**
      * Set the override type
      *
-     * @param type  the type
+     * @param ts temporary symbols
+     * @param lc the current lexical context
+     * @param type the type
      * @return a node equivalent to this one except for the requested change.
      */
-    public T setType(final Type type);
+    public T setType(final TemporarySymbols ts, final LexicalContext lc, final Type type);
 
     /**
      * Returns true if this node can have a callsite override, e.g. all scope ident nodes
--- a/src/jdk/nashorn/internal/ir/UnaryNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/UnaryNode.java	Tue May 14 11:16:52 2013 -0300
@@ -35,7 +35,6 @@
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * UnaryNode nodes represent single operand operations.
@@ -48,24 +47,23 @@
     /**
      * Constructor
      *
-     * @param source the source
      * @param token  token
      * @param rhs    expression
      */
-    public UnaryNode(final Source source, final long token, final Node rhs) {
-        this(source, token, Math.min(rhs.getStart(), Token.descPosition(token)), Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()), rhs);
+    public UnaryNode(final long token, final Node rhs) {
+        this(token, Math.min(rhs.getStart(), Token.descPosition(token)), Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()), rhs);
     }
 
     /**
      * Constructor
-     * @param source the source
+     *
      * @param token  token
      * @param start  start
      * @param finish finish
      * @param rhs    expression
      */
-    public UnaryNode(final Source source, final long token, final int start, final int finish, final Node rhs) {
-        super(source, token, start, finish);
+    public UnaryNode(final long token, final int start, final int finish, final Node rhs) {
+        super(token, start, finish);
         this.rhs = rhs;
     }
 
--- a/src/jdk/nashorn/internal/ir/VarNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/VarNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,13 +27,12 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * Node represents a var/let declaration.
  */
 @Immutable
-public final class VarNode extends Node implements Assignment<IdentNode> {
+public final class VarNode extends Statement implements Assignment<IdentNode> {
     /** Var name. */
     private final IdentNode name;
 
@@ -54,14 +53,14 @@
     /**
      * Constructor
      *
-     * @param source the source
-     * @param token  token
-     * @param finish finish
-     * @param name   name of variable
-     * @param init   init node or null if just a declaration
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
+     * @param name       name of variable
+     * @param init       init node or null if just a declaration
      */
-    public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) {
-        this(source, token, finish, name, init, IS_STATEMENT);
+    public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init) {
+        this(lineNumber, token, finish, name, init, IS_STATEMENT);
     }
 
     private VarNode(final VarNode varNode, final IdentNode name, final Node init, final int flags) {
@@ -74,15 +73,15 @@
     /**
      * Constructor
      *
-     * @param source the source
-     * @param token  token
-     * @param finish finish
-     * @param name   name of variable
-     * @param init   init node or null if just a declaration
-     * @param flags  flags
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
+     * @param name       name of variable
+     * @param init       init node or null if just a declaration
+     * @param flags      flags
      */
-    public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, final int flags) {
-        super(source, token, finish);
+    public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init, final int flags) {
+        super(lineNumber, token, finish);
 
         this.name  = init == null ? name : name.setIsInitializedHere();
         this.init  = init;
--- a/src/jdk/nashorn/internal/ir/WhileNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/WhileNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,7 +27,6 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for a WHILE statement. This is the superclass of all
@@ -42,13 +41,13 @@
     /**
      * Constructor
      *
-     * @param source    the source
-     * @param token     token
-     * @param finish    finish
-     * @param isDoWhile is this a do while loop?
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
+     * @param isDoWhile  is this a do while loop?
      */
-    public WhileNode(final Source source, final long token, final int finish, final boolean isDoWhile) {
-        super(source, token, finish, null, null, false);
+    public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile) {
+        super(lineNumber, token, finish, null, null, false);
         this.isDoWhile = isDoWhile;
     }
 
@@ -135,17 +134,9 @@
 
     @Override
     public void toString(final StringBuilder sb) {
-        if (isDoWhile()) {
-            sb.append("do {");
-            body.toString(sb);
-            sb.append("} while (");
-            test.toString(sb);
-            sb.append(')');
-        } else {
-            sb.append("while (");
-            test.toString(sb);
-            sb.append(')');
-        }
+        sb.append("while (");
+        test.toString(sb);
+        sb.append(')');
     }
 
     @Override
--- a/src/jdk/nashorn/internal/ir/WithNode.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/WithNode.java	Tue May 14 11:16:52 2013 -0300
@@ -27,7 +27,6 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for {@code with} statements.
@@ -43,20 +42,18 @@
     /**
      * Constructor
      *
-     * @param source     the source
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      */
-    public WithNode(final Source source, final long token, final int finish) {
-        super(source, token, finish);
-
+    public WithNode(final int lineNumber, final long token, final int finish) {
+        super(lineNumber, token, finish);
         this.expression = null;
         this.body       = null;
     }
 
     private WithNode(final WithNode node, final Node expression, final Block body) {
         super(node);
-
         this.expression = expression;
         this.body       = body;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/ir/debug/ClassHistogramElement.java	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir.debug;
+
+import java.util.Comparator;
+
+/**
+ * Class histogram element for IR / Java object instrumentation
+ */
+public class ClassHistogramElement {
+    /**
+     * Instance comparator
+     */
+    public static final Comparator<ClassHistogramElement> COMPARE_INSTANCES = new Comparator<ClassHistogramElement>() {
+        @Override
+        public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
+            return (int)Math.abs(o1.instances - o2.instances);
+        }
+    };
+
+    /**
+     * Bytes comparator
+     */
+    public static final Comparator<ClassHistogramElement> COMPARE_BYTES = new Comparator<ClassHistogramElement>() {
+        @Override
+        public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
+            return (int)Math.abs(o1.bytes - o2.bytes);
+        }
+    };
+
+    /**
+     * Classname comparator
+     */
+    public static final Comparator<ClassHistogramElement> COMPARE_CLASSNAMES = new Comparator<ClassHistogramElement>() {
+        @Override
+        public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
+            return o1.clazz.getCanonicalName().compareTo(o2.clazz.getCanonicalName());
+        }
+    };
+
+    private final Class<?> clazz;
+    private long instances;
+    private long bytes;
+
+    /**
+     * Constructor
+     * @param clazz class for which to construct histogram
+     */
+    public ClassHistogramElement(final Class<?> clazz) {
+        this.clazz = clazz;
+    }
+
+    /**
+     * Add an instance
+     * @param sizeInBytes byte count
+     */
+    public void addInstance(final long sizeInBytes) {
+        instances++;
+        this.bytes += sizeInBytes;
+    }
+
+    /**
+     * Get size in bytes
+     * @return size in bytes
+     */
+    public long getBytes() {
+        return bytes;
+    }
+
+    /**
+     * Get class
+     * @return class
+     */
+    public Class<?> getClazz() {
+        return clazz;
+    }
+
+    /**
+     * Get number of instances
+     * @return number of instances
+     */
+    public long getInstances() {
+        return instances;
+    }
+
+    @Override
+    public String toString() {
+        return "ClassHistogramElement[class=" + clazz.getCanonicalName() + ", instances=" + instances + ", bytes=" + bytes + "]";
+    }
+}
--- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Tue May 14 11:16:52 2013 -0300
@@ -27,6 +27,7 @@
 
 import java.util.Arrays;
 import java.util.List;
+
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.BinaryNode;
@@ -44,7 +45,6 @@
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ObjectNode;
@@ -52,6 +52,7 @@
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.ThrowNode;
@@ -406,17 +407,15 @@
         }
 
         // body consists of nested functions and statements
-        final List<Node> stats = functionNode.getBody().getStatements();
+        final List<Statement> stats = functionNode.getBody().getStatements();
         final int size = stats.size();
         int idx = 0;
         arrayStart("body");
 
         for (final Node stat : stats) {
-            if (! stat.isDebug()) {
-                stat.accept(this);
-                if (idx != (size - 1)) {
-                    comma();
-                }
+            stat.accept(this);
+            if (idx != (size - 1)) {
+                comma();
             }
             idx++;
         }
@@ -504,11 +503,6 @@
         return leave();
     }
 
-    @Override
-    public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
-        return false;
-    }
-
     @SuppressWarnings("rawtypes")
     @Override
     public boolean enterLiteralNode(final LiteralNode literalNode) {
@@ -931,15 +925,13 @@
         int idx = 0;
         arrayStart(name);
         for (final Node node : nodes) {
-            if (node == null || !node.isDebug()) {
-                if (node != null) {
-                    node.accept(this);
-                } else {
-                    nullValue();
-                }
-                if (idx != (size - 1)) {
-                    comma();
-                }
+            if (node != null) {
+                node.accept(this);
+            } else {
+                nullValue();
+            }
+            if (idx != (size - 1)) {
+                comma();
             }
             idx++;
         }
@@ -971,7 +963,7 @@
             objectStart("loc");
 
             // source name
-            final Source src = node.getSource();
+            final Source src = getLexicalContext().getCurrentFunction().getSource();
             property("source", src.getName());
             comma();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir.debug;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryPoolMXBean;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Contains utility methods for calculating the memory usage of objects. It
+ * only works on the HotSpot JVM, and infers the actual memory layout (32 bit
+ * vs. 64 bit word size, compressed object pointers vs. uncompressed) from
+ * best available indicators. It can reliably detect a 32 bit vs. 64 bit JVM.
+ * It can only make an educated guess at whether compressed OOPs are used,
+ * though; specifically, it knows what the JVM's default choice of OOP
+ * compression would be based on HotSpot version and maximum heap sizes, but if
+ * the choice is explicitly overridden with the <tt>-XX:{+|-}UseCompressedOops</tt> command line
+ * switch, it can not detect
+ * this fact and will report incorrect sizes, as it will presume the default JVM
+ * behavior.
+ *
+ * @author Attila Szegedi
+ */
+public class ObjectSizeCalculator {
+
+    /**
+     * Describes constant memory overheads for various constructs in a JVM implementation.
+     */
+    public interface MemoryLayoutSpecification {
+
+        /**
+         * Returns the fixed overhead of an array of any type or length in this JVM.
+         *
+         * @return the fixed overhead of an array.
+         */
+        int getArrayHeaderSize();
+
+        /**
+         * Returns the fixed overhead of for any {@link Object} subclass in this JVM.
+         *
+         * @return the fixed overhead of any object.
+         */
+        int getObjectHeaderSize();
+
+        /**
+         * Returns the quantum field size for a field owned by an object in this JVM.
+         *
+         * @return the quantum field size for an object.
+         */
+        int getObjectPadding();
+
+        /**
+         * Returns the fixed size of an object reference in this JVM.
+         *
+         * @return the size of all object references.
+         */
+        int getReferenceSize();
+
+        /**
+         * Returns the quantum field size for a field owned by one of an object's ancestor superclasses
+         * in this JVM.
+         *
+         * @return the quantum field size for a superclass field.
+         */
+        int getSuperclassFieldPadding();
+    }
+
+    private static class CurrentLayout {
+        private static final MemoryLayoutSpecification SPEC =
+                getEffectiveMemoryLayoutSpecification();
+    }
+
+    /**
+     * Given an object, returns the total allocated size, in bytes, of the object
+     * and all other objects reachable from it.  Attempts to to detect the current JVM memory layout,
+     * but may fail with {@link UnsupportedOperationException};
+     *
+     * @param obj the object; can be null. Passing in a {@link java.lang.Class} object doesn't do
+     *          anything special, it measures the size of all objects
+     *          reachable through it (which will include its class loader, and by
+     *          extension, all other Class objects loaded by
+     *          the same loader, and all the parent class loaders). It doesn't provide the
+     *          size of the static fields in the JVM class that the Class object
+     *          represents.
+     * @return the total allocated size of the object and all other objects it
+     *         retains.
+     * @throws UnsupportedOperationException if the current vm memory layout cannot be detected.
+     */
+    public static long getObjectSize(final Object obj) throws UnsupportedOperationException {
+        return obj == null ? 0 : new ObjectSizeCalculator(CurrentLayout.SPEC).calculateObjectSize(obj);
+    }
+
+    // Fixed object header size for arrays.
+    private final int arrayHeaderSize;
+    // Fixed object header size for non-array objects.
+    private final int objectHeaderSize;
+    // Padding for the object size - if the object size is not an exact multiple
+    // of this, it is padded to the next multiple.
+    private final int objectPadding;
+    // Size of reference (pointer) fields.
+    private final int referenceSize;
+    // Padding for the fields of superclass before fields of subclasses are
+    // added.
+    private final int superclassFieldPadding;
+
+    private final Map<Class<?>, ClassSizeInfo> classSizeInfos = new IdentityHashMap<>();
+
+
+    private final Map<Object, Object> alreadyVisited = new IdentityHashMap<>();
+    private final Map<Class<?>, ClassHistogramElement> histogram = new IdentityHashMap<>();
+
+    private final Deque<Object> pending = new ArrayDeque<>(16 * 1024);
+    private long size;
+
+    /**
+     * Creates an object size calculator that can calculate object sizes for a given
+     * {@code memoryLayoutSpecification}.
+     *
+     * @param memoryLayoutSpecification a description of the JVM memory layout.
+     */
+    public ObjectSizeCalculator(final MemoryLayoutSpecification memoryLayoutSpecification) {
+        memoryLayoutSpecification.getClass();
+        arrayHeaderSize = memoryLayoutSpecification.getArrayHeaderSize();
+        objectHeaderSize = memoryLayoutSpecification.getObjectHeaderSize();
+        objectPadding = memoryLayoutSpecification.getObjectPadding();
+        referenceSize = memoryLayoutSpecification.getReferenceSize();
+        superclassFieldPadding = memoryLayoutSpecification.getSuperclassFieldPadding();
+    }
+
+    /**
+     * Given an object, returns the total allocated size, in bytes, of the object
+     * and all other objects reachable from it.
+     *
+     * @param obj the object; can be null. Passing in a {@link java.lang.Class} object doesn't do
+     *          anything special, it measures the size of all objects
+     *          reachable through it (which will include its class loader, and by
+     *          extension, all other Class objects loaded by
+     *          the same loader, and all the parent class loaders). It doesn't provide the
+     *          size of the static fields in the JVM class that the Class object
+     *          represents.
+     * @return the total allocated size of the object and all other objects it
+     *         retains.
+     */
+    public synchronized long calculateObjectSize(final Object obj) {
+        // Breadth-first traversal instead of naive depth-first with recursive
+        // implementation, so we don't blow the stack traversing long linked lists.
+        histogram.clear();
+        try {
+            for (Object o = obj;;) {
+                visit(o);
+                if (pending.isEmpty()) {
+                    return size;
+                }
+                o = pending.removeFirst();
+            }
+        } finally {
+            alreadyVisited.clear();
+            pending.clear();
+            size = 0;
+        }
+    }
+
+    /**
+     * Get the class histograpm
+     * @return class histogram element list
+     */
+    public List<ClassHistogramElement> getClassHistogram() {
+        return new ArrayList<>(histogram.values());
+    }
+
+    private ClassSizeInfo getClassSizeInfo(final Class<?> clazz) {
+        ClassSizeInfo csi = classSizeInfos.get(clazz);
+        if(csi == null) {
+            csi = new ClassSizeInfo(clazz);
+            classSizeInfos.put(clazz, csi);
+        }
+        return csi;
+    }
+
+    private void visit(final Object obj) {
+        if (alreadyVisited.containsKey(obj)) {
+            return;
+        }
+        final Class<?> clazz = obj.getClass();
+        if (clazz == ArrayElementsVisitor.class) {
+            ((ArrayElementsVisitor) obj).visit(this);
+        } else {
+            alreadyVisited.put(obj, obj);
+            if (clazz.isArray()) {
+                visitArray(obj);
+            } else {
+                getClassSizeInfo(clazz).visit(obj, this);
+            }
+        }
+    }
+
+    private void visitArray(final Object array) {
+        final Class<?> arrayClass = array.getClass();
+        final Class<?> componentType = arrayClass.getComponentType();
+        final int length = Array.getLength(array);
+        if (componentType.isPrimitive()) {
+            increaseByArraySize(arrayClass, length, getPrimitiveFieldSize(componentType));
+        } else {
+            increaseByArraySize(arrayClass, length, referenceSize);
+            // If we didn't use an ArrayElementsVisitor, we would be enqueueing every
+            // element of the array here instead. For large arrays, it would
+            // tremendously enlarge the queue. In essence, we're compressing it into
+            // a small command object instead. This is different than immediately
+            // visiting the elements, as their visiting is scheduled for the end of
+            // the current queue.
+            switch (length) {
+            case 0: {
+                break;
+            }
+            case 1: {
+                enqueue(Array.get(array, 0));
+                break;
+            }
+            default: {
+                enqueue(new ArrayElementsVisitor((Object[]) array));
+            }
+            }
+        }
+    }
+
+    private void increaseByArraySize(final Class<?> clazz, final int length, final long elementSize) {
+        increaseSize(clazz, roundTo(arrayHeaderSize + length * elementSize, objectPadding));
+    }
+
+    private static class ArrayElementsVisitor {
+        private final Object[] array;
+
+        ArrayElementsVisitor(final Object[] array) {
+            this.array = array;
+        }
+
+        public void visit(final ObjectSizeCalculator calc) {
+            for (final Object elem : array) {
+                if (elem != null) {
+                    calc.visit(elem);
+                }
+            }
+        }
+    }
+
+    void enqueue(final Object obj) {
+        if (obj != null) {
+            pending.addLast(obj);
+        }
+    }
+
+    void increaseSize(final Class<?> clazz, final long objectSize) {
+        ClassHistogramElement he = histogram.get(clazz);
+        if(he == null) {
+            he = new ClassHistogramElement(clazz);
+            histogram.put(clazz, he);
+        }
+        he.addInstance(objectSize);
+        size += objectSize;
+    }
+
+    static long roundTo(final long x, final int multiple) {
+        return ((x + multiple - 1) / multiple) * multiple;
+    }
+
+    private class ClassSizeInfo {
+        // Padded fields + header size
+        private final long objectSize;
+        // Only the fields size - used to calculate the subclasses' memory
+        // footprint.
+        private final long fieldsSize;
+        private final Field[] referenceFields;
+
+        public ClassSizeInfo(final Class<?> clazz) {
+            long newFieldsSize = 0;
+            final List<Field> newReferenceFields = new LinkedList<>();
+            for (Field f : clazz.getDeclaredFields()) {
+                if (Modifier.isStatic(f.getModifiers())) {
+                    continue;
+                }
+                final Class<?> type = f.getType();
+                if (type.isPrimitive()) {
+                    newFieldsSize += getPrimitiveFieldSize(type);
+                } else {
+                    f.setAccessible(true);
+                    newReferenceFields.add(f);
+                    newFieldsSize += referenceSize;
+                }
+            }
+            final Class<?> superClass = clazz.getSuperclass();
+            if (superClass != null) {
+                final ClassSizeInfo superClassInfo = getClassSizeInfo(superClass);
+                newFieldsSize += roundTo(superClassInfo.fieldsSize, superclassFieldPadding);
+                newReferenceFields.addAll(Arrays.asList(superClassInfo.referenceFields));
+            }
+            this.fieldsSize = newFieldsSize;
+            this.objectSize = roundTo(objectHeaderSize + newFieldsSize, objectPadding);
+            this.referenceFields = newReferenceFields.toArray(
+                    new Field[newReferenceFields.size()]);
+        }
+
+        void visit(final Object obj, final ObjectSizeCalculator calc) {
+            calc.increaseSize(obj.getClass(), objectSize);
+            enqueueReferencedObjects(obj, calc);
+        }
+
+        public void enqueueReferencedObjects(final Object obj, final ObjectSizeCalculator calc) {
+            for (Field f : referenceFields) {
+                try {
+                    calc.enqueue(f.get(obj));
+                } catch (IllegalAccessException e) {
+                    final AssertionError ae = new AssertionError(
+                            "Unexpected denial of access to " + f);
+                    ae.initCause(e);
+                    throw ae;
+                }
+            }
+        }
+    }
+
+    private static long getPrimitiveFieldSize(final Class<?> type) {
+        if (type == boolean.class || type == byte.class) {
+            return 1;
+        }
+        if (type == char.class || type == short.class) {
+            return 2;
+        }
+        if (type == int.class || type == float.class) {
+            return 4;
+        }
+        if (type == long.class || type == double.class) {
+            return 8;
+        }
+        throw new AssertionError("Encountered unexpected primitive type " +
+                type.getName());
+    }
+
+    /**
+     * Return the current memory usage
+     * @return current memory usage derived from system configuration
+     */
+    public static MemoryLayoutSpecification getEffectiveMemoryLayoutSpecification() {
+        final String vmName = System.getProperty("java.vm.name");
+        if (vmName == null || !vmName.startsWith("Java HotSpot(TM) ")) {
+            throw new UnsupportedOperationException(
+                    "ObjectSizeCalculator only supported on HotSpot VM");
+        }
+
+        final String dataModel = System.getProperty("sun.arch.data.model");
+        if ("32".equals(dataModel)) {
+            // Running with 32-bit data model
+            return new MemoryLayoutSpecification() {
+                @Override public int getArrayHeaderSize() {
+                    return 12;
+                }
+                @Override public int getObjectHeaderSize() {
+                    return 8;
+                }
+                @Override public int getObjectPadding() {
+                    return 8;
+                }
+                @Override public int getReferenceSize() {
+                    return 4;
+                }
+                @Override public int getSuperclassFieldPadding() {
+                    return 4;
+                }
+            };
+        } else if (!"64".equals(dataModel)) {
+            throw new UnsupportedOperationException("Unrecognized value '" +
+                    dataModel + "' of sun.arch.data.model system property");
+        }
+
+        final String strVmVersion = System.getProperty("java.vm.version");
+        final int vmVersion = Integer.parseInt(strVmVersion.substring(0,
+                strVmVersion.indexOf('.')));
+        if (vmVersion >= 17) {
+            long maxMemory = 0;
+            for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) {
+                maxMemory += mp.getUsage().getMax();
+            }
+            if (maxMemory < 30L * 1024 * 1024 * 1024) {
+                // HotSpot 17.0 and above use compressed OOPs below 30GB of RAM total
+                // for all memory pools (yes, including code cache).
+                return new MemoryLayoutSpecification() {
+                    @Override public int getArrayHeaderSize() {
+                        return 16;
+                    }
+                    @Override public int getObjectHeaderSize() {
+                        return 12;
+                    }
+                    @Override public int getObjectPadding() {
+                        return 8;
+                    }
+                    @Override public int getReferenceSize() {
+                        return 4;
+                    }
+                    @Override public int getSuperclassFieldPadding() {
+                        return 4;
+                    }
+                };
+            }
+        }
+
+        // In other cases, it's a 64-bit uncompressed OOPs object model
+        return new MemoryLayoutSpecification() {
+            @Override public int getArrayHeaderSize() {
+                return 24;
+            }
+            @Override public int getObjectHeaderSize() {
+                return 16;
+            }
+            @Override public int getObjectPadding() {
+                return 8;
+            }
+            @Override public int getReferenceSize() {
+                return 8;
+            }
+            @Override public int getSuperclassFieldPadding() {
+                return 8;
+            }
+        };
+    }
+}
--- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java	Tue May 14 11:16:52 2013 -0300
@@ -36,9 +36,9 @@
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.TryNode;
@@ -55,7 +55,7 @@
  */
 public final class PrintVisitor extends NodeVisitor {
     /** Tab width */
-    private static final int TABWIDTH = 1;
+    private static final int TABWIDTH = 4;
 
     /** Composing buffer. */
     private final StringBuilder sb;
@@ -69,6 +69,8 @@
     /** Print line numbers */
     private final boolean printLineNumbers;
 
+    private int lastLineNumber = -1;
+
     /**
      * Constructor.
      */
@@ -138,24 +140,27 @@
     @Override
     public boolean enterBlock(final Block block) {
         sb.append(' ');
+        //sb.append(Debug.id(block));
         sb.append('{');
 
         indent += TABWIDTH;
 
-        final List<Node> statements = block.getStatements();
-
-        boolean lastLineNumber = false;
+        final List<Statement> statements = block.getStatements();
 
         for (final Node statement : statements) {
-            if (printLineNumbers || !lastLineNumber) {
-                sb.append(EOLN);
-                indent();
+            if (printLineNumbers && (statement instanceof Statement)) {
+                final int lineNumber = ((Statement)statement).getLineNumber();
+                sb.append('\n');
+                if (lineNumber != lastLineNumber) {
+                    indent();
+                    sb.append("[|").append(lineNumber).append("|];").append('\n');
+                }
+                lastLineNumber = lineNumber;
             }
+            indent();
 
             statement.accept(this);
 
-            lastLineNumber = statement instanceof LineNumberNode;
-
             if (statement instanceof FunctionNode) {
                 continue;
             }
@@ -168,12 +173,14 @@
                 sb.append(']');
             }
 
-            final char lastChar = sb.charAt(sb.length() - 1);
+            int  lastIndex = sb.length() - 1;
+            char lastChar  = sb.charAt(lastIndex);
+            while (Character.isWhitespace(lastChar) && lastIndex >= 0) {
+                lastChar = sb.charAt(--lastIndex);
+            }
 
             if (lastChar != '}' && lastChar != ';') {
-                if (printLineNumbers || !lastLineNumber) {
-                    sb.append(';');
-                }
+                sb.append(';');
             }
 
             if (statement.hasGoto()) {
@@ -189,7 +196,8 @@
 
         sb.append(EOLN);
         indent();
-        sb.append("}");
+        sb.append('}');
+       // sb.append(Debug.id(block));
 
         return false;
     }
@@ -221,7 +229,7 @@
     public boolean enterFunctionNode(final FunctionNode functionNode) {
         functionNode.toString(sb);
         enterBlock(functionNode.getBody());
-        sb.append(EOLN);
+        //sb.append(EOLN);
         return false;
     }
 
@@ -252,15 +260,6 @@
     }
 
     @Override
-    public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
-        if (printLineNumbers) {
-            lineNumberNode.toString(sb);
-        }
-
-        return false;
-    }
-
-    @Override
     public boolean enterSplitNode(final SplitNode splitNode) {
         splitNode.toString(sb);
         sb.append(EOLN);
@@ -334,6 +333,7 @@
             sb.append(" = ");
             init.accept(this);
         }
+
         return false;
     }
 
--- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Tue May 14 11:16:52 2013 -0300
@@ -149,7 +149,7 @@
             return enterASSIGN_SUB(binaryNode);
         case BIND:
             return enterBIND(binaryNode);
-         case BIT_AND:
+        case BIT_AND:
             return enterBIT_AND(binaryNode);
         case BIT_OR:
             return enterBIT_OR(binaryNode);
--- a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Tue May 14 11:16:52 2013 -0300
@@ -42,7 +42,6 @@
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.LabelNode;
 import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ObjectNode;
@@ -454,26 +453,6 @@
     }
 
     /**
-     * Callback for entering a LineNumberNode
-     *
-     * @param  lineNumberNode the node
-     * @return true if traversal should continue and node children be traversed, false otherwise
-     */
-    public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
-        return enterDefault(lineNumberNode);
-    }
-
-    /**
-     * Callback for leaving a LineNumberNode
-     *
-     * @param  lineNumberNode the node
-     * @return processed node, which will replace the original one, or the original node
-     */
-    public Node leaveLineNumberNode(final LineNumberNode lineNumberNode) {
-        return leaveDefault(lineNumberNode);
-    }
-
-    /**
      * Callback for entering a LiteralNode
      *
      * @param  literalNode the node
--- a/src/jdk/nashorn/internal/objects/NativeArray.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/objects/NativeArray.java	Tue May 14 11:16:52 2013 -0300
@@ -297,7 +297,7 @@
     @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
     public static Object length(final Object self) {
         if (isArray(self)) {
-            return ((NativeArray) self).getArray().length() & JSType.MAX_UINT;
+            return ((ScriptObject) self).getArray().length() & JSType.MAX_UINT;
         }
 
         return 0;
@@ -311,7 +311,7 @@
     @Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
     public static void length(final Object self, final Object length) {
         if (isArray(self)) {
-            ((NativeArray) self).setLength(validLength(length, true));
+            ((ScriptObject) self).setLength(validLength(length, true));
         }
     }
 
@@ -642,10 +642,9 @@
             final boolean      strict = sobj.isStrictContext();
 
             if (bulkable(sobj)) {
-                final NativeArray nativeArray = (NativeArray)sobj;
-                if (nativeArray.getArray().length() + args.length <= JSType.MAX_UINT) {
-                    final ArrayData newData = nativeArray.getArray().push(nativeArray.isStrictContext(), args);
-                    nativeArray.setArray(newData);
+                if (sobj.getArray().length() + args.length <= JSType.MAX_UINT) {
+                    final ArrayData newData = sobj.getArray().push(sobj.isStrictContext(), args);
+                    sobj.setArray(newData);
                     return newData.length();
                 }
                 //fallthru
@@ -780,8 +779,7 @@
         }
 
         if (bulkable(sobj)) {
-            final NativeArray narray = (NativeArray) sobj;
-            return new NativeArray(narray.getArray().slice(k, finale));
+            return new NativeArray(sobj.getArray().slice(k, finale));
         }
 
         final NativeArray copy = new NativeArray(0);
@@ -1001,11 +999,10 @@
         }
 
         if (bulkable(sobj)) {
-            final NativeArray nativeArray = (NativeArray) sobj;
-            nativeArray.getArray().shiftRight(items.length);
+            sobj.getArray().shiftRight(items.length);
 
             for (int j = 0; j < items.length; j++) {
-                nativeArray.setArray(nativeArray.getArray().set(j, items[j], sobj.isStrictContext()));
+                sobj.setArray(sobj.getArray().set(j, items[j], sobj.isStrictContext()));
             }
         } else {
             for (long k = len; k > 0; k--) {
--- a/src/jdk/nashorn/internal/objects/NativeRegExp.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java	Tue May 14 11:16:52 2013 -0300
@@ -794,15 +794,15 @@
 
         RegExpResult match;
         final int inputLength = string.length();
-        int lastLength = -1;
-        int lastIndex = 0;
-        int lastLastIndex = 0;
+        int splitLastLength = -1;
+        int splitLastIndex = 0;
+        int splitLastLastIndex = 0;
 
-        while ((match = execSplit(string, lastIndex)) != null) {
-            lastIndex = match.getIndex() + match.length();
+        while ((match = execSplit(string, splitLastIndex)) != null) {
+            splitLastIndex = match.getIndex() + match.length();
 
-            if (lastIndex > lastLastIndex) {
-                matches.add(string.substring(lastLastIndex, match.getIndex()));
+            if (splitLastIndex > splitLastLastIndex) {
+                matches.add(string.substring(splitLastLastIndex, match.getIndex()));
                 final Object[] groups = match.getGroups();
                 if (groups.length > 1 && match.getIndex() < inputLength) {
                     for (int index = 1; index < groups.length && matches.size() < limit; index++) {
@@ -810,7 +810,7 @@
                     }
                 }
 
-                lastLength = match.length();
+                splitLastLength = match.length();
 
                 if (matches.size() >= limit) {
                     break;
@@ -818,10 +818,10 @@
             }
 
             // bump the index to avoid infinite loop
-            if (lastIndex == lastLastIndex) {
-                lastIndex++;
+            if (splitLastIndex == splitLastLastIndex) {
+                splitLastIndex++;
             } else {
-                lastLastIndex = lastIndex;
+                splitLastLastIndex = splitLastIndex;
             }
         }
 
@@ -829,12 +829,12 @@
             // check special case if we need to append an empty string at the
             // end of the match
             // if the lastIndex was the entire string
-            if (lastLastIndex == string.length()) {
-                if (lastLength > 0 || execSplit("", 0) == null) {
+            if (splitLastLastIndex == string.length()) {
+                if (splitLastLength > 0 || execSplit("", 0) == null) {
                     matches.add("");
                 }
             } else {
-                matches.add(string.substring(lastLastIndex, inputLength));
+                matches.add(string.substring(splitLastLastIndex, inputLength));
             }
         }
 
@@ -899,10 +899,6 @@
         }
     }
 
-    private void setGlobal(final boolean global) {
-        regexp.setGlobal(global);
-    }
-
     boolean getGlobal() {
         return regexp.isGlobal();
     }
--- a/src/jdk/nashorn/internal/parser/AbstractParser.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/parser/AbstractParser.java	Tue May 14 11:16:52 2013 -0300
@@ -249,6 +249,7 @@
      *
      * @param errorType  The error type of the warning
      * @param message    Warning message.
+     * @param errorToken error token
      */
     protected final void warning(final JSErrorType errorType, final String message, final long errorToken) {
         errors.warning(error(errorType, message, errorToken));
@@ -363,7 +364,7 @@
             next();
 
             // Create IDENT node.
-            return new IdentNode(source, identToken, finish, ident);
+            return new IdentNode(identToken, finish, ident);
         }
 
         // Get IDENT.
@@ -372,7 +373,7 @@
             return null;
         }
         // Create IDENT node.
-        return new IdentNode(source, identToken, finish, ident);
+        return new IdentNode(identToken, finish, ident);
     }
 
     /**
@@ -407,7 +408,7 @@
             final String ident = (String)getValue(identToken);
             next();
             // Create IDENT node.
-            return new IdentNode(source, identToken, finish, ident);
+            return new IdentNode(identToken, finish, ident);
         } else {
             expect(IDENT);
             return null;
@@ -432,11 +433,11 @@
         LiteralNode<?> node = null;
 
         if (value == null) {
-            node = LiteralNode.newInstance(source, literalToken, finish);
+            node = LiteralNode.newInstance(literalToken, finish);
         } else if (value instanceof Number) {
-            node = LiteralNode.newInstance(source, literalToken, finish, (Number)value);
+            node = LiteralNode.newInstance(literalToken, finish, (Number)value);
         } else if (value instanceof String) {
-            node = LiteralNode.newInstance(source, literalToken, finish, (String)value);
+            node = LiteralNode.newInstance(literalToken, finish, (String)value);
         } else if (value instanceof LexerToken) {
             if (value instanceof RegexToken) {
                 final RegexToken regex = (RegexToken)value;
@@ -446,7 +447,7 @@
                     throw error(e.getMessage());
                 }
             }
-            node = LiteralNode.newInstance(source, literalToken, finish, (LexerToken)value);
+            node = LiteralNode.newInstance(literalToken, finish, (LexerToken)value);
         } else {
             assert false : "unknown type for LiteralNode: " + value.getClass();
         }
--- a/src/jdk/nashorn/internal/parser/JSONParser.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/parser/JSONParser.java	Tue May 14 11:16:52 2013 -0300
@@ -193,13 +193,13 @@
             return getLiteral();
         case FALSE:
             next();
-            return LiteralNode.newInstance(source, literalToken, finish, false);
+            return LiteralNode.newInstance(literalToken, finish, false);
         case TRUE:
             next();
-            return LiteralNode.newInstance(source, literalToken, finish, true);
+            return LiteralNode.newInstance(literalToken, finish, true);
         case NULL:
             next();
-            return LiteralNode.newInstance(source, literalToken, finish);
+            return LiteralNode.newInstance(literalToken, finish);
         case LBRACKET:
             return arrayLiteral();
         case LBRACE:
@@ -218,7 +218,7 @@
 
             if (value instanceof Number) {
                 next();
-                return new UnaryNode(source, literalToken, LiteralNode.newInstance(source, realToken, finish, (Number)value));
+                return new UnaryNode(literalToken, LiteralNode.newInstance(realToken, finish, (Number)value));
             }
 
             throw error(AbstractParser.message("expected", "number", type.getNameOrType()));
@@ -250,7 +250,7 @@
             switch (type) {
             case RBRACKET:
                 next();
-                result = LiteralNode.newInstance(source, arrayToken, finish, elements);
+                result = LiteralNode.newInstance(arrayToken, finish, elements);
                 break loop;
 
             case COMMARIGHT:
@@ -310,7 +310,7 @@
         }
 
         // Construct new object literal.
-        return new ObjectNode(source, objectToken, finish, elements);
+        return new ObjectNode(objectToken, finish, elements);
     }
 
     /**
@@ -331,7 +331,7 @@
         if (name != null) {
             expect(COLON);
             final Node value = jsonLiteral();
-            return new PropertyNode(source, propertyToken, value.getFinish(), name, value, null, null);
+            return new PropertyNode(propertyToken, value.getFinish(), name, value, null, null);
         }
 
         // Raise an error.
--- a/src/jdk/nashorn/internal/parser/Parser.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/parser/Parser.java	Tue May 14 11:16:52 2013 -0300
@@ -59,9 +59,11 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.Namespace;
 import jdk.nashorn.internal.ir.AccessNode;
+import jdk.nashorn.internal.ir.BaseNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.BlockLexicalContext;
@@ -81,7 +83,6 @@
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.LabelNode;
 import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LoopNode;
 import jdk.nashorn.internal.ir.Node;
@@ -90,6 +91,7 @@
 import jdk.nashorn.internal.ir.PropertyNode;
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
+import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.ThrowNode;
@@ -117,7 +119,7 @@
     /** Is scripting mode. */
     private final boolean scripting;
 
-    private List<Node> functionDeclarations;
+    private List<Statement> functionDeclarations;
 
     private final BlockLexicalContext lc = new BlockLexicalContext();
 
@@ -275,8 +277,7 @@
      * @return New block.
      */
     private Block newBlock() {
-        final Block block = new Block(source, token, Token.descPosition(token));
-        return lc.push(block);
+        return lc.push(new Block(line, token, Token.descPosition(token)));
     }
 
     /**
@@ -305,11 +306,17 @@
         if (isStrictMode) {
             flags |= FunctionNode.IS_STRICT;
         }
+        if (env._specialize_calls != null) {
+            if (env._specialize_calls.contains(name)) {
+                flags |= FunctionNode.CAN_SPECIALIZE;
+            }
+        }
 
         // Start new block.
         FunctionNode functionNode =
             new FunctionNode(
                 source,
+                line, //TODO?
                 token,
                 Token.descPosition(token),
                 startToken,
@@ -320,11 +327,11 @@
                 kind,
                 flags);
 
-        functionNode = functionNode.setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
         lc.push(functionNode);
         // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
         // FunctionNode.
         newBlock();
+
         return functionNode;
     }
 
@@ -332,14 +339,19 @@
      * Restore the current block.
      */
     private Block restoreBlock(final Block block) {
-        return lc.pop(block);//.setFlag(lc, flags);
+        return lc.pop(block);
     }
 
+
     private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
         final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
 
-        return lc.pop(functionNode).setBody(lc, newBody).setLastToken(lc, lastToken);
-    }
+        return lc.pop(functionNode).
+            setBody(lc, newBody).
+            setLastToken(lc, lastToken).
+            setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED).
+            snapshot(lc);
+        }
 
     /**
      * Get the statements in a block.
@@ -469,7 +481,7 @@
         }
 
         // Build up node.
-        return new BinaryNode(source, op, lhs, rhs);
+        return new BinaryNode(op, lhs, rhs);
     }
 
     /**
@@ -480,12 +492,12 @@
      * @param isPostfix  Prefix or postfix.
      * @return           Reduced expression.
      */
-    private Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) {
+    private static Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) {
         if (isPostfix) {
-            return new UnaryNode(source, Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
+            return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
         }
 
-        return new UnaryNode(source, firstToken, expression);
+        return new UnaryNode(firstToken, expression);
     }
 
     /**
@@ -514,7 +526,7 @@
 
         FunctionNode script = newFunctionNode(
             functionToken,
-            new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName),
+            new IdentNode(functionToken, Token.descPosition(functionToken), scriptName),
             new ArrayList<IdentNode>(),
             FunctionNode.Kind.SCRIPT);
 
@@ -529,6 +541,7 @@
 
         script = restoreFunctionNode(script, token); //commit code
         script = script.setBody(lc, script.getBody().setNeedsScope(lc));
+
         return script;
     }
 
@@ -670,8 +683,6 @@
      * @param topLevel does this statement occur at the "top level" of a script or a function?
      */
     private void statement(final boolean topLevel) {
-        final LineNumberNode lineNumberNode = lineNumber();
-
         if (type == FUNCTION) {
             // As per spec (ECMA section 12), function declarations as arbitrary statement
             // is not "portable". Implementation can issue a warning or disallow the same.
@@ -679,10 +690,6 @@
             return;
         }
 
-        if (lineNumberNode != null) {
-            appendStatement(lineNumberNode);
-        }
-
         switch (type) {
         case LBRACE:
             block();
@@ -763,7 +770,7 @@
     private void block() {
         final Block newBlock = getBlock(true);
         // Force block execution.
-        appendStatement(new ExecuteNode(source, newBlock.getToken(), finish, newBlock));
+        appendStatement(new ExecuteNode(newBlock.getLineNumber(), newBlock.getToken(), finish, newBlock));
     }
 
     /**
@@ -800,7 +807,6 @@
      * @param ident         Identifier that is verified
      * @param contextString String used in error message to give context to the user
      */
-    @SuppressWarnings("fallthrough")
     private void verifyStrictIdent(final IdentNode ident, final String contextString) {
         if (isStrictMode) {
             switch (ident.getName()) {
@@ -840,6 +846,7 @@
 
         while (true) {
             // Get starting token.
+            final int  varLine  = line;
             final long varToken = token;
             // Get name of var.
             final IdentNode name = getIdent();
@@ -857,7 +864,7 @@
             }
 
             // Allocate var node.
-            final VarNode var = new VarNode(source, varToken, finish, name, init);
+            final VarNode var = new VarNode(varLine, varToken, finish, name, init);
             vars.add(var);
             appendStatement(var);
 
@@ -889,7 +896,7 @@
      */
     private void emptyStatement() {
         if (env._empty_statements) {
-            appendStatement(new EmptyNode(source, token, Token.descPosition(token) + Token.descLength(token)));
+            appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token)));
         }
 
         // SEMICOLON checked in caller.
@@ -906,6 +913,7 @@
      */
     private void expressionStatement() {
         // Lookahead checked in caller.
+        final int  expressionLine  = line;
         final long expressionToken = token;
 
         // Get expression and add as statement.
@@ -913,7 +921,7 @@
 
         ExecuteNode executeNode = null;
         if (expression != null) {
-            executeNode = new ExecuteNode(source, expressionToken, finish, expression);
+            executeNode = new ExecuteNode(expressionLine, expressionToken, finish, expression);
             appendStatement(executeNode);
         } else {
             expect(null);
@@ -938,6 +946,7 @@
      */
     private void ifStatement() {
         // Capture IF token.
+        final int  ifLine  = line;
         final long ifToken = token;
          // IF tested in caller.
         next();
@@ -953,7 +962,7 @@
             fail = getStatement();
         }
 
-        appendStatement(new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
+        appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
     }
 
     /**
@@ -970,8 +979,7 @@
      */
     private void forStatement() {
         // Create FOR node, capturing FOR token.
-        ForNode forNode = new ForNode(source, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR);
-
+        ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR);
 
         // Set up new block for scope of vars. Captures first token.
         Block outer = newBlock();
@@ -1074,7 +1082,7 @@
             outer = restoreBlock(outer);
         }
 
-        appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+        appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
      }
 
     /**
@@ -1105,12 +1113,13 @@
      */
     private void whileStatement() {
         // Capture WHILE token.
+        final int  whileLine  = line;
         final long whileToken = token;
         // WHILE tested in caller.
         next();
 
         // Construct WHILE node.
-        WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken), false);
+        WhileNode whileNode = new WhileNode(whileLine, whileToken, Token.descPosition(whileToken), false);
         lc.push(whileNode);
 
         try {
@@ -1136,11 +1145,12 @@
      */
     private void doStatement() {
         // Capture DO token.
+        final int  doLine  = line;
         final long doToken = token;
         // DO tested in the caller.
         next();
 
-        WhileNode doWhileNode = new WhileNode(source, doToken, Token.descPosition(doToken), true);
+        WhileNode doWhileNode = new WhileNode(doLine, doToken, Token.descPosition(doToken), true);
         lc.push(doWhileNode);
 
         try {
@@ -1172,6 +1182,7 @@
      */
     private void continueStatement() {
         // Capture CONTINUE token.
+        final int  continueLine  = line;
         final long continueToken = token;
         // CONTINUE tested in caller.
         nextOrEOL();
@@ -1206,7 +1217,7 @@
         endOfLine();
 
         // Construct and add CONTINUE node.
-        appendStatement(new ContinueNode(source, continueToken, finish, label == null ? null : new IdentNode(label)));
+        appendStatement(new ContinueNode(continueLine, continueToken, finish, label == null ? null : new IdentNode(label)));
     }
 
     /**
@@ -1218,6 +1229,7 @@
      */
     private void breakStatement() {
         // Capture BREAK token.
+        final int  breakLine  = line;
         final long breakToken = token;
         // BREAK tested in caller.
         nextOrEOL();
@@ -1253,7 +1265,7 @@
         endOfLine();
 
         // Construct and add BREAK node.
-        appendStatement(new BreakNode(source, breakToken, finish, label == null ? null : new IdentNode(label)));
+        appendStatement(new BreakNode(breakLine, breakToken, finish, label == null ? null : new IdentNode(label)));
     }
 
     /**
@@ -1271,6 +1283,7 @@
         }
 
         // Capture RETURN token.
+        final int  returnLine  = line;
         final long returnToken = token;
         // RETURN tested in caller.
         nextOrEOL();
@@ -1292,7 +1305,7 @@
         endOfLine();
 
         // Construct and add RETURN node.
-        appendStatement(new ReturnNode(source, returnToken, finish, expression));
+        appendStatement(new ReturnNode(returnLine, returnToken, finish, expression));
     }
 
     /**
@@ -1305,6 +1318,7 @@
      */
     private void yieldStatement() {
         // Capture YIELD token.
+        final int  yieldLine  = line;
         final long yieldToken = token;
         // YIELD tested in caller.
         nextOrEOL();
@@ -1326,7 +1340,7 @@
         endOfLine();
 
         // Construct and add YIELD node.
-        appendStatement(new ReturnNode(source, yieldToken, finish, expression));
+        appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression));
     }
 
     /**
@@ -1339,6 +1353,7 @@
      */
     private void withStatement() {
         // Capture WITH token.
+        final int  withLine  = line;
         final long withToken = token;
         // WITH tested in caller.
         next();
@@ -1349,7 +1364,7 @@
         }
 
         // Get WITH expression.
-        WithNode withNode = new WithNode(source, withToken, finish);
+        WithNode withNode = new WithNode(withLine, withToken, finish);
 
         try {
             lc.push(withNode);
@@ -1387,12 +1402,13 @@
      * Parse SWITCH statement.
      */
     private void switchStatement() {
+        final int  switchLine  = line;
         final long switchToken = token;
         // SWITCH tested in caller.
         next();
 
         // Create and add switch statement.
-        SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
+        SwitchNode switchNode = new SwitchNode(switchLine, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
         lc.push(switchNode);
 
         try {
@@ -1434,7 +1450,7 @@
 
                 // Get CASE body.
                 final Block statements = getBlock(false);
-                final CaseNode caseNode = new CaseNode(source, caseToken, finish, caseExpression, statements);
+                final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements);
                 statements.setFinish(finish);
 
                 if (caseExpression == null) {
@@ -1474,7 +1490,7 @@
             throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
         }
 
-        LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null);
+        LabelNode labelNode = new LabelNode(line, labelToken, finish, ident, null);
         try {
             lc.push(labelNode);
             labelNode = labelNode.setBody(lc, getStatement());
@@ -1496,6 +1512,7 @@
      */
     private void throwStatement() {
         // Capture THROW token.
+        final int  throwLine  = line;
         final long throwToken = token;
         // THROW tested in caller.
         nextOrEOL();
@@ -1520,7 +1537,7 @@
 
         endOfLine();
 
-        appendStatement(new ThrowNode(source, throwToken, finish, expression));
+        appendStatement(new ThrowNode(throwLine, throwToken, finish, expression));
     }
 
     /**
@@ -1542,6 +1559,7 @@
      */
     private void tryStatement() {
         // Capture TRY token.
+        final int  tryLine  = line;
         final long tryToken = token;
         // TRY tested in caller.
         next();
@@ -1556,6 +1574,7 @@
             final List<Block> catchBlocks = new ArrayList<>();
 
             while (type == CATCH) {
+                final int  catchLine  = line;
                 final long catchToken = token;
                 next();
                 expect(LPAREN);
@@ -1578,7 +1597,7 @@
                 try {
                     // Get CATCH body.
                     final Block catchBody = getBlock(true);
-                    final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody);
+                    final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody);
                     appendStatement(catchNode);
                 } finally {
                     catchBlock = restoreBlock(catchBlock);
@@ -1604,7 +1623,7 @@
                 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
             }
 
-            final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
+            final TryNode tryNode = new TryNode(tryLine, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
             // Add try.
             assert lc.peek() == outer;
             appendStatement(tryNode);
@@ -1616,7 +1635,7 @@
             outer = restoreBlock(outer);
         }
 
-        appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+        appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
     }
 
     /**
@@ -1629,11 +1648,12 @@
      */
     private void  debuggerStatement() {
         // Capture DEBUGGER token.
+        final int  debuggerLine  = line;
         final long debuggerToken = token;
         // DEBUGGER tested in caller.
         next();
         endOfLine();
-        appendStatement(new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>()));
+        appendStatement(new ExecuteNode(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>())));
     }
 
     /**
@@ -1653,13 +1673,14 @@
     @SuppressWarnings("fallthrough")
     private Node primaryExpression() {
         // Capture first token.
+        final int  primaryLine  = line;
         final long primaryToken = token;
 
         switch (type) {
         case THIS:
             final String name = type.getName();
             next();
-            return new IdentNode(source, primaryToken, finish, name);
+            return new IdentNode(primaryToken, finish, name);
         case IDENT:
             final IdentNode ident = getIdent();
             if (ident == null) {
@@ -1680,16 +1701,16 @@
         case XML:
             return getLiteral();
         case EXECSTRING:
-            return execString(primaryToken);
+            return execString(primaryLine, primaryToken);
         case FALSE:
             next();
-            return LiteralNode.newInstance(source, primaryToken, finish, false);
+            return LiteralNode.newInstance(primaryToken, finish, false);
         case TRUE:
             next();
-            return LiteralNode.newInstance(source, primaryToken, finish, true);
+            return LiteralNode.newInstance(primaryToken, finish, true);
         case NULL:
             next();
-            return LiteralNode.newInstance(source, primaryToken, finish);
+            return LiteralNode.newInstance(primaryToken, finish);
         case LBRACKET:
             return arrayLiteral();
         case LBRACE:
@@ -1724,9 +1745,9 @@
      * @param primaryToken Original string token.
      * @return callNode to $EXEC.
      */
-    Node execString(final long primaryToken) {
+    Node execString(final int primaryLine, final long primaryToken) {
         // Synthesize an ident to call $EXEC.
-        final IdentNode execIdent = new IdentNode(source, primaryToken, finish, ScriptingFunctions.EXEC_NAME);
+        final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME);
         // Skip over EXECSTRING.
         next();
         // Set up argument list for call.
@@ -1738,7 +1759,7 @@
         // Skip ending of edit string expression.
         expect(RBRACE);
 
-        return new CallNode(source, primaryToken, finish, execIdent, arguments);
+        return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments);
     }
 
     /**
@@ -1809,7 +1830,7 @@
             }
         }
 
-        return LiteralNode.newInstance(source, arrayToken, finish, elements);
+        return LiteralNode.newInstance(arrayToken, finish, elements);
     }
 
     /**
@@ -1916,7 +1937,7 @@
                             map.put(key, newProperty = newProperty.setValue(value));
                         } else {
                             final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT);
-                            map.put(key, newProperty = newProperty.setValue(new BinaryNode(source, propertyToken, prevValue, value)));
+                            map.put(key, newProperty = newProperty.setValue(new BinaryNode(propertyToken, prevValue, value)));
                         }
 
                         map.put(key, newProperty = newProperty.setGetter(null).setSetter(null));
@@ -1933,7 +1954,7 @@
             }
         }
 
-        return new ObjectNode(source, objectToken, finish, new ArrayList<Node>(map.values()));
+        return new ObjectNode(objectToken, finish, new ArrayList<Node>(map.values()));
     }
 
     /**
@@ -2003,16 +2024,16 @@
                 case "get":
                     final PropertyKey getIdent = propertyName();
                     final String getterName = getIdent.getPropertyName();
-                    final IdentNode getNameNode = new IdentNode(source, ((Node)getIdent).getToken(), finish, "get " + getterName);
+                    final IdentNode getNameNode = new IdentNode(((Node)getIdent).getToken(), finish, "get " + getterName);
                     expect(LPAREN);
                     expect(RPAREN);
                     functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER);
-                    return new PropertyNode(source, propertyToken, finish, getIdent, null, functionNode, null);
+                    return new PropertyNode(propertyToken, finish, getIdent, null, functionNode, null);
 
                 case "set":
                     final PropertyKey setIdent = propertyName();
                     final String setterName = setIdent.getPropertyName();
-                    final IdentNode setNameNode = new IdentNode(source, ((Node)setIdent).getToken(), finish, "set " + setterName);
+                    final IdentNode setNameNode = new IdentNode(((Node)setIdent).getToken(), finish, "set " + setterName);
                     expect(LPAREN);
                     final IdentNode argIdent = getIdent();
                     verifyStrictIdent(argIdent, "setter argument");
@@ -2020,21 +2041,21 @@
                     List<IdentNode> parameters = new ArrayList<>();
                     parameters.add(argIdent);
                     functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
-                    return new PropertyNode(source, propertyToken, finish, setIdent, null, null, functionNode);
+                    return new PropertyNode(propertyToken, finish, setIdent, null, null, functionNode);
 
                 default:
                     break;
                 }
             }
 
-            propertyName =  new IdentNode(source, propertyToken, finish, ident);
+            propertyName =  new IdentNode(propertyToken, finish, ident);
         } else {
             propertyName = propertyName();
         }
 
         expect(COLON);
 
-        return new PropertyNode(source, propertyToken, finish, propertyName, assignmentExpression(false), null, null);
+        return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null);
     }
 
     /**
@@ -2054,6 +2075,7 @@
      * @return Expression node.
      */
     private Node leftHandSideExpression() {
+        int  callLine  = line;
         long callToken = token;
 
         Node lhs = memberExpression();
@@ -2066,12 +2088,13 @@
                 detectSpecialFunction((IdentNode)lhs);
             }
 
-            lhs = new CallNode(source, callToken, finish, lhs, arguments);
+            lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
         }
 
 loop:
         while (true) {
             // Capture token.
+            callLine  = line;
             callToken = token;
 
             switch (type) {
@@ -2080,7 +2103,7 @@
                 final List<Node> arguments = argumentList();
 
                 // Create call node.
-                lhs = new CallNode(source, callToken, finish, lhs, arguments);
+                lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
 
                 break;
 
@@ -2093,7 +2116,7 @@
                 expect(RBRACKET);
 
                 // Create indexing node.
-                lhs = new IndexNode(source, callToken, finish, lhs, rhs);
+                lhs = new IndexNode(callToken, finish, lhs, rhs);
 
                 break;
 
@@ -2103,7 +2126,7 @@
                 final IdentNode property = getIdentifierName();
 
                 // Create property access node.
-                lhs = new AccessNode(source, callToken, finish, lhs, property);
+                lhs = new AccessNode(callToken, finish, lhs, property);
 
                 break;
 
@@ -2131,6 +2154,7 @@
         next();
 
         // Get function base.
+        final int  callLine    = line;
         final Node constructor = memberExpression();
         if (constructor == null) {
             return null;
@@ -2159,9 +2183,9 @@
             arguments.add(objectLiteral());
         }
 
-        final CallNode callNode = new CallNode(source, constructor.getToken(), finish, constructor, arguments);
-
-        return new UnaryNode(source, newToken, callNode);
+        final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, arguments);
+
+        return new UnaryNode(newToken, callNode);
     }
 
     /**
@@ -2213,7 +2237,7 @@
                 expect(RBRACKET);
 
                 // Create indexing node.
-                lhs = new IndexNode(source, callToken, finish, lhs, index);
+                lhs = new IndexNode(callToken, finish, lhs, index);
 
                 break;
 
@@ -2227,7 +2251,7 @@
                 final IdentNode property = getIdentifierName();
 
                 // Create property access node.
-                lhs = new AccessNode(source, callToken, finish, lhs, property);
+                lhs = new AccessNode(callToken, finish, lhs, property);
 
                 break;
 
@@ -2294,9 +2318,8 @@
      * @return Expression node.
      */
     private Node functionExpression(final boolean isStatement, final boolean topLevel) {
-        final LineNumberNode lineNumber = lineNumber();
-
         final long functionToken = token;
+        final int  functionLine  = line;
         // FUNCTION is tested in caller.
         next();
 
@@ -2316,7 +2339,7 @@
         boolean isAnonymous = false;
         if (name == null) {
             final String tmpName = "_L" + source.getLine(Token.descPosition(token));
-            name = new IdentNode(source, functionToken, Token.descPosition(functionToken), tmpName);
+            name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName);
             isAnonymous = true;
         }
 
@@ -2367,7 +2390,7 @@
                     // rename in non-strict mode
                     parameterName = functionNode.uniqueName(parameterName);
                     final long parameterToken = parameter.getToken();
-                    parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
+                    parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
                 }
 
                 parametersSet.add(parameterName);
@@ -2379,12 +2402,10 @@
         }
 
         if (isStatement) {
-            final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
+            final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
             if (topLevel) {
-                functionDeclarations.add(lineNumber);
                 functionDeclarations.add(varNode);
             } else {
-                appendStatement(lineNumber);
                 appendStatement(varNode);
             }
         }
@@ -2459,7 +2480,7 @@
                 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
                 // create a return statement - this creates code in itself and does not need to be
                 // wrapped into an ExecuteNode
-                final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr);
+                final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), finish, expr);
                 appendStatement(returnNode);
                 lastToken = token;
                 functionNode.setFinish(Token.descPosition(token) + Token.descLength(token));
@@ -2468,7 +2489,7 @@
                 expect(LBRACE);
 
                 // Gather the function elements.
-                final List<Node> prevFunctionDecls = functionDeclarations;
+                final List<Statement> prevFunctionDecls = functionDeclarations;
                 functionDeclarations = new ArrayList<>();
                 try {
                     sourceElements();
@@ -2492,7 +2513,7 @@
         assert lc.peek() == lc.getFunctionBody(functionNode);
         VarNode lastDecl = null;
         for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
-            Node decl = functionDeclarations.get(i);
+            Statement decl = functionDeclarations.get(i);
             if (lastDecl == null && decl instanceof VarNode) {
                 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
                 lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS);
@@ -2501,16 +2522,16 @@
         }
     }
 
-    private RuntimeNode referenceError(final Node lhs, final Node rhs) {
+    private static RuntimeNode referenceError(final Node lhs, final Node rhs) {
         final ArrayList<Node> args = new ArrayList<>();
         args.add(lhs);
         if (rhs == null) {
-            args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish()));
+            args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish()));
         } else {
             args.add(rhs);
         }
-        args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString()));
-        return new RuntimeNode(source, lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
+        args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString()));
+        return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
     }
 
     /*
@@ -2548,10 +2569,19 @@
      * @return Expression node.
      */
     private Node unaryExpression() {
+        final int  unaryLine  = line;
         final long unaryToken = token;
 
         switch (type) {
-        case DELETE:
+        case DELETE: {
+            next();
+            final Node expr = unaryExpression();
+            if (expr instanceof BaseNode || expr instanceof IdentNode) {
+                return new UnaryNode(unaryToken, expr);
+            }
+            appendStatement(new ExecuteNode(unaryLine, unaryToken, finish, expr));
+            return LiteralNode.newInstance(unaryToken, finish, true);
+        }
         case VOID:
         case TYPEOF:
         case ADD:
@@ -2560,7 +2590,7 @@
         case NOT:
             next();
             final Node expr = unaryExpression();
-            return new UnaryNode(source, unaryToken, expr);
+            return new UnaryNode(unaryToken, expr);
 
         case INCPREFIX:
         case DECPREFIX:
@@ -2749,7 +2779,7 @@
                 final Node third = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
 
                 // Build up node.
-                lhs = new TernaryNode(source, op, lhs, rhs, third);
+                lhs = new TernaryNode(op, lhs, rhs, third);
             } else {
                 // Skip operator.
                 next();
@@ -2805,16 +2835,6 @@
         }
     }
 
-    /**
-     * Add a line number node at current position
-     */
-    private LineNumberNode lineNumber() {
-        if (env._debug_lines) {
-            return new LineNumberNode(source, token, line);
-        }
-        return null;
-    }
-
     @Override
     public String toString() {
         return "[JavaScript Parsing]";
@@ -2835,11 +2855,11 @@
         }
     }
 
-    private void prependStatement(final Node statement) {
+    private void prependStatement(final Statement statement) {
         lc.prependStatement(statement);
     }
 
-    private void appendStatement(final Node statement) {
+    private void appendStatement(final Statement statement) {
         lc.appendStatement(statement);
     }
 }
--- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Tue May 14 11:16:52 2013 -0300
@@ -88,7 +88,7 @@
 
         int weight = Type.typeFor(type.returnType()).getWeight();
         for (final Class<?> paramType : type.parameterArray()) {
-            final int pweight = Type.typeFor(paramType).getWeight();
+            final int pweight = Type.typeFor(paramType).getWeight() * 2; //params are more important than call types as return values are always specialized
             weight += pweight;
         }
         return weight;
--- a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java	Tue May 14 11:16:52 2013 -0300
@@ -69,5 +69,4 @@
         return best(type).moreGenericThan(type);
     }
 
-
 }
--- a/src/jdk/nashorn/internal/runtime/Context.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/Context.java	Tue May 14 11:16:52 2013 -0300
@@ -411,7 +411,7 @@
         return ScriptRuntime.apply(func, evalThis);
     }
 
-    private Source loadInternal(final String srcStr, final String prefix, final String resourcePath) {
+    private static Source loadInternal(final String srcStr, final String prefix, final String resourcePath) {
         if (srcStr.startsWith(prefix)) {
             final String resource = resourcePath + srcStr.substring(prefix.length());
             // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme
@@ -510,7 +510,7 @@
 
     /**
      * Lookup a Java class. This is used for JSR-223 stuff linking in from
-     * {@link jdk.nashorn.internal.objects.NativeJava} and {@link jdk.nashorn.internal.runtime.NativeJavaPackage}
+     * {@code jdk.nashorn.internal.objects.NativeJava} and {@code jdk.nashorn.internal.runtime.NativeJavaPackage}
      *
      * @param fullName full name of class to load
      *
@@ -759,10 +759,10 @@
         final CodeSource   cs     = url == null ? null : new CodeSource(url, (CodeSigner[])null);
         final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
 
-        final Compiler compiler = new Compiler(installer, functionNode, strict);
+        final Compiler compiler = new Compiler(installer, strict);
 
-        compiler.compile();
-        script = compiler.install();
+        final FunctionNode newFunctionNode = compiler.compile(functionNode);
+        script = compiler.install(newFunctionNode);
 
         if (global != null) {
             global.cacheClass(source, script);
--- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Tue May 14 11:16:52 2013 -0300
@@ -25,8 +25,6 @@
 
 package jdk.nashorn.internal.runtime;
 
-import static jdk.nashorn.internal.runtime.ScriptObject.isArray;
-
 import java.lang.invoke.MethodHandle;
 import java.util.Iterator;
 import java.util.List;
--- a/src/jdk/nashorn/internal/runtime/PropertyMap.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java	Tue May 14 11:16:52 2013 -0300
@@ -744,12 +744,7 @@
      * @return New {@link PropertyMap} with prototype changed.
      */
     PropertyMap changeProto(final ScriptObject oldProto, final ScriptObject newProto) {
-        if ((oldProto == newProto) ||
-            (size() == 0 &&
-             oldProto == null &&
-             protoGetSwitches == null &&
-             history == null &&
-             protoHistory == null)) {
+        if (oldProto == newProto) {
             return this;
         }
 
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Tue May 14 11:16:52 2013 -0300
@@ -30,9 +30,12 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.util.LinkedList;
+
 import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.FunctionSignature;
+import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.parser.Token;
@@ -148,10 +151,10 @@
 
          if (functionNode.isLazy()) {
              Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
-             final Compiler compiler = new Compiler(installer, functionNode);
-             functionNode = compiler.compile();
+             final Compiler compiler = new Compiler(installer);
+             functionNode = compiler.compile(functionNode);
              assert !functionNode.isLazy();
-             compiler.install();
+             compiler.install(functionNode);
 
              // we don't need to update any flags - varArgs and needsCallee are instrincic
              // in the function world we need to get a destination node from the compile instead
@@ -164,23 +167,118 @@
          assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
 
          // code exists - look it up and add it into the automatically sorted invoker list
-         code.add(
-            new CompiledFunction(
-                MH.findStatic(
+         addCode(functionNode, null, null);
+    }
+
+    private MethodHandle addCode(final FunctionNode fn, final MethodHandle guard, final MethodHandle fallback) {
+        final MethodHandle target =
+            MH.findStatic(
                     LOOKUP,
-                    functionNode.getCompileUnit().getCode(),
-                    functionNode.getName(),
-                    new FunctionSignature(functionNode).
-                        getMethodType())));
+                    fn.getCompileUnit().getCode(),
+                    fn.getName(),
+                    new FunctionSignature(fn).
+                        getMethodType());
+        MethodHandle mh = target;
+        if (guard != null) {
+            try {
+                mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback);
+            } catch (Throwable e) {
+                e.printStackTrace();
+            }
+        }
+
+        final CompiledFunction cf = new CompiledFunction(mh);
+        code.add(cf);
+
+        return cf.getInvoker();
     }
 
+    private static Type runtimeType(final Object arg) {
+        if (arg == null) {
+            return Type.OBJECT;
+        }
+
+        final Class<?> clazz = arg.getClass();
+        assert !clazz.isPrimitive() : "always boxed";
+        if (clazz == Double.class) {
+            return JSType.isRepresentableAsInt((double)arg) ? Type.INT : Type.NUMBER;
+        } else if (clazz == Integer.class) {
+            return Type.INT;
+        } else if (clazz == Long.class) {
+            return Type.LONG;
+        } else if (clazz == String.class) {
+            return Type.STRING;
+        }
+        return Type.OBJECT;
+    }
+
+    @SuppressWarnings("unused")
+    private static boolean paramTypeGuard(final Type[] compileTimeTypes, final Type[] runtimeTypes, Object... args) {
+        //System.err.println("Param type guard " + Arrays.asList(args));
+        return false;
+    }
+
+    private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Type[].class, Object[].class);
+
     @Override
     MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
         final MethodHandle mh = super.getBestInvoker(callSiteType, args);
-        if (code.isLessSpecificThan(callSiteType)) {
-            // opportunity for code specialization - we can regenerate a better version of this method
+
+        if (!functionNode.canSpecialize() || !code.isLessSpecificThan(callSiteType)) {
+            return mh;
         }
-        return mh;
+
+        final FunctionNode snapshot = functionNode.getSnapshot();
+        if (snapshot == null) {
+            return mh;
+        }
+
+        int i;
+
+        //classes known at runtime
+        final LinkedList<Type> runtimeArgs = new LinkedList<>();
+        for (i = args.length - 1; i >= args.length - snapshot.getParameters().size(); i--) {
+            runtimeArgs.addLast(runtimeType(args[i]));
+        }
+
+        //classes known at compile time
+        final LinkedList<Type> compileTimeArgs = new LinkedList<>();
+        for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) {
+            compileTimeArgs.addLast(Type.typeFor(callSiteType.parameterType(i)));
+        }
+
+        //the classes known at compile time are a safe to generate as primitives without parameter guards
+        //the classes known at runtime are safe to generate as primitives IFF there are parameter guards
+        MethodHandle guard = null;
+        for (i = 0; i < compileTimeArgs.size(); i++) {
+            final Type runtimeType = runtimeArgs.get(i);
+            final Type compileType = compileTimeArgs.get(i);
+
+            if (compileType.isObject() && !runtimeType.isObject()) {
+                if (guard == null) {
+                    guard = PARAM_TYPE_GUARD;
+                    guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()]));
+                }
+            }
+        }
+
+        //System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs);
+
+        assert snapshot != null;
+        assert snapshot != functionNode;
+
+        final Compiler compiler = new Compiler(installer);
+        final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()]))));
+
+        compiler.install(compiledSnapshot);
+
+        final MethodHandle nmh = addCode(compiledSnapshot, guard, mh);
+
+        return nmh;
+    }
+
+    private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
+        return MH.findStatic(MethodHandles.lookup(), RecompilableScriptFunctionData.class, name, MH.type(rtype, types));
     }
 
 }
--- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Tue May 14 11:16:52 2013 -0300
@@ -26,9 +26,13 @@
 package jdk.nashorn.internal.runtime;
 
 import java.io.PrintWriter;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
+import java.util.StringTokenizer;
 import java.util.TimeZone;
+
 import jdk.nashorn.internal.codegen.Namespace;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import jdk.nashorn.internal.runtime.options.KeyValueOption;
@@ -136,6 +140,9 @@
     /** Print resulting bytecode for script */
     public final boolean _print_code;
 
+    /** Print memory usage for IR after each phase */
+    public final boolean _print_mem_usage;
+
     /** Print function will no print newline characters */
     public final boolean _print_no_newline;
 
@@ -151,6 +158,9 @@
     /** is this environment in scripting mode? */
     public final boolean _scripting;
 
+    /** is the JIT allowed to specializ calls based on callsite types? */
+    public final Set<String> _specialize_calls;
+
     /** is this environment in strict mode? */
     public final boolean _strict;
 
@@ -204,6 +214,7 @@
         _print_ast            = options.getBoolean("print.ast");
         _print_lower_ast      = options.getBoolean("print.lower.ast");
         _print_code           = options.getBoolean("print.code");
+        _print_mem_usage      = options.getBoolean("print.mem.usage");
         _print_no_newline     = options.getBoolean("print.no.newline");
         _print_parse          = options.getBoolean("print.parse");
         _print_lower_parse    = options.getBoolean("print.lower.parse");
@@ -213,6 +224,17 @@
         _version              = options.getBoolean("version");
         _verify_code          = options.getBoolean("verify.code");
 
+        final String specialize = options.getString("specialize.calls");
+        if (specialize == null) {
+            _specialize_calls = null;
+        } else {
+            _specialize_calls = new HashSet<>();
+            final StringTokenizer st = new StringTokenizer(specialize, ",");
+            while (st.hasMoreElements()) {
+                _specialize_calls.add(st.nextToken());
+            }
+        }
+
         int callSiteFlags = 0;
         if (options.getBoolean("profile.callsites")) {
             callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE;
@@ -247,6 +269,18 @@
     }
 
     /**
+     * Can we specialize a particular method name?
+     * @param functionName method name
+     * @return true if we are allowed to generate versions of this method
+     */
+    public boolean canSpecialize(final String functionName) {
+        if (_specialize_calls == null) {
+            return false;
+        }
+        return _specialize_calls.isEmpty() || _specialize_calls.contains(functionName);
+    }
+
+    /**
      * Get the output stream for this environment
      * @return output print writer
      */
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Tue May 14 11:16:52 2013 -0300
@@ -662,9 +662,9 @@
         }
 
         if (deep) {
-            final ScriptObject proto = getProto();
-            if(proto != null) {
-                return proto.findProperty(key, deep, stopOnNonScope, start);
+            final ScriptObject myProto = getProto();
+            if (myProto != null) {
+                return myProto.findProperty(key, deep, stopOnNonScope, start);
             }
         }
 
@@ -970,9 +970,7 @@
      * @param bindName  null or name to bind to second argument (property not found method.)
      *
      * @return value of property as a MethodHandle or null.
-     *
      */
-    @SuppressWarnings("static-method")
     protected MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
         return getCallMethodHandle(getObjectValue(find), type, bindName);
     }
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java	Tue May 14 11:16:52 2013 -0300
@@ -57,7 +57,6 @@
      * Is this a reverse order iteration?
      * @return true if reverse
      */
-    @SuppressWarnings("static-method")
     public boolean isReverse() {
         return false;
     }
--- a/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Tue May 14 11:16:52 2013 -0300
@@ -278,7 +278,7 @@
             @SuppressWarnings("resource")
             @Override
             public void run() {
-                PrintWriter out = null;
+                PrintWriter out    = null;
                 boolean fileOutput = false;
 
                 try {
--- a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Tue May 14 11:16:52 2013 -0300
@@ -44,11 +44,9 @@
 
 /**
  * This is the main dynamic linker for Nashorn. It is used for linking all {@link ScriptObject} and its subclasses (this
- * includes {@link ScriptFunction} and its subclasses) as well as {@link Undefined}. This linker is exported to other
- * language runtimes by being declared in {@code META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker}
- * file of Nashorn's distribution.
+ * includes {@link ScriptFunction} and its subclasses) as well as {@link Undefined}.
  */
-final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
+public final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
     /**
      * Returns true if {@code ScriptObject} is assignable from {@code type}, or it is {@code Undefined}.
      */
--- a/src/jdk/nashorn/internal/runtime/options/Options.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/options/Options.java	Tue May 14 11:16:52 2013 -0300
@@ -243,7 +243,7 @@
      */
     public String getString(final String key) {
         final Option<?> option = get(key);
-        if(option != null) {
+        if (option != null) {
             final String value = (String)option.getValue();
             if(value != null) {
                 return value.intern();
--- a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java	Tue May 14 11:16:52 2013 -0300
@@ -107,16 +107,16 @@
 
     class DefaultMatcher implements RegExpMatcher {
         final String input;
-        final Matcher matcher;
+        final Matcher defaultMatcher;
 
         DefaultMatcher(final String input) {
             this.input = input;
-            this.matcher = pattern.matcher(input);
+            this.defaultMatcher = pattern.matcher(input);
         }
 
         @Override
         public boolean search(final int start) {
-            return matcher.find(start);
+            return defaultMatcher.find(start);
         }
 
         @Override
@@ -126,37 +126,37 @@
 
         @Override
         public int start() {
-            return matcher.start();
+            return defaultMatcher.start();
         }
 
         @Override
         public int start(final int group) {
-            return matcher.start(group);
+            return defaultMatcher.start(group);
         }
 
         @Override
         public int end() {
-            return matcher.end();
+            return defaultMatcher.end();
         }
 
         @Override
         public int end(final int group) {
-            return matcher.end(group);
+            return defaultMatcher.end(group);
         }
 
         @Override
         public String group() {
-            return matcher.group();
+            return defaultMatcher.group();
         }
 
         @Override
         public String group(final int group) {
-            return matcher.group(group);
+            return defaultMatcher.group(group);
         }
 
         @Override
         public int groupCount() {
-            return matcher.groupCount();
+            return defaultMatcher.groupCount();
         }
     }
 
--- a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java	Tue May 14 11:16:52 2013 -0300
@@ -121,16 +121,16 @@
 
     class JoniMatcher implements RegExpMatcher {
         final String input;
-        final Matcher matcher;
+        final Matcher joniMatcher;
 
         JoniMatcher(final String input) {
             this.input = input;
-            this.matcher = regex.matcher(input.toCharArray());
+            this.joniMatcher = regex.matcher(input.toCharArray());
         }
 
         @Override
         public boolean search(final int start) {
-            return matcher.search(start, input.length(), Option.NONE) > -1;
+            return joniMatcher.search(start, input.length(), Option.NONE) > -1;
         }
 
         @Override
@@ -140,27 +140,27 @@
 
         @Override
         public int start() {
-            return matcher.getBegin();
+            return joniMatcher.getBegin();
         }
 
         @Override
         public int start(final int group) {
-            return group == 0 ? start() : matcher.getRegion().beg[group];
+            return group == 0 ? start() : joniMatcher.getRegion().beg[group];
         }
 
         @Override
         public int end() {
-            return matcher.getEnd();
+            return joniMatcher.getEnd();
         }
 
         @Override
         public int end(final int group) {
-            return group == 0 ? end() : matcher.getRegion().end[group];
+            return group == 0 ? end() : joniMatcher.getRegion().end[group];
         }
 
         @Override
         public String group() {
-            return input.substring(matcher.getBegin(), matcher.getEnd());
+            return input.substring(joniMatcher.getBegin(), joniMatcher.getEnd());
         }
 
         @Override
@@ -168,13 +168,13 @@
             if (group == 0) {
                 return group();
             }
-            final Region region = matcher.getRegion();
+            final Region region = joniMatcher.getRegion();
             return input.substring(region.beg[group], region.end[group]);
         }
 
         @Override
         public int groupCount() {
-            final Region region = matcher.getRegion();
+            final Region region = joniMatcher.getRegion();
             return region == null ? 0 : region.numRegs - 1;
         }
     }
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java	Tue May 14 11:16:52 2013 -0300
@@ -65,7 +65,7 @@
     /** Are we currently inside a negated character class? */
     private boolean inNegativeClass = false;
 
-    private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?";
+    private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?-";
 
     private static class Capture {
         /**
@@ -934,7 +934,7 @@
         return true;
     }
 
-    private void unicode(final int value, final StringBuilder buffer) {
+    private static void unicode(final int value, final StringBuilder buffer) {
         final String hex = Integer.toHexString(value);
         buffer.append('u');
         for (int i = 0; i < 4 - hex.length(); i++) {
@@ -944,7 +944,7 @@
     }
 
     // Convert what would have been a backreference into a unicode escape, or a number literal, or both.
-    private void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) {
+    private static void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) {
         final int length = numberLiteral.length();
         int octalValue = 0;
         int pos = 0;
--- a/src/jdk/nashorn/internal/runtime/resources/Options.properties	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties	Tue May 14 11:16:52 2013 -0300
@@ -247,6 +247,12 @@
     desc="Print bytecode."    \
 }
 
+nashorn.option.print.mem.usage = {                            \
+    name="--print-mem-usage",                                 \
+    is_undocumented=true,                                     \
+    desc="Print memory usage of IR after each compile stage." \
+}
+
 nashorn.option.print.no.newline = {                     \
     name="--print-no-newline",                          \
     is_undocumented=true,                               \
@@ -288,12 +294,12 @@
     dependency="--anon-functions=true"  \
 }
 
-nashorn.option.timezone = {                    \
-    name="-timezone",                          \
-    short_name="-t",                           \
-    params="<timezone>",                       \
-    desc="Set timezone for script execution.", \
-    type=TimeZone                              \
+nashorn.option.specialize.calls = {                                                \
+    name="--specialize-calls",                                                     \
+    is_undocumented=true,                                                          \
+    type=String,                                                                   \
+    params="[=function_1,...,function_n]",                                         \
+    desc="Specialize all or a set of method according to callsite parameter types" \
 }
 
 nashorn.option.stdout = {                                               \
@@ -312,6 +318,14 @@
     desc="Redirect stderr to a filename or to another tty, e.g. stdout" \
 }
 
+nashorn.option.timezone = {                    \
+    name="-timezone",                          \
+    short_name="-t",                           \
+    params="<timezone>",                       \
+    desc="Set timezone for script execution.", \
+    type=TimeZone                              \
+}
+
 nashorn.option.trace.callsites = {                                              \
     name="--trace-callsites",                                                   \
     short_name="-tcs",                                                          \
--- a/src/jdk/nashorn/tools/Shell.java	Tue May 14 11:15:12 2013 -0300
+++ b/src/jdk/nashorn/tools/Shell.java	Tue May 14 11:16:52 2013 -0300
@@ -173,9 +173,9 @@
 
         if (env._fx) {
             return runFXScripts(context, global, files);
-        } else {
-            return runScripts(context, global, files);
         }
+
+        return runScripts(context, global, files);
     }
 
     /**
@@ -270,7 +270,7 @@
                 }
 
                 //null - pass no code installer - this is compile only
-                new Compiler(env, functionNode).compile();
+                new Compiler(env).compile(functionNode);
             }
         } finally {
             env.getOut().flush();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8013873.js	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8013873: Regexp regression for escaped dash in character class
+ *
+ * @test
+ * @run
+ */
+
+var re = /[a\-c]/;
+print(re.exec("a"));
+print(re.exec("-"));
+print(re.exec("c"));
+print(re.exec("b"));
+print(re.exec("\\"));
+
+re = /^\-$/;
+print(re.exec("-"));
+print(re.exec("\\-"));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8013873.js.EXPECTED	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,7 @@
+a
+-
+c
+null
+null
+-
+null
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8013874.js	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8013874: Function argument's prototype seem cached and wrongly reused
+ *
+ * @test
+ * @run
+ */
+
+function deepEqual(actual, expected) {
+    print("deepEqual: " + (actual.prop === expected.prop) + ", prop: " + expected.prop);
+}
+
+var proto = {};
+var other = {
+    prop: 0
+};
+
+function NameBuilder(first, last) {
+    this.first = first;
+    this.last = last;
+    return this;
+}
+
+NameBuilder.prototype = proto;
+
+function NameBuilder2(first, last) {
+    this.first = first;
+    this.last = last;
+    return this;
+}
+
+NameBuilder2.prototype = proto;
+
+var nb1 = new NameBuilder('Ryan', 'Dahl');
+var nb2 = new NameBuilder2('Ryan', 'Dahl');
+
+print("In loader, nb1.prop === nb2.prop " + (nb1.prop === nb2.prop));
+deepEqual(nb1, nb2);
+
+NameBuilder2.prototype = other;
+nb2 = new NameBuilder2('Ryan', 'Dahl');
+
+print("In loader, nb1.prop === nb2.prop " + (nb1.prop === nb2.prop));
+deepEqual(nb1, nb2);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8013874.js.EXPECTED	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,4 @@
+In loader, nb1.prop === nb2.prop true
+deepEqual: true, prop: undefined
+In loader, nb1.prop === nb2.prop false
+deepEqual: false, prop: 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8013878.js	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8013878: ClassCastException in Regex
+ *
+ * @test
+ * @run
+ */
+
+var re = /(a)(b)(c)/;
+var str = 'abc';
+
+print(re.exec(str).length);
+print(re.exec(str).concat(['d', 'e', 'f']));
+print(re.exec(str).join('-'));
+print(re.exec(str).push('d'));
+print(re.exec(str).pop());
+print(re.exec(str).reverse());
+print(re.exec(str).shift());
+print(re.exec(str).sort());
+print(re.exec(str).slice(1));
+print(re.exec(str).splice(1, 2, 'foo'));
+print(re.exec(str).unshift('x'));
+print(re.exec(str).indexOf('a'));
+print(re.exec(str).lastIndexOf('a'));
+print(re.exec(str).every(function(a) {return a.length;}));
+print(re.exec(str).some(function(a) {return a.length;}));
+print(re.exec(str).filter(function(a) {return a.length;}));
+print(re.exec(str).forEach(function(a) {print(a)}));
+print(re.exec(str).map(function(a) {return a.length;}));
+print(re.exec(str).reduce(function(a, b) {return a + b}));
+print(re.exec(str).reduceRight(function(a, b) {return a + b}));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8013878.js.EXPECTED	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,24 @@
+4
+abc,a,b,c,d,e,f
+abc-a-b-c
+5
+c
+c,b,a,abc
+abc
+a,abc,b,c
+a,b,c
+a,b
+5
+1
+1
+true
+true
+abc,a,b,c
+abc
+a
+b
+c
+undefined
+3,1,1,1
+abcabc
+cbaabc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/no_line_numbers.js	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * no_line_numbers.js - make sure that switching off line number generation
+ * doesn't break. Otherwise, this is just NASHORN-73, a unit test particularly
+ * prone to label bugs in CodeGenerator
+ *
+ * @test
+ * @run
+ * @option --debug-lines=false
+ */
+
+print("x = " + x);
+do {
+   break;
+   var x;
+} while (true);
+
+
+print("y = " + y);
+while (true) {
+    break;
+    var y;
+}
+
+print("z = " + z);
+for ( ; ; ) {
+   break;
+   var z;
+   print("THIS SHOULD NEVER BE PRINTED!");
+}
+
+while (true) {
+    break;
+    if (true) { 
+	var s; 
+    }
+}
+
+print("s = "+s);
+
+print("u = "+u);
+for ( ; ; ) {
+    break;
+    while (true) {
+	do {
+	    var u;
+	} while (true);
+    }    
+}
+
+function terminal() {
+    print("r = "+r);
+    print("t = "+t);
+    for (;;) {
+	var r;
+	return;
+	var t;
+	print("THIS SHOULD NEVER BE PRINTED!");
+    }
+    print("NEITHER SHOULD THIS");
+}
+
+terminal();
+
+function terminal2() {
+    print("q = "+q);
+    for (;;) {
+	return;
+	print("THIS SHOULD NEVER BE PRINTED!");
+    }
+    print("NEITHER SHOULD THIS");
+}
+
+try { 
+    terminal2();
+} catch (e) {
+    print(e);
+}
+
+function scope2() {
+    var b = 10;
+    print("b = "+b);
+}
+
+scope2();
+
+try {
+    print("b is = "+b);
+}  catch (e) {
+    print(e);
+}
+	
+
+function disp_a() {
+    var a = 20;
+    print("Value of 'a' inside the function " + a);
+}
+	
+var a = 10;
+
+disp_a();
+
+print("Value of 'a' outside the function " + a);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/no_line_numbers.js.EXPECTED	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,12 @@
+x = undefined
+y = undefined
+z = undefined
+s = undefined
+u = undefined
+r = undefined
+t = undefined
+ReferenceError: "q" is not defined
+b = 10
+ReferenceError: "b" is not defined
+Value of 'a' inside the function 20
+Value of 'a' outside the function 10
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/paramspec.js	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * paramspec - test that Attr doesn't break parameters when specializing
+ *
+ * @run
+ * @test
+ */
+
+function f(a) {
+    var b = ~a;
+    return b == ~17;
+}
+
+print(f("17"));
+print(f(17));
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/paramspec.js.EXPECTED	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,2 @@
+true
+true
--- a/test/script/basic/runsunspider.js	Tue May 14 11:15:12 2013 -0300
+++ b/test/script/basic/runsunspider.js	Tue May 14 11:16:52 2013 -0300
@@ -86,7 +86,7 @@
 	    changed = true;
 	}
     } catch (e) {
-	print("error: " + e);
+	print("error: " + e.printStackTrace());
 	if (e.toString().indexOf(tests) == 1) {
 	    throw e;
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/currently-failing/logcoverage.js	Tue May 14 11:16:52 2013 -0300
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * mh_coverage.js
+ * Screen scrape various logs to ensure that we cover enough functionality, 
+ * e.g. method handle instrumentation
+ *
+ * @test
+ * @run
+ */
+
+/*
+ * creates new script engine initialized with given options and
+ * runs given code on it. Returns standard output captured.
+ */
+
+function runScriptEngine(opts, name) {
+    var imports = new JavaImporter(
+        Packages.jdk.nashorn.api.scripting,
+        java.io, java.lang, java.util);
+
+    with(imports) {
+        var fac = new NashornScriptEngineFactory();
+        // get current System.err
+        var oldErr = System.err;
+	var oldOut = System.out;
+        var baosErr = new ByteArrayOutputStream();
+        var newErr = new PrintStream(baosErr);
+        var baosOut = new ByteArrayOutputStream();
+	var newOut = new PrintStream(baosOut);
+        try {
+            // set new standard err
+            System.setErr(newErr);
+            System.setOut(newOut);
+            var strType = Java.type("java.lang.String");
+            var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType));
+	    var reader = new java.io.FileReader(name);
+            engine.eval(reader);
+            newErr.flush();
+	    newOut.flush();
+            return new java.lang.String(baosErr.toByteArray());
+        } finally {
+            // restore System.err to old value
+            System.setErr(oldErr);
+	    System.setOut(oldOut);
+        }
+    }
+}
+
+var str;
+
+var methodsCalled = [
+   'asCollector', 
+   'asType', 
+   'bindTo', 
+   'dropArguments', 
+   'explicitCastArguments', 
+   'filterArguments', 
+   'filterReturnValue', 
+   'findStatic', 
+   'findVirtual',  
+   'foldArguments', 
+   'getter', 
+   'guardWithTest', 
+   'insertArguments', 
+   'methodType', 
+   'setter'
+];
+
+function check(str, strs) {
+    for each (s in strs) {
+       if (str.indexOf(s) !== -1) {
+	   continue;
+       }
+       print(s + " not found");
+       return;
+    }
+    print("check ok!");
+}
+
+str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js");
+str += runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/varargs.js");
+
+check(str, methodsCalled);
+check(str, ['return', 'get', 'set', '[fields]']);
+check(str, ['codegen']);
+
+print("hello, world!");
--- a/test/script/trusted/logcoverage.js	Tue May 14 11:15:12 2013 -0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- * 
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- * 
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- * 
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- * 
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * mh_coverage.js
- * Screen scrape various logs to ensure that we cover enough functionality, 
- * e.g. method handle instrumentation
- *
- * @test
- * @run
- */
-
-/*
- * creates new script engine initialized with given options and
- * runs given code on it. Returns standard output captured.
- */
-
-function runScriptEngine(opts, name) {
-    var imports = new JavaImporter(
-        Packages.jdk.nashorn.api.scripting,
-        java.io, java.lang, java.util);
-
-    with(imports) {
-        var fac = new NashornScriptEngineFactory();
-        // get current System.err
-        var oldErr = System.err;
-	var oldOut = System.out;
-        var baosErr = new ByteArrayOutputStream();
-        var newErr = new PrintStream(baosErr);
-        var baosOut = new ByteArrayOutputStream();
-	var newOut = new PrintStream(baosOut);
-        try {
-            // set new standard err
-            System.setErr(newErr);
-            System.setOut(newOut);
-            var strType = Java.type("java.lang.String");
-            var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType));
-	    var reader = new java.io.FileReader(name);
-            engine.eval(reader);
-            newErr.flush();
-	    newOut.flush();
-            return new java.lang.String(baosErr.toByteArray());
-        } finally {
-            // restore System.err to old value
-            System.setErr(oldErr);
-	    System.setOut(oldOut);
-        }
-    }
-}
-
-var str;
-
-var methodsCalled = [
-   'asCollector', 
-   'asType', 
-   'bindTo', 
-   'dropArguments', 
-   'explicitCastArguments', 
-   'filterArguments', 
-   'filterReturnValue', 
-   'findStatic', 
-   'findVirtual',  
-   'foldArguments', 
-   'getter', 
-   'guardWithTest', 
-   'insertArguments', 
-   'methodType', 
-   'setter'
-];
-
-function check(str, strs) {
-    for each (s in strs) {
-       if (s.indexOf(str) !== -1) {
-	   continue;
-       }
-       print(method + "not found");
-       return;
-    }
-    print("check ok!");
-}
-
-str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js");
-
-check(str, methodsCalled);
-check(str, ['return', 'get', 'set', '[fields]']);
-check(str, ['codegen']);
-
-print("hello, world!");
--- a/test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java	Tue May 14 11:15:12 2013 -0300
+++ b/test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java	Tue May 14 11:16:52 2013 -0300
@@ -117,7 +117,7 @@
     // run this test - compile or compile-and-run depending on option passed
     public void runTest() throws IOException {
         log(toString());
-
+        Thread.currentThread().setName(testFile.getPath());
         if (shouldRun) {
             // Analysis of failing tests list -
             // if test is in failing list it must fail
--- a/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java	Tue May 14 11:15:12 2013 -0300
+++ b/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java	Tue May 14 11:16:52 2013 -0300
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.test.framework;
 
+import static jdk.nashorn.internal.test.framework.TestConfig.TEST_FAILED_LIST_FILE;
 import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_ENABLE_STRICT_MODE;
 import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_EXCLUDES_FILE;
 import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_EXCLUDE_LIST;
@@ -37,6 +38,7 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FileReader;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
@@ -324,7 +326,8 @@
         });
     }
 
-    public void run() {
+    @SuppressWarnings("resource")
+    public boolean run() throws IOException {
         final int testCount = tests.size();
         int passCount = 0;
         int doneCount = 0;
@@ -371,23 +374,36 @@
         });
 
         boolean hasFailed = false;
-        for (final ScriptRunnable.Result result : results) {
-            if (!result.passed()) {
-                if (hasFailed == false) {
-                    hasFailed = true;
-                    System.out.println();
-                    System.out.println("FAILED TESTS");
-                }
+        final String failedList = System.getProperty(TEST_FAILED_LIST_FILE);
+        final boolean hasFailedList = failedList != null;
+        final boolean hadPreviouslyFailingTests = hasFailedList && new File(failedList).length() > 0;
+        final FileWriter failedFileWriter = hasFailedList ? new FileWriter(failedList) : null;
+        try {
+            final PrintWriter failedListWriter = failedFileWriter == null ? null : new PrintWriter(failedFileWriter);
+            for (final ScriptRunnable.Result result : results) {
+                if (!result.passed()) {
+                    if (hasFailed == false) {
+                        hasFailed = true;
+                        System.out.println();
+                        System.out.println("FAILED TESTS");
+                    }
 
-                System.out.println(result.getTest());
-                if (result.exception != null) {
-                    final String exceptionString = result.exception instanceof TestFailedError ? result.exception.getMessage() : result.exception.toString();
-                    System.out.print(exceptionString.endsWith("\n") ? exceptionString : exceptionString + "\n");
-                    System.out.print(result.out != null ? result.out : "");
+                    System.out.println(result.getTest());
+                    if(failedFileWriter != null) {
+                        failedListWriter.println(result.getTest().testFile.getPath());
+                    }
+                    if (result.exception != null) {
+                        final String exceptionString = result.exception instanceof TestFailedError ? result.exception.getMessage() : result.exception.toString();
+                        System.out.print(exceptionString.endsWith("\n") ? exceptionString : exceptionString + "\n");
+                        System.out.print(result.out != null ? result.out : "");
+                    }
                 }
             }
+        } finally {
+            if(failedFileWriter != null) {
+                failedFileWriter.close();
+            }
         }
-
         final double timeElapsed = (System.nanoTime() - startTime) / 1e9; // [s]
         System.out.printf("Tests run: %d/%d tests, passed: %d (%.2f%%), failed: %d. Time elapsed: %.0fmin %.0fs.\n", doneCount, testCount, passCount, 100d * passCount / doneCount, doneCount - passCount, timeElapsed / 60, timeElapsed % 60);
         System.out.flush();
@@ -397,12 +413,25 @@
         if (hasFailed) {
             throw new AssertionError("TEST FAILED");
         }
+
+        if(hasFailedList) {
+            new File(failedList).delete();
+        }
+
+        if(hadPreviouslyFailingTests) {
+            System.out.println();
+            System.out.println("Good job on getting all your previously failing tests pass!");
+            System.out.println("NOW re-running all tests to make sure you haven't caused any NEW test failures.");
+            System.out.println();
+        }
+
+        return hadPreviouslyFailingTests;
     }
 
     public static void main(final String[] args) throws Exception {
         parseArgs(args);
 
-        new ParallelTestRunner().run();
+        while(new ParallelTestRunner().run());
     }
 
     private static void parseArgs(final String[] args) {
--- a/test/src/jdk/nashorn/internal/test/framework/TestConfig.java	Tue May 14 11:15:12 2013 -0300
+++ b/test/src/jdk/nashorn/internal/test/framework/TestConfig.java	Tue May 14 11:16:52 2013 -0300
@@ -72,4 +72,7 @@
 
     // shared context mode or not
     static final String TEST_JS_SHARED_CONTEXT              = "test.js.shared.context";
+
+    // file for storing last run's failed tests
+    static final String TEST_FAILED_LIST_FILE = "test.failed.list.file";
 }
--- a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java	Tue May 14 11:15:12 2013 -0300
+++ b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java	Tue May 14 11:16:52 2013 -0300
@@ -31,6 +31,7 @@
 import static jdk.nashorn.internal.test.framework.TestConfig.OPTIONS_EXPECT_RUN_FAIL;
 import static jdk.nashorn.internal.test.framework.TestConfig.OPTIONS_IGNORE_STD_ERROR;
 import static jdk.nashorn.internal.test.framework.TestConfig.OPTIONS_RUN;
+import static jdk.nashorn.internal.test.framework.TestConfig.TEST_FAILED_LIST_FILE;
 import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_ENABLE_STRICT_MODE;
 import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_EXCLUDES_FILE;
 import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_EXCLUDE_DIR;
@@ -41,7 +42,9 @@
 import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_ROOTS;
 import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_UNCHECKED_DIR;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileReader;
 import java.io.IOException;
 import java.nio.file.FileSystem;
 import java.nio.file.FileSystems;
@@ -86,6 +89,22 @@
     static <T> void findAllTests(final List<T> tests, final Set<String> orphans, final TestFactory<T> testFactory) throws Exception {
         final String framework = System.getProperty(TEST_JS_FRAMEWORK);
         final String testList = System.getProperty(TEST_JS_LIST);
+        final String failedTestFileName = System.getProperty(TEST_FAILED_LIST_FILE);
+        if(failedTestFileName != null) {
+            File failedTestFile = new File(failedTestFileName);
+            if(failedTestFile.exists() && failedTestFile.length() > 0L) {
+                try(final BufferedReader r = new BufferedReader(new FileReader(failedTestFile))) {
+                    for(;;) {
+                        final String testFileName = r.readLine();
+                        if(testFileName == null) {
+                            break;
+                        }
+                        handleOneTest(framework, new File(testFileName).toPath(), tests, orphans, testFactory);
+                    }
+                }
+                return;
+            }
+        }
         if (testList == null || testList.length() == 0) {
             // Run the tests under the test roots dir, selected by the
             // TEST_JS_INCLUDES patterns