changeset 1067:ca67ae7c46cb

8012518: Reengineer Parser.java to make it play well with the copy-on-write IR. Summary: Remove the kludges introduced to make the parser work with the copy on write IR. Now everything is done bottom up, finshing node children completely before node parents. The repeated non-functional pattern 'node = node.setSomething(something);' is gone. Resulting code is much more readable, and extensible for future work. The parser is now also consistent with the rest of the stateless copy-on-write world in code generation. Reviewed-by: lagergren, attila, hannesw, shade Contributed-by: andreas.gabrielsson@oracle.com
author lagergren
date Tue, 14 Oct 2014 15:28:24 +0200
parents 7b6e3a8636a8
children 54c8862b39f1
files .hgignore bin/runopt.sh src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LoopNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Node.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WhileNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WithNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeError.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBaseNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBlockNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBreakableNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextLabelNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextLoopNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextSwitchNode.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
diffstat 24 files changed, 1470 insertions(+), 374 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Oct 14 13:04:56 2014 +0200
+++ b/.hgignore	Tue Oct 14 15:28:24 2014 +0200
@@ -26,3 +26,5 @@
 test/lib/testng.jar
 test/script/external/*
 .project
+.externalToolBuilders/*
+.settings/*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/runopt.sh	Tue Oct 14 15:28:24 2014 +0200
@@ -0,0 +1,137 @@
+#!/bin/sh
+#
+# Copyright (c) 2010, 2014, 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.
+#
+
+###########################################################################################
+# This is a helper script to evaluate nashorn with optimistic types
+# it produces a flight recording for every run, and uses the best 
+# known flags for performance for the current configration
+###########################################################################################
+
+# Flags to enable assertions, we need the system assertions too, since
+# this script runs Nashorn in the BCP to override any nashorn.jar that might
+# reside in your $JAVA_HOME/jre/lib/ext/nashorn.jar
+#
+ENABLE_ASSERTIONS_FLAGS="-ea -esa"
+
+# Flags to instrument lambdaform computation, caching, interpretation and compilation
+# Default compile threshold for lambdaforms is 30
+#
+#LAMBDAFORM_FLAGS="\
+#    -Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 \
+#    -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true \
+#    -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true \
+#    -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true"
+
+# Flags to run trusted tests from the Nashorn test suite
+#
+#TRUSTED_TEST_FLAGS="\
+#-Djava.security.manager \
+#-Djava.security.policy=../build/nashorn.policy -Dnashorn.debug"
+
+# Testing out new code optimizations using the generic hotspot "new code" parameter
+#
+#USE_NEW_CODE_FLAGS=-XX:+UnlockDiagnosticVMOptions -XX:+UseNewCode
+
+#
+#-Dnashorn.typeInfo.disabled=false \
+# and for Nashorn options: 
+# --class-cache-size=0 --persistent-code-cache=false 
+
+# Unique timestamped file name for JFR recordings. For JFR, we also have to
+# crank up the stack cutoff depth to 1024, because of ridiculously long lambda form
+# stack traces.
+#
+# It is also recommended that you go into $JAVA_HOME/jre/lib/jfr/default.jfc and
+# set the "method-sampling-interval" Normal and Maximum sample time as low as you
+# can go (10 ms on most platforms). The default is normally higher. The increased
+# sampling overhead is usually negligible for Nashorn runs, but the data is better
+
+if [ -z $JFR_FILENAME ]; then
+    JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
+    echo "Using default JFR filename: ${JFR_FILENAME}..."
+fi
+
+# Flight recorder
+#
+# see above - already in place, copy the flags down here to disable
+ENABLE_FLIGHT_RECORDER_FLAGS="\
+    -XX:+UnlockCommercialFeatures \
+    -XX:+FlightRecorder \
+    -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$JFR_FILENAME,stackdepth=1024"
+
+# Type specialization and math intrinsic replacement should be enabled by default in 8u20 and nine,
+# keeping this flag around for experimental reasons. Replace + with - to switch it off
+#
+#ENABLE_TYPE_SPECIALIZATION_FLAGS=-XX:+UseTypeSpeculation
+
+# Same with math intrinsics. They should be enabled by default in 8u20 and 9, so
+# this disables them if needed
+#
+#DISABLE_MATH_INTRINSICS_FLAGS=-XX:-UseMathExactIntrinsics
+
+# Add timing to time the compilation phases.
+#ENABLE_TIME_FLAGS=--log=time
+
+# Add ShowHiddenFrames to get lambda form internals on the stack traces
+#ENABLE_SHOW_HIDDEN_FRAMES_FLAGS=-XX:+ShowHiddenFrames
+
+# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product,
+# That tired compilation is switched off, for C2 only output and that the number of
+# compiler threads is set to 1 for determinsm.
+#
+#PRINT_ASM_FLAGS=-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \
+
+# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments)
+#TIER_COMPILATION_THRESHOLD_FLAGS=-XX:IncreaseFirstTierCompileThresholdAt=10
+
+# Directory where to look for nashorn.jar in a dist folder. The default is "..", assuming
+# that we run the script from the make dir
+DIR=..
+NASHORN_JAR=$DIR/dist/nashorn.jar
+
+
+# The built Nashorn jar is placed first in the bootclasspath to override the JDK
+# nashorn.jar in $JAVA_HOME/jre/lib/ext. Thus, we also need -esa, as assertions in
+# nashorn count as system assertions in this configuration
+
+# Type profiling default level is 111, 222 adds some compile time, but is faster
+
+$JAVA_HOME/bin/java \
+$ENABLE_ASSERTIONS_FLAGS \
+$LAMBDAFORM_FLAGS \
+$TRUSTED_FLAGS \
+$USE_NEW_CODE_FLAGS \
+$ENABLE_SHOW_HIDDEN_FRAMES_FLAGS \
+$ENABLE_FLIGHT_RECORDER_FLAGS \
+$ENABLE_TYPE_SPECIALIZATION_FLAGS \
+$TIERED_COMPILATION_THRESOLD_FLAGS \
+$DISABLE_MATH_INTRINSICS_FLAGS \
+$PRINT_ASM_FLAGS \
+-Xbootclasspath/p:$NASHORN_JAR \
+-Xms2G -Xmx2G \
+-XX:TypeProfileLevel=222 \
+-cp $CLASSPATH:../build/test/classes/ \
+jdk.nashorn.tools.Shell $ENABLE_TIME_FLAGS ${@}
+
+
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java	Tue Oct 14 15:28:24 2014 +0200
@@ -25,8 +25,6 @@
 
 package jdk.nashorn.api.scripting;
 
-import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-
 import java.lang.invoke.MethodHandle;
 import jdk.internal.dynalink.beans.StaticClass;
 import jdk.internal.dynalink.linker.LinkerServices;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Tue Oct 14 15:28:24 2014 +0200
@@ -80,11 +80,12 @@
     /**
      * Constructor
      *
-     * @param token      token
-     * @param finish     finish
-     * @param statements statements
+     * @param token      The first token of the block
+     * @param finish     The index of the last character
+     * @param flags      The flags of the block
+     * @param statements All statements in the block
      */
