8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes.
authorlagergren
Tue, 07 May 2013 14:43:17 +0200
changeset 17524 703643aeb0d6
parent 17523 cb4a7c901e0d
child 17525 6582a7788183
8013914: Removed explicit LineNumberNodes that were too brittle when code moves around, and also introduced unnecessary footprint. Introduced the Statement node and fixed dead code elimination issues that were discovered by the absense of labels for LineNumberNodes. Reviewed-by: jlaskey, attila
nashorn/make/project.properties
nashorn/src/jdk/nashorn/internal/codegen/Attr.java
nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java
nashorn/src/jdk/nashorn/internal/codegen/Label.java
nashorn/src/jdk/nashorn/internal/codegen/Lower.java
nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
nashorn/src/jdk/nashorn/internal/codegen/Splitter.java
nashorn/src/jdk/nashorn/internal/ir/Block.java
nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
nashorn/src/jdk/nashorn/internal/ir/BreakNode.java
nashorn/src/jdk/nashorn/internal/ir/BreakableNode.java
nashorn/src/jdk/nashorn/internal/ir/CallNode.java
nashorn/src/jdk/nashorn/internal/ir/CatchNode.java
nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java
nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java
nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java
nashorn/src/jdk/nashorn/internal/ir/ForNode.java
nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java
nashorn/src/jdk/nashorn/internal/ir/IfNode.java
nashorn/src/jdk/nashorn/internal/ir/LabelNode.java
nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java
nashorn/src/jdk/nashorn/internal/ir/LineNumberNode.java
nashorn/src/jdk/nashorn/internal/ir/LoopNode.java
nashorn/src/jdk/nashorn/internal/ir/Node.java
nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java
nashorn/src/jdk/nashorn/internal/ir/SplitNode.java
nashorn/src/jdk/nashorn/internal/ir/Statement.java
nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java
nashorn/src/jdk/nashorn/internal/ir/Symbol.java
nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java
nashorn/src/jdk/nashorn/internal/ir/TryNode.java
nashorn/src/jdk/nashorn/internal/ir/VarNode.java
nashorn/src/jdk/nashorn/internal/ir/WhileNode.java
nashorn/src/jdk/nashorn/internal/ir/WithNode.java
nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
nashorn/src/jdk/nashorn/internal/objects/Global.java
nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java
nashorn/src/jdk/nashorn/internal/parser/Parser.java
nashorn/src/jdk/nashorn/internal/runtime/Context.java
nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java
nashorn/src/jdk/nashorn/tools/Shell.java
nashorn/test/script/basic/no_line_numbers.js
nashorn/test/script/basic/no_line_numbers.js.EXPECTED
--- a/nashorn/make/project.properties	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/make/project.properties	Tue May 07 14:43:17 2013 +0200
@@ -214,7 +214,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/nashorn/src/jdk/nashorn/internal/codegen/Attr.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java	Tue May 07 14:43:17 2013 +0200
@@ -78,6 +78,7 @@
 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.TernaryNode;
@@ -154,7 +155,9 @@
 
     @Override
     public Node leaveAccessNode(final AccessNode accessNode) {
-        //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this
+        //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));
     }
 
@@ -435,6 +438,7 @@
             final IdentNode callee = compilerConstant(CALLEE);
             VarNode selfInit =
                 new VarNode(
+                    newFunctionNode.getLineNumber(),
                     newFunctionNode.getToken(),
                     newFunctionNode.getFinish(),
                     newFunctionNode.getIdent(),
@@ -442,7 +446,7 @@
 
             LOG.info("Accepting self symbol init ", selfInit, " for ", newFunctionNode.getName());
 
-            final List<Node> newStatements = new ArrayList<>();
+            final List<Statement> newStatements = new ArrayList<>();
             assert callee.getSymbol() != null && callee.getSymbol().hasSlot();
 
             final IdentNode name       = selfInit.getName();
@@ -492,7 +496,7 @@
             final Symbol pseudoSymbol = pseudoSymbol(name);
             LOG.info("IdentNode is property name -> assigning pseudo symbol ", pseudoSymbol);
             LOG.unindent();
-            return identNode.setSymbol(lc, pseudoSymbol);
+            return end(identNode.setSymbol(lc, pseudoSymbol));
         }
 
         final Block block = lc.getCurrentBlock();
@@ -658,7 +662,7 @@
         if (literalNode instanceof ArrayLiteralNode) {
             ((ArrayLiteralNode)literalNode).analyze();
         }
-        return literalNode.setSymbol(getLexicalContext(), symbol);
+        return end(literalNode.setSymbol(getLexicalContext(), symbol));
     }
 
     @Override
@@ -779,17 +783,18 @@
         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
             // leaveIdentNode unless we remove the name from the localdef list.
             removeLocalDef(name);
-            return newVarNode;
+            return newVarNode.setSymbol(lc, symbol);
         }
 
         addLocalDef(name);
 
