8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable

Sat, 23 Mar 2013 00:58:39 +0100

author
attila
date
Sat, 23 Mar 2013 00:58:39 +0100
changeset 144
4be452026847
parent 143
606a1946e3e2
child 145
ae4ef3102d9c

8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
Reviewed-by: jlaskey, lagergren

make/project.properties file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Attr.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/ClassEmitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CodeGenerator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CompilationPhase.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Compiler.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FinalizeTypes.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FoldConstants.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FunctionSignature.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Lower.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/MethodEmitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Splitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/WeighNodes.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/AccessNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Assignment.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/BaseNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/BinaryNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Block.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/BreakNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/CallNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/CaseNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/CatchNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/ContinueNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/DoWhileNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/EmptyNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/ExecuteNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/ForNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/FunctionNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/IdentNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/IfNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/IndexNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LabelNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LexicalContext.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LineNumberNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LiteralNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Location.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Node.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/ObjectNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/PropertyNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/ReferenceNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/ReturnNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/RuntimeNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/SplitNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/SwitchNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Symbol.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/TernaryNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/ThrowNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/TryNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/TypeOverride.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/UnaryNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/VarNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/WhileNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/WithNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/debug/JSONWriter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/debug/PrintVisitor.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/Parser.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/resources/Messages.properties file | annotate | diff | comparison | revisions
test/script/basic/JDK-8006755.js file | annotate | diff | comparison | revisions
test/script/basic/NASHORN-837.js file | annotate | diff | comparison | revisions
test/src/jdk/nashorn/internal/codegen/CompilerTest.java file | annotate | diff | comparison | revisions
     1.1 --- a/make/project.properties	Tue Mar 19 11:03:24 2013 -0300
     1.2 +++ b/make/project.properties	Sat Mar 23 00:58:39 2013 +0100
     1.3 @@ -210,7 +210,7 @@
     1.4  # add '-Dtest.js.outofprocess' to run each test in a new sub-process
     1.5  run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -esa -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
     1.6  #-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M  
     1.7 -run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs}
     1.8 +run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main}
     1.9  
    1.10  run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy
    1.11  
     2.1 --- a/src/jdk/nashorn/internal/codegen/Attr.java	Tue Mar 19 11:03:24 2013 -0300
     2.2 +++ b/src/jdk/nashorn/internal/codegen/Attr.java	Sat Mar 23 00:58:39 2013 +0100
     2.3 @@ -37,14 +37,16 @@
     2.4  import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
     2.5  import static jdk.nashorn.internal.ir.Symbol.IS_LET;
     2.6  import static jdk.nashorn.internal.ir.Symbol.IS_PARAM;
     2.7 +import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE;
     2.8  import static jdk.nashorn.internal.ir.Symbol.IS_THIS;
     2.9  import static jdk.nashorn.internal.ir.Symbol.IS_VAR;
    2.10 +import static jdk.nashorn.internal.ir.Symbol.KINDMASK;
    2.11  
    2.12  import java.util.ArrayList;
    2.13  import java.util.HashSet;
    2.14  import java.util.Iterator;
    2.15 -import java.util.LinkedList;
    2.16  import java.util.List;
    2.17 +import java.util.ListIterator;
    2.18  import java.util.Set;
    2.19  import jdk.nashorn.internal.codegen.types.Type;
    2.20  import jdk.nashorn.internal.ir.AccessNode;
    2.21 @@ -52,19 +54,19 @@
    2.22  import jdk.nashorn.internal.ir.Block;
    2.23  import jdk.nashorn.internal.ir.CallNode;
    2.24  import jdk.nashorn.internal.ir.CallNode.EvalArgs;
    2.25 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    2.26  import jdk.nashorn.internal.ir.CaseNode;
    2.27  import jdk.nashorn.internal.ir.CatchNode;
    2.28  import jdk.nashorn.internal.ir.ForNode;
    2.29  import jdk.nashorn.internal.ir.FunctionNode;
    2.30 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    2.31  import jdk.nashorn.internal.ir.IdentNode;
    2.32  import jdk.nashorn.internal.ir.IndexNode;
    2.33 +import jdk.nashorn.internal.ir.LexicalContext;
    2.34  import jdk.nashorn.internal.ir.LiteralNode;
    2.35  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
    2.36  import jdk.nashorn.internal.ir.Node;
    2.37  import jdk.nashorn.internal.ir.ObjectNode;
    2.38  import jdk.nashorn.internal.ir.PropertyNode;
    2.39 -import jdk.nashorn.internal.ir.ReferenceNode;
    2.40  import jdk.nashorn.internal.ir.ReturnNode;
    2.41  import jdk.nashorn.internal.ir.RuntimeNode;
    2.42  import jdk.nashorn.internal.ir.RuntimeNode.Request;
    2.43 @@ -117,6 +119,8 @@
    2.44       */
    2.45      private Set<String> localUses;
    2.46  
    2.47 +    private final LexicalContext lexicalContext = new LexicalContext();
    2.48 +
    2.49      private static final DebugLogger LOG   = new DebugLogger("attr");
    2.50      private static final boolean     DEBUG = LOG.isEnabled();
    2.51  
    2.52 @@ -137,14 +141,15 @@
    2.53      }
    2.54  
    2.55      @Override
    2.56 -    public Node leave(final AccessNode accessNode) {
    2.57 +    public Node leaveAccessNode(final AccessNode accessNode) {
    2.58          newTemporary(Type.OBJECT, accessNode);  //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this
    2.59          end(accessNode);
    2.60          return accessNode;
    2.61      }
    2.62  
    2.63      @Override
    2.64 -    public Node enter(final Block block) {
    2.65 +    public Node enterBlock(final Block block) {
    2.66 +        lexicalContext.push(block);
    2.67          start(block);
    2.68  
    2.69          final Set<String> savedLocalDefs = localDefs;
    2.70 @@ -160,9 +165,7 @@
    2.71              localDefs = new HashSet<>(savedLocalDefs);
    2.72              localUses = new HashSet<>(savedLocalUses);
    2.73  
    2.74 -            for (final Node statement : block.getStatements()) {
    2.75 -                statement.accept(this);
    2.76 -            }
    2.77 +            block.visitStatements(this);
    2.78          } finally {
    2.79              localDefs = savedLocalDefs;
    2.80              localUses = savedLocalUses;
    2.81 @@ -172,11 +175,12 @@
    2.82  
    2.83          end(block);
    2.84  
    2.85 +        lexicalContext.pop(block);
    2.86          return null;
    2.87      }
    2.88  
    2.89      @Override
    2.90 -    public Node enter(final CallNode callNode) {
    2.91 +    public Node enterCallNode(final CallNode callNode) {
    2.92          start(callNode);
    2.93  
    2.94          callNode.getFunction().accept(this);
    2.95 @@ -197,8 +201,7 @@
    2.96              evalArgs.setThis(thisNode);
    2.97          }
    2.98  
    2.99 -        newTemporary(Type.OBJECT, callNode); // object type here, access specialization in FinalizeTypes may narrow it later
   2.100 -        newType(callNode.getFunction().getSymbol(), Type.OBJECT);
   2.101 +        newTemporary(callNode.getType(), callNode); // access specialization in FinalizeTypes may narrow it further later
   2.102  
   2.103          end(callNode);
   2.104  
   2.105 @@ -206,29 +209,106 @@
   2.106      }
   2.107  
   2.108      @Override
   2.109 -    public Node enter(final CatchNode catchNode) {
   2.110 +    public Node enterCatchNode(final CatchNode catchNode) {
   2.111          final IdentNode exception = catchNode.getException();
   2.112          final Block     block     = getCurrentBlock();
   2.113  
   2.114          start(catchNode);
   2.115  
   2.116          // define block-local exception variable
   2.117 -        final Symbol def = block.defineSymbol(exception.getName(), IS_VAR | IS_LET, exception);
   2.118 +        final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception);
   2.119          newType(def, Type.OBJECT);
   2.120          addLocalDef(exception.getName());
   2.121  
   2.122          return catchNode;
   2.123      }
   2.124  
   2.125 +    /**
   2.126 +     * Declare the definition of a new symbol.
   2.127 +     *
   2.128 +     * @param name         Name of symbol.
   2.129 +     * @param symbolFlags  Symbol flags.
   2.130 +     * @param node         Defining Node.
   2.131 +     *
   2.132 +     * @return Symbol for given name or null for redefinition.
   2.133 +     */
   2.134 +    private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) {
   2.135 +        int    flags  = symbolFlags;
   2.136 +        Symbol symbol = findSymbol(block, name); // Locate symbol.
   2.137 +
   2.138 +        if ((flags & KINDMASK) == IS_GLOBAL) {
   2.139 +            flags |= IS_SCOPE;
   2.140 +        }
   2.141 +
   2.142 +        final FunctionNode function = lexicalContext.getFunction(block);
   2.143 +        if (symbol != null) {
   2.144 +            // Symbol was already defined. Check if it needs to be redefined.
   2.145 +            if ((flags & KINDMASK) == IS_PARAM) {
   2.146 +                if (!isLocal(function, symbol)) {
   2.147 +                    // Not defined in this function. Create a new definition.
   2.148 +                    symbol = null;
   2.149 +                } else if (symbol.isParam()) {
   2.150 +                    // Duplicate parameter. Null return will force an error.
   2.151 +                    assert false : "duplicate parameter";
   2.152 +                    return null;
   2.153 +                }
   2.154 +            } else if ((flags & KINDMASK) == IS_VAR) {
   2.155 +                if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) {
   2.156 +                    assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == block) : "duplicate let variable in block";
   2.157 +                    // Always create a new definition.
   2.158 +                    symbol = null;
   2.159 +                } else {
   2.160 +                    // Not defined in this function. Create a new definition.
   2.161 +                    if (!isLocal(function, symbol) || symbol.less(IS_VAR)) {
   2.162 +                        symbol = null;
   2.163 +                    }
   2.164 +                }
   2.165 +            }
   2.166 +        }
   2.167 +
   2.168 +        if (symbol == null) {
   2.169 +            // If not found, then create a new one.
   2.170 +            Block symbolBlock;
   2.171 +
   2.172 +            // Determine where to create it.
   2.173 +            if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
   2.174 +                symbolBlock = block;
   2.175 +            } else {
   2.176 +                symbolBlock = function;
   2.177 +            }
   2.178 +
   2.179 +            // Create and add to appropriate block.
   2.180 +            symbol = new Symbol(name, flags, node, symbolBlock);
   2.181 +            symbolBlock.putSymbol(name, symbol);
   2.182 +
   2.183 +            if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
   2.184 +                symbolBlock.getFrame().addSymbol(symbol);
   2.185 +                symbol.setNeedsSlot(true);
   2.186 +            }
   2.187 +        } else if (symbol.less(flags)) {
   2.188 +            symbol.setFlags(flags);
   2.189 +        }
   2.190 +
   2.191 +        if (node != null) {
   2.192 +            node.setSymbol(symbol);
   2.193 +        }
   2.194 +
   2.195 +        return symbol;
   2.196 +    }
   2.197 +
   2.198      @Override
   2.199 -    public Node enter(final FunctionNode functionNode) {
   2.200 +    public Node enterFunctionNode(final FunctionNode functionNode) {
   2.201          start(functionNode, false);
   2.202          if (functionNode.isLazy()) {
   2.203 -            LOG.info("LAZY: " + functionNode.getName());
   2.204 +            LOG.info("LAZY: " + functionNode.getName() + " => Promoting to OBJECT");
   2.205 +            newTemporary(lexicalContext.getCurrentFunction(), Type.OBJECT, functionNode);
   2.206 +            functionNode.setReturnType(Type.OBJECT);
   2.207              end(functionNode);
   2.208              return null;
   2.209          }
   2.210  
   2.211 +        lexicalContext.push(functionNode);
   2.212 +
   2.213          clearLocalDefs();
   2.214          clearLocalUses();
   2.215  
   2.216 @@ -244,24 +324,36 @@
   2.217          initScope(functionNode);
   2.218          initReturn(functionNode);
   2.219  
   2.220 -        // Add all nested functions as symbols in this function
   2.221 -        for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
   2.222 +        // Add all nested declared functions as symbols in this function
   2.223 +        for (final FunctionNode nestedFunction : functionNode.getDeclaredFunctions()) {
   2.224              final IdentNode ident = nestedFunction.getIdent();
   2.225 -            if (ident != null && nestedFunction.isStatement()) {
   2.226 -                final Symbol functionSymbol = functionNode.defineSymbol(ident.getName(), IS_VAR, nestedFunction);
   2.227 +            if (ident != null) {
   2.228 +                assert nestedFunction.isDeclared();
   2.229 +                final Symbol functionSymbol = defineSymbol(functionNode, ident.getName(), IS_VAR, nestedFunction);
   2.230                  newType(functionSymbol, Type.typeFor(ScriptFunction.class));
   2.231              }
   2.232          }
   2.233  
   2.234 -        if (functionNode.isScript()) {
   2.235 +        if (functionNode.isProgram()) {
   2.236              initFromPropertyMap(functionNode);
   2.237          }
   2.238  
   2.239          // Add function name as local symbol
   2.240 -        if (!functionNode.isStatement() && !functionNode.isAnonymous() && !functionNode.isScript()) {
   2.241 -            final Symbol selfSymbol = functionNode.defineSymbol(functionNode.getIdent().getName(), IS_VAR, functionNode);
   2.242 -            newType(selfSymbol, Type.OBJECT);
   2.243 -            selfSymbol.setNode(functionNode);
   2.244 +        if (!functionNode.isDeclared() && !functionNode.isProgram()) {
   2.245 +            if(functionNode.getSymbol() != null) {
   2.246 +                // a temporary left over from an earlier pass when the function was lazy
   2.247 +                assert functionNode.getSymbol().isTemp();
   2.248 +                // remove it
   2.249 +                functionNode.setSymbol(null);
   2.250 +            }
   2.251 +            final Symbol selfSymbol;
   2.252 +            if(functionNode.isAnonymous()) {
   2.253 +                selfSymbol = newTemporary(functionNode, Type.OBJECT, functionNode);
   2.254 +            } else {
   2.255 +                selfSymbol = defineSymbol(functionNode, functionNode.getIdent().getName(), IS_VAR, functionNode);
   2.256 +                newType(selfSymbol, Type.OBJECT);
   2.257 +                selfSymbol.setNode(functionNode);
   2.258 +            }
   2.259          }
   2.260  
   2.261          /*
   2.262 @@ -282,32 +374,26 @@
   2.263           */
   2.264  
   2.265          final List<Symbol> declaredSymbols = new ArrayList<>();
   2.266 -        for (final VarNode decl : functionNode.getDeclarations()) {
   2.267 -            final IdentNode ident = decl.getName();
   2.268 -            // any declared symbols that aren't visited need to be typed as well, hence the list
   2.269 -            declaredSymbols.add(functionNode.defineSymbol(ident.getName(), IS_VAR, new IdentNode(ident)));
   2.270 -        }
   2.271 +        // This visitor will assign symbol to all declared variables, except function declarations (which are taken care
   2.272 +        // in a separate step above) and "var" declarations in for loop initializers.
   2.273 +        functionNode.accept(new NodeOperatorVisitor() {
   2.274 +            @Override
   2.275 +            public Node enterFunctionNode(FunctionNode nestedFn) {
   2.276 +                // Don't descend into nested functions
   2.277 +                return nestedFn == functionNode ? nestedFn : null;
   2.278 +            }
   2.279 +            @Override
   2.280 +            public Node enterVarNode(VarNode varNode) {
   2.281 +                if(varNode.isStatement() && !varNode.isFunctionDeclaration()) {
   2.282 +                    final IdentNode ident = varNode.getName();
   2.283 +                    // any declared symbols that aren't visited need to be typed as well, hence the list
   2.284 +                    declaredSymbols.add(defineSymbol(functionNode, ident.getName(), IS_VAR, new IdentNode(ident)));
   2.285 +                }
   2.286 +                return null;
   2.287 +            }
   2.288 +        });
   2.289  
   2.290 -        // Every nested function needs a definition in the outer function with its name. Add these.
   2.291 -        for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
   2.292 -            final VarNode varNode = nestedFunction.getFunctionVarNode();
   2.293 -            if (varNode != null) {
   2.294 -                varNode.accept(this);
   2.295 -                assert varNode.isFunctionVarNode() : varNode + " should be function var node";
   2.296 -            }
   2.297 -        }
   2.298 -
   2.299 -        for (final Node statement : functionNode.getStatements()) {
   2.300 -            if (statement instanceof VarNode && ((VarNode)statement).isFunctionVarNode()) {
   2.301 -                continue; //var nodes have already been processed, skip or they will generate additional defs/uses and false "can be undefined"
   2.302 -            }
   2.303 -            statement.accept(this);
   2.304 -        }
   2.305 -
   2.306 -        for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
   2.307 -            LOG.info("Going into nested function " + functionNode.getName() + " -> " + nestedFunction.getName());
   2.308 -            nestedFunction.accept(this);
   2.309 -        }
   2.310 +        visitFunctionStatements(functionNode);
   2.311  
   2.312          //unknown parameters are promoted to object type.
   2.313          finalizeParameters(functionNode);
   2.314 @@ -343,10 +429,19 @@
   2.315          functionNode.setState(CompilationState.ATTR);
   2.316  
   2.317          end(functionNode, false);
   2.318 +        lexicalContext.pop(functionNode);
   2.319  
   2.320          return null;
   2.321      }
   2.322  
   2.323 +    private void visitFunctionStatements(final FunctionNode functionNode) {
   2.324 +        final List<Node> newStatements = new ArrayList<>(functionNode.getStatements());
   2.325 +        for(ListIterator<Node> stmts = newStatements.listIterator(); stmts.hasNext();) {
   2.326 +            stmts.set(stmts.next().accept(this));
   2.327 +        }
   2.328 +        functionNode.setStatements(newStatements);
   2.329 +    }
   2.330 +
   2.331      @Override
   2.332      public Node leaveCONVERT(final UnaryNode unaryNode) {
   2.333          assert false : "There should be no convert operators in IR during Attribution";
   2.334 @@ -355,7 +450,7 @@
   2.335      }
   2.336  
   2.337      @Override
   2.338 -    public Node enter(final IdentNode identNode) {
   2.339 +    public Node enterIdentNode(final IdentNode identNode) {
   2.340          final String name = identNode.getName();
   2.341  
   2.342          start(identNode);
   2.343 @@ -372,7 +467,7 @@
   2.344          final Block  block     = getCurrentBlock();
   2.345          final Symbol oldSymbol = identNode.getSymbol();
   2.346  
   2.347 -        Symbol symbol = block.findSymbol(name);
   2.348 +        Symbol symbol = findSymbol(block, name);
   2.349  
   2.350          //If an existing symbol with the name is found, use that otherwise, declare a new one
   2.351          if (symbol != null) {
   2.352 @@ -396,22 +491,13 @@
   2.353              }
   2.354  
   2.355              identNode.setSymbol(symbol);
   2.356 -            if (!getCurrentFunctionNode().isLocal(symbol)) {
   2.357 -                // non-local: we need to put symbol in scope (if it isn't already)
   2.358 -                if (!symbol.isScope()) {
   2.359 -                    final List<Block> lookupBlocks = findLookupBlocksHelper(getCurrentFunctionNode(), symbol.findFunction());
   2.360 -                    for (final Block lookupBlock : lookupBlocks) {
   2.361 -                        final Symbol refSymbol = lookupBlock.findSymbol(name);
   2.362 -                        if (refSymbol != null) { // See NASHORN-837, function declaration in lexical scope: try {} catch (x){ function f() { use(x) } } f()
   2.363 -                            LOG.finest("Found a ref symbol that must be scope " + refSymbol);
   2.364 -                            refSymbol.setIsScope();
   2.365 -                        }
   2.366 -                    }
   2.367 -                }
   2.368 +            // non-local: we need to put symbol in scope (if it isn't already)
   2.369 +            if (!isLocal(getCurrentFunctionNode(), symbol) && !symbol.isScope()) {
   2.370 +                symbol.setIsScope();
   2.371              }
   2.372          } else {
   2.373              LOG.info("No symbol exists. Declare undefined: " + symbol);
   2.374 -            symbol = block.useSymbol(name, identNode);
   2.375 +            symbol = useSymbol(block, name, identNode);
   2.376              // we have never seen this before, it can be undefined
   2.377              newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway?
   2.378              symbol.setCanBeUndefined();
   2.379 @@ -420,9 +506,10 @@
   2.380  
   2.381          assert symbol != null;
   2.382          if(symbol.isGlobal()) {
   2.383 -            getCurrentFunctionNode().setUsesGlobalSymbol();
   2.384 +            setUsesGlobalSymbol();
   2.385          } else if(symbol.isScope()) {
   2.386 -            getCurrentFunctionNode().setUsesScopeSymbol(symbol);
   2.387 +            final Iterator<Block> blocks = lexicalContext.getBlocks();
   2.388 +            blocks.next().setUsesScopeSymbol(symbol, blocks);
   2.389          }
   2.390  
   2.391          if (symbol != oldSymbol && !identNode.isInitializedHere()) {
   2.392 @@ -435,15 +522,68 @@
   2.393          return null;
   2.394      }
   2.395  
   2.396 +    /**
   2.397 +     * Marks the current function as one using any global symbol. The function and all its parent functions will all be
   2.398 +     * marked as needing parent scope.
   2.399 +     * @see #needsParentScope()
   2.400 +     */
   2.401 +    private void setUsesGlobalSymbol() {
   2.402 +        for(final Iterator<FunctionNode> fns = lexicalContext.getFunctions(); fns.hasNext();) {
   2.403 +            fns.next().setUsesAncestorScope();
   2.404 +        }
   2.405 +    }
   2.406 +
   2.407 +    /**
   2.408 +     * Declare the use of a symbol in a block.
   2.409 +     *
   2.410 +     * @param block block in which the symbol is used
   2.411 +     * @param name Name of symbol.
   2.412 +     * @param node Using node
   2.413 +     *
   2.414 +     * @return Symbol for given name.
   2.415 +     */
   2.416 +    private Symbol useSymbol(final Block block, final String name, final Node node) {
   2.417 +        Symbol symbol = findSymbol(block, name);
   2.418 +
   2.419 +        if (symbol == null) {
   2.420 +            // If not found, declare as a free var.
   2.421 +            symbol = defineSymbol(block, name, IS_GLOBAL, node);
   2.422 +        } else {
   2.423 +            node.setSymbol(symbol);
   2.424 +        }
   2.425 +
   2.426 +        return symbol;
   2.427 +    }
   2.428 +
   2.429 +
   2.430 +    /**
   2.431 +     * Search for symbol in the lexical context starting from the given block.
   2.432 +     * @param name Symbol name.
   2.433 +     * @return Found symbol or null if not found.
   2.434 +     */
   2.435 +    private Symbol findSymbol(final Block block, final String name) {
   2.436 +        // Search up block chain to locate symbol.
   2.437 +
   2.438 +        for(final Iterator<Block> blocks = lexicalContext.getBlocks(block); blocks.hasNext();) {
   2.439 +            // Find name.
   2.440 +            final Symbol symbol = blocks.next().getExistingSymbol(name);
   2.441 +            // If found then we are good.
   2.442 +            if(symbol != null) {
   2.443 +                return symbol;
   2.444 +            }
   2.445 +        }
   2.446 +        return null;
   2.447 +    }
   2.448 +
   2.449      @Override
   2.450 -    public Node leave(final IndexNode indexNode) {
   2.451 +    public Node leaveIndexNode(final IndexNode indexNode) {
   2.452          newTemporary(Type.OBJECT, indexNode); //TORO
   2.453          return indexNode;
   2.454      }
   2.455  
   2.456      @SuppressWarnings("rawtypes")
   2.457      @Override
   2.458 -    public Node enter(final LiteralNode literalNode) {
   2.459 +    public Node enterLiteralNode(final LiteralNode literalNode) {
   2.460          try {
   2.461              start(literalNode);
   2.462              assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens
   2.463 @@ -472,14 +612,14 @@
   2.464      }
   2.465  
   2.466      @Override
   2.467 -    public Node leave(final ObjectNode objectNode) {
   2.468 +    public Node leaveObjectNode(final ObjectNode objectNode) {
   2.469          newTemporary(Type.OBJECT, objectNode);
   2.470          end(objectNode);
   2.471          return objectNode;
   2.472      }
   2.473  
   2.474      @Override
   2.475 -    public Node enter(final PropertyNode propertyNode) {
   2.476 +    public Node enterPropertyNode(final PropertyNode propertyNode) {
   2.477          // assign a pseudo symbol to property name, see NASHORN-710
   2.478          propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
   2.479          end(propertyNode);
   2.480 @@ -487,31 +627,7 @@
   2.481      }
   2.482  
   2.483      @Override
   2.484 -    public Node enter(final ReferenceNode referenceNode) {
   2.485 -        final FunctionNode functionNode = referenceNode.getReference();
   2.486 -        if (functionNode != null) {
   2.487 -            functionNode.addReferencingParentBlock(getCurrentBlock());
   2.488 -        }
   2.489 -        return referenceNode;
   2.490 -    }
   2.491 -
   2.492 -    @Override
   2.493 -    public Node leave(final ReferenceNode referenceNode) {
   2.494 -        newTemporary(Type.OBJECT, referenceNode); //reference node type is always an object, i.e. the scriptFunction. the function return type varies though
   2.495 -
   2.496 -        final FunctionNode functionNode = referenceNode.getReference();
   2.497 -        //assert !functionNode.getType().isUnknown() || functionNode.isLazy() : functionNode.getType();
   2.498 -        if (functionNode.isLazy()) {
   2.499 -            LOG.info("Lazy function node call reference: " + functionNode.getName() + " => Promoting to OBJECT");
   2.500 -            functionNode.setReturnType(Type.OBJECT);
   2.501 -        }
   2.502 -        end(referenceNode);
   2.503 -
   2.504 -        return referenceNode;
   2.505 -    }
   2.506 -
   2.507 -    @Override
   2.508 -    public Node leave(final ReturnNode returnNode) {
   2.509 +    public Node leaveReturnNode(final ReturnNode returnNode) {
   2.510          final Node expr = returnNode.getExpression();
   2.511  
   2.512          if (expr != null) {
   2.513 @@ -530,7 +646,7 @@
   2.514      }
   2.515  
   2.516      @Override
   2.517 -    public Node leave(final SwitchNode switchNode) {
   2.518 +    public Node leaveSwitchNode(final SwitchNode switchNode) {
   2.519          Type type = Type.UNKNOWN;
   2.520  
   2.521          for (final CaseNode caseNode : switchNode.getCases()) {
   2.522 @@ -567,7 +683,7 @@
   2.523      }
   2.524  
   2.525      @Override
   2.526 -    public Node leave(final TryNode tryNode) {
   2.527 +    public Node leaveTryNode(final TryNode tryNode) {
   2.528          tryNode.setException(exceptionSymbol());
   2.529  
   2.530          if (tryNode.getFinallyBody() != null) {
   2.531 @@ -580,13 +696,13 @@
   2.532      }
   2.533  
   2.534      @Override
   2.535 -    public Node enter(final VarNode varNode) {
   2.536 +    public Node enterVarNode(final VarNode varNode) {
   2.537          start(varNode);
   2.538  
   2.539          final IdentNode ident = varNode.getName();
   2.540          final String    name  = ident.getName();
   2.541  
   2.542 -        final Symbol symbol = getCurrentBlock().defineSymbol(name, IS_VAR, ident);
   2.543 +        final Symbol symbol = defineSymbol(getCurrentBlock(), name, IS_VAR, ident);
   2.544          assert symbol != null;
   2.545  
   2.546          LOG.info("VarNode " + varNode + " set symbol " + symbol);
   2.547 @@ -598,23 +714,15 @@
   2.548              symbol.setCanBeUndefined();
   2.549          }
   2.550  
   2.551 -        if (varNode.getInit() != null) {
   2.552 -            varNode.getInit().accept(this);
   2.553 -        }
   2.554 -
   2.555          return varNode;
   2.556      }
   2.557  
   2.558      @Override
   2.559 -    public Node leave(final VarNode varNode) {
   2.560 +    public Node leaveVarNode(final VarNode varNode) {
   2.561          final Node      init  = varNode.getInit();
   2.562          final IdentNode ident = varNode.getName();
   2.563          final String    name  = ident.getName();
   2.564  
   2.565 -        if (init != null) {
   2.566 -            addLocalDef(name);
   2.567 -        }
   2.568 -
   2.569          if (init == null) {
   2.570              // var x; with no init will be treated like a use of x by
   2.571              // visit(IdentNode) unless we remove the name
   2.572 @@ -623,8 +731,10 @@
   2.573              return varNode;
   2.574          }
   2.575  
   2.576 +        addLocalDef(name);
   2.577 +
   2.578          final Symbol  symbol   = varNode.getSymbol();
   2.579 -        final boolean isScript = symbol.getBlock().getFunction().isScript(); //see NASHORN-56
   2.580 +        final boolean isScript = lexicalContext.getFunction(symbol.getBlock()).isProgram(); //see NASHORN-56
   2.581          if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) {
   2.582              // Forbid integers as local vars for now as we have no way to treat them as undefined
   2.583              newType(symbol, init.getType());
   2.584 @@ -718,11 +828,9 @@
   2.585          runtimeNode = new RuntimeNode(unaryNode, request, args);
   2.586          assert runtimeNode.getSymbol() == unaryNode.getSymbol(); //clone constructor should do this
   2.587  
   2.588 -        runtimeNode.accept(this);
   2.589 -        return runtimeNode;
   2.590 +        return leaveRuntimeNode(runtimeNode);
   2.591      }
   2.592  
   2.593 -
   2.594      @Override
   2.595      public Node leaveNEW(final UnaryNode unaryNode) {
   2.596          newTemporary(Type.OBJECT, unaryNode);
   2.597 @@ -755,7 +863,7 @@
   2.598          runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
   2.599          assert runtimeNode.getSymbol() == unaryNode.getSymbol();
   2.600  
   2.601 -        runtimeNode.accept(this);
   2.602 +        runtimeNode = (RuntimeNode)leaveRuntimeNode(runtimeNode);
   2.603  
   2.604          end(unaryNode);
   2.605  
   2.606 @@ -763,7 +871,7 @@
   2.607      }
   2.608  
   2.609      @Override
   2.610 -    public Node leave(final RuntimeNode runtimeNode) {
   2.611 +    public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
   2.612          newTemporary(runtimeNode.getRequest().getReturnType(), runtimeNode);
   2.613          return runtimeNode;
   2.614      }
   2.615 @@ -823,12 +931,12 @@
   2.616              final IdentNode ident = (IdentNode)lhs;
   2.617              final String    name  = ident.getName();
   2.618  
   2.619 -            Symbol symbol = getCurrentBlock().findSymbol(name);
   2.620 +            Symbol symbol = findSymbol(getCurrentBlock(), name);
   2.621  
   2.622              if (symbol == null) {
   2.623 -                symbol = block.defineSymbol(name, IS_GLOBAL, ident);
   2.624 +                symbol = defineSymbol(block, name, IS_GLOBAL, ident);
   2.625                  binaryNode.setSymbol(symbol);
   2.626 -            } else if (!getCurrentFunctionNode().isLocal(symbol)) {
   2.627 +            } else if (!isLocal(getCurrentFunctionNode(), symbol)) {
   2.628                  symbol.setIsScope();
   2.629              }
   2.630  
   2.631 @@ -838,6 +946,12 @@
   2.632          return binaryNode;
   2.633      }
   2.634  
   2.635 +    private boolean isLocal(FunctionNode function, Symbol symbol) {
   2.636 +        final Block block = symbol.getBlock();
   2.637 +        // some temp symbols have no block, so can be assumed local
   2.638 +        return block == null || lexicalContext.getFunction(block) == function;
   2.639 +    }
   2.640 +
   2.641      @Override
   2.642      public Node enterASSIGN(final BinaryNode binaryNode) {
   2.643          return enterAssignmentNode(binaryNode);
   2.644 @@ -995,7 +1109,7 @@
   2.645          return leaveBinaryArithmetic(binaryNode);
   2.646      }
   2.647  
   2.648 -    private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) {
   2.649 +    private Node leaveCmp(final BinaryNode binaryNode) {
   2.650          final Node lhs = binaryNode.lhs();
   2.651          final Node rhs = binaryNode.rhs();
   2.652  
   2.653 @@ -1033,37 +1147,38 @@
   2.654  
   2.655      @Override
   2.656      public Node leaveEQ(final BinaryNode binaryNode) {
   2.657 -        return leaveCmp(binaryNode, Request.EQ);
   2.658 +        return leaveCmp(binaryNode);
   2.659      }
   2.660  
   2.661      @Override
   2.662      public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
   2.663 -        return leaveCmp(binaryNode, Request.EQ_STRICT);
   2.664 +        return leaveCmp(binaryNode);
   2.665      }
   2.666  
   2.667      @Override
   2.668      public Node leaveGE(final BinaryNode binaryNode) {
   2.669 -        return leaveCmp(binaryNode, Request.GE);
   2.670 +        return leaveCmp(binaryNode);
   2.671      }
   2.672  
   2.673      @Override
   2.674      public Node leaveGT(final BinaryNode binaryNode) {
   2.675 -        return leaveCmp(binaryNode, Request.GT);
   2.676 +        return leaveCmp(binaryNode);
   2.677      }
   2.678  
   2.679      @Override
   2.680      public Node leaveIN(final BinaryNode binaryNode) {
   2.681 -        try {
   2.682 -            return new RuntimeNode(binaryNode, Request.IN).accept(this);
   2.683 -        } finally {
   2.684 -            end(binaryNode);
   2.685 -        }
   2.686 +        return leaveBinaryRuntimeOperator(binaryNode, Request.IN);
   2.687      }
   2.688  
   2.689      @Override
   2.690      public Node leaveINSTANCEOF(final BinaryNode binaryNode) {
   2.691 +        return leaveBinaryRuntimeOperator(binaryNode, Request.INSTANCEOF);
   2.692 +    }
   2.693 +
   2.694 +    private Node leaveBinaryRuntimeOperator(final BinaryNode binaryNode, final Request request) {
   2.695          try {
   2.696 -            return new RuntimeNode(binaryNode, Request.INSTANCEOF).accept(this);
   2.697 +            // Don't do a full RuntimeNode.accept, as we don't want to double-visit the binary node operands
   2.698 +            return leaveRuntimeNode(new RuntimeNode(binaryNode, request));
   2.699          } finally {
   2.700              end(binaryNode);
   2.701          }
   2.702 @@ -1071,12 +1186,12 @@
   2.703  
   2.704      @Override
   2.705      public Node leaveLE(final BinaryNode binaryNode) {
   2.706 -        return leaveCmp(binaryNode, Request.LE);
   2.707 +        return leaveCmp(binaryNode);
   2.708      }
   2.709  
   2.710      @Override
   2.711      public Node leaveLT(final BinaryNode binaryNode) {
   2.712 -        return leaveCmp(binaryNode, Request.LT);
   2.713 +        return leaveCmp(binaryNode);
   2.714      }
   2.715  
   2.716      @Override
   2.717 @@ -1091,12 +1206,12 @@
   2.718  
   2.719      @Override
   2.720      public Node leaveNE(final BinaryNode binaryNode) {
   2.721 -        return leaveCmp(binaryNode, Request.NE);
   2.722 +        return leaveCmp(binaryNode);
   2.723      }
   2.724  
   2.725      @Override
   2.726      public Node leaveNE_STRICT(final BinaryNode binaryNode) {
   2.727 -        return leaveCmp(binaryNode, Request.NE_STRICT);
   2.728 +        return leaveCmp(binaryNode);
   2.729      }
   2.730  
   2.731      @Override
   2.732 @@ -1127,9 +1242,9 @@
   2.733      }
   2.734  
   2.735      @Override
   2.736 -    public Node leave(final ForNode forNode) {
   2.737 +    public Node leaveForNode(final ForNode forNode) {
   2.738          if (forNode.isForIn()) {
   2.739 -            forNode.setIterator(newInternal(getCurrentFunctionNode(), getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73
   2.740 +            forNode.setIterator(newInternal(getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73
   2.741              /*
   2.742               * Iterators return objects, so we need to widen the scope of the
   2.743               * init variable if it, for example, has been assigned double type
   2.744 @@ -1144,7 +1259,7 @@
   2.745      }
   2.746  
   2.747      @Override
   2.748 -    public Node leave(final TernaryNode ternaryNode) {
   2.749 +    public Node leaveTernaryNode(final TernaryNode ternaryNode) {
   2.750          final Node lhs  = ternaryNode.rhs();
   2.751          final Node rhs  = ternaryNode.third();
   2.752  
   2.753 @@ -1159,24 +1274,24 @@
   2.754          return ternaryNode;
   2.755      }
   2.756  
   2.757 -    private static void initThis(final FunctionNode functionNode) {
   2.758 -        final Symbol thisSymbol = functionNode.defineSymbol(THIS.tag(), IS_PARAM | IS_THIS, null);
   2.759 +    private void initThis(final FunctionNode functionNode) {
   2.760 +        final Symbol thisSymbol = defineSymbol(functionNode, THIS.tag(), IS_PARAM | IS_THIS, null);
   2.761          newType(thisSymbol, Type.OBJECT);
   2.762          thisSymbol.setNeedsSlot(true);
   2.763          functionNode.getThisNode().setSymbol(thisSymbol);
   2.764          LOG.info("Initialized scope symbol: " + thisSymbol);
   2.765      }
   2.766  
   2.767 -    private static void initScope(final FunctionNode functionNode) {
   2.768 -        final Symbol scopeSymbol = functionNode.defineSymbol(SCOPE.tag(), IS_VAR | IS_INTERNAL, null);
   2.769 +    private void initScope(final FunctionNode functionNode) {
   2.770 +        final Symbol scopeSymbol = defineSymbol(functionNode, SCOPE.tag(), IS_VAR | IS_INTERNAL, null);
   2.771          newType(scopeSymbol, Type.typeFor(ScriptObject.class));
   2.772          scopeSymbol.setNeedsSlot(true);
   2.773          functionNode.getScopeNode().setSymbol(scopeSymbol);
   2.774          LOG.info("Initialized scope symbol: " + scopeSymbol);
   2.775      }
   2.776  
   2.777 -    private static void initReturn(final FunctionNode functionNode) {
   2.778 -        final Symbol returnSymbol = functionNode.defineSymbol(SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null);
   2.779 +    private void initReturn(final FunctionNode functionNode) {
   2.780 +        final Symbol returnSymbol = defineSymbol(functionNode, SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null);
   2.781          newType(returnSymbol, Type.OBJECT);
   2.782          returnSymbol.setNeedsSlot(true);
   2.783          functionNode.getResultNode().setSymbol(returnSymbol);
   2.784 @@ -1186,7 +1301,7 @@
   2.785  
   2.786      private void initVarArg(final FunctionNode functionNode) {
   2.787          if (functionNode.isVarArg()) {
   2.788 -            final Symbol varArgsSymbol = functionNode.defineSymbol(VARARGS.tag(), IS_PARAM | IS_INTERNAL, null);
   2.789 +            final Symbol varArgsSymbol = defineSymbol(functionNode, VARARGS.tag(), IS_PARAM | IS_INTERNAL, null);
   2.790              varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY);
   2.791              varArgsSymbol.setNeedsSlot(true);
   2.792              functionNode.getVarArgsNode().setSymbol(varArgsSymbol);
   2.793 @@ -1194,7 +1309,7 @@
   2.794  
   2.795              if (functionNode.needsArguments()) {
   2.796                  final String    argumentsName   = functionNode.getArgumentsNode().getName();
   2.797 -                final Symbol    argumentsSymbol = functionNode.defineSymbol(argumentsName, IS_VAR | IS_INTERNAL, null);
   2.798 +                final Symbol    argumentsSymbol = defineSymbol(functionNode, argumentsName, IS_VAR | IS_INTERNAL, null);
   2.799                  newType(argumentsSymbol, Type.typeFor(ScriptObject.class));
   2.800                  argumentsSymbol.setNeedsSlot(true);
   2.801                  functionNode.getArgumentsNode().setSymbol(argumentsSymbol);
   2.802 @@ -1204,9 +1319,9 @@
   2.803          }
   2.804      }
   2.805  
   2.806 -    private static void initCallee(final FunctionNode functionNode) {
   2.807 +    private void initCallee(final FunctionNode functionNode) {
   2.808          assert functionNode.getCalleeNode() != null : functionNode + " has no callee";
   2.809 -        final Symbol calleeSymbol = functionNode.defineSymbol(CALLEE.tag(), IS_PARAM | IS_INTERNAL, null);
   2.810 +        final Symbol calleeSymbol = defineSymbol(functionNode, CALLEE.tag(), IS_PARAM | IS_INTERNAL, null);
   2.811          newType(calleeSymbol, Type.typeFor(ScriptFunction.class));
   2.812          calleeSymbol.setNeedsSlot(true);
   2.813          functionNode.getCalleeNode().setSymbol(calleeSymbol);
   2.814 @@ -1226,7 +1341,7 @@
   2.815  
   2.816          for (final IdentNode param : functionNode.getParameters()) {
   2.817              addLocalDef(param.getName());
   2.818 -            final Symbol paramSymbol = functionNode.defineSymbol(param.getName(), IS_PARAM, param);
   2.819 +            final Symbol paramSymbol = defineSymbol(functionNode, param.getName(), IS_PARAM, param);
   2.820              if (paramSymbol != null) {
   2.821                  final Type callSiteParamType = functionNode.getSpecializedType(param);
   2.822                  if (callSiteParamType != null) {
   2.823 @@ -1279,15 +1394,15 @@
   2.824       * Move any properties from a global map into the scope of this method
   2.825       * @param functionNode the function node for which to init scope vars
   2.826       */
   2.827 -    private static void initFromPropertyMap(final FunctionNode functionNode) {
   2.828 +    private void initFromPropertyMap(final FunctionNode functionNode) {
   2.829          // For a script, add scope symbols as defined in the property map
   2.830 -        assert functionNode.isScript();
   2.831 +        assert functionNode.isProgram();
   2.832  
   2.833          final PropertyMap map = Context.getGlobalMap();
   2.834  
   2.835          for (final Property property : map.getProperties()) {
   2.836              final String key    = property.getKey();
   2.837 -            final Symbol symbol = functionNode.defineSymbol(key, IS_GLOBAL, null);
   2.838 +            final Symbol symbol = defineSymbol(functionNode, key, IS_GLOBAL, null);
   2.839              newType(symbol, Type.OBJECT);
   2.840              LOG.info("Added global symbol from property map " + symbol);
   2.841          }
   2.842 @@ -1354,7 +1469,7 @@
   2.843      private static void ensureAssignmentSlots(final FunctionNode functionNode, final Node assignmentDest) {
   2.844          assignmentDest.accept(new NodeVisitor() {
   2.845              @Override
   2.846 -            public Node leave(final IndexNode indexNode) {
   2.847 +            public Node leaveIndexNode(final IndexNode indexNode) {
   2.848                  final Node index = indexNode.getIndex();
   2.849                  index.getSymbol().setNeedsSlot(!index.getSymbol().isConstant());
   2.850                  return indexNode;
   2.851 @@ -1399,7 +1514,7 @@
   2.852                  }
   2.853  
   2.854                  @Override
   2.855 -                public Node enter(final FunctionNode node) {
   2.856 +                public Node enterFunctionNode(final FunctionNode node) {
   2.857                      return node.isLazy() ? null : node;
   2.858                  }
   2.859  
   2.860 @@ -1419,7 +1534,7 @@
   2.861                   */
   2.862                  @SuppressWarnings("fallthrough")
   2.863                  @Override
   2.864 -                public Node leave(final BinaryNode binaryNode) {
   2.865 +                public Node leaveBinaryNode(final BinaryNode binaryNode) {
   2.866                      final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
   2.867                      switch (binaryNode.tokenType()) {
   2.868                      default:
   2.869 @@ -1477,22 +1592,6 @@
   2.870          return binaryNode;
   2.871      }
   2.872  
   2.873 -    private static List<Block> findLookupBlocksHelper(final FunctionNode currentFunction, final FunctionNode topFunction) {
   2.874 -        if (currentFunction.findParentFunction() == topFunction) {
   2.875 -            final List<Block> blocks = new LinkedList<>();
   2.876 -
   2.877 -            blocks.add(currentFunction.getParent());
   2.878 -            blocks.addAll(currentFunction.getReferencingParentBlocks());
   2.879 -            return blocks;
   2.880 -        }
   2.881 -        /*
   2.882 -         * assumption: all parent blocks of an inner function will always be in the same outer function;
   2.883 -         * therefore we can simply skip through intermediate functions.
   2.884 -         * @see FunctionNode#addReferencingParentBlock(Block)
   2.885 -         */
   2.886 -        return findLookupBlocksHelper(currentFunction.findParentFunction(), topFunction);
   2.887 -    }
   2.888 -
   2.889      private static boolean isFunctionExpressionSelfReference(final Symbol symbol) {
   2.890          if (symbol.isVar() && symbol.getNode() == symbol.getBlock() && symbol.getNode() instanceof FunctionNode) {
   2.891              return ((FunctionNode)symbol.getNode()).getIdent().getName().equals(symbol.getName());
   2.892 @@ -1509,16 +1608,12 @@
   2.893          return newTemporary(getCurrentFunctionNode(), type, node);
   2.894      }
   2.895  
   2.896 -    private Symbol newInternal(final FunctionNode functionNode, final String name, final Type type) {
   2.897 -        final Symbol iter = getCurrentFunctionNode().defineSymbol(name, IS_VAR | IS_INTERNAL, null);
   2.898 +    private Symbol newInternal(final String name, final Type type) {
   2.899 +        final Symbol iter = defineSymbol(getCurrentFunctionNode(), name, IS_VAR | IS_INTERNAL, null);
   2.900          iter.setType(type); // NASHORN-73
   2.901          return iter;
   2.902      }
   2.903  
   2.904 -    private Symbol newInternal(final String name, final Type type) {
   2.905 -        return newInternal(getCurrentFunctionNode(), name, type);
   2.906 -    }
   2.907 -
   2.908      private static void newType(final Symbol symbol, final Type type) {
   2.909          final Type oldType = symbol.getSymbolType();
   2.910          symbol.setType(type);
   2.911 @@ -1577,13 +1672,13 @@
   2.912              }
   2.913  
   2.914              @Override
   2.915 -            public Node enter(final Block block) {
   2.916 +            public Node enterBlock(final Block block) {
   2.917                  toObject(block);
   2.918                  return block;
   2.919              }
   2.920  
   2.921              @Override
   2.922 -            public Node enter(final FunctionNode node) {
   2.923 +            public Node enterFunctionNode(final FunctionNode node) {
   2.924                  toObject(node);
   2.925                  if (node.isLazy()) {
   2.926                      return null;
     3.1 --- a/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Tue Mar 19 11:03:24 2013 -0300
     3.2 +++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Sat Mar 23 00:58:39 2013 +0100
     3.3 @@ -195,6 +195,14 @@
     3.4      }
     3.5  
     3.6      /**
     3.7 +     * Returns the name of the compile unit class name.
     3.8 +     * @return the name of the compile unit class name.
     3.9 +     */
    3.10 +    String getUnitClassName() {
    3.11 +        return unitClassName;
    3.12 +    }
    3.13 +
    3.14 +    /**
    3.15       * Convert a binary name to a package/class name.
    3.16       *
    3.17       * @param name Binary name.
    3.18 @@ -244,7 +252,7 @@
    3.19              // $getMap - get the ith entry from the constants table and cast to PropertyMap.
    3.20              final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.tag(), PropertyMap.class, int.class);
    3.21              getMapMethod.begin();
    3.22 -            getMapMethod.loadConstants(unitClassName)
    3.23 +            getMapMethod.loadConstants()
    3.24                          .load(Type.INT, 0)
    3.25                          .arrayload()
    3.26                          .checkcast(PropertyMap.class)
    3.27 @@ -254,7 +262,7 @@
    3.28              // $setMap - overwrite an existing map.
    3.29              final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.tag(), void.class, int.class, PropertyMap.class);
    3.30              setMapMethod.begin();
    3.31 -            setMapMethod.loadConstants(unitClassName)
    3.32 +            setMapMethod.loadConstants()
    3.33                          .load(Type.INT, 0)
    3.34                          .load(Type.OBJECT, 1)
    3.35                          .arraystore();
     4.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue Mar 19 11:03:24 2013 -0300
     4.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Sat Mar 23 00:58:39 2013 +0100
     4.3 @@ -76,18 +76,18 @@
     4.4  import jdk.nashorn.internal.ir.ExecuteNode;
     4.5  import jdk.nashorn.internal.ir.ForNode;
     4.6  import jdk.nashorn.internal.ir.FunctionNode;
     4.7 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
     4.8  import jdk.nashorn.internal.ir.IdentNode;
     4.9  import jdk.nashorn.internal.ir.IfNode;
    4.10  import jdk.nashorn.internal.ir.IndexNode;
    4.11 +import jdk.nashorn.internal.ir.LexicalContext;
    4.12  import jdk.nashorn.internal.ir.LineNumberNode;
    4.13  import jdk.nashorn.internal.ir.LiteralNode;
    4.14 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    4.15  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
    4.16  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
    4.17  import jdk.nashorn.internal.ir.Node;
    4.18  import jdk.nashorn.internal.ir.ObjectNode;
    4.19  import jdk.nashorn.internal.ir.PropertyNode;
    4.20 -import jdk.nashorn.internal.ir.ReferenceNode;
    4.21  import jdk.nashorn.internal.ir.ReturnNode;
    4.22  import jdk.nashorn.internal.ir.RuntimeNode;
    4.23  import jdk.nashorn.internal.ir.RuntimeNode.Request;
    4.24 @@ -107,6 +107,7 @@
    4.25  import jdk.nashorn.internal.parser.Lexer.RegexToken;
    4.26  import jdk.nashorn.internal.parser.TokenType;
    4.27  import jdk.nashorn.internal.runtime.Context;
    4.28 +import jdk.nashorn.internal.runtime.DebugLogger;
    4.29  import jdk.nashorn.internal.runtime.ECMAException;
    4.30  import jdk.nashorn.internal.runtime.Property;
    4.31  import jdk.nashorn.internal.runtime.PropertyMap;
    4.32 @@ -156,12 +157,20 @@
    4.33      /** How many regexp fields have been emitted */
    4.34      private int regexFieldCount;
    4.35  
    4.36 +    /** Used for temporary signaling between enterCallNode and enterFunctionNode to handle the special case of calling
    4.37 +     * a just-defined anonymous function expression. */
    4.38 +    private boolean functionNodeIsCallee;
    4.39 +
    4.40      /** Map of shared scope call sites */
    4.41      private final Map<SharedScopeCall, SharedScopeCall> scopeCalls = new HashMap<>();
    4.42  
    4.43 +    private final LexicalContext lexicalContext = new LexicalContext();
    4.44 +
    4.45      /** When should we stop caching regexp expressions in fields to limit bytecode size? */
    4.46      private static final int MAX_REGEX_FIELDS = 2 * 1024;
    4.47  
    4.48 +    private static final DebugLogger LOG   = new DebugLogger("codegen", "nashorn.codegen.debug");
    4.49 +
    4.50      /**
    4.51       * Constructor.
    4.52       *
    4.53 @@ -210,7 +219,7 @@
    4.54              final int flags = CALLSITE_SCOPE | getCallSiteFlags();
    4.55              method.loadScope();
    4.56  
    4.57 -            if (symbol.isFastScope(getCurrentFunctionNode())) {
    4.58 +            if (isFastScope(symbol)) {
    4.59                  // Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope.
    4.60                  if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) {
    4.61                      return loadSharedScopeVar(identNode.getType(), symbol, flags);
    4.62 @@ -221,8 +230,28 @@
    4.63          }
    4.64      }
    4.65  
    4.66 +    /**
    4.67 +     * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load
    4.68 +     *
    4.69 +     * @param function function to check for fast scope
    4.70 +     * @return true if fast scope
    4.71 +     */
    4.72 +    private boolean isFastScope(final Symbol symbol) {
    4.73 +        if (!symbol.isScope() || !symbol.getBlock().needsScope()) {
    4.74 +            return false;
    4.75 +        }
    4.76 +        // Allow fast scope access if no function contains with or eval
    4.77 +        for(final Iterator<FunctionNode> it = lexicalContext.getFunctions(getCurrentFunctionNode()); it.hasNext();) {
    4.78 +            final FunctionNode func = it.next();
    4.79 +            if (func.hasWith() || func.hasEval()) {
    4.80 +                return false;
    4.81 +            }
    4.82 +        }
    4.83 +        return true;
    4.84 +    }
    4.85 +
    4.86      private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) {
    4.87 -        method.load(symbol.isFastScope(getCurrentFunctionNode()) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1);
    4.88 +        method.load(isFastScope(symbol) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1);
    4.89          final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE);
    4.90          scopeCall.generateInvoke(method);
    4.91          return method;
    4.92 @@ -240,30 +269,18 @@
    4.93          return method;
    4.94      }
    4.95  
    4.96 -    private static int getScopeProtoDepth(final Block currentBlock, final Symbol symbol) {
    4.97 -        if (currentBlock == symbol.getBlock()) {
    4.98 -            return 0;
    4.99 -        }
   4.100 -
   4.101 -        final int   delta       = currentBlock.needsScope() ? 1 : 0;
   4.102 -        final Block parentBlock = currentBlock.getParent();
   4.103 -
   4.104 -        if (parentBlock != null) {
   4.105 -            final int result = getScopeProtoDepth(parentBlock, symbol);
   4.106 -            if (result != -1) {
   4.107 -                return delta + result;
   4.108 +    private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) {
   4.109 +        int depth = 0;
   4.110 +        final Block definingBlock = symbol.getBlock();
   4.111 +        for(final Iterator<Block> blocks = lexicalContext.getBlocks(startingBlock); blocks.hasNext();) {
   4.112 +            final Block currentBlock = blocks.next();
   4.113 +            if (currentBlock == definingBlock) {
   4.114 +                return depth;
   4.115 +            }
   4.116 +            if (currentBlock.needsScope()) {
   4.117 +                ++depth;
   4.118              }
   4.119          }
   4.120 -
   4.121 -        if (currentBlock instanceof FunctionNode) {
   4.122 -            for (final Block lookupBlock : ((FunctionNode)currentBlock).getReferencingParentBlocks()) {
   4.123 -                final int result = getScopeProtoDepth(lookupBlock, symbol);
   4.124 -                if (result != -1) {
   4.125 -                    return delta + result;
   4.126 -                }
   4.127 -            }
   4.128 -        }
   4.129 -
   4.130          return -1;
   4.131      }
   4.132  
   4.133 @@ -313,13 +330,13 @@
   4.134  
   4.135          node.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
   4.136              @Override
   4.137 -            public Node enter(final IdentNode identNode) {
   4.138 +            public Node enterIdentNode(final IdentNode identNode) {
   4.139                  loadIdent(identNode);
   4.140                  return null;
   4.141              }
   4.142  
   4.143              @Override
   4.144 -            public Node enter(final AccessNode accessNode) {
   4.145 +            public Node enterAccessNode(final AccessNode accessNode) {
   4.146                  if (!baseAlreadyOnStack) {
   4.147                      load(accessNode.getBase()).convert(Type.OBJECT);
   4.148                  }
   4.149 @@ -329,7 +346,7 @@
   4.150              }
   4.151  
   4.152              @Override
   4.153 -            public Node enter(final IndexNode indexNode) {
   4.154 +            public Node enterIndexNode(final IndexNode indexNode) {
   4.155                  if (!baseAlreadyOnStack) {
   4.156                      load(indexNode.getBase()).convert(Type.OBJECT);
   4.157                      load(indexNode.getIndex());
   4.158 @@ -339,6 +356,14 @@
   4.159              }
   4.160  
   4.161              @Override
   4.162 +            public Node enterFunctionNode(FunctionNode functionNode) {
   4.163 +                // function nodes will always leave a constructed function object on stack, no need to load the symbol
   4.164 +                // separately as in enterDefault()
   4.165 +                functionNode.accept(codegen);
   4.166 +                return null;
   4.167 +            }
   4.168 +
   4.169 +            @Override
   4.170              public Node enterDefault(final Node otherNode) {
   4.171                  otherNode.accept(codegen); // generate code for whatever we are looking at.
   4.172                  method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there)
   4.173 @@ -350,7 +375,7 @@
   4.174      }
   4.175  
   4.176      @Override
   4.177 -    public Node enter(final AccessNode accessNode) {
   4.178 +    public Node enterAccessNode(final AccessNode accessNode) {
   4.179          if (accessNode.testResolved()) {
   4.180              return null;
   4.181          }
   4.182 @@ -422,10 +447,11 @@
   4.183      }
   4.184  
   4.185      @Override
   4.186 -    public Node enter(final Block block) {
   4.187 +    public Node enterBlock(final Block block) {
   4.188          if (block.testResolved()) {
   4.189              return null;
   4.190          }
   4.191 +        lexicalContext.push(block);
   4.192  
   4.193          method.label(block.getEntryLabel());
   4.194          initLocals(block);
   4.195 @@ -434,14 +460,14 @@
   4.196      }
   4.197  
   4.198      @Override
   4.199 -    public Node leave(final Block block) {
   4.200 +    public Node leaveBlock(final Block block) {
   4.201          method.label(block.getBreakLabel());
   4.202          symbolInfo(block);
   4.203  
   4.204          if (block.needsScope()) {
   4.205              popBlockScope(block);
   4.206          }
   4.207 -
   4.208 +        lexicalContext.pop(block);
   4.209          return block;
   4.210      }
   4.211  
   4.212 @@ -467,7 +493,7 @@
   4.213      }
   4.214  
   4.215      @Override
   4.216 -    public Node enter(final BreakNode breakNode) {
   4.217 +    public Node enterBreakNode(final BreakNode breakNode) {
   4.218          if (breakNode.testResolved()) {
   4.219              return null;
   4.220          }
   4.221 @@ -515,14 +541,13 @@
   4.222      }
   4.223  
   4.224      @Override
   4.225 -    public Node enter(final CallNode callNode) {
   4.226 +    public Node enterCallNode(final CallNode callNode) {
   4.227          if (callNode.testResolved()) {
   4.228              return null;
   4.229          }
   4.230  
   4.231          final List<Node>   args            = callNode.getArgs();
   4.232          final Node         function        = callNode.getFunction();
   4.233 -        final FunctionNode currentFunction = getCurrentFunctionNode();
   4.234          final Block        currentBlock    = getCurrentBlock();
   4.235  
   4.236          function.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
   4.237 @@ -531,7 +556,7 @@
   4.238                  final Symbol symbol = identNode.getSymbol();
   4.239                  int    scopeCallFlags = flags;
   4.240                  method.loadScope();
   4.241 -                if (symbol.isFastScope(currentFunction)) {
   4.242 +                if (isFastScope(symbol)) {
   4.243                      method.load(getScopeProtoDepth(currentBlock, symbol));
   4.244                      scopeCallFlags |= CALLSITE_FAST_SCOPE;
   4.245                  } else {
   4.246 @@ -593,7 +618,7 @@
   4.247              }
   4.248  
   4.249              @Override
   4.250 -            public Node enter(final IdentNode node) {
   4.251 +            public Node enterIdentNode(final IdentNode node) {
   4.252                  final Symbol symbol = node.getSymbol();
   4.253  
   4.254                  if (symbol.isScope()) {
   4.255 @@ -606,7 +631,7 @@
   4.256                      if (callNode.isEval()) {
   4.257                          evalCall(node, flags);
   4.258                      } else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD
   4.259 -                            || (!symbol.isFastScope(currentFunction) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD)
   4.260 +                            || (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD)
   4.261                              || callNode.inWithBlock()) {
   4.262                          scopeCall(node, flags);
   4.263                      } else {
   4.264 @@ -621,7 +646,7 @@
   4.265              }
   4.266  
   4.267              @Override
   4.268 -            public Node enter(final AccessNode node) {
   4.269 +            public Node enterAccessNode(final AccessNode node) {
   4.270                  load(node.getBase());
   4.271                  method.convert(Type.OBJECT);
   4.272                  method.dup();
   4.273 @@ -634,8 +659,7 @@
   4.274              }
   4.275  
   4.276              @Override
   4.277 -            public Node enter(final ReferenceNode node) {
   4.278 -                final FunctionNode callee   = node.getReference();
   4.279 +            public Node enterFunctionNode(final FunctionNode callee) {
   4.280                  final boolean      isVarArg = callee.isVarArg();
   4.281                  final int          argCount = isVarArg ? -1 : callee.getParameters().size();
   4.282  
   4.283 @@ -653,12 +677,13 @@
   4.284                  loadArgs(args, signature, isVarArg, argCount);
   4.285                  method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature);
   4.286                  assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType();
   4.287 -
   4.288 +                functionNodeIsCallee = true;
   4.289 +                callee.accept(CodeGenerator.this);
   4.290                  return null;
   4.291              }
   4.292  
   4.293              @Override
   4.294 -            public Node enter(final IndexNode node) {
   4.295 +            public Node enterIndexNode(final IndexNode node) {
   4.296                  load(node.getBase());
   4.297                  method.convert(Type.OBJECT);
   4.298                  method.dup();
   4.299 @@ -694,7 +719,7 @@
   4.300      }
   4.301  
   4.302      @Override
   4.303 -    public Node enter(final ContinueNode continueNode) {
   4.304 +    public Node enterContinueNode(final ContinueNode continueNode) {
   4.305          if (continueNode.testResolved()) {
   4.306              return null;
   4.307          }
   4.308 @@ -709,17 +734,17 @@
   4.309      }
   4.310  
   4.311      @Override
   4.312 -    public Node enter(final DoWhileNode doWhileNode) {
   4.313 -        return enter((WhileNode)doWhileNode);
   4.314 +    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
   4.315 +        return enterWhileNode(doWhileNode);
   4.316      }
   4.317  
   4.318      @Override
   4.319 -    public Node enter(final EmptyNode emptyNode) {
   4.320 +    public Node enterEmptyNode(final EmptyNode emptyNode) {
   4.321          return null;
   4.322      }
   4.323  
   4.324      @Override
   4.325 -    public Node enter(final ExecuteNode executeNode) {
   4.326 +    public Node enterExecuteNode(final ExecuteNode executeNode) {
   4.327          if (executeNode.testResolved()) {
   4.328              return null;
   4.329          }
   4.330 @@ -731,7 +756,7 @@
   4.331      }
   4.332  
   4.333      @Override
   4.334 -    public Node enter(final ForNode forNode) {
   4.335 +    public Node enterForNode(final ForNode forNode) {
   4.336          if (forNode.testResolved()) {
   4.337              return null;
   4.338          }
   4.339 @@ -813,7 +838,7 @@
   4.340       * @param block block with local vars.
   4.341       */
   4.342      private void initLocals(final Block block) {
   4.343 -        final FunctionNode function       = block.getFunction();
   4.344 +        final FunctionNode function       = lexicalContext.getFunction(block);
   4.345          final boolean      isFunctionNode = block == function;
   4.346  
   4.347          /*
   4.348 @@ -915,7 +940,7 @@
   4.349              foc.makeObject(method);
   4.350  
   4.351              // runScript(): merge scope into global
   4.352 -            if (isFunctionNode && function.isScript()) {
   4.353 +            if (isFunctionNode && function.isProgram()) {
   4.354                  method.invoke(ScriptRuntime.MERGE_SCOPE);
   4.355              }
   4.356  
   4.357 @@ -958,19 +983,29 @@
   4.358      }
   4.359  
   4.360      @Override
   4.361 -    public Node enter(final FunctionNode functionNode) {
   4.362 +    public Node enterFunctionNode(final FunctionNode functionNode) {
   4.363 +        final boolean isCallee = functionNodeIsCallee;
   4.364 +        functionNodeIsCallee = false;
   4.365 +
   4.366 +        if (functionNode.testResolved()) {
   4.367 +            return null;
   4.368 +        }
   4.369 +
   4.370 +        if(!(isCallee || functionNode == compiler.getFunctionNode())) {
   4.371 +            newFunctionObject(functionNode);
   4.372 +        }
   4.373 +
   4.374          if (functionNode.isLazy()) {
   4.375              return null;
   4.376          }
   4.377  
   4.378 -        if (functionNode.testResolved()) {
   4.379 -            return null;
   4.380 -        }
   4.381 +        LOG.info("=== BEGIN " + functionNode.getName());
   4.382 +        lexicalContext.push(functionNode);
   4.383  
   4.384          setCurrentCompileUnit(functionNode.getCompileUnit());
   4.385          assert getCurrentCompileUnit() != null;
   4.386  
   4.387 -        method = getCurrentCompileUnit().getClassEmitter().method(functionNode);
   4.388 +        setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(functionNode));
   4.389          functionNode.setMethodEmitter(method);
   4.390          // Mark end for variable tables.
   4.391          method.begin();
   4.392 @@ -983,7 +1018,7 @@
   4.393      }
   4.394  
   4.395      @Override
   4.396 -    public Node leave(final FunctionNode functionNode) {
   4.397 +    public Node leaveFunctionNode(final FunctionNode functionNode) {
   4.398          // Mark end for variable tables.
   4.399          method.label(functionNode.getBreakLabel());
   4.400  
   4.401 @@ -1001,16 +1036,18 @@
   4.402              throw e;
   4.403          }
   4.404  
   4.405 +        lexicalContext.pop(functionNode);
   4.406 +        LOG.info("=== END " + functionNode.getName());
   4.407          return functionNode;
   4.408      }
   4.409  
   4.410      @Override
   4.411 -    public Node enter(final IdentNode identNode) {
   4.412 +    public Node enterIdentNode(final IdentNode identNode) {
   4.413          return null;
   4.414      }
   4.415  
   4.416      @Override
   4.417 -    public Node enter(final IfNode ifNode) {
   4.418 +    public Node enterIfNode(final IfNode ifNode) {
   4.419          if (ifNode.testResolved()) {
   4.420              return null;
   4.421          }
   4.422 @@ -1049,7 +1086,7 @@
   4.423      }
   4.424  
   4.425      @Override
   4.426 -    public Node enter(final IndexNode indexNode) {
   4.427 +    public Node enterIndexNode(final IndexNode indexNode) {
   4.428          if (indexNode.testResolved()) {
   4.429              return null;
   4.430          }
   4.431 @@ -1060,7 +1097,7 @@
   4.432      }
   4.433  
   4.434      @Override
   4.435 -    public Node enter(final LineNumberNode lineNumberNode) {
   4.436 +    public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
   4.437          if (lineNumberNode.testResolved()) {
   4.438              return null;
   4.439          }
   4.440 @@ -1068,7 +1105,6 @@
   4.441          final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getCurrentFunctionNode().getName() + ")");
   4.442          method.label(label);
   4.443          method.lineNumber(lineNumberNode.getLineNumber(), label);
   4.444 -
   4.445          return null;
   4.446      }
   4.447  
   4.448 @@ -1106,7 +1142,7 @@
   4.449                      final String name      = getCurrentFunctionNode().uniqueName(SPLIT_PREFIX.tag());
   4.450                      final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type);
   4.451  
   4.452 -                    method = getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature);
   4.453 +                    setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
   4.454                      method.setFunctionNode(getCurrentFunctionNode());
   4.455                      method.begin();
   4.456  
   4.457 @@ -1212,7 +1248,7 @@
   4.458              method.invokestatic(unitClassName, methodName, methodDescriptor(cls, int.class));
   4.459              classEmitter.needGetConstantMethod(cls);
   4.460          } else {
   4.461 -            method.loadConstants(unitClassName).load(index).arrayload();
   4.462 +            method.loadConstants().load(index).arrayload();
   4.463              if (cls != Object.class) {
   4.464                  method.checkcast(cls);
   4.465              }
   4.466 @@ -1292,14 +1328,14 @@
   4.467  
   4.468      @SuppressWarnings("rawtypes")
   4.469      @Override
   4.470 -    public Node enter(final LiteralNode literalNode) {
   4.471 +    public Node enterLiteralNode(final LiteralNode literalNode) {
   4.472          assert literalNode.getSymbol() != null : literalNode + " has no symbol";
   4.473          load(literalNode).store(literalNode.getSymbol());
   4.474          return null;
   4.475      }
   4.476  
   4.477      @Override
   4.478 -    public Node enter(final ObjectNode objectNode) {
   4.479 +    public Node enterObjectNode(final ObjectNode objectNode) {
   4.480          if (objectNode.testResolved()) {
   4.481              return null;
   4.482          }
   4.483 @@ -1372,10 +1408,10 @@
   4.484          }
   4.485  
   4.486          for (final Node element : elements) {
   4.487 -            final PropertyNode  propertyNode = (PropertyNode)element;
   4.488 -            final Object        key          = propertyNode.getKey();
   4.489 -            final ReferenceNode getter       = (ReferenceNode)propertyNode.getGetter();
   4.490 -            final ReferenceNode setter       = (ReferenceNode)propertyNode.getSetter();
   4.491 +            final PropertyNode propertyNode = (PropertyNode)element;
   4.492 +            final Object       key          = propertyNode.getKey();
   4.493 +            final FunctionNode getter       = (FunctionNode)propertyNode.getGetter();
   4.494 +            final FunctionNode setter       = (FunctionNode)propertyNode.getSetter();
   4.495  
   4.496              if (getter == null && setter == null) {
   4.497                  continue;
   4.498 @@ -1404,18 +1440,7 @@
   4.499      }
   4.500  
   4.501      @Override
   4.502 -    public Node enter(final ReferenceNode referenceNode) {
   4.503 -        if (referenceNode.testResolved()) {
   4.504 -            return null;
   4.505 -        }
   4.506 -
   4.507 -        newFunctionObject(referenceNode.getReference());
   4.508 -
   4.509 -        return null;
   4.510 -    }
   4.511 -
   4.512 -    @Override
   4.513 -    public Node enter(final ReturnNode returnNode) {
   4.514 +    public Node enterReturnNode(final ReturnNode returnNode) {
   4.515          if (returnNode.testResolved()) {
   4.516              return null;
   4.517          }
   4.518 @@ -1556,7 +1581,7 @@
   4.519      }
   4.520  
   4.521      @Override
   4.522 -    public Node enter(final RuntimeNode runtimeNode) {
   4.523 +    public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
   4.524          if (runtimeNode.testResolved()) {
   4.525              return null;
   4.526          }
   4.527 @@ -1637,7 +1662,7 @@
   4.528      }
   4.529  
   4.530      @Override
   4.531 -    public Node enter(final SplitNode splitNode) {
   4.532 +    public Node enterSplitNode(final SplitNode splitNode) {
   4.533          if (splitNode.testResolved()) {
   4.534              return null;
   4.535          }
   4.536 @@ -1706,7 +1731,7 @@
   4.537      }
   4.538  
   4.539      @Override
   4.540 -    public Node leave(final SplitNode splitNode) {
   4.541 +    public Node leaveSplitNode(final SplitNode splitNode) {
   4.542          try {
   4.543              // Wrap up this method.
   4.544              method.loadResult();
   4.545 @@ -1763,7 +1788,7 @@
   4.546      }
   4.547  
   4.548      @Override
   4.549 -    public Node enter(final SwitchNode switchNode) {
   4.550 +    public Node enterSwitchNode(final SwitchNode switchNode) {
   4.551          if (switchNode.testResolved()) {
   4.552              return null;
   4.553          }
   4.554 @@ -1895,7 +1920,7 @@
   4.555      }
   4.556  
   4.557      @Override
   4.558 -    public Node enter(final ThrowNode throwNode) {
   4.559 +    public Node enterThrowNode(final ThrowNode throwNode) {
   4.560          if (throwNode.testResolved()) {
   4.561              return null;
   4.562          }
   4.563 @@ -1922,7 +1947,7 @@
   4.564      }
   4.565  
   4.566      @Override
   4.567 -    public Node enter(final TryNode tryNode) {
   4.568 +    public Node enterTryNode(final TryNode tryNode) {
   4.569          if (tryNode.testResolved()) {
   4.570              return null;
   4.571          }
   4.572 @@ -1955,7 +1980,7 @@
   4.573              setCurrentBlock(catchBlock);
   4.574  
   4.575              try {
   4.576 -                enter(catchBlock);
   4.577 +                enterBlock(catchBlock);
   4.578  
   4.579                  final CatchNode catchNode          = (CatchNode)catchBlocks.get(i).getStatements().get(0);
   4.580                  final IdentNode exception          = catchNode.getException();
   4.581 @@ -1966,6 +1991,7 @@
   4.582                      // Generate catch body (inlined finally) and rethrow exception
   4.583                      catchBody.accept(this);
   4.584                      method.load(symbol).athrow();
   4.585 +                    lexicalContext.pop(catchBlock);
   4.586                      continue;
   4.587                  }
   4.588  
   4.589 @@ -2012,7 +2038,7 @@
   4.590                      }
   4.591                  }
   4.592  
   4.593 -                leave(catchBlock);
   4.594 +                leaveBlock(catchBlock);
   4.595              } finally {
   4.596                  setCurrentBlock(saveBlock);
   4.597              }
   4.598 @@ -2027,7 +2053,7 @@
   4.599      }
   4.600  
   4.601      @Override
   4.602 -    public Node enter(final VarNode varNode) {
   4.603 +    public Node enterVarNode(final VarNode varNode) {
   4.604          final Node init = varNode.getInit();
   4.605  
   4.606          if (varNode.testResolved() || init == null) {
   4.607 @@ -2049,7 +2075,7 @@
   4.608              int flags = CALLSITE_SCOPE | getCallSiteFlags();
   4.609              final IdentNode identNode = varNode.getName();
   4.610              final Type type = identNode.getType();
   4.611 -            if (varSymbol.isFastScope(getCurrentFunctionNode())) {
   4.612 +            if (isFastScope(varSymbol)) {
   4.613                  storeFastScopeVar(type, varSymbol, flags);
   4.614              } else {
   4.615                  method.dynamicSet(type, identNode.getName(), flags);
   4.616 @@ -2065,7 +2091,7 @@
   4.617      }
   4.618  
   4.619      @Override
   4.620 -    public Node enter(final WhileNode whileNode) {
   4.621 +    public Node enterWhileNode(final WhileNode whileNode) {
   4.622          if (whileNode.testResolved()) {
   4.623              return null;
   4.624          }
   4.625 @@ -2098,7 +2124,7 @@
   4.626      }
   4.627  
   4.628      @Override
   4.629 -    public Node enter(final WithNode withNode) {
   4.630 +    public Node enterWithNode(final WithNode withNode) {
   4.631          if (withNode.testResolved()) {
   4.632              return null;
   4.633          }
   4.634 @@ -2864,7 +2890,7 @@
   4.635       * Ternary visits.
   4.636       */
   4.637      @Override
   4.638 -    public Node enter(final TernaryNode ternaryNode) {
   4.639 +    public Node enterTernaryNode(final TernaryNode ternaryNode) {
   4.640          if (ternaryNode.testResolved()) {
   4.641              return null;
   4.642          }
   4.643 @@ -3060,7 +3086,7 @@
   4.644  
   4.645              target.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
   4.646                  @Override
   4.647 -                public Node enter(final IdentNode node) {
   4.648 +                public Node enterIdentNode(final IdentNode node) {
   4.649                      if (targetSymbol.isScope()) {
   4.650                          method.load(scopeSymbol);
   4.651                          depth++;
   4.652 @@ -3083,13 +3109,13 @@
   4.653                  }
   4.654  
   4.655                  @Override
   4.656 -                public Node enter(final AccessNode node) {
   4.657 +                public Node enterAccessNode(final AccessNode node) {
   4.658                      enterBaseNode();
   4.659                      return null;
   4.660                  }
   4.661  
   4.662                  @Override
   4.663 -                public Node enter(final IndexNode node) {
   4.664 +                public Node enterIndexNode(final IndexNode node) {
   4.665                      enterBaseNode();
   4.666  
   4.667                      final Node index = node.getIndex();
   4.668 @@ -3155,8 +3181,6 @@
   4.669          }
   4.670  
   4.671          private void epilogue() {
   4.672 -            final FunctionNode currentFunction = getCurrentFunctionNode();
   4.673 -
   4.674              /**
   4.675               * Take the original target args from the stack and use them
   4.676               * together with the value to be stored to emit the store code
   4.677 @@ -3174,7 +3198,7 @@
   4.678                  }
   4.679  
   4.680                  @Override
   4.681 -                public Node enter(final UnaryNode node) {
   4.682 +                public Node enterUnaryNode(final UnaryNode node) {
   4.683                      if(node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) {
   4.684                          method.convert(node.rhs().getType());
   4.685                      }
   4.686 @@ -3182,11 +3206,11 @@
   4.687                  }
   4.688  
   4.689                  @Override
   4.690 -                public Node enter(final IdentNode node) {
   4.691 +                public Node enterIdentNode(final IdentNode node) {
   4.692                      final Symbol symbol = node.getSymbol();
   4.693                      assert symbol != null;
   4.694                      if (symbol.isScope()) {
   4.695 -                        if (symbol.isFastScope(currentFunction)) {
   4.696 +                        if (isFastScope(symbol)) {
   4.697                              storeFastScopeVar(node.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags());
   4.698                          } else {
   4.699                              method.dynamicSet(node.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags());
   4.700 @@ -3199,13 +3223,13 @@
   4.701                  }
   4.702  
   4.703                  @Override
   4.704 -                public Node enter(final AccessNode node) {
   4.705 +                public Node enterAccessNode(final AccessNode node) {
   4.706                      method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags());
   4.707                      return null;
   4.708                  }
   4.709  
   4.710                  @Override
   4.711 -                public Node enter(final IndexNode node) {
   4.712 +                public Node enterIndexNode(final IndexNode node) {
   4.713                      method.dynamicSetIndex(getCallSiteFlags());
   4.714                      return null;
   4.715                  }
     5.1 --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Tue Mar 19 11:03:24 2013 -0300
     5.2 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Sat Mar 23 00:58:39 2013 +0100
     5.3 @@ -14,16 +14,16 @@
     5.4  import java.util.EnumSet;
     5.5  import java.util.HashSet;
     5.6  import java.util.Set;
     5.7 -
     5.8  import jdk.nashorn.internal.codegen.types.Type;
     5.9  import jdk.nashorn.internal.ir.CallNode;
    5.10  import jdk.nashorn.internal.ir.FunctionNode;
    5.11  import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    5.12 +import jdk.nashorn.internal.ir.LexicalContext;
    5.13  import jdk.nashorn.internal.ir.Node;
    5.14 -import jdk.nashorn.internal.ir.ReferenceNode;
    5.15 -import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    5.16  import jdk.nashorn.internal.ir.debug.ASTWriter;
    5.17  import jdk.nashorn.internal.ir.debug.PrintVisitor;
    5.18 +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
    5.19 +import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    5.20  import jdk.nashorn.internal.runtime.ECMAErrors;
    5.21  import jdk.nashorn.internal.runtime.ScriptEnvironment;
    5.22  import jdk.nashorn.internal.runtime.Timing;
    5.23 @@ -65,17 +65,17 @@
    5.24              outermostFunctionNode.accept(new NodeVisitor() {
    5.25                  // self references are done with invokestatic and thus cannot have trampolines - never lazy
    5.26                  @Override
    5.27 -                public Node enter(final CallNode node) {
    5.28 +                public Node enterCallNode(final CallNode node) {
    5.29                      final Node callee = node.getFunction();
    5.30 -                    if (callee instanceof ReferenceNode) {
    5.31 -                        neverLazy.add(((ReferenceNode)callee).getReference());
    5.32 +                    if (callee instanceof FunctionNode) {
    5.33 +                        neverLazy.add(((FunctionNode)callee));
    5.34                          return null;
    5.35                      }
    5.36                      return node;
    5.37                  }
    5.38  
    5.39                  @Override
    5.40 -                public Node enter(final FunctionNode node) {
    5.41 +                public Node enterFunctionNode(final FunctionNode node) {
    5.42                      if (node == outermostFunctionNode) {
    5.43                          return node;
    5.44                      }
    5.45 @@ -94,15 +94,24 @@
    5.46                  lazy.remove(node);
    5.47              }
    5.48  
    5.49 -            for (final FunctionNode node : lazy) {
    5.50 -                Compiler.LOG.fine("Marking " + node.getName() + " as lazy");
    5.51 -                node.setIsLazy(true);
    5.52 -                final FunctionNode parent = node.findParentFunction();
    5.53 -                if (parent != null) {
    5.54 -                    Compiler.LOG.fine("Marking " + parent.getName() + " as having lazy children - it needs scope for all variables");
    5.55 -                    parent.setHasLazyChildren();
    5.56 +            outermostFunctionNode.accept(new NodeOperatorVisitor() {
    5.57 +                private final LexicalContext lexicalContext = new LexicalContext();
    5.58 +                @Override
    5.59 +                public Node enterFunctionNode(FunctionNode functionNode) {
    5.60 +                    lexicalContext.push(functionNode);
    5.61 +                    if(lazy.contains(functionNode)) {
    5.62 +                        Compiler.LOG.fine("Marking " + functionNode.getName() + " as lazy");
    5.63 +                        functionNode.setIsLazy(true);
    5.64 +                        lexicalContext.getParentFunction(functionNode).setHasLazyChildren();
    5.65 +                    }
    5.66 +                    return functionNode;
    5.67                  }
    5.68 -            }
    5.69 +                @Override
    5.70 +                public Node leaveFunctionNode(FunctionNode functionNode) {
    5.71 +                    lexicalContext.pop(functionNode);
    5.72 +                    return functionNode;
    5.73 +                }
    5.74 +            });
    5.75          }
    5.76  
    5.77          @Override
    5.78 @@ -241,6 +250,16 @@
    5.79                  final CodeGenerator codegen = new CodeGenerator(compiler);
    5.80                  fn.accept(codegen);
    5.81                  codegen.generateScopeCalls();
    5.82 +                fn.accept(new NodeOperatorVisitor() {
    5.83 +                    @Override
    5.84 +                    public Node enterFunctionNode(FunctionNode functionNode) {
    5.85 +                        if(functionNode.isLazy()) {
    5.86 +                            functionNode.resetResolved();
    5.87 +                            return null;
    5.88 +                        }
    5.89 +                        return fn;
    5.90 +                    }
    5.91 +                });
    5.92  
    5.93              } catch (final VerifyError e) {
    5.94                  if (env._verify_code || env._print_code) {
     6.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java	Tue Mar 19 11:03:24 2013 -0300
     6.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Sat Mar 23 00:58:39 2013 +0100
     6.3 @@ -46,7 +46,6 @@
     6.4  import java.util.Map.Entry;
     6.5  import java.util.Set;
     6.6  import java.util.logging.Level;
     6.7 -
     6.8  import jdk.internal.dynalink.support.NameCodec;
     6.9  import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
    6.10  import jdk.nashorn.internal.codegen.types.Type;
    6.11 @@ -383,7 +382,7 @@
    6.12  
    6.13          functionNode.accept(new NodeVisitor() {
    6.14              @Override
    6.15 -            public Node enter(final FunctionNode node) {
    6.16 +            public Node enterFunctionNode(final FunctionNode node) {
    6.17                  if (node.isLazy()) {
    6.18                      return null;
    6.19                  }
     7.1 --- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Tue Mar 19 11:03:24 2013 -0300
     7.2 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Sat Mar 23 00:58:39 2013 +0100
     7.3 @@ -34,20 +34,20 @@
     7.4  import jdk.nashorn.internal.ir.Block;
     7.5  import jdk.nashorn.internal.ir.CallNode;
     7.6  import jdk.nashorn.internal.ir.CallNode.EvalArgs;
     7.7 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
     7.8  import jdk.nashorn.internal.ir.CaseNode;
     7.9  import jdk.nashorn.internal.ir.CatchNode;
    7.10  import jdk.nashorn.internal.ir.DoWhileNode;
    7.11  import jdk.nashorn.internal.ir.ExecuteNode;
    7.12  import jdk.nashorn.internal.ir.ForNode;
    7.13  import jdk.nashorn.internal.ir.FunctionNode;
    7.14 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    7.15  import jdk.nashorn.internal.ir.IdentNode;
    7.16  import jdk.nashorn.internal.ir.IfNode;
    7.17  import jdk.nashorn.internal.ir.IndexNode;
    7.18 +import jdk.nashorn.internal.ir.LexicalContext;
    7.19  import jdk.nashorn.internal.ir.LiteralNode;
    7.20  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
    7.21  import jdk.nashorn.internal.ir.Node;
    7.22 -import jdk.nashorn.internal.ir.ReferenceNode;
    7.23  import jdk.nashorn.internal.ir.ReturnNode;
    7.24  import jdk.nashorn.internal.ir.RuntimeNode;
    7.25  import jdk.nashorn.internal.ir.RuntimeNode.Request;
    7.26 @@ -85,11 +85,13 @@
    7.27  
    7.28      private static final DebugLogger LOG = new DebugLogger("finalize");
    7.29  
    7.30 +    private final LexicalContext lexicalContext = new LexicalContext();
    7.31 +
    7.32      FinalizeTypes() {
    7.33      }
    7.34  
    7.35      @Override
    7.36 -    public Node leave(final CallNode callNode) {
    7.37 +    public Node leaveCallNode(final CallNode callNode) {
    7.38          final EvalArgs evalArgs = callNode.getEvalArgs();
    7.39          if (evalArgs != null) {
    7.40              evalArgs.setCode(evalArgs.getCode().accept(this));
    7.41 @@ -97,15 +99,14 @@
    7.42  
    7.43          // AccessSpecializer - call return type may change the access for this location
    7.44          final Node function = callNode.getFunction();
    7.45 -        if (function instanceof ReferenceNode) {
    7.46 -            setTypeOverride(callNode, ((ReferenceNode)function).getReference().getType());
    7.47 +        if (function instanceof FunctionNode) {
    7.48 +            return setTypeOverride(callNode, ((FunctionNode)function).getReturnType());
    7.49          }
    7.50          return callNode;
    7.51      }
    7.52  
    7.53      private Node leaveUnary(final UnaryNode unaryNode) {
    7.54 -        unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType()));
    7.55 -        return unaryNode;
    7.56 +        return unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType()));
    7.57      }
    7.58  
    7.59      @Override
    7.60 @@ -126,8 +127,7 @@
    7.61  
    7.62      @Override
    7.63      public Node leaveDECINC(final UnaryNode unaryNode) {
    7.64 -        specialize(unaryNode);
    7.65 -        return unaryNode;
    7.66 +        return specialize(unaryNode).node;
    7.67      }
    7.68  
    7.69      @Override
    7.70 @@ -159,9 +159,7 @@
    7.71              }
    7.72          }
    7.73  
    7.74 -        binaryNode.setLHS(convert(lhs, type));
    7.75 -        binaryNode.setRHS(convert(rhs, type));
    7.76 -        return binaryNode;
    7.77 +        return binaryNode.setLHS(convert(lhs, type)).setRHS(convert(rhs, type));
    7.78      }
    7.79  
    7.80      @Override
    7.81 @@ -171,12 +169,13 @@
    7.82  
    7.83      @Override
    7.84      public Node leaveASSIGN(final BinaryNode binaryNode) {
    7.85 -        Type destType = specialize(binaryNode);
    7.86 +        final SpecializedNode specialized = specialize(binaryNode);
    7.87 +        final BinaryNode specBinaryNode = (BinaryNode)specialized.node;
    7.88 +        Type destType = specialized.type;
    7.89          if (destType == null) {
    7.90 -            destType = binaryNode.getType();
    7.91 +            destType = specBinaryNode.getType();
    7.92          }
    7.93 -        binaryNode.setRHS(convert(binaryNode.rhs(), destType));
    7.94 -        return binaryNode;
    7.95 +        return specBinaryNode.setRHS(convert(specBinaryNode.rhs(), destType));
    7.96      }
    7.97  
    7.98      @Override
    7.99 @@ -255,21 +254,21 @@
   7.100      @Override
   7.101      public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
   7.102          assert binaryNode.getSymbol() != null;
   7.103 -        binaryNode.setRHS(discard(binaryNode.rhs()));
   7.104 +        final BinaryNode newBinaryNode = (BinaryNode)binaryNode.setRHS(discard(binaryNode.rhs()));
   7.105          // AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed
   7.106          // in that case, update the node type as well
   7.107 -        propagateType(binaryNode, binaryNode.lhs().getType());
   7.108 -        return binaryNode;
   7.109 +        propagateType(newBinaryNode, newBinaryNode.lhs().getType());
   7.110 +        return newBinaryNode;
   7.111      }
   7.112  
   7.113      @Override
   7.114      public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
   7.115          assert binaryNode.getSymbol() != null;
   7.116 -        binaryNode.setLHS(discard(binaryNode.lhs()));
   7.117 +        final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs()));
   7.118          // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed
   7.119          // in that case, update the node type as well
   7.120 -        propagateType(binaryNode, binaryNode.rhs().getType());
   7.121 -        return binaryNode;
   7.122 +        propagateType(newBinaryNode, newBinaryNode.rhs().getType());
   7.123 +        return newBinaryNode;
   7.124      }
   7.125  
   7.126      @Override
   7.127 @@ -355,13 +354,20 @@
   7.128      }
   7.129  
   7.130      @Override
   7.131 -    public Node enter(final Block block) {
   7.132 +    public Node enterBlock(final Block block) {
   7.133 +        lexicalContext.push(block);
   7.134          updateSymbols(block);
   7.135          return block;
   7.136      }
   7.137  
   7.138      @Override
   7.139 -    public Node leave(final CatchNode catchNode) {
   7.140 +    public Node leaveBlock(Block block) {
   7.141 +        lexicalContext.pop(block);
   7.142 +        return super.leaveBlock(block);
   7.143 +    }
   7.144 +
   7.145 +    @Override
   7.146 +    public Node leaveCatchNode(final CatchNode catchNode) {
   7.147          final Node exceptionCondition = catchNode.getExceptionCondition();
   7.148          if (exceptionCondition != null) {
   7.149              catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
   7.150 @@ -370,23 +376,23 @@
   7.151      }
   7.152  
   7.153      @Override
   7.154 -    public Node enter(final DoWhileNode doWhileNode) {
   7.155 -        return enter((WhileNode)doWhileNode);
   7.156 +    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
   7.157 +        return enterWhileNode(doWhileNode);
   7.158      }
   7.159  
   7.160      @Override
   7.161 -    public Node leave(final DoWhileNode doWhileNode) {
   7.162 -        return leave((WhileNode)doWhileNode);
   7.163 +    public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
   7.164 +        return leaveWhileNode(doWhileNode);
   7.165      }
   7.166  
   7.167      @Override
   7.168 -    public Node leave(final ExecuteNode executeNode) {
   7.169 +    public Node leaveExecuteNode(final ExecuteNode executeNode) {
   7.170          executeNode.setExpression(discard(executeNode.getExpression()));
   7.171          return executeNode;
   7.172      }
   7.173  
   7.174      @Override
   7.175 -    public Node leave(final ForNode forNode) {
   7.176 +    public Node leaveForNode(final ForNode forNode) {
   7.177          final Node init   = forNode.getInit();
   7.178          final Node test   = forNode.getTest();
   7.179          final Node modify = forNode.getModify();
   7.180 @@ -414,11 +420,12 @@
   7.181      }
   7.182  
   7.183      @Override
   7.184 -    public Node enter(final FunctionNode functionNode) {
   7.185 +    public Node enterFunctionNode(final FunctionNode functionNode) {
   7.186          if (functionNode.isLazy()) {
   7.187              return null;
   7.188          }
   7.189  
   7.190 +        lexicalContext.push(functionNode);
   7.191          // If the function doesn't need a callee, we ensure its __callee__ symbol doesn't get a slot. We can't do
   7.192          // this earlier, as access to scoped variables, self symbol, etc. in previous phases can all trigger the
   7.193          // need for the callee.
   7.194 @@ -439,14 +446,20 @@
   7.195      }
   7.196  
   7.197      @Override
   7.198 -    public Node leave(final IfNode ifNode) {
   7.199 +    public Node leaveFunctionNode(FunctionNode functionNode) {
   7.200 +        lexicalContext.pop(functionNode);
   7.201 +        return super.leaveFunctionNode(functionNode);
   7.202 +    }
   7.203 +
   7.204 +    @Override
   7.205 +    public Node leaveIfNode(final IfNode ifNode) {
   7.206          ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN));
   7.207          return ifNode;
   7.208      }
   7.209  
   7.210      @SuppressWarnings("rawtypes")
   7.211      @Override
   7.212 -    public Node enter(final LiteralNode literalNode) {
   7.213 +    public Node enterLiteralNode(final LiteralNode literalNode) {
   7.214          if (literalNode instanceof ArrayLiteralNode) {
   7.215              final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
   7.216              final Node[]           array            = arrayLiteralNode.getValue();
   7.217 @@ -464,7 +477,7 @@
   7.218      }
   7.219  
   7.220      @Override
   7.221 -    public Node leave(final ReturnNode returnNode) {
   7.222 +    public Node leaveReturnNode(final ReturnNode returnNode) {
   7.223          final Node expr = returnNode.getExpression();
   7.224          if (expr != null) {
   7.225              returnNode.setExpression(convert(expr, getCurrentFunctionNode().getReturnType()));
   7.226 @@ -473,7 +486,7 @@
   7.227      }
   7.228  
   7.229      @Override
   7.230 -    public Node leave(final RuntimeNode runtimeNode) {
   7.231 +    public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
   7.232          final List<Node> args = runtimeNode.getArgs();
   7.233          for (final Node arg : args) {
   7.234              assert !arg.getType().isUnknown();
   7.235 @@ -482,7 +495,7 @@
   7.236      }
   7.237  
   7.238      @Override
   7.239 -    public Node leave(final SwitchNode switchNode) {
   7.240 +    public Node leaveSwitchNode(final SwitchNode switchNode) {
   7.241          final Node           expression  = switchNode.getExpression();
   7.242          final List<CaseNode> cases       = switchNode.getCases();
   7.243          final boolean        allInteger  = switchNode.getTag().getSymbolType().isInteger();
   7.244 @@ -501,33 +514,34 @@
   7.245      }
   7.246  
   7.247      @Override
   7.248 -    public Node leave(final TernaryNode ternaryNode) {
   7.249 -        ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN));
   7.250 -        return ternaryNode;
   7.251 +    public Node leaveTernaryNode(final TernaryNode ternaryNode) {
   7.252 +        return ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN));
   7.253      }
   7.254  
   7.255      @Override
   7.256 -    public Node leave(final ThrowNode throwNode) {
   7.257 +    public Node leaveThrowNode(final ThrowNode throwNode) {
   7.258          throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT));
   7.259          return throwNode;
   7.260      }
   7.261  
   7.262      @Override
   7.263 -    public Node leave(final VarNode varNode) {
   7.264 +    public Node leaveVarNode(final VarNode varNode) {
   7.265          final Node rhs = varNode.getInit();
   7.266          if (rhs != null) {
   7.267 -            Type destType = specialize(varNode);
   7.268 +            final SpecializedNode specialized = specialize(varNode);
   7.269 +            final VarNode specVarNode = (VarNode)specialized.node;
   7.270 +            Type destType = specialized.type;
   7.271              if (destType == null) {
   7.272 -                destType = varNode.getType();
   7.273 +                destType = specVarNode.getType();
   7.274              }
   7.275 -            assert varNode.hasType() : varNode + " doesn't have a type";
   7.276 -            varNode.setInit(convert(rhs, destType));
   7.277 +            assert specVarNode.hasType() : specVarNode + " doesn't have a type";
   7.278 +            return specVarNode.setInit(convert(rhs, destType));
   7.279          }
   7.280          return varNode;
   7.281      }
   7.282  
   7.283      @Override
   7.284 -    public Node leave(final WhileNode whileNode) {
   7.285 +    public Node leaveWhileNode(final WhileNode whileNode) {
   7.286          final Node test = whileNode.getTest();
   7.287          if (test != null) {
   7.288              whileNode.setTest(convert(test, Type.BOOLEAN));
   7.289 @@ -536,7 +550,7 @@
   7.290      }
   7.291  
   7.292      @Override
   7.293 -    public Node leave(final WithNode withNode) {
   7.294 +    public Node leaveWithNode(final WithNode withNode) {
   7.295          withNode.setExpression(convert(withNode.getExpression(), Type.OBJECT));
   7.296          return withNode;
   7.297      }
   7.298 @@ -555,14 +569,14 @@
   7.299       * that scope and slot information is correct for every symbol
   7.300       * @param block block for which to to finalize type info.
   7.301       */
   7.302 -    private static void updateSymbols(final Block block) {
   7.303 +    private void updateSymbols(final Block block) {
   7.304          if (!block.needsScope()) {
   7.305              return; // nothing to do
   7.306          }
   7.307  
   7.308 -        assert !(block instanceof FunctionNode) || block.getFunction() == block;
   7.309 +        final FunctionNode functionNode = lexicalContext.getFunction(block);
   7.310 +        assert !(block instanceof FunctionNode) || functionNode == block;
   7.311  
   7.312 -        final FunctionNode functionNode   = block.getFunction();
   7.313          final List<Symbol> symbols        = block.getFrame().getSymbols();
   7.314          final boolean      allVarsInScope = functionNode.allVarsInScope();
   7.315          final boolean      isVarArg       = functionNode.isVarArg();
   7.316 @@ -631,10 +645,7 @@
   7.317              break;
   7.318          }
   7.319  
   7.320 -        binaryNode.setLHS(convert(lhs, widest));
   7.321 -        binaryNode.setRHS(convert(rhs, widest));
   7.322 -
   7.323 -        return binaryNode;
   7.324 +        return binaryNode.setLHS(convert(lhs, widest)).setRHS(convert(rhs, widest));
   7.325      }
   7.326  
   7.327      /**
   7.328 @@ -656,9 +667,7 @@
   7.329      }
   7.330  
   7.331      private Node leaveBinary(final BinaryNode binaryNode, final Type lhsType, final Type rhsType) {
   7.332 -        binaryNode.setLHS(convert(binaryNode.lhs(), lhsType));
   7.333 -        binaryNode.setRHS(convert(binaryNode.rhs(), rhsType));
   7.334 -        return binaryNode;
   7.335 +        return binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType));
   7.336      }
   7.337  
   7.338      /**
   7.339 @@ -679,7 +688,7 @@
   7.340              }
   7.341  
   7.342              @Override
   7.343 -            public Node enter(final IdentNode identNode) {
   7.344 +            public Node enterIdentNode(final IdentNode identNode) {
   7.345                  if (!exclude.contains(identNode)) {
   7.346                      setCanBePrimitive(identNode.getSymbol());
   7.347                  }
   7.348 @@ -687,26 +696,36 @@
   7.349              }
   7.350  
   7.351              @Override
   7.352 -            public Node enter(final AccessNode accessNode) {
   7.353 +            public Node enterAccessNode(final AccessNode accessNode) {
   7.354                  setCanBePrimitive(accessNode.getProperty().getSymbol());
   7.355                  return null;
   7.356              }
   7.357  
   7.358              @Override
   7.359 -            public Node enter(final IndexNode indexNode) {
   7.360 +            public Node enterIndexNode(final IndexNode indexNode) {
   7.361                  exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine
   7.362                  return indexNode;
   7.363              }
   7.364          });
   7.365      }
   7.366  
   7.367 -    private static Type specialize(final Assignment<?> assignment) {
   7.368 +    private static class SpecializedNode {
   7.369 +        final Node node;
   7.370 +        final Type type;
   7.371 +
   7.372 +        SpecializedNode(Node node, Type type) {
   7.373 +            this.node = node;
   7.374 +            this.type = type;
   7.375 +        }
   7.376 +    }
   7.377 +
   7.378 +    private static <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) {
   7.379          final Node node = ((Node)assignment);
   7.380 -        final Node lhs = assignment.getAssignmentDest();
   7.381 +        final T lhs = assignment.getAssignmentDest();
   7.382          final Node rhs = assignment.getAssignmentSource();
   7.383  
   7.384          if (!canHaveCallSiteType(lhs)) {
   7.385 -            return null;
   7.386 +            return new SpecializedNode(node, null);
   7.387          }
   7.388  
   7.389          final Type to;
   7.390 @@ -718,13 +737,13 @@
   7.391  
   7.392          if (!isSupportedCallSiteType(to)) {
   7.393              //meaningless to specialize to boolean or object
   7.394 -            return null;
   7.395 +            return new SpecializedNode(node, null);
   7.396          }
   7.397  
   7.398 -        setTypeOverride(lhs, to);
   7.399 -        propagateType(node, to);
   7.400 +        final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to));
   7.401 +        propagateType(newNode, to);
   7.402  
   7.403 -        return to;
   7.404 +        return new SpecializedNode(newNode, to);
   7.405      }
   7.406  
   7.407  
   7.408 @@ -736,7 +755,7 @@
   7.409       * @return true if node can have a callsite type
   7.410       */
   7.411      private static boolean canHaveCallSiteType(final Node node) {
   7.412 -        return node instanceof TypeOverride && ((TypeOverride)node).canHaveCallSiteType();
   7.413 +        return node instanceof TypeOverride && ((TypeOverride<?>)node).canHaveCallSiteType();
   7.414      }
   7.415  
   7.416      /**
   7.417 @@ -762,7 +781,8 @@
   7.418       * @param node    node for which to change type
   7.419       * @param to      new type
   7.420       */
   7.421 -    private static void setTypeOverride(final Node node, final Type to) {
   7.422 +    @SuppressWarnings("unchecked")
   7.423 +    private static <T extends Node> T setTypeOverride(final T node, final Type to) {
   7.424          final Type from = node.getType();
   7.425          if (!node.getType().equals(to)) {
   7.426              LOG.info("Changing call override type for '" + node + "' from " + node.getType() + " to " + to);
   7.427 @@ -771,7 +791,7 @@
   7.428              }
   7.429          }
   7.430          LOG.info("Type override for lhs in '" + node + "' => " + to);
   7.431 -        ((TypeOverride)node).setType(to);
   7.432 +        return ((TypeOverride<T>)node).setType(to);
   7.433      }
   7.434  
   7.435      /**
   7.436 @@ -816,8 +836,8 @@
   7.437              }
   7.438          } else {
   7.439              if (canHaveCallSiteType(node) && isSupportedCallSiteType(to)) {
   7.440 -                setTypeOverride(node, to);
   7.441 -                return resultNode;
   7.442 +                assert node instanceof TypeOverride;
   7.443 +                return setTypeOverride(node, to);
   7.444              }
   7.445              resultNode = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.CONVERT), node);
   7.446          }
     8.1 --- a/src/jdk/nashorn/internal/codegen/FoldConstants.java	Tue Mar 19 11:03:24 2013 -0300
     8.2 +++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java	Sat Mar 23 00:58:39 2013 +0100
     8.3 @@ -31,12 +31,12 @@
     8.4  import jdk.nashorn.internal.ir.EmptyNode;
     8.5  import jdk.nashorn.internal.ir.ExecuteNode;
     8.6  import jdk.nashorn.internal.ir.FunctionNode;
     8.7 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
     8.8  import jdk.nashorn.internal.ir.IfNode;
     8.9  import jdk.nashorn.internal.ir.LiteralNode;
    8.10  import jdk.nashorn.internal.ir.Node;
    8.11  import jdk.nashorn.internal.ir.TernaryNode;
    8.12  import jdk.nashorn.internal.ir.UnaryNode;
    8.13 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    8.14  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    8.15  import jdk.nashorn.internal.runtime.DebugLogger;
    8.16  import jdk.nashorn.internal.runtime.JSType;
    8.17 @@ -54,7 +54,7 @@
    8.18      }
    8.19  
    8.20      @Override
    8.21 -    public Node leave(final UnaryNode unaryNode) {
    8.22 +    public Node leaveUnaryNode(final UnaryNode unaryNode) {
    8.23          final LiteralNode<?> literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval();
    8.24          if (literalNode != null) {
    8.25              LOG.info("Unary constant folded " + unaryNode + " to " + literalNode);
    8.26 @@ -64,7 +64,7 @@
    8.27      }
    8.28  
    8.29      @Override
    8.30 -    public Node leave(final BinaryNode binaryNode) {
    8.31 +    public Node leaveBinaryNode(final BinaryNode binaryNode) {
    8.32          final LiteralNode<?> literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval();
    8.33          if (literalNode != null) {
    8.34              LOG.info("Binary constant folded " + binaryNode + " to " + literalNode);
    8.35 @@ -74,7 +74,7 @@
    8.36      }
    8.37  
    8.38      @Override
    8.39 -    public Node enter(final FunctionNode functionNode) {
    8.40 +    public Node enterFunctionNode(final FunctionNode functionNode) {
    8.41          if (functionNode.isLazy()) {
    8.42              return null;
    8.43          }
    8.44 @@ -82,13 +82,13 @@
    8.45      }
    8.46  
    8.47      @Override
    8.48 -    public Node leave(final FunctionNode functionNode) {
    8.49 +    public Node leaveFunctionNode(final FunctionNode functionNode) {
    8.50          functionNode.setState(CompilationState.CONSTANT_FOLDED);
    8.51          return functionNode;
    8.52      }
    8.53  
    8.54      @Override
    8.55 -    public Node leave(final IfNode ifNode) {
    8.56 +    public Node leaveIfNode(final IfNode ifNode) {
    8.57          final Node test = ifNode.getTest();
    8.58          if (test instanceof LiteralNode) {
    8.59              final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
    8.60 @@ -101,7 +101,7 @@
    8.61      }
    8.62  
    8.63      @Override
    8.64 -    public Node leave(final TernaryNode ternaryNode) {
    8.65 +    public Node leaveTernaryNode(final TernaryNode ternaryNode) {
    8.66          final Node test = ternaryNode.lhs();
    8.67          if (test instanceof LiteralNode) {
    8.68              return ((LiteralNode<?>)test).isTrue() ? ternaryNode.rhs() : ternaryNode.third();
     9.1 --- a/src/jdk/nashorn/internal/codegen/FunctionSignature.java	Tue Mar 19 11:03:24 2013 -0300
     9.2 +++ b/src/jdk/nashorn/internal/codegen/FunctionSignature.java	Sat Mar 23 00:58:39 2013 +0100
     9.3 @@ -155,7 +155,7 @@
     9.4              true,
     9.5              functionNode.needsCallee(),
     9.6              functionNode.getReturnType(),
     9.7 -            (functionNode.isVarArg() && !functionNode.isScript()) ?
     9.8 +            (functionNode.isVarArg() && !functionNode.isProgram()) ?
     9.9                  null :
    9.10                  functionNode.getParameters());
    9.11      }
    10.1 --- a/src/jdk/nashorn/internal/codegen/Lower.java	Tue Mar 19 11:03:24 2013 -0300
    10.2 +++ b/src/jdk/nashorn/internal/codegen/Lower.java	Sat Mar 23 00:58:39 2013 +0100
    10.3 @@ -37,8 +37,8 @@
    10.4  import java.util.ArrayList;
    10.5  import java.util.Arrays;
    10.6  import java.util.Deque;
    10.7 +import java.util.Iterator;
    10.8  import java.util.List;
    10.9 -import jdk.nashorn.internal.ir.AccessNode;
   10.10  import jdk.nashorn.internal.ir.BaseNode;
   10.11  import jdk.nashorn.internal.ir.BinaryNode;
   10.12  import jdk.nashorn.internal.ir.Block;
   10.13 @@ -52,11 +52,12 @@
   10.14  import jdk.nashorn.internal.ir.ExecuteNode;
   10.15  import jdk.nashorn.internal.ir.ForNode;
   10.16  import jdk.nashorn.internal.ir.FunctionNode;
   10.17 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
   10.18  import jdk.nashorn.internal.ir.IdentNode;
   10.19  import jdk.nashorn.internal.ir.IfNode;
   10.20 -import jdk.nashorn.internal.ir.IndexNode;
   10.21  import jdk.nashorn.internal.ir.LabelNode;
   10.22  import jdk.nashorn.internal.ir.LabeledNode;
   10.23 +import jdk.nashorn.internal.ir.LexicalContext;
   10.24  import jdk.nashorn.internal.ir.LineNumberNode;
   10.25  import jdk.nashorn.internal.ir.LiteralNode;
   10.26  import jdk.nashorn.internal.ir.Node;
   10.27 @@ -69,7 +70,6 @@
   10.28  import jdk.nashorn.internal.ir.VarNode;
   10.29  import jdk.nashorn.internal.ir.WhileNode;
   10.30  import jdk.nashorn.internal.ir.WithNode;
   10.31 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
   10.32  import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
   10.33  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   10.34  import jdk.nashorn.internal.parser.Token;
   10.35 @@ -103,6 +103,8 @@
   10.36  
   10.37      private List<Node> statements;
   10.38  
   10.39 +    private LexicalContext lexicalContext = new LexicalContext();
   10.40 +
   10.41      /**
   10.42       * Constructor.
   10.43       *
   10.44 @@ -114,14 +116,15 @@
   10.45      }
   10.46  
   10.47      @Override
   10.48 -    public Node enter(final Block block) {
   10.49 +    public Node enterBlock(final Block block) {
   10.50          final Node       savedLastStatement = lastStatement;
   10.51          final List<Node> savedStatements    = statements;
   10.52 -
   10.53 +        lexicalContext.push(block);
   10.54          try {
   10.55              this.statements = new ArrayList<>();
   10.56 +            NodeVisitor visitor = this;
   10.57              for (final Node statement : block.getStatements()) {
   10.58 -                statement.accept(this);
   10.59 +                statement.accept(visitor);
   10.60                  /*
   10.61                   * This is slightly unsound, for example if we have a loop with
   10.62                   * a guarded statement like if (x) continue in the body and the
   10.63 @@ -133,7 +136,7 @@
   10.64                   */
   10.65                  if (lastStatement != null && lastStatement.isTerminal()) {
   10.66                      copyTerminal(block, lastStatement);
   10.67 -                    break;
   10.68 +                    visitor = new DeadCodeVarDeclarationVisitor();
   10.69                  }
   10.70              }
   10.71              block.setStatements(statements);
   10.72 @@ -141,18 +144,19 @@
   10.73          } finally {
   10.74              this.statements = savedStatements;
   10.75              this.lastStatement = savedLastStatement;
   10.76 +            lexicalContext.pop(block);
   10.77          }
   10.78  
   10.79          return null;
   10.80      }
   10.81  
   10.82      @Override
   10.83 -    public Node enter(final BreakNode breakNode) {
   10.84 +    public Node enterBreakNode(final BreakNode breakNode) {
   10.85          return enterBreakOrContinue(breakNode);
   10.86      }
   10.87  
   10.88      @Override
   10.89 -    public Node enter(final CallNode callNode) {
   10.90 +    public Node enterCallNode(final CallNode callNode) {
   10.91          final Node function = markerFunction(callNode.getFunction());
   10.92          callNode.setFunction(function);
   10.93          checkEval(callNode); //check if this is an eval call and store the information
   10.94 @@ -160,44 +164,44 @@
   10.95      }
   10.96  
   10.97      @Override
   10.98 -    public Node leave(final CaseNode caseNode) {
   10.99 +    public Node leaveCaseNode(final CaseNode caseNode) {
  10.100          caseNode.copyTerminalFlags(caseNode.getBody());
  10.101          return caseNode;
  10.102      }
  10.103  
  10.104      @Override
  10.105 -    public Node leave(final CatchNode catchNode) {
  10.106 +    public Node leaveCatchNode(final CatchNode catchNode) {
  10.107          catchNode.copyTerminalFlags(catchNode.getBody());
  10.108          addStatement(catchNode);
  10.109          return catchNode;
  10.110      }
  10.111  
  10.112      @Override
  10.113 -    public Node enter(final ContinueNode continueNode) {
  10.114 +    public Node enterContinueNode(final ContinueNode continueNode) {
  10.115          return enterBreakOrContinue(continueNode);
  10.116      }
  10.117  
  10.118      @Override
  10.119 -    public Node enter(final DoWhileNode doWhileNode) {
  10.120 -        return enter((WhileNode)doWhileNode);
  10.121 +    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
  10.122 +        return enterWhileNode(doWhileNode);
  10.123      }
  10.124  
  10.125      @Override
  10.126 -    public Node leave(final DoWhileNode doWhileNode) {
  10.127 -        return leave((WhileNode)doWhileNode);
  10.128 +    public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
  10.129 +        return leaveWhileNode(doWhileNode);
  10.130      }
  10.131  
  10.132      @Override
  10.133 -    public Node enter(final EmptyNode emptyNode) {
  10.134 +    public Node enterEmptyNode(final EmptyNode emptyNode) {
  10.135          return null;
  10.136      }
  10.137  
  10.138      @Override
  10.139 -    public Node leave(final ExecuteNode executeNode) {
  10.140 +    public Node leaveExecuteNode(final ExecuteNode executeNode) {
  10.141          final Node expr = executeNode.getExpression();
  10.142  
  10.143 -        if (getCurrentFunctionNode().isScript()) {
  10.144 -            if (!(expr instanceof Block)) {
  10.145 +        if (getCurrentFunctionNode().isProgram()) {
  10.146 +            if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function
  10.147                  if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
  10.148                      executeNode.setExpression(new BinaryNode(executeNode.getSource(), Token.recast(executeNode.getToken(), TokenType.ASSIGN),
  10.149                              getCurrentFunctionNode().getResultNode(),
  10.150 @@ -213,13 +217,13 @@
  10.151      }
  10.152  
  10.153      @Override
  10.154 -    public Node enter(final ForNode forNode) {
  10.155 +    public Node enterForNode(final ForNode forNode) {
  10.156          nest(forNode);
  10.157          return forNode;
  10.158      }
  10.159  
  10.160      @Override
  10.161 -    public Node leave(final ForNode forNode) {
  10.162 +    public Node leaveForNode(final ForNode forNode) {
  10.163          final Node  test = forNode.getTest();
  10.164          final Block body = forNode.getBody();
  10.165  
  10.166 @@ -247,18 +251,16 @@
  10.167      }
  10.168  
  10.169      @Override
  10.170 -    public Node enter(final FunctionNode functionNode) {
  10.171 +    public Node enterFunctionNode(final FunctionNode functionNode) {
  10.172          LOG.info("START FunctionNode: " + functionNode.getName());
  10.173  
  10.174          if (functionNode.isLazy()) {
  10.175              LOG.info("LAZY: " + functionNode.getName());
  10.176              return null;
  10.177          }
  10.178 -
  10.179 +        lexicalContext.push(functionNode);
  10.180          initFunctionNode(functionNode);
  10.181  
  10.182 -        Node initialEvalResult = LiteralNode.newInstance(functionNode, ScriptRuntime.UNDEFINED);
  10.183 -
  10.184          nest(functionNode);
  10.185  
  10.186          /*
  10.187 @@ -272,60 +274,40 @@
  10.188          statements    = new ArrayList<>();
  10.189          lastStatement = null;
  10.190  
  10.191 -        // for initial eval result is the last declared function
  10.192 -        for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
  10.193 -            final IdentNode ident = nestedFunction.getIdent();
  10.194 -            if (ident != null && nestedFunction.isStatement()) {
  10.195 -                initialEvalResult = new IdentNode(ident);
  10.196 -            }
  10.197 -        }
  10.198 -
  10.199          if (functionNode.needsSelfSymbol()) {
  10.200              //function needs to start with var funcIdent = __callee_;
  10.201              statements.add(functionNode.getSelfSymbolInit().accept(this));
  10.202          }
  10.203  
  10.204 +        NodeVisitor visitor = this;
  10.205          try {
  10.206 -            // Every nested function needs a definition in the outer function with its name. Add these.
  10.207 -            for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
  10.208 -                final VarNode varNode = nestedFunction.getFunctionVarNode();
  10.209 -                if (varNode != null) {
  10.210 -                    final LineNumberNode lineNumberNode = nestedFunction.getFunctionVarLineNumberNode();
  10.211 -                    if (lineNumberNode != null) {
  10.212 -                        lineNumberNode.accept(this);
  10.213 -                    }
  10.214 -                    varNode.accept(this);
  10.215 -                    varNode.setIsFunctionVarNode();
  10.216 +            //do the statements - this fills the block with code
  10.217 +            boolean needsInitialEvalResult = functionNode.isProgram();
  10.218 +            for (final Node statement : functionNode.getStatements()) {
  10.219 +                // If this function is a program, then insert an assignment to the initial eval result after all
  10.220 +                // function declarations.
  10.221 +                if(needsInitialEvalResult && !(statement instanceof LineNumberNode || (statement instanceof VarNode && ((VarNode)statement).isFunctionDeclaration()))) {
  10.222 +                    addInitialEvalResult(functionNode);
  10.223 +                    needsInitialEvalResult = false;
  10.224                  }
  10.225 -            }
  10.226 -
  10.227 -            if (functionNode.isScript()) {
  10.228 -                new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(), initialEvalResult).accept(this);
  10.229 -            }
  10.230 -
  10.231 -            //do the statements - this fills the block with code
  10.232 -            for (final Node statement : functionNode.getStatements()) {
  10.233 -                statement.accept(this);
  10.234 +                statement.accept(visitor);
  10.235                  //If there are unused terminated endpoints in the function, we need
  10.236                  // to add a "return undefined" in those places for correct semantics
  10.237                  LOG.info("Checking lastStatement="+lastStatement+" for terminal flags");
  10.238                  if (lastStatement != null && lastStatement.hasTerminalFlags()) {
  10.239                      copyTerminal(functionNode, lastStatement);
  10.240 -                    break;
  10.241 +                    assert !needsInitialEvalResult;
  10.242 +                    visitor = new DeadCodeVarDeclarationVisitor();
  10.243                  }
  10.244              }
  10.245 -
  10.246 +            if(needsInitialEvalResult) {
  10.247 +                addInitialEvalResult(functionNode);
  10.248 +            }
  10.249              functionNode.setStatements(statements);
  10.250  
  10.251              if (!functionNode.isTerminal()) {
  10.252                  guaranteeReturn(functionNode);
  10.253              }
  10.254 -
  10.255 -            //lower all nested functions
  10.256 -            for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
  10.257 -                nestedFunction.accept(this);
  10.258 -            }
  10.259 -
  10.260          } finally {
  10.261              statements    = savedStatements;
  10.262              lastStatement = savedLastStatement;
  10.263 @@ -333,19 +315,67 @@
  10.264  
  10.265          LOG.info("END FunctionNode: " + functionNode.getName());
  10.266          unnest(functionNode);
  10.267 +        lexicalContext.pop(functionNode);
  10.268  
  10.269          functionNode.setState(CompilationState.LOWERED);
  10.270  
  10.271          return null;
  10.272      }
  10.273  
  10.274 +    /**
  10.275 +     * This visitor is used to go over statements after a terminal statement. Those statements are dead code, but the
  10.276 +     * var declarations in them still have the effect of declaring a local variable on the function level. Therefore,
  10.277 +     * they aren't really dead code and must be preserved. Note that they're only preserved as no-op declarations; their
  10.278 +     * initializers are wiped out as those are, in fact, dead code.
  10.279 +     */
  10.280 +    private class DeadCodeVarDeclarationVisitor extends NodeOperatorVisitor {
  10.281 +        DeadCodeVarDeclarationVisitor() {
  10.282 +        }
  10.283 +
  10.284 +        @Override
  10.285 +        public Node enterVarNode(VarNode varNode) {
  10.286 +            // Can't ever see a function declaration, as this visitor is only ever used after a terminal statement was
  10.287 +            // encountered, and all function declarations precede any terminal statements.
  10.288 +            assert !varNode.isFunctionDeclaration();
  10.289 +            if(varNode.getInit() == null) {
  10.290 +                // No initializer, just pass it to Lower.
  10.291 +                return varNode.accept(Lower.this);
  10.292 +            }
  10.293 +            // Wipe out the initializer and then pass it to Lower.
  10.294 +            return varNode.setInit(null).accept(Lower.this);
  10.295 +        }
  10.296 +    }
  10.297 +
  10.298 +    private void addInitialEvalResult(final FunctionNode functionNode) {
  10.299 +        new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(),
  10.300 +                getInitialEvalResult(functionNode)).accept(this);
  10.301 +    }
  10.302 +
  10.303 +    /**
  10.304 +     * Result of initial result of evaluating a particular program, which is either the last function it declares, or
  10.305 +     * undefined if it doesn't declare any functions.
  10.306 +     * @param program
  10.307 +     * @return the initial result of evaluating the program
  10.308 +     */
  10.309 +    private static Node getInitialEvalResult(final FunctionNode program) {
  10.310 +        IdentNode lastFnName = null;
  10.311 +        for (final FunctionNode fn : program.getDeclaredFunctions()) {
  10.312 +            assert fn.isDeclared();
  10.313 +            final IdentNode fnName = fn.getIdent();
  10.314 +            if(fnName != null) {
  10.315 +                lastFnName = fnName;
  10.316 +            }
  10.317 +        }
  10.318 +        return lastFnName != null ? new IdentNode(lastFnName) : LiteralNode.newInstance(program, ScriptRuntime.UNDEFINED);
  10.319 +    }
  10.320 +
  10.321      @Override
  10.322 -    public Node enter(final IfNode ifNode) {
  10.323 +    public Node enterIfNode(final IfNode ifNode) {
  10.324          return nest(ifNode);
  10.325      }
  10.326  
  10.327      @Override
  10.328 -    public Node leave(final IfNode ifNode) {
  10.329 +    public Node leaveIfNode(final IfNode ifNode) {
  10.330          final Node pass = ifNode.getPass();
  10.331          final Node fail = ifNode.getFail();
  10.332  
  10.333 @@ -360,7 +390,7 @@
  10.334      }
  10.335  
  10.336      @Override
  10.337 -    public Node enter(LabelNode labelNode) {
  10.338 +    public Node enterLabelNode(LabelNode labelNode) {
  10.339          final Block body = labelNode.getBody();
  10.340          body.accept(this);
  10.341          copyTerminal(labelNode, body);
  10.342 @@ -369,13 +399,13 @@
  10.343      }
  10.344  
  10.345      @Override
  10.346 -    public Node enter(final LineNumberNode lineNumberNode) {
  10.347 +    public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
  10.348          addStatement(lineNumberNode, false); // don't put it in lastStatement cache
  10.349          return null;
  10.350      }
  10.351  
  10.352      @Override
  10.353 -    public Node enter(final ReturnNode returnNode) {
  10.354 +    public Node enterReturnNode(final ReturnNode returnNode) {
  10.355          final TryNode tryNode = returnNode.getTryChain();
  10.356          final Node    expr    = returnNode.getExpression();
  10.357  
  10.358 @@ -413,19 +443,19 @@
  10.359      }
  10.360  
  10.361      @Override
  10.362 -    public Node leave(final ReturnNode returnNode) {
  10.363 +    public Node leaveReturnNode(final ReturnNode returnNode) {
  10.364          addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor
  10.365          return returnNode;
  10.366      }
  10.367  
  10.368      @Override
  10.369 -    public Node enter(final SwitchNode switchNode) {
  10.370 +    public Node enterSwitchNode(final SwitchNode switchNode) {
  10.371          nest(switchNode);
  10.372          return switchNode;
  10.373      }
  10.374  
  10.375      @Override
  10.376 -    public Node leave(final SwitchNode switchNode) {
  10.377 +    public Node leaveSwitchNode(final SwitchNode switchNode) {
  10.378          unnest(switchNode);
  10.379  
  10.380          final List<CaseNode> cases       = switchNode.getCases();
  10.381 @@ -446,13 +476,13 @@
  10.382      }
  10.383  
  10.384      @Override
  10.385 -    public Node leave(final ThrowNode throwNode) {
  10.386 +    public Node leaveThrowNode(final ThrowNode throwNode) {
  10.387          addStatement(throwNode); //ThrowNodes are always terminal, marked as such in constructor
  10.388          return throwNode;
  10.389      }
  10.390  
  10.391      @Override
  10.392 -    public Node enter(final TryNode tryNode) {
  10.393 +    public Node enterTryNode(final TryNode tryNode) {
  10.394          final Block  finallyBody = tryNode.getFinallyBody();
  10.395          final long   token       = tryNode.getToken();
  10.396          final int    finish      = tryNode.getFinish();
  10.397 @@ -538,26 +568,19 @@
  10.398  
  10.399              // set outer tryNode's body to innerTryNode
  10.400              final Block outerBody;
  10.401 -            outerBody = new Block(source, token, finish, tryNode.getBody().getParent(), getCurrentFunctionNode());
  10.402 +            outerBody = new Block(source, token, finish);
  10.403              outerBody.setStatements(new ArrayList<Node>(Arrays.asList(innerTryNode)));
  10.404              tryNode.setBody(outerBody);
  10.405              tryNode.setCatchBlocks(null);
  10.406 -
  10.407 -            // now before we go on, we have to fix the block parents
  10.408 -            // (we repair the block tree after the insertion so that all references are intact)
  10.409 -            innerTryNode.getBody().setParent(tryNode.getBody());
  10.410 -            for (final Block block : innerTryNode.getCatchBlocks()) {
  10.411 -                block.setParent(tryNode.getBody());
  10.412 -            }
  10.413          }
  10.414  
  10.415          // create a catch-all that inlines finally and rethrows
  10.416  
  10.417 -        final Block catchBlock      = new Block(source, token, finish, getCurrentBlock(), getCurrentFunctionNode());
  10.418 +        final Block catchBlock      = new Block(source, token, finish);
  10.419          //this catch block should get define symbol
  10.420  
  10.421 -        final Block catchBody       = new Block(source, token, finish, catchBlock, getCurrentFunctionNode());
  10.422 -        final Node  catchAllFinally = finallyBody.clone();
  10.423 +        final Block catchBody       = new Block(source, token, finish);
  10.424 +        final Node  catchAllFinally = finallyBody.copy();
  10.425  
  10.426          catchBody.addStatement(new ExecuteNode(source, finallyBody.getToken(), finallyBody.getFinish(), catchAllFinally));
  10.427          setTerminal(catchBody, true);
  10.428 @@ -584,7 +607,7 @@
  10.429      }
  10.430  
  10.431      @Override
  10.432 -    public Node leave(final TryNode tryNode) {
  10.433 +    public Node leaveTryNode(final TryNode tryNode) {
  10.434          final Block finallyBody   = tryNode.getFinallyBody();
  10.435  
  10.436          boolean allTerminal = tryNode.getBody().isTerminal() && (finallyBody == null || finallyBody.isTerminal());
  10.437 @@ -608,18 +631,18 @@
  10.438      }
  10.439  
  10.440      @Override
  10.441 -    public Node leave(final VarNode varNode) {
  10.442 +    public Node leaveVarNode(final VarNode varNode) {
  10.443          addStatement(varNode);
  10.444          return varNode;
  10.445      }
  10.446  
  10.447      @Override
  10.448 -    public Node enter(final WhileNode whileNode) {
  10.449 +    public Node enterWhileNode(final WhileNode whileNode) {
  10.450          return nest(whileNode);
  10.451      }
  10.452  
  10.453      @Override
  10.454 -    public Node leave(final WhileNode whileNode) {
  10.455 +    public Node leaveWhileNode(final WhileNode whileNode) {
  10.456          final Node test = whileNode.getTest();
  10.457  
  10.458          if (test == null) {
  10.459 @@ -653,7 +676,7 @@
  10.460      }
  10.461  
  10.462      @Override
  10.463 -    public Node leave(final WithNode withNode) {
  10.464 +    public Node leaveWithNode(final WithNode withNode) {
  10.465          if (withNode.getBody().isTerminal()) {
  10.466              setTerminal(withNode,  true);
  10.467          }
  10.468 @@ -682,28 +705,10 @@
  10.469       */
  10.470      private static Node markerFunction(final Node function) {
  10.471          if (function instanceof IdentNode) {
  10.472 -            return new IdentNode((IdentNode)function) {
  10.473 -                @Override
  10.474 -                public boolean isFunction() {
  10.475 -                    return true;
  10.476 -                }
  10.477 -            };
  10.478 -        } else if (function instanceof AccessNode) {
  10.479 -            return new AccessNode((AccessNode)function) {
  10.480 -                @Override
  10.481 -                public boolean isFunction() {
  10.482 -                    return true;
  10.483 -                }
  10.484 -            };
  10.485 -        } else if (function instanceof IndexNode) {
  10.486 -            return new IndexNode((IndexNode)function) {
  10.487 -                @Override
  10.488 -                public boolean isFunction() {
  10.489 -                    return true;
  10.490 -                }
  10.491 -            };
  10.492 +            return ((IdentNode)function).setIsFunction();
  10.493 +        } else if (function instanceof BaseNode) {
  10.494 +            return ((BaseNode)function).setIsFunction();
  10.495          }
  10.496 -
  10.497          return function;
  10.498      }
  10.499  
  10.500 @@ -746,7 +751,7 @@
  10.501              if (args.size() >= 1 && EVAL.tag().equals(callee.getName())) {
  10.502                  final CallNode.EvalArgs evalArgs =
  10.503                      new CallNode.EvalArgs(
  10.504 -                        args.get(0).clone().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case"
  10.505 +                        args.get(0).copy().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case"
  10.506                          getCurrentFunctionNode().getThisNode(),
  10.507                          evalLocation(callee),
  10.508                          getCurrentFunctionNode().isStrictMode());
  10.509 @@ -773,13 +778,13 @@
  10.510  
  10.511          loopBody.accept(new NodeVisitor() {
  10.512              @Override
  10.513 -            public Node leave(final BreakNode node) {
  10.514 +            public Node leaveBreakNode(final BreakNode node) {
  10.515                  escapes.add(node);
  10.516                  return node;
  10.517              }
  10.518  
  10.519              @Override
  10.520 -            public Node leave(final ContinueNode node) {
  10.521 +            public Node leaveContinueNode(final ContinueNode node) {
  10.522                  // all inner loops have been popped.
  10.523                  if (nesting.contains(node.getTargetNode())) {
  10.524                      escapes.add(node);
  10.525 @@ -794,7 +799,7 @@
  10.526      private void guaranteeReturn(final FunctionNode functionNode) {
  10.527          Node resultNode;
  10.528  
  10.529 -        if (functionNode.isScript()) {
  10.530 +        if (functionNode.isProgram()) {
  10.531              resultNode = functionNode.getResultNode(); // the eval result, symbol assigned in Attr
  10.532          } else {
  10.533              if (lastStatement != null && lastStatement.isTerminal() || lastStatement instanceof ReturnNode) {
  10.534 @@ -859,18 +864,15 @@
  10.535       * @return true if try block is inside the target, false otherwise.
  10.536       */
  10.537      private boolean isNestedTry(final TryNode tryNode, final Block target) {
  10.538 -        for (Block current = getCurrentBlock(); current != target; current = current.getParent()) {
  10.539 -            if (tryNode.getBody() == current) {
  10.540 +        for(Iterator<Block> blocks = lexicalContext.getBlocks(getCurrentBlock()); blocks.hasNext();) {
  10.541 +            final Block block = blocks.next();
  10.542 +            if(block == target) {
  10.543 +                return false;
  10.544 +            }
  10.545 +            if(tryNode.isChildBlock(block)) {
  10.546                  return true;
  10.547              }
  10.548 -
  10.549 -            for (final Block catchBlock : tryNode.getCatchBlocks()) {
  10.550 -                if (catchBlock == current) {
  10.551 -                    return true;
  10.552 -                }
  10.553 -            }
  10.554          }
  10.555 -
  10.556          return false;
  10.557      }
  10.558  
  10.559 @@ -899,7 +901,7 @@
  10.560                  continue;
  10.561              }
  10.562  
  10.563 -            finallyBody = (Block)finallyBody.clone();
  10.564 +            finallyBody = (Block)finallyBody.copy();
  10.565              final boolean hasTerminalFlags = finallyBody.hasTerminalFlags();
  10.566  
  10.567              new ExecuteNode(finallyBody.getSource(), finallyBody.getToken(), finallyBody.getFinish(), finallyBody).accept(this);
  10.568 @@ -974,6 +976,3 @@
  10.569      }
  10.570  
  10.571  }
  10.572 -
  10.573 -
  10.574 -
    11.1 --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue Mar 19 11:03:24 2013 -0300
    11.2 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Sat Mar 23 00:58:39 2013 +0100
    11.3 @@ -651,11 +651,10 @@
    11.4  
    11.5      /**
    11.6       * Load the constants array
    11.7 -     * @param unitClassName name of the compile unit from which to load constants
    11.8       * @return this method emitter
    11.9       */
   11.10 -    MethodEmitter loadConstants(final String unitClassName) {
   11.11 -        getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor());
   11.12 +    MethodEmitter loadConstants() {
   11.13 +        getStatic(classEmitter.getUnitClassName(), CONSTANTS.tag(), CONSTANTS.descriptor());
   11.14          assert peekType().isArray() : peekType();
   11.15          return this;
   11.16      }
    12.1 --- a/src/jdk/nashorn/internal/codegen/Splitter.java	Tue Mar 19 11:03:24 2013 -0300
    12.2 +++ b/src/jdk/nashorn/internal/codegen/Splitter.java	Sat Mar 23 00:58:39 2013 +0100
    12.3 @@ -41,6 +41,7 @@
    12.4  import jdk.nashorn.internal.ir.FunctionNode;
    12.5  import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    12.6  import jdk.nashorn.internal.ir.LabelNode;
    12.7 +import jdk.nashorn.internal.ir.LexicalContext;
    12.8  import jdk.nashorn.internal.ir.LiteralNode;
    12.9  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
   12.10  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
   12.11 @@ -49,6 +50,7 @@
   12.12  import jdk.nashorn.internal.ir.SplitNode;
   12.13  import jdk.nashorn.internal.ir.SwitchNode;
   12.14  import jdk.nashorn.internal.ir.WhileNode;
   12.15 +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
   12.16  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   12.17  import jdk.nashorn.internal.runtime.DebugLogger;
   12.18  import jdk.nashorn.internal.runtime.Source;
   12.19 @@ -70,6 +72,8 @@
   12.20      /** Cache for calculated block weights. */
   12.21      private final Map<Node, Long> weightCache = new HashMap<>();
   12.22  
   12.23 +    private final LexicalContext lexicalContext = new LexicalContext();
   12.24 +
   12.25      /** Weight threshold for when to start a split. */
   12.26      public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024);
   12.27  
   12.28 @@ -112,7 +116,7 @@
   12.29              }
   12.30  
   12.31              if (weight >= SPLIT_THRESHOLD) {
   12.32 -                weight = splitBlock(functionNode);
   12.33 +                weight = splitBlock(functionNode, functionNode);
   12.34              }
   12.35  
   12.36              if (functionNode.isSplit()) {
   12.37 @@ -132,9 +136,20 @@
   12.38          }
   12.39  
   12.40          // Recursively split nested functions
   12.41 -        for (final FunctionNode function : functionNode.getFunctions()) {
   12.42 -            new Splitter(compiler, function, outermostCompileUnit).split();
   12.43 -        }
   12.44 +        functionNode.accept(new NodeOperatorVisitor() {
   12.45 +            @Override
   12.46 +            public Node enterFunctionNode(FunctionNode function) {
   12.47 +                if(function == functionNode) {
   12.48 +                    // Don't process outermost function (it was already processed) but descend into it to find nested
   12.49 +                    // functions.
   12.50 +                    return function;
   12.51 +                }
   12.52 +                // Process a nested function
   12.53 +                new Splitter(compiler, function, outermostCompileUnit).split();
   12.54 +                // Don't descend into a a nested function; Splitter.split() has taken care of nested-in-nested functions.
   12.55 +                return null;
   12.56 +            }
   12.57 +        });
   12.58  
   12.59          functionNode.setState(CompilationState.SPLIT);
   12.60      }
   12.61 @@ -155,7 +170,7 @@
   12.62       *
   12.63       * @return new weight for the resulting block.
   12.64       */
   12.65 -    private long splitBlock(final Block block) {
   12.66 +    private long splitBlock(final Block block, final FunctionNode function) {
   12.67          functionNode.setIsSplit();
   12.68  
   12.69          final List<Node> splits = new ArrayList<>();
   12.70 @@ -167,7 +182,7 @@
   12.71  
   12.72              if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) {
   12.73                  if (!statements.isEmpty()) {
   12.74 -                    splits.add(createBlockSplitNode(block, statements, statementsWeight));
   12.75 +                    splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
   12.76                      statements = new ArrayList<>();
   12.77                      statementsWeight = 0;
   12.78                  }
   12.79 @@ -183,7 +198,7 @@
   12.80          }
   12.81  
   12.82          if (!statements.isEmpty()) {
   12.83 -            splits.add(createBlockSplitNode(block, statements, statementsWeight));
   12.84 +            splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
   12.85          }
   12.86  
   12.87          block.setStatements(splits);
   12.88 @@ -199,13 +214,13 @@
   12.89       *
   12.90       * @return New split node.
   12.91       */
   12.92 -    private SplitNode createBlockSplitNode(final Block parent, final List<Node> statements, final long weight) {
   12.93 +    private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Node> statements, final long weight) {
   12.94          final Source source = parent.getSource();
   12.95          final long   token  = parent.getToken();
   12.96          final int    finish = parent.getFinish();
   12.97 -        final String name   = parent.getFunction().uniqueName(SPLIT_PREFIX.tag());
   12.98 +        final String name   = function.uniqueName(SPLIT_PREFIX.tag());
   12.99  
  12.100 -        final Block newBlock = new Block(source, token, finish, parent, functionNode);
  12.101 +        final Block newBlock = new Block(source, token, finish);
  12.102          newBlock.setFrame(new Frame(parent.getFrame()));
  12.103          newBlock.setStatements(statements);
  12.104  
  12.105 @@ -217,15 +232,17 @@
  12.106      }
  12.107  
  12.108      @Override
  12.109 -    public Node enter(final Block block) {
  12.110 +    public Node enterBlock(final Block block) {
  12.111          if (block.isCatchBlock()) {
  12.112              return null;
  12.113          }
  12.114 +        lexicalContext.push(block);
  12.115  
  12.116          final long weight = WeighNodes.weigh(block, weightCache);
  12.117  
  12.118          if (weight < SPLIT_THRESHOLD) {
  12.119              weightCache.put(block, weight);
  12.120 +            lexicalContext.pop(block);
  12.121              return null;
  12.122          }
  12.123  
  12.124 @@ -233,23 +250,24 @@
  12.125      }
  12.126  
  12.127      @Override
  12.128 -    public Node leave(final Block block) {
  12.129 +    public Node leaveBlock(final Block block) {
  12.130          assert !block.isCatchBlock();
  12.131  
  12.132          // Block was heavier than SLIT_THRESHOLD in enter, but a sub-block may have
  12.133          // been split already, so weigh again before splitting.
  12.134          long weight = WeighNodes.weigh(block, weightCache);
  12.135          if (weight >= SPLIT_THRESHOLD) {
  12.136 -            weight = splitBlock(block);
  12.137 +            weight = splitBlock(block, lexicalContext.getFunction(block));
  12.138          }
  12.139          weightCache.put(block, weight);
  12.140  
  12.141 +        lexicalContext.pop(block);
  12.142          return block;
  12.143      }
  12.144  
  12.145      @SuppressWarnings("rawtypes")
  12.146      @Override
  12.147 -    public Node leave(final LiteralNode literal) {
  12.148 +    public Node leaveLiteralNode(final LiteralNode literal) {
  12.149          long weight = WeighNodes.weigh(literal);
  12.150  
  12.151          if (weight < SPLIT_THRESHOLD) {
  12.152 @@ -294,17 +312,12 @@
  12.153      }
  12.154  
  12.155      @Override
  12.156 -    public Node enter(final FunctionNode node) {
  12.157 -        if (node.isLazy()) {
  12.158 -            return null;
  12.159 +    public Node enterFunctionNode(final FunctionNode node) {
  12.160 +        if(node == functionNode && !node.isLazy()) {
  12.161 +            lexicalContext.push(node);
  12.162 +            node.visitStatements(this);
  12.163 +            lexicalContext.pop(node);
  12.164          }
  12.165 -
  12.166 -        final List<Node> statements = node.getStatements();
  12.167 -
  12.168 -        for (final Node statement : statements) {
  12.169 -            statement.accept(this);
  12.170 -        }
  12.171 -
  12.172          return null;
  12.173      }
  12.174  
  12.175 @@ -321,38 +334,38 @@
  12.176          }
  12.177  
  12.178          @Override
  12.179 -        public Node enter(final LabelNode labelNode) {
  12.180 +        public Node enterLabelNode(final LabelNode labelNode) {
  12.181              registerJumpTarget(labelNode.getBreakNode());
  12.182              registerJumpTarget(labelNode.getContinueNode());
  12.183              return labelNode;
  12.184          }
  12.185  
  12.186          @Override
  12.187 -        public Node enter(final WhileNode whileNode) {
  12.188 +        public Node enterWhileNode(final WhileNode whileNode) {
  12.189              registerJumpTarget(whileNode);
  12.190              return whileNode;
  12.191          }
  12.192  
  12.193          @Override
  12.194 -        public Node enter(final DoWhileNode doWhileNode) {
  12.195 +        public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
  12.196              registerJumpTarget(doWhileNode);
  12.197              return doWhileNode;
  12.198          }
  12.199  
  12.200          @Override
  12.201 -        public Node enter(final ForNode forNode) {
  12.202 +        public Node enterForNode(final ForNode forNode) {
  12.203              registerJumpTarget(forNode);
  12.204              return forNode;
  12.205          }
  12.206  
  12.207          @Override
  12.208 -        public Node enter(final SwitchNode switchNode) {
  12.209 +        public Node enterSwitchNode(final SwitchNode switchNode) {
  12.210              registerJumpTarget(switchNode);
  12.211              return switchNode;
  12.212          }
  12.213  
  12.214          @Override
  12.215 -        public Node enter(final ReturnNode returnNode) {
  12.216 +        public Node enterReturnNode(final ReturnNode returnNode) {
  12.217              for (final SplitNode split : splitStack) {
  12.218                  split.setHasReturn(true);
  12.219              }
  12.220 @@ -360,25 +373,25 @@
  12.221          }
  12.222  
  12.223          @Override
  12.224 -        public Node enter(final ContinueNode continueNode) {
  12.225 +        public Node enterContinueNode(final ContinueNode continueNode) {
  12.226              searchJumpTarget(continueNode.getTargetNode(), continueNode.getTargetLabel());
  12.227              return continueNode;
  12.228          }
  12.229  
  12.230          @Override
  12.231 -        public Node enter(final BreakNode breakNode) {
  12.232 +        public Node enterBreakNode(final BreakNode breakNode) {
  12.233              searchJumpTarget(breakNode.getTargetNode(), breakNode.getTargetLabel());
  12.234              return breakNode;
  12.235          }
  12.236  
  12.237          @Override
  12.238 -        public Node enter(final SplitNode splitNode) {
  12.239 +        public Node enterSplitNode(final SplitNode splitNode) {
  12.240              splitStack.addFirst(splitNode);
  12.241              return splitNode;
  12.242          }
  12.243  
  12.244          @Override
  12.245 -        public Node leave(final SplitNode splitNode) {
  12.246 +        public Node leaveSplitNode(final SplitNode splitNode) {
  12.247              assert splitNode == splitStack.peekFirst();
  12.248              splitStack.removeFirst();
  12.249              return splitNode;
    13.1 --- a/src/jdk/nashorn/internal/codegen/WeighNodes.java	Tue Mar 19 11:03:24 2013 -0300
    13.2 +++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java	Sat Mar 23 00:58:39 2013 +0100
    13.3 @@ -47,7 +47,6 @@
    13.4  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
    13.5  import jdk.nashorn.internal.ir.Node;
    13.6  import jdk.nashorn.internal.ir.PropertyNode;
    13.7 -import jdk.nashorn.internal.ir.ReferenceNode;
    13.8  import jdk.nashorn.internal.ir.ReturnNode;
    13.9  import jdk.nashorn.internal.ir.RuntimeNode;
   13.10  import jdk.nashorn.internal.ir.SplitNode;
   13.11 @@ -80,7 +79,7 @@
   13.12      private static final long LITERAL_WEIGHT   = 10;
   13.13      private static final long LOOP_WEIGHT      = 4;
   13.14      private static final long NEW_WEIGHT       = 6;
   13.15 -    private static final long REFERENCE_WEIGHT = 20;
   13.16 +    private static final long FUNC_EXPR_WEIGHT = 20;
   13.17      private static final long RETURN_WEIGHT    = 2;
   13.18      private static final long SPLIT_WEIGHT     = 40;
   13.19      private static final long SWITCH_WEIGHT    = 8;
   13.20 @@ -94,36 +93,37 @@
   13.21      /** Optional cache for weight of block nodes. */
   13.22      private final Map<Node, Long> weightCache;
   13.23  
   13.24 -    /*
   13.25 +    private final FunctionNode topFunction;
   13.26 +
   13.27 +    /**
   13.28       * Constructor
   13.29       *
   13.30       * @param weightCache cache of already calculated block weights
   13.31       */
   13.32 -    private WeighNodes(final Map<Node, Long> weightCache) {
   13.33 +    private WeighNodes(FunctionNode topFunction, final Map<Node, Long> weightCache) {
   13.34          super(null, null);
   13.35 +        this.topFunction = topFunction;
   13.36          this.weightCache = weightCache;
   13.37      }
   13.38  
   13.39      static long weigh(final Node node) {
   13.40 -        final WeighNodes weighNodes = new WeighNodes(null);
   13.41 -        node.accept(weighNodes);
   13.42 -        return weighNodes.weight;
   13.43 +        return weigh(node, null);
   13.44      }
   13.45  
   13.46      static long weigh(final Node node, final Map<Node, Long> weightCache) {
   13.47 -        final WeighNodes weighNodes = new WeighNodes(weightCache);
   13.48 +        final WeighNodes weighNodes = new WeighNodes(node instanceof FunctionNode ? (FunctionNode)node : null, weightCache);
   13.49          node.accept(weighNodes);
   13.50          return weighNodes.weight;
   13.51      }
   13.52  
   13.53      @Override
   13.54 -    public Node leave(final AccessNode accessNode) {
   13.55 +    public Node leaveAccessNode(final AccessNode accessNode) {
   13.56          weight += ACCESS_WEIGHT;
   13.57          return accessNode;
   13.58      }
   13.59  
   13.60      @Override
   13.61 -    public Node enter(final Block block) {
   13.62 +    public Node enterBlock(final Block block) {
   13.63          if (weightCache != null && weightCache.containsKey(block)) {
   13.64              weight += weightCache.get(block);
   13.65              return null;
   13.66 @@ -133,78 +133,79 @@
   13.67      }
   13.68  
   13.69      @Override
   13.70 -    public Node leave(final BreakNode breakNode) {
   13.71 +    public Node leaveBreakNode(final BreakNode breakNode) {
   13.72          weight += BREAK_WEIGHT;
   13.73          return breakNode;
   13.74      }
   13.75  
   13.76      @Override
   13.77 -    public Node leave(final CallNode callNode) {
   13.78 +    public Node leaveCallNode(final CallNode callNode) {
   13.79          weight += CALL_WEIGHT;
   13.80          return callNode;
   13.81      }
   13.82  
   13.83      @Override
   13.84 -    public Node leave(final CatchNode catchNode) {
   13.85 +    public Node leaveCatchNode(final CatchNode catchNode) {
   13.86          weight += CATCH_WEIGHT;
   13.87          return catchNode;
   13.88      }
   13.89  
   13.90      @Override
   13.91 -    public Node leave(final ContinueNode continueNode) {
   13.92 +    public Node leaveContinueNode(final ContinueNode continueNode) {
   13.93          weight += CONTINUE_WEIGHT;
   13.94          return continueNode;
   13.95      }
   13.96  
   13.97      @Override
   13.98 -    public Node leave(final DoWhileNode doWhileNode) {
   13.99 +    public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
  13.100          weight += LOOP_WEIGHT;
  13.101          return doWhileNode;
  13.102      }
  13.103  
  13.104      @Override
  13.105 -    public Node leave(final ExecuteNode executeNode) {
  13.106 +    public Node leaveExecuteNode(final ExecuteNode executeNode) {
  13.107          return executeNode;
  13.108      }
  13.109  
  13.110      @Override
  13.111 -    public Node leave(final ForNode forNode) {
  13.112 +    public Node leaveForNode(final ForNode forNode) {
  13.113          weight += LOOP_WEIGHT;
  13.114          return forNode;
  13.115      }
  13.116  
  13.117      @Override
  13.118 -    public Node enter(final FunctionNode functionNode) {
  13.119 -        final List<Node> statements = functionNode.getStatements();
  13.120 -
  13.121 -        for (final Node statement : statements) {
  13.122 -            statement.accept(this);
  13.123 +    public Node enterFunctionNode(final FunctionNode functionNode) {
  13.124 +        if(functionNode == topFunction) {
  13.125 +            // the function being weighted; descend into its statements
  13.126 +            functionNode.visitStatements(this);
  13.127 +        } else {
  13.128 +            // just a reference to inner function from outer function
  13.129 +            weight += FUNC_EXPR_WEIGHT;
  13.130          }
  13.131 -
  13.132          return null;
  13.133      }
  13.134  
  13.135      @Override
  13.136 -    public Node leave(final IdentNode identNode) {
  13.137 +    public Node leaveIdentNode(final IdentNode identNode) {
  13.138          weight += ACCESS_WEIGHT + identNode.getName().length() * 2;
  13.139          return identNode;
  13.140      }
  13.141  
  13.142      @Override
  13.143 -    public Node leave(final IfNode ifNode) {
  13.144 +    public Node leaveIfNode(final IfNode ifNode) {
  13.145          weight += IF_WEIGHT;
  13.146          return ifNode;
  13.147      }
  13.148  
  13.149      @Override
  13.150 -    public Node leave(final IndexNode indexNode) {
  13.151 +    public Node leaveIndexNode(final IndexNode indexNode) {
  13.152          weight += ACCESS_WEIGHT;
  13.153          return indexNode;
  13.154      }
  13.155  
  13.156      @SuppressWarnings("rawtypes")
  13.157      @Override
  13.158 -    public Node enter(final LiteralNode literalNode) {
  13.159 +    public Node enterLiteralNode(final LiteralNode literalNode) {
  13.160          weight += LITERAL_WEIGHT;
  13.161  
  13.162          if (literalNode instanceof ArrayLiteralNode) {
  13.163 @@ -230,67 +231,61 @@
  13.164      }
  13.165  
  13.166      @Override
  13.167 -    public Node leave(final PropertyNode propertyNode) {
  13.168 +    public Node leavePropertyNode(final PropertyNode propertyNode) {
  13.169          weight += LITERAL_WEIGHT;
  13.170          return propertyNode;
  13.171      }
  13.172  
  13.173      @Override
  13.174 -    public Node leave(final ReferenceNode referenceNode) {
  13.175 -        weight += REFERENCE_WEIGHT;
  13.176 -        return referenceNode;
  13.177 -    }
  13.178 -
  13.179 -    @Override
  13.180 -    public Node leave(final ReturnNode returnNode) {
  13.181 +    public Node leaveReturnNode(final ReturnNode returnNode) {
  13.182          weight += RETURN_WEIGHT;
  13.183          return returnNode;
  13.184      }
  13.185  
  13.186      @Override
  13.187 -    public Node leave(final RuntimeNode runtimeNode) {
  13.188 +    public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
  13.189          weight += CALL_WEIGHT;
  13.190          return runtimeNode;
  13.191      }
  13.192  
  13.193      @Override
  13.194 -    public Node enter(final SplitNode splitNode) {
  13.195 +    public Node enterSplitNode(final SplitNode splitNode) {
  13.196          weight += SPLIT_WEIGHT;
  13.197          return null;
  13.198      }
  13.199  
  13.200      @Override
  13.201 -    public Node leave(final SwitchNode switchNode) {
  13.202 +    public Node leaveSwitchNode(final SwitchNode switchNode) {
  13.203          weight += SWITCH_WEIGHT;
  13.204          return switchNode;
  13.205      }
  13.206  
  13.207      @Override
  13.208 -    public Node leave(final ThrowNode throwNode) {
  13.209 +    public Node leaveThrowNode(final ThrowNode throwNode) {
  13.210          weight += THROW_WEIGHT;
  13.211          return throwNode;
  13.212      }
  13.213  
  13.214      @Override
  13.215 -    public Node leave(final TryNode tryNode) {
  13.216 +    public Node leaveTryNode(final TryNode tryNode) {
  13.217          weight += THROW_WEIGHT;
  13.218          return tryNode;
  13.219      }
  13.220  
  13.221      @Override
  13.222 -    public Node leave(final VarNode varNode) {
  13.223 +    public Node leaveVarNode(final VarNode varNode) {
  13.224          weight += VAR_WEIGHT;
  13.225          return varNode;
  13.226      }
  13.227  
  13.228      @Override
  13.229 -    public Node leave(final WhileNode whileNode) {
  13.230 +    public Node leaveWhileNode(final WhileNode whileNode) {
  13.231          weight += LOOP_WEIGHT;
  13.232          return whileNode;
  13.233      }
  13.234  
  13.235      @Override
  13.236 -    public Node leave(final WithNode withNode) {
  13.237 +    public Node leaveWithNode(final WithNode withNode) {
  13.238          weight += WITH_WEIGHT;
  13.239          return withNode;
  13.240      }
    14.1 --- a/src/jdk/nashorn/internal/ir/AccessNode.java	Tue Mar 19 11:03:24 2013 -0300
    14.2 +++ b/src/jdk/nashorn/internal/ir/AccessNode.java	Sat Mar 23 00:58:39 2013 +0100
    14.3 @@ -36,7 +36,7 @@
    14.4   * IR representation of a property access (period operator.)
    14.5   *
    14.6   */
    14.7 -public class AccessNode extends BaseNode implements TypeOverride {
    14.8 +public class AccessNode extends BaseNode implements TypeOverride<AccessNode> {
    14.9      /** Property ident. */
   14.10      private IdentNode property;
   14.11  
   14.12 @@ -56,9 +56,7 @@
   14.13          super(source, token, finish, base);
   14.14  
   14.15          this.start    = base.getStart();
   14.16 -        this.property = property;
   14.17 -
   14.18 -        this.property.setIsPropertyName();
   14.19 +        this.property = property.setIsPropertyName();
   14.20      }
   14.21  
   14.22      /**
   14.23 @@ -106,10 +104,10 @@
   14.24       */
   14.25      @Override
   14.26      public Node accept(final NodeVisitor visitor) {
   14.27 -        if (visitor.enter(this) != null) {
   14.28 +        if (visitor.enterAccessNode(this) != null) {
   14.29              base = base.accept(visitor);
   14.30              property = (IdentNode)property.accept(visitor);
   14.31 -            return visitor.leave(this);
   14.32 +            return visitor.leaveAccessNode(this);
   14.33          }
   14.34  
   14.35          return this;
   14.36 @@ -150,13 +148,14 @@
   14.37      }
   14.38  
   14.39      @Override
   14.40 -    public void setType(final Type type) {
   14.41 +    public AccessNode setType(final Type type) {
   14.42          if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
   14.43              ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
   14.44          }
   14.45 -        property.setType(type);
   14.46 +        property = property.setType(type);
   14.47          getSymbol().setTypeOverride(type); //always a temp so this is fine.
   14.48          hasCallSiteType = true;
   14.49 +        return this;
   14.50      }
   14.51  
   14.52      @Override
    15.1 --- a/src/jdk/nashorn/internal/ir/Assignment.java	Tue Mar 19 11:03:24 2013 -0300
    15.2 +++ b/src/jdk/nashorn/internal/ir/Assignment.java	Sat Mar 23 00:58:39 2013 +0100
    15.3 @@ -46,4 +46,11 @@
    15.4       * @return get the assignment source node
    15.5       */
    15.6      public Node getAssignmentSource();
    15.7 +
    15.8 +    /**
    15.9 +     * Set assignment destination node.
   15.10 +     * @param n the assignment destination node.
   15.11 +     * @return a node equivalent to this one except for the requested change.
   15.12 +     */
   15.13 +    public Node setAssignmentDest(D n);
   15.14  }
    16.1 --- a/src/jdk/nashorn/internal/ir/BaseNode.java	Tue Mar 19 11:03:24 2013 -0300
    16.2 +++ b/src/jdk/nashorn/internal/ir/BaseNode.java	Sat Mar 23 00:58:39 2013 +0100
    16.3 @@ -38,6 +38,8 @@
    16.4      /** Base Node. */
    16.5      protected Node base;
    16.6  
    16.7 +    private boolean function;
    16.8 +
    16.9      /**
   16.10       * Constructor
   16.11       *
   16.12 @@ -96,6 +98,15 @@
   16.13  
   16.14      @Override
   16.15      public boolean isFunction() {
   16.16 -        return false;
   16.17 +        return function;
   16.18 +    }
   16.19 +
   16.20 +    /**
   16.21 +     * Mark this node as being the callee operand of a {@link CallNode}.
   16.22 +     * @return a base node identical to this one in all aspects except with its function flag set.
   16.23 +     */
   16.24 +    public BaseNode setIsFunction() {
   16.25 +        function = true;
   16.26 +        return this;
   16.27      }
   16.28  }
    17.1 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java	Tue Mar 19 11:03:24 2013 -0300
    17.2 +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java	Sat Mar 23 00:58:39 2013 +0100
    17.3 @@ -35,7 +35,7 @@
    17.4   */
    17.5  public class BinaryNode extends UnaryNode {
    17.6      /** Left hand side argument. */
    17.7 -    protected Node lhs;
    17.8 +    private Node lhs;
    17.9  
   17.10      /**
   17.11       * Constructor
   17.12 @@ -140,6 +140,11 @@
   17.13      }
   17.14  
   17.15      @Override
   17.16 +    public Node setAssignmentDest(Node n) {
   17.17 +        return setLHS(n);
   17.18 +    }
   17.19 +
   17.20 +    @Override
   17.21      public Node getAssignmentSource() {
   17.22          return rhs();
   17.23      }
   17.24 @@ -163,10 +168,9 @@
   17.25       */
   17.26      @Override
   17.27      public Node accept(final NodeVisitor visitor) {
   17.28 -        if (visitor.enter(this) != null) {
   17.29 -            lhs = lhs.accept(visitor);
   17.30 -            rhs = rhs.accept(visitor);
   17.31 -            return visitor.leave(this);
   17.32 +        if (visitor.enterBinaryNode(this) != null) {
   17.33 +            // TODO: good cause for a separate visitMembers: we could delegate to UnaryNode.visitMembers
   17.34 +            return visitor.leaveBinaryNode((BinaryNode)setLHS(lhs.accept(visitor)).setRHS(rhs().accept(visitor)));
   17.35          }
   17.36  
   17.37          return this;
   17.38 @@ -229,8 +233,12 @@
   17.39      /**
   17.40       * Set the left hand side expression for this node
   17.41       * @param lhs new left hand side expression
   17.42 +     * @return a node equivalent to this one except for the requested change.
   17.43       */
   17.44 -    public void setLHS(final Node lhs) {
   17.45 -        this.lhs = lhs;
   17.46 +    public BinaryNode setLHS(final Node lhs) {
   17.47 +        if(this.lhs == lhs) return this;
   17.48 +        final BinaryNode n = (BinaryNode)clone();
   17.49 +        n.lhs = lhs;
   17.50 +        return n;
   17.51      }
   17.52  }
    18.1 --- a/src/jdk/nashorn/internal/ir/Block.java	Tue Mar 19 11:03:24 2013 -0300
    18.2 +++ b/src/jdk/nashorn/internal/ir/Block.java	Sat Mar 23 00:58:39 2013 +0100
    18.3 @@ -25,14 +25,6 @@
    18.4  
    18.5  package jdk.nashorn.internal.ir;
    18.6  
    18.7 -import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
    18.8 -import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
    18.9 -import static jdk.nashorn.internal.ir.Symbol.IS_LET;
   18.10 -import static jdk.nashorn.internal.ir.Symbol.IS_PARAM;
   18.11 -import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE;
   18.12 -import static jdk.nashorn.internal.ir.Symbol.IS_VAR;
   18.13 -import static jdk.nashorn.internal.ir.Symbol.KINDMASK;
   18.14 -
   18.15  import java.io.PrintWriter;
   18.16  import java.util.ArrayList;
   18.17  import java.util.Collections;
   18.18 @@ -40,9 +32,9 @@
   18.19  import java.util.HashMap;
   18.20  import java.util.Iterator;
   18.21  import java.util.List;
   18.22 +import java.util.ListIterator;
   18.23  import jdk.nashorn.internal.codegen.Frame;
   18.24  import jdk.nashorn.internal.codegen.Label;
   18.25 -import jdk.nashorn.internal.ir.annotations.Reference;
   18.26  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   18.27  import jdk.nashorn.internal.runtime.Source;
   18.28  
   18.29 @@ -51,14 +43,6 @@
   18.30   * basis for script body.
   18.31   */
   18.32  public class Block extends Node {
   18.33 -    /** Parent context */
   18.34 -    @Reference
   18.35 -    private Block parent;
   18.36 -
   18.37 -    /** Owning function - a FunctionNode has itself as function */
   18.38 -    @Reference
   18.39 -    protected FunctionNode function;
   18.40 -
   18.41      /** List of statements */
   18.42      protected List<Node> statements;
   18.43  
   18.44 @@ -83,14 +67,10 @@
   18.45       * @param source   source code
   18.46       * @param token    token
   18.47       * @param finish   finish
   18.48 -     * @param parent   reference to parent block
   18.49 -     * @param function function node this block is in
   18.50       */
   18.51 -    public Block(final Source source, final long token, final int finish, final Block parent, final FunctionNode function) {
   18.52 +    public Block(final Source source, final long token, final int finish) {
   18.53          super(source, token, finish);
   18.54  
   18.55 -        this.parent     = parent;
   18.56 -        this.function   = function;
   18.57          this.statements = new ArrayList<>();
   18.58          this.symbols    = new HashMap<>();
   18.59          this.entryLabel = new Label("block_entry");
   18.60 @@ -106,8 +86,6 @@
   18.61      protected Block(final Block block, final CopyState cs) {
   18.62          super(block);
   18.63  
   18.64 -        this.parent     = block.parent;
   18.65 -        this.function   = block.function;
   18.66          this.statements = new ArrayList<>();
   18.67          for (final Node statement : block.getStatements()) {
   18.68              statements.add(cs.existingOrCopy(statement));
   18.69 @@ -122,55 +100,7 @@
   18.70  
   18.71      @Override
   18.72      protected Node copy(final CopyState cs) {
   18.73 -        return fixBlockChain(new Block(this, cs));
   18.74 -    }
   18.75 -
   18.76 -    /**
   18.77 -     * Whenever a clone that contains a hierarchy of blocks is created,
   18.78 -     * this function has to be called to ensure that the parents point
   18.79 -     * to the correct parent blocks or two different ASTs would not
   18.80 -     * be completely separated.
   18.81 -     *
   18.82 -     * @return the argument
   18.83 -     */
   18.84 -    static Block fixBlockChain(final Block root) {
   18.85 -        root.accept(new NodeVisitor() {
   18.86 -            private Block        parent   = root.getParent();
   18.87 -            private final FunctionNode function = root.getFunction();
   18.88 -
   18.89 -            @Override
   18.90 -            public Node enter(final Block block) {
   18.91 -                assert block.getFunction() == function;
   18.92 -                block.setParent(parent);
   18.93 -                parent = block;
   18.94 -
   18.95 -                return block;
   18.96 -            }
   18.97 -
   18.98 -            @Override
   18.99 -            public Node leave(final Block block) {
  18.100 -                parent = block.getParent();
  18.101 -
  18.102 -                return block;
  18.103 -            }
  18.104 -
  18.105 -            @Override
  18.106 -            public Node enter(final FunctionNode functionNode) {
  18.107 -                assert functionNode.getFunction() == function;
  18.108 -
  18.109 -                return enter((Block)functionNode);
  18.110 -            }
  18.111 -
  18.112 -            @Override
  18.113 -            public Node leave(final FunctionNode functionNode) {
  18.114 -                assert functionNode.getFunction() == function;
  18.115 -
  18.116 -                return leave((Block)functionNode);
  18.117 -            }
  18.118 -
  18.119 -        });
  18.120 -
  18.121 -        return root;
  18.122 +        return new Block(this, cs);
  18.123      }
  18.124  
  18.125      /**
  18.126 @@ -188,17 +118,12 @@
  18.127      }
  18.128  
  18.129      /**
  18.130 -     * Prepend a statement to the statement list
  18.131 +     * Prepend statements to the statement list
  18.132       *
  18.133 -     * @param statement Statement node to add
  18.134 +     * @param prepended statement to add
  18.135       */
  18.136 -    public void prependStatement(final Node statement) {
  18.137 -        if (statement != null) {
  18.138 -            final List<Node> newStatements = new ArrayList<>();
  18.139 -            newStatements.add(statement);
  18.140 -            newStatements.addAll(statements);
  18.141 -            setStatements(newStatements);
  18.142 -        }
  18.143 +    public void prependStatements(final List<Node> prepended) {
  18.144 +        statements.addAll(0, prepended);
  18.145      }
  18.146  
  18.147      /**
  18.148 @@ -211,39 +136,6 @@
  18.149      }
  18.150  
  18.151      /**
  18.152 -     * Add a new function to the function list.
  18.153 -     *
  18.154 -     * @param functionNode Function node to add.
  18.155 -     */
  18.156 -    public void addFunction(final FunctionNode functionNode) {
  18.157 -        assert parent != null : "Parent context missing.";
  18.158 -
  18.159 -        parent.addFunction(functionNode);
  18.160 -    }
  18.161 -
  18.162 -    /**
  18.163 -     * Add a list of functions to the function list.
  18.164 -     *
  18.165 -     * @param functionNodes Function nodes to add.
  18.166 -     */
  18.167 -    public void addFunctions(final List<FunctionNode> functionNodes) {
  18.168 -        assert parent != null : "Parent context missing.";
  18.169 -
  18.170 -        parent.addFunctions(functionNodes);
  18.171 -    }
  18.172 -
  18.173 -    /**
  18.174 -     * Set the function list to a new one
  18.175 -     *
  18.176 -     * @param functionNodes the nodes to set
  18.177 -     */
  18.178 -    public void setFunctions(final List<FunctionNode> functionNodes) {
  18.179 -        assert parent != null : "Parent context missing.";
  18.180 -
  18.181 -        parent.setFunctions(functionNodes);
  18.182 -    }
  18.183 -
  18.184 -    /**
  18.185       * Assist in IR navigation.
  18.186       *
  18.187       * @param visitor IR navigating visitor.
  18.188 @@ -257,13 +149,9 @@
  18.189          try {
  18.190              // Ignore parent to avoid recursion.
  18.191  
  18.192 -            if (visitor.enter(this) != null) {
  18.193 -                for (int i = 0, count = statements.size(); i < count; i++) {
  18.194 -                    final Node statement = statements.get(i);
  18.195 -                    statements.set(i, statement.accept(visitor));
  18.196 -                }
  18.197 -
  18.198 -                return visitor.leave(this);
  18.199 +            if (visitor.enterBlock(this) != null) {
  18.200 +                visitStatements(visitor);
  18.201 +                return visitor.leaveBlock(this);
  18.202              }
  18.203          } finally {
  18.204              visitor.setCurrentBlock(saveBlock);
  18.205 @@ -281,51 +169,13 @@
  18.206      }
  18.207  
  18.208      /**
  18.209 -     * Search for symbol.
  18.210 -     *
  18.211 -     * @param name Symbol name.
  18.212 -     *
  18.213 -     * @return Found symbol or null if not found.
  18.214 +     * Retrieves an existing symbol defined in the current block.
  18.215 +     * @param name the name of the symbol
  18.216 +     * @return an existing symbol with the specified name defined in the current block, or null if this block doesn't
  18.217 +     * define a symbol with this name.
  18.218       */
  18.219 -    public Symbol findSymbol(final String name) {
  18.220 -        // Search up block chain to locate symbol.
  18.221 -
  18.222 -        for (Block block = this; block != null; block = block.getParent()) {
  18.223 -            // Find name.
  18.224 -            final Symbol symbol = block.symbols.get(name);
  18.225 -            // If found then we are good.
  18.226 -            if (symbol != null) {
  18.227 -                return symbol;
  18.228 -            }
  18.229 -        }
  18.230 -        return null;
  18.231 -    }
  18.232 -
  18.233 -    /**
  18.234 -     * Search for symbol in current function.
  18.235 -     *
  18.236 -     * @param name Symbol name.
  18.237 -     *
  18.238 -     * @return Found symbol or null if not found.
  18.239 -     */
  18.240 -    public Symbol findLocalSymbol(final String name) {
  18.241 -        // Search up block chain to locate symbol.
  18.242 -        for (Block block = this; block != null; block = block.getParent()) {
  18.243 -            // Find name.
  18.244 -            final Symbol symbol = block.symbols.get(name);
  18.245 -            // If found then we are good.
  18.246 -            if (symbol != null) {
  18.247 -                return symbol;
  18.248 -            }
  18.249 -
  18.250 -            // If searched function then we are done.
  18.251 -            if (block == block.function) {
  18.252 -                break;
  18.253 -            }
  18.254 -        }
  18.255 -
  18.256 -        // Not found.
  18.257 -        return null;
  18.258 +    public Symbol getExistingSymbol(final String name) {
  18.259 +        return symbols.get(name);
  18.260      }
  18.261  
  18.262      /**
  18.263 @@ -338,122 +188,6 @@
  18.264          return statements.size() == 1 && statements.get(0) instanceof CatchNode;
  18.265      }
  18.266  
  18.267 -    /**
  18.268 -     * Test to see if a symbol is local to the function.
  18.269 -     *
  18.270 -     * @param symbol Symbol to test.
  18.271 -     * @return True if a local symbol.
  18.272 -     */
  18.273 -    public boolean isLocal(final Symbol symbol) {
  18.274 -        // some temp symbols have no block, so can be assumed local
  18.275 -        final Block block = symbol.getBlock();
  18.276 -        return block == null || block.getFunction() == function;
  18.277 -    }
  18.278 -
  18.279 -    /**
  18.280 -     * Declare the definition of a new symbol.
  18.281 -     *
  18.282 -     * @param name         Name of symbol.
  18.283 -     * @param symbolFlags  Symbol flags.
  18.284 -     * @param node         Defining Node.
  18.285 -     *
  18.286 -     * @return Symbol for given name or null for redefinition.
  18.287 -     */
  18.288 -    public Symbol defineSymbol(final String name, final int symbolFlags, final Node node) {
  18.289 -        int    flags  = symbolFlags;
  18.290 -        Symbol symbol = findSymbol(name); // Locate symbol.
  18.291 -
  18.292 -        if ((flags & KINDMASK) == IS_GLOBAL) {
  18.293 -            flags |= IS_SCOPE;
  18.294 -        }
  18.295 -
  18.296 -        if (symbol != null) {
  18.297 -            // Symbol was already defined. Check if it needs to be redefined.
  18.298 -            if ((flags & KINDMASK) == IS_PARAM) {
  18.299 -                if (!function.isLocal(symbol)) {
  18.300 -                    // Not defined in this function. Create a new definition.
  18.301 -                    symbol = null;
  18.302 -                } else if (symbol.isParam()) {
  18.303 -                    // Duplicate parameter. Null return will force an error.
  18.304 -                    assert false : "duplicate parameter";
  18.305 -                    return null;
  18.306 -                }
  18.307 -            } else if ((flags & KINDMASK) == IS_VAR) {
  18.308 -                if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & Symbol.IS_LET) == Symbol.IS_LET) {
  18.309 -                    assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == this) : "duplicate let variable in block";
  18.310 -                    // Always create a new definition.
  18.311 -                    symbol = null;
  18.312 -                } else {
  18.313 -                    // Not defined in this function. Create a new definition.
  18.314 -                    if (!function.isLocal(symbol) || symbol.less(IS_VAR)) {
  18.315 -                        symbol = null;
  18.316 -                    }
  18.317 -                }
  18.318 -            }
  18.319 -        }
  18.320 -
  18.321 -        if (symbol == null) {
  18.322 -            // If not found, then create a new one.
  18.323 -            Block symbolBlock;
  18.324 -
  18.325 -            // Determine where to create it.
  18.326 -            if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
  18.327 -                symbolBlock = this;
  18.328 -            } else {
  18.329 -                symbolBlock = getFunction();
  18.330 -            }
  18.331 -
  18.332 -            // Create and add to appropriate block.
  18.333 -            symbol = new Symbol(name, flags, node, symbolBlock);
  18.334 -            symbolBlock.putSymbol(name, symbol);
  18.335 -
  18.336 -            if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
  18.337 -                symbolBlock.getFrame().addSymbol(symbol);
  18.338 -                symbol.setNeedsSlot(true);
  18.339 -            }
  18.340 -        } else if (symbol.less(flags)) {
  18.341 -            symbol.setFlags(flags);
  18.342 -        }
  18.343 -
  18.344 -        if (node != null) {
  18.345 -            node.setSymbol(symbol);
  18.346 -        }
  18.347 -
  18.348 -        return symbol;
  18.349 -    }
  18.350 -
  18.351 -    /**
  18.352 -     * Declare the use of a symbol.
  18.353 -     *
  18.354 -     * @param name Name of symbol.
  18.355 -     * @param node Using node
  18.356 -     *
  18.357 -     * @return Symbol for given name.
  18.358 -     */
  18.359 -    public Symbol useSymbol(final String name, final Node node) {
  18.360 -        Symbol symbol = findSymbol(name);
  18.361 -
  18.362 -        if (symbol == null) {
  18.363 -            // If not found, declare as a free var.
  18.364 -            symbol = defineSymbol(name, IS_GLOBAL, node);
  18.365 -        } else {
  18.366 -            node.setSymbol(symbol);
  18.367 -        }
  18.368 -
  18.369 -        return symbol;
  18.370 -    }
  18.371 -
  18.372 -    /**
  18.373 -     * Add parent name to the builder.
  18.374 -     *
  18.375 -     * @param sb String bulder.
  18.376 -     */
  18.377 -    public void addParentName(final StringBuilder sb) {
  18.378 -        if (parent != null) {
  18.379 -            parent.addParentName(sb);
  18.380 -        }
  18.381 -    }
  18.382 -
  18.383      @Override
  18.384      public void toString(final StringBuilder sb) {
  18.385          for (final Node statement : statements) {
  18.386 @@ -512,16 +246,6 @@
  18.387      }
  18.388  
  18.389      /**
  18.390 -     * Get the FunctionNode for this block, i.e. the function it
  18.391 -     * belongs to
  18.392 -     *
  18.393 -     * @return the function node
  18.394 -     */
  18.395 -    public FunctionNode getFunction() {
  18.396 -        return function;
  18.397 -    }
  18.398 -
  18.399 -    /**
  18.400       * Reset the frame for this block
  18.401       *
  18.402       * @param frame  the new frame
  18.403 @@ -531,24 +255,6 @@
  18.404      }
  18.405  
  18.406      /**
  18.407 -     * Get the parent block
  18.408 -     *
  18.409 -     * @return parent block, or null if none exists
  18.410 -     */
  18.411 -    public Block getParent() {
  18.412 -        return parent;
  18.413 -    }
  18.414 -
  18.415 -    /**
  18.416 -     * Set the parent block
  18.417 -     *
  18.418 -     * @param parent the new parent block
  18.419 -     */
  18.420 -    public void setParent(final Block parent) {
  18.421 -        this.parent = parent;
  18.422 -    }
  18.423 -
  18.424 -    /**
  18.425       * Get the list of statements in this block
  18.426       *
  18.427       * @return a list of statements
  18.428 @@ -558,6 +264,15 @@
  18.429      }
  18.430  
  18.431      /**
  18.432 +     * Applies the specified visitor to all statements in the block.
  18.433 +     * @param visitor the visitor.
  18.434 +     */
  18.435 +    public void visitStatements(NodeVisitor visitor) {
  18.436 +        for (ListIterator<Node> stmts = statements.listIterator(); stmts.hasNext();) {
  18.437 +            stmts.set(stmts.next().accept(visitor));
  18.438 +        }
  18.439 +    }
  18.440 +    /**
  18.441       * Reset the statement list for this block
  18.442       *
  18.443       * @param statements  new statement list
  18.444 @@ -592,4 +307,29 @@
  18.445          needsScope = true;
  18.446      }
  18.447  
  18.448 +    /**
  18.449 +     * Marks this block as using a specified scoped symbol. The block and its parent blocks up to but not
  18.450 +     * including the block defining the symbol will be marked as needing parent scope. The block defining the symbol
  18.451 +     * will be marked as one that needs to have its own scope.
  18.452 +     * @param symbol the symbol being used.
  18.453 +     * @param ancestors the iterator over block's containing lexical context
  18.454 +     */
  18.455 +    public void setUsesScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) {
  18.456 +        if(symbol.getBlock() == this) {
  18.457 +            setNeedsScope();
  18.458 +        } else {
  18.459 +            setUsesParentScopeSymbol(symbol, ancestors);
  18.460 +        }
  18.461 +    }
  18.462 +
  18.463 +    /**
  18.464 +     * Invoked when this block uses a scope symbol defined in one of its ancestors.
  18.465 +     * @param symbol the scope symbol being used
  18.466 +     * @param ancestors iterator over ancestor blocks
  18.467 +     */
  18.468 +    void setUsesParentScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) {
  18.469 +        if(ancestors.hasNext()) {
  18.470 +            ancestors.next().setUsesScopeSymbol(symbol, ancestors);
  18.471 +        }
  18.472 +    }
  18.473  }
    19.1 --- a/src/jdk/nashorn/internal/ir/BreakNode.java	Tue Mar 19 11:03:24 2013 -0300
    19.2 +++ b/src/jdk/nashorn/internal/ir/BreakNode.java	Sat Mar 23 00:58:39 2013 +0100
    19.3 @@ -64,8 +64,8 @@
    19.4       */
    19.5      @Override
    19.6      public Node accept(final NodeVisitor visitor) {
    19.7 -        if (visitor.enter(this) != null) {
    19.8 -            return visitor.leave(this);
    19.9 +        if (visitor.enterBreakNode(this) != null) {
   19.10 +            return visitor.leaveBreakNode(this);
   19.11          }
   19.12  
   19.13          return this;
    20.1 --- a/src/jdk/nashorn/internal/ir/CallNode.java	Tue Mar 19 11:03:24 2013 -0300
    20.2 +++ b/src/jdk/nashorn/internal/ir/CallNode.java	Sat Mar 23 00:58:39 2013 +0100
    20.3 @@ -37,7 +37,7 @@
    20.4   * IR representation for a function call.
    20.5   *
    20.6   */
    20.7 -public class CallNode extends Node implements TypeOverride {
    20.8 +public class CallNode extends Node implements TypeOverride<CallNode> {
    20.9  
   20.10      private Type type;
   20.11  
   20.12 @@ -176,13 +176,13 @@
   20.13          if (hasCallSiteType()) {
   20.14              return type;
   20.15          }
   20.16 -        assert !function.getType().isUnknown();
   20.17 -        return function.getType();
   20.18 +        return function instanceof FunctionNode ? ((FunctionNode)function).getReturnType() : Type.OBJECT;
   20.19      }
   20.20  
   20.21      @Override
   20.22 -    public void setType(final Type type) {
   20.23 +    public CallNode setType(final Type type) {
   20.24          this.type = type;
   20.25 +        return this;
   20.26      }
   20.27  
   20.28      private boolean hasCallSiteType() {
   20.29 @@ -208,14 +208,14 @@
   20.30       */
   20.31      @Override
   20.32      public Node accept(final NodeVisitor visitor) {
   20.33 -        if (visitor.enter(this) != null) {
   20.34 +        if (visitor.enterCallNode(this) != null) {
   20.35              function = function.accept(visitor);
   20.36  
   20.37              for (int i = 0, count = args.size(); i < count; i++) {
   20.38                  args.set(i, args.get(i).accept(visitor));
   20.39              }
   20.40  
   20.41 -            return visitor.leave(this);
   20.42 +            return visitor.leaveCallNode(this);
   20.43          }
   20.44  
   20.45          return this;
    21.1 --- a/src/jdk/nashorn/internal/ir/CaseNode.java	Tue Mar 19 11:03:24 2013 -0300
    21.2 +++ b/src/jdk/nashorn/internal/ir/CaseNode.java	Sat Mar 23 00:58:39 2013 +0100
    21.3 @@ -79,7 +79,7 @@
    21.4       */
    21.5      @Override
    21.6      public Node accept(final NodeVisitor visitor) {
    21.7 -        if (visitor.enter(this) != null) {
    21.8 +        if (visitor.enterCaseNode(this) != null) {
    21.9              if (test != null) {
   21.10                  test = test.accept(visitor);
   21.11              }
   21.12 @@ -87,7 +87,7 @@
   21.13                  body = (Block)body.accept(visitor);
   21.14              }
   21.15  
   21.16 -            return visitor.leave(this);
   21.17 +            return visitor.leaveCaseNode(this);
   21.18          }
   21.19  
   21.20          return this;
    22.1 --- a/src/jdk/nashorn/internal/ir/CatchNode.java	Tue Mar 19 11:03:24 2013 -0300
    22.2 +++ b/src/jdk/nashorn/internal/ir/CatchNode.java	Sat Mar 23 00:58:39 2013 +0100
    22.3 @@ -84,7 +84,7 @@
    22.4       */
    22.5      @Override
    22.6      public Node accept(final NodeVisitor visitor) {
    22.7 -        if (visitor.enter(this) != null) {
    22.8 +        if (visitor.enterCatchNode(this) != null) {
    22.9              exception = (IdentNode)exception.accept(visitor);
   22.10  
   22.11              if (exceptionCondition != null) {
   22.12 @@ -92,7 +92,7 @@
   22.13              }
   22.14  
   22.15              body = (Block)body.accept(visitor);
   22.16 -            return visitor.leave(this);
   22.17 +            return visitor.leaveCatchNode(this);
   22.18          }
   22.19  
   22.20          return this;
    23.1 --- a/src/jdk/nashorn/internal/ir/ContinueNode.java	Tue Mar 19 11:03:24 2013 -0300
    23.2 +++ b/src/jdk/nashorn/internal/ir/ContinueNode.java	Sat Mar 23 00:58:39 2013 +0100
    23.3 @@ -61,8 +61,8 @@
    23.4  
    23.5      @Override
    23.6      public Node accept(final NodeVisitor visitor) {
    23.7 -        if (visitor.enter(this) != null) {
    23.8 -            return visitor.leave(this);
    23.9 +        if (visitor.enterContinueNode(this) != null) {
   23.10 +            return visitor.leaveContinueNode(this);
   23.11          }
   23.12  
   23.13          return this;
    24.1 --- a/src/jdk/nashorn/internal/ir/DoWhileNode.java	Tue Mar 19 11:03:24 2013 -0300
    24.2 +++ b/src/jdk/nashorn/internal/ir/DoWhileNode.java	Sat Mar 23 00:58:39 2013 +0100
    24.3 @@ -63,11 +63,11 @@
    24.4  
    24.5      @Override
    24.6      public Node accept(final NodeVisitor visitor) {
    24.7 -        if (visitor.enter(this) != null) {
    24.8 +        if (visitor.enterDoWhileNode(this) != null) {
    24.9              body = (Block)body.accept(visitor);
   24.10              test = test.accept(visitor);
   24.11  
   24.12 -            return visitor.leave(this);
   24.13 +            return visitor.leaveDoWhileNode(this);
   24.14          }
   24.15  
   24.16          return this;
    25.1 --- a/src/jdk/nashorn/internal/ir/EmptyNode.java	Tue Mar 19 11:03:24 2013 -0300
    25.2 +++ b/src/jdk/nashorn/internal/ir/EmptyNode.java	Sat Mar 23 00:58:39 2013 +0100
    25.3 @@ -57,8 +57,8 @@
    25.4  
    25.5      @Override
    25.6      public Node accept(final NodeVisitor visitor) {
    25.7 -        if (visitor.enter(this) != null) {
    25.8 -            return visitor.leave(this);
    25.9 +        if (visitor.enterEmptyNode(this) != null) {
   25.10 +            return visitor.leaveEmptyNode(this);
   25.11          }
   25.12          return this;
   25.13      }
    26.1 --- a/src/jdk/nashorn/internal/ir/ExecuteNode.java	Tue Mar 19 11:03:24 2013 -0300
    26.2 +++ b/src/jdk/nashorn/internal/ir/ExecuteNode.java	Sat Mar 23 00:58:39 2013 +0100
    26.3 @@ -85,9 +85,9 @@
    26.4  
    26.5      @Override
    26.6      public Node accept(final NodeVisitor visitor) {
    26.7 -        if (visitor.enter(this) != null) {
    26.8 +        if (visitor.enterExecuteNode(this) != null) {
    26.9              setExpression(expression.accept(visitor));
   26.10 -            return visitor.leave(this);
   26.11 +            return visitor.leaveExecuteNode(this);
   26.12          }
   26.13  
   26.14          return this;
    27.1 --- a/src/jdk/nashorn/internal/ir/ForNode.java	Tue Mar 19 11:03:24 2013 -0300
    27.2 +++ b/src/jdk/nashorn/internal/ir/ForNode.java	Sat Mar 23 00:58:39 2013 +0100
    27.3 @@ -76,7 +76,7 @@
    27.4  
    27.5      @Override
    27.6      public Node accept(final NodeVisitor visitor) {
    27.7 -        if (visitor.enter(this) != null) {
    27.8 +        if (visitor.enterForNode(this) != null) {
    27.9              if (init != null) {
   27.10                  init = init.accept(visitor);
   27.11              }
   27.12 @@ -91,7 +91,7 @@
   27.13  
   27.14              body = (Block)body.accept(visitor);
   27.15  
   27.16 -            return visitor.leave(this);
   27.17 +            return visitor.leaveForNode(this);
   27.18          }
   27.19  
   27.20          return this;
    28.1 --- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Tue Mar 19 11:03:24 2013 -0300
    28.2 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Sat Mar 23 00:58:39 2013 +0100
    28.3 @@ -34,7 +34,7 @@
    28.4  import java.util.Collections;
    28.5  import java.util.EnumSet;
    28.6  import java.util.HashMap;
    28.7 -import java.util.LinkedList;
    28.8 +import java.util.Iterator;
    28.9  import java.util.List;
   28.10  import java.util.Map;
   28.11  import java.util.Stack;
   28.12 @@ -47,7 +47,7 @@
   28.13  import jdk.nashorn.internal.ir.annotations.Ignore;
   28.14  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   28.15  import jdk.nashorn.internal.parser.Parser;
   28.16 -import jdk.nashorn.internal.runtime.Debug;
   28.17 +import jdk.nashorn.internal.runtime.ScriptFunction;
   28.18  import jdk.nashorn.internal.runtime.Source;
   28.19  import jdk.nashorn.internal.runtime.UserAccessorProperty;
   28.20  import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
   28.21 @@ -57,6 +57,8 @@
   28.22   */
   28.23  public class FunctionNode extends Block {
   28.24  
   28.25 +    private static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
   28.26 +
   28.27      /** Function kinds */
   28.28      public enum Kind {
   28.29          /** a normal function - nothing special */
   28.30 @@ -112,9 +114,6 @@
   28.31      /** List of parameters. */
   28.32      private List<IdentNode> parameters;
   28.33  
   28.34 -    /** List of nested functions. */
   28.35 -    private List<FunctionNode> functions;
   28.36 -
   28.37      /** First token of function. **/
   28.38      private long firstToken;
   28.39  
   28.40 @@ -157,10 +156,6 @@
   28.41      /** Pending control list. */
   28.42      private final Stack<Node> controlStack;
   28.43  
   28.44 -    /** Variable declarations in the function's scope */
   28.45 -    @Ignore
   28.46 -    private final List<VarNode> declarations;
   28.47 -
   28.48      /** VarNode for this function statement */
   28.49      @Ignore //this is explicit code anyway and should not be traversed after lower
   28.50      private VarNode funcVarNode;
   28.51 @@ -184,33 +179,35 @@
   28.52      private int flags;
   28.53  
   28.54      /** Is anonymous function flag. */
   28.55 -    private static final int IS_ANONYMOUS                = 0b0000_0000_0000_0001;
   28.56 -    /** Is statement flag */
   28.57 -    private static final int IS_STATEMENT                = 0b0000_0000_0000_0010;
   28.58 +    private static final int IS_ANONYMOUS                = 1 << 0;
   28.59 +    /** Is the function created in a function declaration (as opposed to a function expression) */
   28.60 +    private static final int IS_DECLARED                 = 1 << 1;
   28.61      /** is this a strict mode function? */
   28.62 -    private static final int IS_STRICT_MODE              = 0b0000_0000_0000_0100;
   28.63 +    private static final int IS_STRICT_MODE              = 1 << 2;
   28.64      /** Does the function use the "arguments" identifier ? */
   28.65 -    private static final int USES_ARGUMENTS              = 0b0000_0000_0000_1000;
   28.66 +    private static final int USES_ARGUMENTS              = 1 << 3;
   28.67      /** Are we lowered ? */
   28.68 -    private static final int IS_LOWERED                  = 0b0000_0000_0001_0000;
   28.69 +    private static final int IS_LOWERED                  = 1 << 4;
   28.70      /** Has this node been split because it was too large? */
   28.71 -    private static final int IS_SPLIT                    = 0b0000_0000_0010_0000;
   28.72 +    private static final int IS_SPLIT                    = 1 << 5;
   28.73      /** Does the function call eval? */
   28.74 -    private static final int HAS_EVAL                    = 0b0000_0000_0100_0000;
   28.75 +    private static final int HAS_EVAL                    = 1 << 6;
   28.76      /** Does the function contain a with block ? */
   28.77 -    private static final int HAS_WITH                    = 0b0000_0000_1000_0000;
   28.78 +    private static final int HAS_WITH                    = 1 << 7;
   28.79      /** Does a descendant function contain a with or eval? */
   28.80 -    private static final int HAS_DESCENDANT_WITH_OR_EVAL = 0b0000_0001_0000_0000;
   28.81 +    private static final int HAS_DESCENDANT_WITH_OR_EVAL = 1 << 8;
   28.82      /** Does the function define "arguments" identifier as a parameter of nested function name? */
   28.83 -    private static final int DEFINES_ARGUMENTS           = 0b0000_0010_0000_0000;
   28.84 +    private static final int DEFINES_ARGUMENTS           = 1 << 9;
   28.85      /** Does the function need a self symbol? */
   28.86 -    private static final int NEEDS_SELF_SYMBOL           = 0b0000_0100_0000_0000;
   28.87 +    private static final int NEEDS_SELF_SYMBOL           = 1 << 10;
   28.88      /** Does this function or any of its descendants use variables from an ancestor function's scope (incl. globals)? */
   28.89 -    private static final int USES_ANCESTOR_SCOPE         = 0b0000_1000_0000_0000;
   28.90 +    private static final int USES_ANCESTOR_SCOPE         = 1 << 11;
   28.91      /** Is this function lazily compiled? */
   28.92 -    private static final int IS_LAZY                     = 0b0001_0000_0000_0000;
   28.93 +    private static final int IS_LAZY                     = 1 << 12;
   28.94      /** Does this function have lazy, yet uncompiled children */
   28.95 -    private static final int HAS_LAZY_CHILDREN           = 0b0010_0000_0000_0000;
   28.96 +    private static final int HAS_LAZY_CHILDREN           = 1 << 13;
   28.97 +    /** Does this function have lazy, yet uncompiled children */
   28.98 +    private static final int IS_PROGRAM                   = 1 << 14;
   28.99  
  28.100      /** Does this function or any nested functions contain a with or an eval? */
  28.101      private static final int HAS_DEEP_WITH_OR_EVAL = HAS_EVAL | HAS_WITH | HAS_DESCENDANT_WITH_OR_EVAL;
  28.102 @@ -226,56 +223,34 @@
  28.103      private Type returnType = Type.UNKNOWN;
  28.104  
  28.105      /**
  28.106 -     * Used to keep track of a function's parent blocks.
  28.107 -     * This is needed when a (finally body) block is cloned than contains inner functions.
  28.108 -     * Does not include function.getParent().
  28.109 -     */
  28.110 -    @Ignore
  28.111 -    private List<Block> referencingParentBlocks;
  28.112 -
  28.113 -    /**
  28.114       * Constructor
  28.115       *
  28.116       * @param source    the source
  28.117       * @param token     token
  28.118       * @param finish    finish
  28.119       * @param namespace the namespace
  28.120 -     * @param parent    the parent block
  28.121       * @param ident     the identifier
  28.122       * @param name      the name of the function
  28.123       */
  28.124 -    @SuppressWarnings("LeakingThisInConstructor")
  28.125 -    public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final Block parent, final IdentNode ident, final String name) {
  28.126 -        super(source, token, finish, parent, null);
  28.127 +    public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final IdentNode ident, final String name) {
  28.128 +        super(source, token, finish);
  28.129  
  28.130          this.ident             = ident;
  28.131          this.name              = name;
  28.132          this.kind              = Kind.NORMAL;
  28.133          this.parameters        = new ArrayList<>();
  28.134 -        this.functions         = new ArrayList<>();
  28.135          this.firstToken        = token;
  28.136          this.lastToken         = token;
  28.137          this.namespace         = namespace;
  28.138          this.labelStack        = new Stack<>();
  28.139          this.controlStack      = new Stack<>();
  28.140 -        this.declarations      = new ArrayList<>();
  28.141 -        // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies
  28.142 -        // it as such a leak - this is a false positive as we're setting this into a field of the object being
  28.143 -        // constructed, so it can't be seen from other threads.
  28.144 -        this.function          = this;
  28.145          this.compilationState  = EnumSet.of(CompilationState.INITIALIZED);
  28.146          this.specializedTypes  = new HashMap<>();
  28.147      }
  28.148  
  28.149 -    @SuppressWarnings("LeakingThisInConstructor")
  28.150      private FunctionNode(final FunctionNode functionNode, final CopyState cs) {
  28.151          super(functionNode, cs);
  28.152  
  28.153 -        this.functions = new ArrayList<>();
  28.154 -        for (final FunctionNode f : functionNode.getFunctions()) {
  28.155 -            this.functions.add((FunctionNode)cs.existingOrCopy(f));
  28.156 -        }
  28.157 -
  28.158          this.ident = (IdentNode)cs.existingOrCopy(functionNode.ident);
  28.159          this.name  = functionNode.name;
  28.160          this.kind  = functionNode.kind;
  28.161 @@ -296,22 +271,12 @@
  28.162          this.calleeNode        = (IdentNode)cs.existingOrCopy(functionNode.calleeNode);
  28.163          this.labelStack        = new Stack<>();
  28.164          this.controlStack      = new Stack<>();
  28.165 -        this.declarations      = new ArrayList<>();
  28.166 -
  28.167 -        for (final VarNode decl : functionNode.getDeclarations()) {
  28.168 -            declarations.add((VarNode) cs.existingOrCopy(decl)); //TODO same?
  28.169 -        }
  28.170  
  28.171          this.flags = functionNode.flags;
  28.172  
  28.173          this.funcVarNode = (VarNode)cs.existingOrCopy(functionNode.funcVarNode);
  28.174          /** VarNode for this function statement */
  28.175  
  28.176 -        // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies
  28.177 -        // it as such a leak - this is a false positive as we're setting this into a field of the object being
  28.178 -        // constructed, so it can't be seen from other threads.
  28.179 -        this.function = this;
  28.180 -
  28.181          this.compilationState = EnumSet.copyOf(functionNode.compilationState);
  28.182          this.specializedTypes = new HashMap<>();
  28.183      }
  28.184 @@ -319,21 +284,21 @@
  28.185      @Override
  28.186      protected Node copy(final CopyState cs) {
  28.187          // deep clone all parent blocks
  28.188 -        return fixBlockChain(new FunctionNode(this, cs));
  28.189 +        return new FunctionNode(this, cs);
  28.190      }
  28.191  
  28.192      @Override
  28.193      public Node accept(final NodeVisitor visitor) {
  28.194 -        final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode();
  28.195 -        final Block        saveBlock        = visitor.getCurrentBlock();
  28.196 +        final FunctionNode  saveFunctionNode  = visitor.getCurrentFunctionNode();
  28.197 +        final Block         saveBlock         = visitor.getCurrentBlock();
  28.198 +        final MethodEmitter saveMethodEmitter = visitor.getCurrentMethodEmitter();
  28.199 +        final CompileUnit   saveCompileUnit   = visitor.getCurrentCompileUnit();
  28.200  
  28.201          visitor.setCurrentFunctionNode(this);
  28.202 -        visitor.setCurrentCompileUnit(getCompileUnit());
  28.203 -        visitor.setCurrentMethodEmitter(getMethodEmitter());
  28.204          visitor.setCurrentBlock(this);
  28.205  
  28.206          try {
  28.207 -            if (visitor.enter(this) != null) {
  28.208 +            if (visitor.enterFunctionNode(this) != null) {
  28.209                  if (ident != null) {
  28.210                      ident = (IdentNode)ident.accept(visitor);
  28.211                  }
  28.212 @@ -342,51 +307,25 @@
  28.213                      parameters.set(i, (IdentNode)parameters.get(i).accept(visitor));
  28.214                  }
  28.215  
  28.216 -                for (int i = 0, count = functions.size(); i < count; i++) {
  28.217 -                    functions.set(i, (FunctionNode)functions.get(i).accept(visitor));
  28.218 -                }
  28.219 -
  28.220                  for (int i = 0, count = statements.size(); i < count; i++) {
  28.221                      statements.set(i, statements.get(i).accept(visitor));
  28.222                  }
  28.223  
  28.224 -                return visitor.leave(this);
  28.225 +                return visitor.leaveFunctionNode(this);
  28.226              }
  28.227          } finally {
  28.228              visitor.setCurrentBlock(saveBlock);
  28.229              visitor.setCurrentFunctionNode(saveFunctionNode);
  28.230 -            visitor.setCurrentCompileUnit(saveFunctionNode != null ? saveFunctionNode.getCompileUnit() : null);
  28.231 -            visitor.setCurrentMethodEmitter(saveFunctionNode != null ? saveFunctionNode.getMethodEmitter() : null);
  28.232 +            visitor.setCurrentCompileUnit(saveCompileUnit);
  28.233 +            visitor.setCurrentMethodEmitter(saveMethodEmitter);
  28.234          }
  28.235  
  28.236          return this;
  28.237      }
  28.238  
  28.239 -    /**
  28.240 -     * Locate the parent function.
  28.241 -     *
  28.242 -     * @return Parent function.
  28.243 -     */
  28.244 -    public FunctionNode findParentFunction() {
  28.245 -        return getParent() != null ? getParent().getFunction() : null;
  28.246 -    }
  28.247 -
  28.248 -    /**
  28.249 -     * Add parent name to the builder.
  28.250 -     *
  28.251 -     * @param sb String builder.
  28.252 -     */
  28.253 -    @Override
  28.254 -    public void addParentName(final StringBuilder sb) {
  28.255 -        if (!isScript()) {
  28.256 -            sb.append(getName());
  28.257 -            sb.append("$");
  28.258 -        }
  28.259 -    }
  28.260 -
  28.261      @Override
  28.262      public boolean needsScope() {
  28.263 -        return super.needsScope() || isScript();
  28.264 +        return super.needsScope() || isProgram();
  28.265      }
  28.266  
  28.267      /**
  28.268 @@ -544,12 +483,18 @@
  28.269      }
  28.270  
  28.271      /**
  28.272 -     * Determine if script function.
  28.273 -     *
  28.274 -     * @return True if script function.
  28.275 +     * Returns true if the function is the top-level program.
  28.276 +     * @return True if this function node represents the top-level program.
  28.277       */
  28.278 -    public boolean isScript() {
  28.279 -        return getParent() == null;
  28.280 +    public boolean isProgram() {
  28.281 +        return (flags & IS_PROGRAM) != 0;
  28.282 +    }
  28.283 +
  28.284 +    /**
  28.285 +     * Marks the function as representing the top-level program.
  28.286 +     */
  28.287 +    public void setProgram() {
  28.288 +        flags |= IS_PROGRAM;
  28.289      }
  28.290  
  28.291      /**
  28.292 @@ -589,31 +534,31 @@
  28.293  
  28.294      /**
  28.295       * Flag this function as using the {@code with} keyword
  28.296 +     * @param ancestors the iterator over functions in this functions's containing lexical context
  28.297       */
  28.298 -    public void setHasWith() {
  28.299 +    public void setHasWith(final Iterator<FunctionNode> ancestors) {
  28.300          if(!hasWith()) {
  28.301              this.flags |= HAS_WITH;
  28.302              // with requires scope in parents.
  28.303              // TODO: refine this. with should not force all variables in parents to be in scope, only those that are
  28.304              // actually referenced as identifiers by name
  28.305 -            markParentForWithOrEval();
  28.306 +            markParentForWithOrEval(ancestors);
  28.307          }
  28.308      }
  28.309  
  28.310 -    private void markParentForWithOrEval() {
  28.311 +    private void markParentForWithOrEval(final Iterator<FunctionNode> ancestors) {
  28.312          // If this is invoked, then either us or a descendant uses with or eval, meaning we must have our own scope.
  28.313          setNeedsScope();
  28.314  
  28.315 -        final FunctionNode parentFunction = findParentFunction();
  28.316 -        if(parentFunction != null) {
  28.317 -            parentFunction.setDescendantHasWithOrEval();
  28.318 +        if(ancestors.hasNext()) {
  28.319 +            ancestors.next().setDescendantHasWithOrEval(ancestors);
  28.320          }
  28.321      }
  28.322  
  28.323 -    private void setDescendantHasWithOrEval() {
  28.324 +    private void setDescendantHasWithOrEval(final Iterator<FunctionNode> ancestors) {
  28.325          if((flags & HAS_DESCENDANT_WITH_OR_EVAL) == 0) {
  28.326              flags |= HAS_DESCENDANT_WITH_OR_EVAL;
  28.327 -            markParentForWithOrEval();
  28.328 +            markParentForWithOrEval(ancestors);
  28.329          }
  28.330      }
  28.331  
  28.332 @@ -628,11 +573,12 @@
  28.333  
  28.334      /**
  28.335       * Flag this function as calling the {@code eval} function
  28.336 +     * @param ancestors the iterator over functions in this functions's containing lexical context
  28.337       */
  28.338 -    public void setHasEval() {
  28.339 +    public void setHasEval(final Iterator<FunctionNode> ancestors) {
  28.340          if(!hasEval()) {
  28.341              this.flags |= HAS_EVAL;
  28.342 -            markParentForWithOrEval();
  28.343 +            markParentForWithOrEval(ancestors);
  28.344          }
  28.345      }
  28.346  
  28.347 @@ -665,11 +611,34 @@
  28.348      }
  28.349  
  28.350      /**
  28.351 -     * Get all nested functions
  28.352 -     * @return list of nested functions in this function
  28.353 +     * Returns a list of functions declared by this function. Only includes declared functions, and does not include any
  28.354 +     * function expressions that might occur in its body.
  28.355 +     * @return a list of functions declared by this function.
  28.356       */
  28.357 -    public List<FunctionNode> getFunctions() {
  28.358 -        return Collections.unmodifiableList(functions);
  28.359 +    public List<FunctionNode> getDeclaredFunctions() {
  28.360 +        // Note that the function does not have a dedicated list of declared functions, but rather relies on the
  28.361 +        // invariant that all function declarations are at the beginning of the statement list as VarNode with a
  28.362 +        // FunctionNode marked as statement with its variable initializer. Every VarNode is also preceded by a
  28.363 +        // LineNumberNode. This invariant is established by the parser and has to be preserved in visitors.
  28.364 +        final List<FunctionNode> fns = new ArrayList<>();
  28.365 +        for (final Node stmt : statements) {
  28.366 +            if(stmt instanceof LineNumberNode) {
  28.367 +                continue;
  28.368 +            } else if(stmt instanceof VarNode) {
  28.369 +                final Node init = ((VarNode)stmt).getInit();
  28.370 +                if(init instanceof FunctionNode) {
  28.371 +                    final FunctionNode fn = (FunctionNode)init;
  28.372 +                    if(fn.isDeclared()) {
  28.373 +                        fns.add(fn);
  28.374 +                        continue;
  28.375 +                    }
  28.376 +                }
  28.377 +            }
  28.378 +            // Node is neither a LineNumberNode, nor a function declaration VarNode. Since all function declarations are
  28.379 +            // at the start of the function, we've reached the end of function declarations.
  28.380 +            break;
  28.381 +        }
  28.382 +        return fns;
  28.383      }
  28.384  
  28.385      /**
  28.386 @@ -801,7 +770,7 @@
  28.387      public boolean needsArguments() {
  28.388          // uses "arguments" or calls eval, but it does not redefine "arguments", and finally, it's not a script, since
  28.389          // for top-level script, "arguments" is picked up from Context by Global.init() instead.
  28.390 -        return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isScript();
  28.391 +        return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isProgram();
  28.392      }
  28.393  
  28.394      /**
  28.395 @@ -820,7 +789,7 @@
  28.396       * @return true if the function needs parent scope.
  28.397       */
  28.398      public boolean needsParentScope() {
  28.399 -        return (flags & NEEDS_PARENT_SCOPE) != 0 || isScript();
  28.400 +        return (flags & NEEDS_PARENT_SCOPE) != 0 || isProgram();
  28.401      }
  28.402  
  28.403      /**
  28.404 @@ -880,7 +849,7 @@
  28.405       * @return true if all variables should be in scope
  28.406       */
  28.407      public boolean allVarsInScope() {
  28.408 -        return isScript() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0;
  28.409 +        return isProgram() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0;
  28.410      }
  28.411  
  28.412      /**
  28.413 @@ -989,19 +958,19 @@
  28.414      }
  28.415  
  28.416      /**
  28.417 -     * Check if this function is a statement
  28.418 -     * @return true if function is a statement
  28.419 +     * Check if this function is created as a function declaration (as opposed to function expression)
  28.420 +     * @return true if function is declared.
  28.421       */
  28.422 -    public boolean isStatement() {
  28.423 -        return (flags & IS_STATEMENT) != 0;
  28.424 +    public boolean isDeclared() {
  28.425 +        return (flags & IS_DECLARED) != 0;
  28.426      }
  28.427  
  28.428      /**
  28.429 -     * Flag this function as a statement
  28.430 +     * Flag this function as being created as a function declaration (as opposed to a function expression).
  28.431       * @see Parser
  28.432       */
  28.433 -    public void setIsStatement() {
  28.434 -        this.flags |= IS_STATEMENT;
  28.435 +    public void setIsDeclared() {
  28.436 +        this.flags |= IS_DECLARED;
  28.437      }
  28.438  
  28.439      /**
  28.440 @@ -1049,35 +1018,16 @@
  28.441      }
  28.442  
  28.443      /**
  28.444 -     * Marks this function as one using any global symbol. The function and all its parent functions will all be marked
  28.445 -     * as needing parent scope.
  28.446 -     * @see #needsParentScope()
  28.447 +     * Marks this function as using any of its ancestors' scopes.
  28.448       */
  28.449 -    public void setUsesGlobalSymbol() {
  28.450 +    public void setUsesAncestorScope() {
  28.451          this.flags |= USES_ANCESTOR_SCOPE;
  28.452 -        final FunctionNode parentFn = findParentFunction();
  28.453 -        if(parentFn != null) {
  28.454 -            parentFn.setUsesGlobalSymbol();
  28.455 -        }
  28.456      }
  28.457  
  28.458 -    /**
  28.459 -     * Marks this function as using a specified scoped symbol. The function and its parent functions up to but not
  28.460 -     * including the function defining the symbol will be marked as needing parent scope. The function defining the
  28.461 -     * symbol will be marked as one that needs to have its own scope.
  28.462 -     * @param symbol the symbol being used.
  28.463 -     * @see #needsParentScope()
  28.464 -     */
  28.465 -    public void setUsesScopeSymbol(final Symbol symbol) {
  28.466 -        if(symbol.getBlock() == this) {
  28.467 -            setNeedsScope();
  28.468 -        } else {
  28.469 -            this.flags |= USES_ANCESTOR_SCOPE;
  28.470 -            final FunctionNode parentFn = findParentFunction();
  28.471 -            if (parentFn != null) {
  28.472 -                parentFn.setUsesScopeSymbol(symbol);
  28.473 -            }
  28.474 -        }
  28.475 +    @Override
  28.476 +    void setUsesParentScopeSymbol(Symbol symbol, Iterator<Block> ancestors) {
  28.477 +        setUsesAncestorScope();
  28.478 +        super.setUsesParentScopeSymbol(symbol, ancestors);
  28.479      }
  28.480  
  28.481      /**
  28.482 @@ -1152,7 +1102,7 @@
  28.483  
  28.484      @Override
  28.485      public Type getType() {
  28.486 -        return getReturnType();
  28.487 +        return FUNCTION_TYPE;
  28.488      }
  28.489  
  28.490      /**
  28.491 @@ -1212,56 +1162,6 @@
  28.492      }
  28.493  
  28.494      /**
  28.495 -     * Add a new function to the function list.
  28.496 -     *
  28.497 -     * @param functionNode Function node to add.
  28.498 -     */
  28.499 -    @Override
  28.500 -    public void addFunction(final FunctionNode functionNode) {
  28.501 -        assert functionNode != null;
  28.502 -        functions.add(functionNode);
  28.503 -    }
  28.504 -
  28.505 -    /**
  28.506 -     * Add a list of functions to the function list.
  28.507 -     *
  28.508 -     * @param functionNodes  Function nodes to add.
  28.509 -     */
  28.510 -    @Override
  28.511 -    public void addFunctions(final List<FunctionNode> functionNodes) {
  28.512 -        functions.addAll(functionNodes);
  28.513 -    }
  28.514 -
  28.515 -    /**
  28.516 -     * Set a function list
  28.517 -     *
  28.518 -     * @param functionNodes to set
  28.519 -     */
  28.520 -    @Override
  28.521 -    public void setFunctions(final List<FunctionNode> functionNodes) {
  28.522 -        this.functions = functionNodes;
  28.523 -    }
  28.524 -
  28.525 -    /**
  28.526 -     * Add a variable declaration that should be visible to the entire function
  28.527 -     * scope. Parser does this.
  28.528 -     *
  28.529 -     * @param varNode a var node
  28.530 -     */
  28.531 -    public void addDeclaration(final VarNode varNode) {
  28.532 -        declarations.add(varNode);
  28.533 -    }
  28.534 -
  28.535 -    /**
  28.536 -     * Return all variable declarations from this function scope
  28.537 -     *
  28.538 -     * @return all VarNodes in scope
  28.539 -     */
  28.540 -    public List<VarNode> getDeclarations() {
  28.541 -        return Collections.unmodifiableList(declarations);
  28.542 -    }
  28.543 -
  28.544 -    /**
  28.545       * Get the compile unit used to compile this function
  28.546       * @see Compiler
  28.547       * @return the compile unit
  28.548 @@ -1294,32 +1194,4 @@
  28.549      public void setMethodEmitter(final MethodEmitter method) {
  28.550          this.method = method;
  28.551      }
  28.552 -
  28.553 -    /**
  28.554 -     * Each FunctionNode maintains a list of reference to its parent blocks.
  28.555 -     * Add a parent block to this function.
  28.556 -     *
  28.557 -     * @param parentBlock  a block to remember as parent
  28.558 -     */
  28.559 -    public void addReferencingParentBlock(final Block parentBlock) {
  28.560 -        assert parentBlock.getFunction() == function.findParentFunction() : Debug.id(parentBlock.getFunction()) + "!=" + Debug.id(function.findParentFunction()); // all parent blocks must be in the same function
  28.561 -        if (parentBlock != function.getParent()) {
  28.562 -            if (referencingParentBlocks == null) {
  28.563 -                referencingParentBlocks = new LinkedList<>();
  28.564 -            }
  28.565 -            referencingParentBlocks.add(parentBlock);
  28.566 -        }
  28.567 -    }
  28.568 -
  28.569 -    /**
  28.570 -     * Get the known parent blocks to this function
  28.571 -     *
  28.572 -     * @return list of parent blocks
  28.573 -     */
  28.574 -    public List<Block> getReferencingParentBlocks() {
  28.575 -        if (referencingParentBlocks == null) {
  28.576 -            return Collections.emptyList();
  28.577 -        }
  28.578 -        return Collections.unmodifiableList(referencingParentBlocks);
  28.579 -    }
  28.580  }
    29.1 --- a/src/jdk/nashorn/internal/ir/IdentNode.java	Tue Mar 19 11:03:24 2013 -0300
    29.2 +++ b/src/jdk/nashorn/internal/ir/IdentNode.java	Sat Mar 23 00:58:39 2013 +0100
    29.3 @@ -38,18 +38,18 @@
    29.4  /**
    29.5   * IR representation for an identifier.
    29.6   */
    29.7 -public class IdentNode extends Node implements PropertyKey, TypeOverride, FunctionCall {
    29.8 +public class IdentNode extends Node implements PropertyKey, TypeOverride<IdentNode>, FunctionCall {
    29.9 +    private static final int PROPERTY_NAME    = 1 << 0;
   29.10 +    private static final int INITIALIZED_HERE = 1 << 1;
   29.11 +    private static final int FUNCTION         = 1 << 2;
   29.12 +
   29.13      /** Identifier. */
   29.14      private final String name;
   29.15  
   29.16      /** Type for a callsite, e.g. X in a get()X or a set(X)V */
   29.17      private Type callSiteType;
   29.18  
   29.19 -    /** flag for an ident that is the property name of an AccessNode. */
   29.20 -    private boolean isPropertyName;
   29.21 -
   29.22 -    /** flag for an ident on the left hand side of <code>var lhs = rhs;</code>. */
   29.23 -    private boolean isInitializedHere;
   29.24 +    private byte flags;
   29.25  
   29.26      /**
   29.27       * Constructor
   29.28 @@ -71,9 +71,8 @@
   29.29       */
   29.30      public IdentNode(final IdentNode identNode) {
   29.31          super(identNode);
   29.32 -        this.name              = identNode.getName();
   29.33 -        this.isPropertyName    = identNode.isPropertyName;
   29.34 -        this.isInitializedHere = identNode.isInitializedHere;
   29.35 +        this.name  = identNode.getName();
   29.36 +        this.flags = identNode.flags;
   29.37      }
   29.38  
   29.39      @Override
   29.40 @@ -92,12 +91,17 @@
   29.41      }
   29.42  
   29.43      @Override
   29.44 -    public void setType(final Type type) {
   29.45 +    public IdentNode setType(final Type type) {
   29.46          if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
   29.47              ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
   29.48          }
   29.49 -        this.callSiteType = type;
   29.50          // do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't
   29.51 +        if(this.callSiteType == type) {
   29.52 +            return this;
   29.53 +        }
   29.54 +        final IdentNode n = (IdentNode)clone();
   29.55 +        n.callSiteType = type;
   29.56 +        return n;
   29.57      }
   29.58  
   29.59      @Override
   29.60 @@ -131,8 +135,8 @@
   29.61       */
   29.62      @Override
   29.63      public Node accept(final NodeVisitor visitor) {
   29.64 -        if (visitor.enter(this) != null) {
   29.65 -            return visitor.leave(this);
   29.66 +        if (visitor.enterIdentNode(this) != null) {
   29.67 +            return visitor.leaveIdentNode(this);
   29.68          }
   29.69  
   29.70          return this;
   29.71 @@ -179,14 +183,18 @@
   29.72       * @return true if this is a property name
   29.73       */
   29.74      public boolean isPropertyName() {
   29.75 -        return isPropertyName;
   29.76 +        return (flags & PROPERTY_NAME) != 0;
   29.77      }
   29.78  
   29.79      /**
   29.80       * Flag this IdentNode as a property name
   29.81 +     * @return a node equivalent to this one except for the requested change.
   29.82       */
   29.83 -    public void setIsPropertyName() {
   29.84 -        isPropertyName = true;
   29.85 +    public IdentNode setIsPropertyName() {
   29.86 +        if(isPropertyName()) return this;
   29.87 +        final IdentNode n = (IdentNode)clone();
   29.88 +        n.flags |= PROPERTY_NAME;
   29.89 +        return n;
   29.90      }
   29.91  
   29.92      /**
   29.93 @@ -194,14 +202,18 @@
   29.94       * @return true if IdentNode is initialized on creation
   29.95       */
   29.96      public boolean isInitializedHere() {
   29.97 -        return isInitializedHere;
   29.98 +        return (flags & INITIALIZED_HERE) != 0;
   29.99      }
  29.100  
  29.101      /**
  29.102       * Flag IdentNode to be initialized on creation
  29.103 +     * @return a node equivalent to this one except for the requested change.
  29.104       */
  29.105 -    public void setIsInitializedHere() {
  29.106 -        isInitializedHere = true;
  29.107 +    public IdentNode setIsInitializedHere() {
  29.108 +        if(isInitializedHere()) return this;
  29.109 +        final IdentNode n = (IdentNode)clone();
  29.110 +        n.flags |= INITIALIZED_HERE;
  29.111 +        return n;
  29.112      }
  29.113  
  29.114      /**
  29.115 @@ -216,6 +228,17 @@
  29.116  
  29.117      @Override
  29.118      public boolean isFunction() {
  29.119 -        return false;
  29.120 +        return (flags & FUNCTION) != 0;
  29.121 +    }
  29.122 +
  29.123 +    /**
  29.124 +     * Mark this node as being the callee operand of a {@link CallNode}.
  29.125 +     * @return an ident node identical to this one in all aspects except with its function flag set.
  29.126 +     */
  29.127 +    public IdentNode setIsFunction() {
  29.128 +        if(isFunction()) return this;
  29.129 +        final IdentNode n = (IdentNode)clone();
  29.130 +        n.flags |= FUNCTION;
  29.131 +        return n;
  29.132      }
  29.133  }
    30.1 --- a/src/jdk/nashorn/internal/ir/IfNode.java	Tue Mar 19 11:03:24 2013 -0300
    30.2 +++ b/src/jdk/nashorn/internal/ir/IfNode.java	Sat Mar 23 00:58:39 2013 +0100
    30.3 @@ -75,7 +75,7 @@
    30.4  
    30.5      @Override
    30.6      public Node accept(final NodeVisitor visitor) {
    30.7 -        if (visitor.enter(this) != null) {
    30.8 +        if (visitor.enterIfNode(this) != null) {
    30.9              test = test.accept(visitor);
   30.10  
   30.11              pass = (Block)pass.accept(visitor);
   30.12 @@ -84,7 +84,7 @@
   30.13                  fail = (Block)fail.accept(visitor);
   30.14              }
   30.15  
   30.16 -            return visitor.leave(this);
   30.17 +            return visitor.leaveIfNode(this);
   30.18          }
   30.19  
   30.20          return this;
    31.1 --- a/src/jdk/nashorn/internal/ir/IndexNode.java	Tue Mar 19 11:03:24 2013 -0300
    31.2 +++ b/src/jdk/nashorn/internal/ir/IndexNode.java	Sat Mar 23 00:58:39 2013 +0100
    31.3 @@ -36,7 +36,7 @@
    31.4   * IR representation of an indexed access (brackets operator.)
    31.5   *
    31.6   */
    31.7 -public class IndexNode extends BaseNode implements TypeOverride {
    31.8 +public class IndexNode extends BaseNode implements TypeOverride<IndexNode> {
    31.9      /** Property ident. */
   31.10      private Node index;
   31.11  
   31.12 @@ -92,10 +92,10 @@
   31.13  
   31.14      @Override
   31.15      public Node accept(final NodeVisitor visitor) {
   31.16 -        if (visitor.enter(this) != null) {
   31.17 +        if (visitor.enterIndexNode(this) != null) {
   31.18              base = base.accept(visitor);
   31.19              index = index.accept(visitor);
   31.20 -            return visitor.leave(this);
   31.21 +            return visitor.leaveIndexNode(this);
   31.22          }
   31.23  
   31.24          return this;
   31.25 @@ -144,12 +144,13 @@
   31.26      }
   31.27  
   31.28      @Override
   31.29 -    public void setType(final Type type) {
   31.30 +    public IndexNode setType(final Type type) {
   31.31          if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
   31.32              ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
   31.33          }
   31.34          hasCallSiteType = true;
   31.35          getSymbol().setTypeOverride(type);
   31.36 +        return this;
   31.37      }
   31.38  
   31.39      @Override
    32.1 --- a/src/jdk/nashorn/internal/ir/LabelNode.java	Tue Mar 19 11:03:24 2013 -0300
    32.2 +++ b/src/jdk/nashorn/internal/ir/LabelNode.java	Sat Mar 23 00:58:39 2013 +0100
    32.3 @@ -81,10 +81,10 @@
    32.4  
    32.5      @Override
    32.6      public Node accept(final NodeVisitor visitor) {
    32.7 -        if (visitor.enter(this) != null) {
    32.8 +        if (visitor.enterLabelNode(this) != null) {
    32.9              label = (IdentNode)label.accept(visitor);
   32.10              body  = (Block)body.accept(visitor);
   32.11 -            return visitor.leave(this);
   32.12 +            return visitor.leaveLabelNode(this);
   32.13          }
   32.14  
   32.15          return this;
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java	Sat Mar 23 00:58:39 2013 +0100
    33.3 @@ -0,0 +1,198 @@
    33.4 +package jdk.nashorn.internal.ir;
    33.5 +
    33.6 +import java.util.ArrayDeque;
    33.7 +import java.util.Deque;
    33.8 +import java.util.Iterator;
    33.9 +import java.util.NoSuchElementException;
   33.10 +
   33.11 +/**
   33.12 + * A class that tracks the current lexical context of node visitation as a stack of {@link Block} nodes. Has special
   33.13 + * methods to retrieve useful subsets of the context.
   33.14 + */
   33.15 +public class LexicalContext implements Cloneable {
   33.16 +    private final Deque<Block> lexicalContext;
   33.17 +
   33.18 +    /**
   33.19 +     * Creates a new empty lexical context.
   33.20 +     */
   33.21 +    public LexicalContext() {
   33.22 +        lexicalContext = new ArrayDeque<>();
   33.23 +    }
   33.24 +
   33.25 +    /**
   33.26 +     * Pushes a new block on top of the context, making it the innermost open block.
   33.27 +     * @param block the new block
   33.28 +     */
   33.29 +    public void push(Block block) {
   33.30 +        //new Exception(block.toString()).printStackTrace();
   33.31 +        lexicalContext.push(block);
   33.32 +    }
   33.33 +
   33.34 +    /**
   33.35 +     * Pops the innermost block off the context.
   33.36 +     * @param the block expected to be popped, used to detect unbalanced pushes/pops
   33.37 +     */
   33.38 +    public void pop(Block block) {
   33.39 +        final Block popped = lexicalContext.pop();
   33.40 +        assert popped == block;
   33.41 +    }
   33.42 +
   33.43 +    /**
   33.44 +     * Returns an iterator over all blocks in the context, with the top block (innermost lexical context) first.
   33.45 +     * @return an iterator over all blocks in the context.
   33.46 +     */
   33.47 +    public Iterator<Block> getBlocks() {
   33.48 +        return lexicalContext.iterator();
   33.49 +    }
   33.50 +
   33.51 +    /**
   33.52 +     * Returns an iterator over all functions in the context, with the top (innermost open) function first.
   33.53 +     * @return an iterator over all functions in the context.
   33.54 +     */
   33.55 +    public Iterator<FunctionNode> getFunctions() {
   33.56 +        return new FunctionIterator(getBlocks());
   33.57 +    }
   33.58 +
   33.59 +    private static final class FunctionIterator implements Iterator<FunctionNode> {
   33.60 +        private final Iterator<Block> it;
   33.61 +        private FunctionNode next;
   33.62 +
   33.63 +        FunctionIterator(Iterator<Block> it) {
   33.64 +            this.it = it;
   33.65 +            next = findNext();
   33.66 +        }
   33.67 +
   33.68 +        @Override
   33.69 +        public boolean hasNext() {
   33.70 +            return next != null;
   33.71 +        }
   33.72 +
   33.73 +        @Override
   33.74 +        public FunctionNode next() {
   33.75 +            if(next == null) {
   33.76 +                throw new NoSuchElementException();
   33.77 +            }
   33.78 +            FunctionNode lnext = next;
   33.79 +            next = findNext();
   33.80 +            return lnext;
   33.81 +        }
   33.82 +
   33.83 +        private FunctionNode findNext() {
   33.84 +            while(it.hasNext()) {
   33.85 +                final Block block = it.next();
   33.86 +                if(block instanceof FunctionNode) {
   33.87 +                    return ((FunctionNode)block);
   33.88 +                }
   33.89 +            }
   33.90 +            return null;
   33.91 +        }
   33.92 +
   33.93 +        @Override
   33.94 +        public void remove() {
   33.95 +            throw new UnsupportedOperationException();
   33.96 +        }
   33.97 +    }
   33.98 +
   33.99 +    /**
  33.100 +     * Returns an iterator over all ancestors block of the given block, with its parent block first.
  33.101 +     * @param block the block whose ancestors are returned
  33.102 +     * @return an iterator over all ancestors block of the given block.
  33.103 +     */
  33.104 +    public Iterator<Block> getAncestorBlocks(Block block) {
  33.105 +        final Iterator<Block> it = getBlocks();
  33.106 +        while(it.hasNext()) {
  33.107 +            final Block b = it.next();
  33.108 +            if(block == b) {
  33.109 +                return it;
  33.110 +            }
  33.111 +        }
  33.112 +        throw new AssertionError("Block is not on the current lexical context stack");
  33.113 +    }
  33.114 +
  33.115 +    /**
  33.116 +     * Returns an iterator over a block and all its ancestors blocks, with the block first.
  33.117 +     * @param block the block that is the starting point of the iteration.
  33.118 +     * @return an iterator over a block and all its ancestors.
  33.119 +     */
  33.120 +    public Iterator<Block> getBlocks(final Block block) {
  33.121 +        final Iterator<Block> it = getAncestorBlocks(block);
  33.122 +        return new Iterator<Block>() {
  33.123 +            boolean blockReturned = false;
  33.124 +            @Override
  33.125 +            public boolean hasNext() {
  33.126 +                return it.hasNext() || !blockReturned;
  33.127 +            }
  33.128 +            @Override
  33.129 +            public Block next() {
  33.130 +                if(blockReturned) {
  33.131 +                    return it.next();
  33.132 +                }
  33.133 +                blockReturned = true;
  33.134 +                return block;
  33.135 +            }
  33.136 +            @Override
  33.137 +            public void remove() {
  33.138 +                throw new UnsupportedOperationException();
  33.139 +            }
  33.140 +        };
  33.141 +    }
  33.142 +
  33.143 +    /**
  33.144 +     * Returns the closest function node to the block. If the block is itself a function, it is returned.
  33.145 +     * @param block the block
  33.146 +     * @return the function closest to the block.
  33.147 +     * @see #getParentFunction(Block)
  33.148 +     */
  33.149 +    public FunctionNode getFunction(Block block) {
  33.150 +        if(block instanceof FunctionNode) {
  33.151 +            return (FunctionNode)block;
  33.152 +        }
  33.153 +        return getParentFunction(block);
  33.154 +    }
  33.155 +
  33.156 +    /**
  33.157 +     * Returns the closest function node to the block and all its ancestor functions. If the block is itself a function,
  33.158 +     * it is returned too.
  33.159 +     * @param block the block
  33.160 +     * @return the closest function node to the block and all its ancestor functions.
  33.161 +     */
  33.162 +    public Iterator<FunctionNode> getFunctions(final Block block) {
  33.163 +        return new FunctionIterator(getBlocks(block));
  33.164 +    }
  33.165 +
  33.166 +    /**
  33.167 +     * Returns the containing function of the block. If the block is itself a function, its parent function is returned.
  33.168 +     * @param block the block
  33.169 +     * @return the containing function of the block.
  33.170 +     * @see #getFunction(Block)
  33.171 +     */
  33.172 +    public FunctionNode getParentFunction(Block block) {
  33.173 +        return getFirstFunction(getAncestorBlocks(block));
  33.174 +    }
  33.175 +
  33.176 +    private static FunctionNode getFirstFunction(Iterator<Block> it) {
  33.177 +        while(it.hasNext()) {
  33.178 +            final Block ancestor = it.next();
  33.179 +            if(ancestor instanceof FunctionNode) {
  33.180 +                return (FunctionNode)ancestor;
  33.181 +            }
  33.182 +        }
  33.183 +        return null;
  33.184 +    }
  33.185 +
  33.186 +    /**
  33.187 +     * Returns the innermost block in the context.
  33.188 +     * @return the innermost block in the context.
  33.189 +     */
  33.190 +    public Block getCurrentBlock() {
  33.191 +        return lexicalContext.element();
  33.192 +    }
  33.193 +
  33.194 +    /**
  33.195 +     * Returns the innermost function in the context.
  33.196 +     * @return the innermost function in the context.
  33.197 +     */
  33.198 +    public FunctionNode getCurrentFunction() {
  33.199 +        return getFirstFunction(getBlocks());
  33.200 +    }
  33.201 +}
    34.1 --- a/src/jdk/nashorn/internal/ir/LineNumberNode.java	Tue Mar 19 11:03:24 2013 -0300
    34.2 +++ b/src/jdk/nashorn/internal/ir/LineNumberNode.java	Sat Mar 23 00:58:39 2013 +0100
    34.3 @@ -63,8 +63,8 @@
    34.4  
    34.5      @Override
    34.6      public Node accept(final NodeVisitor visitor) {
    34.7 -        if (visitor.enter(this) != null) {
    34.8 -            return visitor.leave(this);
    34.9 +        if (visitor.enterLineNumberNode(this) != null) {
   34.10 +            return visitor.leaveLineNumberNode(this);
   34.11          }
   34.12  
   34.13          return this;
    35.1 --- a/src/jdk/nashorn/internal/ir/LiteralNode.java	Tue Mar 19 11:03:24 2013 -0300
    35.2 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java	Sat Mar 23 00:58:39 2013 +0100
    35.3 @@ -46,7 +46,7 @@
    35.4   */
    35.5  public abstract class LiteralNode<T> extends Node implements PropertyKey {
    35.6      /** Literal value */
    35.7 -    protected T value;
    35.8 +    protected final T value;
    35.9  
   35.10       /**
   35.11       * Constructor
   35.12 @@ -67,8 +67,17 @@
   35.13       * @param literalNode source node
   35.14       */
   35.15      protected LiteralNode(final LiteralNode<T> literalNode) {
   35.16 +        this(literalNode, literalNode.value);
   35.17 +    }
   35.18 +
   35.19 +    /**
   35.20 +     * A copy constructor with value change.
   35.21 +     * @param literalNode the original literal node
   35.22 +     * @param newValue new value for this node
   35.23 +     */
   35.24 +    protected LiteralNode(final LiteralNode<T> literalNode, final T newValue) {
   35.25          super(literalNode);
   35.26 -        this.value = literalNode.value;
   35.27 +        this.value = newValue;
   35.28      }
   35.29  
   35.30      @Override
   35.31 @@ -217,8 +226,8 @@
   35.32       */
   35.33      @Override
   35.34      public Node accept(final NodeVisitor visitor) {
   35.35 -        if (visitor.enter(this) != null) {
   35.36 -            return visitor.leave(this);
   35.37 +        if (visitor.enterLiteralNode(this) != null) {
   35.38 +            return visitor.leaveLiteralNode(this);
   35.39          }
   35.40  
   35.41          return this;
   35.42 @@ -544,6 +553,10 @@
   35.43              super(literalNode);
   35.44          }
   35.45  
   35.46 +        private NodeLiteralNode(final LiteralNode<Node> literalNode, final Node value) {
   35.47 +            super(literalNode, value);
   35.48 +        }
   35.49 +
   35.50          @Override
   35.51          protected Node copy(final CopyState cs) {
   35.52              return new NodeLiteralNode(this);
   35.53 @@ -551,11 +564,14 @@
   35.54  
   35.55          @Override
   35.56          public Node accept(final NodeVisitor visitor) {
   35.57 -            if (visitor.enter(this) != null) {
   35.58 +            if (visitor.enterLiteralNode(this) != null) {
   35.59                  if (value != null) {
   35.60 -                    value = value.accept(visitor);
   35.61 +                    final Node newValue = value.accept(visitor);
   35.62 +                    if(value != newValue) {
   35.63 +                        return visitor.leaveLiteralNode(new NodeLiteralNode(this, newValue));
   35.64 +                    }
   35.65                  }
   35.66 -                return visitor.leave(this);
   35.67 +                return visitor.leaveLiteralNode(this);
   35.68              }
   35.69  
   35.70              return this;
   35.71 @@ -878,14 +894,14 @@
   35.72  
   35.73          @Override
   35.74          public Node accept(final NodeVisitor visitor) {
   35.75 -            if (visitor.enter(this) != null) {
   35.76 +            if (visitor.enterLiteralNode(this) != null) {
   35.77                  for (int i = 0; i < value.length; i++) {
   35.78                      final Node element = value[i];
   35.79                      if (element != null) {
   35.80                          value[i] = element.accept(visitor);
   35.81                      }
   35.82                  }
   35.83 -                return visitor.leave(this);
   35.84 +                return visitor.leaveLiteralNode(this);
   35.85              }
   35.86              return this;
   35.87          }
    36.1 --- a/src/jdk/nashorn/internal/ir/Location.java	Tue Mar 19 11:03:24 2013 -0300
    36.2 +++ b/src/jdk/nashorn/internal/ir/Location.java	Sat Mar 23 00:58:39 2013 +0100
    36.3 @@ -65,7 +65,11 @@
    36.4  
    36.5      @Override
    36.6      protected Object clone() {
    36.7 -        return new Location(this);
    36.8 +        try {
    36.9 +            return super.clone();
   36.10 +        } catch(CloneNotSupportedException e) {
   36.11 +            throw new AssertionError(e);
   36.12 +        }
   36.13      }
   36.14  
   36.15      @Override
    37.1 --- a/src/jdk/nashorn/internal/ir/Node.java	Tue Mar 19 11:03:24 2013 -0300
    37.2 +++ b/src/jdk/nashorn/internal/ir/Node.java	Sat Mar 23 00:58:39 2013 +0100
    37.3 @@ -165,12 +165,19 @@
    37.4              return true;
    37.5          }
    37.6  
    37.7 -        setIsResolved();
    37.8 +        setIsResolved(true);
    37.9  
   37.10          return false;
   37.11      }
   37.12  
   37.13      /**
   37.14 +     * Reset the resolved flag.
   37.15 +     */
   37.16 +    public void resetResolved() {
   37.17 +        setIsResolved(false);
   37.18 +    }
   37.19 +
   37.20 +    /**
   37.21       * Is this a debug info node like LineNumberNode etc?
   37.22       *
   37.23       * @return true if this is a debug node
   37.24 @@ -234,8 +241,7 @@
   37.25       *
   37.26       * @return Deep copy of the  Node.
   37.27       */
   37.28 -    @Override
   37.29 -    public final Node clone() {
   37.30 +    public final Node copy() {
   37.31          return copy(new CopyState());
   37.32      }
   37.33  
   37.34 @@ -349,10 +355,10 @@
   37.35      }
   37.36  
   37.37      /**
   37.38 -     * Flag this node as resolved, i.e. code has been generated for it
   37.39 +     * Flag this node as resolved or not, i.e. code has been generated for it
   37.40       */
   37.41 -    public void setIsResolved() {
   37.42 -        this.isResolved = true;
   37.43 +    private void setIsResolved(boolean isResolved) {
   37.44 +        this.isResolved = isResolved;
   37.45      }
   37.46  
   37.47      /**
    38.1 --- a/src/jdk/nashorn/internal/ir/ObjectNode.java	Tue Mar 19 11:03:24 2013 -0300
    38.2 +++ b/src/jdk/nashorn/internal/ir/ObjectNode.java	Sat Mar 23 00:58:39 2013 +0100
    38.3 @@ -72,12 +72,12 @@
    38.4  
    38.5      @Override
    38.6      public Node accept(final NodeVisitor visitor) {
    38.7 -        if (visitor.enter(this) != null) {
    38.8 +        if (visitor.enterObjectNode(this) != null) {
    38.9              for (int i = 0, count = elements.size(); i < count; i++) {
   38.10                  elements.set(i, elements.get(i).accept(visitor));
   38.11              }
   38.12  
   38.13 -            return visitor.leave(this);
   38.14 +            return visitor.leaveObjectNode(this);
   38.15          }
   38.16  
   38.17          return this;
    39.1 --- a/src/jdk/nashorn/internal/ir/PropertyNode.java	Tue Mar 19 11:03:24 2013 -0300
    39.2 +++ b/src/jdk/nashorn/internal/ir/PropertyNode.java	Sat Mar 23 00:58:39 2013 +0100
    39.3 @@ -88,7 +88,7 @@
    39.4  
    39.5      @Override
    39.6      public Node accept(final NodeVisitor visitor) {
    39.7 -        if (visitor.enter(this) != null) {
    39.8 +        if (visitor.enterPropertyNode(this) != null) {
    39.9              key = (PropertyKey)((Node)key).accept(visitor);
   39.10  
   39.11              if (value != null) {
   39.12 @@ -103,7 +103,7 @@
   39.13                  setter = setter.accept(visitor);
   39.14              }
   39.15  
   39.16 -            return visitor.leave(this);
   39.17 +            return visitor.leavePropertyNode(this);
   39.18          }
   39.19  
   39.20          return this;
    40.1 --- a/src/jdk/nashorn/internal/ir/ReferenceNode.java	Tue Mar 19 11:03:24 2013 -0300
    40.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.3 @@ -1,91 +0,0 @@
    40.4 -/*
    40.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
    40.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    40.7 - *
    40.8 - * This code is free software; you can redistribute it and/or modify it
    40.9 - * under the terms of the GNU General Public License version 2 only, as
   40.10 - * published by the Free Software Foundation.  Oracle designates this
   40.11 - * particular file as subject to the "Classpath" exception as provided
   40.12 - * by Oracle in the LICENSE file that accompanied this code.
   40.13 - *
   40.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
   40.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   40.16 - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   40.17 - * version 2 for more details (a copy is included in the LICENSE file that
   40.18 - * accompanied this code).
   40.19 - *
   40.20 - * You should have received a copy of the GNU General Public License version
   40.21 - * 2 along with this work; if not, write to the Free Software Foundation,
   40.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   40.23 - *
   40.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   40.25 - * or visit www.oracle.com if you need additional information or have any
   40.26 - * questions.
   40.27 - */
   40.28 -
   40.29 -package jdk.nashorn.internal.ir;
   40.30 -
   40.31 -import jdk.nashorn.internal.ir.annotations.Reference;
   40.32 -import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   40.33 -import jdk.nashorn.internal.runtime.Source;
   40.34 -
   40.35 -/**
   40.36 - * IR representation of a reference to another entity (function.)
   40.37 - */
   40.38 -public class ReferenceNode extends Node {
   40.39 -    /** Node referenced. */
   40.40 -    @Reference
   40.41 -    private final FunctionNode reference;
   40.42 -
   40.43 -    /**
   40.44 -     * Constructor
   40.45 -     *
   40.46 -     * @param source the source
   40.47 -     * @param token  token
   40.48 -     * @param finish finish
   40.49 -     * @param reference the function node to reference
   40.50 -     */
   40.51 -    public ReferenceNode(final Source source, final long token, final int finish, final FunctionNode reference) {
   40.52 -        super(source, token, finish);
   40.53 -
   40.54 -        this.reference = reference;
   40.55 -    }
   40.56 -
   40.57 -    private ReferenceNode(final ReferenceNode referenceNode) {
   40.58 -        super(referenceNode);
   40.59 -
   40.60 -        this.reference = referenceNode.reference;
   40.61 -    }
   40.62 -
   40.63 -    @Override
   40.64 -    protected Node copy(final CopyState cs) {
   40.65 -        return new ReferenceNode(this);
   40.66 -    }
   40.67 -
   40.68 -    @Override
   40.69 -    public Node accept(final NodeVisitor visitor) {
   40.70 -        if (visitor.enter(this) != null) {
   40.71 -            return visitor.leave(this);
   40.72 -        }
   40.73 -
   40.74 -        return this;
   40.75 -    }
   40.76 -
   40.77 -    @Override
   40.78 -    public void toString(final StringBuilder sb) {
   40.79 -        if (reference == null) {
   40.80 -            sb.append("null");
   40.81 -        } else {
   40.82 -            reference.toString(sb);
   40.83 -        }
   40.84 -    }
   40.85 -
   40.86 -    /**
   40.87 -     * Get there function node reference that this node points tp
   40.88 -     * @return a function node reference
   40.89 -     */
   40.90 -    public FunctionNode getReference() {
   40.91 -        return reference;
   40.92 -    }
   40.93 -
   40.94 -}
    41.1 --- a/src/jdk/nashorn/internal/ir/ReturnNode.java	Tue Mar 19 11:03:24 2013 -0300
    41.2 +++ b/src/jdk/nashorn/internal/ir/ReturnNode.java	Sat Mar 23 00:58:39 2013 +0100
    41.3 @@ -100,12 +100,12 @@
    41.4  
    41.5      @Override
    41.6      public Node accept(final NodeVisitor visitor) {
    41.7 -        if (visitor.enter(this) != null) {
    41.8 +        if (visitor.enterReturnNode(this) != null) {
    41.9              if (expression != null) {
   41.10                  expression = expression.accept(visitor);
   41.11              }
   41.12  
   41.13 -            return visitor.leave(this);
   41.14 +            return visitor.leaveReturnNode(this);
   41.15          }
   41.16  
   41.17          return this;
    42.1 --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java	Tue Mar 19 11:03:24 2013 -0300
    42.2 +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java	Sat Mar 23 00:58:39 2013 +0100
    42.3 @@ -38,7 +38,7 @@
    42.4   * IR representation for a runtime call.
    42.5   *
    42.6   */
    42.7 -public class RuntimeNode extends Node implements TypeOverride {
    42.8 +public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
    42.9  
   42.10      /**
   42.11       * Request enum used for meta-information about the runtime request
   42.12 @@ -393,8 +393,9 @@
   42.13      }
   42.14  
   42.15      @Override
   42.16 -    public void setType(final Type type) {
   42.17 +    public RuntimeNode setType(final Type type) {
   42.18          this.callSiteType = type;
   42.19 +        return this;
   42.20      }
   42.21  
   42.22      @Override
   42.23 @@ -408,12 +409,12 @@
   42.24  
   42.25      @Override
   42.26      public Node accept(final NodeVisitor visitor) {
   42.27 -        if (visitor.enter(this) != null) {
   42.28 +        if (visitor.enterRuntimeNode(this) != null) {
   42.29              for (int i = 0, count = args.size(); i < count; i++) {
   42.30                  args.set(i, args.get(i).accept(visitor));
   42.31              }
   42.32  
   42.33 -            return visitor.leave(this);
   42.34 +            return visitor.leaveRuntimeNode(this);
   42.35          }
   42.36  
   42.37          return this;
    43.1 --- a/src/jdk/nashorn/internal/ir/SplitNode.java	Tue Mar 19 11:03:24 2013 -0300
    43.2 +++ b/src/jdk/nashorn/internal/ir/SplitNode.java	Sat Mar 23 00:58:39 2013 +0100
    43.3 @@ -108,10 +108,10 @@
    43.4          visitor.setCurrentMethodEmitter(getMethodEmitter());
    43.5  
    43.6          try {
    43.7 -            if (visitor.enter(this) != null) {
    43.8 +            if (visitor.enterSplitNode(this) != null) {
    43.9                  body = body.accept(visitor);
   43.10  
   43.11 -                return visitor.leave(this);
   43.12 +                return visitor.leaveSplitNode(this);
   43.13              }
   43.14          } finally {
   43.15              visitor.setCurrentCompileUnit(saveCompileUnit);
    44.1 --- a/src/jdk/nashorn/internal/ir/SwitchNode.java	Tue Mar 19 11:03:24 2013 -0300
    44.2 +++ b/src/jdk/nashorn/internal/ir/SwitchNode.java	Sat Mar 23 00:58:39 2013 +0100
    44.3 @@ -85,7 +85,7 @@
    44.4  
    44.5      @Override
    44.6      public Node accept(final NodeVisitor visitor) {
    44.7 -        if (visitor.enter(this) != null) {
    44.8 +        if (visitor.enterSwitchNode(this) != null) {
    44.9              expression = expression.accept(visitor);
   44.10  
   44.11              for (int i = 0, count = cases.size(); i < count; i++) {
   44.12 @@ -94,7 +94,7 @@
   44.13  
   44.14              //the default case is in the cases list and should not be explicitly traversed!
   44.15  
   44.16 -            return visitor.leave(this);
   44.17 +            return visitor.leaveSwitchNode(this);
   44.18          }
   44.19  
   44.20          return this;
    45.1 --- a/src/jdk/nashorn/internal/ir/Symbol.java	Tue Mar 19 11:03:24 2013 -0300
    45.2 +++ b/src/jdk/nashorn/internal/ir/Symbol.java	Sat Mar 23 00:58:39 2013 +0100
    45.3 @@ -38,31 +38,31 @@
    45.4   */
    45.5  
    45.6  public final class Symbol implements Comparable<Symbol> {
    45.7 -    /** Symbol flags. Kind ordered by precedence. */
    45.8 -    public static final int IS_TEMP     = 0b0000_0001;
    45.9 +    /** Symbol kinds. Kind ordered by precedence. */
   45.10 +    public static final int IS_TEMP     = 1;
   45.11      /** Is this Global */
   45.12 -    public static final int IS_GLOBAL   = 0b0000_0010;
   45.13 +    public static final int IS_GLOBAL   = 2;
   45.14      /** Is this a variable */
   45.15 -    public static final int IS_VAR      = 0b0000_0011;
   45.16 +    public static final int IS_VAR      = 3;
   45.17      /** Is this a parameter */
   45.18 -    public static final int IS_PARAM    = 0b0000_0100;
   45.19 +    public static final int IS_PARAM    = 4;
   45.20      /** Is this a constant */
   45.21 -    public static final int IS_CONSTANT = 0b0000_0101;
   45.22 -
   45.23 -    static final int KINDMASK = 0b0000_1111;
   45.24 +    public static final int IS_CONSTANT = 5;
   45.25 +    /** Mask for kind flags */
   45.26 +    public static final int KINDMASK = (1 << 3) - 1; // Kinds are represented by lower three bits
   45.27  
   45.28      /** Is this scope */
   45.29 -    public static final int IS_SCOPE         = 0b0000_0001_0000;
   45.30 +    public static final int IS_SCOPE         = 1 << 4;
   45.31      /** Is this a this symbol */
   45.32 -    public static final int IS_THIS          = 0b0000_0010_0000;
   45.33 +    public static final int IS_THIS          = 1 << 5;
   45.34      /** Can this symbol ever be undefined */
   45.35 -    public static final int CAN_BE_UNDEFINED = 0b0000_0100_0000;
   45.36 +    public static final int CAN_BE_UNDEFINED = 1 << 6;
   45.37      /** Can this symbol ever have primitive types */
   45.38 -    public static final int CAN_BE_PRIMITIVE = 0b0000_1000_0000;
   45.39 +    public static final int CAN_BE_PRIMITIVE = 1 << 7;
   45.40      /** Is this a let */
   45.41 -    public static final int IS_LET           = 0b0001_0000_0000;
   45.42 +    public static final int IS_LET           = 1 << 8;
   45.43      /** Is this an internal symbol, never represented explicitly in source code */
   45.44 -    public static final int IS_INTERNAL      = 0b0010_0000_0000;
   45.45 +    public static final int IS_INTERNAL      = 1 << 9;
   45.46  
   45.47      /** Null or name identifying symbol. */
   45.48      private final String name;
   45.49 @@ -269,15 +269,6 @@
   45.50          return type.isCategory2() ? 2 : 1;
   45.51      }
   45.52  
   45.53 -    /**
   45.54 -     * Return the defining function (scope.)
   45.55 -     *
   45.56 -     * @return Defining function.
   45.57 -     */
   45.58 -    public FunctionNode findFunction() {
   45.59 -        return block != null ? block.getFunction() : null;
   45.60 -    }
   45.61 -
   45.62      @Override
   45.63      public boolean equals(final Object other) {
   45.64          if (!(other instanceof Symbol)) {
   45.65 @@ -487,27 +478,6 @@
   45.66      }
   45.67  
   45.68      /**
   45.69 -     * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load
   45.70 -     *
   45.71 -     * @param currentFunction function to check for fast scope
   45.72 -     * @return true if fast scope
   45.73 -     */
   45.74 -    public boolean isFastScope(final FunctionNode currentFunction) {
   45.75 -        if (!isScope() || !block.needsScope()) {
   45.76 -            return false;
   45.77 -        }
   45.78 -        // Allow fast scope access if no parent function contains with or eval
   45.79 -        FunctionNode func = currentFunction;
   45.80 -        while (func != null) {
   45.81 -            if (func.hasWith() || func.hasEval()) {
   45.82 -                return false;
   45.83 -            }
   45.84 -            func = func.findParentFunction();
   45.85 -        }
   45.86 -        return true;
   45.87 -    }
   45.88 -
   45.89 -    /**
   45.90       * Get the block in which the symbol is defined
   45.91       * @return a block
   45.92       */
   45.93 @@ -651,7 +621,7 @@
   45.94       * @return true if this this is a global scope symbol
   45.95       */
   45.96      public boolean isTopLevel() {
   45.97 -        return block instanceof FunctionNode && ((FunctionNode) block).isScript();
   45.98 +        return block instanceof FunctionNode && ((FunctionNode) block).isProgram();
   45.99      }
  45.100  
  45.101  
    46.1 --- a/src/jdk/nashorn/internal/ir/TernaryNode.java	Tue Mar 19 11:03:24 2013 -0300
    46.2 +++ b/src/jdk/nashorn/internal/ir/TernaryNode.java	Sat Mar 23 00:58:39 2013 +0100
    46.3 @@ -77,11 +77,11 @@
    46.4  
    46.5      @Override
    46.6      public Node accept(final NodeVisitor visitor) {
    46.7 -        if (visitor.enter(this) != null) {
    46.8 -            lhs = lhs.accept(visitor);
    46.9 -            rhs = rhs.accept(visitor);
   46.10 -            third = third.accept(visitor);
   46.11 -            return visitor.leave(this);
   46.12 +        if (visitor.enterTernaryNode(this) != null) {
   46.13 +            final Node newLhs = lhs().accept(visitor);
   46.14 +            final Node newRhs = rhs().accept(visitor);
   46.15 +            final Node newThird = third.accept(visitor);
   46.16 +            return visitor.leaveTernaryNode((TernaryNode)setThird(newThird).setLHS(newLhs).setRHS(newRhs));
   46.17          }
   46.18  
   46.19          return this;
   46.20 @@ -133,8 +133,12 @@
   46.21      /**
   46.22       * Reset the "third" node for this ternary expression, i.e. "z" in x ? y : z
   46.23       * @param third a node
   46.24 +     * @return a node equivalent to this one except for the requested change.
   46.25       */
   46.26 -    public void setThird(final Node third) {
   46.27 -        this.third = third;
   46.28 +    public TernaryNode setThird(final Node third) {
   46.29 +        if(this.third == third) return this;
   46.30 +        final TernaryNode n = (TernaryNode)clone();
   46.31 +        n.third = third;
   46.32 +        return n;
   46.33      }
   46.34  }
    47.1 --- a/src/jdk/nashorn/internal/ir/ThrowNode.java	Tue Mar 19 11:03:24 2013 -0300
    47.2 +++ b/src/jdk/nashorn/internal/ir/ThrowNode.java	Sat Mar 23 00:58:39 2013 +0100
    47.3 @@ -75,9 +75,9 @@
    47.4       */
    47.5      @Override
    47.6      public Node accept(final NodeVisitor visitor) {
    47.7 -        if (visitor.enter(this) != null) {
    47.8 +        if (visitor.enterThrowNode(this) != null) {
    47.9              setExpression(expression.accept(visitor));
   47.10 -            return visitor.leave(this);
   47.11 +            return visitor.leaveThrowNode(this);
   47.12          }
   47.13  
   47.14          return this;
    48.1 --- a/src/jdk/nashorn/internal/ir/TryNode.java	Tue Mar 19 11:03:24 2013 -0300
    48.2 +++ b/src/jdk/nashorn/internal/ir/TryNode.java	Sat Mar 23 00:58:39 2013 +0100
    48.3 @@ -101,7 +101,7 @@
    48.4       */
    48.5      @Override
    48.6      public Node accept(final NodeVisitor visitor) {
    48.7 -        if (visitor.enter(this) != null) {
    48.8 +        if (visitor.enterTryNode(this) != null) {
    48.9              // Need to do first for termination analysis.
   48.10              if (finallyBody != null) {
   48.11                  finallyBody = (Block)finallyBody.accept(visitor);
   48.12 @@ -115,7 +115,7 @@
   48.13              }
   48.14              this.catchBlocks = newCatchBlocks;
   48.15  
   48.16 -            return visitor.leave(this);
   48.17 +            return visitor.leaveTryNode(this);
   48.18          }
   48.19  
   48.20          return this;
   48.21 @@ -155,6 +155,15 @@
   48.22      }
   48.23  
   48.24      /**
   48.25 +     * Returns true if the specified block is the body of this try block, or any of its catch blocks.
   48.26 +     * @param block the block
   48.27 +     * @return true if the specified block is the body of this try block, or any of its catch blocks.
   48.28 +     */
   48.29 +    public boolean isChildBlock(Block block) {
   48.30 +        return body == block || catchBlocks.contains(block);
   48.31 +    }
   48.32 +
   48.33 +    /**
   48.34       * Get the catch blocks for this try block
   48.35       * @return a list of blocks
   48.36       */
    49.1 --- a/src/jdk/nashorn/internal/ir/TypeOverride.java	Tue Mar 19 11:03:24 2013 -0300
    49.2 +++ b/src/jdk/nashorn/internal/ir/TypeOverride.java	Sat Mar 23 00:58:39 2013 +0100
    49.3 @@ -36,15 +36,17 @@
    49.4   * by using JSType.toInt32. Especially in scenarios where the field is already stored
    49.5   * as a primitive, this will be much faster than the "object is all I see" scope
    49.6   * available in the method
    49.7 + * @param <T> the type of the node implementing the interface
    49.8   */
    49.9  
   49.10 -public interface TypeOverride {
   49.11 +public interface TypeOverride<T extends Node> {
   49.12      /**
   49.13       * Set the override type
   49.14       *
   49.15       * @param type  the type
   49.16 +     * @return a node equivalent to this one except for the requested change.
   49.17       */
   49.18 -    public void setType(final Type type);
   49.19 +    public T setType(final Type type);
   49.20  
   49.21      /**
   49.22       * Returns true if this node can have a callsite override, e.g. all scope ident nodes
    50.1 --- a/src/jdk/nashorn/internal/ir/UnaryNode.java	Tue Mar 19 11:03:24 2013 -0300
    50.2 +++ b/src/jdk/nashorn/internal/ir/UnaryNode.java	Sat Mar 23 00:58:39 2013 +0100
    50.3 @@ -41,7 +41,7 @@
    50.4   */
    50.5  public class UnaryNode extends Node implements Assignment<Node> {
    50.6      /** Right hand side argument. */
    50.7 -    protected Node rhs;
    50.8 +    private Node rhs;
    50.9  
   50.10      /**
   50.11       * Constructor
   50.12 @@ -104,6 +104,11 @@
   50.13      }
   50.14  
   50.15      @Override
   50.16 +    public Node setAssignmentDest(Node n) {
   50.17 +        return setRHS(n);
   50.18 +    }
   50.19 +
   50.20 +    @Override
   50.21      public Node getAssignmentSource() {
   50.22          return getAssignmentDest();
   50.23      }
   50.24 @@ -132,9 +137,8 @@
   50.25       */
   50.26      @Override
   50.27      public Node accept(final NodeVisitor visitor) {
   50.28 -        if (visitor.enter(this) != null) {
   50.29 -            rhs = rhs.accept(visitor);
   50.30 -            return visitor.leave(this);
   50.31 +        if (visitor.enterUnaryNode(this) != null) {
   50.32 +            return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor)));
   50.33          }
   50.34  
   50.35          return this;
   50.36 @@ -212,10 +216,12 @@
   50.37       * @see BinaryNode
   50.38       *
   50.39       * @param rhs right hand side or expression node
   50.40 +     * @return a node equivalent to this one except for the requested change.
   50.41       */
   50.42 -    public void setRHS(final Node rhs) {
   50.43 -        this.rhs = rhs;
   50.44 +    public UnaryNode setRHS(final Node rhs) {
   50.45 +        if(this.rhs == rhs) return this;
   50.46 +        final UnaryNode n = (UnaryNode)clone();
   50.47 +        n.rhs = rhs;
   50.48 +        return n;
   50.49      }
   50.50 -
   50.51 -
   50.52  }
    51.1 --- a/src/jdk/nashorn/internal/ir/VarNode.java	Tue Mar 19 11:03:24 2013 -0300
    51.2 +++ b/src/jdk/nashorn/internal/ir/VarNode.java	Sat Mar 23 00:58:39 2013 +0100
    51.3 @@ -38,8 +38,8 @@
    51.4      /** Initialization expression. */
    51.5      private Node init;
    51.6  
    51.7 -    /** Is this a function var node */
    51.8 -    private boolean isFunctionVarNode;
    51.9 +    /** Is this a var statement (as opposed to a "var" in a for loop statement) */
   51.10 +    private final boolean isStatement;
   51.11  
   51.12      /**
   51.13       * Constructor
   51.14 @@ -51,20 +51,34 @@
   51.15       * @param init   init node or null if just a declaration
   51.16       */
   51.17      public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) {
   51.18 +        this(source, token, finish, name, init, true);
   51.19 +    }
   51.20 +
   51.21 +    /**
   51.22 +     * Constructor
   51.23 +     *
   51.24 +     * @param source the source
   51.25 +     * @param token  token
   51.26 +     * @param finish finish
   51.27 +     * @param name   name of variable
   51.28 +     * @param init   init node or null if just a declaration
   51.29 +     * @param isStatement if this is a var statement (true), or a for-loop initializer (false)
   51.30 +     */
   51.31 +    public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, boolean isStatement) {
   51.32          super(source, token, finish);
   51.33  
   51.34 -        this.name  = name;
   51.35 +        this.name  = init == null ? name : name.setIsInitializedHere();
   51.36          this.init  = init;
   51.37 -        if (init != null) {
   51.38 -            this.name.setIsInitializedHere();
   51.39 -        }
   51.40 +        this.isStatement = isStatement;
   51.41      }
   51.42  
   51.43 +
   51.44      private VarNode(final VarNode varNode, final CopyState cs) {
   51.45          super(varNode);
   51.46  
   51.47          this.name = (IdentNode)cs.existingOrCopy(varNode.name);
   51.48          this.init = cs.existingOrCopy(varNode.init);
   51.49 +        this.isStatement = varNode.isStatement;
   51.50      }
   51.51  
   51.52      @Override
   51.53 @@ -83,6 +97,11 @@
   51.54      }
   51.55  
   51.56      @Override
   51.57 +    public Node setAssignmentDest(IdentNode n) {
   51.58 +        return setName(n);
   51.59 +    }
   51.60 +
   51.61 +    @Override
   51.62      public Node getAssignmentSource() {
   51.63          return isAssignment() ? getInit() : null;
   51.64      }
   51.65 @@ -127,16 +146,19 @@
   51.66       */
   51.67      @Override
   51.68      public Node accept(final NodeVisitor visitor) {
   51.69 -        if (visitor.enter(this) != null) {
   51.70 -            name = (IdentNode)name.accept(visitor);
   51.71 -
   51.72 -            if (init != null) {
   51.73 -                init = init.accept(visitor);
   51.74 +        if (visitor.enterVarNode(this) != null) {
   51.75 +            final IdentNode newName = (IdentNode)name.accept(visitor);
   51.76 +            final Node newInit = init == null ? null : init.accept(visitor);
   51.77 +            final VarNode newThis;
   51.78 +            if(name != newName || init != newInit) {
   51.79 +                newThis = (VarNode)clone();
   51.80 +                newThis.init = newInit;
   51.81 +                newThis.name = newInit == null ? newName : newName.setIsInitializedHere();
   51.82 +            } else {
   51.83 +                newThis = this;
   51.84              }
   51.85 -
   51.86 -            return visitor.leave(this);
   51.87 +            return visitor.leaveVarNode(newThis);
   51.88          }
   51.89 -
   51.90          return this;
   51.91      }
   51.92  
   51.93 @@ -162,9 +184,13 @@
   51.94      /**
   51.95       * Reset the initialization expression
   51.96       * @param init new initialization expression
   51.97 +     * @return a node equivalent to this one except for the requested change.
   51.98       */
   51.99 -    public void setInit(final Node init) {
  51.100 -        this.init = init;
  51.101 +    public VarNode setInit(final Node init) {
  51.102 +        if(this.init == init) return this;
  51.103 +        final VarNode n = (VarNode)clone();
  51.104 +        n.init = init;
  51.105 +        return n;
  51.106      }
  51.107  
  51.108      /**
  51.109 @@ -179,30 +205,26 @@
  51.110       * Reset the identifier for this VarNode
  51.111       * @param name new IdentNode representing the variable being set or declared
  51.112       */
  51.113 -    public void setName(final IdentNode name) {
  51.114 -        this.name = name;
  51.115 +    private VarNode setName(final IdentNode name) {
  51.116 +        if(this.name == name) return this;
  51.117 +        final VarNode n = (VarNode)clone();
  51.118 +        n.name = name;
  51.119 +        return n;
  51.120      }
  51.121  
  51.122      /**
  51.123 -     * Check if this is a virtual assignment of a function node. Function nodes declared
  51.124 -     * with a name are hoisted to the top of the scope and appear as symbols too. This is
  51.125 -     * implemented by representing them as virtual VarNode assignments added to the code
  51.126 -     * during lowering
  51.127 -     *
  51.128 -     * @see FunctionNode
  51.129 -     *
  51.130 -     * @return true if this is a virtual function declaration
  51.131 +     * Returns true if this is a var statement (as opposed to a var initializer in a for loop).
  51.132 +     * @return true if this is a var statement (as opposed to a var initializer in a for loop).
  51.133       */
  51.134 -    public boolean isFunctionVarNode() {
  51.135 -        return isFunctionVarNode;
  51.136 +    public boolean isStatement() {
  51.137 +        return isStatement;
  51.138      }
  51.139  
  51.140      /**
  51.141 -     * Flag this var node as a virtual function var node assignment as described in
  51.142 -     * {@link VarNode#isFunctionVarNode()}
  51.143 +     * Returns true if this is a function declaration.
  51.144 +     * @return true if this is a function declaration.
  51.145       */
  51.146 -    public void setIsFunctionVarNode() {
  51.147 -        this.isFunctionVarNode = true;
  51.148 +    public boolean isFunctionDeclaration() {
  51.149 +        return init instanceof FunctionNode && ((FunctionNode)init).isDeclared();
  51.150      }
  51.151 -
  51.152  }
    52.1 --- a/src/jdk/nashorn/internal/ir/WhileNode.java	Tue Mar 19 11:03:24 2013 -0300
    52.2 +++ b/src/jdk/nashorn/internal/ir/WhileNode.java	Sat Mar 23 00:58:39 2013 +0100
    52.3 @@ -88,11 +88,11 @@
    52.4       */
    52.5      @Override
    52.6      public Node accept(final NodeVisitor visitor) {
    52.7 -        if (visitor.enter(this) != null) {
    52.8 +        if (visitor.enterWhileNode(this) != null) {
    52.9              test = test.accept(visitor);
   52.10              body = (Block)body.accept(visitor);
   52.11  
   52.12 -            return visitor.leave(this);
   52.13 +            return visitor.leaveWhileNode(this);
   52.14          }
   52.15          return this;
   52.16      }
    53.1 --- a/src/jdk/nashorn/internal/ir/WithNode.java	Tue Mar 19 11:03:24 2013 -0300
    53.2 +++ b/src/jdk/nashorn/internal/ir/WithNode.java	Sat Mar 23 00:58:39 2013 +0100
    53.3 @@ -73,10 +73,10 @@
    53.4       */
    53.5      @Override
    53.6      public Node accept(final NodeVisitor visitor) {
    53.7 -        if (visitor.enter(this) != null) {
    53.8 +        if (visitor.enterWithNode(this) != null) {
    53.9              expression = expression.accept(visitor);
   53.10              body = (Block)body.accept(visitor);
   53.11 -            return visitor.leave(this);
   53.12 +            return visitor.leaveWithNode(this);
   53.13          }
   53.14  
   53.15          return this;
    54.1 --- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Tue Mar 19 11:03:24 2013 -0300
    54.2 +++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Sat Mar 23 00:58:39 2013 +0100
    54.3 @@ -112,7 +112,7 @@
    54.4      }
    54.5  
    54.6      @Override
    54.7 -    public Node enter(final AccessNode accessNode) {
    54.8 +    public Node enterAccessNode(final AccessNode accessNode) {
    54.9          enterDefault(accessNode);
   54.10  
   54.11          type("MemberExpression");
   54.12 @@ -132,7 +132,7 @@
   54.13      }
   54.14  
   54.15      @Override
   54.16 -    public Node enter(final Block block) {
   54.17 +    public Node enterBlock(final Block block) {
   54.18          enterDefault(block);
   54.19  
   54.20          type("BlockStatement");
   54.21 @@ -154,7 +154,7 @@
   54.22      }
   54.23  
   54.24      @Override
   54.25 -    public Node enter(final BinaryNode binaryNode) {
   54.26 +    public Node enterBinaryNode(final BinaryNode binaryNode) {
   54.27          enterDefault(binaryNode);
   54.28  
   54.29          final String name;
   54.30 @@ -183,7 +183,7 @@
   54.31      }
   54.32  
   54.33      @Override
   54.34 -    public Node enter(final BreakNode breakNode) {
   54.35 +    public Node enterBreakNode(final BreakNode breakNode) {
   54.36          enterDefault(breakNode);
   54.37  
   54.38          type("BreakStatement");
   54.39 @@ -201,7 +201,7 @@
   54.40      }
   54.41  
   54.42      @Override
   54.43 -    public Node enter(final CallNode callNode) {
   54.44 +    public Node enterCallNode(final CallNode callNode) {
   54.45          enterDefault(callNode);
   54.46  
   54.47          type("CallExpression");
   54.48 @@ -217,7 +217,7 @@
   54.49      }
   54.50  
   54.51      @Override
   54.52 -    public Node enter(final CaseNode caseNode) {
   54.53 +    public Node enterCaseNode(final CaseNode caseNode) {
   54.54          enterDefault(caseNode);
   54.55  
   54.56          type("SwitchCase");
   54.57 @@ -238,7 +238,7 @@
   54.58      }
   54.59  
   54.60      @Override
   54.61 -    public Node enter(final CatchNode catchNode) {
   54.62 +    public Node enterCatchNode(final CatchNode catchNode) {
   54.63          enterDefault(catchNode);
   54.64  
   54.65          type("CatchClause");
   54.66 @@ -264,7 +264,7 @@
   54.67      }
   54.68  
   54.69      @Override
   54.70 -    public Node enter(final ContinueNode continueNode) {
   54.71 +    public Node enterContinueNode(final ContinueNode continueNode) {
   54.72          enterDefault(continueNode);
   54.73  
   54.74          type("ContinueStatement");
   54.75 @@ -282,7 +282,7 @@
   54.76      }
   54.77  
   54.78      @Override
   54.79 -    public Node enter(final DoWhileNode doWhileNode) {
   54.80 +    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
   54.81          enterDefault(doWhileNode);
   54.82  
   54.83          type("DoWhileStatement");
   54.84 @@ -299,7 +299,7 @@
   54.85      }
   54.86  
   54.87      @Override
   54.88 -    public Node enter(final EmptyNode emptyNode) {
   54.89 +    public Node enterEmptyNode(final EmptyNode emptyNode) {
   54.90          enterDefault(emptyNode);
   54.91  
   54.92          type("EmptyStatement");
   54.93 @@ -308,7 +308,7 @@
   54.94      }
   54.95  
   54.96      @Override
   54.97 -    public Node enter(final ExecuteNode executeNode) {
   54.98 +    public Node enterExecuteNode(final ExecuteNode executeNode) {
   54.99          enterDefault(executeNode);
  54.100  
  54.101          type("ExpressionStatement");
  54.102 @@ -321,7 +321,7 @@
  54.103      }
  54.104  
  54.105      @Override
  54.106 -    public Node enter(final ForNode forNode) {
  54.107 +    public Node enterForNode(final ForNode forNode) {
  54.108          enterDefault(forNode);
  54.109  
  54.110          if (forNode.isForIn() || (forNode.isForEach() && forNode.getInit() != null)) {
  54.111 @@ -384,14 +384,14 @@
  54.112      }
  54.113  
  54.114      @Override
  54.115 -    public Node enter(final FunctionNode functionNode) {
  54.116 +    public Node enterFunctionNode(final FunctionNode functionNode) {
  54.117          enterDefault(functionNode);
  54.118  
  54.119 -        final boolean program = functionNode.isScript();
  54.120 +        final boolean program = functionNode.isProgram();
  54.121          final String name;
  54.122          if (program) {
  54.123              name = "Program";
  54.124 -        } else if (functionNode.isStatement()) {
  54.125 +        } else if (functionNode.isDeclared()) {
  54.126              name = "FunctionDeclaration";
  54.127          } else {
  54.128              name = "FunctionExpression";
  54.129 @@ -419,20 +419,11 @@
  54.130          }
  54.131  
  54.132          // body consists of nested functions and statements
  54.133 -        final List<FunctionNode> funcs = functionNode.getFunctions();
  54.134          final List<Node> stats = functionNode.getStatements();
  54.135 -        final int size = stats.size() + funcs.size();
  54.136 +        final int size = stats.size();
  54.137          int idx = 0;
  54.138          arrayStart("body");
  54.139  
  54.140 -        for (final Node func : funcs) {
  54.141 -            func.accept(this);
  54.142 -            if (idx != (size - 1)) {
  54.143 -                comma();
  54.144 -            }
  54.145 -            idx++;
  54.146 -        }
  54.147 -
  54.148          for (final Node stat : stats) {
  54.149              if (! stat.isDebug()) {
  54.150                  stat.accept(this);
  54.151 @@ -448,7 +439,7 @@
  54.152      }
  54.153  
  54.154      @Override
  54.155 -    public Node enter(final IdentNode identNode) {
  54.156 +    public Node enterIdentNode(final IdentNode identNode) {
  54.157          enterDefault(identNode);
  54.158  
  54.159          final String name = identNode.getName();
  54.160 @@ -464,7 +455,7 @@
  54.161      }
  54.162  
  54.163      @Override
  54.164 -    public Node enter(final IfNode ifNode) {
  54.165 +    public Node enterIfNode(final IfNode ifNode) {
  54.166          enterDefault(ifNode);
  54.167  
  54.168          type("IfStatement");
  54.169 @@ -490,7 +481,7 @@
  54.170      }
  54.171  
  54.172      @Override
  54.173 -    public Node enter(final IndexNode indexNode) {
  54.174 +    public Node enterIndexNode(final IndexNode indexNode) {
  54.175          enterDefault(indexNode);
  54.176  
  54.177          type("MemberExpression");
  54.178 @@ -510,7 +501,7 @@
  54.179      }
  54.180  
  54.181      @Override
  54.182 -    public Node enter(final LabelNode labelNode) {
  54.183 +    public Node enterLabelNode(final LabelNode labelNode) {
  54.184          enterDefault(labelNode);
  54.185  
  54.186          type("LabeledStatement");
  54.187 @@ -527,13 +518,13 @@
  54.188      }
  54.189  
  54.190      @Override
  54.191 -    public Node enter(final LineNumberNode lineNumberNode) {
  54.192 +    public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
  54.193          return null;
  54.194      }
  54.195  
  54.196      @SuppressWarnings("rawtypes")
  54.197      @Override
  54.198 -    public Node enter(final LiteralNode literalNode) {
  54.199 +    public Node enterLiteralNode(final LiteralNode literalNode) {
  54.200          enterDefault(literalNode);
  54.201  
  54.202          if (literalNode instanceof LiteralNode.ArrayLiteralNode) {
  54.203 @@ -569,7 +560,7 @@
  54.204      }
  54.205  
  54.206      @Override
  54.207 -    public Node enter(final ObjectNode objectNode) {
  54.208 +    public Node enterObjectNode(final ObjectNode objectNode) {
  54.209          enterDefault(objectNode);
  54.210  
  54.211          type("ObjectExpression");
  54.212 @@ -581,7 +572,7 @@
  54.213      }
  54.214  
  54.215      @Override
  54.216 -    public Node enter(final PropertyNode propertyNode) {
  54.217 +    public Node enterPropertyNode(final PropertyNode propertyNode) {
  54.218          final Node key = propertyNode.getKey();
  54.219  
  54.220          final Node value = propertyNode.getValue();
  54.221 @@ -647,7 +638,7 @@
  54.222      }
  54.223  
  54.224      @Override
  54.225 -    public Node enter(final ReturnNode returnNode) {
  54.226 +    public Node enterReturnNode(final ReturnNode returnNode) {
  54.227          enterDefault(returnNode);
  54.228  
  54.229          type("ReturnStatement");
  54.230 @@ -665,7 +656,7 @@
  54.231      }
  54.232  
  54.233      @Override
  54.234 -    public Node enter(final RuntimeNode runtimeNode) {
  54.235 +    public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
  54.236          final RuntimeNode.Request req = runtimeNode.getRequest();
  54.237  
  54.238          if (req == RuntimeNode.Request.DEBUGGER) {
  54.239 @@ -680,12 +671,12 @@
  54.240      }
  54.241  
  54.242      @Override
  54.243 -    public Node enter(final SplitNode splitNode) {
  54.244 +    public Node enterSplitNode(final SplitNode splitNode) {
  54.245          return null;
  54.246      }
  54.247  
  54.248      @Override
  54.249 -    public Node enter(final SwitchNode switchNode) {
  54.250 +    public Node enterSwitchNode(final SwitchNode switchNode) {
  54.251          enterDefault(switchNode);
  54.252  
  54.253          type("SwitchStatement");
  54.254 @@ -701,7 +692,7 @@
  54.255      }
  54.256  
  54.257      @Override
  54.258 -    public Node enter(final TernaryNode ternaryNode) {
  54.259 +    public Node enterTernaryNode(final TernaryNode ternaryNode) {
  54.260          enterDefault(ternaryNode);
  54.261  
  54.262          type("ConditionalExpression");
  54.263 @@ -722,7 +713,7 @@
  54.264      }
  54.265  
  54.266      @Override
  54.267 -    public Node enter(final ThrowNode throwNode) {
  54.268 +    public Node enterThrowNode(final ThrowNode throwNode) {
  54.269          enterDefault(throwNode);
  54.270  
  54.271          type("ThrowStatement");
  54.272 @@ -735,7 +726,7 @@
  54.273      }
  54.274  
  54.275      @Override
  54.276 -    public Node enter(final TryNode tryNode) {
  54.277 +    public Node enterTryNode(final TryNode tryNode) {
  54.278          enterDefault(tryNode);
  54.279  
  54.280          type("TryStatement");
  54.281 @@ -760,7 +751,7 @@
  54.282      }
  54.283  
  54.284      @Override
  54.285 -    public Node enter(final UnaryNode unaryNode) {
  54.286 +    public Node enterUnaryNode(final UnaryNode unaryNode) {
  54.287          enterDefault(unaryNode);
  54.288  
  54.289          final TokenType tokenType = unaryNode.tokenType();
  54.290 @@ -816,7 +807,7 @@
  54.291      }
  54.292  
  54.293      @Override
  54.294 -    public Node enter(final VarNode varNode) {
  54.295 +    public Node enterVarNode(final VarNode varNode) {
  54.296          enterDefault(varNode);
  54.297  
  54.298          type("VariableDeclaration");
  54.299 @@ -852,7 +843,7 @@
  54.300      }
  54.301  
  54.302      @Override
  54.303 -    public Node enter(final WhileNode whileNode) {
  54.304 +    public Node enterWhileNode(final WhileNode whileNode) {
  54.305          enterDefault(whileNode);
  54.306  
  54.307          type("WhileStatement");
  54.308 @@ -869,7 +860,7 @@
  54.309      }
  54.310  
  54.311      @Override
  54.312 -    public Node enter(final WithNode withNode) {
  54.313 +    public Node enterWithNode(final WithNode withNode) {
  54.314          enterDefault(withNode);
  54.315  
  54.316          type("WithStatement");
    55.1 --- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java	Tue Mar 19 11:03:24 2013 -0300
    55.2 +++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java	Sat Mar 23 00:58:39 2013 +0100
    55.3 @@ -42,7 +42,6 @@
    55.4  import jdk.nashorn.internal.ir.LabelNode;
    55.5  import jdk.nashorn.internal.ir.LineNumberNode;
    55.6  import jdk.nashorn.internal.ir.Node;
    55.7 -import jdk.nashorn.internal.ir.ReferenceNode;
    55.8  import jdk.nashorn.internal.ir.ReturnNode;
    55.9  import jdk.nashorn.internal.ir.RuntimeNode;
   55.10  import jdk.nashorn.internal.ir.SplitNode;
   55.11 @@ -138,13 +137,13 @@
   55.12       * Visits.
   55.13       */
   55.14      @Override
   55.15 -    public Node enter(final AccessNode accessNode) {
   55.16 +    public Node enterAccessNode(final AccessNode accessNode) {
   55.17          accessNode.toString(sb);
   55.18          return null;
   55.19      }
   55.20  
   55.21      @Override
   55.22 -    public Node enter(final Block block) {
   55.23 +    public Node enterBlock(final Block block) {
   55.24          sb.append(' ');
   55.25          sb.append('{');
   55.26  
   55.27 @@ -152,21 +151,6 @@
   55.28  
   55.29          final boolean isFunction = block instanceof FunctionNode;
   55.30  
   55.31 -        if (isFunction) {
   55.32 -            final FunctionNode       function  = (FunctionNode)block;
   55.33 -            final List<FunctionNode> functions = function.getFunctions();
   55.34 -
   55.35 -            for (final FunctionNode f : functions) {
   55.36 -                sb.append(EOLN);
   55.37 -                indent();
   55.38 -                f.accept(this);
   55.39 -            }
   55.40 -
   55.41 -            if (!functions.isEmpty()) {
   55.42 -                sb.append(EOLN);
   55.43 -            }
   55.44 -        }
   55.45 -
   55.46          final List<Node> statements = block.getStatements();
   55.47  
   55.48          boolean lastLineNumber = false;
   55.49 @@ -224,25 +208,25 @@
   55.50      }
   55.51  
   55.52      @Override
   55.53 -    public Node enter(final BreakNode breakNode) {
   55.54 +    public Node enterBreakNode(final BreakNode breakNode) {
   55.55          breakNode.toString(sb);
   55.56          return null;
   55.57      }
   55.58  
   55.59      @Override
   55.60 -    public Node enter(final CallNode callNode) {
   55.61 +    public Node enterCallNode(final CallNode callNode) {
   55.62          callNode.toString(sb);
   55.63          return null;
   55.64      }
   55.65  
   55.66      @Override
   55.67 -    public Node enter(final ContinueNode continueNode) {
   55.68 +    public Node enterContinueNode(final ContinueNode continueNode) {
   55.69          continueNode.toString(sb);
   55.70          return null;
   55.71      }
   55.72  
   55.73      @Override
   55.74 -    public Node enter(final DoWhileNode doWhileNode) {
   55.75 +    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
   55.76          sb.append("do");
   55.77          doWhileNode.getBody().accept(this);
   55.78          sb.append(' ');
   55.79 @@ -252,7 +236,7 @@
   55.80      }
   55.81  
   55.82      @Override
   55.83 -    public Node enter(final ExecuteNode executeNode) {
   55.84 +    public Node enterExecuteNode(final ExecuteNode executeNode) {
   55.85          final Node expression = executeNode.getExpression();
   55.86  
   55.87          if (expression instanceof UnaryNode) {
   55.88 @@ -265,7 +249,7 @@
   55.89      }
   55.90  
   55.91      @Override
   55.92 -    public Node enter(final ForNode forNode) {
   55.93 +    public Node enterForNode(final ForNode forNode) {
   55.94          forNode.toString(sb);
   55.95          forNode.getBody().accept(this);
   55.96  
   55.97 @@ -273,15 +257,15 @@
   55.98      }
   55.99  
  55.100      @Override
  55.101 -    public Node enter(final FunctionNode functionNode) {
  55.102 +    public Node enterFunctionNode(final FunctionNode functionNode) {
  55.103          functionNode.toString(sb);
  55.104 -        enter((Block)functionNode);
  55.105 +        enterBlock(functionNode);
  55.106  
  55.107          return null;
  55.108      }
  55.109  
  55.110      @Override
  55.111 -    public Node enter(final IfNode ifNode) {
  55.112 +    public Node enterIfNode(final IfNode ifNode) {
  55.113          ifNode.toString(sb);
  55.114          ifNode.getPass().accept(this);
  55.115  
  55.116 @@ -296,13 +280,13 @@
  55.117      }
  55.118  
  55.119      @Override
  55.120 -    public Node enter(final IndexNode indexNode) {
  55.121 +    public Node enterIndexNode(final IndexNode indexNode) {
  55.122          indexNode.toString(sb);
  55.123          return null;
  55.124      }
  55.125  
  55.126      @Override
  55.127 -    public Node enter(final LabelNode labeledNode) {
  55.128 +    public Node enterLabelNode(final LabelNode labeledNode) {
  55.129          indent -= TABWIDTH;
  55.130          indent();
  55.131          indent += TABWIDTH;
  55.132 @@ -313,7 +297,7 @@
  55.133      }
  55.134  
  55.135      @Override
  55.136 -    public Node enter(final LineNumberNode lineNumberNode) {
  55.137 +    public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
  55.138          if (printLineNumbers) {
  55.139              lineNumberNode.toString(sb);
  55.140          }
  55.141 @@ -323,25 +307,19 @@
  55.142  
  55.143  
  55.144      @Override
  55.145 -    public Node enter(final ReferenceNode referenceNode) {
  55.146 -        referenceNode.toString(sb);
  55.147 -        return null;
  55.148 -    }
  55.149 -
  55.150 -    @Override
  55.151 -    public Node enter(final ReturnNode returnNode) {
  55.152 +    public Node enterReturnNode(final ReturnNode returnNode) {
  55.153          returnNode.toString(sb);
  55.154          return null;
  55.155      }
  55.156  
  55.157      @Override
  55.158 -    public Node enter(final RuntimeNode runtimeNode) {
  55.159 +    public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
  55.160          runtimeNode.toString(sb);
  55.161          return null;
  55.162      }
  55.163  
  55.164      @Override
  55.165 -    public Node enter(final SplitNode splitNode) {
  55.166 +    public Node enterSplitNode(final SplitNode splitNode) {
  55.167          splitNode.toString(sb);
  55.168          sb.append(EOLN);
  55.169          indent += TABWIDTH;
  55.170 @@ -350,7 +328,7 @@
  55.171      }
  55.172  
  55.173      @Override
  55.174 -    public Node leave(final SplitNode splitNode) {
  55.175 +    public Node leaveSplitNode(final SplitNode splitNode) {
  55.176          sb.append("</split>");
  55.177          sb.append(EOLN);
  55.178          indent -= TABWIDTH;
  55.179 @@ -359,7 +337,7 @@
  55.180      }
  55.181  
  55.182      @Override
  55.183 -    public Node enter(final SwitchNode switchNode) {
  55.184 +    public Node enterSwitchNode(final SwitchNode switchNode) {
  55.185          switchNode.toString(sb);
  55.186          sb.append(" {");
  55.187  
  55.188 @@ -383,13 +361,13 @@
  55.189     }
  55.190  
  55.191      @Override
  55.192 -    public Node enter(final ThrowNode throwNode) {
  55.193 +    public Node enterThrowNode(final ThrowNode throwNode) {
  55.194          throwNode.toString(sb);
  55.195          return null;
  55.196      }
  55.197  
  55.198      @Override
  55.199 -    public Node enter(final TryNode tryNode) {
  55.200 +    public Node enterTryNode(final TryNode tryNode) {
  55.201          tryNode.toString(sb);
  55.202          tryNode.getBody().accept(this);
  55.203  
  55.204 @@ -412,13 +390,19 @@
  55.205      }
  55.206  
  55.207      @Override
  55.208 -    public Node enter(final VarNode varNode) {
  55.209 -        varNode.toString(sb);
  55.210 +    public Node enterVarNode(final VarNode varNode) {
  55.211 +        sb.append("var ");
  55.212 +        varNode.getName().toString(sb);
  55.213 +        final Node init = varNode.getInit();
  55.214 +        if(init != null) {
  55.215 +            sb.append(" = ");
  55.216 +            init.accept(this);
  55.217 +        }
  55.218          return null;
  55.219      }
  55.220  
  55.221      @Override
  55.222 -    public Node enter(final WhileNode whileNode) {
  55.223 +    public Node enterWhileNode(final WhileNode whileNode) {
  55.224          whileNode.toString(sb);
  55.225          whileNode.getBody().accept(this);
  55.226  
  55.227 @@ -426,7 +410,7 @@
  55.228      }
  55.229  
  55.230      @Override
  55.231 -    public Node enter(final WithNode withNode) {
  55.232 +    public Node enterWithNode(final WithNode withNode) {
  55.233          withNode.toString(sb);
  55.234          withNode.getBody().accept(this);
  55.235  
    56.1 --- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Tue Mar 19 11:03:24 2013 -0300
    56.2 +++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Sat Mar 23 00:58:39 2013 +0100
    56.3 @@ -53,7 +53,7 @@
    56.4      }
    56.5  
    56.6      @Override
    56.7 -    public final Node enter(final UnaryNode unaryNode) {
    56.8 +    public final Node enterUnaryNode(final UnaryNode unaryNode) {
    56.9          switch (unaryNode.tokenType()) {
   56.10          case ADD:
   56.11              return enterADD(unaryNode);
   56.12 @@ -81,12 +81,12 @@
   56.13          case INCPOSTFIX:
   56.14              return enterDECINC(unaryNode);
   56.15          default:
   56.16 -            return super.enter(unaryNode);
   56.17 +            return super.enterUnaryNode(unaryNode);
   56.18          }
   56.19      }
   56.20  
   56.21      @Override
   56.22 -    public final Node leave(final UnaryNode unaryNode) {
   56.23 +    public final Node leaveUnaryNode(final UnaryNode unaryNode) {
   56.24          switch (unaryNode.tokenType()) {
   56.25          case ADD:
   56.26              return leaveADD(unaryNode);
   56.27 @@ -114,12 +114,12 @@
   56.28          case INCPOSTFIX:
   56.29              return leaveDECINC(unaryNode);
   56.30          default:
   56.31 -            return super.leave(unaryNode);
   56.32 +            return super.leaveUnaryNode(unaryNode);
   56.33          }
   56.34      }
   56.35  
   56.36      @Override
   56.37 -    public final Node enter(final BinaryNode binaryNode) {
   56.38 +    public final Node enterBinaryNode(final BinaryNode binaryNode) {
   56.39          switch (binaryNode.tokenType()) {
   56.40          case ADD:
   56.41              return enterADD(binaryNode);
   56.42 @@ -198,12 +198,12 @@
   56.43          case SUB:
   56.44              return enterSUB(binaryNode);
   56.45          default:
   56.46 -            return super.enter(binaryNode);
   56.47 +            return super.enterBinaryNode(binaryNode);
   56.48          }
   56.49      }
   56.50  
   56.51      @Override
   56.52 -    public final Node leave(final BinaryNode binaryNode) {
   56.53 +    public final Node leaveBinaryNode(final BinaryNode binaryNode) {
   56.54          switch (binaryNode.tokenType()) {
   56.55          case ADD:
   56.56              return leaveADD(binaryNode);
   56.57 @@ -282,7 +282,7 @@
   56.58          case SUB:
   56.59              return leaveSUB(binaryNode);
   56.60          default:
   56.61 -            return super.leave(binaryNode);
   56.62 +            return super.leaveBinaryNode(binaryNode);
   56.63          }
   56.64      }
   56.65  
    57.1 --- a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Tue Mar 19 11:03:24 2013 -0300
    57.2 +++ b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Sat Mar 23 00:58:39 2013 +0100
    57.3 @@ -49,7 +49,6 @@
    57.4  import jdk.nashorn.internal.ir.Node;
    57.5  import jdk.nashorn.internal.ir.ObjectNode;
    57.6  import jdk.nashorn.internal.ir.PropertyNode;
    57.7 -import jdk.nashorn.internal.ir.ReferenceNode;
    57.8  import jdk.nashorn.internal.ir.ReturnNode;
    57.9  import jdk.nashorn.internal.ir.RuntimeNode;
   57.10  import jdk.nashorn.internal.ir.SplitNode;
   57.11 @@ -153,7 +152,7 @@
   57.12       * @param  accessNode the node
   57.13       * @return processed node, null if traversal should end, null if traversal should end
   57.14       */
   57.15 -    public Node enter(final AccessNode accessNode) {
   57.16 +    public Node enterAccessNode(final AccessNode accessNode) {
   57.17          return enterDefault(accessNode);
   57.18      }
   57.19  
   57.20 @@ -163,7 +162,7 @@
   57.21       * @param  accessNode the node
   57.22       * @return processed node, null if traversal should end
   57.23       */
   57.24 -    public Node leave(final AccessNode accessNode) {
   57.25 +    public Node leaveAccessNode(final AccessNode accessNode) {
   57.26          return leaveDefault(accessNode);
   57.27      }
   57.28  
   57.29 @@ -173,7 +172,7 @@
   57.30       * @param  block     the node
   57.31       * @return processed node, null if traversal should end
   57.32       */
   57.33 -    public Node enter(final Block block) {
   57.34 +    public Node enterBlock(final Block block) {
   57.35          return enterDefault(block);
   57.36      }
   57.37  
   57.38 @@ -183,7 +182,7 @@
   57.39       * @param  block the node
   57.40       * @return processed node, which will replace the original one, or the original node
   57.41       */
   57.42 -    public Node leave(final Block block) {
   57.43 +    public Node leaveBlock(final Block block) {
   57.44          return leaveDefault(block);
   57.45      }
   57.46  
   57.47 @@ -193,7 +192,7 @@
   57.48       * @param  binaryNode  the node
   57.49       * @return processed   node
   57.50       */
   57.51 -    public Node enter(final BinaryNode binaryNode) {
   57.52 +    public Node enterBinaryNode(final BinaryNode binaryNode) {
   57.53          return enterDefault(binaryNode);
   57.54      }
   57.55  
   57.56 @@ -203,7 +202,7 @@
   57.57       * @param  binaryNode the node
   57.58       * @return processed node, which will replace the original one, or the original node
   57.59       */
   57.60 -    public Node leave(final BinaryNode binaryNode) {
   57.61 +    public Node leaveBinaryNode(final BinaryNode binaryNode) {
   57.62          return leaveDefault(binaryNode);
   57.63      }
   57.64  
   57.65 @@ -213,7 +212,7 @@
   57.66       * @param  breakNode the node
   57.67       * @return processed node, null if traversal should end
   57.68       */
   57.69 -    public Node enter(final BreakNode breakNode) {
   57.70 +    public Node enterBreakNode(final BreakNode breakNode) {
   57.71          return enterDefault(breakNode);
   57.72      }
   57.73  
   57.74 @@ -223,7 +222,7 @@
   57.75       * @param  breakNode the node
   57.76       * @return processed node, which will replace the original one, or the original node
   57.77       */
   57.78 -    public Node leave(final BreakNode breakNode) {
   57.79 +    public Node leaveBreakNode(final BreakNode breakNode) {
   57.80          return leaveDefault(breakNode);
   57.81      }
   57.82  
   57.83 @@ -233,7 +232,7 @@
   57.84       * @param  callNode  the node
   57.85       * @return processed node, null if traversal should end
   57.86       */
   57.87 -    public Node enter(final CallNode callNode) {
   57.88 +    public Node enterCallNode(final CallNode callNode) {
   57.89          return enterDefault(callNode);
   57.90      }
   57.91  
   57.92 @@ -243,7 +242,7 @@
   57.93       * @param  callNode the node
   57.94       * @return processed node, which will replace the original one, or the original node
   57.95       */
   57.96 -    public Node leave(final CallNode callNode) {
   57.97 +    public Node leaveCallNode(final CallNode callNode) {
   57.98          return leaveDefault(callNode);
   57.99      }
  57.100  
  57.101 @@ -253,7 +252,7 @@
  57.102       * @param  caseNode  the node
  57.103       * @return processed node, null if traversal should end
  57.104       */
  57.105 -    public Node enter(final CaseNode caseNode) {
  57.106 +    public Node enterCaseNode(final CaseNode caseNode) {
  57.107          return enterDefault(caseNode);
  57.108      }
  57.109  
  57.110 @@ -263,7 +262,7 @@
  57.111       * @param  caseNode the node
  57.112       * @return processed node, which will replace the original one, or the original node
  57.113       */
  57.114 -    public Node leave(final CaseNode caseNode) {
  57.115 +    public Node leaveCaseNode(final CaseNode caseNode) {
  57.116          return leaveDefault(caseNode);
  57.117      }
  57.118  
  57.119 @@ -273,7 +272,7 @@
  57.120       * @param  catchNode the node
  57.121       * @return processed node, null if traversal should end
  57.122       */
  57.123 -    public Node enter(final CatchNode catchNode) {
  57.124 +    public Node enterCatchNode(final CatchNode catchNode) {
  57.125          return enterDefault(catchNode);
  57.126      }
  57.127  
  57.128 @@ -283,7 +282,7 @@
  57.129       * @param  catchNode the node
  57.130       * @return processed node, which will replace the original one, or the original node
  57.131       */
  57.132 -    public Node leave(final CatchNode catchNode) {
  57.133 +    public Node leaveCatchNode(final CatchNode catchNode) {
  57.134          return leaveDefault(catchNode);
  57.135      }
  57.136  
  57.137 @@ -293,7 +292,7 @@
  57.138       * @param  continueNode the node
  57.139       * @return processed node, null if traversal should end
  57.140       */
  57.141 -    public Node enter(final ContinueNode continueNode) {
  57.142 +    public Node enterContinueNode(final ContinueNode continueNode) {
  57.143          return enterDefault(continueNode);
  57.144      }
  57.145  
  57.146 @@ -303,7 +302,7 @@
  57.147       * @param  continueNode the node
  57.148       * @return processed node, which will replace the original one, or the original node
  57.149       */
  57.150 -    public Node leave(final ContinueNode continueNode) {
  57.151 +    public Node leaveContinueNode(final ContinueNode continueNode) {
  57.152          return leaveDefault(continueNode);
  57.153      }
  57.154  
  57.155 @@ -313,7 +312,7 @@
  57.156       * @param  doWhileNode the node
  57.157       * @return processed   node
  57.158       */
  57.159 -    public Node enter(final DoWhileNode doWhileNode) {
  57.160 +    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
  57.161          return enterDefault(doWhileNode);
  57.162      }
  57.163  
  57.164 @@ -323,7 +322,7 @@
  57.165       * @param  doWhileNode the node
  57.166       * @return processed node, which will replace the original one, or the original node
  57.167       */
  57.168 -    public Node leave(final DoWhileNode doWhileNode) {
  57.169 +    public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
  57.170          return leaveDefault(doWhileNode);
  57.171      }
  57.172  
  57.173 @@ -333,7 +332,7 @@
  57.174       * @param  emptyNode   the node
  57.175       * @return processed   node
  57.176       */
  57.177 -    public Node enter(final EmptyNode emptyNode) {
  57.178 +    public Node enterEmptyNode(final EmptyNode emptyNode) {
  57.179          return enterDefault(emptyNode);
  57.180      }
  57.181  
  57.182 @@ -343,7 +342,7 @@
  57.183       * @param  emptyNode the node
  57.184       * @return processed node, which will replace the original one, or the original node
  57.185       */
  57.186 -    public Node leave(final EmptyNode emptyNode) {
  57.187 +    public Node leaveEmptyNode(final EmptyNode emptyNode) {
  57.188          return leaveDefault(emptyNode);
  57.189      }
  57.190  
  57.191 @@ -353,7 +352,7 @@
  57.192       * @param  executeNode the node
  57.193       * @return processed node, null if traversal should end
  57.194       */
  57.195 -    public Node enter(final ExecuteNode executeNode) {
  57.196 +    public Node enterExecuteNode(final ExecuteNode executeNode) {
  57.197          return enterDefault(executeNode);
  57.198      }
  57.199  
  57.200 @@ -363,7 +362,7 @@
  57.201       * @param  executeNode the node
  57.202       * @return processed node, which will replace the original one, or the original node
  57.203       */
  57.204 -    public Node leave(final ExecuteNode executeNode) {
  57.205 +    public Node leaveExecuteNode(final ExecuteNode executeNode) {
  57.206          return leaveDefault(executeNode);
  57.207      }
  57.208  
  57.209 @@ -373,7 +372,7 @@
  57.210       * @param  forNode   the node
  57.211       * @return processed node, null if traversal should end
  57.212       */
  57.213 -    public Node enter(final ForNode forNode) {
  57.214 +    public Node enterForNode(final ForNode forNode) {
  57.215          return enterDefault(forNode);
  57.216      }
  57.217  
  57.218 @@ -383,7 +382,7 @@
  57.219       * @param  forNode the node
  57.220       * @return processed node, which will replace the original one, or the original node
  57.221       */
  57.222 -    public Node leave(final ForNode forNode) {
  57.223 +    public Node leaveForNode(final ForNode forNode) {
  57.224          return leaveDefault(forNode);
  57.225      }
  57.226  
  57.227 @@ -393,7 +392,7 @@
  57.228       * @param  functionNode the node
  57.229       * @return processed    node
  57.230       */
  57.231 -    public Node enter(final FunctionNode functionNode) {
  57.232 +    public Node enterFunctionNode(final FunctionNode functionNode) {
  57.233          return enterDefault(functionNode);
  57.234      }
  57.235  
  57.236 @@ -403,7 +402,7 @@
  57.237       * @param  functionNode the node
  57.238       * @return processed node, which will replace the original one, or the original node
  57.239       */
  57.240 -    public Node leave(final FunctionNode functionNode) {
  57.241 +    public Node leaveFunctionNode(final FunctionNode functionNode) {
  57.242          return leaveDefault(functionNode);
  57.243      }
  57.244  
  57.245 @@ -413,7 +412,7 @@
  57.246       * @param  identNode the node
  57.247       * @return processed node, null if traversal should end
  57.248       */
  57.249 -    public Node enter(final IdentNode identNode) {
  57.250 +    public Node enterIdentNode(final IdentNode identNode) {
  57.251          return enterDefault(identNode);
  57.252      }
  57.253  
  57.254 @@ -423,7 +422,7 @@
  57.255       * @param  identNode the node
  57.256       * @return processed node, which will replace the original one, or the original node
  57.257       */
  57.258 -    public Node leave(final IdentNode identNode) {
  57.259 +    public Node leaveIdentNode(final IdentNode identNode) {
  57.260          return leaveDefault(identNode);
  57.261      }
  57.262  
  57.263 @@ -433,7 +432,7 @@
  57.264       * @param  ifNode    the node
  57.265       * @return processed node, null if traversal should end
  57.266       */
  57.267 -    public Node enter(final IfNode ifNode) {
  57.268 +    public Node enterIfNode(final IfNode ifNode) {
  57.269          return enterDefault(ifNode);
  57.270      }
  57.271  
  57.272 @@ -443,7 +442,7 @@
  57.273       * @param  ifNode the node
  57.274       * @return processed node, which will replace the original one, or the original node
  57.275       */
  57.276 -    public Node leave(final IfNode ifNode) {
  57.277 +    public Node leaveIfNode(final IfNode ifNode) {
  57.278          return leaveDefault(ifNode);
  57.279      }
  57.280  
  57.281 @@ -453,7 +452,7 @@
  57.282       * @param  indexNode  the node
  57.283       * @return processed node, null if traversal should end
  57.284       */
  57.285 -    public Node enter(final IndexNode indexNode) {
  57.286 +    public Node enterIndexNode(final IndexNode indexNode) {
  57.287          return enterDefault(indexNode);
  57.288      }
  57.289  
  57.290 @@ -463,7 +462,7 @@
  57.291       * @param  indexNode the node
  57.292       * @return processed node, which will replace the original one, or the original node
  57.293       */
  57.294 -    public Node leave(final IndexNode indexNode) {
  57.295 +    public Node leaveIndexNode(final IndexNode indexNode) {
  57.296          return leaveDefault(indexNode);
  57.297      }
  57.298  
  57.299 @@ -473,7 +472,7 @@
  57.300       * @param  labelNode the node
  57.301       * @return processed node, null if traversal should end
  57.302       */
  57.303 -    public Node enter(final LabelNode labelNode) {
  57.304 +    public Node enterLabelNode(final LabelNode labelNode) {
  57.305          return enterDefault(labelNode);
  57.306      }
  57.307  
  57.308 @@ -483,7 +482,7 @@
  57.309       * @param  labelNode the node
  57.310       * @return processed node, which will replace the original one, or the original node
  57.311       */
  57.312 -    public Node leave(final LabelNode labelNode) {
  57.313 +    public Node leaveLabelNode(final LabelNode labelNode) {
  57.314          return leaveDefault(labelNode);
  57.315      }
  57.316  
  57.317 @@ -493,7 +492,7 @@
  57.318       * @param  lineNumberNode the node
  57.319       * @return processed node, null if traversal should end
  57.320       */
  57.321 -    public Node enter(final LineNumberNode lineNumberNode) {
  57.322 +    public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
  57.323          return enterDefault(lineNumberNode);
  57.324      }
  57.325  
  57.326 @@ -503,7 +502,7 @@
  57.327       * @param  lineNumberNode the node
  57.328       * @return processed node, which will replace the original one, or the original node
  57.329       */
  57.330 -    public Node leave(final LineNumberNode lineNumberNode) {
  57.331 +    public Node leaveLineNumberNode(final LineNumberNode lineNumberNode) {
  57.332          return leaveDefault(lineNumberNode);
  57.333      }
  57.334  
  57.335 @@ -513,8 +512,7 @@
  57.336       * @param  literalNode the node
  57.337       * @return processed   node
  57.338       */
  57.339 -    @SuppressWarnings("rawtypes")
  57.340 -    public Node enter(final LiteralNode literalNode) {
  57.341 +    public Node enterLiteralNode(final LiteralNode<?> literalNode) {
  57.342          return enterDefault(literalNode);
  57.343      }
  57.344  
  57.345 @@ -524,8 +522,7 @@
  57.346       * @param  literalNode the node
  57.347       * @return processed node, which will replace the original one, or the original node
  57.348       */
  57.349 -    @SuppressWarnings("rawtypes")
  57.350 -    public Node leave(final LiteralNode literalNode) {
  57.351 +    public Node leaveLiteralNode(final LiteralNode<?> literalNode) {
  57.352          return leaveDefault(literalNode);
  57.353      }
  57.354  
  57.355 @@ -535,7 +532,7 @@
  57.356       * @param  objectNode the node
  57.357       * @return processed  node
  57.358       */
  57.359 -    public Node enter(final ObjectNode objectNode) {
  57.360 +    public Node enterObjectNode(final ObjectNode objectNode) {
  57.361          return enterDefault(objectNode);
  57.362      }
  57.363  
  57.364 @@ -545,7 +542,7 @@
  57.365       * @param  objectNode the node
  57.366       * @return processed node, which will replace the original one, or the original node
  57.367       */
  57.368 -    public Node leave(final ObjectNode objectNode) {
  57.369 +    public Node leaveObjectNode(final ObjectNode objectNode) {
  57.370          return leaveDefault(objectNode);
  57.371      }
  57.372  
  57.373 @@ -555,7 +552,7 @@
  57.374       * @param  propertyNode the node
  57.375       * @return processed node, null if traversal should end
  57.376       */
  57.377 -    public Node enter(final PropertyNode propertyNode) {
  57.378 +    public Node enterPropertyNode(final PropertyNode propertyNode) {
  57.379          return enterDefault(propertyNode);
  57.380      }
  57.381  
  57.382 @@ -565,37 +562,17 @@
  57.383       * @param  propertyNode the node
  57.384       * @return processed node, which will replace the original one, or the original node
  57.385       */
  57.386 -    public Node leave(final PropertyNode propertyNode) {
  57.387 +    public Node leavePropertyNode(final PropertyNode propertyNode) {
  57.388          return leaveDefault(propertyNode);
  57.389      }
  57.390  
  57.391      /**
  57.392 -     * Callback for entering a ReferenceNode
  57.393 -     *
  57.394 -     * @param  referenceNode the node
  57.395 -     * @return processed node, null if traversal should end
  57.396 -     */
  57.397 -    public Node enter(final ReferenceNode referenceNode) {
  57.398 -        return enterDefault(referenceNode);
  57.399 -    }
  57.400 -
  57.401 -    /**
  57.402 -     * Callback for leaving a ReferenceNode
  57.403 -     *
  57.404 -     * @param  referenceNode the node
  57.405 -     * @return processed node, which will replace the original one, or the original node
  57.406 -     */
  57.407 -    public Node leave(final ReferenceNode referenceNode) {
  57.408 -        return leaveDefault(referenceNode);
  57.409 -    }
  57.410 -
  57.411 -    /**
  57.412       * Callback for entering a ReturnNode
  57.413       *
  57.414       * @param  returnNode the node
  57.415       * @return processed node, null if traversal should end
  57.416       */
  57.417 -    public Node enter(final ReturnNode returnNode) {
  57.418 +    public Node enterReturnNode(final ReturnNode returnNode) {
  57.419          return enterDefault(returnNode);
  57.420      }
  57.421  
  57.422 @@ -605,7 +582,7 @@
  57.423       * @param  returnNode the node
  57.424       * @return processed node, which will replace the original one, or the original node
  57.425       */
  57.426 -    public Node leave(final ReturnNode returnNode) {
  57.427 +    public Node leaveReturnNode(final ReturnNode returnNode) {
  57.428          return leaveDefault(returnNode);
  57.429      }
  57.430  
  57.431 @@ -615,7 +592,7 @@
  57.432       * @param  runtimeNode the node
  57.433       * @return processed node, null if traversal should end
  57.434       */
  57.435 -    public Node enter(final RuntimeNode runtimeNode) {
  57.436 +    public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
  57.437          return enterDefault(runtimeNode);
  57.438      }
  57.439  
  57.440 @@ -625,7 +602,7 @@
  57.441       * @param  runtimeNode the node
  57.442       * @return processed node, which will replace the original one, or the original node
  57.443       */
  57.444 -    public Node leave(final RuntimeNode runtimeNode) {
  57.445 +    public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
  57.446          return leaveDefault(runtimeNode);
  57.447      }
  57.448  
  57.449 @@ -635,7 +612,7 @@
  57.450       * @param  splitNode the node
  57.451       * @return processed node, null if traversal should end
  57.452       */
  57.453 -    public Node enter(final SplitNode splitNode) {
  57.454 +    public Node enterSplitNode(final SplitNode splitNode) {
  57.455          return enterDefault(splitNode);
  57.456      }
  57.457  
  57.458 @@ -645,7 +622,7 @@
  57.459       * @param  splitNode the node
  57.460       * @return processed node, which will replace the original one, or the original node
  57.461       */
  57.462 -    public Node leave(final SplitNode splitNode) {
  57.463 +    public Node leaveSplitNode(final SplitNode splitNode) {
  57.464          return leaveDefault(splitNode);
  57.465      }
  57.466  
  57.467 @@ -655,7 +632,7 @@
  57.468       * @param  switchNode the node
  57.469       * @return processed node, null if traversal should end
  57.470       */
  57.471 -    public Node enter(final SwitchNode switchNode) {
  57.472 +    public Node enterSwitchNode(final SwitchNode switchNode) {
  57.473          return enterDefault(switchNode);
  57.474      }
  57.475  
  57.476 @@ -665,7 +642,7 @@
  57.477       * @param  switchNode the node
  57.478       * @return processed node, which will replace the original one, or the original node
  57.479       */
  57.480 -    public Node leave(final SwitchNode switchNode) {
  57.481 +    public Node leaveSwitchNode(final SwitchNode switchNode) {
  57.482          return leaveDefault(switchNode);
  57.483      }
  57.484  
  57.485 @@ -675,7 +652,7 @@
  57.486       * @param  ternaryNode the node
  57.487       * @return processed node, null if traversal should end
  57.488       */
  57.489 -    public Node enter(final TernaryNode ternaryNode) {
  57.490 +    public Node enterTernaryNode(final TernaryNode ternaryNode) {
  57.491          return enterDefault(ternaryNode);
  57.492      }
  57.493  
  57.494 @@ -685,7 +662,7 @@
  57.495       * @param  ternaryNode the node
  57.496       * @return processed node, which will replace the original one, or the original node
  57.497       */
  57.498 -    public Node leave(final TernaryNode ternaryNode) {
  57.499 +    public Node leaveTernaryNode(final TernaryNode ternaryNode) {
  57.500          return leaveDefault(ternaryNode);
  57.501      }
  57.502  
  57.503 @@ -695,7 +672,7 @@
  57.504       * @param  throwNode the node
  57.505       * @return processed node, null if traversal should end
  57.506       */
  57.507 -    public Node enter(final ThrowNode throwNode) {
  57.508 +    public Node enterThrowNode(final ThrowNode throwNode) {
  57.509          return enterDefault(throwNode);
  57.510      }
  57.511  
  57.512 @@ -705,7 +682,7 @@
  57.513       * @param  throwNode the node
  57.514       * @return processed node, which will replace the original one, or the original node
  57.515       */
  57.516 -    public Node leave(final ThrowNode throwNode) {
  57.517 +    public Node leaveThrowNode(final ThrowNode throwNode) {
  57.518          return leaveDefault(throwNode);
  57.519      }
  57.520  
  57.521 @@ -715,7 +692,7 @@
  57.522       * @param  tryNode the node
  57.523       * @return processed node, null if traversal should end
  57.524       */
  57.525 -    public Node enter(final TryNode tryNode) {
  57.526 +    public Node enterTryNode(final TryNode tryNode) {
  57.527          return enterDefault(tryNode);
  57.528      }
  57.529  
  57.530 @@ -725,7 +702,7 @@
  57.531       * @param  tryNode the node
  57.532       * @return processed node, which will replace the original one, or the original node
  57.533       */
  57.534 -    public Node leave(final TryNode tryNode) {
  57.535 +    public Node leaveTryNode(final TryNode tryNode) {
  57.536          return leaveDefault(tryNode);
  57.537      }
  57.538  
  57.539 @@ -735,7 +712,7 @@
  57.540       * @param  unaryNode the node
  57.541       * @return processed node, null if traversal should end
  57.542       */
  57.543 -    public Node enter(final UnaryNode unaryNode) {
  57.544 +    public Node enterUnaryNode(final UnaryNode unaryNode) {
  57.545          return enterDefault(unaryNode);
  57.546      }
  57.547  
  57.548 @@ -745,7 +722,7 @@
  57.549       * @param  unaryNode the node
  57.550       * @return processed node, which will replace the original one, or the original node
  57.551       */
  57.552 -    public Node leave(final UnaryNode unaryNode) {
  57.553 +    public Node leaveUnaryNode(final UnaryNode unaryNode) {
  57.554          return leaveDefault(unaryNode);
  57.555      }
  57.556  
  57.557 @@ -755,7 +732,7 @@
  57.558       * @param  varNode   the node
  57.559       * @return processed node, null if traversal should end
  57.560       */
  57.561 -    public Node enter(final VarNode varNode) {
  57.562 +    public Node enterVarNode(final VarNode varNode) {
  57.563          return enterDefault(varNode);
  57.564      }
  57.565  
  57.566 @@ -765,7 +742,7 @@
  57.567       * @param  varNode the node
  57.568       * @return processed node, which will replace the original one, or the original node
  57.569       */
  57.570 -    public Node leave(final VarNode varNode) {
  57.571 +    public Node leaveVarNode(final VarNode varNode) {
  57.572          return leaveDefault(varNode);
  57.573      }
  57.574  
  57.575 @@ -775,7 +752,7 @@
  57.576       * @param  whileNode the node
  57.577       * @return processed node, null if traversal should end
  57.578       */
  57.579 -    public Node enter(final WhileNode whileNode) {
  57.580 +    public Node enterWhileNode(final WhileNode whileNode) {
  57.581          return enterDefault(whileNode);
  57.582      }
  57.583  
  57.584 @@ -785,7 +762,7 @@
  57.585       * @param  whileNode the node
  57.586       * @return processed node, which will replace the original one, or the original node
  57.587       */
  57.588 -    public Node leave(final WhileNode whileNode) {
  57.589 +    public Node leaveWhileNode(final WhileNode whileNode) {
  57.590          return leaveDefault(whileNode);
  57.591      }
  57.592  
  57.593 @@ -795,7 +772,7 @@
  57.594       * @param  withNode  the node
  57.595       * @return processed node, null if traversal should end
  57.596       */
  57.597 -    public Node enter(final WithNode withNode) {
  57.598 +    public Node enterWithNode(final WithNode withNode) {
  57.599          return enterDefault(withNode);
  57.600      }
  57.601  
  57.602 @@ -805,7 +782,7 @@
  57.603       * @param  withNode  the node
  57.604       * @return processed node, which will replace the original one, or the original node
  57.605       */
  57.606 -    public Node leave(final WithNode withNode) {
  57.607 +    public Node leaveWithNode(final WithNode withNode) {
  57.608          return leaveDefault(withNode);
  57.609      }
  57.610  
    58.1 --- a/src/jdk/nashorn/internal/parser/Parser.java	Tue Mar 19 11:03:24 2013 -0300
    58.2 +++ b/src/jdk/nashorn/internal/parser/Parser.java	Sat Mar 23 00:58:39 2013 +0100
    58.3 @@ -56,10 +56,10 @@
    58.4  import java.util.ArrayList;
    58.5  import java.util.HashMap;
    58.6  import java.util.HashSet;
    58.7 +import java.util.Iterator;
    58.8  import java.util.List;
    58.9  import java.util.Map;
   58.10  import java.util.Stack;
   58.11 -
   58.12  import jdk.nashorn.internal.codegen.CompilerConstants;
   58.13  import jdk.nashorn.internal.codegen.Namespace;
   58.14  import jdk.nashorn.internal.ir.AccessNode;
   58.15 @@ -76,17 +76,18 @@
   58.16  import jdk.nashorn.internal.ir.ExecuteNode;
   58.17  import jdk.nashorn.internal.ir.ForNode;
   58.18  import jdk.nashorn.internal.ir.FunctionNode;
   58.19 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
   58.20  import jdk.nashorn.internal.ir.IdentNode;
   58.21  import jdk.nashorn.internal.ir.IfNode;
   58.22  import jdk.nashorn.internal.ir.IndexNode;
   58.23  import jdk.nashorn.internal.ir.LabelNode;
   58.24 +import jdk.nashorn.internal.ir.LexicalContext;
   58.25  import jdk.nashorn.internal.ir.LineNumberNode;
   58.26  import jdk.nashorn.internal.ir.LiteralNode;
   58.27  import jdk.nashorn.internal.ir.Node;
   58.28  import jdk.nashorn.internal.ir.ObjectNode;
   58.29  import jdk.nashorn.internal.ir.PropertyKey;
   58.30  import jdk.nashorn.internal.ir.PropertyNode;
   58.31 -import jdk.nashorn.internal.ir.ReferenceNode;
   58.32  import jdk.nashorn.internal.ir.ReturnNode;
   58.33  import jdk.nashorn.internal.ir.RuntimeNode;
   58.34  import jdk.nashorn.internal.ir.SwitchNode;
   58.35 @@ -97,7 +98,6 @@
   58.36  import jdk.nashorn.internal.ir.VarNode;
   58.37  import jdk.nashorn.internal.ir.WhileNode;
   58.38  import jdk.nashorn.internal.ir.WithNode;
   58.39 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
   58.40  import jdk.nashorn.internal.runtime.DebugLogger;
   58.41  import jdk.nashorn.internal.runtime.ErrorManager;
   58.42  import jdk.nashorn.internal.runtime.JSErrorType;
   58.43 @@ -117,11 +117,8 @@
   58.44      /** Is scripting mode. */
   58.45      private final boolean scripting;
   58.46  
   58.47 -    /** Current function being parsed. */
   58.48 -    private FunctionNode function;
   58.49 -
   58.50 -    /** Current parsing block. */
   58.51 -    private Block block;
   58.52 +    private final LexicalContext lexicalContext = new LexicalContext();
   58.53 +    private List<Node> functionDeclarations;
   58.54  
   58.55      /** Namespace for function names where not explicitly given */
   58.56      private final Namespace namespace;
   58.57 @@ -277,7 +274,9 @@
   58.58       * @return New block.
   58.59       */
   58.60      private Block newBlock() {
   58.61 -        return block = new Block(source, token, Token.descPosition(token), block, function);
   58.62 +        final Block block = new Block(source, token, Token.descPosition(token));
   58.63 +        lexicalContext.push(block);
   58.64 +        return block;
   58.65      }
   58.66  
   58.67      /**
   58.68 @@ -290,19 +289,23 @@
   58.69          // Build function name.
   58.70          final StringBuilder sb = new StringBuilder();
   58.71  
   58.72 -        if (block != null) {
   58.73 -            block.addParentName(sb);
   58.74 +        final FunctionNode parentFunction = getFunction();
   58.75 +        if(parentFunction != null && !parentFunction.isProgram()) {
   58.76 +            sb.append(parentFunction.getName()).append('$');
   58.77          }
   58.78  
   58.79          sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.tag());
   58.80          final String name = namespace.uniqueName(sb.toString());
   58.81 -        assert function != null || name.equals(RUN_SCRIPT.tag())  : "name = " + name;// must not rename runScript().
   58.82 +        assert parentFunction != null || name.equals(RUN_SCRIPT.tag())  : "name = " + name;// must not rename runScript().
   58.83  
   58.84          // Start new block.
   58.85 -        final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, block, ident, name);
   58.86 -        block = function = functionBlock;
   58.87 -        function.setStrictMode(isStrictMode);
   58.88 -        function.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
   58.89 +        final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, ident, name);
   58.90 +        if(parentFunction == null) {
   58.91 +            functionBlock.setProgram();
   58.92 +        }
   58.93 +        functionBlock.setStrictMode(isStrictMode);
   58.94 +        functionBlock.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
   58.95 +        lexicalContext.push(functionBlock);
   58.96  
   58.97          return functionBlock;
   58.98      }
   58.99 @@ -310,9 +313,8 @@
  58.100      /**
  58.101       * Restore the current block.
  58.102       */
  58.103 -    private void restoreBlock() {
  58.104 -        block    = block.getParent();
  58.105 -        function = block.getFunction();
  58.106 +    private void restoreBlock(Block block) {
  58.107 +        lexicalContext.pop(block);
  58.108      }
  58.109  
  58.110      /**
  58.111 @@ -322,19 +324,22 @@
  58.112      private Block getBlock(final boolean needsBraces) {
  58.113          // Set up new block. Captures LBRACE.
  58.114          final Block newBlock = newBlock();
  58.115 -        pushControlNode(newBlock);
  58.116 -
  58.117 -        // Block opening brace.
  58.118 -        if (needsBraces) {
  58.119 -            expect(LBRACE);
  58.120 -        }
  58.121 -
  58.122          try {
  58.123 -            // Accumulate block statements.
  58.124 -            statementList();
  58.125 +            pushControlNode(newBlock);
  58.126 +
  58.127 +            // Block opening brace.
  58.128 +            if (needsBraces) {
  58.129 +                expect(LBRACE);
  58.130 +            }
  58.131 +
  58.132 +            try {
  58.133 +                // Accumulate block statements.
  58.134 +                statementList();
  58.135 +            } finally {
  58.136 +                popControlNode();
  58.137 +            }
  58.138          } finally {
  58.139 -            restoreBlock();
  58.140 -            popControlNode();
  58.141 +            restoreBlock(newBlock);
  58.142          }
  58.143  
  58.144          final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
  58.145 @@ -364,7 +369,7 @@
  58.146              // Accumulate statements.
  58.147              statement();
  58.148          } finally {
  58.149 -            restoreBlock();
  58.150 +            restoreBlock(newBlock);
  58.151          }
  58.152  
  58.153          return newBlock;
  58.154 @@ -378,7 +383,10 @@
  58.155          final String name = ident.getName();
  58.156  
  58.157          if (EVAL.tag().equals(name)) {
  58.158 -            function.setHasEval();
  58.159 +            final Iterator<FunctionNode> it = lexicalContext.getFunctions();
  58.160 +            if(it.hasNext()) {
  58.161 +                it.next().setHasEval(it);
  58.162 +            }
  58.163          }
  58.164      }
  58.165  
  58.166 @@ -390,7 +398,7 @@
  58.167          final String name = ident.getName();
  58.168  
  58.169          if (ARGUMENTS.tag().equals(name)) {
  58.170 -            function.setUsesArguments();
  58.171 +            getFunction().setUsesArguments();
  58.172          }
  58.173      }
  58.174  
  58.175 @@ -481,7 +489,7 @@
  58.176       * @return null or the found label node.
  58.177       */
  58.178      private LabelNode findLabel(final IdentNode ident) {
  58.179 -        for (final LabelNode labelNode : function.getLabelStack()) {
  58.180 +        for (final LabelNode labelNode : getFunction().getLabelStack()) {
  58.181              if (labelNode.getLabel().equals(ident)) {
  58.182                  return labelNode;
  58.183              }
  58.184 @@ -495,14 +503,14 @@
  58.185       * @param labelNode Label to add.
  58.186       */
  58.187      private void pushLabel(final LabelNode labelNode) {
  58.188 -        function.getLabelStack().push(labelNode);
  58.189 +        getFunction().getLabelStack().push(labelNode);
  58.190      }
  58.191  
  58.192      /**
  58.193        * Remove a label from the label stack.
  58.194        */
  58.195      private void popLabel() {
  58.196 -        function.getLabelStack().pop();
  58.197 +        getFunction().getLabelStack().pop();
  58.198      }
  58.199  
  58.200      /**
  58.201 @@ -512,6 +520,7 @@
  58.202      private void pushControlNode(final Node node) {
  58.203          final boolean isLoop = node instanceof WhileNode;
  58.204          final boolean isBreakable = node instanceof BreakableNode || node instanceof Block;
  58.205 +        final FunctionNode function = getFunction();
  58.206          function.getControlStack().push(node);
  58.207  
  58.208          for (final LabelNode labelNode : function.getLabelStack()) {
  58.209 @@ -530,7 +539,7 @@
  58.210       */
  58.211      private void popControlNode() {
  58.212          // Get control stack.
  58.213 -        final Stack<Node> controlStack = function.getControlStack();
  58.214 +        final Stack<Node> controlStack = getFunction().getControlStack();
  58.215  
  58.216          // Can be empty if missing brace.
  58.217          if (!controlStack.isEmpty()) {
  58.218 @@ -540,7 +549,7 @@
  58.219  
  58.220      private void popControlNode(final Node node) {
  58.221          // Get control stack.
  58.222 -        final Stack<Node> controlStack = function.getControlStack();
  58.223 +        final Stack<Node> controlStack = getFunction().getControlStack();
  58.224  
  58.225          // Can be empty if missing brace.
  58.226          if (!controlStack.isEmpty() && controlStack.peek() == node) {
  58.227 @@ -549,7 +558,7 @@
  58.228      }
  58.229  
  58.230      private boolean isInWithBlock() {
  58.231 -        final Stack<Node> controlStack = function.getControlStack();
  58.232 +        final Stack<Node> controlStack = getFunction().getControlStack();
  58.233          for (int i = controlStack.size() - 1; i >= 0; i--) {
  58.234              final Node node = controlStack.get(i);
  58.235  
  58.236 @@ -562,7 +571,7 @@
  58.237      }
  58.238  
  58.239      private <T extends Node> T findControl(final Class<T> ctype) {
  58.240 -        final Stack<Node> controlStack = function.getControlStack();
  58.241 +        final Stack<Node> controlStack = getFunction().getControlStack();
  58.242          for (int i = controlStack.size() - 1; i >= 0; i--) {
  58.243              final Node node = controlStack.get(i);
  58.244  
  58.245 @@ -576,7 +585,7 @@
  58.246  
  58.247      private <T extends Node> List<T> findControls(final Class<T> ctype, final Node to) {
  58.248          final List<T> nodes = new ArrayList<>();
  58.249 -        final Stack<Node> controlStack = function.getControlStack();
  58.250 +        final Stack<Node> controlStack = getFunction().getControlStack();
  58.251          for (int i = controlStack.size() - 1; i >= 0; i--) {
  58.252              final Node node = controlStack.get(i);
  58.253  
  58.254 @@ -625,7 +634,10 @@
  58.255  
  58.256          script.setKind(FunctionNode.Kind.SCRIPT);
  58.257          script.setFirstToken(functionToken);
  58.258 +        functionDeclarations = new ArrayList<>();
  58.259          sourceElements();
  58.260 +        script.prependStatements(functionDeclarations);
  58.261 +        functionDeclarations = null;
  58.262          expect(EOF);
  58.263          script.setLastToken(token);
  58.264          script.setFinish(source.getLength() - 1);
  58.265 @@ -704,7 +716,7 @@
  58.266                      // check for directive prologues
  58.267                      if (checkDirective) {
  58.268                          // skip any debug statement like line number to get actual first line
  58.269 -                        final Node lastStatement = lastStatement(block.getStatements());
  58.270 +                        final Node lastStatement = lastStatement(getBlock().getStatements());
  58.271  
  58.272                          // get directive prologue, if any
  58.273                          final String directive = getDirective(lastStatement);
  58.274 @@ -724,6 +736,7 @@
  58.275                              // handle use strict directive
  58.276                              if ("use strict".equals(directive)) {
  58.277                                  isStrictMode = true;
  58.278 +                                final FunctionNode function = getFunction();
  58.279                                  function.setStrictMode(true);
  58.280  
  58.281                                  // We don't need to check these, if lexical environment is already strict
  58.282 @@ -796,11 +809,11 @@
  58.283              if (isStrictMode && !topLevel) {
  58.284                  error(AbstractParser.message("strict.no.func.here"), token);
  58.285              }
  58.286 -            functionExpression(true);
  58.287 +            functionExpression(true, topLevel);
  58.288              return;
  58.289          }
  58.290  
  58.291 -        block.addStatement(lineNumberNode);
  58.292 +        getBlock().addStatement(lineNumberNode);
  58.293  
  58.294          switch (type) {
  58.295          case LBRACE:
  58.296 @@ -886,7 +899,7 @@
  58.297          // Force block execution.
  58.298          final ExecuteNode executeNode = new ExecuteNode(source, newBlock.getToken(), finish, newBlock);
  58.299  
  58.300 -        block.addStatement(executeNode);
  58.301 +        getBlock().addStatement(executeNode);
  58.302      }
  58.303  
  58.304      /**
  58.305 @@ -981,13 +994,9 @@
  58.306  
  58.307              // Allocate var node.
  58.308              final VarNode var = new VarNode(source, varToken, finish, name, init);
  58.309 -            if (isStatement) {
  58.310 -                function.addDeclaration(var);
  58.311 -            }
  58.312 -
  58.313              vars.add(var);
  58.314              // Add to current block.
  58.315 -            block.addStatement(var);
  58.316 +            getBlock().addStatement(var);
  58.317  
  58.318              if (type != COMMARIGHT) {
  58.319                  break;
  58.320 @@ -1000,7 +1009,7 @@
  58.321              boolean semicolon = type == SEMICOLON;
  58.322              endOfLine();
  58.323              if (semicolon) {
  58.324 -                block.setFinish(finish);
  58.325 +                getBlock().setFinish(finish);
  58.326              }
  58.327          }
  58.328  
  58.329 @@ -1017,7 +1026,7 @@
  58.330       */
  58.331      private void emptyStatement() {
  58.332          if (env._empty_statements) {
  58.333 -            block.addStatement(new EmptyNode(source, token,
  58.334 +            getBlock().addStatement(new EmptyNode(source, token,
  58.335                      Token.descPosition(token) + Token.descLength(token)));
  58.336          }
  58.337  
  58.338 @@ -1043,7 +1052,7 @@
  58.339          ExecuteNode executeNode = null;
  58.340          if (expression != null) {
  58.341              executeNode = new ExecuteNode(source, expressionToken, finish, expression);
  58.342 -            block.addStatement(executeNode);
  58.343 +            getBlock().addStatement(executeNode);
  58.344          } else {
  58.345              expect(null);
  58.346          }
  58.347 @@ -1052,7 +1061,7 @@
  58.348  
  58.349          if (executeNode != null) {
  58.350              executeNode.setFinish(finish);
  58.351 -            block.setFinish(finish);
  58.352 +            getBlock().setFinish(finish);
  58.353          }
  58.354      }
  58.355  
  58.356 @@ -1094,7 +1103,7 @@
  58.357          // Construct and add new if node.
  58.358          final IfNode ifNode = new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail);
  58.359  
  58.360 -        block.addStatement(ifNode);
  58.361 +        getBlock().addStatement(ifNode);
  58.362      }
  58.363  
  58.364      /**
  58.365 @@ -1143,13 +1152,13 @@
  58.366              outer.setFinish(body.getFinish());
  58.367  
  58.368              // Add for to current block.
  58.369 -            block.addStatement(forNode);
  58.370 +            getBlock().addStatement(forNode);
  58.371          } finally {
  58.372 -            restoreBlock();
  58.373 +            restoreBlock(outer);
  58.374              popControlNode();
  58.375          }
  58.376  
  58.377 -        block.addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
  58.378 +        getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
  58.379       }
  58.380  
  58.381      /**
  58.382 @@ -1283,7 +1292,7 @@
  58.383              whileNode.setFinish(statements.getFinish());
  58.384  
  58.385              // Add WHILE node.
  58.386 -            block.addStatement(whileNode);
  58.387 +            getBlock().addStatement(whileNode);
  58.388          } finally {
  58.389              popControlNode();
  58.390          }
  58.391 @@ -1330,7 +1339,7 @@
  58.392              doWhileNode.setFinish(finish);
  58.393  
  58.394              // Add DO node.
  58.395 -            block.addStatement(doWhileNode);
  58.396 +            getBlock().addStatement(doWhileNode);
  58.397          } finally {
  58.398              popControlNode();
  58.399          }
  58.400 @@ -1382,7 +1391,7 @@
  58.401          final ContinueNode continueNode = new ContinueNode(source, continueToken, finish, labelNode, targetNode, findControl(TryNode.class));
  58.402          continueNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
  58.403  
  58.404 -        block.addStatement(continueNode);
  58.405 +        getBlock().addStatement(continueNode);
  58.406      }
  58.407  
  58.408      /**
  58.409 @@ -1430,7 +1439,7 @@
  58.410          final BreakNode breakNode = new BreakNode(source, breakToken, finish, labelNode, targetNode, findControl(TryNode.class));
  58.411          breakNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
  58.412  
  58.413 -        block.addStatement(breakNode);
  58.414 +        getBlock().addStatement(breakNode);
  58.415      }
  58.416  
  58.417      /**
  58.418 @@ -1443,7 +1452,7 @@
  58.419       */
  58.420      private void returnStatement() {
  58.421          // check for return outside function
  58.422 -        if (function.getKind() == FunctionNode.Kind.SCRIPT) {
  58.423 +        if (getFunction().getKind() == FunctionNode.Kind.SCRIPT) {
  58.424              error(AbstractParser.message("invalid.return"));
  58.425          }
  58.426  
  58.427 @@ -1470,7 +1479,7 @@
  58.428  
  58.429          // Construct and add RETURN node.
  58.430          final ReturnNode returnNode = new ReturnNode(source, returnToken, finish, expression, findControl(TryNode.class));
  58.431 -        block.addStatement(returnNode);
  58.432 +        getBlock().addStatement(returnNode);
  58.433      }
  58.434  
  58.435      /**
  58.436 @@ -1505,7 +1514,7 @@
  58.437  
  58.438          // Construct and add YIELD node.
  58.439          final ReturnNode yieldNode = new ReturnNode(source, yieldToken, finish, expression, findControl(TryNode.class));
  58.440 -        block.addStatement(yieldNode);
  58.441 +        getBlock().addStatement(yieldNode);
  58.442      }
  58.443  
  58.444      /**
  58.445 @@ -1529,7 +1538,10 @@
  58.446  
  58.447          // Get WITH expression.
  58.448          final WithNode withNode = new WithNode(source, withToken, finish, null, null);
  58.449 -        function.setHasWith();
  58.450 +        final Iterator<FunctionNode> it = lexicalContext.getFunctions();
  58.451 +        if(it.hasNext()) {
  58.452 +            it.next().setHasWith(it);
  58.453 +        }
  58.454  
  58.455          try {
  58.456              pushControlNode(withNode);
  58.457 @@ -1549,7 +1561,7 @@
  58.458              popControlNode(withNode);
  58.459          }
  58.460  
  58.461 -        block.addStatement(withNode);
  58.462 +        getBlock().addStatement(withNode);
  58.463      }
  58.464  
  58.465      /**
  58.466 @@ -1649,7 +1661,7 @@
  58.467  
  58.468              switchNode.setFinish(finish);
  58.469  
  58.470 -            block.addStatement(switchNode);
  58.471 +            getBlock().addStatement(switchNode);
  58.472          } finally {
  58.473              popControlNode();
  58.474          }
  58.475 @@ -1684,7 +1696,7 @@
  58.476              labelNode.setBody(statements);
  58.477              labelNode.setFinish(finish);
  58.478  
  58.479 -            block.addStatement(labelNode);
  58.480 +            getBlock().addStatement(labelNode);
  58.481          } finally {
  58.482              // Remove label.
  58.483              popLabel();
  58.484 @@ -1727,7 +1739,7 @@
  58.485  
  58.486          // Construct and add THROW node.
  58.487          final ThrowNode throwNode = new ThrowNode(source, throwToken, finish, expression, findControl(TryNode.class));
  58.488 -        block.addStatement(throwNode);
  58.489 +        getBlock().addStatement(throwNode);
  58.490      }
  58.491  
  58.492      /**
  58.493 @@ -1793,18 +1805,18 @@
  58.494  
  58.495                  expect(RPAREN);
  58.496  
  58.497 +                final Block catchBlock = newBlock();
  58.498                  try {
  58.499 -                    final Block catchBlock = newBlock();
  58.500  
  58.501                      // Get CATCH body.
  58.502                      final Block catchBody = getBlock(true);
  58.503  
  58.504                      // Create and add catch.
  58.505                      final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody);
  58.506 -                    block.addStatement(catchNode);
  58.507 +                    getBlock().addStatement(catchNode);
  58.508                      catchBlocks.add(catchBlock);
  58.509                  } finally {
  58.510 -                    restoreBlock();
  58.511 +                    restoreBlock(catchBlock);
  58.512                  }
  58.513  
  58.514                  // If unconditional catch then should to be the end.
  58.515 @@ -1840,11 +1852,11 @@
  58.516              outer.addStatement(tryNode);
  58.517          } finally {
  58.518              popControlNode(tryNode);
  58.519 -            restoreBlock();
  58.520 +            restoreBlock(outer);
  58.521              popControlNode(outer);
  58.522          }
  58.523  
  58.524 -        block.addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
  58.525 +        getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
  58.526      }
  58.527  
  58.528      /**
  58.529 @@ -1864,7 +1876,7 @@
  58.530          endOfLine();
  58.531  
  58.532          final RuntimeNode runtimeNode = new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>());
  58.533 -        block.addStatement(runtimeNode);
  58.534 +        getBlock().addStatement(runtimeNode);
  58.535      }
  58.536  
  58.537      /**
  58.538 @@ -2244,7 +2256,7 @@
  58.539                      parameters = new ArrayList<>();
  58.540                      functionNode = functionBody(getSetToken, getNameNode, parameters, FunctionNode.Kind.GETTER);
  58.541                      propertyNode = new PropertyNode(source, propertyToken, finish, getIdent, null);
  58.542 -                    propertyNode.setGetter(new ReferenceNode(source, propertyToken, finish, functionNode));
  58.543 +                    propertyNode.setGetter(functionNode);
  58.544                      return propertyNode;
  58.545  
  58.546                  case "set":
  58.547 @@ -2259,7 +2271,7 @@
  58.548                      parameters.add(argIdent);
  58.549                      functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
  58.550                      propertyNode = new PropertyNode(source, propertyToken, finish, setIdent, null);
  58.551 -                    propertyNode.setSetter(new ReferenceNode(source, propertyToken, finish, functionNode));
  58.552 +                    propertyNode.setSetter(functionNode);
  58.553                      return propertyNode;
  58.554  
  58.555                  default:
  58.556 @@ -2440,7 +2452,7 @@
  58.557  
  58.558          case FUNCTION:
  58.559              // Get function expression.
  58.560 -            lhs = functionExpression(false);
  58.561 +            lhs = functionExpression(false, false);
  58.562              break;
  58.563  
  58.564          default:
  58.565 @@ -2545,7 +2557,7 @@
  58.566       *
  58.567       * @return Expression node.
  58.568       */
  58.569 -    private Node functionExpression(final boolean isStatement) {
  58.570 +    private Node functionExpression(final boolean isStatement, final boolean topLevel) {
  58.571          final LineNumberNode lineNumber = lineNumber();
  58.572  
  58.573          final long functionToken = token;
  58.574 @@ -2580,10 +2592,12 @@
  58.575  
  58.576          final FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL);
  58.577  
  58.578 -        if (isStatement && !isInWithBlock()) {
  58.579 -            functionNode.setIsStatement();
  58.580 +        if (isStatement) {
  58.581 +            if(topLevel) {
  58.582 +                functionNode.setIsDeclared();
  58.583 +            }
  58.584              if(ARGUMENTS.tag().equals(name.getName())) {
  58.585 -                functionNode.findParentFunction().setDefinesArguments();
  58.586 +                getFunction().setDefinesArguments();
  58.587              }
  58.588          }
  58.589  
  58.590 @@ -2591,8 +2605,6 @@
  58.591              functionNode.setIsAnonymous();
  58.592          }
  58.593  
  58.594 -        final ReferenceNode referenceNode = new ReferenceNode(source, functionToken, finish, functionNode);
  58.595 -
  58.596          final int arity = parameters.size();
  58.597  
  58.598          final boolean strict = functionNode.isStrictMode();
  58.599 @@ -2628,17 +2640,18 @@
  58.600          }
  58.601  
  58.602          if (isStatement) {
  58.603 -            final VarNode var = new VarNode(source, functionToken, finish, name, referenceNode);
  58.604 -            if (isInWithBlock()) {
  58.605 -                function.addDeclaration(var);
  58.606 -                // Add to current block.
  58.607 -                block.addStatement(var);
  58.608 +            final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, true);
  58.609 +            if(topLevel) {
  58.610 +                functionDeclarations.add(lineNumber);
  58.611 +                functionDeclarations.add(varNode);
  58.612              } else {
  58.613 -                functionNode.setFunctionVarNode(var, lineNumber);
  58.614 +                final Block block = getBlock();
  58.615 +                block.addStatement(lineNumber);
  58.616 +                block.addStatement(varNode);
  58.617              }
  58.618          }
  58.619  
  58.620 -        return referenceNode;
  58.621 +        return functionNode;
  58.622      }
  58.623  
  58.624      /**
  58.625 @@ -2721,7 +2734,14 @@
  58.626                  expect(LBRACE);
  58.627  
  58.628                  // Gather the function elements.
  58.629 -                sourceElements();
  58.630 +                final List<Node> prevFunctionDecls = functionDeclarations;
  58.631 +                functionDeclarations = new ArrayList<>();
  58.632 +                try {
  58.633 +                    sourceElements();
  58.634 +                    functionNode.prependStatements(functionDeclarations);
  58.635 +                } finally {
  58.636 +                    functionDeclarations = prevFunctionDecls;
  58.637 +                }
  58.638  
  58.639                  functionNode.setLastToken(token);
  58.640                  expect(RBRACE);
  58.641 @@ -2729,12 +2749,9 @@
  58.642  
  58.643              }
  58.644          } finally {
  58.645 -            restoreBlock();
  58.646 +            restoreBlock(functionNode);
  58.647          }
  58.648  
  58.649 -        // Add the body of the function to the current block.
  58.650 -        block.addFunction(functionNode);
  58.651 -
  58.652          return functionNode;
  58.653      }
  58.654  
  58.655 @@ -3069,4 +3086,12 @@
  58.656      public String toString() {
  58.657          return "[JavaScript Parsing]";
  58.658      }
  58.659 +
  58.660 +    private Block getBlock() {
  58.661 +        return lexicalContext.getCurrentBlock();
  58.662 +    }
  58.663 +
  58.664 +    private FunctionNode getFunction() {
  58.665 +        return lexicalContext.getCurrentFunction();
  58.666 +    }
  58.667  }
    59.1 --- a/src/jdk/nashorn/internal/runtime/Context.java	Tue Mar 19 11:03:24 2013 -0300
    59.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java	Sat Mar 23 00:58:39 2013 +0100
    59.3 @@ -27,9 +27,9 @@
    59.4  
    59.5  import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
    59.6  import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
    59.7 +import static jdk.nashorn.internal.lookup.Lookup.MH;
    59.8  import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
    59.9  import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
   59.10 -import static jdk.nashorn.internal.lookup.Lookup.MH;
   59.11  
   59.12  import java.io.File;
   59.13  import java.io.IOException;
    60.1 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties	Tue Mar 19 11:03:24 2013 -0300
    60.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties	Sat Mar 23 00:58:39 2013 +0100
    60.3 @@ -42,6 +42,8 @@
    60.4  parser.error.expected.comma=Expected comma but found {0}
    60.5  parser.error.expected=Expected {0} but found {1}
    60.6  parser.error.invalid.return=Invalid return statement
    60.7 +parser.error.no.func.decl.here=Function declarations can only occur at program or function body level. You should use a function expression here instead.
    60.8 +parser.error.no.func.decl.here.warn=Function declarations should only occur at program or function body level. Function declaration in nested block was converted to a function expression.
    60.9  parser.error.property.redefinition=Property "{0}" already defined
   60.10  parser.error.unexpected.token=Unexpected token: {0}
   60.11  parser.error.many.vars.in.for.in.loop=Only one variable allowed in for..in loop
   60.12 @@ -57,7 +59,7 @@
   60.13  parser.error.strict.cant.delete.ident=cannot delete identifier "{0}" in strict mode
   60.14  parser.error.strict.param.redefinition=strict mode function cannot have duplicate parameter name "{0}"
   60.15  parser.error.strict.no.octal=cannot use octal value in strict mode
   60.16 -parser.error.strict.no.func.here=In strict mode, functions can only be declared at top-level or immediately within a function
   60.17 +parser.error.strict.no.func.decl.here=In strict mode, function declarations can only occur at program or function body level. You should use a function expression here instead.
   60.18  type.error.strict.getter.setter.poison=In strict mode, "caller", "callee", and "arguments" properties can not be accessed on functions or the arguments object
   60.19  
   60.20  # not the expected type in a given context
    61.1 --- a/test/script/basic/JDK-8006755.js	Tue Mar 19 11:03:24 2013 -0300
    61.2 +++ b/test/script/basic/JDK-8006755.js	Sat Mar 23 00:58:39 2013 +0100
    61.3 @@ -31,7 +31,7 @@
    61.4  var scope = { x: "hello" };
    61.5  
    61.6  with (scope) {
    61.7 -    function main() {
    61.8 +    var main = function() {
    61.9          if (x != "hello") {
   61.10              fail("x != 'hello'");
   61.11          }
    62.1 --- a/test/script/basic/NASHORN-837.js	Tue Mar 19 11:03:24 2013 -0300
    62.2 +++ b/test/script/basic/NASHORN-837.js	Sat Mar 23 00:58:39 2013 +0100
    62.3 @@ -28,23 +28,13 @@
    62.4   * @run
    62.5   */
    62.6  
    62.7 -var failed = false;
    62.8 -
    62.9  try {
   62.10 -    try {
   62.11 -	throw new TypeError('error');
   62.12 -    } catch (iox) {
   62.13 -	function f() {
   62.14 -	    print(iox.message);
   62.15 -	}
   62.16 +    throw new TypeError('error');
   62.17 +} catch (iox) {
   62.18 +    var f = function() {
   62.19 +        if(iox.message != 'error') {
   62.20 +            print("Failure! iox did not throw correct exception");
   62.21 +        }
   62.22      }
   62.23 -    f();
   62.24 -} catch (e) {
   62.25 -    failed = (e instanceof ReferenceError);
   62.26 -    //iox not defined should be thrown
   62.27  }
   62.28 -
   62.29 -if (!failed) {
   62.30 -    print("Failure! iox did not throw correct exception");
   62.31 -}
   62.32 -
   62.33 +f();
    63.1 --- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java	Tue Mar 19 11:03:24 2013 -0300
    63.2 +++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java	Sat Mar 23 00:58:39 2013 +0100
    63.3 @@ -44,6 +44,7 @@
    63.4      private static final boolean VERBOSE  = Boolean.valueOf(System.getProperty("compilertest.verbose"));
    63.5      private static final boolean TEST262  = Boolean.valueOf(System.getProperty("compilertest.test262"));
    63.6      private static final String TEST_BASIC_DIR  = System.getProperty("test.basic.dir");
    63.7 +    private static final String TEST_NODE_DIR  = System.getProperty("test.node.dir");
    63.8      private static final String TEST262_SUITE_DIR = System.getProperty("test262.suite.dir");
    63.9  
   63.10      interface TestFilter {
   63.11 @@ -81,21 +82,22 @@
   63.12      @Test
   63.13      public void compileAllTests() {
   63.14          if (TEST262) {
   63.15 -            compileTestSet(TEST262_SUITE_DIR, new TestFilter() {
   63.16 +            compileTestSet(new File(TEST262_SUITE_DIR), new TestFilter() {
   63.17                  @Override
   63.18                  public boolean exclude(final File file, final String content) {
   63.19                      return content.indexOf("@negative") != -1;
   63.20                  }
   63.21              });
   63.22          }
   63.23 -        compileTestSet(TEST_BASIC_DIR, null);
   63.24 +        compileTestSet(new File(TEST_BASIC_DIR), null);
   63.25 +        compileTestSet(new File(TEST_NODE_DIR, "node"), null);
   63.26 +        compileTestSet(new File(TEST_NODE_DIR, "src"), null);
   63.27      }
   63.28  
   63.29 -    private void compileTestSet(final String testSet, final TestFilter filter) {
   63.30 +    private void compileTestSet(final File testSetDir, final TestFilter filter) {
   63.31          passed = 0;
   63.32          failed = 0;
   63.33          skipped = 0;
   63.34 -        final File testSetDir = new File(testSet);
   63.35          if (! testSetDir.isDirectory()) {
   63.36              log("WARNING: " + testSetDir + " not found or not a directory");
   63.37              return;
   63.38 @@ -103,7 +105,7 @@
   63.39          log(testSetDir.getAbsolutePath());
   63.40          compileJSDirectory(testSetDir, filter);
   63.41  
   63.42 -        log(testSet + " compile done!");
   63.43 +        log(testSetDir + " compile done!");
   63.44          log("compile ok: " + passed);
   63.45          log("compile failed: " + failed);
   63.46          log("compile skipped: " + skipped);

mercurial