-    public Block(final long token, final int finish, final Statement... statements) {
+    public Block(final long token, final int finish, final int flags, final Statement... statements) {
         super(token, finish);
 
         this.statements = Arrays.asList(statements);
@@ -92,29 +93,52 @@
         this.entryLabel = new Label("block_entry");
         this.breakLabel = new Label("block_break");
         final int len = statements.length;
-        this.flags = len > 0 && statements[len - 1].hasTerminalFlags() ? IS_TERMINAL : 0;
+        final int terminalFlags = len > 0 && statements[len - 1].hasTerminalFlags() ? IS_TERMINAL : 0;
+        this.flags = terminalFlags | flags;
         this.conversion = null;
     }
 
     /**
+     * Constructs a new block
+     *
+     * @param token The first token of the block
+     * @param finish The index of the last character
+     * @param statements All statements in the block
+     */
+    public Block(final long token, final int finish, final Statement...statements){
+        this(token, finish, 0, statements);
+    }
+
+    /**
+     * Constructs a new block
+     *
+     * @param token The first token of the block
+     * @param finish The index of the last character
+     * @param statements All statements in the block
+     */
+    public Block(final long token, final int finish, final List<Statement> statements){
+        this(token, finish, 0, statements);
+    }
+
+    /**
      * Constructor
      *
-     * @param token      token
-     * @param finish     finish
-     * @param statements statements
+     * @param token      The first token of the block
+     * @param finish     The index of the last character
+     * @param flags      The flags of the block
+     * @param statements All statements in the block
      */
-    public Block(final long token, final int finish, final List<Statement> statements) {
-        this(token, finish, statements.toArray(new Statement[statements.size()]));
+    public Block(final long token, final int finish, final int flags, final List<Statement> statements) {
+        this(token, finish, flags, statements.toArray(new Statement[statements.size()]));
     }
 
     private Block(final Block block, final int finish, final List<Statement> statements, final int flags, final Map<String, Symbol> symbols, final LocalVariableConversion conversion) {
-        super(block);
+        super(block, finish);
         this.statements = statements;
         this.flags      = flags;
         this.symbols    = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
         this.entryLabel = new Label(block.entryLabel);
         this.breakLabel = new Label(block.breakLabel);
-        this.finish     = finish;
         this.conversion = conversion;
     }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -55,19 +55,36 @@
     private final int flags;
 
     /**
+     * Constructs a ForNode
+     *
+     * @param lineNumber The line number of header
+     * @param token      The for token
+     * @param finish     The last character of the for node
+     * @param body       The body of the for node
+     * @param flags      The flags
+     */
+    public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags){
+        this(lineNumber, token, finish, body, flags, null, null, null);
+    }
+
+    /**
      * Constructor
      *
-     * @param lineNumber line number
-     * @param token      token
-     * @param finish     finish
-     * @param body       body
-     * @param flags      flags
+     * @param lineNumber The line number of header
+     * @param token      The for token
+     * @param finish     The last character of the for node
+     * @param body       The body of the for node
+     * @param flags      The flags
+     * @param init       The initial expression
+     * @param test       The test expression
+     * @param modify     The modify expression
      */
-    public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags) {
-        super(lineNumber, token, finish, body, false);
+    public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags, final Expression init, final JoinPredecessorExpression test, final JoinPredecessorExpression modify) {
+        super(lineNumber, token, finish, body, test, false);
         this.flags  = flags;
-        this.init = null;
-        this.modify = null;
+        this.init = init;
+        this.modify = modify;
+
     }
 
     private ForNode(final ForNode forNode, final Expression init, final JoinPredecessorExpression test,
@@ -166,16 +183,6 @@
     public boolean isForIn() {
         return (flags & IS_FOR_IN) != 0;
     }
-
-    /**
-     * Flag this to be a for in construct
-     * @param lc lexical context
-     * @return new for node if changed or existing if not
-     */
-    public ForNode setIsForIn(final LexicalContext lc) {
-        return setFlags(lc, flags | IS_FOR_IN);
-    }
-
     /**
      * Is this a for each construct, known from e.g. Rhino. This will be a for of construct
      * in ECMAScript 6
@@ -186,15 +193,6 @@
     }
 
     /**
-     * Flag this to be a for each construct
-     * @param lc lexical context
-     * @return new for node if changed or existing if not
-     */
-    public ForNode setIsForEach(final LexicalContext lc) {
-        return setFlags(lc, flags | IS_FOR_EACH);
-    }
-
-    /**
      * If this is a for in or for each construct, there is an iterator symbol
      * @return the symbol for the iterator to be used, or null if none exists
      */
@@ -260,13 +258,6 @@
         return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
     }
 
-    private ForNode setFlags(final LexicalContext lc, final int flags) {
-        if (this.flags == flags) {
-            return this;
-        }
-        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
-    }
-
     @Override
     JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
         return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -31,7 +31,6 @@
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_ENTEREXIT;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES;
-
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.Iterator;
@@ -46,6 +45,7 @@
 import jdk.nashorn.internal.ir.annotations.Ignore;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.Source;
@@ -299,12 +299,16 @@
      * @param token      token
      * @param finish     finish
      * @param firstToken first token of the function node (including the function declaration)
+     * @param lastToken  lastToken
      * @param namespace  the namespace
      * @param ident      the identifier
      * @param name       the name of the function
      * @param parameters parameter list
      * @param kind       kind of function as in {@link FunctionNode.Kind}
      * @param flags      initial flags
+     * @param body       body of the function
+     * @param state      The initial state from the parser. Must be one of {@link CompilationState#PARSED} and {@link CompilationState#PARSE_ERROR}
+     * @param endParserState The parser state at the end of the parsing.
      */
     public FunctionNode(
         final Source source,
@@ -312,12 +316,16 @@
         final long token,
         final int finish,
         final long firstToken,
+        final long lastToken,
         final Namespace namespace,
         final IdentNode ident,
         final String name,
         final List<IdentNode> parameters,
         final FunctionNode.Kind kind,
-        final int flags) {
+        final int flags,
+        final Block body,
+        final CompilationState state,
+        final Object endParserState) {
         super(token, finish);
 
         this.source           = source;
@@ -327,15 +335,15 @@
         this.kind             = kind;
         this.parameters       = parameters;
         this.firstToken       = firstToken;
-        this.lastToken        = token;
+        this.lastToken        = lastToken;
         this.namespace        = namespace;
-        this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
+        this.compilationState = EnumSet.of(CompilationState.INITIALIZED, state);
         this.flags            = flags;
         this.compileUnit      = null;
-        this.body             = null;
+        this.body             = body;
         this.thisProperties   = 0;
         this.rootClass        = null;
-        this.endParserState    = null;
+        this.endParserState    = endParserState;
     }
 
     private FunctionNode(
@@ -439,7 +447,7 @@
      * @return the id
      */
     public int getId() {
-        return position();
+        return isProgram() ? -1: Token.descPosition(firstToken);
     }
 
     /**
@@ -903,34 +911,6 @@
     }
 
     /**
-     * Set the last token for this function's code
-     * @param lc lexical context
-     * @param lastToken the last token
-     * @return function node or a new one if state was changed
-     */
-    public FunctionNode setLastToken(final LexicalContext lc, final long lastToken) {
-        if (this.lastToken == lastToken) {
-            return this;
-        }
-        return Node.replaceInLexicalContext(
-                lc,
-                this,
-                new FunctionNode(
-                        this,
-                        lastToken,
-                        endParserState,
-                        flags,
-                        name,
-                        returnType,
-                        compileUnit,
-                        compilationState,
-                        body,
-                        parameters,
-                        thisProperties,
-                        rootClass));
-    }
-
-    /**
      * Returns the end parser state for this function.
      * @return the end parser state for this function.
      */
@@ -939,33 +919,6 @@
     }
 
     /**
-     * Set the end parser state for this function.
-     * @param lc lexical context
-     * @param endParserState the parser state to set
-     * @return function node or a new one if state was changed
-     */
-    public FunctionNode setEndParserState(final LexicalContext lc, final Object endParserState) {
-        if (this.endParserState == endParserState) {
-            return this;
-        }
-        return Node.replaceInLexicalContext(
-                lc,
-                this,
-                new FunctionNode(
-                        this,
-                        lastToken,
-                        endParserState,
-                        flags,
-                        name,
-                        returnType,
-                        compileUnit,
-                        compilationState,
-                        body,
-                        parameters,
-                        thisProperties, rootClass));
-    }
-
-    /**
      * Get the name of this function
      * @return the name
      */
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LoopNode.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LoopNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -53,14 +53,15 @@
      * @param token              token
      * @param finish             finish
      * @param body               loop body
+     * @param test               test
      * @param controlFlowEscapes controlFlowEscapes
      */
-    protected LoopNode(final int lineNumber, final long token, final int finish, final Block body, final boolean controlFlowEscapes) {
+    protected LoopNode(final int lineNumber, final long token, final int finish, final Block body, final JoinPredecessorExpression test, final boolean controlFlowEscapes) {
         super(lineNumber, token, finish, new Label("while_break"));
         this.continueLabel = new Label("while_continue");
-        this.test = null;
         this.body = body;
         this.controlFlowEscapes = controlFlowEscapes;
+        this.test = test;
     }
 
     /**
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Node.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Node.java	Tue Oct 14 15:28:24 2014 +0200
@@ -39,7 +39,7 @@
     protected final int start;
 
     /** End of source range. */
-    protected int finish;
+    protected final int finish;
 
     /** Token descriptor. */
     private final long token;
@@ -81,6 +81,18 @@
     }
 
     /**
+     * Copy constructor that overrides finish
+     *
+     * @param node source node
+     * @param finish Last character
+     */
+    protected Node(final Node node, final int finish) {
+        this.token = node.token;
+        this.start = node.start;
+        this.finish = finish;
+    }
+
+    /**
      * Is this a loop node?
      *
      * @return true if atom
@@ -152,14 +164,6 @@
     }
 
     /**
-     * Set finish position for this node in the source string
-     * @param finish finish
-     */
-    public void setFinish(final int finish) {
-        this.finish = finish;
-    }
-
-    /**
      * Get start position for node
      * @return start position
      */
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WhileNode.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WhileNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -45,9 +45,11 @@
      * @param token      token
      * @param finish     finish
      * @param isDoWhile  is this a do while loop?
+     * @param test       test expression
+     * @param body       body of the while loop
      */
-    public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile) {
-        super(lineNumber, token, finish, null, false);
+    public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile, final JoinPredecessorExpression test, final Block body) {
+        super(lineNumber, token, finish, body, test, false);
         this.isDoWhile = isDoWhile;
     }
 
@@ -55,10 +57,10 @@
      * Internal copy constructor
      *
      * @param whileNode while node
-     * @param test      test
-     * @param body      body
+     * @param test      Test expression
+     * @param body      body of the while loop
      * @param controlFlowEscapes control flow escapes?