-        final LexicalContext lc = getLexicalContext();
-        final Symbol  symbol = findSymbol(lc.getCurrentBlock(), ident.getName());
         assert symbol != null;
 
         final IdentNode newIdent = (IdentNode)ident.setSymbol(lc, symbol);
@@ -1398,7 +1403,9 @@
     private FunctionNode finalizeParameters(final FunctionNode functionNode) {
         final List<IdentNode> newParams = new ArrayList<>();
         final boolean isVarArg = functionNode.isVarArg();
+        final int nparams = functionNode.getParameters().size();
 
+        int specialize = 0;
         int pos = 0;
         for (final IdentNode param : functionNode.getParameters()) {
             final Symbol paramSymbol = functionNode.getBody().getExistingSymbol(param.getName());
@@ -1414,9 +1421,13 @@
 
             // 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()) {
+            // 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()));
@@ -1429,7 +1440,13 @@
             pos++;
         }
 
-        return functionNode.setParameters(getLexicalContext(), newParams);
+        FunctionNode newFunctionNode = functionNode;
+
+        if (nparams == 0 || (specialize * 2) < nparams) {
+            newFunctionNode = newFunctionNode.clearSnapshot(getLexicalContext());
+        }
+
+        return newFunctionNode.setParameters(getLexicalContext(), newParams);
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue May 07 14:43:17 2013 +0200
@@ -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;
 
@@ -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();
@@ -1148,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();
@@ -1187,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;
     }
 
     /**
@@ -1524,6 +1541,8 @@
 
     @Override
     public boolean enterReturnNode(final ReturnNode returnNode) {
+        lineNumber(returnNode);
+
         method.registerReturn();
 
         final Type returnType = getLexicalContext().getCurrentFunction().getReturnType();
@@ -1733,6 +1752,8 @@
 
     @Override
     public boolean enterSplitNode(final SplitNode splitNode) {
+        lineNumber(splitNode);
+
         final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
 
         final FunctionNode fn   = getLexicalContext().getCurrentFunction();
@@ -1876,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();
@@ -1958,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];
                 }
@@ -2004,6 +2026,8 @@
 
     @Override
     public boolean enterThrowNode(final ThrowNode throwNode) {
+        lineNumber(throwNode);
+
         method._new(ECMAException.class).dup();
 
         final Source source     = getLexicalContext().getCurrentFunction().getSource();
@@ -2028,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();
@@ -2124,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";
 
@@ -2162,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();
@@ -2184,7 +2215,7 @@
     }
 
     private void closeWith() {
-        if(method.hasScope()) {
+        if (method.hasScope()) {
             method.loadCompilerConstant(SCOPE);
             method.invoke(ScriptRuntime.CLOSE_WITH);
             method.storeCompilerConstant(SCOPE);
@@ -2227,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");
@@ -3010,6 +3041,7 @@
      * @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;
@@ -3190,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);
@@ -3288,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/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Tue May 07 14:43:17 2013 +0200
@@ -228,19 +228,19 @@
     }
 
     @Override
-    public Node leaveBIT_AND(BinaryNode binaryNode) {
+    public Node leaveBIT_AND(final BinaryNode binaryNode) {
         assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
         return leaveBinary(binaryNode, Type.INT, Type.INT);
     }
 
     @Override
-    public Node leaveBIT_OR(BinaryNode binaryNode) {
+    public Node leaveBIT_OR(final BinaryNode binaryNode) {
         assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
         return leaveBinary(binaryNode, Type.INT, Type.INT);
     }
 
     @Override
-    public Node leaveBIT_XOR(BinaryNode binaryNode) {
+    public Node leaveBIT_XOR(final BinaryNode binaryNode) {
         assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
         return leaveBinary(binaryNode, Type.INT, Type.INT);
     }
--- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java	Tue May 07 14:43:17 2013 +0200
@@ -88,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);
         }
--- a/nashorn/src/jdk/nashorn/internal/codegen/Label.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Label.java	Tue May 07 14:43:17 2013 +0200
@@ -27,6 +27,7 @@
 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,13 +36,16 @@
  *
  * see -Dnashorn.codegen.debug, --log=codegen
  */