-     * @param conversion TODO
+     * @param conversion local variable conversion info
      */
     private WhileNode(final WhileNode whileNode, final JoinPredecessorExpression test, final Block body, final boolean controlFlowEscapes, final LocalVariableConversion conversion) {
         super(whileNode, test, body, controlFlowEscapes, conversion);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WithNode.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WithNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -42,14 +42,16 @@
     /**
      * Constructor
      *
-     * @param lineNumber line number
-     * @param token      token
-     * @param finish     finish
+     * @param lineNumber Line number of the header
+     * @param token      First token
+     * @param finish     Character index of the last token
+     * @param expression With expression
+     * @param body       Body of with node
      */
-    public WithNode(final int lineNumber, final long token, final int finish) {
+    public WithNode(final int lineNumber, final long token, final int finish, final Expression expression, final Block body) {
         super(lineNumber, token, finish);
-        this.expression = null;
-        this.body       = null;
+        this.expression = expression;
+        this.body       = body;
     }
 
     private WithNode(final WithNode node, final Expression expression, final Block body) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Tue Oct 14 15:28:24 2014 +0200
@@ -561,7 +561,6 @@
      *
      * @param engine ScriptEngine to initialize
      */
-    @SuppressWarnings("hiding")
     public void initBuiltinObjects(final ScriptEngine engine) {
         if (this.builtinObject != null) {
             // already initialized, just return
@@ -1718,7 +1717,6 @@
         return func;
     }
 
-    @SuppressWarnings("hiding")
     private void init(final ScriptEngine engine) {
         assert Context.getGlobal() == this : "this global is not set as current";
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeError.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeError.java	Tue Oct 14 15:28:24 2014 +0200
@@ -27,7 +27,6 @@
 
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import jdk.nashorn.api.scripting.NashornException;
@@ -131,7 +130,6 @@
 
     // This is called NativeError, NativeTypeError etc. to
     // associate a ECMAException with the ECMA Error object.
-    @SuppressWarnings("unused")
     static void initException(final ScriptObject self) {
         // ECMAException constructor has side effects
         new ECMAException(self, null);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java	Tue Oct 14 15:28:24 2014 +0200
@@ -27,7 +27,6 @@
 
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Array;
 import java.util.Collection;
@@ -36,7 +35,6 @@
 import jdk.internal.dynalink.beans.StaticClass;
 import jdk.internal.dynalink.support.TypeUtilities;
 import jdk.nashorn.api.scripting.JSObject;
-import jdk.nashorn.api.scripting.ScriptUtils;
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Tue Oct 14 15:28:24 2014 +0200
@@ -53,7 +53,6 @@
 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON;
 import static jdk.nashorn.internal.parser.TokenType.TERNARY;
 import static jdk.nashorn.internal.parser.TokenType.WHILE;
-
 import java.io.Serializable;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -71,10 +70,8 @@
 import jdk.nashorn.internal.ir.BaseNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
-import jdk.nashorn.internal.ir.BlockLexicalContext;
 import jdk.nashorn.internal.ir.BlockStatement;
 import jdk.nashorn.internal.ir.BreakNode;
-import jdk.nashorn.internal.ir.BreakableNode;
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
@@ -90,9 +87,7 @@
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.JoinPredecessorExpression;
 import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
-import jdk.nashorn.internal.ir.LoopNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ObjectNode;
 import jdk.nashorn.internal.ir.PropertyKey;
@@ -138,8 +133,8 @@
 
     private List<Statement> functionDeclarations;
 
-    private final BlockLexicalContext lc = new BlockLexicalContext();
-    private final Deque<Object> defaultNames = new ArrayDeque<>();
+    private final ParserContext lc;
+    private final Deque<Object> defaultNames;
 
     /** Namespace for function names where not explicitly given */
     private final Namespace namespace;
@@ -187,6 +182,8 @@
      */
     public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) {
         super(source, errors, strict, lineOffset);
+        this.lc = new ParserContext();
+        this.defaultNames = new ArrayDeque<>();
         this.env = env;
         this.namespace = new Namespace(env.getNamespace());
         this.scripting = env._scripting;
@@ -344,26 +341,35 @@
             final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
             // Set up the function to append elements.
 
-            FunctionNode function = newFunctionNode(
-                functionToken,
-                new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName()),
-                new ArrayList<IdentNode>(),
-                FunctionNode.Kind.NORMAL,
-                functionLine);
+            final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName());
+            final ParserContextFunctionNode function = createParserContextFunctionNode(ident, functionToken, FunctionNode.Kind.NORMAL, functionLine, Collections.<IdentNode>emptyList());
+            lc.push(function);
+
+            final ParserContextBlockNode body = newBlock();
 
             functionDeclarations = new ArrayList<>();
             sourceElements(false);
             addFunctionDeclarations(function);
             functionDeclarations = null;
 
+            restoreBlock(body);
+            body.setFlag(Block.NEEDS_SCOPE);
+
+            final Block functionBody = new Block(functionToken, source.getLength() - 1, body.getFlags(), body.getStatements());
+            lc.pop(function);
+
             expect(EOF);
 
-            function.setFinish(source.getLength() - 1);
-            function = restoreFunctionNode(function, token); //commit code
-            function = function.setBody(lc, function.getBody().setNeedsScope(lc));
-
-            printAST(function);
-            return function;
+            final FunctionNode functionNode = createFunctionNode(
+                    function,
+                    functionToken,
+                    ident,
+                    Collections.<IdentNode>emptyList(),
+                    FunctionNode.Kind.NORMAL,
+                    functionLine,
+                    functionBody);
+            printAST(functionNode);
+            return functionNode;
         } catch (final Exception e) {
             handleParseException(e);
             return null;
@@ -444,21 +450,15 @@
      *
      * @return New block.
      */
-    private Block newBlock() {
-        return lc.push(new Block(token, Token.descPosition(token)));
+    private ParserContextBlockNode newBlock() {
+        return lc.push(new ParserContextBlockNode(token));
     }
 
-    /**
-     * Set up a new function block.
-     *
-     * @param ident Name of function.
-     * @return New block.
-     */
-    private FunctionNode newFunctionNode(final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine) {
+    private ParserContextFunctionNode createParserContextFunctionNode(final IdentNode ident, final long functionToken, final FunctionNode.Kind kind, final int functionLine, final List<IdentNode> parameters) {
         // Build function name.
         final StringBuilder sb = new StringBuilder();
 
-        final FunctionNode parentFunction = lc.getCurrentFunction();
+        final ParserContextFunctionNode parentFunction = lc.getCurrentFunction();
         if (parentFunction != null && !parentFunction.isProgram()) {
             sb.append(parentFunction.getName()).append('$');
         }
@@ -477,25 +477,33 @@
             flags |= FunctionNode.IS_PROGRAM;
         }
 
+        final ParserContextFunctionNode functionNode = new ParserContextFunctionNode(functionToken, ident, name, namespace, functionLine, kind, parameters);
+        functionNode.setFlag(flags);
+        return functionNode;
+    }
+
+    private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body){
+        final CompilationState state = errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED;
         // Start new block.
         final FunctionNode functionNode =
             new FunctionNode(
                 source,
                 functionLine,
-                token,
-                Token.descPosition(token),
+                body.getToken(),
+                Token.descPosition(body.getToken()),
                 startToken,
+                function.getLastToken(),
                 namespace,
                 ident,
-                name,
+                function.getName(),
                 parameters,
                 kind,
-                flags);
-
-        lc.push(functionNode);
-        // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
-        // FunctionNode.
-        newBlock();
+                function.getFlags(),
+                body,
+                state,
+                function.getEndParserState());
+
+        printAST(functionNode);
 
         return functionNode;
     }
@@ -503,27 +511,17 @@
     /**
      * Restore the current block.
      */
-    private Block restoreBlock(final Block block) {
+    private ParserContextBlockNode restoreBlock(final ParserContextBlockNode block) {
         return lc.pop(block);
     }
 
-
-    private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
-        final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
-
-        return lc.pop(functionNode).
-            setBody(lc, newBody).
-            setLastToken(lc, lastToken).
-            setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
-    }
-
     /**
      * Get the statements in a block.
      * @return Block statements.
      */
     private Block getBlock(final boolean needsBraces) {
-        // Set up new block. Captures LBRACE.
-        Block newBlock = newBlock();
+        final long blockToken = token;
+        final ParserContextBlockNode newBlock = newBlock();
         try {
             // Block opening brace.
             if (needsBraces) {
@@ -533,21 +531,18 @@
             statementList();
 
         } finally {
-            newBlock = restoreBlock(newBlock);
+            restoreBlock(newBlock);
         }
 
-        final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
-
         // Block closing brace.
         if (needsBraces) {
             expect(RBRACE);
         }
 
-        newBlock.setFinish(possibleEnd);
-
-        return newBlock;
+        return new Block(blockToken, finish, newBlock.getFlags(), newBlock.getStatements());
     }
 
+
     /**
      * Get all the statements generated by a single statement.
      * @return Statements.
@@ -557,13 +552,13 @@
             return getBlock(true);
         }
         // Set up new block. Captures first token.
-        Block newBlock = newBlock();
+        final ParserContextBlockNode newBlock = newBlock();
         try {
             statement();
         } finally {
-            newBlock = restoreBlock(newBlock);
+            restoreBlock(newBlock);
         }
-        return newBlock;
+        return new Block(newBlock.getToken(), finish, newBlock.getFlags(), newBlock.getStatements());
     }
 
     /**
@@ -584,7 +579,7 @@
      */
     private void detectSpecialProperty(final IdentNode ident) {
         if (isArguments(ident)) {
-            lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_ARGUMENTS);
+            lc.getCurrentFunction().setFlag(FunctionNode.USES_ARGUMENTS);
         }
     }
 
@@ -698,18 +693,19 @@
         // Make a pseudo-token for the script holding its start and length.
         final long functionToken = Token.toDesc(FUNCTION, Token.descPosition(Token.withDelimiter(token)), source.getLength());
         final int  functionLine  = line;
-        // Set up the script to append elements.
-
-        FunctionNode script = newFunctionNode(
-            functionToken,
-            new IdentNode(functionToken, Token.descPosition(functionToken), scriptName),
-            new ArrayList<IdentNode>(),
-            FunctionNode.Kind.SCRIPT,
-            functionLine);
-
+
+        final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), scriptName);
+        final ParserContextFunctionNode script = createParserContextFunctionNode(
+                ident,
+                functionToken,
+                FunctionNode.Kind.SCRIPT,
+                functionLine,
+                Collections.<IdentNode>emptyList());
+        lc.push(script);
+        final ParserContextBlockNode body = newBlock();
         // If ES6 block scope is enabled add a per-script block for top-level LET and CONST declarations.
         final int startLine = start;
-        Block outer = useBlockScope() ? newBlock() : null;
+        final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
         functionDeclarations = new ArrayList<>();
 
         try {
@@ -717,20 +713,25 @@
             addFunctionDeclarations(script);
         } finally {
             if (outer != null) {
-                outer = restoreBlock(outer);
-                appendStatement(new BlockStatement(startLine, outer));
+                restoreBlock(outer);
+                appendStatement(new BlockStatement(
+                        startLine,
+                        new Block(
+                                functionToken,
+                                startLine, outer.getFlags(),
+                                outer.getStatements())));
             }
         }
         functionDeclarations = null;
+        restoreBlock(body);
+        body.setFlag(Block.NEEDS_SCOPE);
+        final Block programBody = new Block(functionToken, functionLine, body.getFlags(), body.getStatements());
+        lc.pop(script);
+        script.setLastToken(token);
 
         expect(EOF);
 
-        script.setFinish(source.getLength() - 1);
-
-        script = restoreFunctionNode(script, token); //commit code
-        script = script.setBody(lc, script.getBody().setNeedsScope(lc));
-
-        return script;
+        return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.SCRIPT, functionLine, programBody);
     }
 
     /**
@@ -789,7 +790,7 @@
                     // check for directive prologues
                     if (checkDirective) {
                         // skip any debug statement like line number to get actual first line
-                        final Node lastStatement = lc.getLastStatement();
+                        final Statement lastStatement = lc.getLastStatement();
 
                         // get directive prologue, if any
                         final String directive = getDirective(lastStatement);
@@ -809,8 +810,8 @@
                             // handle use strict directive
                             if ("use strict".equals(directive)) {
                                 isStrictMode = true;
-                                final FunctionNode function = lc.getCurrentFunction();
-                                lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_STRICT);
+                                final ParserContextFunctionNode function = lc.getCurrentFunction();
+                                function.setFlag(FunctionNode.IS_STRICT);
 
                                 // We don't need to check these, if lexical environment is already strict
                                 if (!oldStrictMode && directiveStmts != null) {
@@ -831,8 +832,8 @@
                             } else if (Context.DEBUG) {
                                 final int flag = FunctionNode.getDirectiveFlag(directive);
                                 if (flag != 0) {
-                                    final FunctionNode function = lc.getCurrentFunction();
-                                    lc.setFlag(function, flag);
+                                    final ParserContextFunctionNode function = lc.getCurrentFunction();
+                                    function.setFlag(flag);
                                 }
                             }
                         }
@@ -1114,11 +1115,7 @@
 
         // If is a statement then handle end of line.
         if (isStatement) {
-            final boolean semicolon = type == SEMICOLON;
             endOfLine();
-            if (semicolon) {
-                lc.getCurrentBlock().setFinish(finish);
-            }
         }
 
         return vars;
@@ -1166,11 +1163,6 @@
         }
 
         endOfLine();
-
-        if (expressionStatement != null) {
-            expressionStatement.setFinish(finish);
-            lc.getCurrentBlock().setFinish(finish);
-        }
     }
 
     /**
@@ -1216,13 +1208,23 @@
      * Parse a FOR statement.
      */
     private void forStatement() {
+        final long forToken = token;
+        final int forLine = line;
         // When ES6 for-let is enabled we create a container block to capture the LET.
         final int startLine = start;
-        Block outer = useBlockScope() ? newBlock() : null;
+        final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
+
 
         // Create FOR node, capturing FOR token.
-        ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR);
+        final ParserContextLoopNode forNode = new ParserContextLoopNode();
         lc.push(forNode);
+        Block body = null;
+        List<VarNode> vars = null;
+        Expression init = null;
+        JoinPredecessorExpression test = null;
+        JoinPredecessorExpression modify = null;
+
+        int flags = 0;
 
         try {
             // FOR tested in caller.
@@ -1231,13 +1233,12 @@
             // Nashorn extension: for each expression.
             // iterate property values rather than property names.
             if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) {
-                forNode = forNode.setIsForEach(lc);
+                flags |= ForNode.IS_FOR_EACH;
                 next();
             }
 
             expect(LPAREN);
 
-            List<VarNode> vars = null;
 
             switch (type) {
             case VAR:
@@ -1258,8 +1259,7 @@
                     break;
                 }
 
-                final Expression expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
-                forNode = forNode.setInit(lc, expression);
+                init = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
                 break;
             }
 
@@ -1268,26 +1268,27 @@
                 // for (init; test; modify)
 
                 // for each (init; test; modify) is invalid