-public class Label extends jdk.internal.org.objectweb.asm.Label {
+public final class Label {
     /** Name of this label */
     private final String name;
 
     /** Type stack at this label */
     private ArrayDeque<Type> stack;
 
+    /** ASM representation of this label */
+    private jdk.internal.org.objectweb.asm.Label label;
+
     /**
      * Constructor
      *
@@ -62,6 +66,14 @@
         this.name = label.name;
     }
 
+
+    jdk.internal.org.objectweb.asm.Label getLabel() {
+        if (this.label == null) {
+            this.label = new jdk.internal.org.objectweb.asm.Label();
+        }
+        return label;
+    }
+
     ArrayDeque<Type> getStack() {
         return stack;
     }
@@ -72,12 +84,7 @@
 
     @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/nashorn/src/jdk/nashorn/internal/codegen/Lower.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java	Tue May 07 14:43:17 2013 +0200
@@ -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;
@@ -120,7 +124,7 @@
         final LexicalContext lc = getLexicalContext();
         final FunctionNode   function = lc.getCurrentFunction();
         if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) {
-            new ExecuteNode(block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
+            new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
         }
         return true;
     }
@@ -132,19 +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(
+                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()) {
@@ -239,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;
@@ -271,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;
             }
@@ -283,16 +282,17 @@
     }
 
     private Block catchAllBlock(final TryNode tryNode) {
-        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(token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all"));
 
-        final Block catchBody = new Block(token, finish, new ThrowNode(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(token, finish, new IdentNode(exception), null, catchBody);
-        final Block     catchAllBlock = new Block(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
 
@@ -304,7 +304,7 @@
         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();
     }
 
@@ -316,7 +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 int    finish = tryNode.getFinish();
+        final int finish = tryNode.getFinish();
 
         assert tryNode.getFinallyBody() == null;
 
@@ -338,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(throwNode.getToken(), throwNode.getFinish(), newStatements);
+                    return new Block(throwNode.getLineNumber(), throwNode.getToken(), throwNode.getFinish(), newStatements);
                 }
                 return throwNode;
             }
@@ -360,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(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;
                 }
@@ -377,16 +377,16 @@
                     newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode));
                 }
 
-                return new ExecuteNode(new Block(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(endpoint.getToken(), finish, newStatements));
+                    return new ExecuteNode(endpoint.getLineNumber(), endpoint.getToken(), endpoint.getFinish(), new Block(endpoint.getLineNumber(), endpoint.getToken(), finish, newStatements));
                 }
                 return endpoint;
             }
@@ -394,7 +394,7 @@
 
         addStatement(newTryNode);
         for (final Node statement : finallyBody.getStatements()) {
-            addStatement(statement);
+            addStatement((Statement)statement);
         }
 
         return newTryNode;
@@ -448,7 +448,7 @@
         if (tryNode.getCatchBlocks().isEmpty()) {
             newTryNode = tryNode.setFinallyBody(null);
         } else {
-            Block outerBody = new Block(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);
         }
 
@@ -465,7 +465,7 @@
     public Node leaveVarNode(final VarNode varNode) {
         addStatement(varNode);
         if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) {
-            new ExecuteNode(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;
     }
@@ -477,7 +477,7 @@
 
         if (conservativeAlwaysTrue(test)) {
             //turn it into a for node without a test.
-            final ForNode forNode = (ForNode)new ForNode(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;
         }
@@ -490,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}
@@ -616,7 +606,7 @@
     }
 
 
-    private Node addStatement(final Node statement) {
+    private Node addStatement(final Statement statement) {
         ((BlockLexicalContext)getLexicalContext()).appendStatement(statement);
         return statement;
     }
--- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue May 07 14:43:17 2013 +0200
@@ -71,6 +71,7 @@
 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;
@@ -189,7 +190,7 @@
     @Override
     public void begin() {
         classEmitter.beginMethod(this);
-        stack = new ArrayDeque<>();
+        newStack();
         method.visitCode();
     }
 
@@ -205,6 +206,10 @@
         classEmitter.endMethod(this);
     }
 
+    private void newStack() {
+        stack = new ArrayDeque<>();
+    }
+
     @Override
     public String toString() {
         return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this);
@@ -484,7 +489,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 +514,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 +620,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 +632,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));
     }
 
     /**
@@ -1228,6 +1222,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 +1237,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 +1250,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 +1360,7 @@
             popType();
         }
         mergeStackTo(label);
-        method.visitJumpInsn(opcode, label);
+        method.visitJumpInsn(opcode, label.getLabel());
     }
 
     /**
@@ -1487,9 +1489,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
     }
 
     /**
@@ -1521,13 +1523,24 @@
     /**
      * 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) {
+        //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 ArrayDeque<Type> labelStack = label.getStack();
-        //debug(labelStack == null ? " >> Control flow - first visit ", label : " >> Control flow - JOIN with ", labelStack, " at ", label);
         if (labelStack == null) {
-            assert stack != null;
             label.setStack(stack.clone());
             return;
         }
@@ -1548,14 +1561,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());
     }
 
     /**
@@ -2018,8 +2031,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,7 +2134,7 @@
                 pad--;
             }
 
-            if (!stack.isEmpty()) {
+            if (stack != null && !stack.isEmpty()) {
                 sb.append("{");
                 sb.append(stack.size());
                 sb.append(":");
--- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java	Tue May 07 14:43:17 2013 +0200
@@ -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,6 +41,7 @@
 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.options.Options;
@@ -126,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;
@@ -181,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()) {
@@ -219,14 +221,15 @@
      *
      * @return New split node.
      */
-    private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Node> statements, final long weight) {
-        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(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
--- a/nashorn/src/jdk/nashorn/internal/ir/Block.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/Block.java	Tue May 07 14:43:17 2013 +0200
@@ -44,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;
@@ -76,12 +76,13 @@
     /**
      * Constructor
      *
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param statements statements
      */
-    public Block(final long token, final int finish, final Node... statements) {
-        super(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<>();
@@ -92,15 +93,16 @@
     /**
      * Constructor
      *
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param statements statements
      */
-    public Block(final long token, final int finish, final List<Node> statements) {
-        this(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, final Map<String, Symbol> symbols) {
+    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;
@@ -131,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;
@@ -226,7 +228,7 @@
      *
      * @return a list of statements
      */
-    public List<Node> getStatements() {
+    public List<Statement> getStatements() {
         return Collections.unmodifiableList(statements);
     }
 
@@ -237,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;
         }
--- a/nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java	Tue May 07 14:43:17 2013 +0200
@@ -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,7 +59,7 @@
      * Get the statement list from the stack, possibly filtered
      * @return statement list
      */
-    protected List<Node> popStatements() {
+    protected List<Statement> popStatements() {
         return sstack.pop();
     }
 
@@ -68,7 +68,7 @@
     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/nashorn/src/jdk/nashorn/internal/ir/BreakNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/BreakNode.java	Tue May 07 14:43:17 2013 +0200
@@ -32,19 +32,20 @@
  * 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 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 long token, final int finish, final IdentNode label) {
-        super(token, finish);
+    public BreakNode(final int lineNumber, final long token, final int finish, final IdentNode label) {
+        super(lineNumber, token, finish);
         this.label = label;
     }
 
--- a/nashorn/src/jdk/nashorn/internal/ir/BreakableNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/BreakableNode.java	Tue May 07 14:43:17 2013 +0200
@@ -44,12 +44,13 @@
     /**
      * Constructor
      *
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param breakLabel break label
      */
-    protected BreakableNode(final long token, final int finish, final Label breakLabel) {
-        super(token, finish);
+    protected BreakableNode(final int lineNumber, final long token, final int finish, final Label breakLabel) {
+        super(lineNumber, token, finish);
         this.breakLabel = breakLabel;
     }
 
--- a/nashorn/src/jdk/nashorn/internal/ir/CallNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/CallNode.java	Tue May 07 14:43:17 2013 +0200
@@ -136,13 +136,14 @@
     /**
      * Constructors
      *
-     * @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 long token, final int finish, final Node function, final List<Node> args) {
-        super(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;
--- a/nashorn/src/jdk/nashorn/internal/ir/CatchNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/CatchNode.java	Tue May 07 14:43:17 2013 +0200
@@ -32,7 +32,7 @@
  * 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;
 
@@ -45,14 +45,15 @@
     /**
      * Constructors
      *
+     * @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 long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) {
-        super(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;
--- a/nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java	Tue May 07 14:43:17 2013 +0200
@@ -32,19 +32,20 @@
  * IR representation for CONTINUE statements.
  */
 @Immutable
-public class ContinueNode extends Node {
+public class ContinueNode extends Statement {
 
     private IdentNode label;
 
     /**
      * Constructor
      *
-     * @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 long token, final int finish, final IdentNode label) {
-        super(token, finish);
+    public ContinueNode(final int lineNumber, final long token, final int finish, final IdentNode label) {
+        super(lineNumber, token, finish);
         this.label = label;
     }
 
--- a/nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java	Tue May 07 14:43:17 2013 +0200
@@ -32,25 +32,26 @@
  * 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 lineNumber line number
      * @param token      token
      * @param finish     finish
      */
-    public EmptyNode(final long token, final int finish) {
-        super(token, finish);
+    public EmptyNode(final int lineNumber, final long token, final int finish) {
+        super(lineNumber, token, finish);
     }
 
 
--- a/nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java	Tue May 07 14:43:17 2013 +0200
@@ -34,19 +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 lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param expression the expression to execute
      */
-    public ExecuteNode(final long token, final int finish, final Node expression) {
-        super(token, finish);
+    public ExecuteNode(final int lineNumber, final long token, final int finish, final Node expression) {
+        super(lineNumber, token, finish);
         this.expression = expression;
     }
 
@@ -55,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.getToken(), expression.getFinish());
-        this.expression = expression;
-    }
-
     @Override
     public boolean isTerminal() {
         return expression.isTerminal();
--- a/nashorn/src/jdk/nashorn/internal/ir/ForNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/ForNode.java	Tue May 07 14:43:17 2013 +0200
@@ -56,16 +56,17 @@
     /**
      * Constructor
      *
-     * @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 long token, final int finish, final Node init, final Node test, final Block body, final Node modify, final int flags) {
-        super(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/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java	Tue May 07 14:43:17 2013 +0200
@@ -204,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)
@@ -216,6 +217,7 @@
      */
     public FunctionNode(
         final Source source,
+        final int lineNumber,
         final long token,
         final int finish,
         final long firstToken,
@@ -225,7 +227,7 @@
         final List<IdentNode> parameters,
         final FunctionNode.Kind kind,
         final int flags) {
-        super(token, finish);
+        super(lineNumber, token, finish);
 
         this.source           = source;
         this.ident            = ident;
@@ -303,6 +305,20 @@
     }
 
     /**
+     * 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
@@ -806,5 +822,4 @@
     public Symbol compilerConstant(final CompilerConstants cc) {
         return body.getExistingSymbol(cc.symbolName());
     }
-
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/IfNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/IfNode.java	Tue May 07 14:43:17 2013 +0200
@@ -32,7 +32,7 @@
  * 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;
 
@@ -45,14 +45,15 @@
     /**
      * Constructor
      *
-     * @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 long token, final int finish, final Node test, final Block pass, final Block fail) {
-        super(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/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java	Tue May 07 14:43:17 2013 +0200
@@ -42,13 +42,14 @@
     /**
      * Constructor
      *
-     * @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 long token, final int finish, final IdentNode label, final Block body) {
-        super(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/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java	Tue May 07 14:43:17 2013 +0200
@@ -30,15 +30,16 @@
  * 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 token  token
-     * @param finish finish
+     * @param lineNumber line number
+     * @param token      token
+     * @param finish     finish
      */
-    protected LexicalContextNode(final long token, final int finish) {
-        super(token, finish);
+    protected LexicalContextNode(final int lineNumber, final long token, final int finish) {
+        super(lineNumber, token, finish);
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/ir/LineNumberNode.java	Tue May 07 14:36:57 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +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;
-
-/**
- * IR Node representing a line number
- */
-@Immutable
-public final class LineNumberNode extends Node {
-    /** Line number */
-    private final int lineNumber;
-
-    /**
-     * Constructor
-     *
-     * @param token      token
-     * @param lineNumber the line number
-     */
-    public LineNumberNode(final long token, final int lineNumber) {
-        super(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/nashorn/src/jdk/nashorn/internal/ir/LoopNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/LoopNode.java	Tue May 07 14:43:17 2013 +0200
@@ -49,14 +49,15 @@
     /**
      * Constructor
      *
-     * @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 long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
-        super(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/nashorn/src/jdk/nashorn/internal/ir/Node.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/Node.java	Tue May 07 14:43:17 2013 +0200
@@ -154,15 +154,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
--- a/nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java	Tue May 07 14:43:17 2013 +0200
@@ -34,19 +34,20 @@
  * 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 lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param expression expression to return
      */
-    public ReturnNode(final long token, final int finish, final Node expression) {
-        super(token, finish);
+    public ReturnNode(final int lineNumber, final long token, final int finish, final Node expression) {
+        super(lineNumber, token, finish);
         this.expression = expression;
     }
 
@@ -99,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/nashorn/src/jdk/nashorn/internal/ir/SplitNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/SplitNode.java	Tue May 07 14:43:17 2013 +0200
@@ -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.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/nashorn/src/jdk/nashorn/internal/ir/Statement.java	Tue May 07 14:43:17 2013 +0200
@@ -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/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java	Tue May 07 14:43:17 2013 +0200
@@ -53,14 +53,15 @@
     /**
      * Constructor
      *
+     * @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 long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) {
-        super(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/nashorn/src/jdk/nashorn/internal/ir/Symbol.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java	Tue May 07 14:43:17 2013 +0200
@@ -263,32 +263,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()) {
--- a/nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java	Tue May 07 14:43:17 2013 +0200
@@ -32,23 +32,24 @@
  * 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 lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param expression expression to throw
      */
-    public ThrowNode(final long token, final int finish, final Node expression) {
-        super(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/nashorn/src/jdk/nashorn/internal/ir/TryNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/TryNode.java	Tue May 07 14:43:17 2013 +0200
@@ -37,7 +37,7 @@
  * 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;
 
@@ -59,26 +59,27 @@
     /**
      * Constructor
      *
+     * @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 long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
-        super(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/nashorn/src/jdk/nashorn/internal/ir/VarNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/VarNode.java	Tue May 07 14:43:17 2013 +0200
@@ -32,7 +32,7 @@
  * 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;
 
@@ -53,13 +53,14 @@
     /**
      * Constructor
      *
-     * @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 long token, final int finish, final IdentNode name, final Node init) {
-        this(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) {
@@ -72,14 +73,15 @@
     /**
      * Constructor
      *
-     * @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 long token, final int finish, final IdentNode name, final Node init, final int flags) {
-        super(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/nashorn/src/jdk/nashorn/internal/ir/WhileNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/WhileNode.java	Tue May 07 14:43:17 2013 +0200
@@ -41,12 +41,13 @@
     /**
      * Constructor
      *
-     * @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 long token, final int finish, final boolean isDoWhile) {
-        super(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;
     }
 
@@ -133,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/nashorn/src/jdk/nashorn/internal/ir/WithNode.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/WithNode.java	Tue May 07 14:43:17 2013 +0200
@@ -42,11 +42,12 @@
     /**
      * Constructor
      *
+     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      */
-    public WithNode(final long token, final int finish) {
-        super(token, finish);
+    public WithNode(final int lineNumber, final long token, final int finish) {
+        super(lineNumber, token, finish);
         this.expression = null;
         this.body       = null;
     }
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Tue May 07 14:43:17 2013 +0200
@@ -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++;
         }
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java	Tue May 07 14:43:17 2013 +0200
@@ -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/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Tue May 07 14:43:17 2013 +0200
@@ -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/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Tue May 07 14:43:17 2013 +0200
@@ -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/nashorn/src/jdk/nashorn/internal/objects/Global.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java	Tue May 07 14:43:17 2013 +0200
@@ -1625,6 +1625,7 @@
         this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug"));
     }
 
+    @SuppressWarnings("resource")
     private static Object printImpl(final boolean newLine, final Object... objects) {
         final PrintWriter out = Global.getEnv().getOut();
 
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java	Tue May 07 14:43:17 2013 +0200
@@ -178,6 +178,7 @@
      * @param self self reference
      * @return undefined
      */
+    @SuppressWarnings("resource")
     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object dumpCounters(final Object self) {
         final PrintWriter out = Context.getCurrentErr();
--- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Tue May 07 14:43:17 2013 +0200
@@ -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,7 +277,7 @@
      * @return New block.
      */
     private Block newBlock() {
-        return lc.push(new Block(token, Token.descPosition(token)));
+        return lc.push(new Block(line, token, Token.descPosition(token)));
     }
 
     /**
@@ -314,6 +316,7 @@
         FunctionNode functionNode =
             new FunctionNode(
                 source,
+                line, //TODO?
                 token,
                 Token.descPosition(token),
                 startToken,
@@ -680,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.
@@ -689,10 +690,6 @@
             return;
         }
 
-        if (lineNumberNode != null) {
-            appendStatement(lineNumberNode);
-        }
-
         switch (type) {
         case LBRACE:
             block();
@@ -773,7 +770,7 @@
     private void block() {
         final Block newBlock = getBlock(true);
         // Force block execution.
-        appendStatement(new ExecuteNode(newBlock.getToken(), finish, newBlock));
+        appendStatement(new ExecuteNode(newBlock.getLineNumber(), newBlock.getToken(), finish, newBlock));
     }
 
     /**
@@ -849,6 +846,7 @@
 
         while (true) {
             // Get starting token.
+            final int  varLine  = line;
             final long varToken = token;
             // Get name of var.
             final IdentNode name = getIdent();
@@ -866,7 +864,7 @@
             }
 
             // Allocate var node.
-            final VarNode var = new VarNode(varToken, finish, name, init);
+            final VarNode var = new VarNode(varLine, varToken, finish, name, init);
             vars.add(var);
             appendStatement(var);
 
@@ -898,7 +896,7 @@
      */
     private void emptyStatement() {
         if (env._empty_statements) {
-            appendStatement(new EmptyNode(token, Token.descPosition(token) + Token.descLength(token)));
+            appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token)));
         }
 
         // SEMICOLON checked in caller.
@@ -915,6 +913,7 @@
      */
     private void expressionStatement() {
         // Lookahead checked in caller.
+        final int  expressionLine  = line;
         final long expressionToken = token;
 
         // Get expression and add as statement.
@@ -922,7 +921,7 @@
 
         ExecuteNode executeNode = null;
         if (expression != null) {
-            executeNode = new ExecuteNode(expressionToken, finish, expression);
+            executeNode = new ExecuteNode(expressionLine, expressionToken, finish, expression);
             appendStatement(executeNode);
         } else {
             expect(null);
@@ -947,6 +946,7 @@
      */
     private void ifStatement() {
         // Capture IF token.
+        final int  ifLine  = line;
         final long ifToken = token;
          // IF tested in caller.
         next();
@@ -962,7 +962,7 @@
             fail = getStatement();
         }
 
-        appendStatement(new IfNode(ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
+        appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
     }
 
     /**
@@ -979,8 +979,7 @@
      */
     private void forStatement() {
         // Create FOR node, capturing FOR token.
-        ForNode forNode = new ForNode(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();
@@ -1083,7 +1082,7 @@
             outer = restoreBlock(outer);
         }
 
-        appendStatement(new ExecuteNode(outer.getToken(), outer.getFinish(), outer));
+        appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
      }
 
     /**
@@ -1114,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(whileToken, Token.descPosition(whileToken), false);
+        WhileNode whileNode = new WhileNode(whileLine, whileToken, Token.descPosition(whileToken), false);
         lc.push(whileNode);
 
         try {
@@ -1145,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(doToken, Token.descPosition(doToken), true);
+        WhileNode doWhileNode = new WhileNode(doLine, doToken, Token.descPosition(doToken), true);
         lc.push(doWhileNode);
 
         try {
@@ -1181,6 +1182,7 @@
      */
     private void continueStatement() {
         // Capture CONTINUE token.
+        final int  continueLine  = line;
         final long continueToken = token;
         // CONTINUE tested in caller.
         nextOrEOL();
@@ -1215,7 +1217,7 @@
         endOfLine();
 
         // Construct and add CONTINUE node.
-        appendStatement(new ContinueNode(continueToken, finish, label == null ? null : new IdentNode(label)));
+        appendStatement(new ContinueNode(continueLine, continueToken, finish, label == null ? null : new IdentNode(label)));
     }
 
     /**
@@ -1227,6 +1229,7 @@
      */
     private void breakStatement() {
         // Capture BREAK token.
+        final int  breakLine  = line;
         final long breakToken = token;
         // BREAK tested in caller.
         nextOrEOL();
@@ -1262,7 +1265,7 @@
         endOfLine();
 
         // Construct and add BREAK node.
-        appendStatement(new BreakNode(breakToken, finish, label == null ? null : new IdentNode(label)));
+        appendStatement(new BreakNode(breakLine, breakToken, finish, label == null ? null : new IdentNode(label)));
     }
 
     /**
@@ -1280,6 +1283,7 @@
         }
 
         // Capture RETURN token.
+        final int  returnLine  = line;
         final long returnToken = token;
         // RETURN tested in caller.
         nextOrEOL();
@@ -1301,7 +1305,7 @@
         endOfLine();
 
         // Construct and add RETURN node.
-        appendStatement(new ReturnNode(returnToken, finish, expression));
+        appendStatement(new ReturnNode(returnLine, returnToken, finish, expression));
     }
 
     /**
@@ -1314,6 +1318,7 @@
      */
     private void yieldStatement() {
         // Capture YIELD token.
+        final int  yieldLine  = line;
         final long yieldToken = token;
         // YIELD tested in caller.
         nextOrEOL();
@@ -1335,7 +1340,7 @@
         endOfLine();
 
         // Construct and add YIELD node.
-        appendStatement(new ReturnNode(yieldToken, finish, expression));
+        appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression));
     }
 
     /**
@@ -1348,6 +1353,7 @@
      */
     private void withStatement() {
         // Capture WITH token.
+        final int  withLine  = line;
         final long withToken = token;
         // WITH tested in caller.
         next();
@@ -1358,7 +1364,7 @@
         }
 
         // Get WITH expression.
-        WithNode withNode = new WithNode(withToken, finish);
+        WithNode withNode = new WithNode(withLine, withToken, finish);
 
         try {
             lc.push(withNode);
@@ -1396,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(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 {
@@ -1483,7 +1490,7 @@
             throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
         }
 
-        LabelNode labelNode = new LabelNode(labelToken, finish, ident, null);
+        LabelNode labelNode = new LabelNode(line, labelToken, finish, ident, null);
         try {
             lc.push(labelNode);
             labelNode = labelNode.setBody(lc, getStatement());
@@ -1505,6 +1512,7 @@
      */
     private void throwStatement() {
         // Capture THROW token.
+        final int  throwLine  = line;
         final long throwToken = token;
         // THROW tested in caller.
         nextOrEOL();
@@ -1529,7 +1537,7 @@
 
         endOfLine();
 
-        appendStatement(new ThrowNode(throwToken, finish, expression));
+        appendStatement(new ThrowNode(throwLine, throwToken, finish, expression));
     }
 
     /**
@@ -1551,6 +1559,7 @@
      */
     private void tryStatement() {
         // Capture TRY token.
+        final int  tryLine  = line;
         final long tryToken = token;
         // TRY tested in caller.
         next();
@@ -1565,6 +1574,7 @@
             final List<Block> catchBlocks = new ArrayList<>();
 
             while (type == CATCH) {
+                final int  catchLine  = line;
                 final long catchToken = token;
                 next();
                 expect(LPAREN);
@@ -1587,7 +1597,7 @@
                 try {
                     // Get CATCH body.
                     final Block catchBody = getBlock(true);
-                    final CatchNode catchNode = new CatchNode(catchToken, finish, exception, ifExpression, catchBody);
+                    final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody);
                     appendStatement(catchNode);
                 } finally {
                     catchBlock = restoreBlock(catchBlock);
@@ -1613,7 +1623,7 @@
                 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
             }
 
-            final TryNode tryNode = new TryNode(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);
@@ -1625,7 +1635,7 @@
             outer = restoreBlock(outer);
         }
 
-        appendStatement(new ExecuteNode(outer.getToken(), outer.getFinish(), outer));
+        appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
     }
 
     /**
@@ -1638,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(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>()));
+        appendStatement(new ExecuteNode(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>())));
     }
 
     /**
@@ -1662,6 +1673,7 @@
     @SuppressWarnings("fallthrough")
     private Node primaryExpression() {
         // Capture first token.
+        final int  primaryLine  = line;
         final long primaryToken = token;
 
         switch (type) {
@@ -1689,7 +1701,7 @@
         case XML:
             return getLiteral();
         case EXECSTRING:
-            return execString(primaryToken);
+            return execString(primaryLine, primaryToken);
         case FALSE:
             next();
             return LiteralNode.newInstance(primaryToken, finish, false);
@@ -1733,7 +1745,7 @@
      * @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(primaryToken, finish, ScriptingFunctions.EXEC_NAME);
         // Skip over EXECSTRING.
@@ -1747,7 +1759,7 @@
         // Skip ending of edit string expression.
         expect(RBRACE);
 
-        return new CallNode(primaryToken, finish, execIdent, arguments);
+        return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments);
     }
 
     /**
@@ -2063,6 +2075,7 @@
      * @return Expression node.
      */
     private Node leftHandSideExpression() {
+        int  callLine  = line;
         long callToken = token;
 
         Node lhs = memberExpression();
@@ -2075,12 +2088,13 @@
                 detectSpecialFunction((IdentNode)lhs);
             }
 
-            lhs = new CallNode(callToken, finish, lhs, arguments);
+            lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
         }
 
 loop:
         while (true) {
             // Capture token.
+            callLine  = line;
             callToken = token;
 
             switch (type) {
@@ -2089,7 +2103,7 @@
                 final List<Node> arguments = argumentList();
 
                 // Create call node.
-                lhs = new CallNode(callToken, finish, lhs, arguments);
+                lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
 
                 break;
 
@@ -2140,6 +2154,7 @@
         next();
 
         // Get function base.
+        final int  callLine    = line;
         final Node constructor = memberExpression();
         if (constructor == null) {
             return null;
@@ -2168,7 +2183,7 @@
             arguments.add(objectLiteral());
         }
 
-        final CallNode callNode = new CallNode(constructor.getToken(), finish, constructor, arguments);
+        final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, arguments);
 
         return new UnaryNode(newToken, callNode);
     }
@@ -2303,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();
 
@@ -2388,12 +2402,10 @@
         }
 
         if (isStatement) {
-            final VarNode varNode = new VarNode(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);
             }
         }
@@ -2468,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(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));
@@ -2477,7 +2489,7 @@
                 expect(LBRACE);
 
                 // Gather the function elements.
-                final List<Node> prevFunctionDecls = functionDeclarations;
+                final List<Statement> prevFunctionDecls = functionDeclarations;
                 functionDeclarations = new ArrayList<>();
                 try {
                     sourceElements();
@@ -2501,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);
@@ -2557,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:
@@ -2814,16 +2835,6 @@
         }
     }
 
-    /**
-     * Add a line number node at current position
-     */
-    private LineNumberNode lineNumber() {
-        if (env._debug_lines) {
-            return new LineNumberNode(token, line);
-        }
-        return null;
-    }
-
     @Override
     public String toString() {
         return "[JavaScript Parsing]";
@@ -2844,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/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Tue May 07 14:43:17 2013 +0200
@@ -171,6 +171,7 @@
      * @param str  text to write
      * @param crlf write a carriage return/new line after text
      */
+    @SuppressWarnings("resource")
     public static void err(final String str, final boolean crlf) {
         final PrintWriter err = Context.getCurrentErr();
         if (err != null) {
@@ -509,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
      *
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Tue May 07 14:43:17 2013 +0200
@@ -275,9 +275,10 @@
         }
 
         static class ProfileDumper implements Runnable {
+            @SuppressWarnings("resource")
             @Override
             public void run() {
-                PrintWriter out = null;
+                PrintWriter out    = null;
                 boolean fileOutput = false;
 
                 try {
@@ -446,7 +447,7 @@
          *
          * @throws Throwable if invocation fails or throws exception/error
          */
-        @SuppressWarnings("unused")
+        @SuppressWarnings({"unused", "resource"})
         public Object traceObject(final MethodHandle mh, final Object... args) throws Throwable {
             final PrintWriter out = Context.getCurrentErr();
             tracePrint(out, "ENTER ", args, null);
@@ -464,7 +465,7 @@
          *
          * @throws Throwable if invocation fails or throws exception/error
          */
-        @SuppressWarnings("unused")
+        @SuppressWarnings({"unused", "resource"})
         public void traceVoid(final MethodHandle mh, final Object... args) throws Throwable {
             final PrintWriter out = Context.getCurrentErr();
             tracePrint(out, "ENTER ", args, null);
--- a/nashorn/src/jdk/nashorn/tools/Shell.java	Tue May 07 14:36:57 2013 +0200
+++ b/nashorn/src/jdk/nashorn/tools/Shell.java	Tue May 07 14:43:17 2013 +0200
@@ -392,6 +392,7 @@
      * @param global  global scope object to use
      * @return return code
      */
+    @SuppressWarnings("resource")
     private static int readEvalPrint(final Context context, final ScriptObject global) {
         final String prompt = bundle.getString("shell.prompt");
         final BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/no_line_numbers.js	Tue May 07 14:43:17 2013 +0200
@@ -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/nashorn/test/script/basic/no_line_numbers.js.EXPECTED	Tue May 07 14:43:17 2013 +0200
@@ -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