-                if (forNode.isForEach()) {
+                if ((flags & ForNode.IS_FOR_EACH) != 0) {
                     throw error(AbstractParser.message("for.each.without.in"), token);
                 }
 
                 expect(SEMICOLON);
                 if (type != SEMICOLON) {
-                    forNode = forNode.setTest(lc, joinPredecessorExpression());
+                    test = joinPredecessorExpression();
                 }
                 expect(SEMICOLON);
                 if (type != RPAREN) {
-                    forNode = forNode.setModify(lc, joinPredecessorExpression());
+                    modify = joinPredecessorExpression();
                 }
                 break;
 
             case IN:
-                forNode = forNode.setIsForIn(lc).setTest(lc, new JoinPredecessorExpression());
+                flags |= ForNode.IS_FOR_IN;
+                test = new JoinPredecessorExpression();
                 if (vars != null) {
                     // for (var i in obj)
                     if (vars.size() == 1) {
-                        forNode = forNode.setInit(lc, new IdentNode(vars.get(0).getName()));
+                        init = new IdentNode(vars.get(0).getName());
                     } else {
                         // for (var i, j in obj) is invalid
                         throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken());
@@ -1295,7 +1296,6 @@
 
                 } else {
                     // for (expr in obj)
-                    final Node init = forNode.getInit();
                     assert init != null : "for..in init expression can not be null here";
 
                     // check if initial expression is a valid L-value
@@ -1316,7 +1316,7 @@
                 next();
 
                 // Get the collection expression.
-                forNode = forNode.setModify(lc, joinPredecessorExpression());
+                modify = joinPredecessorExpression();
                 break;
 
             default:
@@ -1327,38 +1327,28 @@
             expect(RPAREN);
 
             // Set the for body.
-            final Block body = getStatement();
-            forNode = forNode.setBody(lc, body);
-            forNode.setFinish(body.getFinish());
-
-            appendStatement(forNode);
+            body = getStatement();
         } finally {
             lc.pop(forNode);
+            if (vars != null) {
+                for (final VarNode var : vars) {
+                    appendStatement(var);
+                }
+            }
+            if (body != null) {
+                appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
+            }
             if (outer != null) {
-                outer.setFinish(forNode.getFinish());
-                outer = restoreBlock(outer);
-                appendStatement(new BlockStatement(startLine, outer));
+                restoreBlock(outer);
+                appendStatement(new BlockStatement(startLine, new Block(
+                        outer.getToken(),
+                        body.getFinish(),
+                        outer.getStatements())));
             }
         }
     }
 
     /**
-     * ... IterationStatement :
-     *           ...
-     *           Expression[NoIn]?; Expression? ; Expression?
-     *           var VariableDeclarationList[NoIn]; Expression? ; Expression?
-     *           LeftHandSideExpression in Expression
-     *           var VariableDeclaration[NoIn] in Expression
-     *
-     * See 12.6
-     *
-     * Parse the control section of a FOR statement.  Also used for
-     * comprehensions.
-     * @param forNode Owning FOR.
-     */
-
-
-    /**
      * ...IterationStatement :
      *           ...
      *           while ( Expression ) Statement
@@ -1371,25 +1361,26 @@
     private void whileStatement() {
         // Capture WHILE token.
         final long whileToken = token;
+        final int whileLine = line;
         // WHILE tested in caller.
         next();
 
-        // Construct WHILE node.
-        WhileNode whileNode = new WhileNode(line, whileToken, Token.descPosition(whileToken), false);
+        final ParserContextLoopNode whileNode = new ParserContextLoopNode();
         lc.push(whileNode);
 
+        JoinPredecessorExpression test = null;
+        Block body = null;
+
         try {
             expect(LPAREN);
-            final int whileLine = line;
-            final JoinPredecessorExpression test = joinPredecessorExpression();
+            test = joinPredecessorExpression();
             expect(RPAREN);
-            final Block body = getStatement();
-            appendStatement(whileNode =
-                new WhileNode(whileLine, whileToken, finish, false).
-                    setTest(lc, test).
-                    setBody(lc, body));
+            body = getStatement();
         } finally {
             lc.pop(whileNode);
+            if (body != null){
+              appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body));
+            }
         }
     }
 
@@ -1406,34 +1397,32 @@
     private void doStatement() {
         // Capture DO token.
         final long doToken = token;
+        int doLine = 0;
         // DO tested in the caller.
         next();
 
-        WhileNode doWhileNode = new WhileNode(-1, doToken, Token.descPosition(doToken), true);
+        final ParserContextLoopNode doWhileNode = new ParserContextLoopNode();
         lc.push(doWhileNode);
 
+        Block body = null;
+        JoinPredecessorExpression test = null;
+
         try {
            // Get DO body.
-            final Block body = getStatement();
+            body = getStatement();
 
             expect(WHILE);
             expect(LPAREN);
-            final int doLine = line;
-            final JoinPredecessorExpression test = joinPredecessorExpression();
+            doLine = line;
+            test = joinPredecessorExpression();
             expect(RPAREN);
 
             if (type == SEMICOLON) {
                 endOfLine();
             }
-            doWhileNode.setFinish(finish);
-
-            //line number is last
-            appendStatement(doWhileNode =
-                new WhileNode(doLine, doToken, finish, true).
-                    setBody(lc, body).
-                    setTest(lc, test));
         } finally {
             lc.pop(doWhileNode);
+            appendStatement(new WhileNode(doLine, doToken, finish, true, test, body));
         }
     }
 
@@ -1452,7 +1441,7 @@
         // CONTINUE tested in caller.
         nextOrEOL();
 
-        LabelNode labelNode = null;
+        ParserContextLabelNode labelNode = null;
 
         // SEMICOLON or label.
         switch (type) {
@@ -1474,7 +1463,7 @@
         }
 
         final String labelName = labelNode == null ? null : labelNode.getLabelName();
-        final LoopNode targetNode = lc.getContinueTo(labelName);
+        final ParserContextLoopNode targetNode = lc.getContinueTo(labelName);
 
         if (targetNode == null) {
             throw error(AbstractParser.message("illegal.continue.stmt"), continueToken);
@@ -1500,7 +1489,7 @@
         // BREAK tested in caller.
         nextOrEOL();
 
-        LabelNode labelNode = null;
+        ParserContextLabelNode labelNode = null;
 
         // SEMICOLON or label.
         switch (type) {
@@ -1524,7 +1513,7 @@
         //either an explicit label - then get its node or just a "break" - get first breakable
         //targetNode is what we are breaking out from.
         final String labelName = labelNode == null ? null : labelNode.getLabelName();
-        final BreakableNode targetNode = lc.getBreakable(labelName);
+        final ParserContextBreakableNode targetNode = lc.getBreakable(labelName);
         if (targetNode == null) {
             throw error(AbstractParser.message("illegal.break.stmt"), breakToken);
         }
@@ -1632,20 +1621,17 @@
             throw error(AbstractParser.message("strict.no.with"), withToken);
         }
 
-        // Get WITH expression.
-        WithNode withNode = new WithNode(withLine, withToken, finish);
-
+        Expression expression = null;
+        Block body = null;
         try {
-            lc.push(withNode);
             expect(LPAREN);
-            withNode = withNode.setExpression(lc, expression());
+            expression = expression();
             expect(RPAREN);
-            withNode = withNode.setBody(lc, getStatement());
+            body = getStatement();
         } finally {
-            lc.pop(withNode);
+            appendStatement(new WithNode(withLine, withToken, finish, expression, body));
         }
 
-        appendStatement(withNode);
     }
 
     /**
@@ -1677,19 +1663,22 @@
         next();
 
         // Create and add switch statement.
-        SwitchNode switchNode = new SwitchNode(switchLine, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
+        final ParserContextSwitchNode switchNode= new ParserContextSwitchNode();
         lc.push(switchNode);
 
+        CaseNode defaultCase = null;
+        // Prepare to accumulate cases.
+        final List<CaseNode> cases = new ArrayList<>();
+
+        Expression expression = null;
+
         try {
             expect(LPAREN);
-            switchNode = switchNode.setExpression(lc, expression());
+            expression = expression();
             expect(RPAREN);
 
             expect(LBRACE);
 
-            // Prepare to accumulate cases.
-            final List<CaseNode> cases = new ArrayList<>();
-            CaseNode defaultCase = null;
 
             while (type != RBRACE) {
                 // Prepare for next case.
@@ -1720,7 +1709,6 @@
                 // Get CASE body.
                 final Block statements = getBlock(false);
                 final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements);
-                statements.setFinish(finish);
 
                 if (caseExpression == null) {
                     defaultCase = caseNode;
@@ -1729,13 +1717,10 @@
                 cases.add(caseNode);
             }
 
-            switchNode = switchNode.setCases(lc, cases, defaultCase);
             next();
-            switchNode.setFinish(finish);
-
-            appendStatement(switchNode);
         } finally {
             lc.pop(switchNode);
+            appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase));
         }
     }
 
@@ -1759,15 +1744,17 @@
             throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
         }
 
-        LabelNode labelNode = new LabelNode(line, labelToken, finish, ident.getName(), null);
+        final ParserContextLabelNode labelNode = new ParserContextLabelNode(ident.getName());
+        Block body = null;
         try {
             lc.push(labelNode);
-            labelNode = labelNode.setBody(lc, getStatement());
-            labelNode.setFinish(finish);
-            appendStatement(labelNode);
+            body = getStatement();
         } finally {
-            assert lc.peek() instanceof LabelNode;
+            assert lc.peek() instanceof ParserContextLabelNode;
             lc.pop(labelNode);
+            if (ident != null){
+              appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body));
+            }
         }
     }
 
@@ -1835,8 +1822,7 @@
 
         // Container block needed to act as target for labeled break statements
         final int startLine = line;
-        Block outer = newBlock();
-
+        final ParserContextBlockNode outer = newBlock();
         // Create try.
 
         try {
@@ -1867,15 +1853,15 @@
 
                 expect(RPAREN);
 
-                Block catchBlock = newBlock();
+                final ParserContextBlockNode catchBlock = newBlock();
                 try {
                     // Get CATCH body.
                     final Block catchBody = getBlock(true);
                     final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false);
                     appendStatement(catchNode);
                 } finally {
-                    catchBlock = restoreBlock(catchBlock);
-                    catchBlocks.add(catchBlock);
+                    restoreBlock(catchBlock);
+                    catchBlocks.add(new Block(catchBlock.getToken(), finish, catchBlock.getFlags(), catchBlock.getStatements()));
                 }
 
                 // If unconditional catch then should to be the end.
@@ -1897,19 +1883,15 @@
                 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
             }
 
-            final TryNode tryNode = new TryNode(tryLine, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
+            final TryNode tryNode = new TryNode(tryLine, tryToken, finish, tryBody, catchBlocks, finallyStatements);
             // Add try.
             assert lc.peek() == outer;
             appendStatement(tryNode);
-
-            tryNode.setFinish(finish);
-            outer.setFinish(finish);
-
         } finally {
-            outer = restoreBlock(outer);
+            restoreBlock(outer);
         }
 
-        appendStatement(new BlockStatement(startLine, outer));
+        appendStatement(new BlockStatement(startLine, new Block(tryToken, finish, outer.getFlags(), outer.getStatements())));
     }
 
     /**
@@ -1927,7 +1909,7 @@
         // DEBUGGER tested in caller.
         next();
         endOfLine();
-        appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Expression>())));
+        appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, Collections.<Expression>emptyList())));
     }
 
     /**
@@ -1954,7 +1936,7 @@
         case THIS:
             final String name = type.getName();
             next();
-            lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_THIS);
+            lc.getCurrentFunction().setFlag(FunctionNode.USES_THIS);
             return new IdentNode(primaryToken, finish, name);
         case IDENT:
             final IdentNode ident = getIdent();
@@ -2314,9 +2296,24 @@
         final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName));
         expect(LPAREN);
         expect(RPAREN);
-        final FunctionNode functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER, functionLine);
-
-        return new PropertyFunction(getIdent, functionNode);
+
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList());
+        lc.push(functionNode);
+
+        final Block functionBody = functionBody(functionNode);
+
+        lc.pop(functionNode);
+
+        final FunctionNode  function = createFunctionNode(
+                functionNode,
+                getSetToken,
+                getNameNode,
+                Collections.<IdentNode>emptyList(),
+                FunctionNode.Kind.GETTER,
+                functionLine,
+                functionBody);
+
+        return new PropertyFunction(getIdent, function);
     }
 
     private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) {
@@ -2338,9 +2335,25 @@
         if (argIdent != null) {
             parameters.add(argIdent);
         }
-        final FunctionNode functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER, functionLine);
-
-        return new PropertyFunction(setIdent, functionNode);
+
+
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters);
+        lc.push(functionNode);
+
+        final Block functionBody = functionBody(functionNode);
+
+        lc.pop(functionNode);
+
+        final FunctionNode  function = createFunctionNode(
+                functionNode,
+                getSetToken,
+                setNameNode,
+                parameters,
+                FunctionNode.Kind.SETTER,
+                functionLine,
+                functionBody);
+
+        return new PropertyFunction(setIdent, function);
     }
 
     private static class PropertyFunction {
@@ -2655,11 +2668,18 @@
         final List<IdentNode> parameters = formalParameterList();
         expect(RPAREN);
 
-        FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine);
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.NORMAL, functionLine, parameters);
+        lc.push(functionNode);
+        Block functionBody = null;
+        try{
+            functionBody = functionBody(functionNode);
+        } finally {
+            lc.pop(functionNode);
+        }
 
         if (isStatement) {
             if (topLevel || useBlockScope()) {
-                functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
+                functionNode.setFlag(FunctionNode.IS_DECLARED);
             } else if (isStrictMode) {
                 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
             } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) {
@@ -2668,12 +2688,12 @@
                 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken);
             }
             if (isArguments(name)) {
-                lc.setFlag(lc.getCurrentFunction(), FunctionNode.DEFINES_ARGUMENTS);
+               lc.getCurrentFunction().setFlag(FunctionNode.DEFINES_ARGUMENTS);
             }
         }
 
         if (isAnonymous) {
-            functionNode = functionNode.setFlag(lc, FunctionNode.IS_ANONYMOUS);
+            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
         }
 
         final int arity = parameters.size();
@@ -2687,7 +2707,7 @@
                 String parameterName = parameter.getName();
 
                 if (isArguments(parameterName)) {
-                    functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
+                    functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS);
                 }
 
                 if (parametersSet.contains(parameterName)) {
@@ -2705,17 +2725,26 @@
             }
         } else if (arity == 1) {
             if (isArguments(parameters.get(0))) {
-                functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
+                functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS);
             }
         }
 
+        final FunctionNode function = createFunctionNode(
+                functionNode,
+                functionToken,
+                name,
+                parameters,
+                FunctionNode.Kind.NORMAL,
+                functionLine,
+                functionBody);
+
         if (isStatement) {
             int varFlags = VarNode.IS_STATEMENT;
             if (!topLevel && useBlockScope()) {
                 // mark ES6 block functions as lexically scoped
                 varFlags |= VarNode.IS_LET;
             }
-            final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags);
+            final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags);
             if (topLevel) {
                 functionDeclarations.add(varNode);
             } else if (useBlockScope()) {
@@ -2725,7 +2754,7 @@
             }
         }
 
-        return functionNode;
+        return function;
     }
 
     private String getDefaultValidFunctionName(final int functionLine) {
@@ -2832,15 +2861,19 @@
      * Parse function body.
      * @return function node (body.)
      */
-    private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine) {
-        FunctionNode functionNode = null;
+    private Block functionBody(final ParserContextFunctionNode functionNode) {
         long lastToken = 0L;
+        ParserContextBlockNode body = null;
+        final long bodyToken = token;
+        Block functionBody;
+        int bodyFinish = 0;
+
 
         final boolean parseBody;
         Object endParserState = null;
         try {
             // Create a new function block.
-            functionNode = newFunctionNode(firstToken, ident, parameters, kind, functionLine);
+            body = newBlock();
             assert functionNode != null;
             final int functionId = functionNode.getId();
             parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
@@ -2856,6 +2889,7 @@
                 // just expression as function body
                 final Expression expr = assignmentExpression(true);
                 lastToken = previousToken;
+                functionNode.setLastToken(previousToken);
                 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
                 // EOL uses length field to store the line number
                 final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken));
@@ -2868,7 +2902,6 @@
                     final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
                     appendStatement(returnNode);
                 }
-                functionNode.setFinish(lastFinish);
             } else {
                 expectDontAdvance(LBRACE);
                 if (parseBody || !skipFunctionBody(functionNode)) {
@@ -2902,25 +2935,25 @@
                         // we'll rather just restart parsing from this well-known, friendly token instead.
                     }
                 }
+                bodyFinish = finish;
+                functionNode.setLastToken(token);
                 expect(RBRACE);
-                functionNode.setFinish(finish);
             }
         } finally {
-            functionNode = restoreFunctionNode(functionNode, lastToken);
+            restoreBlock(body);
         }
 
         // NOTE: we can only do alterations to the function node after restoreFunctionNode.
 
         if (parseBody) {
-            functionNode = functionNode.setEndParserState(lc, endParserState);
-        } else if (functionNode.getBody().getStatementCount() > 0){
+            functionNode.setEndParserState(endParserState);
+        } else if (!body.getStatements().isEmpty()){
             // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see
             // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to
             // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as
             // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away
             // nested bodies early if we were supposed to skip 'em.
-            functionNode = functionNode.setBody(null, functionNode.getBody().setStatements(null,
-                    Collections.<Statement>emptyList()));
+            body.setStatements(Collections.<Statement>emptyList());
         }
 
         if (reparsedFunction != null) {
@@ -2932,20 +2965,20 @@
             if (data != null) {
                 // Data can be null if when we originally parsed the file, we removed the function declaration
                 // as it was dead code.
-                functionNode = functionNode.setFlags(lc, data.getFunctionFlags());
+                functionNode.setFlag(data.getFunctionFlags());
                 // This compensates for missing markEval() in case the function contains an inner function
                 // that contains eval(), that now we didn't discover since we skipped the inner function.
                 if (functionNode.hasNestedEval()) {
                     assert functionNode.hasScopeBlock();
-                    functionNode = functionNode.setBody(lc, functionNode.getBody().setNeedsScope(null));
+                    body.setFlag(Block.NEEDS_SCOPE);
                 }
             }
         }
-        printAST(functionNode);
-        return functionNode;
+        functionBody = new Block(bodyToken, bodyFinish, body.getFlags(), body.getStatements());
+        return functionBody;
     }
 
-    private boolean skipFunctionBody(final FunctionNode functionNode) {
+    private boolean skipFunctionBody(final ParserContextFunctionNode functionNode) {
         if (reparsedFunction == null) {
             // Not reparsing, so don't skip any function body.
             return false;
@@ -3008,13 +3041,13 @@
         }
     }
 
-    private void addFunctionDeclarations(final FunctionNode functionNode) {
+    private void addFunctionDeclarations(final ParserContextFunctionNode functionNode) {
         VarNode lastDecl = null;
         for (int i = functionDeclarations.size() - 1; i >= 0; 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);
+                functionNode.setFlag(FunctionNode.HAS_FUNCTION_DECLARATIONS);
             }
             prependStatement(decl);
         }
@@ -3359,29 +3392,31 @@
         return "'JavaScript Parsing'";
     }
 
-    private static void markEval(final LexicalContext lc) {
-        final Iterator<FunctionNode> iter = lc.getFunctions();
+    private static void markEval(final ParserContext lc) {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
         boolean flaggedCurrentFn = false;
         while (iter.hasNext()) {
-            final FunctionNode fn = iter.next();
+            final ParserContextFunctionNode fn = iter.next();
             if (!flaggedCurrentFn) {
-                lc.setFlag(fn, FunctionNode.HAS_EVAL);
+                fn.setFlag(FunctionNode.HAS_EVAL);
                 flaggedCurrentFn = true;
             } else {
-                lc.setFlag(fn, FunctionNode.HAS_NESTED_EVAL);
+                fn.setFlag(FunctionNode.HAS_NESTED_EVAL);
             }
+            final ParserContextBlockNode body = lc.getFunctionBody(fn);
             // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip
             // parsing a nested function. functionBody() contains code to compensate for the lack of invoking
             // this method when the parser skips a nested function.
-            lc.setBlockNeedsScope(lc.getFunctionBody(fn));
+            body.setFlag(Block.NEEDS_SCOPE);
+            fn.setFlag(FunctionNode.HAS_SCOPE_BLOCK);
         }
     }
 
     private void prependStatement(final Statement statement) {
-        lc.prependStatement(statement);
+        lc.prependStatementToCurrentNode(statement);
     }
 
     private void appendStatement(final Statement statement) {
-        lc.appendStatement(statement);
+        lc.appendStatementToCurrentNode(statement);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java	Tue Oct 14 15:28:24 2014 +0200
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2014, 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.parser;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import jdk.nashorn.internal.ir.Statement;
+
+/**
+ * A class that tracks the current lexical context of node visitation as a stack of {@code ParserContextNode} nodes. Has special
+ * methods to retrieve useful subsets of the context.
+ *
+ * This is implemented with a primitive array and a stack pointer, because it really makes a difference
+ * performance wise. None of the collection classes were optimal
+ */
+
+class ParserContext {
+
+    private ParserContextNode[] stack;
+    private int sp;
+
+    private static final int INITIAL_DEPTH = 16;
+
+    /**
+     * Constructs a ParserContext,
+     * initializes the stack
+     */
+    public ParserContext(){
+        this.sp    = 0;
+        this.stack = new ParserContextNode[INITIAL_DEPTH];
+    }
+
+    /**
+     * Pushes a new block on top of the context, making it the innermost open block.
+     * @param node the new node
+     * @return The node that was pushed
+     */
+    public <T extends ParserContextNode> T push(final T node) {
+        assert !contains(node);
+        if (sp == stack.length) {
+            final ParserContextNode[] newStack = new ParserContextNode[sp * 2];
+            System.arraycopy(stack, 0, newStack, 0, sp);
+            stack = newStack;
+        }
+        stack[sp] = node;
+        sp++;
+
+        return node;
+    }
+
+    /**
+     * The topmost node on the stack
+     * @return The topmost node on the stack
+     */
+    public ParserContextNode peek() {
+        return stack[sp - 1];
+    }
+
+    /**
+     * Removes and returns the topmost Node from the stack.
+     * @param node The node expected to be popped, used for sanity check
+     * @return The removed node
+     */
+    public <T extends ParserContextNode> T pop(final T node) {
+        --sp;
+        @SuppressWarnings("unchecked")
+        final T popped = (T)stack[sp];
+        stack[sp] = null;
+        assert node == popped;
+
+        return popped;
+    }
+
+    /**
+     * Tests if a node is on the stack.
+     * @param node  The node to test
+     * @return true if stack contains node, false otherwise
+     */
+    public boolean contains(final ParserContextNode node) {
+        for (int i = 0; i < sp; i++) {
+            if (stack[i] == node) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the topmost {@link ParserContextBreakableNode} on the stack, null if none on stack
+     * @return Returns the topmost {@link ParserContextBreakableNode} on the stack, null if none on stack
+     */
+    private ParserContextBreakableNode getBreakable() {
+        for (final NodeIterator<ParserContextBreakableNode> iter = new NodeIterator<>(ParserContextBreakableNode.class, getCurrentFunction()); iter.hasNext(); ) {
+            final ParserContextBreakableNode next = iter.next();
+            if (next.isBreakableWithoutLabel()) {
+                return next;
+            }
+        }
+        return null;
+    }
+
+
+
+    /**
+     * Find the breakable node corresponding to this label.
+     * @param labelName name of the label to search for. If null, the closest breakable node will be returned
+     * unconditionally, e.g. a while loop with no label
+     * @return closest breakable node
+     */
+    public ParserContextBreakableNode getBreakable(final String labelName) {
+        if (labelName != null) {
+            final ParserContextLabelNode foundLabel = findLabel(labelName);
+            if (foundLabel != null) {
+                // iterate to the nearest breakable to the foundLabel
+                ParserContextBreakableNode breakable = null;
+                for (final NodeIterator<ParserContextBreakableNode> iter = new NodeIterator<>(ParserContextBreakableNode.class, foundLabel); iter.hasNext(); ) {
+                    breakable = iter.next();
+                }
+                return breakable;
+            }
+            return null;
+        } else {
+            return getBreakable();
+        }
+    }
+
+    /**
+     * Returns the loop node of the current loop, or null if not inside a loop
+     * @return loop noder
+     */
+    public ParserContextLoopNode getCurrentLoop() {
+        final Iterator<ParserContextLoopNode> iter = new NodeIterator<>(ParserContextLoopNode.class, getCurrentFunction());
+        return iter.hasNext() ? iter.next() : null;
+    }
+
+    private ParserContextLoopNode getContinueTo() {
+        return getCurrentLoop();
+    }
+
+    /**
+     * Find the continue target node corresponding to this label.
+     * @param labelName label name to search for. If null the closest loop node will be returned unconditionally, e.g. a
+     * while loop with no label
+     * @return closest continue target node
+     */
+    public ParserContextLoopNode getContinueTo(final String labelName) {
+        if (labelName != null) {
+            final ParserContextLabelNode foundLabel = findLabel(labelName);
+            if (foundLabel != null) {
+                // iterate to the nearest loop to the foundLabel
+                ParserContextLoopNode loop = null;
+                for (final NodeIterator<ParserContextLoopNode> iter = new NodeIterator<>(ParserContextLoopNode.class, foundLabel); iter.hasNext(); ) {
+                    loop = iter.next();
+                }
+                return loop;
+            }
+            return null;
+        }
+        return getContinueTo();
+    }
+
+    /**
+     * Get the function body of a function node on the stack.
+     * This will trigger an assertion if node isn't present
+     * @param functionNode function node
+     * @return body of function node
+     */
+    public ParserContextBlockNode getFunctionBody(final ParserContextFunctionNode functionNode) {
+        for (int i = sp - 1; i >= 0 ; i--) {
+            if (stack[i] == functionNode) {
+                return (ParserContextBlockNode)stack[i + 1];
+            }
+        }
+        throw new AssertionError(functionNode.getName() + " not on context stack");
+    }
+
+    /**
+     * Check the stack for a given label node by name
+     * @param name name of the label
+     * @return LabelNode if found, null otherwise
+     */
+    public ParserContextLabelNode findLabel(final String name) {
+        for (final Iterator<ParserContextLabelNode> iter = new NodeIterator<>(ParserContextLabelNode.class, getCurrentFunction()); iter.hasNext(); ) {
+            final ParserContextLabelNode next = iter.next();
+            if (next.getLabelName().equals(name)) {
+                return next;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Prepends a statement to the current node.
+     * @param statement The statement to prepend
+     */
+    public void prependStatementToCurrentNode(final Statement statement) {
+        assert statement != null;
+        stack[sp - 1].prependStatement(statement);
+    }
+
+    /**
+     * Appends a statement to the current Node.
+     * @param statement The statement to append
+     */
+    public void appendStatementToCurrentNode(final Statement statement) {
+        assert statement != null;
+        stack[sp - 1].appendStatement(statement);
+    }
+
+    /**
+     * Returns the innermost function in the context.
+     * @return the innermost function in the context.
+     */
+    public ParserContextFunctionNode getCurrentFunction() {
+        for (int i = sp - 1; i >= 0; i--) {
+            if (stack[i] instanceof ParserContextFunctionNode) {
+                return (ParserContextFunctionNode) stack[i];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns an iterator over all blocks in the context, with the top block (innermost lexical context) first.
+     * @return an iterator over all blocks in the context.
+     */
+    public Iterator<ParserContextBlockNode> getBlocks() {
+        return new NodeIterator<>(ParserContextBlockNode.class);
+    }
+
+    /**
+     * Returns the innermost block in the context.
+     * @return the innermost block in the context.
+     */
+    public ParserContextBlockNode getCurrentBlock() {
+        return getBlocks().next();
+    }
+
+    /**
+     * The last statement added to the context
+     * @return The last statement added to the context
+     */
+    public Statement getLastStatement() {
+        if (sp == 0) {
+            return null;
+        }
+        final ParserContextNode top = stack[sp - 1];
+        final int s = top.getStatements().size();
+        return s == 0 ? null : top.getStatements().get(s - 1);
+    }
+
+    /**
+     * Returns an iterator over all functions in the context, with the top (innermost open) function first.
+     * @return an iterator over all functions in the context.
+     */
+    public Iterator<ParserContextFunctionNode> getFunctions() {
+        return new NodeIterator<>(ParserContextFunctionNode.class);
+    }
+
+    private class NodeIterator <T extends ParserContextNode> implements Iterator<T> {
+        private int index;
+        private T next;
+        private final Class<T> clazz;
+        private ParserContextNode until;
+
+        NodeIterator(final Class<T> clazz) {
+            this(clazz, null);
+        }
+
+        NodeIterator(final Class<T> clazz, final ParserContextNode until) {
+            this.index = sp - 1;
+            this.clazz = clazz;
+            this.until = until;
+            this.next  = findNext();
+        }
+
+        @Override
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        @Override
+        public T next() {
+            if (next == null) {
+                throw new NoSuchElementException();
+            }
+            final T lnext = next;
+            next = findNext();
+            return lnext;
+        }
+
+        @SuppressWarnings("unchecked")
+        private T findNext() {
+            for (int i = index; i >= 0; i--) {
+                final Object node = stack[i];
+                if (node == until) {
+                    return null;
+                }
+                if (clazz.isAssignableFrom(node.getClass())) {
+                    index = i - 1;
+                    return (T)node;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBaseNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014, 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.parser;
+
+import java.util.ArrayList;
+import java.util.List;
+import jdk.nashorn.internal.ir.Statement;
+
+/**
+ * Base class for parser context nodes
+ */
+abstract class ParserContextBaseNode implements ParserContextNode {
+    /**
+     * Flags for this node
+     */
+    protected int flags;
+
+    private List<Statement> statements;
+
+    /**
+     * Constructor
+     */
+    public ParserContextBaseNode() {
+        this.statements = new ArrayList<>();
+    }
+
+    /**
+     * @return The flags for this node
+     */
+    @Override
+    public int getFlags() {
+        return flags;
+    }
+
+    /**
+     * Returns a single flag
+     * @param flag
+     * @return A single flag
+     */
+    protected int getFlag(final int flag) {
+        return (flags & flag);
+    }
+
+    /**
+     * @param flag
+     * @return the new flags
+     */
+    @Override
+    public int setFlag(final int flag) {
+        flags |= flag;
+        return flags;
+    }
+
+    /**
+     * @return The list of statements that belongs to this node
+     */
+    @Override
+    public List<Statement> getStatements() {
+        return statements;
+    }
+
+    /**
+     * @param statements
+     */
+    @Override
+    public void setStatements(final List<Statement> statements) {
+        this.statements = statements;
+    }
+
+    /**
+     * Adds a Statement at the end of the Statementlist
+     * @param statement The statement to add
+     */
+    @Override
+    public void appendStatement(final Statement statement) {
+        this.statements.add(statement);
+    }
+
+    /**
+     * Adds a statement at the begining of the statementlist
+     * @param statement The statement to add
+     */
+    @Override
+    public void prependStatement(final Statement statement) {
+        this.statements.add(0, statement);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBlockNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014, 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.parser;
+
+/**
+ * A ParserContextNode that represents a block that is currently being parsed
+ */
+class ParserContextBlockNode extends ParserContextBaseNode implements ParserContextBreakableNode {
+
+    private final long token;
+
+    /**
+     * Constructs a ParserContextBlockNode
+     *
+     * @param token The first token of the block
+     */
+    public ParserContextBlockNode(final long token) {
+        this.token = token;
+    }
+
+    @Override
+    public boolean isBreakableWithoutLabel() {
+        return false;
+    }
+
+    /**
+     * Get token
+     * @return The first token of the block
+     */
+    public long getToken() {
+        return token;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBreakableNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, 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.parser;
+
+import jdk.nashorn.internal.ir.BreakNode;
+
+/**
+ * An interface that is implemented by ParserContextNodes that can
+ * contain a {@link BreakNode}
+ */
+interface ParserContextBreakableNode extends ParserContextNode {
+
+    /**
+     * Returns true if not i breakable without label, false otherwise
+     * @return Returns true if not i breakable without label, false otherwise
+     */
+    boolean isBreakableWithoutLabel();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2014, 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.parser;
+
+import java.util.List;
+import jdk.nashorn.internal.codegen.Namespace;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.IdentNode;
+
+/**
+ * ParserContextNode that represents a function that is currently being parsed
+ */
+class ParserContextFunctionNode extends ParserContextBaseNode {
+
+    /** Function name */
+    private final String name;
+
+    /** Function identifier node */
+    private final IdentNode ident;
+
+    /** Name space for function */
+    private final Namespace namespace;
+
+    /** Line number for function declaration */
+    private final int line;
+
+    /** Function node kind, see {@link FunctionNode#Kind} */
+    private final FunctionNode.Kind kind;
+
+    /** List of parameter identifiers for function */
+    private final List<IdentNode> parameters;
+
+    /** Token for function start */
+    private final long token;
+
+    /** Last function token */
+    private long lastToken;
+
+    /** Opaque node for parser end state, see {@link Parser} */
+    private Object endParserState;
+
+    /**
+     * @param token The token for the function
+     * @param ident External function name
+     * @param name  Internal name of the function
+     * @param namespace Function's namespace
+     * @param line  The source line of the function
+     * @param kind  Function kind
+     * @param parameters The parameters of the function
+     */
+    public ParserContextFunctionNode(final long token, final IdentNode ident, final String name, final Namespace namespace, final int line, final FunctionNode.Kind kind, final List<IdentNode> parameters) {
+        this.ident      = ident;
+        this.namespace  = namespace;
+        this.line       = line;
+        this.kind       = kind;
+        this.name       = name;
+        this.parameters = parameters;
+        this.token      = token;
+    }
+
+    /**
+     * @return Internal name of the function
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return The external identifier for the function
+     */
+    public IdentNode getIdent() {
+        return ident;
+    }
+
+    /**
+     *
+     * @return true if function is the program function
+     */
+    public boolean isProgram() {
+        return getFlag(FunctionNode.IS_PROGRAM) != 0;
+    }
+
+    /**
+     * @return if function in strict mode
+     */
+    public boolean isStrict() {
+        return getFlag(FunctionNode.IS_STRICT) != 0;
+    }
+
+    /**
+     * @return true if the function has nested evals
+     */
+    public boolean hasNestedEval() {
+        return getFlag(FunctionNode.HAS_NESTED_EVAL) != 0;
+    }
+
+    /**
+     * Returns true if any of the blocks in this function create their own scope.
+     * @return true if any of the blocks in this function create their own scope.
+     */
+    public boolean hasScopeBlock() {
+        return getFlag(FunctionNode.HAS_SCOPE_BLOCK) != 0;
+    }
+
+    /**
+     * Create a unique name in the namespace of this FunctionNode
+     * @param base prefix for name
+     * @return base if no collision exists, otherwise a name prefix with base
+     */
+    public String uniqueName(final String base) {
+        return namespace.uniqueName(base);
+    }
+
+    /**
+     * @return line number of the function
+     */
+    public int getLineNumber() {
+        return line;
+    }
+
+    /**
+     * @return The kind if function
+     */
+    public FunctionNode.Kind getKind() {
+        return kind;
+    }
+
+    /**
+     * Get parameters
+     * @return The parameters of the function
+     */
+    public List<IdentNode> getParameters() {
+        return parameters;
+    }
+
+    /**
+     * Set last token
+     * @param token New last token
+     */
+    public void setLastToken(final long token) {
+        this.lastToken = token;
+
+    }
+
+    /**
+     * @return lastToken Function's last token
+     */
+    public long getLastToken() {
+        return lastToken;
+    }
+
+    /**
+     * Returns the ParserState of when the parsing of this function was ended
+     * @return endParserState The end parser state
+     */
+    public Object getEndParserState() {
+        return endParserState;
+    }
+
+    /**
+     * Sets the ParserState of when the parsing of this function was ended
+     * @param endParserState The end parser state
+     */
+    public void setEndParserState(final Object endParserState) {
+        this.endParserState = endParserState;
+    }
+
+    /**
+     * Returns the if of this function
+     * @return The function id
+     */
+    public int getId() {
+        return isProgram() ? -1 : Token.descPosition(token);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextLabelNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -0,0 +1,52 @@
+/**
+/*
+ * Copyright (c) 2014, 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.parser;
+
+/**
+ * ParserContextNode that represents a LabelNode
+ */
+class ParserContextLabelNode extends ParserContextBaseNode {
+
+    /** Name for label */
+    private final String name;
+
+    /**
+     * Constructor
+     *
+     * @param name The name of the label
+     */
+    public ParserContextLabelNode(final String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns the name of the label
+     * @return name of label
+     */
+    public String getLabelName() {
+        return name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextLoopNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, 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.parser;
+
+/**
+ * A ParserContextNode that represents a loop that is being parsed
+ */
+class ParserContextLoopNode extends ParserContextBaseNode implements ParserContextBreakableNode {
+
+    @Override
+    public boolean isBreakableWithoutLabel() {
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014, 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.parser;
+
+import java.util.List;
+import jdk.nashorn.internal.ir.Statement;
+
+/**
+ * Used for keeping state when needed in the parser.
+ */
+interface ParserContextNode {
+    /**
+     * @return The flags for this node
+     */
+    public int getFlags();
+
+    /**
+     * @param flag The flag to set
+     * @return All current flags after update
+     */
+    public int setFlag(final int flag);
+
+    /**
+     * @return The list of statements that belongs to this node
+     */
+    public List<Statement> getStatements();
+
+    /**
+     * @param statements The statement list
+     */
+    public void setStatements(final List<Statement> statements);
+
+    /**
+     * Adds a Statement at the end of the Statementlist
+     * @param statement The statement to add
+     */
+    public void appendStatement(final Statement statement);
+
+    /**
+     * Adds a statement at the begining of the statementlist
+     * @param statement The statement to add
+     */
+    public void prependStatement(final Statement statement);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextSwitchNode.java	Tue Oct 14 15:28:24 2014 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 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.parser;
+
+/**
+ * A ParserContextNode that represents a SwithcNode that is currently being parsed
+ */
+class ParserContextSwitchNode extends ParserContextBaseNode implements ParserContextBreakableNode {
+
+    @Override
+    public boolean isBreakableWithoutLabel() {
+        return true;
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Tue Oct 14 13:04:56 2014 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Tue Oct 14 15:28:24 2014 +0200
@@ -483,7 +483,7 @@
 
         final int cacheSize = env._class_cache_size;
         if (cacheSize > 0) {
-            classCache = new ClassCache(cacheSize);
+            classCache = new ClassCache(this, cacheSize);
         }
 
         if (env._persistent_cache) {
@@ -1261,17 +1261,23 @@
      * Cache for compiled script classes.
      */
     @SuppressWarnings("serial")
-    private static class ClassCache extends LinkedHashMap<Source, ClassReference> {
+    @Logger(name="classcache")
+    private static class ClassCache extends LinkedHashMap<Source, ClassReference> implements Loggable {
         private final int size;
         private final ReferenceQueue<Class<?>> queue;
+        private final DebugLogger log;
 
-        ClassCache(final int size) {
+        ClassCache(final Context context, final int size) {
             super(size, 0.75f, true);
             this.size = size;
             this.queue = new ReferenceQueue<>();
+            this.log   = initLogger(context);
         }
 
         void cache(final Source source, final Class<?> clazz) {
+            if (log.isEnabled()) {
+                log.info("Caching ", source, " in class cache");
+            }
             put(source, new ClassReference(clazz, queue, source));
         }
 
@@ -1283,9 +1289,28 @@
         @Override
         public ClassReference get(final Object key) {
             for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
-                remove(ref.source);
+                final Source source = ref.source;
+                if (log.isEnabled()) {
+                    log.info("Evicting ", source, " from class cache.");
+                }
+                remove(source);
             }
-            return super.get(key);
+
+            final ClassReference ref = super.get(key);
+            if (ref != null && log.isEnabled()) {
+                log.info("Retrieved class reference for ", ref.source, " from class cache");
+            }
+            return ref;
+        }
+
+        @Override
+        public DebugLogger initLogger(final Context context) {
+            return context.getLogger(getClass());
+        }
+
+        @Override
+        public DebugLogger getLogger() {
+            return log;
         }
 
     }