8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.

Wed, 30 Jan 2013 12:26:45 +0100

author
lagergren
date
Wed, 30 Jan 2013 12:26:45 +0100
changeset 57
59970b70ebb5
parent 56
755404d7d189
child 58
ca6d5e4b8170

8007062: Split Lower up into Lower/Attr/FinalizeTypes. Integrate AccessSpecalizer into FinalizeTypes.
Summary: Lower suffered from being a "God class" trying to do everything at once. As Nashorn code generation has grown, so has Lower. It does several post processing passes, tries to do several things at once even though all type information isn't in place, adjusting state afterwards and so on. It also performs control flow analysis, type attribution and constant folding, and everything else code generation related before byte code emission. I have now separated the compilation process into Lower (create low level nodes from high level ones, copy code such as finally block inlining etc), Attr (assign types and symbols to all nodes - freeze slot and scope information) and FinalizeTypes (insert explicit casts, specialize invoke dynamic types for scope accesses). I've removed the kludgy AccessSpecializer, as this now integrates naturally with typing. Everything is now much easier to read and each module performs only one thing. I have added separate loggers for the separate tiers. In the process I have also fixed: (1) problems with type coercion (see test/script/basic/typecoercion.js, basically our coercion was too late and our symbol inference was erroneous. This only manifested itself in very rare occasions where toNumber coercion has side effects, such as for example when valueOf is overridden) (2) copying literal nodes (literal copy did not use the superclass copy, which made all the Node specific fields not to be copied (3) erroneous literal tokenization (literals shouldn't always just inherit token information from whatever node that creates them) (4) splitter weighnodes - unary nodes were considered weightless (4) removed the hateful and kludgy "VarNode.shouldAppend", which really isn't needed when we have an attribution phase that determines self reference symbols (the only thing it was used for) (5) duplicate line number issues in the parser (6) convert bug in CodeGenerator for intermediate results of scope accesses (see test/script/basic/access-specializer.js) ... Several of these things just stopped being problems with the new architecture "can't happen anymore" and are not bug fixes per se. All tests run. No performance regressions exist that I've been able to measure. Some increases in performance were measured, but in the statistical margin of error (which is very wide as HotSpot currently has warmup issues with LambdaForms/invoke dynamic). Compile speed has not measurably increased.
Reviewed-by: jlaskey, attila

docs/DEVELOPER_README file | annotate | diff | comparison | revisions
src/jdk/nashorn/api/scripting/Formatter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/api/scripting/NashornScriptEngine.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/AccessSpecializer.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Attr.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CodeGenerator.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/Lower.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/MethodEmitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/SharedScopeCall.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/WeighNodes.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Block.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/CallNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/CatchNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/ExecuteNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/FunctionNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LiteralNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Node.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/RuntimeNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Symbol.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/TryNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/VarNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/debug/ASTWriter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeJSON.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeString.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/AbstractParser.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/Parser.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/TokenType.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/DebugLogger.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/OptionsObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/PropertyMap.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptingFunctions.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/options/Options.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/tools/Shell.java file | annotate | diff | comparison | revisions
test/script/basic/access-specializer.js file | annotate | diff | comparison | revisions
test/script/basic/compile-octane.js.EXPECTED file | annotate | diff | comparison | revisions
test/script/basic/run-octane.js file | annotate | diff | comparison | revisions
test/script/basic/typecoerce.js file | annotate | diff | comparison | revisions
test/script/basic/typecoerce.js.EXPECTED file | annotate | diff | comparison | revisions
     1.1 --- a/docs/DEVELOPER_README	Tue Jan 29 14:25:39 2013 -0400
     1.2 +++ b/docs/DEVELOPER_README	Wed Jan 30 12:26:45 2013 +0100
     1.3 @@ -36,16 +36,6 @@
     1.4  equivalent to enabling the access logger with "info" level.
     1.5  
     1.6  
     1.7 -SYSTEM PROPERTY: -Dnashorn.compiler.ints.disable
     1.8 -
     1.9 -This flag prevents ints and longs (non double values) from being used
    1.10 -for any primitive representation in the lowered IR. This is default
    1.11 -false, i.e Lower will attempt to use integer variables as long as it
    1.12 -can. For example, var x = 17 would try to use x as an integer, unless
    1.13 -other operations occur later that require coercion to wider type, for
    1.14 -example x *= 17.1;
    1.15 -
    1.16 -
    1.17  SYSTEM PROPERTY: -Dnashorn.compiler.intarithmetic 
    1.18  
    1.19  Arithmetic operations in Nashorn (except bitwise ones) typically
    1.20 @@ -195,7 +185,8 @@
    1.21  slots, possibly through code copying and versioning.
    1.22  
    1.23  
    1.24 -SYSTEM PROPERTY: -Dnashorn.compiler.symbol.trace=<x>
    1.25 +SYSTEM PROPERTY: -Dnashorn.compiler.symbol.trace=[<x>[,*]], 
    1.26 +  -Dnashorn.compiler.symbol.stacktrace=[<x>[,*]]
    1.27  
    1.28  When this property is set, creation and manipulation of any symbol
    1.29  named "x" will show information about when the compiler changes its
    1.30 @@ -203,8 +194,16 @@
    1.31  data. This is useful if, for example, a symbol shows up as an Object,
    1.32  when you believe it should be a primitive. Usually there is an
    1.33  explanation for this, for example that it exists in the global scope
    1.34 -and type analysis has to be more conservative. In that case, the stack
    1.35 -trace upon type change to object will usually tell us why.
    1.36 +and type analysis has to be more conservative. 
    1.37 +
    1.38 +Several symbols names to watch can be specified by comma separation.
    1.39 +
    1.40 +If no variable name is specified (and no equals sign), all symbols
    1.41 +will be watched
    1.42 +
    1.43 +By using "stacktrace" instead of or together with "trace", stack
    1.44 +traces will be displayed upon symbol changes according to the same
    1.45 +semantics.
    1.46  
    1.47  
    1.48  SYSTEM PROPERTY: nashorn.lexer.xmlliterals
    1.49 @@ -349,6 +348,9 @@
    1.50  2. The loggers.
    1.51  ===============
    1.52  
    1.53 +It is very simple to create your own logger. Use the DebugLogger class
    1.54 +and give the subsystem name as a constructor argument.
    1.55 +
    1.56  The Nashorn loggers can be used to print per-module or per-subsystem
    1.57  debug information with different levels of verbosity. The loggers for
    1.58  a given subsystem are available are enabled by using
    1.59 @@ -382,7 +384,7 @@
    1.60  controlled from the Context. Log messages are, for example, about
    1.61  things like new compile units being allocated. The compiler has global
    1.62  settings that all the tiers of codegen (e.g. Lower and CodeGenerator)
    1.63 -use.
    1.64 +use.s
    1.65  
    1.66  
    1.67  * codegen
    1.68 @@ -429,6 +431,18 @@
    1.69  
    1.70  * lower
    1.71  
    1.72 +This is the first lowering pass.
    1.73 +
    1.74 +Lower is a code generation pass that turns high level IR nodes into
    1.75 +lower level one, for example substituting comparisons to RuntimeNodes
    1.76 +and inlining finally blocks.
    1.77 +
    1.78 +Lower is also responsible for determining control flow information
    1.79 +like end points.
    1.80 +
    1.81 +
    1.82 +* attr
    1.83 +
    1.84  The lowering annotates a FunctionNode with symbols for each identifier
    1.85  and transforms high level constructs into lower level ones, that the
    1.86  CodeGenerator consumes.
    1.87 @@ -439,14 +453,11 @@
    1.88  this logger. This will probably change.
    1.89  
    1.90  
    1.91 -* access
    1.92 +* finalize
    1.93  
    1.94 -The --log=access option is equivalent to setting the system variable
    1.95 -"nashorn.callsiteaccess.debug" to true. There are several levels of
    1.96 -the access logger, usually the default level "info" is enough
    1.97 -
    1.98 -It is very simple to create your own logger. Use the DebugLogger class
    1.99 -and give the subsystem name as a constructor argument.
   1.100 +This --log=finalize log option outputs information for type finalization,
   1.101 +the third tier of the compiler. This means things like placement of 
   1.102 +specialized scope nodes or explicit conversions. 
   1.103  
   1.104  
   1.105  * fields
     2.1 --- a/src/jdk/nashorn/api/scripting/Formatter.java	Tue Jan 29 14:25:39 2013 -0400
     2.2 +++ b/src/jdk/nashorn/api/scripting/Formatter.java	Wed Jan 30 12:26:45 2013 +0100
     2.3 @@ -48,6 +48,9 @@
     2.4   */
     2.5  public final class Formatter {
     2.6  
     2.7 +    private Formatter() {
     2.8 +    }
     2.9 +
    2.10      /**
    2.11       * Method which converts javascript types to java types for the
    2.12       * String.format method (jrunscript function sprintf).
    2.13 @@ -149,7 +152,9 @@
    2.14          if (s != null) {
    2.15              try {
    2.16                  index = Integer.parseInt(s.substring(0, s.length() - 1));
    2.17 -            } catch (NumberFormatException e) { }
    2.18 +            } catch (final NumberFormatException e) {
    2.19 +                //ignored
    2.20 +            }
    2.21          } else {
    2.22              index = 0;
    2.23          }
     3.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Tue Jan 29 14:25:39 2013 -0400
     3.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Wed Jan 30 12:26:45 2013 +0100
     3.3 @@ -327,6 +327,7 @@
     3.4          try {
     3.5              final InputStream is = AccessController.doPrivileged(
     3.6                      new PrivilegedExceptionAction<InputStream>() {
     3.7 +                        @Override
     3.8                          public InputStream run() throws Exception {
     3.9                              final URL url = NashornScriptEngine.class.getResource(script);
    3.10                              return url.openStream();
     4.1 --- a/src/jdk/nashorn/internal/codegen/AccessSpecializer.java	Tue Jan 29 14:25:39 2013 -0400
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,399 +0,0 @@
     4.4 -/*
     4.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     4.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.7 - *
     4.8 - * This code is free software; you can redistribute it and/or modify it
     4.9 - * under the terms of the GNU General Public License version 2 only, as
    4.10 - * published by the Free Software Foundation.  Oracle designates this
    4.11 - * particular file as subject to the "Classpath" exception as provided
    4.12 - * by Oracle in the LICENSE file that accompanied this code.
    4.13 - *
    4.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
    4.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    4.16 - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    4.17 - * version 2 for more details (a copy is included in the LICENSE file that
    4.18 - * accompanied this code).
    4.19 - *
    4.20 - * You should have received a copy of the GNU General Public License version
    4.21 - * 2 along with this work; if not, write to the Free Software Foundation,
    4.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    4.23 - *
    4.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    4.25 - * or visit www.oracle.com if you need additional information or have any
    4.26 - * questions.
    4.27 - */
    4.28 -
    4.29 -package jdk.nashorn.internal.codegen;
    4.30 -
    4.31 -import java.util.HashSet;
    4.32 -import jdk.nashorn.internal.codegen.types.Type;
    4.33 -import jdk.nashorn.internal.ir.AccessNode;
    4.34 -import jdk.nashorn.internal.ir.Assignment;
    4.35 -import jdk.nashorn.internal.ir.BinaryNode;
    4.36 -import jdk.nashorn.internal.ir.CallNode;
    4.37 -import jdk.nashorn.internal.ir.IdentNode;
    4.38 -import jdk.nashorn.internal.ir.IndexNode;
    4.39 -import jdk.nashorn.internal.ir.Node;
    4.40 -import jdk.nashorn.internal.ir.ReferenceNode;
    4.41 -import jdk.nashorn.internal.ir.Symbol;
    4.42 -import jdk.nashorn.internal.ir.TypeOverride;
    4.43 -import jdk.nashorn.internal.ir.UnaryNode;
    4.44 -import jdk.nashorn.internal.ir.VarNode;
    4.45 -import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
    4.46 -import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    4.47 -import jdk.nashorn.internal.parser.Token;
    4.48 -import jdk.nashorn.internal.parser.TokenType;
    4.49 -import jdk.nashorn.internal.runtime.Debug;
    4.50 -import jdk.nashorn.internal.runtime.DebugLogger;
    4.51 -
    4.52 -/**
    4.53 - * This is a post pass for Lower, that removes casts for accessors to objects in
    4.54 - * Scope, and replaces the accessor type with a narrower one with possible.
    4.55 - *
    4.56 - * Any node that implements TypeOverride will be subject to access specialization.
    4.57 - *
    4.58 - * TypeOverride basically means "type inference has determined that the field x
    4.59 - * is an object, but if you do x & 17, it can be read as an int, which we hope
    4.60 - * coincides with its internal representation. In that case there is no boxing
    4.61 - * that may or may not be removed by the JVM and less data bandwidth.
    4.62 - *
    4.63 - * Ideally this should not be a post pass, but it requires slot AND scope info, and has
    4.64 - * to be run where it is, which is called from {@link CodeGenerator}.
    4.65 - *
    4.66 - * @see TypeOverride
    4.67 - */
    4.68 -
    4.69 -final class AccessSpecializer extends NodeOperatorVisitor {
    4.70 -    /** Debug logger for access specialization. Enable it with --log=access:level
    4.71 -        or -Dnashorn.callsiteaccess.debug */
    4.72 -    private static final DebugLogger LOG   = new DebugLogger("access", "nashorn.callsiteaccess.debug");
    4.73 -    private static final boolean     DEBUG = LOG.isEnabled();
    4.74 -
    4.75 -    @Override
    4.76 -    public Node leave(final VarNode varNode) {
    4.77 -        if (varNode.isAssignment()) {
    4.78 -            return leaveAssign(varNode);
    4.79 -        }
    4.80 -
    4.81 -        return varNode;
    4.82 -    }
    4.83 -
    4.84 -    @Override
    4.85 -    public Node leave(final CallNode callNode) {
    4.86 -        final Node function = callNode.getFunction();
    4.87 -        if (function instanceof ReferenceNode) {
    4.88 -            changeType(callNode, ((ReferenceNode)function).getReference().getType());
    4.89 -        }
    4.90 -        return callNode;
    4.91 -    }
    4.92 -
    4.93 -    @Override
    4.94 -    public Node leaveASSIGN(final BinaryNode binaryNode) {
    4.95 -        return leaveAssign(binaryNode);
    4.96 -    }
    4.97 -
    4.98 -    @Override
    4.99 -    public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
   4.100 -        return leaveAssign(binaryNode);
   4.101 -    }
   4.102 -
   4.103 -    @Override
   4.104 -    public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) {
   4.105 -        return leaveAssign(binaryNode);
   4.106 -    }
   4.107 -
   4.108 -    @Override
   4.109 -    public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) {
   4.110 -        return leaveAssign(binaryNode);
   4.111 -    }
   4.112 -
   4.113 -    @Override
   4.114 -    public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) {
   4.115 -        return leaveAssign(binaryNode);
   4.116 -    }
   4.117 -
   4.118 -    @Override
   4.119 -    public Node leaveASSIGN_DIV(final BinaryNode binaryNode) {
   4.120 -        return leaveAssign(binaryNode);
   4.121 -    }
   4.122 -
   4.123 -    @Override
   4.124 -    public Node leaveASSIGN_MOD(final BinaryNode binaryNode) {
   4.125 -        return leaveAssign(binaryNode);
   4.126 -    }
   4.127 -
   4.128 -    @Override
   4.129 -    public Node leaveASSIGN_MUL(final BinaryNode binaryNode) {
   4.130 -        return leaveAssign(binaryNode);
   4.131 -    }
   4.132 -
   4.133 -    @Override
   4.134 -    public Node leaveASSIGN_SAR(final BinaryNode binaryNode) {
   4.135 -        return leaveAssign(binaryNode);
   4.136 -    }
   4.137 -
   4.138 -    @Override
   4.139 -    public Node leaveASSIGN_SHL(final BinaryNode binaryNode) {
   4.140 -        return leaveAssign(binaryNode);
   4.141 -    }
   4.142 -
   4.143 -    @Override
   4.144 -    public Node leaveASSIGN_SHR(final BinaryNode binaryNode) {
   4.145 -        return leaveAssign(binaryNode);
   4.146 -    }
   4.147 -
   4.148 -    @Override
   4.149 -    public Node leaveASSIGN_SUB(final BinaryNode binaryNode) {
   4.150 -        return leaveAssign(binaryNode);
   4.151 -    }
   4.152 -
   4.153 -    @Override
   4.154 -    public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
   4.155 -        return propagateResultType(binaryNode, binaryNode.lhs().getType());
   4.156 -    }
   4.157 -
   4.158 -    @Override
   4.159 -    public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
   4.160 -        return propagateResultType(binaryNode, binaryNode.rhs().getType());
   4.161 -    }
   4.162 -
   4.163 -    @Override
   4.164 -    public Node leaveCONVERT(final UnaryNode unaryNode) {
   4.165 -        final Type castTo = unaryNode.getType();
   4.166 -
   4.167 -        Node rhs = unaryNode.rhs();
   4.168 -
   4.169 -        // Go through all conversions until we find the first non-convert node.
   4.170 -        while (rhs.tokenType() == TokenType.CONVERT) {
   4.171 -            rhs = ((UnaryNode)rhs).rhs();
   4.172 -        }
   4.173 -
   4.174 -        // If this node can be type changed
   4.175 -        if (canHaveCallSiteType(rhs) && isSupportedCallSiteType(castTo)) {
   4.176 -            /*
   4.177 -             * Just add a callsite type and throw away the cast, appropriate
   4.178 -             * getter/setter is selected, which will do the conversion for us
   4.179 -             */
   4.180 -            changeType(rhs, castTo);
   4.181 -            LOG.fine("*** cast: converting " + debugNode(unaryNode) + " to " + debugNode(rhs));
   4.182 -
   4.183 -            return rhs;
   4.184 -        }
   4.185 -
   4.186 -        // Micro optimization for node hygiene and pattern detection - remove unnecessary same type cast
   4.187 -        if (unaryNode.getType().isEquivalentTo(rhs.getType())) {
   4.188 -            return rhs;
   4.189 -        }
   4.190 -
   4.191 -        return unaryNode;
   4.192 -    }
   4.193 -
   4.194 -    @Override
   4.195 -    public Node leaveDECINC(final UnaryNode unaryNode) {
   4.196 -        assert unaryNode.isAssignment();
   4.197 -
   4.198 -        final Node dest = unaryNode.getAssignmentDest();
   4.199 -        if (canHaveCallSiteType(dest) && isSupportedCallSiteType(unaryNode.getType())) {
   4.200 -            changeTypeInAssignment(dest, unaryNode.getType());
   4.201 -        }
   4.202 -
   4.203 -        return unaryNode;
   4.204 -    }
   4.205 -
   4.206 -    /**
   4.207 -     * Is this a node that can have its type overridden. This is true for
   4.208 -     * AccessNodes, IndexNodes and IdentNodes
   4.209 -     *
   4.210 -     * @param node the node to check
   4.211 -     * @return true if node can have a callsite type
   4.212 -     */
   4.213 -    private static boolean canHaveCallSiteType(final Node node) {
   4.214 -        return node instanceof TypeOverride && ((TypeOverride)node).canHaveCallSiteType();
   4.215 -    }
   4.216 -
   4.217 -    /**
   4.218 -     * Is the specialization type supported. Currently we treat booleans as objects
   4.219 -     * and have no special boolean type accessor, thus booleans are ignored.
   4.220 -     * TODO - support booleans? NASHORN-590
   4.221 -     *
   4.222 -     * @param castTo the type to check
   4.223 -     * @return true if call site type is supported
   4.224 -     */
   4.225 -    private static boolean isSupportedCallSiteType(final Type castTo) {
   4.226 -        return castTo.isNumeric(); // don't specializable for boolean
   4.227 -    }
   4.228 -
   4.229 -    /**
   4.230 -     * Turn a node into a covert node
   4.231 -     *
   4.232 -     * @param  node the node
   4.233 -     * @return the node as a convert node
   4.234 -     */
   4.235 -    private static Node convert(final Node node) {
   4.236 -        return new UnaryNode(node.getSource(),
   4.237 -                Token.recast(node.getToken(), TokenType.CONVERT),
   4.238 -                node);
   4.239 -    }
   4.240 -
   4.241 -    private static Node leaveAssign(final Node node) {
   4.242 -        assert node.isAssignment() : node + " is not an assignment";
   4.243 -
   4.244 -
   4.245 -        final Node lhs = ((Assignment<?>)node).getAssignmentDest();
   4.246 -        Node       rhs = ((Assignment<?>)node).getAssignmentSource();
   4.247 -
   4.248 -        /**
   4.249 -         * Nodes with local variable slots  are assumed to be of their optimal type
   4.250 -         * already and aren't affected here. This is not strictly true, for instance
   4.251 -         * with doubles instead of in a bounded loop. TODO - range check: NASHORN-363
   4.252 -         *
   4.253 -         * This is also not strictly true for var y = x = 55; where y has no other uses
   4.254 -         * Then y can be an int, but lower conservatively does an object of the assign to
   4.255 -         * scope
   4.256 -         */
   4.257 -        final Symbol lhsSymbol = lhs.getSymbol();
   4.258 -
   4.259 -        if (lhsSymbol.hasSlot() && !lhsSymbol.isScope()) {
   4.260 -            LOG.finest(lhs.getSymbol() + " has slot!");
   4.261 -            if (!lhs.getType().isEquivalentTo(rhs.getType())) {
   4.262 -                LOG.finest("\tslot assignment: " +lhs.getType()+ " " +rhs.getType() + " " + debugNode(node));
   4.263 -
   4.264 -                final Node c = convert(rhs);
   4.265 -                c.setSymbol(lhsSymbol);
   4.266 -                ((Assignment<?>)node).setAssignmentSource(c);
   4.267 -
   4.268 -                LOG.fine("*** slot assignment turned to : " + debugNode(node));
   4.269 -            } else {
   4.270 -                LOG.finest("aborted - type equivalence between lhs and rhs");
   4.271 -            }
   4.272 -
   4.273 -            return node;
   4.274 -        }
   4.275 -
   4.276 -        // e.g. __DIR__, __LINE__, __FILE__ - don't try to change these
   4.277 -        if (lhs instanceof IdentNode && ((IdentNode)lhs).isSpecialIdentity()) {
   4.278 -            return node;
   4.279 -        }
   4.280 -
   4.281 -        /**
   4.282 -         * Try to cast to the type of the right hand side, now pruned. E.g. an (object)17 should
   4.283 -         * now be just 17, an int.
   4.284 -         */
   4.285 -        Type castTo = rhs.getType();
   4.286 -
   4.287 -        // If LHS can't get a new type, neither can rhs - retain the convert
   4.288 -        if (!canHaveCallSiteType(lhs)) {
   4.289 -            return node;
   4.290 -        }
   4.291 -
   4.292 -        // Take the narrowest type of the entire cast sequence
   4.293 -        while (rhs.tokenType() == TokenType.CONVERT) {
   4.294 -            rhs    = ((UnaryNode)rhs).rhs();
   4.295 -            castTo = Type.narrowest(rhs.getType(), castTo); //e.g. (object)(int) -> int even though object is outermost
   4.296 -        }
   4.297 -
   4.298 -        // If castTo is wider than widestOperationType, castTo can be further slowed down
   4.299 -        final Type widestOperationType = node.getWidestOperationType();
   4.300 -        LOG.finest("node wants to be " + castTo + " and its widest operation is " + widestOperationType);
   4.301 -
   4.302 -        if (widestOperationType != castTo && Type.widest(castTo, widestOperationType) == castTo) {
   4.303 -            LOG.info("###" + node + " castTo was " + castTo + " but could be downgraded to " + node.getWidestOperationType());
   4.304 -            castTo = node.getWidestOperationType();
   4.305 -            if (rhs instanceof TypeOverride) {
   4.306 -                changeType(rhs, castTo);
   4.307 -            }
   4.308 -        }
   4.309 -
   4.310 -        /*
   4.311 -         * If this is a self modifying op, we can't be narrower than the widest optype
   4.312 -         * or e.g. x = x + 12 and x += 12 will turn into different things
   4.313 -         */
   4.314 -        if (node.isSelfModifying()) {
   4.315 -            castTo = Type.widest(widestOperationType, castTo);
   4.316 -        }
   4.317 -
   4.318 -        // We only specialize for numerics, not for booleans.
   4.319 -        if (isSupportedCallSiteType(castTo)) {
   4.320 -            if (rhs.getType() != castTo) {
   4.321 -                LOG.finest("cast was necessary, abort: " + node + " " + rhs.getType() + " != " + castTo);
   4.322 -                return node;
   4.323 -            }
   4.324 -
   4.325 -            LOG.finest("assign: " + debugNode(node));
   4.326 -
   4.327 -            changeTypeInAssignment(lhs, castTo);
   4.328 -            ((Assignment<?>)node).setAssignmentSource(rhs);
   4.329 -
   4.330 -            LOG.info("### modified to " + debugNode(node) + " (given type override " + castTo + ")");
   4.331 -
   4.332 -            propagateResultType(node, castTo);
   4.333 -        }
   4.334 -
   4.335 -        return node;
   4.336 -    }
   4.337 -
   4.338 -    private static Node propagateResultType(final Node node, final Type type) {
   4.339 -        //warning! this CANNOT be done for non temporaries as they are used in other computations
   4.340 -        if (isSupportedCallSiteType(type)) {
   4.341 -            if (node.getSymbol().isTemp()) {
   4.342 -                LOG.finest("changing temporary type: " + debugNode(node) + " to " + type);
   4.343 -                node.getSymbol().setTypeOverride(type);
   4.344 -                LOG.info("### node modified to " + debugNode(node) + " (given type override " + type + ")");
   4.345 -            }
   4.346 -        }
   4.347 -        return node;
   4.348 -    }
   4.349 -
   4.350 -    private static void changeTypeInAssignment(final Node dest, final Type newType) {
   4.351 -        if (changeType(dest, newType)) {
   4.352 -            LOG.finest("changed assignment " + dest + " " + dest.getSymbol());
   4.353 -            assert !newType.isObject();
   4.354 -
   4.355 -            final HashSet<Node> exclude = new HashSet<>();
   4.356 -
   4.357 -            dest.accept(new NodeVisitor() {
   4.358 -
   4.359 -                private void setCanBePrimitive(final Symbol symbol) {
   4.360 -                    LOG.fine("*** can be primitive symbol " + symbol + " " + Debug.id(symbol));
   4.361 -                    symbol.setCanBePrimitive(newType);
   4.362 -                }
   4.363 -
   4.364 -                @Override
   4.365 -                public Node enter(final IdentNode identNode) {
   4.366 -                    if (!exclude.contains(identNode)) {
   4.367 -                        setCanBePrimitive(identNode.getSymbol());
   4.368 -                    }
   4.369 -                    return null;
   4.370 -                }
   4.371 -
   4.372 -                @Override
   4.373 -                public Node enter(final AccessNode accessNode) {
   4.374 -                    setCanBePrimitive(accessNode.getProperty().getSymbol());
   4.375 -                    return null;
   4.376 -                }
   4.377 -
   4.378 -                @Override
   4.379 -                public Node enter(final IndexNode indexNode) {
   4.380 -                    exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine
   4.381 -                    return indexNode;
   4.382 -                }
   4.383 -
   4.384 -            });
   4.385 -        }
   4.386 -    }
   4.387 -
   4.388 -    private static boolean changeType(final Node node, final Type newType) {
   4.389 -        if (!node.getType().equals(newType)) {
   4.390 -            ((TypeOverride)node).setType(newType);
   4.391 -            return true;
   4.392 -        }
   4.393 -        return false;
   4.394 -    }
   4.395 -
   4.396 -    private static String debugNode(final Node node) {
   4.397 -        if (DEBUG) {
   4.398 -            return node.toString();
   4.399 -        }
   4.400 -        return "";
   4.401 -    }
   4.402 -}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/jdk/nashorn/internal/codegen/Attr.java	Wed Jan 30 12:26:45 2013 +0100
     5.3 @@ -0,0 +1,1584 @@
     5.4 +/*
     5.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.  Oracle designates this
    5.11 + * particular file as subject to the "Classpath" exception as provided
    5.12 + * by Oracle in the LICENSE file that accompanied this code.
    5.13 + *
    5.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.17 + * version 2 for more details (a copy is included in the LICENSE file that
    5.18 + * accompanied this code).
    5.19 + *
    5.20 + * You should have received a copy of the GNU General Public License version
    5.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.23 + *
    5.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.25 + * or visit www.oracle.com if you need additional information or have any
    5.26 + * questions.
    5.27 + */
    5.28 +
    5.29 +package jdk.nashorn.internal.codegen;
    5.30 +
    5.31 +import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
    5.32 +import static jdk.nashorn.internal.codegen.CompilerConstants.EXCEPTION_PREFIX;
    5.33 +import static jdk.nashorn.internal.codegen.CompilerConstants.ITERATOR_PREFIX;
    5.34 +import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
    5.35 +import static jdk.nashorn.internal.codegen.CompilerConstants.SCRIPT_RETURN;
    5.36 +import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX;
    5.37 +import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
    5.38 +import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
    5.39 +import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
    5.40 +import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
    5.41 +import static jdk.nashorn.internal.ir.Symbol.IS_LET;
    5.42 +import static jdk.nashorn.internal.ir.Symbol.IS_PARAM;
    5.43 +import static jdk.nashorn.internal.ir.Symbol.IS_THIS;
    5.44 +import static jdk.nashorn.internal.ir.Symbol.IS_VAR;
    5.45 +
    5.46 +import java.util.ArrayList;
    5.47 +import java.util.HashSet;
    5.48 +import java.util.LinkedList;
    5.49 +import java.util.List;
    5.50 +import java.util.Set;
    5.51 +
    5.52 +import jdk.nashorn.internal.codegen.types.Type;
    5.53 +import jdk.nashorn.internal.ir.AccessNode;
    5.54 +import jdk.nashorn.internal.ir.BinaryNode;
    5.55 +import jdk.nashorn.internal.ir.Block;
    5.56 +import jdk.nashorn.internal.ir.CallNode;
    5.57 +import jdk.nashorn.internal.ir.CallNode.EvalArgs;
    5.58 +import jdk.nashorn.internal.ir.CaseNode;
    5.59 +import jdk.nashorn.internal.ir.CatchNode;
    5.60 +import jdk.nashorn.internal.ir.ForNode;
    5.61 +import jdk.nashorn.internal.ir.FunctionNode;
    5.62 +import jdk.nashorn.internal.ir.IdentNode;
    5.63 +import jdk.nashorn.internal.ir.IndexNode;
    5.64 +import jdk.nashorn.internal.ir.LiteralNode;
    5.65 +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
    5.66 +import jdk.nashorn.internal.ir.Node;
    5.67 +import jdk.nashorn.internal.ir.ObjectNode;
    5.68 +import jdk.nashorn.internal.ir.PropertyNode;
    5.69 +import jdk.nashorn.internal.ir.ReferenceNode;
    5.70 +import jdk.nashorn.internal.ir.ReturnNode;
    5.71 +import jdk.nashorn.internal.ir.RuntimeNode;
    5.72 +import jdk.nashorn.internal.ir.RuntimeNode.Request;
    5.73 +import jdk.nashorn.internal.ir.SwitchNode;
    5.74 +import jdk.nashorn.internal.ir.Symbol;
    5.75 +import jdk.nashorn.internal.ir.TernaryNode;
    5.76 +import jdk.nashorn.internal.ir.TryNode;
    5.77 +import jdk.nashorn.internal.ir.UnaryNode;
    5.78 +import jdk.nashorn.internal.ir.VarNode;
    5.79 +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
    5.80 +import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    5.81 +import jdk.nashorn.internal.parser.TokenType;
    5.82 +import jdk.nashorn.internal.runtime.Context;
    5.83 +import jdk.nashorn.internal.runtime.Debug;
    5.84 +import jdk.nashorn.internal.runtime.DebugLogger;
    5.85 +import jdk.nashorn.internal.runtime.ECMAException;
    5.86 +import jdk.nashorn.internal.runtime.JSType;
    5.87 +import jdk.nashorn.internal.runtime.Property;
    5.88 +import jdk.nashorn.internal.runtime.PropertyMap;
    5.89 +import jdk.nashorn.internal.runtime.ScriptFunction;
    5.90 +import jdk.nashorn.internal.runtime.ScriptObject;
    5.91 +import jdk.nashorn.internal.runtime.Source;
    5.92 +
    5.93 +/**
    5.94 + * This is the attribution pass of the code generator. Attr takes Lowered IR,
    5.95 + * that is, IR where control flow has been computed and high level to low level
    5.96 + * substitions for operations have been performed.
    5.97 + *
    5.98 + * After Attr, every symbol will have a conservative correct type.
    5.99 + *
   5.100 + * Any expression that requires temporary storage as part of computation will
   5.101 + * also be detected here and give a temporary symbol
   5.102 + *
   5.103 + * Types can be narrowed after Attr by Access Specialization in FinalizeTypes,
   5.104 + * but in general, this is where the main symbol type information is
   5.105 + * computed.
   5.106 + */
   5.107 +
   5.108 +final class Attr extends NodeOperatorVisitor {
   5.109 +    /** Current compiler. */
   5.110 +    private final Compiler compiler;
   5.111 +
   5.112 +    /** Current source. */
   5.113 +    private final Source source;
   5.114 +
   5.115 +    /**
   5.116 +     * Local definitions in current block (to discriminate from function
   5.117 +     * declarations always defined in the function scope. This is for
   5.118 +     * "can be undefined" analysis.
   5.119 +     */
   5.120 +    private Set<String> localDefs;
   5.121 +
   5.122 +    /**
   5.123 +     * Local definitions in current block to guard against cases like
   5.124 +     * NASHORN-467 when things can be undefined as they are used before
   5.125 +     * their local var definition. *sigh* JavaScript...
   5.126 +     */
   5.127 +    private Set<String> localUses;
   5.128 +
   5.129 +    private static final DebugLogger LOG = new DebugLogger("attr");
   5.130 +
   5.131 +    /**
   5.132 +     * Constructor.
   5.133 +     *
   5.134 +     * @param compiler the compiler
   5.135 +     */
   5.136 +    Attr(final Compiler compiler) {
   5.137 +        this.compiler = compiler;
   5.138 +        this.source   = compiler.getSource();
   5.139 +    }
   5.140 +
   5.141 +    @Override
   5.142 +    protected Node enterDefault(final Node node) {
   5.143 +        return start(node);
   5.144 +    }
   5.145 +
   5.146 +    @Override
   5.147 +    protected Node leaveDefault(final Node node) {
   5.148 +        return end(node);
   5.149 +    }
   5.150 +
   5.151 +    @Override
   5.152 +    public Node leave(final AccessNode accessNode) {
   5.153 +        newTemporary(Type.OBJECT, accessNode);  //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this
   5.154 +        end(accessNode);
   5.155 +        return accessNode;
   5.156 +    }
   5.157 +
   5.158 +    @Override
   5.159 +    public Node enter(final Block block) {
   5.160 +        start(block);
   5.161 +
   5.162 +        final Set<String> savedLocalDefs = localDefs;
   5.163 +        final Set<String> savedLocalUses = localUses;
   5.164 +
   5.165 +        block.setFrame(getCurrentFunctionNode().pushFrame());
   5.166 +
   5.167 +        try {
   5.168 +            // a block starts out by copying the local defs and local uses
   5.169 +            // from the outer level. But we need the copies, as when we
   5.170 +            // leave the block the def and use sets given upon entry must
   5.171 +            // be restored
   5.172 +            localDefs = new HashSet<>(savedLocalDefs);
   5.173 +            localUses = new HashSet<>(savedLocalUses);
   5.174 +
   5.175 +            for (final Node statement : block.getStatements()) {
   5.176 +                statement.accept(this);
   5.177 +            }
   5.178 +        } finally {
   5.179 +            localDefs = savedLocalDefs;
   5.180 +            localUses = savedLocalUses;
   5.181 +
   5.182 +            getCurrentFunctionNode().popFrame();
   5.183 +        }
   5.184 +
   5.185 +        end(block);
   5.186 +
   5.187 +        return null;
   5.188 +    }
   5.189 +
   5.190 +    @Override
   5.191 +    public Node enter(final CallNode callNode) {
   5.192 +        start(callNode);
   5.193 +
   5.194 +        callNode.getFunction().accept(this);
   5.195 +
   5.196 +        final List<Node> acceptedArgs = new ArrayList<>(callNode.getArgs().size());
   5.197 +        for (final Node arg : callNode.getArgs()) {
   5.198 +            LOG.info("Doing call arg " + arg);
   5.199 +            acceptedArgs.add(arg.accept(this));
   5.200 +        }
   5.201 +        callNode.setArgs(acceptedArgs);
   5.202 +
   5.203 +        final EvalArgs evalArgs = callNode.getEvalArgs();
   5.204 +        if (evalArgs != null) {
   5.205 +            evalArgs.setCode(evalArgs.getCode().accept(this));
   5.206 +
   5.207 +            final IdentNode thisNode = new IdentNode(getCurrentFunctionNode().getThisNode());
   5.208 +            assert thisNode.getSymbol() != null; //should copy attributed symbol and that's it
   5.209 +            evalArgs.setThis(thisNode);
   5.210 +        }
   5.211 +
   5.212 +        newTemporary(Type.OBJECT, callNode); // object type here, access specialization in FinalizeTypes may narrow it later
   5.213 +        newType(callNode.getFunction().getSymbol(), Type.OBJECT);
   5.214 +
   5.215 +        end(callNode);
   5.216 +
   5.217 +        return null;
   5.218 +    }
   5.219 +
   5.220 +    @Override
   5.221 +    public Node enter(final CatchNode catchNode) {
   5.222 +        final IdentNode exception = catchNode.getException();
   5.223 +        final Block     block     = getCurrentBlock();
   5.224 +
   5.225 +        start(catchNode);
   5.226 +
   5.227 +        // define block-local exception variable
   5.228 +        final Symbol def = block.defineSymbol(exception.getName(), IS_VAR | IS_LET, exception);
   5.229 +        newType(def, Type.OBJECT);
   5.230 +        addLocalDef(exception.getName());
   5.231 +
   5.232 +        return catchNode;
   5.233 +    }
   5.234 +
   5.235 +    @Override
   5.236 +    public Node enter(final FunctionNode functionNode) {
   5.237 +        start(functionNode, false);
   5.238 +
   5.239 +        clearLocalDefs();
   5.240 +        clearLocalUses();
   5.241 +
   5.242 +        functionNode.setFrame(functionNode.pushFrame());
   5.243 +
   5.244 +        initThis(functionNode);
   5.245 +        initCallee(functionNode);
   5.246 +        if (functionNode.isVarArg()) {
   5.247 +            initVarArg(functionNode);
   5.248 +        }
   5.249 +
   5.250 +        initParameters(functionNode);
   5.251 +        initScope(functionNode);
   5.252 +        initReturn(functionNode);
   5.253 +
   5.254 +        // Add all nested functions as symbols in this function
   5.255 +        for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
   5.256 +            final IdentNode ident = nestedFunction.getIdent();
   5.257 +            if (ident != null && nestedFunction.isStatement()) {
   5.258 +                final Symbol functionSymbol = functionNode.defineSymbol(ident.getName(), IS_VAR, nestedFunction);
   5.259 +                newType(functionSymbol, Type.typeFor(ScriptFunction.class));
   5.260 +            }
   5.261 +        }
   5.262 +
   5.263 +        if (functionNode.isScript()) {
   5.264 +            initFromPropertyMap(compiler.getContext(), functionNode);
   5.265 +        }
   5.266 +
   5.267 +        // Add function name as local symbol
   5.268 +        if (!functionNode.isStatement() && !functionNode.isAnonymous() && !functionNode.isScript()) {
   5.269 +            final Symbol selfSymbol = functionNode.defineSymbol(functionNode.getIdent().getName(), IS_VAR, functionNode);
   5.270 +            newType(selfSymbol, Type.OBJECT);
   5.271 +            selfSymbol.setNode(functionNode);
   5.272 +        }
   5.273 +
   5.274 +        /*
   5.275 +         * This pushes all declarations (except for non-statements, i.e. for
   5.276 +         * node temporaries) to the top of the function scope. This way we can
   5.277 +         * get around problems like
   5.278 +         *
   5.279 +         * while (true) {
   5.280 +         *   break;
   5.281 +         *   if (true) {
   5.282 +         *     var s;
   5.283 +         *   }
   5.284 +         * }
   5.285 +         *
   5.286 +         * to an arbitrary nesting depth.
   5.287 +         *
   5.288 +         * @see NASHORN-73
   5.289 +         */
   5.290 +
   5.291 +        final List<Symbol> declaredSymbols = new ArrayList<>();
   5.292 +        for (final VarNode decl : functionNode.getDeclarations()) {
   5.293 +            final IdentNode ident = decl.getName();
   5.294 +            // any declared symbols that aren't visited need to be typed as well, hence the list
   5.295 +            declaredSymbols.add(functionNode.defineSymbol(ident.getName(), IS_VAR, new IdentNode(ident)));
   5.296 +        }
   5.297 +
   5.298 +        // Every nested function needs a definition in the outer function with its name. Add these.
   5.299 +        for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
   5.300 +            final VarNode varNode = nestedFunction.getFunctionVarNode();
   5.301 +            if (varNode != null) {
   5.302 +                varNode.accept(this);
   5.303 +                assert varNode.isFunctionVarNode() : varNode + " should be function var node";
   5.304 +            }
   5.305 +        }
   5.306 +
   5.307 +        for (final Node statement : functionNode.getStatements()) {
   5.308 +            if (statement instanceof VarNode && ((VarNode)statement).isFunctionVarNode()) {
   5.309 +                continue; //var nodes have already been processed, skip or they will generate additional defs/uses and false "can be undefined"
   5.310 +            }
   5.311 +            statement.accept(this);
   5.312 +        }
   5.313 +
   5.314 +        for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
   5.315 +            LOG.info("Going into nested function " + functionNode.getName() + " -> " + nestedFunction.getName());
   5.316 +            nestedFunction.accept(this);
   5.317 +        }
   5.318 +
   5.319 +        //unknown parameters are promoted to object type.
   5.320 +        finalizeParameters(functionNode);
   5.321 +        finalizeTypes(functionNode);
   5.322 +        for (final Symbol symbol : declaredSymbols) {
   5.323 +            if (symbol.getSymbolType().isUnknown()) {
   5.324 +                symbol.setType(Type.OBJECT);
   5.325 +                symbol.setCanBeUndefined();
   5.326 +            }
   5.327 +        }
   5.328 +
   5.329 +        if (functionNode.getReturnType().isUnknown()) {
   5.330 +            LOG.info("Unknown return type promoted to object");
   5.331 +            functionNode.setReturnType(Type.OBJECT);
   5.332 +        }
   5.333 +
   5.334 +        if (functionNode.getSelfSymbolInit() != null) {
   5.335 +            LOG.info("Accepting self symbol init " + functionNode.getSelfSymbolInit() + " for " + functionNode.getName());
   5.336 +            final Node init = functionNode.getSelfSymbolInit();
   5.337 +            final List<Node> newStatements = new ArrayList<>();
   5.338 +            newStatements.add(init);
   5.339 +            newStatements.addAll(functionNode.getStatements());
   5.340 +            functionNode.setStatements(newStatements);
   5.341 +            functionNode.setNeedsSelfSymbol(functionNode.getSelfSymbolInit().accept(this));
   5.342 +        }
   5.343 +
   5.344 +        functionNode.popFrame();
   5.345 +
   5.346 +        end(functionNode, false);
   5.347 +
   5.348 +        return null;
   5.349 +    }
   5.350 +
   5.351 +    @Override
   5.352 +    public Node leaveCONVERT(final UnaryNode unaryNode) {
   5.353 +        assert false : "There should be no convert operators in IR during Attribution";
   5.354 +        end(unaryNode);
   5.355 +        return unaryNode;
   5.356 +    }
   5.357 +
   5.358 +    @Override
   5.359 +    public Node enter(final IdentNode identNode) {
   5.360 +        final String name = identNode.getName();
   5.361 +
   5.362 +        start(identNode);
   5.363 +
   5.364 +        if (identNode.isPropertyName()) {
   5.365 +            // assign a pseudo symbol to property name
   5.366 +            final Symbol pseudoSymbol = pseudoSymbol(name);
   5.367 +            LOG.info("IdentNode is property name -> assigning pseudo symbol " + pseudoSymbol);
   5.368 +            LOG.unindent();
   5.369 +            identNode.setSymbol(pseudoSymbol);
   5.370 +            return null;
   5.371 +        }
   5.372 +
   5.373 +        final Block  block     = getCurrentBlock();
   5.374 +        final Symbol oldSymbol = identNode.getSymbol();
   5.375 +
   5.376 +        Symbol symbol = block.findSymbol(name);
   5.377 +
   5.378 +        //If an existing symbol with the name is found, use that otherwise, declare a new one
   5.379 +        if (symbol != null) {
   5.380 +            LOG.info("Existing symbol = " + symbol);
   5.381 +            if (isFunctionExpressionSelfReference(symbol)) {
   5.382 +                final FunctionNode functionNode = (FunctionNode)symbol.getNode();
   5.383 +                assert functionNode.getCalleeNode() != null;
   5.384 +
   5.385 +                final VarNode var = new VarNode(source, functionNode.getToken(), functionNode.getFinish(), functionNode.getIdent(), functionNode.getCalleeNode());
   5.386 +                //newTemporary(Type.OBJECT, var); //ScriptFunction? TODO
   5.387 +
   5.388 +                functionNode.setNeedsSelfSymbol(var);
   5.389 +            }
   5.390 +
   5.391 +            if (!identNode.isInitializedHere()) { // NASHORN-448
   5.392 +                // here is a use outside the local def scope
   5.393 +                if (!isLocalDef(name)) {
   5.394 +                    newType(symbol, Type.OBJECT);
   5.395 +                    symbol.setCanBeUndefined();
   5.396 +                }
   5.397 +            }
   5.398 +
   5.399 +            identNode.setSymbol(symbol);
   5.400 +            if (!getCurrentFunctionNode().isLocal(symbol)) {
   5.401 +                // non-local: we need to put symbol in scope (if it isn't already)
   5.402 +                if (!symbol.isScope()) {
   5.403 +                    final List<Block> lookupBlocks = findLookupBlocksHelper(getCurrentFunctionNode(), symbol.findFunction());
   5.404 +                    for (final Block lookupBlock : lookupBlocks) {
   5.405 +                        final Symbol refSymbol = lookupBlock.findSymbol(name);
   5.406 +                        if (refSymbol != null) { // See NASHORN-837, function declaration in lexical scope: try {} catch (x){ function f() { use(x) } } f()
   5.407 +                            LOG.finest("Found a ref symbol that must be scope " + refSymbol);
   5.408 +                            refSymbol.setIsScope();
   5.409 +                        }
   5.410 +                    }
   5.411 +                }
   5.412 +            }
   5.413 +        } else {
   5.414 +            LOG.info("No symbol exists. Declare undefined: " + symbol);
   5.415 +            symbol = block.useSymbol(name, identNode);
   5.416 +            // we have never seen this before, it can be undefined
   5.417 +            newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway?
   5.418 +            symbol.setCanBeUndefined();
   5.419 +        }
   5.420 +
   5.421 +        if (symbol != oldSymbol && !identNode.isInitializedHere()) {
   5.422 +            symbol.increaseUseCount();
   5.423 +        }
   5.424 +        addLocalUse(identNode.getName());
   5.425 +
   5.426 +        end(identNode);
   5.427 +
   5.428 +        return null;
   5.429 +    }
   5.430 +
   5.431 +    @Override
   5.432 +    public Node leave(final IndexNode indexNode) {
   5.433 +        newTemporary(Type.OBJECT, indexNode); //TORO
   5.434 +        return indexNode;
   5.435 +    }
   5.436 +
   5.437 +    @SuppressWarnings("rawtypes")
   5.438 +    @Override
   5.439 +    public Node enter(final LiteralNode literalNode) {
   5.440 +        try {
   5.441 +            start(literalNode);
   5.442 +            assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens
   5.443 +
   5.444 +            if (literalNode instanceof ArrayLiteralNode) {
   5.445 +                final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
   5.446 +                final Node[]           array            = arrayLiteralNode.getValue();
   5.447 +
   5.448 +                for (int i = 0; i < array.length; i++) {
   5.449 +                    final Node element = array[i];
   5.450 +                    if (element != null) {
   5.451 +                        array[i] = element.accept(this);
   5.452 +                    }
   5.453 +                }
   5.454 +                arrayLiteralNode.analyze();
   5.455 +                //array literal node now has an element type and all elements are attributed
   5.456 +            } else {
   5.457 +                assert !(literalNode.getValue() instanceof Node) : "literals with Node values not supported";
   5.458 +            }
   5.459 +
   5.460 +            getCurrentFunctionNode().newLiteral(literalNode);
   5.461 +        } finally {
   5.462 +            end(literalNode);
   5.463 +        }
   5.464 +        return null;
   5.465 +    }
   5.466 +
   5.467 +    @Override
   5.468 +    public Node leave(final ObjectNode objectNode) {
   5.469 +        newTemporary(Type.OBJECT, objectNode);
   5.470 +        end(objectNode);
   5.471 +        return objectNode;
   5.472 +    }
   5.473 +
   5.474 +    @Override
   5.475 +    public Node enter(final PropertyNode propertyNode) {
   5.476 +        // assign a pseudo symbol to property name, see NASHORN-710
   5.477 +        propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
   5.478 +        end(propertyNode);
   5.479 +        return propertyNode;
   5.480 +    }
   5.481 +
   5.482 +    @Override
   5.483 +    public Node enter(final ReferenceNode referenceNode) {
   5.484 +        final FunctionNode functionNode = referenceNode.getReference();
   5.485 +        if (functionNode != null) {
   5.486 +            functionNode.addReferencingParentBlock(getCurrentBlock());
   5.487 +        }
   5.488 +        end(referenceNode);
   5.489 +
   5.490 +        return referenceNode;
   5.491 +    }
   5.492 +
   5.493 +    @Override
   5.494 +    public Node leave(final ReferenceNode referenceNode) {
   5.495 +        newTemporary(Type.OBJECT, referenceNode); //reference node type is always an object, i.e. the scriptFunction. the function return type varies though
   5.496 +        end(referenceNode);
   5.497 +        return referenceNode;
   5.498 +    }
   5.499 +
   5.500 +    @Override
   5.501 +    public Node leave(final ReturnNode returnNode) {
   5.502 +        final Node expr = returnNode.getExpression();
   5.503 +
   5.504 +        if (expr != null) {
   5.505 +            //we can't do parameter specialization if we return something that hasn't been typed yet
   5.506 +            final Symbol symbol = expr.getSymbol();
   5.507 +            if (expr.getType().isUnknown() && symbol.isParam()) {
   5.508 +                symbol.setType(Type.OBJECT);
   5.509 +            }
   5.510 +            getCurrentFunctionNode().setReturnType(Type.widest(getCurrentFunctionNode().getReturnType(), symbol.getSymbolType()));
   5.511 +            LOG.info("Returntype is now " + getCurrentFunctionNode().getReturnType());
   5.512 +        }
   5.513 +
   5.514 +        end(returnNode);
   5.515 +
   5.516 +        return returnNode;
   5.517 +    }
   5.518 +
   5.519 +    @Override
   5.520 +    public Node leave(final SwitchNode switchNode) {
   5.521 +        Type type = Type.UNKNOWN;
   5.522 +
   5.523 +        for (final CaseNode caseNode : switchNode.getCases()) {
   5.524 +            final Node test = caseNode.getTest();
   5.525 +            if (test != null) {
   5.526 +                if (test instanceof LiteralNode) {
   5.527 +                    //go down to integers if we can
   5.528 +                    final LiteralNode<?> lit = (LiteralNode<?>)test;
   5.529 +                    if (lit.isNumeric() && !(lit.getValue() instanceof Integer)) {
   5.530 +                        if (JSType.isRepresentableAsInt(lit.getNumber())) {
   5.531 +                            caseNode.setTest(LiteralNode.newInstance(lit, lit.getInt32()).accept(this));
   5.532 +                        }
   5.533 +                    }
   5.534 +                }
   5.535 +
   5.536 +                type = Type.widest(type, caseNode.getTest().getType());
   5.537 +            }
   5.538 +        }
   5.539 +
   5.540 +        //only optimize for all integers
   5.541 +        if (!type.isInteger()) {
   5.542 +            type = Type.OBJECT;
   5.543 +        }
   5.544 +
   5.545 +        switchNode.setTag(newInternal(compiler.uniqueName(SWITCH_TAG_PREFIX.tag()), type));
   5.546 +
   5.547 +        end(switchNode);
   5.548 +
   5.549 +        return switchNode;
   5.550 +    }
   5.551 +
   5.552 +    @Override
   5.553 +    public Node leave(final TryNode tryNode) {
   5.554 +        tryNode.setException(exceptionSymbol());
   5.555 +
   5.556 +        if (tryNode.getFinallyBody() != null) {
   5.557 +            tryNode.setFinallyCatchAll(exceptionSymbol());
   5.558 +        }
   5.559 +
   5.560 +        end(tryNode);
   5.561 +
   5.562 +        return tryNode;
   5.563 +    }
   5.564 +
   5.565 +    @Override
   5.566 +    public Node enter(final VarNode varNode) {
   5.567 +        start(varNode);
   5.568 +
   5.569 +        final IdentNode ident = varNode.getName();
   5.570 +        final String    name  = ident.getName();
   5.571 +
   5.572 +        final Symbol symbol = getCurrentBlock().defineSymbol(name, IS_VAR, ident);
   5.573 +        assert symbol != null;
   5.574 +
   5.575 +        LOG.info("VarNode " + varNode + " set symbol " + symbol);
   5.576 +        varNode.setSymbol(symbol);
   5.577 +
   5.578 +        // NASHORN-467 - use before definition of vars - conservative
   5.579 +        if (localUses.contains(ident.getName())) {
   5.580 +            newType(symbol, Type.OBJECT);
   5.581 +            symbol.setCanBeUndefined();
   5.582 +        }
   5.583 +
   5.584 +        if (varNode.getInit() != null) {
   5.585 +            varNode.getInit().accept(this);
   5.586 +        }
   5.587 +
   5.588 +        return varNode;
   5.589 +    }
   5.590 +
   5.591 +    @Override
   5.592 +    public Node leave(final VarNode varNode) {
   5.593 +        final Node      init  = varNode.getInit();
   5.594 +        final IdentNode ident = varNode.getName();
   5.595 +        final String    name  = ident.getName();
   5.596 +
   5.597 +        if (init != null) {
   5.598 +            addLocalDef(name);
   5.599 +        }
   5.600 +
   5.601 +        if (init == null) {
   5.602 +            // var x; with no init will be treated like a use of x by
   5.603 +            // visit(IdentNode) unless we remove the name
   5.604 +            // from the localdef list.
   5.605 +            removeLocalDef(name);
   5.606 +            return varNode;
   5.607 +        }
   5.608 +
   5.609 +        final Symbol  symbol   = varNode.getSymbol();
   5.610 +        final boolean isScript = symbol.getBlock().getFunction().isScript(); //see NASHORN-56
   5.611 +        if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) {
   5.612 +            // Forbid integers as local vars for now as we have no way to treat them as undefined
   5.613 +            newType(symbol, init.getType());
   5.614 +        } else {
   5.615 +            newType(symbol, Type.OBJECT);
   5.616 +        }
   5.617 +
   5.618 +        assert varNode.hasType() : varNode;
   5.619 +
   5.620 +        end(varNode);
   5.621 +
   5.622 +        return varNode;
   5.623 +    }
   5.624 +
   5.625 +    @Override
   5.626 +    public Node leaveADD(final UnaryNode unaryNode) {
   5.627 +        newTemporary(arithType(), unaryNode);
   5.628 +        end(unaryNode);
   5.629 +        return unaryNode;
   5.630 +    }
   5.631 +
   5.632 +    @Override
   5.633 +    public Node leaveBIT_NOT(final UnaryNode unaryNode) {
   5.634 +        newTemporary(Type.INT, unaryNode);
   5.635 +        end(unaryNode);
   5.636 +        return unaryNode;
   5.637 +    }
   5.638 +
   5.639 +    @Override
   5.640 +    public Node leaveDECINC(final UnaryNode unaryNode) {
   5.641 +        // @see assignOffset
   5.642 +        ensureAssignmentSlots(getCurrentFunctionNode(), unaryNode.rhs());
   5.643 +        final Type type = arithType();
   5.644 +        newType(unaryNode.rhs().getSymbol(), type);
   5.645 +        newTemporary(type, unaryNode);
   5.646 +        end(unaryNode);
   5.647 +        return unaryNode;
   5.648 +    }
   5.649 +
   5.650 +    @Override
   5.651 +    public Node leaveDELETE(final UnaryNode unaryNode) {
   5.652 +        final FunctionNode   currentFunctionNode = getCurrentFunctionNode();
   5.653 +        final boolean        strictMode          = currentFunctionNode.isStrictMode();
   5.654 +        final Node           rhs                 = unaryNode.rhs();
   5.655 +        final Node           strictFlagNode      = LiteralNode.newInstance(unaryNode, strictMode).accept(this);
   5.656 +
   5.657 +        Request request = Request.DELETE;
   5.658 +        final RuntimeNode runtimeNode;
   5.659 +        final List<Node> args = new ArrayList<>();
   5.660 +
   5.661 +        if (rhs instanceof IdentNode) {
   5.662 +            // If this is a declared variable or a function parameter, delete always fails (except for globals).
   5.663 +            final String name = ((IdentNode)rhs).getName();
   5.664 +
   5.665 +            final boolean failDelete = strictMode || rhs.getSymbol().isParam() || (rhs.getSymbol().isVar() && !rhs.getSymbol().isTopLevel());
   5.666 +
   5.667 +            if (failDelete && rhs.getSymbol().isThis()) {
   5.668 +                return LiteralNode.newInstance(unaryNode, true).accept(this);
   5.669 +            }
   5.670 +            final Node literalNode = LiteralNode.newInstance(unaryNode, name).accept(this);
   5.671 +
   5.672 +            args.add(currentFunctionNode.getScopeNode());
   5.673 +            args.add(literalNode);
   5.674 +            args.add(strictFlagNode);
   5.675 +
   5.676 +            if (failDelete) {
   5.677 +                request = Request.FAIL_DELETE;
   5.678 +            }
   5.679 +        } else if (rhs instanceof AccessNode) {
   5.680 +            final Node      base     = ((AccessNode)rhs).getBase();
   5.681 +            final IdentNode property = ((AccessNode)rhs).getProperty();
   5.682 +
   5.683 +            args.add(base);
   5.684 +            args.add(LiteralNode.newInstance(unaryNode, property.getName()).accept(this));
   5.685 +            args.add(strictFlagNode);
   5.686 +
   5.687 +        } else if (rhs instanceof IndexNode) {
   5.688 +            final Node base  = ((IndexNode)rhs).getBase();
   5.689 +            final Node index = ((IndexNode)rhs).getIndex();
   5.690 +
   5.691 +            args.add(base);
   5.692 +            args.add(index);
   5.693 +            args.add(strictFlagNode);
   5.694 +
   5.695 +        } else {
   5.696 +            return LiteralNode.newInstance(unaryNode, true).accept(this);
   5.697 +        }
   5.698 +
   5.699 +        runtimeNode = new RuntimeNode(unaryNode, request, args);
   5.700 +        assert runtimeNode.getSymbol() == unaryNode.getSymbol(); //clone constructor should do this
   5.701 +
   5.702 +        runtimeNode.accept(this);
   5.703 +        return runtimeNode;
   5.704 +    }
   5.705 +
   5.706 +
   5.707 +    @Override
   5.708 +    public Node leaveNEW(final UnaryNode unaryNode) {
   5.709 +        newTemporary(Type.OBJECT, unaryNode);
   5.710 +        end(unaryNode);
   5.711 +        return unaryNode;
   5.712 +    }
   5.713 +
   5.714 +    @Override
   5.715 +    public Node leaveNOT(final UnaryNode unaryNode) {
   5.716 +        newTemporary(Type.BOOLEAN, unaryNode);
   5.717 +        end(unaryNode);
   5.718 +        return unaryNode;
   5.719 +    }
   5.720 +
   5.721 +    @Override
   5.722 +    public Node leaveTYPEOF(final UnaryNode unaryNode) {
   5.723 +        final Node rhs    = unaryNode.rhs();
   5.724 +
   5.725 +        RuntimeNode runtimeNode;
   5.726 +
   5.727 +        List<Node> args = new ArrayList<>();
   5.728 +        if (rhs instanceof IdentNode && !rhs.getSymbol().isParam() && !rhs.getSymbol().isVar()) {
   5.729 +            args.add(getCurrentFunctionNode().getScopeNode());
   5.730 +            args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
   5.731 +        } else {
   5.732 +            args.add(rhs);
   5.733 +            args.add(LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
   5.734 +        }
   5.735 +
   5.736 +        runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
   5.737 +        assert runtimeNode.getSymbol() == unaryNode.getSymbol();
   5.738 +
   5.739 +        runtimeNode.accept(this);
   5.740 +
   5.741 +        end(unaryNode);
   5.742 +
   5.743 +        return runtimeNode;
   5.744 +    }
   5.745 +
   5.746 +    @Override
   5.747 +    public Node leave(final RuntimeNode runtimeNode) {
   5.748 +        newTemporary(runtimeNode.getRequest().getReturnType(), runtimeNode);
   5.749 +        return runtimeNode;
   5.750 +    }
   5.751 +
   5.752 +    @Override
   5.753 +    public Node leaveSUB(final UnaryNode unaryNode) {
   5.754 +        newTemporary(arithType(), unaryNode);
   5.755 +        end(unaryNode);
   5.756 +        return unaryNode;
   5.757 +    }
   5.758 +
   5.759 +    @Override
   5.760 +    public Node leaveVOID(final UnaryNode unaryNode) {
   5.761 +        final RuntimeNode runtimeNode = new RuntimeNode(unaryNode, Request.VOID);
   5.762 +        runtimeNode.accept(this);
   5.763 +        assert runtimeNode.getSymbol().getSymbolType().isObject();
   5.764 +        end(unaryNode);
   5.765 +        return runtimeNode;
   5.766 +    }
   5.767 +
   5.768 +    /**
   5.769 +     * Add is a special binary, as it works not only on arithmetic, but for
   5.770 +     * strings etc as well.
   5.771 +     */
   5.772 +    @Override
   5.773 +    public Node leaveADD(final BinaryNode binaryNode) {
   5.774 +        final Node lhs = binaryNode.lhs();
   5.775 +        final Node rhs = binaryNode.rhs();
   5.776 +
   5.777 +        ensureTypeNotUnknown(lhs);
   5.778 +        ensureTypeNotUnknown(rhs);
   5.779 +        newTemporary(Type.widest(lhs.getType(), rhs.getType()), binaryNode);
   5.780 +
   5.781 +        end(binaryNode);
   5.782 +
   5.783 +        return binaryNode;
   5.784 +    }
   5.785 +
   5.786 +    @Override
   5.787 +    public Node leaveAND(final BinaryNode binaryNode) {
   5.788 +        newTemporary(Type.OBJECT, binaryNode);
   5.789 +        end(binaryNode);
   5.790 +        return binaryNode;
   5.791 +    }
   5.792 +
   5.793 +    /**
   5.794 +     * This is a helper called before an assignment.
   5.795 +     * @param binaryNode assignment node
   5.796 +     */
   5.797 +    private Node enterAssignmentNode(final BinaryNode binaryNode) {
   5.798 +        start(binaryNode);
   5.799 +
   5.800 +        final Node lhs = binaryNode.lhs();
   5.801 +
   5.802 +        if (lhs instanceof IdentNode) {
   5.803 +            final Block     block = getCurrentBlock();
   5.804 +            final IdentNode ident = (IdentNode)lhs;
   5.805 +            final String    name  = ident.getName();
   5.806 +
   5.807 +            Symbol symbol = getCurrentBlock().findSymbol(name);
   5.808 +
   5.809 +            if (symbol == null) {
   5.810 +                symbol = block.defineSymbol(name, IS_GLOBAL, ident);
   5.811 +                binaryNode.setSymbol(symbol);
   5.812 +            } else if (!getCurrentFunctionNode().isLocal(symbol)) {
   5.813 +                symbol.setIsScope();
   5.814 +            }
   5.815 +
   5.816 +            addLocalDef(name);
   5.817 +        }
   5.818 +
   5.819 +        return binaryNode;
   5.820 +    }
   5.821 +
   5.822 +    @Override
   5.823 +    public Node enterASSIGN(final BinaryNode binaryNode) {
   5.824 +        return enterAssignmentNode(binaryNode);
   5.825 +    }
   5.826 +
   5.827 +    @Override
   5.828 +    public Node leaveASSIGN(final BinaryNode binaryNode) {
   5.829 +        return leaveAssignmentNode(binaryNode);
   5.830 +    }
   5.831 +
   5.832 +    @Override
   5.833 +    public Node enterASSIGN_ADD(final BinaryNode binaryNode) {
   5.834 +        return enterAssignmentNode(binaryNode);
   5.835 +    }
   5.836 +
   5.837 +    @Override
   5.838 +    public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
   5.839 +        final Node lhs = binaryNode.lhs();
   5.840 +        final Node rhs = binaryNode.rhs();
   5.841 +
   5.842 +        final Type widest = Type.widest(lhs.getType(), rhs.getType());
   5.843 +        //Type.NUMBER if we can't prove that the add doesn't overflow. todo
   5.844 +        return leaveSelfModifyingAssignmentNode(binaryNode, widest.isNumeric() ? Type.NUMBER : Type.OBJECT);
   5.845 +    }
   5.846 +
   5.847 +    @Override
   5.848 +    public Node enterASSIGN_BIT_AND(final BinaryNode binaryNode) {
   5.849 +        return enterAssignmentNode(binaryNode);
   5.850 +    }
   5.851 +
   5.852 +    @Override
   5.853 +    public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) {
   5.854 +        return leaveSelfModifyingAssignmentNode(binaryNode);
   5.855 +    }
   5.856 +
   5.857 +    @Override
   5.858 +    public Node enterASSIGN_BIT_OR(final BinaryNode binaryNode) {
   5.859 +        return enterAssignmentNode(binaryNode);
   5.860 +    }
   5.861 +
   5.862 +    @Override
   5.863 +    public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) {
   5.864 +        return leaveSelfModifyingAssignmentNode(binaryNode);
   5.865 +    }
   5.866 +
   5.867 +    @Override
   5.868 +    public Node enterASSIGN_BIT_XOR(final BinaryNode binaryNode) {
   5.869 +        return enterAssignmentNode(binaryNode);
   5.870 +    }
   5.871 +
   5.872 +    @Override
   5.873 +    public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) {
   5.874 +        return leaveSelfModifyingAssignmentNode(binaryNode);
   5.875 +    }
   5.876 +
   5.877 +    @Override
   5.878 +    public Node enterASSIGN_DIV(final BinaryNode binaryNode) {
   5.879 +        return enterAssignmentNode(binaryNode);
   5.880 +    }
   5.881 +
   5.882 +    @Override
   5.883 +    public Node leaveASSIGN_DIV(final BinaryNode binaryNode) {
   5.884 +        return leaveSelfModifyingAssignmentNode(binaryNode);
   5.885 +    }
   5.886 +
   5.887 +    @Override
   5.888 +    public Node enterASSIGN_MOD(final BinaryNode binaryNode) {
   5.889 +        return enterAssignmentNode(binaryNode);
   5.890 +    }
   5.891 +
   5.892 +    @Override
   5.893 +    public Node leaveASSIGN_MOD(final BinaryNode binaryNode) {
   5.894 +        return leaveSelfModifyingAssignmentNode(binaryNode);
   5.895 +    }
   5.896 +
   5.897 +    @Override
   5.898 +    public Node enterASSIGN_MUL(final BinaryNode binaryNode) {
   5.899 +        return enterAssignmentNode(binaryNode);
   5.900 +    }
   5.901 +
   5.902 +    @Override
   5.903 +    public Node leaveASSIGN_MUL(final BinaryNode binaryNode) {
   5.904 +        return leaveSelfModifyingAssignmentNode(binaryNode);
   5.905 +    }
   5.906 +
   5.907 +    @Override
   5.908 +    public Node enterASSIGN_SAR(final BinaryNode binaryNode) {
   5.909 +        return enterAssignmentNode(binaryNode);
   5.910 +    }
   5.911 +
   5.912 +    @Override
   5.913 +    public Node leaveASSIGN_SAR(final BinaryNode binaryNode) {
   5.914 +        return leaveSelfModifyingAssignmentNode(binaryNode);
   5.915 +    }
   5.916 +
   5.917 +    @Override
   5.918 +    public Node enterASSIGN_SHL(final BinaryNode binaryNode) {
   5.919 +        return enterAssignmentNode(binaryNode);
   5.920 +    }
   5.921 +
   5.922 +    @Override
   5.923 +    public Node leaveASSIGN_SHL(final BinaryNode binaryNode) {
   5.924 +        return leaveSelfModifyingAssignmentNode(binaryNode);
   5.925 +    }
   5.926 +
   5.927 +    @Override
   5.928 +    public Node enterASSIGN_SHR(final BinaryNode binaryNode) {
   5.929 +        return enterAssignmentNode(binaryNode);
   5.930 +    }
   5.931 +
   5.932 +    @Override
   5.933 +    public Node leaveASSIGN_SHR(final BinaryNode binaryNode) {
   5.934 +        return leaveSelfModifyingAssignmentNode(binaryNode);
   5.935 +    }
   5.936 +
   5.937 +    @Override
   5.938 +    public Node enterASSIGN_SUB(final BinaryNode binaryNode) {
   5.939 +        return enterAssignmentNode(binaryNode);
   5.940 +    }
   5.941 +
   5.942 +    @Override
   5.943 +    public Node leaveASSIGN_SUB(final BinaryNode binaryNode) {
   5.944 +        return leaveSelfModifyingAssignmentNode(binaryNode);
   5.945 +    }
   5.946 +
   5.947 +    @Override
   5.948 +    public Node leaveBIT_AND(final BinaryNode binaryNode) {
   5.949 +        newTemporary(Type.INT, binaryNode);
   5.950 +        return binaryNode;
   5.951 +    }
   5.952 +
   5.953 +    @Override
   5.954 +    public Node leaveBIT_OR(final BinaryNode binaryNode) {
   5.955 +        newTemporary(Type.INT, binaryNode);
   5.956 +        return binaryNode;
   5.957 +    }
   5.958 +
   5.959 +    @Override
   5.960 +    public Node leaveBIT_XOR(final BinaryNode binaryNode) {
   5.961 +        newTemporary(Type.INT, binaryNode);
   5.962 +        return binaryNode;
   5.963 +    }
   5.964 +
   5.965 +    @Override
   5.966 +    public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
   5.967 +        newTemporary(binaryNode.rhs().getType(), binaryNode);
   5.968 +        return binaryNode;
   5.969 +    }
   5.970 +
   5.971 +    @Override
   5.972 +    public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
   5.973 +        newTemporary(binaryNode.lhs().getType(), binaryNode);
   5.974 +        return binaryNode;
   5.975 +    }
   5.976 +
   5.977 +    @Override
   5.978 +    public Node leaveDIV(final BinaryNode binaryNode) {
   5.979 +        return leaveBinaryArithmetic(binaryNode);
   5.980 +    }
   5.981 +
   5.982 +    private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) {
   5.983 +        final Node lhs = binaryNode.lhs();
   5.984 +        final Node rhs = binaryNode.rhs();
   5.985 +
   5.986 +        newTemporary(Type.BOOLEAN, binaryNode);
   5.987 +        ensureTypeNotUnknown(lhs);
   5.988 +        ensureTypeNotUnknown(rhs);
   5.989 +
   5.990 +        end(binaryNode);
   5.991 +        return binaryNode;
   5.992 +    }
   5.993 +
   5.994 +    //leave a binary node and inherit the widest type of lhs , rhs
   5.995 +    private Node leaveBinaryArithmetic(final BinaryNode binaryNode) {
   5.996 +        if (!Compiler.shouldUseIntegerArithmetic()) {
   5.997 +            newTemporary(Type.NUMBER, binaryNode);
   5.998 +            return binaryNode;
   5.999 +        }
  5.1000 +        newTemporary(Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType(), Type.NUMBER), binaryNode);
  5.1001 +        return binaryNode;
  5.1002 +    }
  5.1003 +
  5.1004 +    @Override
  5.1005 +    public Node leaveEQ(final BinaryNode binaryNode) {
  5.1006 +        return leaveCmp(binaryNode, Request.EQ);
  5.1007 +    }
  5.1008 +
  5.1009 +    @Override
  5.1010 +    public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
  5.1011 +        return leaveCmp(binaryNode, Request.EQ_STRICT);
  5.1012 +    }
  5.1013 +
  5.1014 +    @Override
  5.1015 +    public Node leaveGE(final BinaryNode binaryNode) {
  5.1016 +        return leaveCmp(binaryNode, Request.GE);
  5.1017 +    }
  5.1018 +
  5.1019 +    @Override
  5.1020 +    public Node leaveGT(final BinaryNode binaryNode) {
  5.1021 +        return leaveCmp(binaryNode, Request.GT);
  5.1022 +    }
  5.1023 +
  5.1024 +    @Override
  5.1025 +    public Node leaveIN(final BinaryNode binaryNode) {
  5.1026 +        try {
  5.1027 +            return new RuntimeNode(binaryNode, Request.IN).accept(this);
  5.1028 +        } finally {
  5.1029 +            end(binaryNode);
  5.1030 +        }
  5.1031 +    }
  5.1032 +
  5.1033 +    @Override
  5.1034 +    public Node leaveINSTANCEOF(final BinaryNode binaryNode) {
  5.1035 +        try {
  5.1036 +            return new RuntimeNode(binaryNode, Request.INSTANCEOF).accept(this);
  5.1037 +        } finally {
  5.1038 +            end(binaryNode);
  5.1039 +        }
  5.1040 +    }
  5.1041 +
  5.1042 +    @Override
  5.1043 +    public Node leaveLE(final BinaryNode binaryNode) {
  5.1044 +        return leaveCmp(binaryNode, Request.LE);
  5.1045 +    }
  5.1046 +
  5.1047 +    @Override
  5.1048 +    public Node leaveLT(final BinaryNode binaryNode) {
  5.1049 +        return leaveCmp(binaryNode, Request.LT);
  5.1050 +    }
  5.1051 +
  5.1052 +    @Override
  5.1053 +    public Node leaveMOD(final BinaryNode binaryNode) {
  5.1054 +        return leaveBinaryArithmetic(binaryNode);
  5.1055 +    }
  5.1056 +
  5.1057 +    @Override
  5.1058 +    public Node leaveMUL(final BinaryNode binaryNode) {
  5.1059 +        return leaveBinaryArithmetic(binaryNode);
  5.1060 +    }
  5.1061 +
  5.1062 +    @Override
  5.1063 +    public Node leaveNE(final BinaryNode binaryNode) {
  5.1064 +        return leaveCmp(binaryNode, Request.NE);
  5.1065 +    }
  5.1066 +
  5.1067 +    @Override
  5.1068 +    public Node leaveNE_STRICT(final BinaryNode binaryNode) {
  5.1069 +        return leaveCmp(binaryNode, Request.NE_STRICT);
  5.1070 +    }
  5.1071 +
  5.1072 +    @Override
  5.1073 +    public Node leaveOR(final BinaryNode binaryNode) {
  5.1074 +        newTemporary(Type.OBJECT, binaryNode);
  5.1075 +        end(binaryNode);
  5.1076 +        return binaryNode;
  5.1077 +    }
  5.1078 +
  5.1079 +    @Override
  5.1080 +    public Node leaveSAR(final BinaryNode binaryNode) {
  5.1081 +        newTemporary(Type.INT, binaryNode);
  5.1082 +        end(binaryNode);
  5.1083 +        return binaryNode;
  5.1084 +    }
  5.1085 +
  5.1086 +    @Override
  5.1087 +    public Node leaveSHL(final BinaryNode binaryNode) {
  5.1088 +        newTemporary(Type.INT, binaryNode);
  5.1089 +        end(binaryNode);
  5.1090 +        return binaryNode;
  5.1091 +    }
  5.1092 +
  5.1093 +    @Override
  5.1094 +    public Node leaveSHR(final BinaryNode binaryNode) {
  5.1095 +        newTemporary(Type.LONG, binaryNode);
  5.1096 +        end(binaryNode);
  5.1097 +        return binaryNode;
  5.1098 +    }
  5.1099 +
  5.1100 +    @Override
  5.1101 +    public Node leaveSUB(final BinaryNode binaryNode) {
  5.1102 +        return leaveBinaryArithmetic(binaryNode);
  5.1103 +    }
  5.1104 +
  5.1105 +    @Override
  5.1106 +    public Node leave(final ForNode forNode) {
  5.1107 +        if (forNode.isForIn()) {
  5.1108 +            forNode.setIterator(newInternal(getCurrentFunctionNode(), compiler.uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73
  5.1109 +            /*
  5.1110 +             * Iterators return objects, so we need to widen the scope of the
  5.1111 +             * init variable if it, for example, has been assigned double type
  5.1112 +             * see NASHORN-50
  5.1113 +             */
  5.1114 +            newType(forNode.getInit().getSymbol(), Type.OBJECT);
  5.1115 +        }
  5.1116 +
  5.1117 +        end(forNode);
  5.1118 +
  5.1119 +        return forNode;
  5.1120 +    }
  5.1121 +
  5.1122 +    @Override
  5.1123 +    public Node leave(final TernaryNode ternaryNode) {
  5.1124 +        final Node lhs  = ternaryNode.rhs();
  5.1125 +        final Node rhs  = ternaryNode.third();
  5.1126 +
  5.1127 +        ensureTypeNotUnknown(lhs);
  5.1128 +        ensureTypeNotUnknown(rhs);
  5.1129 +
  5.1130 +        final Type type = Type.widest(lhs.getType(), rhs.getType());
  5.1131 +        newTemporary(type, ternaryNode);
  5.1132 +
  5.1133 +        end(ternaryNode);
  5.1134 +
  5.1135 +        return ternaryNode;
  5.1136 +    }
  5.1137 +
  5.1138 +    private static void initThis(final FunctionNode functionNode) {
  5.1139 +        final Symbol thisSymbol = functionNode.defineSymbol(THIS.tag(), IS_PARAM | IS_THIS, null);
  5.1140 +        newType(thisSymbol, Type.OBJECT);
  5.1141 +        thisSymbol.setNeedsSlot(true);
  5.1142 +        functionNode.getThisNode().setSymbol(thisSymbol);
  5.1143 +        LOG.info("Initialized scope symbol: " + thisSymbol);
  5.1144 +    }
  5.1145 +
  5.1146 +    private static void initScope(final FunctionNode functionNode) {
  5.1147 +        final Symbol scopeSymbol = functionNode.defineSymbol(SCOPE.tag(), IS_VAR | IS_INTERNAL, null);
  5.1148 +        newType(scopeSymbol, Type.typeFor(ScriptObject.class));
  5.1149 +        scopeSymbol.setNeedsSlot(true);
  5.1150 +        functionNode.getScopeNode().setSymbol(scopeSymbol);
  5.1151 +        LOG.info("Initialized scope symbol: " + scopeSymbol);
  5.1152 +    }
  5.1153 +
  5.1154 +    private static void initReturn(final FunctionNode functionNode) {
  5.1155 +        final Symbol returnSymbol = functionNode.defineSymbol(SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null);
  5.1156 +        newType(returnSymbol, Type.OBJECT);
  5.1157 +        returnSymbol.setNeedsSlot(true);
  5.1158 +        functionNode.getResultNode().setSymbol(returnSymbol);
  5.1159 +        LOG.info("Initialized return symbol: " + returnSymbol);
  5.1160 +        //return symbol is always object as it's the __return__ thing. What returnType is is another matter though
  5.1161 +    }
  5.1162 +
  5.1163 +    private static void initVarArg(final FunctionNode functionNode) {
  5.1164 +        assert functionNode.getCalleeNode() != null;
  5.1165 +
  5.1166 +        final Symbol varArgsSymbol = functionNode.defineSymbol(VARARGS.tag(), IS_PARAM | IS_INTERNAL, null);
  5.1167 +        newType(varArgsSymbol, Type.OBJECT_ARRAY);
  5.1168 +        varArgsSymbol.setNeedsSlot(true);
  5.1169 +        functionNode.getVarArgsNode().setSymbol(varArgsSymbol);
  5.1170 +        LOG.info("Initialized varargs symbol: " + varArgsSymbol);
  5.1171 +
  5.1172 +        final String    argumentsName   = functionNode.getArgumentsNode().getName();
  5.1173 +        final Symbol    argumentsSymbol = functionNode.defineSymbol(argumentsName, IS_PARAM | IS_INTERNAL, null);
  5.1174 +        newType(argumentsSymbol, Type.OBJECT);
  5.1175 +        argumentsSymbol.setNeedsSlot(true);
  5.1176 +        functionNode.getArgumentsNode().setSymbol(argumentsSymbol);
  5.1177 +        LOG.info("Initialized vararg varArgsSymbol=" + varArgsSymbol + " argumentsSymbol=" + argumentsSymbol);
  5.1178 +    }
  5.1179 +
  5.1180 +    private static void initCallee(final FunctionNode functionNode) {
  5.1181 +        assert functionNode.getCalleeNode() != null : functionNode + " has no callee";
  5.1182 +        final Symbol calleeSymbol = functionNode.defineSymbol(CALLEE.tag(), IS_PARAM | IS_INTERNAL, null);
  5.1183 +        newType(calleeSymbol, Type.typeFor(ScriptFunction.class));
  5.1184 +        calleeSymbol.setNeedsSlot(true);
  5.1185 +        functionNode.getCalleeNode().setSymbol(calleeSymbol);
  5.1186 +        LOG.info("Initialized callee symbol " + calleeSymbol);
  5.1187 +    }
  5.1188 +
  5.1189 +    /**
  5.1190 +     * Initialize parameters for function node. This may require specializing
  5.1191 +     * types if a specialization profile is known
  5.1192 +     *
  5.1193 +     * @param functionNode the function node
  5.1194 +     */
  5.1195 +    private void initParameters(final FunctionNode functionNode) {
  5.1196 +        //If a function is specialized, we don't need to tag either it return
  5.1197 +        // type or its parameters with the widest (OBJECT) type for safety.
  5.1198 +        functionNode.setReturnType(Type.UNKNOWN);
  5.1199 +
  5.1200 +        for (final IdentNode ident : functionNode.getParameters()) {
  5.1201 +            addLocalDef(ident.getName());
  5.1202 +            final Symbol paramSymbol = functionNode.defineSymbol(ident.getName(), IS_PARAM, ident);
  5.1203 +            if (paramSymbol != null) {
  5.1204 +                newType(paramSymbol, Type.UNKNOWN);
  5.1205 +            }
  5.1206 +
  5.1207 +            LOG.info("Initialized param " + paramSymbol);
  5.1208 +        }
  5.1209 +    }
  5.1210 +
  5.1211 +    /**
  5.1212 +     * This has to run before fix assignment types, store any type specializations for
  5.1213 +     * paramters, then turn then to objects for the generic version of this method
  5.1214 +     *
  5.1215 +     * @param functionNode functionNode
  5.1216 +     */
  5.1217 +    private static void finalizeParameters(final FunctionNode functionNode) {
  5.1218 +        boolean nonObjectParams = false;
  5.1219 +        List<Type> paramSpecializations = new ArrayList<>();
  5.1220 +
  5.1221 +        for (final IdentNode ident : functionNode.getParameters()) {
  5.1222 +            final Symbol paramSymbol = ident.getSymbol();
  5.1223 +            if (paramSymbol != null) {
  5.1224 +                Type type = paramSymbol.getSymbolType();
  5.1225 +                if (type.isUnknown()) {
  5.1226 +                    type = Type.OBJECT;
  5.1227 +                }
  5.1228 +                paramSpecializations.add(type);
  5.1229 +                if (!type.isObject()) {
  5.1230 +                    nonObjectParams = true;
  5.1231 +                }
  5.1232 +                newType(paramSymbol, Type.OBJECT);
  5.1233 +            }
  5.1234 +        }
  5.1235 +
  5.1236 +        if (!nonObjectParams) {
  5.1237 +            paramSpecializations = null;
  5.1238 +            // Later, when resolving a call to this method, the linker can say "I have a double, an int and an object" as parameters
  5.1239 +            // here. If the callee has parameter specializations, we can regenerate it with those particular types for speed.
  5.1240 +        } else {
  5.1241 +            LOG.info("parameter specialization possible: " + functionNode.getName() + " " + paramSpecializations);
  5.1242 +        }
  5.1243 +
  5.1244 +        // parameters should not be slots for a vararg function, make sure this is the case
  5.1245 +        if (functionNode.isVarArg()) {
  5.1246 +            for (final IdentNode param : functionNode.getParameters()) {
  5.1247 +                param.getSymbol().setNeedsSlot(false);
  5.1248 +            }
  5.1249 +        }
  5.1250 +    }
  5.1251 +
  5.1252 +    /**
  5.1253 +     * Move any properties from a global map into the scope of this method
  5.1254 +     * @param context      context
  5.1255 +     * @param functionNode the function node for which to init scope vars
  5.1256 +     */
  5.1257 +    private static void initFromPropertyMap(final Context context, final FunctionNode functionNode) {
  5.1258 +        // For a script, add scope symbols as defined in the property map
  5.1259 +        assert functionNode.isScript();
  5.1260 +
  5.1261 +        final PropertyMap map = Context.getGlobalMap();
  5.1262 +
  5.1263 +        for (final Property property : map.getProperties()) {
  5.1264 +            final String key    = property.getKey();
  5.1265 +            final Symbol symbol = functionNode.defineSymbol(key, IS_GLOBAL, null);
  5.1266 +            newType(symbol, Type.OBJECT);
  5.1267 +            LOG.info("Added global symbol from property map " + symbol);
  5.1268 +        }
  5.1269 +    }
  5.1270 +
  5.1271 +    private static void ensureTypeNotUnknown(final Node node) {
  5.1272 +
  5.1273 +        final Symbol symbol = node.getSymbol();
  5.1274 +
  5.1275 +        LOG.info("Ensure type not unknown for: " + symbol);
  5.1276 +
  5.1277 +        /*
  5.1278 +         * Note that not just unknowns, but params need to be blown
  5.1279 +         * up to objects, because we can have something like
  5.1280 +         *
  5.1281 +         * function f(a) {
  5.1282 +         *    var b = ~a; //b and a are inferred to be int
  5.1283 +         *    return b;
  5.1284 +         * }
  5.1285 +         *
  5.1286 +         * In this case, it would be correct to say that "if you have
  5.1287 +         * an int at the callsite, just pass it".
  5.1288 +         *
  5.1289 +         * However
  5.1290 +         *
  5.1291 +         * function f(a) {
  5.1292 +         *    var b = ~a;      //b and a are inferred to be int
  5.1293 +         *    return b == 17;  //b is still inferred to be int.
  5.1294 +         * }
  5.1295 +         *
  5.1296 +         * can be called with f("17") and if we assume that b is an
  5.1297 +         * int and don't blow it up to an object in the comparison, we
  5.1298 +         * are screwed. I hate JavaScript.
  5.1299 +         *
  5.1300 +         * This check has to be done for any operation that might take
  5.1301 +         * objects as parameters, for example +, but not *, which is known
  5.1302 +         * to coerce types into doubles
  5.1303 +         */
  5.1304 +        if (node.getType().isUnknown() || symbol.isParam()) {
  5.1305 +            newType(symbol, Type.OBJECT);
  5.1306 +            symbol.setCanBeUndefined();
  5.1307 +         }
  5.1308 +    }
  5.1309 +
  5.1310 +    private static Symbol pseudoSymbol(final String name) {
  5.1311 +        return new Symbol(name, 0, Type.OBJECT);
  5.1312 +    }
  5.1313 +
  5.1314 +    private Symbol exceptionSymbol() {
  5.1315 +        return newInternal(compiler.uniqueName(EXCEPTION_PREFIX.tag()), Type.typeFor(ECMAException.class));
  5.1316 +    }
  5.1317 +
  5.1318 +    /**
  5.1319 +     * In an assignment, recursively make sure that there are slots for
  5.1320 +     * everything that has to be laid out as temporary storage, which is the
  5.1321 +     * case if we are assign-op:ing a BaseNode subclass. This has to be
  5.1322 +     * recursive to handle things like multi dimensional arrays as lhs
  5.1323 +     *
  5.1324 +     * see NASHORN-258
  5.1325 +     *
  5.1326 +     * @param functionNode   the current function node (has to be passed as it changes in the visitor below)
  5.1327 +     * @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes
  5.1328 +     */
  5.1329 +    private static void ensureAssignmentSlots(final FunctionNode functionNode, final Node assignmentDest) {
  5.1330 +        assignmentDest.accept(new NodeVisitor() {
  5.1331 +            @Override
  5.1332 +            public Node leave(final IndexNode indexNode) {
  5.1333 +                final Node index = indexNode.getIndex();
  5.1334 +                index.getSymbol().setNeedsSlot(!index.getSymbol().isConstant());
  5.1335 +                return indexNode;
  5.1336 +            }
  5.1337 +        });
  5.1338 +    }
  5.1339 +
  5.1340 +    /**
  5.1341 +     * Return the type that arithmetic ops should use. Until we have implemented better type
  5.1342 +     * analysis (range based) or overflow checks that are fast enough for int arithmetic,
  5.1343 +     * this is the number type
  5.1344 +     * @return the arithetic type
  5.1345 +     */
  5.1346 +    private static Type arithType() {
  5.1347 +        return Compiler.shouldUseIntegerArithmetic() ? Type.INT : Type.NUMBER;
  5.1348 +    }
  5.1349 +
  5.1350 +    /**
  5.1351 +     * If types have changed, we can have failed to update vars. For example
  5.1352 +     *
  5.1353 +     * var x = 17; //x is int
  5.1354 +     * x = "apa";  //x is object. This will be converted fine
  5.1355 +     *
  5.1356 +     * @param functionNode
  5.1357 +     */
  5.1358 +    private static void finalizeTypes(final FunctionNode functionNode) {
  5.1359 +        final Set<Node> changed = new HashSet<>();
  5.1360 +        do {
  5.1361 +            changed.clear();
  5.1362 +            functionNode.accept(new NodeVisitor() {
  5.1363 +
  5.1364 +                private void widen(final Node node, final Type to) {
  5.1365 +                    if (node instanceof LiteralNode) {
  5.1366 +                        return;
  5.1367 +                    }
  5.1368 +                    Type from = node.getType();
  5.1369 +                    if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) {
  5.1370 +                        LOG.fine("Had to post pass widen '" + node + "' " + Debug.id(node) + " from " + node.getType() + " to " + to);
  5.1371 +                        newType(node.getSymbol(), to);
  5.1372 +                        changed.add(node);
  5.1373 +                    }
  5.1374 +                }
  5.1375 +
  5.1376 +                /**
  5.1377 +                 * Eg.
  5.1378 +                 *
  5.1379 +                 * var d = 17;
  5.1380 +                 * var e;
  5.1381 +                 * e = d; //initially typed as int for node type, should retype as double
  5.1382 +                 * e = object;
  5.1383 +                 *
  5.1384 +                 * var d = 17;
  5.1385 +                 * var e;
  5.1386 +                 * e -= d; //initially type number, should number remain with a final conversion supplied by Store. ugly, but the computation result of the sub is numeric
  5.1387 +                 * e = object;
  5.1388 +                 *
  5.1389 +                 */
  5.1390 +                @SuppressWarnings("fallthrough")
  5.1391 +                @Override
  5.1392 +                public Node leave(final BinaryNode binaryNode) {
  5.1393 +                    final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
  5.1394 +                    switch (binaryNode.tokenType()) {
  5.1395 +                    default:
  5.1396 +                        if (!binaryNode.isAssignment() || binaryNode.isSelfModifying()) {
  5.1397 +                            break;
  5.1398 +                        }
  5.1399 +                        widen(binaryNode.lhs(), widest);
  5.1400 +                    case ADD:
  5.1401 +                        widen(binaryNode, widest);
  5.1402 +                        break;
  5.1403 +                    }
  5.1404 +                    return binaryNode;
  5.1405 +                }
  5.1406 +            });
  5.1407 +        } while (!changed.isEmpty());
  5.1408 +    }
  5.1409 +
  5.1410 +    /**
  5.1411 +     * This assign helper is called after an assignment, when all children of
  5.1412 +     * the assign has been processed. It fixes the types and recursively makes
  5.1413 +     * sure that everyhing has slots that should have them in the chain.
  5.1414 +     *
  5.1415 +     * @param binaryNode assignment node
  5.1416 +     */
  5.1417 +    private Node leaveAssignmentNode(final BinaryNode binaryNode) {
  5.1418 +        final Node lhs = binaryNode.lhs();
  5.1419 +        final Node rhs = binaryNode.rhs();
  5.1420 +
  5.1421 +        final Type type;
  5.1422 +        if (rhs.getType().isNumeric()) {
  5.1423 +            type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
  5.1424 +        } else {
  5.1425 +            type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too.
  5.1426 +        }
  5.1427 +        newTemporary(type, binaryNode);
  5.1428 +        newType(lhs.getSymbol(), type);
  5.1429 +        end(binaryNode);
  5.1430 +        return binaryNode;
  5.1431 +    }
  5.1432 +
  5.1433 +    private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode) {
  5.1434 +        return leaveSelfModifyingAssignmentNode(binaryNode, binaryNode.getWidestOperationType());
  5.1435 +    }
  5.1436 +
  5.1437 +    private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode, final Type destType) {
  5.1438 +        //e.g. for -=, Number, no wider, destType (binaryNode.getWidestOperationType())  is the coerce type
  5.1439 +        final Node lhs = binaryNode.lhs();
  5.1440 +
  5.1441 +        newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType
  5.1442 +        newTemporary(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
  5.1443 +
  5.1444 +        ensureAssignmentSlots(getCurrentFunctionNode(), binaryNode);
  5.1445 +
  5.1446 +        end(binaryNode);
  5.1447 +        return binaryNode;
  5.1448 +    }
  5.1449 +
  5.1450 +    private static List<Block> findLookupBlocksHelper(final FunctionNode currentFunction, final FunctionNode topFunction) {
  5.1451 +        if (currentFunction.findParentFunction() == topFunction) {
  5.1452 +            final List<Block> blocks = new LinkedList<>();
  5.1453 +
  5.1454 +            blocks.add(currentFunction.getParent());
  5.1455 +            blocks.addAll(currentFunction.getReferencingParentBlocks());
  5.1456 +            return blocks;
  5.1457 +        }
  5.1458 +        /*
  5.1459 +         * assumption: all parent blocks of an inner function will always be in the same outer function;
  5.1460 +         * therefore we can simply skip through intermediate functions.
  5.1461 +         * @see FunctionNode#addReferencingParentBlock(Block)
  5.1462 +         */
  5.1463 +        return findLookupBlocksHelper(currentFunction.findParentFunction(), topFunction);
  5.1464 +    }
  5.1465 +
  5.1466 +    private static boolean isFunctionExpressionSelfReference(final Symbol symbol) {
  5.1467 +        if (symbol.isVar() && symbol.getNode() == symbol.getBlock() && symbol.getNode() instanceof FunctionNode) {
  5.1468 +            return ((FunctionNode)symbol.getNode()).getIdent().getName().equals(symbol.getName());
  5.1469 +        }
  5.1470 +        return false;
  5.1471 +    }
  5.1472 +
  5.1473 +    private static Symbol newTemporary(final FunctionNode functionNode, final Type type, final Node node) {
  5.1474 +        LOG.info("New TEMPORARY added to " + functionNode.getName() + " type=" + type);
  5.1475 +        return functionNode.newTemporary(type, node);
  5.1476 +    }
  5.1477 +
  5.1478 +    private Symbol newTemporary(final Type type, final Node node) {
  5.1479 +        return newTemporary(getCurrentFunctionNode(), type, node);
  5.1480 +    }
  5.1481 +
  5.1482 +    private Symbol newInternal(final FunctionNode functionNode, final String name, final Type type) {
  5.1483 +        final Symbol iter = getCurrentFunctionNode().defineSymbol(name, IS_VAR | IS_INTERNAL, null);
  5.1484 +        iter.setType(type); // NASHORN-73
  5.1485 +        return iter;
  5.1486 +    }
  5.1487 +
  5.1488 +    private Symbol newInternal(final String name, final Type type) {
  5.1489 +        return newInternal(getCurrentFunctionNode(), name, type);
  5.1490 +    }
  5.1491 +
  5.1492 +    private static void newType(final Symbol symbol, final Type type) {
  5.1493 +        final Type oldType = symbol.getSymbolType();
  5.1494 +        symbol.setType(type);
  5.1495 +
  5.1496 +        if (symbol.getSymbolType() != oldType) {
  5.1497 +            LOG.info("New TYPE " + type + " for " + symbol + " (was " + oldType + ")");
  5.1498 +        }
  5.1499 +
  5.1500 +        if (symbol.isParam()) {
  5.1501 +            symbol.setType(type);
  5.1502 +            LOG.info("Param type change " + symbol);
  5.1503 +        }
  5.1504 +    }
  5.1505 +
  5.1506 +    private void clearLocalDefs() {
  5.1507 +        localDefs = new HashSet<>();
  5.1508 +    }
  5.1509 +
  5.1510 +    private boolean isLocalDef(final String name) {
  5.1511 +        return localDefs.contains(name);
  5.1512 +    }
  5.1513 +
  5.1514 +    private void addLocalDef(final String name) {
  5.1515 +        LOG.info("Adding local def of symbol: '" + name + "'");
  5.1516 +        localDefs.add(name);
  5.1517 +    }
  5.1518 +
  5.1519 +    private void removeLocalDef(final String name) {
  5.1520 +        LOG.info("Removing local def of symbol: '" + name + "'");
  5.1521 +        localDefs.remove(name);
  5.1522 +    }
  5.1523 +
  5.1524 +    private void clearLocalUses() {
  5.1525 +        localUses = new HashSet<>();
  5.1526 +    }
  5.1527 +
  5.1528 +    private void addLocalUse(final String name) {
  5.1529 +        LOG.info("Adding local use of symbol: '" + name + "'");
  5.1530 +        localUses.add(name);
  5.1531 +    }
  5.1532 +
  5.1533 +    private static String name(final Node node) {
  5.1534 +        final String cn = node.getClass().getName();
  5.1535 +        int lastDot = cn.lastIndexOf('.');
  5.1536 +        if (lastDot == -1) {
  5.1537 +            return cn;
  5.1538 +        }
  5.1539 +        return cn.substring(lastDot + 1);
  5.1540 +    }
  5.1541 +
  5.1542 +    private Node start(final Node node) {
  5.1543 +        return start(node, true);
  5.1544 +    }
  5.1545 +
  5.1546 +    private Node start(final Node node, final boolean printNode) {
  5.1547 +        final StringBuilder sb = new StringBuilder();
  5.1548 +
  5.1549 +        sb.append("[ENTER ").
  5.1550 +            append(name(node)).
  5.1551 +            append("] ").
  5.1552 +            append(printNode ? node.toString() : "").
  5.1553 +            append(" in '").
  5.1554 +            append(getCurrentFunctionNode().getName()).
  5.1555 +            append("'");
  5.1556 +        LOG.info(sb.toString());
  5.1557 +        LOG.indent();
  5.1558 +
  5.1559 +        return node;
  5.1560 +    }
  5.1561 +
  5.1562 +    private Node end(final Node node) {
  5.1563 +        return end(node, true);
  5.1564 +    }
  5.1565 +
  5.1566 +    private Node end(final Node node, final boolean printNode) {
  5.1567 +        final StringBuilder sb = new StringBuilder();
  5.1568 +
  5.1569 +        sb.append("[LEAVE ").
  5.1570 +            append(name(node)).
  5.1571 +            append("] ").
  5.1572 +            append(printNode ? node.toString() : "").
  5.1573 +            append(" in '").
  5.1574 +            append(getCurrentFunctionNode().getName());
  5.1575 +
  5.1576 +        if (node.getSymbol() == null) {
  5.1577 +            sb.append(" <NO SYMBOL>");
  5.1578 +        } else {
  5.1579 +            sb.append(" <symbol=").append(node.getSymbol()).append('>');
  5.1580 +        }
  5.1581 +
  5.1582 +        LOG.unindent();
  5.1583 +        LOG.info(sb.toString());
  5.1584 +
  5.1585 +        return node;
  5.1586 +    }
  5.1587 +}
     6.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue Jan 29 14:25:39 2013 -0400
     6.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Jan 30 12:26:45 2013 +0100
     6.3 @@ -56,7 +56,6 @@
     6.4  import java.util.LinkedList;
     6.5  import java.util.List;
     6.6  import java.util.Map;
     6.7 -import java.util.Map.Entry;
     6.8  import java.util.TreeMap;
     6.9  import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
    6.10  import jdk.nashorn.internal.codegen.CompilerConstants.Call;
    6.11 @@ -524,28 +523,6 @@
    6.12          return method;
    6.13      }
    6.14  
    6.15 -    /**
    6.16 -     * Create a new function object, including generating its stub code.
    6.17 -     *
    6.18 -     * @param functionNode  FunctionNode to utilize.
    6.19 -     */
    6.20 -    private void newFunctionObject(final FunctionNode functionNode) {
    6.21 -         // Turn thisProperties into keys and symbols for the FunctionAnalyzer
    6.22 -        final Map<String, Node> thisProperties = functionNode.getThisProperties();
    6.23 -
    6.24 -        final List<String> keys    = new ArrayList<>();
    6.25 -        final List<Symbol> symbols = new ArrayList<>();
    6.26 -
    6.27 -        /* TODO - Predefine known properties.
    6.28 -        for (final Entry<String, Node> entry : thisProperties.entrySet()) {
    6.29 -            keys.add(entry.getKey());
    6.30 -            symbols.add(entry.getValue().getSymbol());
    6.31 -        }
    6.32 -        */
    6.33 -
    6.34 -        new FunctionObjectCreator(this, functionNode, keys, symbols).makeObject(method);
    6.35 -    }
    6.36 -
    6.37      @Override
    6.38      public Node enter(final CallNode callNode) {
    6.39          if (callNode.testResolved()) {
    6.40 @@ -603,12 +580,12 @@
    6.41  
    6.42                  final CallNode.EvalArgs evalArgs = callNode.getEvalArgs();
    6.43                  // load evaluated code
    6.44 -                load(evalArgs.code);
    6.45 +                load(evalArgs.getCode());
    6.46                  method.convert(Type.OBJECT);
    6.47                  // special/extra 'eval' arguments
    6.48 -                load(evalArgs.evalThis);
    6.49 -                method.load(evalArgs.location);
    6.50 -                method.load(evalArgs.strictMode);
    6.51 +                load(evalArgs.getThis());
    6.52 +                method.load(evalArgs.getLocation());
    6.53 +                method.load(evalArgs.getStrictMode());
    6.54                  method.convert(Type.OBJECT);
    6.55  
    6.56                  // direct call to Global.directEval
    6.57 @@ -683,7 +660,7 @@
    6.58                  }
    6.59  
    6.60                  if (callee.needsCallee()) { // TODO: always true
    6.61 -                    newFunctionObject(callee); // TODO: if callee not needed, function object is used only to pass scope (could be optimized). if neither the scope nor the function object is needed by the callee, we can pass null instead.
    6.62 +                    new FunctionObjectCreator(CodeGenerator.this, callee).makeObject(method); // TODO: if callee not needed, function object is used only to pass scope (could be optimized). if neither the scope nor the function object is needed by the callee, we can pass null instead.
    6.63                  }
    6.64  
    6.65                  loadArgs(args, signature, isVarArg, argCount);
    6.66 @@ -1300,6 +1277,7 @@
    6.67      @SuppressWarnings("rawtypes")
    6.68      @Override
    6.69      public Node enter(final LiteralNode literalNode) {
    6.70 +        assert literalNode.getSymbol() != null : literalNode + " has no symbol";
    6.71          load(literalNode).store(literalNode.getSymbol());
    6.72          return null;
    6.73      }
    6.74 @@ -1410,7 +1388,7 @@
    6.75              return null;
    6.76          }
    6.77  
    6.78 -        newFunctionObject(referenceNode.getReference());
    6.79 +        new FunctionObjectCreator(this, referenceNode.getReference()).makeObject(method);
    6.80  
    6.81          return null;
    6.82      }
    6.83 @@ -1561,15 +1539,12 @@
    6.84          /*
    6.85           * First check if this should be something other than a runtime node
    6.86           * AccessSpecializer might have changed the type
    6.87 +         *
    6.88 +         * TODO - remove this - Access Specializer will always know after Attr/Lower
    6.89           */
    6.90 -        if (runtimeNode.isPrimitive()) {
    6.91 -
    6.92 +        if (runtimeNode.isPrimitive() && !runtimeNode.isFinal()) {
    6.93              final Node lhs = runtimeNode.getArgs().get(0);
    6.94 -            Node rhs = null;
    6.95 -
    6.96 -            if (runtimeNode.getArgs().size() > 1) {
    6.97 -                rhs = runtimeNode.getArgs().get(1);
    6.98 -            }
    6.99 +            final Node rhs = runtimeNode.getArgs().size() > 1 ? runtimeNode.getArgs().get(1) : null;
   6.100  
   6.101              final Type   type   = runtimeNode.getType();
   6.102              final Symbol symbol = runtimeNode.getSymbol();
   6.103 @@ -1590,7 +1565,15 @@
   6.104              case GT:
   6.105                  return enterCmp(lhs, rhs, Condition.GT, type, symbol);
   6.106              case ADD:
   6.107 -                return enterNumericAdd(lhs, rhs, type, symbol);
   6.108 +                Type widest = Type.widest(lhs.getType(), rhs.getType());
   6.109 +                load(lhs);
   6.110 +                method.convert(widest);
   6.111 +                load(rhs);
   6.112 +                method.convert(widest);
   6.113 +                method.add();
   6.114 +                method.convert(type);
   6.115 +                method.store(symbol);
   6.116 +                return null;
   6.117              default:
   6.118                  // it's ok to send this one on with only primitive arguments, maybe INSTANCEOF(true, true) or similar
   6.119                  // assert false : runtimeNode + " has all primitive arguments. This is an inconsistent state";
   6.120 @@ -1605,7 +1588,7 @@
   6.121              return null;
   6.122          }
   6.123  
   6.124 -        if (specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) {
   6.125 +        if (!runtimeNode.isFinal() && specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) {
   6.126              return null;
   6.127          }
   6.128  
   6.129 @@ -2029,7 +2012,6 @@
   6.130          if (needsScope) {
   6.131              method.loadScope();
   6.132          }
   6.133 -
   6.134          load(init);
   6.135  
   6.136          if (needsScope) {
   6.137 @@ -2324,12 +2306,11 @@
   6.138      }
   6.139  
   6.140      private Node enterNumericAdd(final Node lhs, final Node rhs, final Type type, final Symbol symbol) {
   6.141 -        assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type);
   6.142 +        assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs);
   6.143          load(lhs);
   6.144          load(rhs);
   6.145          method.add();
   6.146          method.store(symbol);
   6.147 -
   6.148          return null;
   6.149      }
   6.150  
   6.151 @@ -3152,17 +3133,19 @@
   6.152              /**
   6.153               * Take the original target args from the stack and use them
   6.154               * together with the value to be stored to emit the store code
   6.155 +             *
   6.156 +             * The case that targetSymbol is in scope (!hasSlot) and we actually
   6.157 +             * need to do a conversion on non-equivalent types exists, but is
   6.158 +             * very rare. See for example test/script/basic/access-specializer.js
   6.159               */
   6.160 -            if (targetSymbol.hasSlot()) {
   6.161 -                method.convert(target.getType());
   6.162 -            }
   6.163 +            method.convert(target.getType());
   6.164  
   6.165              target.accept(new NodeVisitor(compileUnit, method) {
   6.166                  @Override
   6.167                  public Node enter(final IdentNode node) {
   6.168                      final Symbol symbol = target.getSymbol();
   6.169                      if (symbol.isScope()) {
   6.170 -                        if(symbol.isFastScope(currentFunction)) {
   6.171 +                        if (symbol.isFastScope(currentFunction)) {
   6.172                              storeFastScopeVar(target.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags());
   6.173                          } else {
   6.174                              method.dynamicSet(target.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags());
     7.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java	Tue Jan 29 14:25:39 2013 -0400
     7.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Wed Jan 30 12:26:45 2013 +0100
     7.3 @@ -70,8 +70,16 @@
     7.4          INITIALIZED,
     7.5          /** method has been parsed */
     7.6          PARSED,
     7.7 +        /** constant folding pass */
     7.8 +        CONSTANT_FOLDED,
     7.9          /** method has been lowered */
    7.10          LOWERED,
    7.11 +        /** method hass been attributed */
    7.12 +        ATTR,
    7.13 +        /** method has been split */
    7.14 +        SPLIT,
    7.15 +        /** method has had its types finalized */
    7.16 +        FINALIZED,
    7.17          /** method has been emitted to bytecode */
    7.18          EMITTED
    7.19      }
    7.20 @@ -136,25 +144,6 @@
    7.21      private static final boolean LAZY_JIT = false;
    7.22  
    7.23      /**
    7.24 -     * Should we use integers for literals and all operations
    7.25 -     * that are based in constant and parameter assignment as
    7.26 -     * long as they can be proven not to overflow? With this enabled
    7.27 -     * var x = 17 would tag x as an integer, rather than a double,
    7.28 -     * but as soon as it is used in an operation that may potentially
    7.29 -     * overflow, such as an add, we conservatively widen it to double
    7.30 -     * (number type). This is because overflow checks in the code
    7.31 -     * are likely much more expensive that method specialization
    7.32 -     *
    7.33 -     * @return true if numbers should start as ints, false if they should
    7.34 -     *   start as doubles
    7.35 -     */
    7.36 -    static boolean shouldUseIntegers() {
    7.37 -        return USE_INTS;
    7.38 -    }
    7.39 -
    7.40 -    private static final boolean USE_INTS;
    7.41 -
    7.42 -    /**
    7.43       * Should we use integers for arithmetic operations as well?
    7.44       * TODO: We currently generate no overflow checks so this is
    7.45       * disabled
    7.46 @@ -165,13 +154,12 @@
    7.47       *   operands by default.
    7.48       */
    7.49      static boolean shouldUseIntegerArithmetic() {
    7.50 -        return Compiler.shouldUseIntegers() && USE_INT_ARITH;
    7.51 +        return USE_INT_ARITH;
    7.52      }
    7.53  
    7.54      private static final boolean USE_INT_ARITH;
    7.55  
    7.56      static {
    7.57 -        USE_INTS       = !Options.getBooleanProperty("nashorn.compiler.ints.disable");
    7.58          USE_INT_ARITH  =  Options.getBooleanProperty("nashorn.compiler.intarithmetic");
    7.59  
    7.60          assert !USE_INT_ARITH : "Integer arithmetic is not enabled";
    7.61 @@ -338,46 +326,93 @@
    7.62          try {
    7.63              strict |= functionNode.isStrictMode();
    7.64  
    7.65 -            if (!state.contains(State.LOWERED)) {
    7.66 -                debugPrintAST();
    7.67 +            /*
    7.68 +             * These are the compile phases:
    7.69 +             *
    7.70 +             * Constant folding pass
    7.71 +             *   Simple constant folding that will make elementary constructs go away
    7.72 +             *
    7.73 +             * Lower (Control flow pass)
    7.74 +             *   Finalizes the control flow. Clones blocks for finally constructs and
    7.75 +             *   similar things. Establishes termination criteria for nodes
    7.76 +             *   Guarantee return instructions to method making sure control flow
    7.77 +             *   cannot fall off the end. Replacing high level nodes with lower such
    7.78 +             *   as runtime nodes where applicable.
    7.79 +             *
    7.80 +             * Attr
    7.81 +             *   Assign symbols and types to all nodes.
    7.82 +             *
    7.83 +             * Splitter
    7.84 +             *   Split the AST into several compile units based on a size heuristic
    7.85 +             *   Splitter needs attributed AST for weight calculations (e.g. is
    7.86 +             *   a + b a ScriptRuntime.ADD with call overhead or a dadd with much
    7.87 +             *   less). Split IR can lead to scope information being changed.
    7.88 +             *
    7.89 +             * Contract: all variables must have slot assignments and scope assignments
    7.90 +             * before lowering.
    7.91 +             *
    7.92 +             * FinalizeTypes
    7.93 +             *   This pass finalizes the types for nodes. If Attr created wider types than
    7.94 +             *   known during the first pass, convert nodes are inserted or access nodes
    7.95 +             *   are specialized where scope accesses.
    7.96 +             *
    7.97 +             *   Runtime nodes may be removed and primitivized or reintroduced depending
    7.98 +             *   on information that was established in Attr.
    7.99 +             *
   7.100 +             * CodeGeneration
   7.101 +             *   Emit bytecode
   7.102 +             *
   7.103 +             */
   7.104 +
   7.105 +            debugPrintAST();
   7.106 +
   7.107 +            if (!state.contains(State.FINALIZED)) {
   7.108 +                LOG.info("Folding constants in '" + functionNode.getName() + "'");
   7.109 +                functionNode.accept(new FoldConstants());
   7.110 +                state.add(State.CONSTANT_FOLDED);
   7.111 +
   7.112                  LOG.info("Lowering '" + functionNode.getName() + "'");
   7.113                  functionNode.accept(new Lower(this));
   7.114                  state.add(State.LOWERED);
   7.115  
   7.116 +                LOG.info("Attributing types '" + functionNode.getName() + "'");
   7.117 +                functionNode.accept(new Attr(this));
   7.118 +                state.add(State.ATTR);
   7.119 +
   7.120 +                this.scriptName = computeNames();
   7.121 +
   7.122 +                // Main script code always goes to this compile unit. Note that since we start this with zero weight
   7.123 +                // and add script code last this class may end up slightly larger than others, but reserving one class
   7.124 +                // just for the main script seems wasteful.
   7.125 +                final CompileUnit scriptCompileUnit = addCompileUnit(firstCompileUnitName(), 0L);
   7.126 +                LOG.info("Splitting '" + functionNode.getName() + "'");
   7.127 +                new Splitter(this, functionNode, scriptCompileUnit).split();
   7.128 +                state.add(State.SPLIT);
   7.129 +                assert functionNode.getCompileUnit() == scriptCompileUnit;
   7.130 +
   7.131 +                assert strict == functionNode.isStrictMode() : "strict == " + strict + " but functionNode == " + functionNode.isStrictMode();
   7.132 +                if (functionNode.isStrictMode()) {
   7.133 +                    strict = true;
   7.134 +                }
   7.135 +
   7.136 +                LOG.info("Finalizing types for '" + functionNode.getName() + "'");
   7.137 +                functionNode.accept(new FinalizeTypes(this));
   7.138 +                state.add(State.FINALIZED);
   7.139 +
   7.140 +                // print ast and parse if --print-lower-ast and/or --print-lower-parse are selected
   7.141 +                debugPrintAST();
   7.142 +                debugPrintParse();
   7.143 +
   7.144                  if (errors.hasErrors()) {
   7.145                      return false;
   7.146                  }
   7.147              }
   7.148  
   7.149 -            scriptName = computeNames();
   7.150 -
   7.151 -            // Main script code always goes to this compile unit. Note that since we start this with zero weight
   7.152 -            // and add script code last this class may end up slightly larger than others, but reserving one class
   7.153 -            // just for the main script seems wasteful.
   7.154 -            final CompileUnit scriptCompileUnit = addCompileUnit(firstCompileUnitName(), 0l);
   7.155 -            LOG.info("Splitting '" + functionNode.getName() + "'");
   7.156 -            new Splitter(this, functionNode, scriptCompileUnit).split();
   7.157 -            assert functionNode.getCompileUnit() == scriptCompileUnit;
   7.158 -
   7.159 -            /** Compute compile units */
   7.160 -            assert strict == functionNode.isStrictMode() : "strict == " + strict + " but functionNode == " + functionNode.isStrictMode();
   7.161 -            if (functionNode.isStrictMode()) {
   7.162 -                strict = true;
   7.163 -            }
   7.164 -
   7.165 -            LOG.info("Adjusting slot and scope information for symbols for '" + functionNode.getName() + "'");
   7.166 -            functionNode.accept(new Lower.FinalizeSymbols());
   7.167 -
   7.168 -            LOG.info("Specializing callsite types for '" + functionNode.getName() + "'");
   7.169 -            functionNode.accept(new AccessSpecializer());
   7.170 -
   7.171              try {
   7.172                  LOG.info("Emitting bytecode for '" + functionNode.getName() + "'");
   7.173                  final CodeGenerator codegen = new CodeGenerator(this);
   7.174                  functionNode.accept(codegen);
   7.175                  codegen.generateScopeCalls();
   7.176 -                debugPrintAST();
   7.177 -                debugPrintParse();
   7.178              } catch (final VerifyError e) {
   7.179                  if (context._verify_code || context._print_code) {
   7.180                      context.getErr().println(e.getClass().getSimpleName() + ": " + e.getMessage());
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Wed Jan 30 12:26:45 2013 +0100
     8.3 @@ -0,0 +1,919 @@
     8.4 +/*
     8.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     8.7 + *
     8.8 + * This code is free software; you can redistribute it and/or modify it
     8.9 + * under the terms of the GNU General Public License version 2 only, as
    8.10 + * published by the Free Software Foundation.  Oracle designates this
    8.11 + * particular file as subject to the "Classpath" exception as provided
    8.12 + * by Oracle in the LICENSE file that accompanied this code.
    8.13 + *
    8.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    8.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    8.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    8.17 + * version 2 for more details (a copy is included in the LICENSE file that
    8.18 + * accompanied this code).
    8.19 + *
    8.20 + * You should have received a copy of the GNU General Public License version
    8.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    8.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    8.23 + *
    8.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    8.25 + * or visit www.oracle.com if you need additional information or have any
    8.26 + * questions.
    8.27 + */
    8.28 +
    8.29 +package jdk.nashorn.internal.codegen;
    8.30 +
    8.31 +import java.util.HashSet;
    8.32 +import java.util.List;
    8.33 +
    8.34 +import jdk.nashorn.internal.codegen.types.Type;
    8.35 +import jdk.nashorn.internal.ir.AccessNode;
    8.36 +import jdk.nashorn.internal.ir.Assignment;
    8.37 +import jdk.nashorn.internal.ir.BinaryNode;
    8.38 +import jdk.nashorn.internal.ir.Block;
    8.39 +import jdk.nashorn.internal.ir.CallNode;
    8.40 +import jdk.nashorn.internal.ir.CallNode.EvalArgs;
    8.41 +import jdk.nashorn.internal.ir.CaseNode;
    8.42 +import jdk.nashorn.internal.ir.CatchNode;
    8.43 +import jdk.nashorn.internal.ir.DoWhileNode;
    8.44 +import jdk.nashorn.internal.ir.ExecuteNode;
    8.45 +import jdk.nashorn.internal.ir.ForNode;
    8.46 +import jdk.nashorn.internal.ir.FunctionNode;
    8.47 +import jdk.nashorn.internal.ir.IdentNode;
    8.48 +import jdk.nashorn.internal.ir.IfNode;
    8.49 +import jdk.nashorn.internal.ir.IndexNode;
    8.50 +import jdk.nashorn.internal.ir.LiteralNode;
    8.51 +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
    8.52 +import jdk.nashorn.internal.ir.Node;
    8.53 +import jdk.nashorn.internal.ir.ReferenceNode;
    8.54 +import jdk.nashorn.internal.ir.ReturnNode;
    8.55 +import jdk.nashorn.internal.ir.RuntimeNode;
    8.56 +import jdk.nashorn.internal.ir.RuntimeNode.Request;
    8.57 +import jdk.nashorn.internal.ir.SwitchNode;
    8.58 +import jdk.nashorn.internal.ir.Symbol;
    8.59 +import jdk.nashorn.internal.ir.TernaryNode;
    8.60 +import jdk.nashorn.internal.ir.ThrowNode;
    8.61 +import jdk.nashorn.internal.ir.TypeOverride;
    8.62 +import jdk.nashorn.internal.ir.UnaryNode;
    8.63 +import jdk.nashorn.internal.ir.VarNode;
    8.64 +import jdk.nashorn.internal.ir.WhileNode;
    8.65 +import jdk.nashorn.internal.ir.WithNode;
    8.66 +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
    8.67 +import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    8.68 +import jdk.nashorn.internal.parser.Token;
    8.69 +import jdk.nashorn.internal.parser.TokenType;
    8.70 +import jdk.nashorn.internal.runtime.Debug;
    8.71 +import jdk.nashorn.internal.runtime.DebugLogger;
    8.72 +import jdk.nashorn.internal.runtime.JSType;
    8.73 +import jdk.nashorn.internal.runtime.Source;
    8.74 +
    8.75 +/**
    8.76 + * Lower to more primitive operations. After lowering, an AST has symbols and
    8.77 + * types. Lowering may also add specialized versions of methods to the script if
    8.78 + * the optimizer is turned on.
    8.79 + *
    8.80 + * Any expression that requires temporary storage as part of computation will
    8.81 + * also be detected here and give a temporary symbol
    8.82 + *
    8.83 + * For any op that we process in FinalizeTypes it is an absolute guarantee
    8.84 + * that scope and slot information is correct. This enables e.g. AccessSpecialization
    8.85 + * and frame optimizations
    8.86 + */
    8.87 +
    8.88 +final class FinalizeTypes extends NodeOperatorVisitor {
    8.89 +
    8.90 +    /** Current source. */
    8.91 +    private final Source source;
    8.92 +
    8.93 +    private static final DebugLogger LOG = new DebugLogger("finalize");
    8.94 +
    8.95 +    /**
    8.96 +     * Constructor.
    8.97 +     *
    8.98 +     * @param compiler the compiler
    8.99 +     */
   8.100 +    FinalizeTypes(final Compiler compiler) {
   8.101 +        this.source = compiler.getSource();
   8.102 +    }
   8.103 +
   8.104 +    @Override
   8.105 +    public Node leave(final CallNode callNode) {
   8.106 +        final EvalArgs evalArgs = callNode.getEvalArgs();
   8.107 +        if (evalArgs != null) {
   8.108 +            evalArgs.setCode(evalArgs.getCode().accept(this));
   8.109 +        }
   8.110 +
   8.111 +        // AccessSpecializer - call return type may change the access for this location
   8.112 +        final Node function = callNode.getFunction();
   8.113 +        if (function instanceof ReferenceNode) {
   8.114 +            setTypeOverride(callNode, ((ReferenceNode)function).getReference().getType());
   8.115 +        }
   8.116 +        return callNode;
   8.117 +    }
   8.118 +
   8.119 +    private Node leaveUnary(final UnaryNode unaryNode) {
   8.120 +        unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType()));
   8.121 +        return unaryNode;
   8.122 +    }
   8.123 +
   8.124 +    @Override
   8.125 +    public Node leaveADD(final UnaryNode unaryNode) {
   8.126 +        return leaveUnary(unaryNode);
   8.127 +    }
   8.128 +
   8.129 +    @Override
   8.130 +    public Node leaveBIT_NOT(final UnaryNode unaryNode) {
   8.131 +        return leaveUnary(unaryNode);
   8.132 +    }
   8.133 +
   8.134 +    @Override
   8.135 +    public Node leaveCONVERT(final UnaryNode unaryNode) {
   8.136 +        assert unaryNode.rhs().tokenType() != TokenType.CONVERT : "convert(convert encountered. check its origin and remove it";
   8.137 +        return unaryNode;
   8.138 +    }
   8.139 +
   8.140 +    @Override
   8.141 +    public Node leaveDECINC(final UnaryNode unaryNode) {
   8.142 +        specialize(unaryNode);
   8.143 +        return unaryNode;
   8.144 +    }
   8.145 +
   8.146 +    @Override
   8.147 +    public Node leaveNEW(final UnaryNode unaryNode) {
   8.148 +        assert unaryNode.getSymbol() != null && unaryNode.getSymbol().getSymbolType().isObject();
   8.149 +        ((CallNode)unaryNode.rhs()).setIsNew();
   8.150 +        return unaryNode;
   8.151 +    }
   8.152 +
   8.153 +    @Override
   8.154 +    public Node leaveSUB(final UnaryNode unaryNode) {
   8.155 +        return leaveUnary(unaryNode);
   8.156 +    }
   8.157 +
   8.158 +    /**
   8.159 +     * Add is a special binary, as it works not only on arithmetic, but for
   8.160 +     * strings etc as well.
   8.161 +     */
   8.162 +    @Override
   8.163 +    public Node leaveADD(final BinaryNode binaryNode) {
   8.164 +        final Node lhs = binaryNode.lhs();
   8.165 +        final Node rhs = binaryNode.rhs();
   8.166 +
   8.167 +        final Type type = binaryNode.getType();
   8.168 +
   8.169 +        if (type.isObject()) {
   8.170 +            if (!isAddString(binaryNode)) {
   8.171 +                return new RuntimeNode(binaryNode, Request.ADD);
   8.172 +            }
   8.173 +        }
   8.174 +
   8.175 +        binaryNode.setLHS(convert(lhs, type));
   8.176 +        binaryNode.setRHS(convert(rhs, type));
   8.177 +        return binaryNode;
   8.178 +    }
   8.179 +
   8.180 +    @Override
   8.181 +    public Node leaveAND(final BinaryNode binaryNode) {
   8.182 +        return binaryNode;
   8.183 +    }
   8.184 +
   8.185 +    @Override
   8.186 +    public Node leaveASSIGN(final BinaryNode binaryNode) {
   8.187 +        Type destType = specialize(binaryNode);
   8.188 +        if (destType == null) {
   8.189 +            destType = binaryNode.getType();
   8.190 +        }
   8.191 +        binaryNode.setRHS(convert(binaryNode.rhs(), destType));
   8.192 +        return binaryNode;
   8.193 +    }
   8.194 +
   8.195 +    @Override
   8.196 +    public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
   8.197 +        return leaveASSIGN(binaryNode);
   8.198 +    }
   8.199 +
   8.200 +    @Override
   8.201 +    public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) {
   8.202 +        return leaveASSIGN(binaryNode);
   8.203 +    }
   8.204 +
   8.205 +    @Override
   8.206 +    public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) {
   8.207 +        return leaveASSIGN(binaryNode);
   8.208 +    }
   8.209 +
   8.210 +    @Override
   8.211 +    public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) {
   8.212 +        return leaveASSIGN(binaryNode);
   8.213 +    }
   8.214 +
   8.215 +    @Override
   8.216 +    public Node leaveASSIGN_DIV(final BinaryNode binaryNode) {
   8.217 +        return leaveASSIGN(binaryNode);
   8.218 +    }
   8.219 +
   8.220 +    @Override
   8.221 +    public Node leaveASSIGN_MOD(final BinaryNode binaryNode) {
   8.222 +        return leaveASSIGN(binaryNode);
   8.223 +    }
   8.224 +
   8.225 +    @Override
   8.226 +    public Node leaveASSIGN_MUL(final BinaryNode binaryNode) {
   8.227 +        return leaveASSIGN(binaryNode);
   8.228 +    }
   8.229 +
   8.230 +    @Override
   8.231 +    public Node leaveASSIGN_SAR(final BinaryNode binaryNode) {
   8.232 +        return leaveASSIGN(binaryNode);
   8.233 +    }
   8.234 +
   8.235 +    @Override
   8.236 +    public Node leaveASSIGN_SHL(final BinaryNode binaryNode) {
   8.237 +        return leaveASSIGN(binaryNode);
   8.238 +    }
   8.239 +
   8.240 +    @Override
   8.241 +    public Node leaveASSIGN_SHR(final BinaryNode binaryNode) {
   8.242 +        return leaveASSIGN(binaryNode);
   8.243 +    }
   8.244 +
   8.245 +    @Override
   8.246 +    public Node leaveASSIGN_SUB(final BinaryNode binaryNode) {
   8.247 +        return leaveASSIGN(binaryNode);
   8.248 +    }
   8.249 +
   8.250 +    @Override
   8.251 +    public Node leaveBIT_AND(BinaryNode binaryNode) {
   8.252 +        assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : binaryNode.getSymbol();
   8.253 +        return leaveBinary(binaryNode, Type.INT, Type.INT);
   8.254 +    }
   8.255 +
   8.256 +    @Override
   8.257 +    public Node leaveBIT_OR(BinaryNode binaryNode) {
   8.258 +        assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger();
   8.259 +        return leaveBinary(binaryNode, Type.INT, Type.INT);
   8.260 +    }
   8.261 +
   8.262 +    @Override
   8.263 +    public Node leaveBIT_XOR(BinaryNode binaryNode) {
   8.264 +        assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger();
   8.265 +        return leaveBinary(binaryNode, Type.INT, Type.INT);
   8.266 +    }
   8.267 +
   8.268 +    @Override
   8.269 +    public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
   8.270 +        assert binaryNode.getSymbol() != null;
   8.271 +        binaryNode.setRHS(discard(binaryNode.rhs()));
   8.272 +        // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed
   8.273 +        // in that case, update the node type as well
   8.274 +        propagateType(binaryNode, binaryNode.lhs().getType());
   8.275 +        return binaryNode;
   8.276 +    }
   8.277 +
   8.278 +    @Override
   8.279 +    public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
   8.280 +        assert binaryNode.getSymbol() != null;
   8.281 +        binaryNode.setLHS(discard(binaryNode.lhs()));
   8.282 +        // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed
   8.283 +        // in that case, update the node type as well
   8.284 +        propagateType(binaryNode, binaryNode.rhs().getType());
   8.285 +        return binaryNode;
   8.286 +    }
   8.287 +
   8.288 +    @Override
   8.289 +    public Node leaveDIV(final BinaryNode binaryNode) {
   8.290 +        return leaveBinaryArith(binaryNode);
   8.291 +    }
   8.292 +
   8.293 +
   8.294 +    @Override
   8.295 +    public Node leaveEQ(final BinaryNode binaryNode) {
   8.296 +        return leaveCmp(binaryNode, Request.EQ);
   8.297 +    }
   8.298 +
   8.299 +    @Override
   8.300 +    public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
   8.301 +        return leaveCmp(binaryNode, Request.EQ_STRICT);
   8.302 +    }
   8.303 +
   8.304 +    @Override
   8.305 +    public Node leaveGE(final BinaryNode binaryNode) {
   8.306 +        return leaveCmp(binaryNode, Request.GE);
   8.307 +    }
   8.308 +
   8.309 +    @Override
   8.310 +    public Node leaveGT(final BinaryNode binaryNode) {
   8.311 +        return leaveCmp(binaryNode, Request.GT);
   8.312 +    }
   8.313 +
   8.314 +    @Override
   8.315 +    public Node leaveLE(final BinaryNode binaryNode) {
   8.316 +        return leaveCmp(binaryNode, Request.LE);
   8.317 +    }
   8.318 +
   8.319 +    @Override
   8.320 +    public Node leaveLT(final BinaryNode binaryNode) {
   8.321 +        return leaveCmp(binaryNode, Request.LT);
   8.322 +    }
   8.323 +
   8.324 +    @Override
   8.325 +    public Node leaveMOD(final BinaryNode binaryNode) {
   8.326 +        return leaveBinaryArith(binaryNode);
   8.327 +    }
   8.328 +
   8.329 +    @Override
   8.330 +    public Node leaveMUL(final BinaryNode binaryNode) {
   8.331 +        return leaveBinaryArith(binaryNode);
   8.332 +    }
   8.333 +
   8.334 +    @Override
   8.335 +    public Node leaveNE(final BinaryNode binaryNode) {
   8.336 +        return leaveCmp(binaryNode, Request.NE);
   8.337 +    }
   8.338 +
   8.339 +    @Override
   8.340 +    public Node leaveNE_STRICT(final BinaryNode binaryNode) {
   8.341 +        return leaveCmp(binaryNode, Request.NE_STRICT);
   8.342 +    }
   8.343 +
   8.344 +    @Override
   8.345 +    public Node leaveOR(final BinaryNode binaryNode) {
   8.346 +        return binaryNode;
   8.347 +    }
   8.348 +
   8.349 +    @Override
   8.350 +    public Node leaveSAR(final BinaryNode binaryNode) {
   8.351 +        return leaveBinary(binaryNode, Type.INT, Type.INT);
   8.352 +    }
   8.353 +
   8.354 +    @Override
   8.355 +    public Node leaveSHL(final BinaryNode binaryNode) {
   8.356 +        return leaveBinary(binaryNode, Type.INT, Type.INT);
   8.357 +    }
   8.358 +
   8.359 +    @Override
   8.360 +    public Node leaveSHR(final BinaryNode binaryNode) {
   8.361 +        assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isLong();
   8.362 +        return leaveBinary(binaryNode, Type.INT, Type.INT);
   8.363 +    }
   8.364 +
   8.365 +    @Override
   8.366 +    public Node leaveSUB(final BinaryNode binaryNode) {
   8.367 +        return leaveBinaryArith(binaryNode);
   8.368 +    }
   8.369 +
   8.370 +    @Override
   8.371 +    public Node enter(final Block block) {
   8.372 +        updateSymbols(block);
   8.373 +        return block;
   8.374 +    }
   8.375 +
   8.376 +    @Override
   8.377 +    public Node leave(final CatchNode catchNode) {
   8.378 +        final Node exceptionCondition = catchNode.getExceptionCondition();
   8.379 +        if (exceptionCondition != null) {
   8.380 +            catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
   8.381 +        }
   8.382 +        return catchNode;
   8.383 +    }
   8.384 +
   8.385 +    @Override
   8.386 +    public Node enter(final DoWhileNode doWhileNode) {
   8.387 +        return enter((WhileNode)doWhileNode);
   8.388 +    }
   8.389 +
   8.390 +    @Override
   8.391 +    public Node leave(final DoWhileNode doWhileNode) {
   8.392 +        return leave((WhileNode)doWhileNode);
   8.393 +    }
   8.394 +
   8.395 +    @Override
   8.396 +    public Node leave(final ExecuteNode executeNode) {
   8.397 +        executeNode.setExpression(discard(executeNode.getExpression()));
   8.398 +        return executeNode;
   8.399 +    }
   8.400 +
   8.401 +    @Override
   8.402 +    public Node leave(final ForNode forNode) {
   8.403 +        final Node init   = forNode.getInit();
   8.404 +        final Node test   = forNode.getTest();
   8.405 +        final Node modify = forNode.getModify();
   8.406 +
   8.407 +        if (forNode.isForIn()) {
   8.408 +            forNode.setModify(convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400
   8.409 +            return forNode;
   8.410 +        }
   8.411 +
   8.412 +        if (init != null) {
   8.413 +            forNode.setInit(discard(init));
   8.414 +        }
   8.415 +
   8.416 +        if (test != null) {
   8.417 +            forNode.setTest(convert(test, Type.BOOLEAN));
   8.418 +        } else {
   8.419 +            assert forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + getCurrentFunctionNode();
   8.420 +        }
   8.421 +
   8.422 +        if (modify != null) {
   8.423 +            forNode.setModify(discard(modify));
   8.424 +        }
   8.425 +
   8.426 +        return forNode;
   8.427 +    }
   8.428 +
   8.429 +    @Override
   8.430 +    public Node enter(final FunctionNode functionNode) {
   8.431 +        updateSymbols(functionNode);
   8.432 +        return functionNode;
   8.433 +    }
   8.434 +
   8.435 +    @Override
   8.436 +    public Node leave(final IfNode ifNode) {
   8.437 +        final Node test = convert(ifNode.getTest(), Type.BOOLEAN);
   8.438 +        ifNode.setTest(test);
   8.439 +        return ifNode;
   8.440 +    }
   8.441 +
   8.442 +    @SuppressWarnings("rawtypes")
   8.443 +    @Override
   8.444 +    public Node enter(final LiteralNode literalNode) {
   8.445 +        if (literalNode instanceof ArrayLiteralNode) {
   8.446 +            final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
   8.447 +            final Node[]           array            = arrayLiteralNode.getValue();
   8.448 +            final Type             elementType      = arrayLiteralNode.getElementType();
   8.449 +
   8.450 +            for (int i = 0; i < array.length; i++) {
   8.451 +                final Node element = array[i];
   8.452 +                if (element != null) {
   8.453 +                    array[i] = convert(element.accept(this), elementType);
   8.454 +                }
   8.455 +            }
   8.456 +        }
   8.457 +
   8.458 +        return null;
   8.459 +    }
   8.460 +
   8.461 +    @Override
   8.462 +    public Node leave(final ReturnNode returnNode) {
   8.463 +        final Node expr = returnNode.getExpression();
   8.464 +        if (expr != null) {
   8.465 +            returnNode.setExpression(convert(expr, getCurrentFunctionNode().getReturnType()));
   8.466 +        }
   8.467 +        return returnNode;
   8.468 +    }
   8.469 +
   8.470 +    @Override
   8.471 +    public Node leave(final RuntimeNode runtimeNode) {
   8.472 +        final List<Node> args = runtimeNode.getArgs();
   8.473 +        for (final Node arg : args) {
   8.474 +            assert !arg.getType().isUnknown();
   8.475 +        }
   8.476 +        return runtimeNode;
   8.477 +    }
   8.478 +
   8.479 +    @Override
   8.480 +    public Node leave(final SwitchNode switchNode) {
   8.481 +        final Node           expression  = switchNode.getExpression();
   8.482 +        final List<CaseNode> cases       = switchNode.getCases();
   8.483 +        final boolean        allInteger  = switchNode.getTag().getSymbolType().isInteger();
   8.484 +
   8.485 +        if (!allInteger) {
   8.486 +            switchNode.setExpression(convert(expression, Type.OBJECT));
   8.487 +            for (final CaseNode caseNode : cases) {
   8.488 +                final Node test = caseNode.getTest();
   8.489 +                if (test != null) {
   8.490 +                    caseNode.setTest(convert(test, Type.OBJECT));
   8.491 +                }
   8.492 +            }
   8.493 +        }
   8.494 +
   8.495 +        return switchNode;
   8.496 +    }
   8.497 +
   8.498 +    @Override
   8.499 +    public Node leave(final TernaryNode ternaryNode) {
   8.500 +        ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN));
   8.501 +        return ternaryNode;
   8.502 +    }
   8.503 +
   8.504 +    @Override
   8.505 +    public Node leave(final ThrowNode throwNode) {
   8.506 +        throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT));
   8.507 +        return throwNode;
   8.508 +    }
   8.509 +
   8.510 +    @Override
   8.511 +    public Node leave(final VarNode varNode) {
   8.512 +        final Node rhs = varNode.getInit();
   8.513 +        if (rhs != null) {
   8.514 +            Type destType = specialize(varNode);
   8.515 +            if (destType == null) {
   8.516 +                destType = varNode.getType();
   8.517 +            }
   8.518 +            assert varNode.hasType() : varNode + " doesn't have a type";
   8.519 +            varNode.setInit(convert(rhs, destType));
   8.520 +        }
   8.521 +        return varNode;
   8.522 +    }
   8.523 +
   8.524 +    @Override
   8.525 +    public Node leave(final WhileNode whileNode) {
   8.526 +        final Node test = whileNode.getTest();
   8.527 +        if (test != null) {
   8.528 +            whileNode.setTest(convert(test, Type.BOOLEAN));
   8.529 +        }
   8.530 +        return whileNode;
   8.531 +    }
   8.532 +
   8.533 +    @Override
   8.534 +    public Node leave(final WithNode withNode) {
   8.535 +        withNode.setExpression(convert(withNode.getExpression(), Type.OBJECT));
   8.536 +        return withNode;
   8.537 +    }
   8.538 +
   8.539 +    private static void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) {
   8.540 +        if (!symbol.isScope()) {
   8.541 +            LOG.finest("updateSymbols: " + symbol + " => scope, because all vars in " + functionNode.getName() + " are in scope");
   8.542 +        }
   8.543 +        if (loseSlot && symbol.hasSlot()) {
   8.544 +            LOG.finest("updateSymbols: " + symbol + " => no slot, because all vars in " + functionNode.getName() + " are in scope");
   8.545 +        }
   8.546 +    }
   8.547 +
   8.548 +    /**
   8.549 +     * Called after a block or function node (subclass of block) is finished. Guarantees
   8.550 +     * that scope and slot information is correct for every symbol
   8.551 +     * @param block block for which to to finalize type info.
   8.552 +     */
   8.553 +    private static void updateSymbols(final Block block) {
   8.554 +
   8.555 +        if (!block.needsScope()) {
   8.556 +            return; // nothing to do
   8.557 +        }
   8.558 +
   8.559 +        assert !(block instanceof FunctionNode) || block.getFunction() == block;
   8.560 +
   8.561 +        final FunctionNode functionNode   = block.getFunction();
   8.562 +        final List<Symbol> symbols        = block.getFrame().getSymbols();
   8.563 +        final boolean      allVarsInScope = functionNode.varsInScope();
   8.564 +        final boolean      isVarArg       = functionNode.isVarArg();
   8.565 +
   8.566 +        for (final Symbol symbol : symbols) {
   8.567 +            if (symbol.isInternal() || symbol.isThis()) {
   8.568 +                continue;
   8.569 +            }
   8.570 +
   8.571 +            if (symbol.isVar()) {
   8.572 +                if (allVarsInScope || symbol.isScope()) {
   8.573 +                    updateSymbolsLog(functionNode, symbol, true);
   8.574 +                    symbol.setIsScope();
   8.575 +                    symbol.setNeedsSlot(false);
   8.576 +                } else {
   8.577 +                    assert symbol.hasSlot() : symbol + " should have a slot only, no scope";
   8.578 +                }
   8.579 +            } else if (symbol.isParam() && (allVarsInScope || isVarArg || symbol.isScope())) {
   8.580 +                updateSymbolsLog(functionNode, symbol, isVarArg);
   8.581 +                symbol.setIsScope();
   8.582 +                symbol.setNeedsSlot(!isVarArg);
   8.583 +            }
   8.584 +        }
   8.585 +    }
   8.586 +
   8.587 +    /**
   8.588 +     * Exit a comparison node and do the appropriate replacements. We need to introduce runtime
   8.589 +     * nodes late for comparisons as types aren't known until the last minute
   8.590 +     *
   8.591 +     * Both compares and adds may turn into runtimes node at this level as when we first bump
   8.592 +     * into the op in Attr, we may type it according to what we know there, which may be wrong later
   8.593 +     *
   8.594 +     * e.g. i (int) < 5 -> normal compare
   8.595 +     *     i = object
   8.596 +     *  then the post pass that would add the conversion to the 5 needs to
   8.597 +     *
   8.598 +     * @param binaryNode binary node to leave
   8.599 +     * @param request    runtime request
   8.600 +     * @return lowered cmp node
   8.601 +     */
   8.602 +    @SuppressWarnings("fallthrough")
   8.603 +    private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) {
   8.604 +        final Node lhs    = binaryNode.lhs();
   8.605 +        final Node rhs    = binaryNode.rhs();
   8.606 +
   8.607 +        Type widest = Type.widest(lhs.getType(), rhs.getType());
   8.608 +
   8.609 +        boolean newRuntimeNode = false, finalized = false;
   8.610 +        switch (request) {
   8.611 +        case EQ_STRICT:
   8.612 +        case NE_STRICT:
   8.613 +            if (lhs.getType().isBoolean() != rhs.getType().isBoolean()) {
   8.614 +                newRuntimeNode = true;
   8.615 +                widest = Type.OBJECT;
   8.616 +                finalized = true;
   8.617 +            }
   8.618 +            //fallthru
   8.619 +        default:
   8.620 +            if (newRuntimeNode || widest.isObject()) {
   8.621 +                final RuntimeNode runtimeNode = new RuntimeNode(binaryNode, request);
   8.622 +                if (finalized) {
   8.623 +                    runtimeNode.setIsFinal();
   8.624 +                }
   8.625 +                return runtimeNode;
   8.626 +            }
   8.627 +            break;
   8.628 +        }
   8.629 +
   8.630 +        binaryNode.setLHS(convert(lhs, widest));
   8.631 +        binaryNode.setRHS(convert(rhs, widest));
   8.632 +
   8.633 +        return binaryNode;
   8.634 +    }
   8.635 +
   8.636 +    /**
   8.637 +     * Compute the binary arithmetic type given the lhs and an rhs of a binary expression
   8.638 +     * @param lhsType  the lhs type
   8.639 +     * @param rhsType  the rhs type
   8.640 +     * @return the correct binary type
   8.641 +     */
   8.642 +    private static Type binaryArithType(final Type lhsType, final Type rhsType) {
   8.643 +        if (!Compiler.shouldUseIntegerArithmetic()) {
   8.644 +            return Type.NUMBER;
   8.645 +        }
   8.646 +        return Type.widest(lhsType, rhsType, Type.NUMBER);
   8.647 +    }
   8.648 +
   8.649 +    private Node leaveBinaryArith(final BinaryNode binaryNode) {
   8.650 +        final Type type = binaryArithType(binaryNode.lhs().getType(), binaryNode.rhs().getType());
   8.651 +        return leaveBinary(binaryNode, type, type);
   8.652 +    }
   8.653 +
   8.654 +    private Node leaveBinary(final BinaryNode binaryNode, final Type lhsType, final Type rhsType) {
   8.655 +        binaryNode.setLHS(convert(binaryNode.lhs(), lhsType));
   8.656 +        binaryNode.setRHS(convert(binaryNode.rhs(), rhsType));
   8.657 +        return binaryNode;
   8.658 +    }
   8.659 +
   8.660 +    /**
   8.661 +     * A symbol (and {@link Property}) can be tagged as "may be primitive". This is
   8.662 +     * used a hint for dual fields that it is even worth it to try representing this
   8.663 +     * field as something other than java.lang.Object.
   8.664 +     *
   8.665 +     * @param node node in which to tag symbols as primitive
   8.666 +     * @param to   which primitive type to use for tagging
   8.667 +     */
   8.668 +    private static void setCanBePrimitive(final Node node, final Type to) {
   8.669 +        final HashSet<Node> exclude = new HashSet<>();
   8.670 +
   8.671 +        node.accept(new NodeVisitor() {
   8.672 +            private void setCanBePrimitive(final Symbol symbol) {
   8.673 +                LOG.info("*** can be primitive symbol " + symbol + " " + Debug.id(symbol));
   8.674 +                symbol.setCanBePrimitive(to);
   8.675 +            }
   8.676 +
   8.677 +            @Override
   8.678 +            public Node enter(final IdentNode identNode) {
   8.679 +                if (!exclude.contains(identNode)) {
   8.680 +                    setCanBePrimitive(identNode.getSymbol());
   8.681 +                }
   8.682 +                return null;
   8.683 +            }
   8.684 +
   8.685 +            @Override
   8.686 +            public Node enter(final AccessNode accessNode) {
   8.687 +                setCanBePrimitive(accessNode.getProperty().getSymbol());
   8.688 +                return null;
   8.689 +            }
   8.690 +
   8.691 +            @Override
   8.692 +            public Node enter(final IndexNode indexNode) {
   8.693 +                exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine
   8.694 +                return indexNode;
   8.695 +            }
   8.696 +        });
   8.697 +    }
   8.698 +
   8.699 +    private static Type specialize(final Assignment<?> assignment) {
   8.700 +        final Node node = ((Node)assignment);
   8.701 +        final Node lhs = assignment.getAssignmentDest();
   8.702 +        final Node rhs = assignment.getAssignmentSource();
   8.703 +
   8.704 +        if (!canHaveCallSiteType(lhs)) {
   8.705 +            return null;
   8.706 +        }
   8.707 +
   8.708 +        final Type to;
   8.709 +        if (node.isSelfModifying()) {
   8.710 +            to = node.getWidestOperationType();
   8.711 +        } else {
   8.712 +            to = rhs.getType();
   8.713 +        }
   8.714 +
   8.715 +        if (!isSupportedCallSiteType(to)) {
   8.716 +            //meaningless to specialize to boolean or object
   8.717 +            return null;
   8.718 +        }
   8.719 +
   8.720 +        setTypeOverride(lhs, to);
   8.721 +        propagateType(node, to);
   8.722 +
   8.723 +        return to;
   8.724 +    }
   8.725 +
   8.726 +
   8.727 +    /**
   8.728 +     * Is this a node that can have its type overridden. This is true for
   8.729 +     * AccessNodes, IndexNodes and IdentNodes
   8.730 +     *
   8.731 +     * @param node the node to check
   8.732 +     * @return true if node can have a callsite type
   8.733 +     */
   8.734 +    private static boolean canHaveCallSiteType(final Node node) {
   8.735 +        return node instanceof TypeOverride && ((TypeOverride)node).canHaveCallSiteType();
   8.736 +    }
   8.737 +
   8.738 +    /**
   8.739 +     * Is the specialization type supported. Currently we treat booleans as objects
   8.740 +     * and have no special boolean type accessor, thus booleans are ignored.
   8.741 +     * TODO - support booleans? NASHORN-590
   8.742 +     *
   8.743 +     * @param castTo the type to check
   8.744 +     * @return true if call site type is supported
   8.745 +     */
   8.746 +    private static boolean isSupportedCallSiteType(final Type castTo) {
   8.747 +        return castTo.isNumeric(); // don't specializable for boolean
   8.748 +    }
   8.749 +
   8.750 +    /**
   8.751 +     * Override the type of a node for e.g. access specialization of scope
   8.752 +     * objects. Normally a variable can only get a wider type and narrower type
   8.753 +     * sets are ignored. Not that a variable can still be on object type as
   8.754 +     * per the type analysis, but a specific access may be narrower, e.g. if it
   8.755 +     * is used in an arithmetic op. This overrides a type, regardless of
   8.756 +     * type environment and is used primarily by the access specializer
   8.757 +     *
   8.758 +     * @param node    node for which to change type
   8.759 +     * @param to      new type
   8.760 +     */
   8.761 +    private static void setTypeOverride(final Node node, final Type to) {
   8.762 +        final Type from = node.getType();
   8.763 +        if (!node.getType().equals(to)) {
   8.764 +            LOG.info("Changing call override type for '" + node + "' from " + node.getType() + " to " + to);
   8.765 +            if (!to.isObject() && from.isObject()) {
   8.766 +                setCanBePrimitive(node, to);
   8.767 +            }
   8.768 +        }
   8.769 +        LOG.info("Type override for lhs in '" + node + "' => " + to);
   8.770 +        ((TypeOverride)node).setType(to);
   8.771 +    }
   8.772 +
   8.773 +    /**
   8.774 +     * Add an explicit conversion. This is needed when attribution has created types
   8.775 +     * that do not mesh into an op type, e.g. a = b, where b is object and a is double
   8.776 +     * at the end of Attr, needs explicit conversion logic.
   8.777 +     *
   8.778 +     * An explicit conversion can be one of the following:
   8.779 +     *   + Convert a literal - just replace it with another literal
   8.780 +     *   + Convert a scope object - just replace the type of the access, e.g. get()D->get()I
   8.781 +     *   + Explicit convert placement, e.g. a = (double)b - all other cases
   8.782 +     *
   8.783 +     * No other part of the world after {@link Attr} may introduce new symbols. This
   8.784 +     * is the only place.
   8.785 +     *
   8.786 +     * @param node node to convert
   8.787 +     * @param to   destination type
   8.788 +     * @return     conversion node
   8.789 +     */
   8.790 +    private Node convert(final Node node, final Type to) {
   8.791 +        assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass();
   8.792 +        assert node != null : "node is null";
   8.793 +        assert node.getSymbol() != null : "node " + node + " has no symbol!";
   8.794 +        assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getCurrentFunctionNode();
   8.795 +
   8.796 +        final Type from = node.getType();
   8.797 +
   8.798 +        if (Type.areEquivalent(from, to)) {
   8.799 +            return node;
   8.800 +        }
   8.801 +
   8.802 +        if (from.isObject() && to.isObject()) {
   8.803 +            return node;
   8.804 +        }
   8.805 +
   8.806 +        Node resultNode = node;
   8.807 +
   8.808 +        if (node instanceof LiteralNode && !to.isObject()) {
   8.809 +            final LiteralNode<?> newNode = new LiteralNodeConstantEvaluator((LiteralNode<?>)node, to).eval();
   8.810 +            if (newNode != null) {
   8.811 +                resultNode = newNode;
   8.812 +            }
   8.813 +        } else {
   8.814 +            if (canHaveCallSiteType(node) && isSupportedCallSiteType(to)) {
   8.815 +                setTypeOverride(node, to);
   8.816 +                return resultNode;
   8.817 +            }
   8.818 +            resultNode = new UnaryNode(source, Token.recast(node.getToken(), TokenType.CONVERT), node);
   8.819 +        }
   8.820 +
   8.821 +        LOG.info("CONVERT('" + node + "', " + to + ") => '" + resultNode + "'");
   8.822 +
   8.823 +        //This is the only place in this file that can create new temporaries
   8.824 +        //FinalizeTypes may not introduce ANY node that is not a conversion.
   8.825 +        getCurrentFunctionNode().newTemporary(getCurrentBlock().getFrame(), to, resultNode);
   8.826 +        resultNode.copyTerminalFlags(node);
   8.827 +
   8.828 +        return resultNode;
   8.829 +    }
   8.830 +
   8.831 +    private Node discard(final Node node) {
   8.832 +        node.setDiscard(true);
   8.833 +
   8.834 +        if (node.getSymbol() != null) {
   8.835 +            final Node discard = new UnaryNode(source, Token.recast(node.getToken(), TokenType.DISCARD), node);
   8.836 +            //discard never has a symbol in the discard node - then it would be a nop
   8.837 +            discard.copyTerminalFlags(node);
   8.838 +            return discard;
   8.839 +        }
   8.840 +
   8.841 +        // node has no result (symbol) so we can keep it the way it is
   8.842 +        return node;
   8.843 +    }
   8.844 +
   8.845 +    /**
   8.846 +     * Whenever an expression like an addition or an assignment changes type, it
   8.847 +     * may be that case that {@link Attr} created a symbol for an intermediate
   8.848 +     * result of the expression, say for an addition. This also has to be updated
   8.849 +     * if the expression type changes.
   8.850 +     *
   8.851 +     * Assignments use their lhs as node symbol, and in this case we can't modify
   8.852 +     * it. Then {@link CodeGenerator#Store} needs to do an explicit conversion.
   8.853 +     * This is happens very rarely.
   8.854 +     *
   8.855 +     * @param node
   8.856 +     * @param to
   8.857 +     */
   8.858 +    private static void propagateType(final Node node, final Type to) {
   8.859 +        final Symbol symbol = node.getSymbol();
   8.860 +        if (symbol.isTemp()) {
   8.861 +            symbol.setTypeOverride(to);
   8.862 +            LOG.info("Type override for temporary in '" + node + "' => " + to);
   8.863 +        }
   8.864 +    }
   8.865 +
   8.866 +    /**
   8.867 +     * Determine if the outcome of + operator is a string.
   8.868 +     *
   8.869 +     * @param node  Node to test.
   8.870 +     * @return true if a string result.
   8.871 +     */
   8.872 +    private boolean isAddString(final Node node) {
   8.873 +        if (node instanceof BinaryNode && node.isTokenType(TokenType.ADD)) {
   8.874 +            final BinaryNode binaryNode = (BinaryNode)node;
   8.875 +            final Node lhs = binaryNode.lhs();
   8.876 +            final Node rhs = binaryNode.rhs();
   8.877 +
   8.878 +            return isAddString(lhs) || isAddString(rhs);
   8.879 +        }
   8.880 +
   8.881 +        return node instanceof LiteralNode<?> && ((LiteralNode<?>)node).isString();
   8.882 +    }
   8.883 +
   8.884 +    /**
   8.885 +     * Whenever an explicit conversion is needed and the convertee is a literal, we can
   8.886 +     * just change the literal
   8.887 +     */
   8.888 +    static class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> {
   8.889 +        private final Type type;
   8.890 +
   8.891 +        LiteralNodeConstantEvaluator(final LiteralNode<?> parent, final Type type) {
   8.892 +            super(parent);
   8.893 +            this.type = type;
   8.894 +        }
   8.895 +
   8.896 +        @Override
   8.897 +        protected LiteralNode<?> eval() {
   8.898 +            final Object value = ((LiteralNode<?>)parent).getValue();
   8.899 +
   8.900 +            LiteralNode<?> literalNode = null;
   8.901 +
   8.902 +            if (type.isString()) {
   8.903 +                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toString(value));
   8.904 +            } else if (type.isBoolean()) {
   8.905 +                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toBoolean(value));
   8.906 +            } else if (type.isInteger()) {
   8.907 +                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toInt32(value));
   8.908 +            } else if (type.isLong()) {
   8.909 +                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toLong(value));
   8.910 +            } else if (type.isNumber() || parent.getType().isNumeric() && !parent.getType().isNumber()) {
   8.911 +                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toNumber(value));
   8.912 +            }
   8.913 +
   8.914 +            if (literalNode != null) {
   8.915 +                //inherit literal symbol for attr.
   8.916 +                literalNode.setSymbol(parent.getSymbol());
   8.917 +            }
   8.918 +
   8.919 +            return literalNode;
   8.920 +        }
   8.921 +    }
   8.922 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java	Wed Jan 30 12:26:45 2013 +0100
     9.3 @@ -0,0 +1,278 @@
     9.4 +/*
     9.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     9.7 + *
     9.8 + * This code is free software; you can redistribute it and/or modify it
     9.9 + * under the terms of the GNU General Public License version 2 only, as
    9.10 + * published by the Free Software Foundation.  Oracle designates this
    9.11 + * particular file as subject to the "Classpath" exception as provided
    9.12 + * by Oracle in the LICENSE file that accompanied this code.
    9.13 + *
    9.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    9.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    9.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    9.17 + * version 2 for more details (a copy is included in the LICENSE file that
    9.18 + * accompanied this code).
    9.19 + *
    9.20 + * You should have received a copy of the GNU General Public License version
    9.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    9.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    9.23 + *
    9.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    9.25 + * or visit www.oracle.com if you need additional information or have any
    9.26 + * questions.
    9.27 + */
    9.28 +
    9.29 +package jdk.nashorn.internal.codegen;
    9.30 +
    9.31 +import jdk.nashorn.internal.codegen.types.Type;
    9.32 +import jdk.nashorn.internal.ir.BinaryNode;
    9.33 +import jdk.nashorn.internal.ir.Block;
    9.34 +import jdk.nashorn.internal.ir.EmptyNode;
    9.35 +import jdk.nashorn.internal.ir.ExecuteNode;
    9.36 +import jdk.nashorn.internal.ir.IfNode;
    9.37 +import jdk.nashorn.internal.ir.LiteralNode;
    9.38 +import jdk.nashorn.internal.ir.Node;
    9.39 +import jdk.nashorn.internal.ir.TernaryNode;
    9.40 +import jdk.nashorn.internal.ir.UnaryNode;
    9.41 +import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    9.42 +import jdk.nashorn.internal.runtime.DebugLogger;
    9.43 +import jdk.nashorn.internal.runtime.JSType;
    9.44 +import jdk.nashorn.internal.runtime.ScriptRuntime;
    9.45 +import jdk.nashorn.internal.runtime.Source;
    9.46 +
    9.47 +/**
    9.48 + * Simple constant folding pass, executed before IR is starting to be lowered.
    9.49 + */
    9.50 +public class FoldConstants extends NodeVisitor {
    9.51 +
    9.52 +    private static final DebugLogger LOG = new DebugLogger("fold");
    9.53 +
    9.54 +    @Override
    9.55 +    public Node leave(final UnaryNode unaryNode) {
    9.56 +        final LiteralNode<?> literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval();
    9.57 +        if (literalNode != null) {
    9.58 +            LOG.info("Unary constant folded " + unaryNode + " to " + literalNode);
    9.59 +            return literalNode;
    9.60 +        }
    9.61 +        return unaryNode;
    9.62 +    }
    9.63 +
    9.64 +    @Override
    9.65 +    public Node leave(final BinaryNode binaryNode) {
    9.66 +        final LiteralNode<?> literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval();
    9.67 +        if (literalNode != null) {
    9.68 +            LOG.info("Binary constant folded " + binaryNode + " to " + literalNode);
    9.69 +            return literalNode;
    9.70 +        }
    9.71 +        return binaryNode;
    9.72 +    }
    9.73 +
    9.74 +    @Override
    9.75 +    public Node leave(final IfNode ifNode) {
    9.76 +        final Node test = ifNode.getTest();
    9.77 +        if (test instanceof LiteralNode) {
    9.78 +            final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
    9.79 +            if (shortCut != null) {
    9.80 +                return new ExecuteNode(shortCut);
    9.81 +            }
    9.82 +            return new EmptyNode(ifNode);
    9.83 +        }
    9.84 +        return ifNode;
    9.85 +    }
    9.86 +
    9.87 +    @Override
    9.88 +    public Node leave(final TernaryNode ternaryNode) {
    9.89 +        final Node test = ternaryNode.lhs();
    9.90 +        if (test instanceof LiteralNode) {
    9.91 +            return ((LiteralNode<?>)test).isTrue() ? ternaryNode.rhs() : ternaryNode.third();
    9.92 +        }
    9.93 +        return ternaryNode;
    9.94 +    }
    9.95 +
    9.96 +    /**
    9.97 +     * Helper class to evaluate constant expressions at compile time This is
    9.98 +     * also a simplifier used by BinaryNode visits, UnaryNode visits and
    9.99 +     * conversions.
   9.100 +     */
   9.101 +    abstract static class ConstantEvaluator<T extends Node> {
   9.102 +        protected T            parent;
   9.103 +        protected final Source source;
   9.104 +        protected final long   token;
   9.105 +        protected final int    finish;
   9.106 +
   9.107 +        protected ConstantEvaluator(final T parent) {
   9.108 +            this.parent = parent;
   9.109 +            this.source = parent.getSource();
   9.110 +            this.token  = parent.getToken();
   9.111 +            this.finish = parent.getFinish();
   9.112 +        }
   9.113 +
   9.114 +        /**
   9.115 +         * Returns a literal node that replaces the given parent node, or null if replacement
   9.116 +         * is impossible
   9.117 +         * @return the literal node
   9.118 +         */
   9.119 +        protected abstract LiteralNode<?> eval();
   9.120 +    }
   9.121 +
   9.122 +    private static class UnaryNodeConstantEvaluator extends ConstantEvaluator<UnaryNode> {
   9.123 +        UnaryNodeConstantEvaluator(final UnaryNode parent) {
   9.124 +            super(parent);
   9.125 +        }
   9.126 +
   9.127 +        @Override
   9.128 +        protected LiteralNode<?> eval() {
   9.129 +            final Node rhsNode = parent.rhs();
   9.130 +
   9.131 +            if (!(rhsNode instanceof LiteralNode)) {
   9.132 +                return null;
   9.133 +            }
   9.134 +
   9.135 +            final LiteralNode<?> rhs = (LiteralNode<?>)rhsNode;
   9.136 +            final boolean rhsInteger = rhs.getType().isInteger();
   9.137 +
   9.138 +            LiteralNode<?> literalNode;
   9.139 +
   9.140 +            switch (parent.tokenType()) {
   9.141 +            case ADD:
   9.142 +                if (rhsInteger) {
   9.143 +                    literalNode = LiteralNode.newInstance(source, token, finish, rhs.getInt32());
   9.144 +                } else {
   9.145 +                    literalNode = LiteralNode.newInstance(source, token, finish, rhs.getNumber());
   9.146 +                }
   9.147 +                break;
   9.148 +            case SUB:
   9.149 +                if (rhsInteger && rhs.getInt32() != 0) { // @see test/script/basic/minuszero.js
   9.150 +                    literalNode = LiteralNode.newInstance(source, token, finish, -rhs.getInt32());
   9.151 +                } else {
   9.152 +                    literalNode = LiteralNode.newInstance(source, token, finish, -rhs.getNumber());
   9.153 +                }
   9.154 +                break;
   9.155 +            case NOT:
   9.156 +                literalNode = LiteralNode.newInstance(source, token, finish, !rhs.getBoolean());
   9.157 +                break;
   9.158 +            case BIT_NOT:
   9.159 +                literalNode = LiteralNode.newInstance(source, token, finish, ~rhs.getInt32());
   9.160 +                break;
   9.161 +            default:
   9.162 +                return null;
   9.163 +            }
   9.164 +
   9.165 +            return literalNode;
   9.166 +        }
   9.167 +    }
   9.168 +
   9.169 +    //TODO add AND and OR with one constant parameter (bitwise)
   9.170 +    private static class BinaryNodeConstantEvaluator extends ConstantEvaluator<BinaryNode> {
   9.171 +        BinaryNodeConstantEvaluator(final BinaryNode parent) {
   9.172 +            super(parent);
   9.173 +        }
   9.174 +
   9.175 +        @Override
   9.176 +        protected LiteralNode<?> eval() {
   9.177 +            LiteralNode<?> result;
   9.178 +
   9.179 +            result = reduceTwoLiterals();
   9.180 +            if (result != null) {
   9.181 +                return result;
   9.182 +            }
   9.183 +
   9.184 +            result = reduceOneLiteral();
   9.185 +            if (result != null) {
   9.186 +                return result;
   9.187 +            }
   9.188 +
   9.189 +            return null;
   9.190 +        }
   9.191 +
   9.192 +        @SuppressWarnings("static-method")
   9.193 +        private LiteralNode<?> reduceOneLiteral() {
   9.194 +            //TODO handle patterns like AND, OR, numeric ops that can be strength reduced but not replaced by a single literal node etc
   9.195 +            return null;
   9.196 +        }
   9.197 +
   9.198 +        private LiteralNode<?> reduceTwoLiterals() {
   9.199 +            if (!(parent.lhs() instanceof LiteralNode && parent.rhs() instanceof LiteralNode)) {
   9.200 +                return null;
   9.201 +            }
   9.202 +
   9.203 +            final LiteralNode<?> lhs = (LiteralNode<?>)parent.lhs();
   9.204 +            final LiteralNode<?> rhs = (LiteralNode<?>)parent.rhs();
   9.205 +
   9.206 +            final Type widest = Type.widest(lhs.getType(), rhs.getType());
   9.207 +
   9.208 +            boolean isInteger = widest.isInteger();
   9.209 +            boolean isLong    = widest.isLong();
   9.210 +
   9.211 +            double value;
   9.212 +
   9.213 +            switch (parent.tokenType()) {
   9.214 +            case DIV:
   9.215 +                value = lhs.getNumber() / rhs.getNumber();
   9.216 +                break;
   9.217 +            case ADD:
   9.218 +                if ((lhs.isString() || rhs.isNumeric()) && (rhs.isString() || rhs.isNumeric())) {
   9.219 +                    Object res = ScriptRuntime.ADD(lhs.getObject(), rhs.getObject());
   9.220 +                    if (res instanceof Number) {
   9.221 +                        value = ((Number)res).doubleValue();
   9.222 +                        break;
   9.223 +                    }
   9.224 +                    assert res instanceof CharSequence : res + " was not a CharSequence, it was a " + res.getClass();
   9.225 +                    return LiteralNode.newInstance(source, token, finish, res.toString());
   9.226 +                }
   9.227 +                return null;
   9.228 +            case MUL:
   9.229 +                value = lhs.getNumber() * rhs.getNumber();
   9.230 +                break;
   9.231 +            case MOD:
   9.232 +                value = lhs.getNumber() % rhs.getNumber();
   9.233 +                break;
   9.234 +            case SUB:
   9.235 +                value = lhs.getNumber() - rhs.getNumber();
   9.236 +                break;
   9.237 +            case SHR:
   9.238 +                return LiteralNode.newInstance(source, token, finish, (lhs.getInt32() >>> rhs.getInt32()) & 0xffff_ffffL);
   9.239 +            case SAR:
   9.240 +                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() >> rhs.getInt32());
   9.241 +            case SHL:
   9.242 +                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() << rhs.getInt32());
   9.243 +            case BIT_XOR:
   9.244 +                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() ^ rhs.getInt32());
   9.245 +            case BIT_AND:
   9.246 +                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() & rhs.getInt32());
   9.247 +            case BIT_OR:
   9.248 +                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() | rhs.getInt32());
   9.249 +            case GE:
   9.250 +                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.GE(lhs.getObject(), rhs.getObject()));
   9.251 +            case LE:
   9.252 +                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.LE(lhs.getObject(), rhs.getObject()));
   9.253 +            case GT:
   9.254 +                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.GT(lhs.getObject(), rhs.getObject()));
   9.255 +            case LT:
   9.256 +                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.LT(lhs.getObject(), rhs.getObject()));
   9.257 +            case NE:
   9.258 +                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.NE(lhs.getObject(), rhs.getObject()));
   9.259 +            case NE_STRICT:
   9.260 +                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.NE_STRICT(lhs.getObject(), rhs.getObject()));
   9.261 +            case EQ:
   9.262 +                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.EQ(lhs.getObject(), rhs.getObject()));
   9.263 +            case EQ_STRICT:
   9.264 +                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.EQ_STRICT(lhs.getObject(), rhs.getObject()));
   9.265 +            default:
   9.266 +                return null;
   9.267 +            }
   9.268 +
   9.269 +            isInteger &= value != 0.0 && JSType.isRepresentableAsInt(value);
   9.270 +            isLong    &= value != 0.0 && JSType.isRepresentableAsLong(value);
   9.271 +
   9.272 +            if (isInteger) {
   9.273 +                return LiteralNode.newInstance(source, token, finish, JSType.toInt32(value));
   9.274 +            } else if (isLong) {
   9.275 +                return LiteralNode.newInstance(source, token, finish, JSType.toLong(value));
   9.276 +            }
   9.277 +
   9.278 +            return LiteralNode.newInstance(source, token, finish, value);
   9.279 +        }
   9.280 +    }
   9.281 +}
    10.1 --- a/src/jdk/nashorn/internal/codegen/Lower.java	Tue Jan 29 14:25:39 2013 -0400
    10.2 +++ b/src/jdk/nashorn/internal/codegen/Lower.java	Wed Jan 30 12:26:45 2013 +0100
    10.3 @@ -28,47 +28,19 @@
    10.4  import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
    10.5  import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
    10.6  import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
    10.7 -import static jdk.nashorn.internal.codegen.CompilerConstants.EXCEPTION_PREFIX;
    10.8 -import static jdk.nashorn.internal.codegen.CompilerConstants.ITERATOR_PREFIX;
    10.9  import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
   10.10  import static jdk.nashorn.internal.codegen.CompilerConstants.SCRIPT_RETURN;
   10.11 -import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX;
   10.12  import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
   10.13  import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
   10.14 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.ADD;
   10.15 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.DELETE;
   10.16 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.EQ;
   10.17 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.EQ_STRICT;
   10.18 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.FAIL_DELETE;
   10.19 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.GE;
   10.20 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.GT;
   10.21 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.IN;
   10.22 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.INSTANCEOF;
   10.23 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.LE;
   10.24 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.LT;
   10.25 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.NE;
   10.26 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.NE_STRICT;
   10.27 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.TYPEOF;
   10.28 -import static jdk.nashorn.internal.ir.RuntimeNode.Request.VOID;
   10.29 -import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
   10.30 -import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
   10.31 -import static jdk.nashorn.internal.ir.Symbol.IS_LET;
   10.32 -import static jdk.nashorn.internal.ir.Symbol.IS_PARAM;
   10.33 -import static jdk.nashorn.internal.ir.Symbol.IS_THIS;
   10.34 -import static jdk.nashorn.internal.ir.Symbol.IS_VAR;
   10.35 -import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
   10.36  
   10.37  import java.util.ArrayDeque;
   10.38  import java.util.ArrayList;
   10.39  import java.util.Arrays;
   10.40  import java.util.Deque;
   10.41 -import java.util.HashSet;
   10.42 -import java.util.LinkedList;
   10.43  import java.util.List;
   10.44 -import java.util.Set;
   10.45 -import jdk.nashorn.internal.codegen.types.Type;
   10.46 +
   10.47  import jdk.nashorn.internal.ir.AccessNode;
   10.48 -import jdk.nashorn.internal.ir.Assignment;
   10.49 +import jdk.nashorn.internal.ir.BaseNode;
   10.50  import jdk.nashorn.internal.ir.BinaryNode;
   10.51  import jdk.nashorn.internal.ir.Block;
   10.52  import jdk.nashorn.internal.ir.BreakNode;
   10.53 @@ -85,19 +57,13 @@
   10.54  import jdk.nashorn.internal.ir.IfNode;
   10.55  import jdk.nashorn.internal.ir.IndexNode;
   10.56  import jdk.nashorn.internal.ir.LabelNode;
   10.57 +import jdk.nashorn.internal.ir.LabeledNode;
   10.58  import jdk.nashorn.internal.ir.LineNumberNode;
   10.59  import jdk.nashorn.internal.ir.LiteralNode;
   10.60 -import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
   10.61  import jdk.nashorn.internal.ir.Node;
   10.62 -import jdk.nashorn.internal.ir.ObjectNode;
   10.63 -import jdk.nashorn.internal.ir.PropertyNode;
   10.64 -import jdk.nashorn.internal.ir.ReferenceNode;
   10.65  import jdk.nashorn.internal.ir.ReturnNode;
   10.66 -import jdk.nashorn.internal.ir.RuntimeNode;
   10.67 -import jdk.nashorn.internal.ir.RuntimeNode.Request;
   10.68  import jdk.nashorn.internal.ir.SwitchNode;
   10.69  import jdk.nashorn.internal.ir.Symbol;
   10.70 -import jdk.nashorn.internal.ir.TernaryNode;
   10.71  import jdk.nashorn.internal.ir.ThrowNode;
   10.72  import jdk.nashorn.internal.ir.TryNode;
   10.73  import jdk.nashorn.internal.ir.UnaryNode;
   10.74 @@ -108,54 +74,26 @@
   10.75  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   10.76  import jdk.nashorn.internal.parser.Token;
   10.77  import jdk.nashorn.internal.parser.TokenType;
   10.78 -import jdk.nashorn.internal.runtime.Context;
   10.79  import jdk.nashorn.internal.runtime.DebugLogger;
   10.80 -import jdk.nashorn.internal.runtime.ECMAException;
   10.81 -import jdk.nashorn.internal.runtime.JSType;
   10.82 -import jdk.nashorn.internal.runtime.Property;
   10.83 -import jdk.nashorn.internal.runtime.PropertyMap;
   10.84 -import jdk.nashorn.internal.runtime.ScriptFunction;
   10.85 -import jdk.nashorn.internal.runtime.ScriptObject;
   10.86  import jdk.nashorn.internal.runtime.ScriptRuntime;
   10.87  import jdk.nashorn.internal.runtime.Source;
   10.88 -import jdk.nashorn.internal.runtime.Undefined;
   10.89  
   10.90  /**
   10.91 - * Lower to more primitive operations. After lowering, an AST has symbols and
   10.92 - * types. Lowering may also add specialized versions of methods to the script if
   10.93 - * the optimizer is turned on.
   10.94 + * Lower to more primitive operations. After lowering, an AST still has no symbols
   10.95 + * and types, but several nodes have been turned into more low level constructs
   10.96 + * and control flow termination criteria have been computed.
   10.97   *
   10.98 - * Any expression that requires temporary storage as part of computation will
   10.99 - * also be detected here and give a temporary symbol
  10.100 + * We do things like code copying/inlining of finallies here, as it is much
  10.101 + * harder and context dependent to do any code copying after symbols have been
  10.102 + * finalized.
  10.103   */
  10.104  
  10.105  final class Lower extends NodeOperatorVisitor {
  10.106 -    /** Current compiler. */
  10.107 +
  10.108      private final Compiler compiler;
  10.109  
  10.110 -    /** Current source. */
  10.111      private final Source source;
  10.112  
  10.113 -    /** List of lowered statements */
  10.114 -    private List<Node> statements;
  10.115 -
  10.116 -    /** All symbols that are declared locally in a function node */
  10.117 -    private List<Symbol> declaredSymbolsLocal;
  10.118 -
  10.119 -    /**
  10.120 -     * Local definitions in current block (to discriminate from function
  10.121 -     * declarations always defined in the function scope. This is for
  10.122 -     * "can be undefined" analysis.
  10.123 -     */
  10.124 -    private Set<String> localDefs;
  10.125 -
  10.126 -    /**
  10.127 -     * Local definitions in current block to guard against cases like
  10.128 -     * NASHORN-467 when things can be undefined as they are used before
  10.129 -     * their local var definition. *sigh* JavaScript...
  10.130 -     */
  10.131 -    private Set<String> localUses;
  10.132 -
  10.133      /**
  10.134       * Nesting level stack. Currently just used for loops to avoid the problem
  10.135       * with terminal bodies that end with throw/return but still do continues to
  10.136 @@ -163,8 +101,11 @@
  10.137       */
  10.138      private final Deque<Node> nesting;
  10.139  
  10.140 -    private static final DebugLogger LOG   = new DebugLogger("lower");
  10.141 -    private static final boolean     DEBUG = LOG.isEnabled();
  10.142 +    private static final DebugLogger LOG = new DebugLogger("lower");
  10.143 +
  10.144 +    private Node lastStatement;
  10.145 +
  10.146 +    private List<Node> statements;
  10.147  
  10.148      /**
  10.149       * Constructor.
  10.150 @@ -174,52 +115,17 @@
  10.151      Lower(final Compiler compiler) {
  10.152          this.compiler   = compiler;
  10.153          this.source     = compiler.getSource();
  10.154 +        this.nesting    = new ArrayDeque<>();
  10.155          this.statements = new ArrayList<>();
  10.156 -        this.nesting    = new ArrayDeque<>();
  10.157 -    }
  10.158 -
  10.159 -    private void nest(final Node node) {
  10.160 -        nesting.push(node);
  10.161 -    }
  10.162 -
  10.163 -    private void unnest() {
  10.164 -        nesting.pop();
  10.165 -    }
  10.166 -
  10.167 -    static void debug(final String str) {
  10.168 -        if (DEBUG) {
  10.169 -            LOG.info(str);
  10.170 -        }
  10.171 -    }
  10.172 -
  10.173 -    @Override
  10.174 -    public Node leave(final AccessNode accessNode) {
  10.175 -        //accessNode.setBase(convert(accessNode.getBase(), Type.OBJECT));
  10.176 -        getCurrentFunctionNode().newTemporary(Type.OBJECT, accessNode); //This is not always an object per se, but currently the narrowing logic resides in AccessSpecializer. @see AccessSpecializer!
  10.177 -
  10.178 -        return accessNode;
  10.179      }
  10.180  
  10.181      @Override
  10.182      public Node enter(final Block block) {
  10.183 -        /*
  10.184 -         * Save the statement list from the outer construct we are currently
  10.185 -         * generating and push frame
  10.186 -         */
  10.187 -        final List<Node>  savedStatements = statements;
  10.188 -        final Set<String> savedDefs       = localDefs;
  10.189 -        final Set<String> savedUses       = localUses;
  10.190 -
  10.191 -        block.setFrame(getCurrentFunctionNode().pushFrame());
  10.192 +        final Node       savedLastStatement = lastStatement;
  10.193 +        final List<Node> savedStatements    = statements;
  10.194  
  10.195          try {
  10.196 -            /*
  10.197 -             * Reset the statement instance var, new block
  10.198 -             */
  10.199 -            statements = new ArrayList<>();
  10.200 -            localDefs  = new HashSet<>(savedDefs);
  10.201 -            localUses  = new HashSet<>(savedUses);
  10.202 -
  10.203 +            this.statements = new ArrayList<>();
  10.204              for (final Node statement : block.getStatements()) {
  10.205                  statement.accept(this);
  10.206                  /*
  10.207 @@ -231,28 +137,715 @@
  10.208                   *
  10.209                   * @see NASHORN-285
  10.210                   */
  10.211 -                final Node lastStatement = Node.lastStatement(statements);
  10.212                  if (lastStatement != null && lastStatement.isTerminal()) {
  10.213 -                    block.copyTerminalFlags(lastStatement);
  10.214 +                    copyTerminal(block, lastStatement);
  10.215 +                    break;
  10.216 +                }
  10.217 +            }
  10.218 +            block.setStatements(statements);
  10.219 +
  10.220 +        } finally {
  10.221 +            this.statements = savedStatements;
  10.222 +            this.lastStatement = savedLastStatement;
  10.223 +        }
  10.224 +
  10.225 +        return null;
  10.226 +    }
  10.227 +
  10.228 +    @Override
  10.229 +    public Node enter(final BreakNode breakNode) {
  10.230 +        return enterBreakOrContinue(breakNode);
  10.231 +    }
  10.232 +
  10.233 +    @Override
  10.234 +    public Node enter(final CallNode callNode) {
  10.235 +        final Node function = markerFunction(callNode.getFunction());
  10.236 +        callNode.setFunction(function);
  10.237 +        checkEval(callNode); //check if this is an eval call and store the information
  10.238 +        return callNode;
  10.239 +    }
  10.240 +
  10.241 +    @Override
  10.242 +    public Node leave(final CaseNode caseNode) {
  10.243 +        caseNode.copyTerminalFlags(caseNode.getBody());
  10.244 +        return caseNode;
  10.245 +    }
  10.246 +
  10.247 +    @Override
  10.248 +    public Node leave(final CatchNode catchNode) {
  10.249 +        catchNode.copyTerminalFlags(catchNode.getBody());
  10.250 +        addStatement(catchNode);
  10.251 +        return catchNode;
  10.252 +    }
  10.253 +
  10.254 +    @Override
  10.255 +    public Node enter(final ContinueNode continueNode) {
  10.256 +        return enterBreakOrContinue(continueNode);
  10.257 +    }
  10.258 +
  10.259 +    @Override
  10.260 +    public Node enter(final DoWhileNode doWhileNode) {
  10.261 +        return enter((WhileNode)doWhileNode);
  10.262 +    }
  10.263 +
  10.264 +    @Override
  10.265 +    public Node leave(final DoWhileNode doWhileNode) {
  10.266 +        return leave((WhileNode)doWhileNode);
  10.267 +    }
  10.268 +
  10.269 +    @Override
  10.270 +    public Node enter(final EmptyNode emptyNode) {
  10.271 +        return null;
  10.272 +    }
  10.273 +
  10.274 +    @Override
  10.275 +    public Node leave(final ExecuteNode executeNode) {
  10.276 +        final Node expr = executeNode.getExpression();
  10.277 +
  10.278 +        if (getCurrentFunctionNode().isScript()) {
  10.279 +            if (!(expr instanceof Block)) {
  10.280 +                if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
  10.281 +                    executeNode.setExpression(new BinaryNode(source, Token.recast(executeNode.getToken(), TokenType.ASSIGN),
  10.282 +                            getCurrentFunctionNode().getResultNode(),
  10.283 +                            expr));
  10.284 +                }
  10.285 +            }
  10.286 +        }
  10.287 +
  10.288 +        copyTerminal(executeNode, executeNode.getExpression());
  10.289 +        addStatement(executeNode);
  10.290 +
  10.291 +        return executeNode;
  10.292 +    }
  10.293 +
  10.294 +    @Override
  10.295 +    public Node enter(final ForNode forNode) {
  10.296 +        nest(forNode);
  10.297 +        return forNode;
  10.298 +    }
  10.299 +
  10.300 +    @Override
  10.301 +    public Node leave(final ForNode forNode) {
  10.302 +        final Node  test = forNode.getTest();
  10.303 +        final Block body = forNode.getBody();
  10.304 +
  10.305 +        if (!forNode.isForIn() && test == null) {
  10.306 +            setHasGoto(forNode);
  10.307 +        }
  10.308 +
  10.309 +        final boolean escapes = controlFlowEscapes(body);
  10.310 +        if (escapes) {
  10.311 +            setTerminal(body, false);
  10.312 +        }
  10.313 +
  10.314 +        // pop the loop from the loop context
  10.315 +        unnest(forNode);
  10.316 +
  10.317 +        if (!forNode.isForIn() && conservativeAlwaysTrue(test)) {
  10.318 +            forNode.setTest(null);
  10.319 +            setTerminal(forNode, !escapes);
  10.320 +        }
  10.321 +
  10.322 +        addStatement(forNode);
  10.323 +
  10.324 +        return forNode;
  10.325 +    }
  10.326 +
  10.327 +    @Override
  10.328 +    public Node enter(final FunctionNode functionNode) {
  10.329 +        LOG.info("START FunctionNode: " + functionNode.getName());
  10.330 +
  10.331 +        initFunctionNode(functionNode);
  10.332 +
  10.333 +        Node initialEvalResult = LiteralNode.newInstance(functionNode, ScriptRuntime.UNDEFINED);
  10.334 +
  10.335 +        nest(functionNode);
  10.336 +
  10.337 +        /*
  10.338 +         * As we are evaluating a nested structure, we need to store the
  10.339 +         * statement list for the surrounding block and restore it when the
  10.340 +         * function is done
  10.341 +         */
  10.342 +        final List<Node> savedStatements = statements;
  10.343 +        final Node savedLastStatement = lastStatement;
  10.344 +
  10.345 +        statements    = new ArrayList<>();
  10.346 +        lastStatement = null;
  10.347 +
  10.348 +        // for initial eval result is the last declared function
  10.349 +        for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
  10.350 +            final IdentNode ident = nestedFunction.getIdent();
  10.351 +            if (ident != null && nestedFunction.isStatement()) {
  10.352 +                initialEvalResult = new IdentNode(ident);
  10.353 +            }
  10.354 +        }
  10.355 +
  10.356 +        if (functionNode.needsSelfSymbol()) {
  10.357 +            //function needs to start with var funcIdent = __callee_;
  10.358 +            statements.add(functionNode.getSelfSymbolInit().accept(this));
  10.359 +        }
  10.360 +
  10.361 +        try {
  10.362 +            // Every nested function needs a definition in the outer function with its name. Add these.
  10.363 +            for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
  10.364 +                final VarNode varNode = nestedFunction.getFunctionVarNode();
  10.365 +                if (varNode != null) {
  10.366 +                    final LineNumberNode lineNumberNode = nestedFunction.getFunctionVarLineNumberNode();
  10.367 +                    if (lineNumberNode != null) {
  10.368 +                        lineNumberNode.accept(this);
  10.369 +                    }
  10.370 +                    varNode.accept(this);
  10.371 +                    varNode.setIsFunctionVarNode();
  10.372 +                }
  10.373 +            }
  10.374 +
  10.375 +            if (functionNode.isScript()) {
  10.376 +                new ExecuteNode(source, functionNode.getFirstToken(), functionNode.getFinish(), initialEvalResult).accept(this);
  10.377 +            }
  10.378 +
  10.379 +            //do the statements - this fills the block with code
  10.380 +            for (final Node statement : functionNode.getStatements()) {
  10.381 +                statement.accept(this);
  10.382 +                //If there are unused terminated endpoints in the function, we need
  10.383 +                // to add a "return undefined" in those places for correct semantics
  10.384 +                LOG.info("Checking lastStatement="+lastStatement+" for terminal flags");
  10.385 +                if (lastStatement != null && lastStatement.hasTerminalFlags()) {
  10.386 +                    copyTerminal(functionNode, lastStatement);
  10.387                      break;
  10.388                  }
  10.389              }
  10.390  
  10.391 -            block.setStatements(statements);
  10.392 +            functionNode.setStatements(statements);
  10.393 +
  10.394 +            if (!functionNode.isTerminal()) {
  10.395 +                guaranteeReturn(functionNode);
  10.396 +            }
  10.397 +
  10.398 +            //lower all nested functions
  10.399 +            for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
  10.400 +                nestedFunction.accept(this);
  10.401 +            }
  10.402 +
  10.403          } finally {
  10.404 -            /*
  10.405 -             * Restore the saved statements after block ends and pop frame
  10.406 -             */
  10.407 -            statements = savedStatements;
  10.408 -            localDefs  = savedDefs;
  10.409 -            localUses  = savedUses;
  10.410 -
  10.411 -            getCurrentFunctionNode().popFrame();
  10.412 +            statements    = savedStatements;
  10.413 +            lastStatement = savedLastStatement;
  10.414          }
  10.415  
  10.416 +        LOG.info("END FunctionNode: " + functionNode.getName());
  10.417 +        unnest(functionNode);
  10.418 +
  10.419          return null;
  10.420      }
  10.421  
  10.422 +    @Override
  10.423 +    public Node enter(final IfNode ifNode) {
  10.424 +        return nest(ifNode);
  10.425 +    }
  10.426 +
  10.427 +    @Override
  10.428 +    public Node leave(final IfNode ifNode) {
  10.429 +        final Node pass = ifNode.getPass();
  10.430 +        final Node fail = ifNode.getFail();
  10.431 +
  10.432 +        if (pass.isTerminal() && fail != null && fail.isTerminal()) {
  10.433 +            setTerminal(ifNode,  true);
  10.434 +        }
  10.435 +
  10.436 +        addStatement(ifNode);
  10.437 +        unnest(ifNode);
  10.438 +
  10.439 +        return ifNode;
  10.440 +    }
  10.441 +
  10.442 +    @Override
  10.443 +    public Node enter(LabelNode labelNode) {
  10.444 +        final Block body = labelNode.getBody();
  10.445 +        body.accept(this);
  10.446 +        copyTerminal(labelNode, body);
  10.447 +        addStatement(labelNode);
  10.448 +        return null;
  10.449 +    }
  10.450 +
  10.451 +    @Override
  10.452 +    public Node enter(final LineNumberNode lineNumberNode) {
  10.453 +        addStatement(lineNumberNode, false); // don't put it in lastStatement cache
  10.454 +        return null;
  10.455 +    }
  10.456 +
  10.457 +    @Override
  10.458 +    public Node enter(final ReturnNode returnNode) {
  10.459 +        final TryNode tryNode = returnNode.getTryChain();
  10.460 +        final Node    expr    = returnNode.getExpression();
  10.461 +
  10.462 +        if (tryNode != null) {
  10.463 +            //we are inside a try block - we don't necessarily have a result node yet. attr will do that.
  10.464 +            if (expr != null) {
  10.465 +                //we need to evaluate the result of the return in case it is complex while
  10.466 +                //still in the try block, store it in a result value and return it afterwards
  10.467 +                final long token        = returnNode.getToken();
  10.468 +                final Node resultNode   = new IdentNode(getCurrentFunctionNode().getResultNode());
  10.469 +                final Node assignResult = new BinaryNode(source, Token.recast(token, TokenType.ASSIGN), resultNode, expr);
  10.470 +
  10.471 +                //add return_in_try = expr; to try block
  10.472 +                new ExecuteNode(source, token, Token.descPosition(token), assignResult).accept(this);
  10.473 +
  10.474 +                //splice in the finally code, inlining it here
  10.475 +                if (copyFinally(tryNode, null)) {
  10.476 +                    return null;
  10.477 +                }
  10.478 +
  10.479 +                //make sure that the return node now returns 'return_in_try'
  10.480 +                returnNode.setExpression(resultNode);
  10.481 +            } else if (copyFinally(tryNode, null)) {
  10.482 +                return null;
  10.483 +            }
  10.484 +        } else if (expr != null) {
  10.485 +            returnNode.setExpression(expr.accept(this));
  10.486 +        }
  10.487 +
  10.488 +        addStatement(returnNode);
  10.489 +
  10.490 +        return null;
  10.491 +    }
  10.492 +
  10.493 +    @Override
  10.494 +    public Node leave(final ReturnNode returnNode) {
  10.495 +        addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor
  10.496 +        return returnNode;
  10.497 +    }
  10.498 +
  10.499 +    @Override
  10.500 +    public Node enter(final SwitchNode switchNode) {
  10.501 +        nest(switchNode);
  10.502 +        return switchNode;
  10.503 +    }
  10.504 +
  10.505 +    @Override
  10.506 +    public Node leave(final SwitchNode switchNode) {
  10.507 +        unnest(switchNode);
  10.508 +
  10.509 +        final List<CaseNode> cases       = switchNode.getCases();
  10.510 +        final CaseNode       defaultCase = switchNode.getDefaultCase();
  10.511 +
  10.512 +        boolean allTerminal = !cases.isEmpty();
  10.513 +        for (final CaseNode caseNode : switchNode.getCases()) {
  10.514 +            allTerminal &= caseNode.isTerminal();
  10.515 +        }
  10.516 +
  10.517 +        if (allTerminal && defaultCase != null && defaultCase.isTerminal()) {
  10.518 +            setTerminal(switchNode, true);
  10.519 +        }
  10.520 +
  10.521 +        addStatement(switchNode);
  10.522 +
  10.523 +        return switchNode;
  10.524 +    }
  10.525 +
  10.526 +    @Override
  10.527 +    public Node leave(final ThrowNode throwNode) {
  10.528 +        addStatement(throwNode); //ThrowNodes are always terminal, marked as such in constructor
  10.529 +        return throwNode;
  10.530 +    }
  10.531 +
  10.532 +    @Override
  10.533 +    public Node enter(final TryNode tryNode) {
  10.534 +        final Block  finallyBody = tryNode.getFinallyBody();
  10.535 +        final long   token       = tryNode.getToken();
  10.536 +        final int    finish      = tryNode.getFinish();
  10.537 +
  10.538 +        nest(tryNode);
  10.539 +
  10.540 +        if (finallyBody == null) {
  10.541 +            //do nothing if no finally exists
  10.542 +            return tryNode;
  10.543 +        }
  10.544 +
  10.545 +        /*
  10.546 +         * We have a finally clause.
  10.547 +         *
  10.548 +         * Transform to do finally tail duplication as follows:
  10.549 +         *
  10.550 +         * <pre>
  10.551 +         *  try {
  10.552 +         *    try_body
  10.553 +         *  } catch e1 {
  10.554 +         *    catchbody_1
  10.555 +         *  }
  10.556 +         *  ...
  10.557 +         *  } catch en {
  10.558 +         *    catchbody_n
  10.559 +         *  } finally {
  10.560 +         *    finally_body
  10.561 +         *  }
  10.562 +         *
  10.563 +         *  (where e1 ... en are optional)
  10.564 +         *
  10.565 +         *  turns into
  10.566 +         *
  10.567 +         *  try {
  10.568 +         *    try {
  10.569 +         *      try_body
  10.570 +         *    } catch e1 {
  10.571 +         *      catchbody1
  10.572 +         *      //nothing inlined explicitly here, return, break other
  10.573 +         *      //terminals may inline the finally body
  10.574 +         *      ...
  10.575 +         *    } catch en {
  10.576 +         *      catchbody2
  10.577 +         *      //nothing inlined explicitly here, return, break other
  10.578 +         *      //terminals may inline the finally body
  10.579 +         *    }
  10.580 +         *  } catch all ex {
  10.581 +         *      finally_body_inlined
  10.582 +         *      rethrow ex
  10.583 +         *  }
  10.584 +         *  finally_body_inlined
  10.585 +         * </pre>
  10.586 +         *
  10.587 +         * If tries are catches are terminal, visitors for return, break &
  10.588 +         * continue will handle the tail duplications. Throw needs to be
  10.589 +         * treated specially with the catchall as described in the above
  10.590 +         * ASCII art.
  10.591 +         *
  10.592 +         * If the try isn't terminal we do the finally_body_inlined at the
  10.593 +         * end. If the try is terminated with continue/break/return the
  10.594 +         * existing visitor logic will inline the finally before that
  10.595 +         * operation. if the try is terminated with a throw, the catches e1
  10.596 +         * ... en will have a chance to process the exception. If the
  10.597 +         * appropriate catch e1..en is non terminal we fall through to the
  10.598 +         * last finally_body_inlined. if the catch e1...en IS terminal with
  10.599 +         * continue/break/return existing visitor logic will fix it. If they
  10.600 +         * are terminal with another throw it goes to the catchall and the
  10.601 +         * finally_body_inlined marked (*) will fix it before rethrowing
  10.602 +         * whatever problem there was for identical semantic.
  10.603 +         */
  10.604 +
  10.605 +        // if try node does not contain a catch we can skip creation of a new
  10.606 +        // try node and just append our synthetic catch to the existing try node.
  10.607 +        if (!tryNode.getCatchBlocks().isEmpty()) {
  10.608 +            // insert an intermediate try-catch* node, where we move the body and all catch blocks.
  10.609 +            // the original try node become a try-finally container for the new try-catch* node.
  10.610 +            // because we don't clone (to avoid deep copy), we have to fix the block chain in the end.
  10.611 +            final TryNode innerTryNode;
  10.612 +            innerTryNode = new TryNode(source, token, finish, tryNode.getNext());
  10.613 +            innerTryNode.setBody(tryNode.getBody());
  10.614 +            innerTryNode.setCatchBlocks(tryNode.getCatchBlocks());
  10.615 +
  10.616 +            // set outer tryNode's body to innerTryNode
  10.617 +            final Block outerBody;
  10.618 +            outerBody = new Block(source, token, finish, tryNode.getBody().getParent(), getCurrentFunctionNode());
  10.619 +            outerBody.setStatements(new ArrayList<Node>(Arrays.asList(innerTryNode)));
  10.620 +            tryNode.setBody(outerBody);
  10.621 +            tryNode.setCatchBlocks(null);
  10.622 +
  10.623 +            // now before we go on, we have to fix the block parents
  10.624 +            // (we repair the block tree after the insertion so that all references are intact)
  10.625 +            innerTryNode.getBody().setParent(tryNode.getBody());
  10.626 +            for (final Block block : innerTryNode.getCatchBlocks()) {
  10.627 +                block.setParent(tryNode.getBody());
  10.628 +            }
  10.629 +        }
  10.630 +
  10.631 +        // create a catch-all that inlines finally and rethrows
  10.632 +
  10.633 +        final Block catchBlock      = new Block(source, token, finish, getCurrentBlock(), getCurrentFunctionNode());
  10.634 +        //this catch block should get define symbol
  10.635 +
  10.636 +        final Block catchBody       = new Block(source, token, finish, catchBlock, getCurrentFunctionNode());
  10.637 +        final Node  catchAllFinally = finallyBody.clone();
  10.638 +
  10.639 +        catchBody.addStatement(new ExecuteNode(source, finallyBody.getToken(), finallyBody.getFinish(), catchAllFinally));
  10.640 +        setTerminal(catchBody, true);
  10.641 +
  10.642 +        final CatchNode catchAllNode;
  10.643 +        final IdentNode exception;
  10.644 +
  10.645 +        exception    = new IdentNode(source, token, finish, compiler.uniqueName("catch_all"));
  10.646 +        catchAllNode = new CatchNode(source, token, finish, new IdentNode(exception), null, catchBody);
  10.647 +        catchAllNode.setIsSyntheticRethrow();
  10.648 +
  10.649 +        catchBlock.addStatement(catchAllNode);
  10.650 +
  10.651 +        // replace all catches of outer tryNode with the catch-all
  10.652 +        tryNode.setCatchBlocks(new ArrayList<>(Arrays.asList(catchBlock)));
  10.653 +
  10.654 +        /*
  10.655 +         * We leave the finally block for the original try in place for now
  10.656 +         * so that children visitations will work. It is removed and placed
  10.657 +         * afterwards in the else case below, after all children are visited
  10.658 +         */
  10.659 +
  10.660 +        return tryNode;
  10.661 +    }
  10.662 +
  10.663 +    @Override
  10.664 +    public Node leave(final TryNode tryNode) {
  10.665 +        final Block finallyBody   = tryNode.getFinallyBody();
  10.666 +
  10.667 +        boolean allTerminal = tryNode.getBody().isTerminal() && (finallyBody == null || finallyBody.isTerminal());
  10.668 +
  10.669 +        for (final Block catchBlock : tryNode.getCatchBlocks()) {
  10.670 +            allTerminal &= catchBlock.isTerminal();
  10.671 +        }
  10.672 +
  10.673 +        tryNode.setIsTerminal(allTerminal);
  10.674 +
  10.675 +        addStatement(tryNode);
  10.676 +        unnest(tryNode);
  10.677 +
  10.678 +        // if finally body is present, place it after the tryNode
  10.679 +        if (finallyBody != null) {
  10.680 +            tryNode.setFinallyBody(null);
  10.681 +            addStatement(finallyBody);
  10.682 +        }
  10.683 +
  10.684 +        return tryNode;
  10.685 +    }
  10.686 +
  10.687 +    @Override
  10.688 +    public Node leave(final VarNode varNode) {
  10.689 +        addStatement(varNode);
  10.690 +        return varNode;
  10.691 +    }
  10.692 +
  10.693 +    @Override
  10.694 +    public Node enter(final WhileNode whileNode) {
  10.695 +        return nest(whileNode);
  10.696 +    }
  10.697 +
  10.698 +    @Override
  10.699 +    public Node leave(final WhileNode whileNode) {
  10.700 +        final Node test = whileNode.getTest();
  10.701 +
  10.702 +        if (test == null) {
  10.703 +            setHasGoto(whileNode);
  10.704 +        }
  10.705 +
  10.706 +        final Block   body    = whileNode.getBody();
  10.707 +        final boolean escapes = controlFlowEscapes(body);
  10.708 +        if (escapes) {
  10.709 +            setTerminal(body, false);
  10.710 +        }
  10.711 +
  10.712 +        Node node = whileNode;
  10.713 +
  10.714 +        if (body.isTerminal()) {
  10.715 +            if (whileNode instanceof DoWhileNode) {
  10.716 +                setTerminal(whileNode, true);
  10.717 +            } else if (conservativeAlwaysTrue(test)) {
  10.718 +                node = new ForNode(source, whileNode.getToken(), whileNode.getFinish());
  10.719 +                ((ForNode)node).setBody(body);
  10.720 +                ((ForNode)node).accept(this);
  10.721 +                setTerminal(node, !escapes);
  10.722 +            }
  10.723 +        }
  10.724 +
  10.725 +        // pop the loop from the loop context
  10.726 +        unnest(whileNode);
  10.727 +        addStatement(node);
  10.728 +
  10.729 +        return node;
  10.730 +    }
  10.731 +
  10.732 +    @Override
  10.733 +    public Node leave(final WithNode withNode) {
  10.734 +        if (withNode.getBody().isTerminal()) {
  10.735 +            setTerminal(withNode,  true);
  10.736 +        }
  10.737 +        addStatement(withNode);
  10.738 +
  10.739 +        return withNode;
  10.740 +    }
  10.741 +
  10.742 +    @Override
  10.743 +    public Node leaveDELETE(final UnaryNode unaryNode) {
  10.744 +        final Node rhs = unaryNode.rhs();
  10.745 +        if (rhs instanceof IdentNode || rhs instanceof BaseNode) {
  10.746 +            return unaryNode;
  10.747 +        }
  10.748 +        addStatement(new ExecuteNode(rhs));
  10.749 +        return LiteralNode.newInstance(unaryNode, true);
  10.750 +    }
  10.751 +
  10.752 +    /**
  10.753 +     * Given a function node that is a callee in a CallNode, replace it with
  10.754 +     * the appropriate marker function. This is used by {@link CodeGenerator}
  10.755 +     * for fast scope calls
  10.756 +     *
  10.757 +     * @param function function called by a CallNode
  10.758 +     * @return transformed node to marker function or identity if not ident/access/indexnode
  10.759 +     */
  10.760 +    private static Node markerFunction(final Node function) {
  10.761 +        if (function instanceof IdentNode) {
  10.762 +            return new IdentNode((IdentNode)function) {
  10.763 +                @Override
  10.764 +                public boolean isFunction() {
  10.765 +                    return true;
  10.766 +                }
  10.767 +            };
  10.768 +        } else if (function instanceof AccessNode) {
  10.769 +            return new AccessNode((AccessNode)function) {
  10.770 +                @Override
  10.771 +                public boolean isFunction() {
  10.772 +                    return true;
  10.773 +                }
  10.774 +            };
  10.775 +        } else if (function instanceof IndexNode) {
  10.776 +            return new IndexNode((IndexNode)function) {
  10.777 +                @Override
  10.778 +                public boolean isFunction() {
  10.779 +                    return true;
  10.780 +                }
  10.781 +            };
  10.782 +        }
  10.783 +
  10.784 +        return function;
  10.785 +    }
  10.786 +
  10.787 +    /**
  10.788 +     * Calculate a synthetic eval location for a node for the stacktrace, for example src#17<eval>
  10.789 +     * @param node a node
  10.790 +     * @return eval location
  10.791 +     */
  10.792 +    private static String evalLocation(final IdentNode node) {
  10.793 +        //final StringBuilder sb = new StringBuilder(node.getSource().getName());
  10.794 +        return new StringBuilder().
  10.795 +            append(node.getSource().getName()).
  10.796 +            append('#').
  10.797 +            append(node.getSource().getLine(node.position())).
  10.798 +            append("<eval>").
  10.799 +            toString();
  10.800 +    }
  10.801 +
  10.802 +    /**
  10.803 +     * Check whether a call node may be a call to eval. In that case we
  10.804 +     * clone the args in order to create the following construct in
  10.805 +     * {@link CodeGenerator}
  10.806 +     *
  10.807 +     * <pre>
  10.808 +     * if (calledFuntion == buildInEval) {
  10.809 +     *    eval(cloned arg);
  10.810 +     * } else {
  10.811 +     *    cloned arg;
  10.812 +     * }
  10.813 +     * </pre>
  10.814 +     *
  10.815 +     * @param callNode call node to check if it's an eval
  10.816 +     */
  10.817 +    private void checkEval(final CallNode callNode) {
  10.818 +        if (callNode.getFunction() instanceof IdentNode) {
  10.819 +
  10.820 +            final List<Node> args   = callNode.getArgs();
  10.821 +            final IdentNode  callee = (IdentNode)callNode.getFunction();
  10.822 +
  10.823 +            // 'eval' call with at least one argument
  10.824 +            if (args.size() >= 1 && EVAL.tag().equals(callee.getName())) {
  10.825 +                final CallNode.EvalArgs evalArgs =
  10.826 +                    new CallNode.EvalArgs(
  10.827 +                        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.828 +                        getCurrentFunctionNode().getThisNode(),
  10.829 +                        evalLocation(callee),
  10.830 +                        getCurrentFunctionNode().isStrictMode());
  10.831 +                callNode.setEvalArgs(evalArgs);
  10.832 +            }
  10.833 +        }
  10.834 +    }
  10.835 +
  10.836 +    private static boolean conservativeAlwaysTrue(final Node node) {
  10.837 +        return node == null || ((node instanceof LiteralNode) && Boolean.TRUE.equals(((LiteralNode<?>)node).getValue()));
  10.838 +    }
  10.839 +
  10.840 +    /**
  10.841 +     * Helper that given a loop body makes sure that it is not terminal if it
  10.842 +     * has a continue that leads to the loop header or to outer loops' loop
  10.843 +     * headers. This means that, even if the body ends with a terminal
  10.844 +     * statement, we cannot tag it as terminal
  10.845 +     *
  10.846 +     * @param loopBody the loop body to check
  10.847 +     * @return true if control flow may escape the loop
  10.848 +     */
  10.849 +    private boolean controlFlowEscapes(final Node loopBody) {
  10.850 +        final List<Node> escapes = new ArrayList<>();
  10.851 +
  10.852 +        loopBody.accept(new NodeVisitor() {
  10.853 +            @Override
  10.854 +            public Node leave(final BreakNode node) {
  10.855 +                escapes.add(node);
  10.856 +                return node;
  10.857 +            }
  10.858 +
  10.859 +            @Override
  10.860 +            public Node leave(final ContinueNode node) {
  10.861 +                // all inner loops have been popped.
  10.862 +                if (nesting.contains(node.getTargetNode())) {
  10.863 +                    escapes.add(node);
  10.864 +                }
  10.865 +                return node;
  10.866 +            }
  10.867 +        });
  10.868 +
  10.869 +        return !escapes.isEmpty();
  10.870 +    }
  10.871 +
  10.872 +    private void guaranteeReturn(final FunctionNode functionNode) {
  10.873 +        Node resultNode;
  10.874 +
  10.875 +        if (functionNode.isScript()) {
  10.876 +            resultNode = functionNode.getResultNode(); // the eval result, symbol assigned in Attr
  10.877 +        } else {
  10.878 +            if (lastStatement != null && lastStatement.isTerminal() || lastStatement instanceof ReturnNode) {
  10.879 +                return; //already in place or not needed, as it should be for a non-undefined returning function
  10.880 +            }
  10.881 +            resultNode = LiteralNode.newInstance(functionNode, ScriptRuntime.UNDEFINED);
  10.882 +        }
  10.883 +
  10.884 +        //create a return statement
  10.885 +        final Node returnNode = new ReturnNode(source, functionNode.getLastToken(), functionNode.getFinish(), resultNode, null);
  10.886 +        returnNode.accept(this);
  10.887 +    }
  10.888 +
  10.889 +
  10.890 +    private Node nest(final Node node) {
  10.891 +        LOG.info("Nesting: " + node);
  10.892 +        LOG.indent();
  10.893 +        nesting.push(node);
  10.894 +        return node;
  10.895 +    }
  10.896 +
  10.897 +    private void unnest(final Node node) {
  10.898 +        LOG.unindent();
  10.899 +        assert nesting.getFirst() == node : "inconsistent nesting order : " + nesting.getFirst() + " != " + node;
  10.900 +        LOG.info("Unnesting: " + nesting);
  10.901 +        nesting.pop();
  10.902 +    }
  10.903 +
  10.904 +    private static void setTerminal(final Node node, final boolean isTerminal) {
  10.905 +        LOG.info("terminal = " + isTerminal + " for " + node);
  10.906 +        node.setIsTerminal(isTerminal);
  10.907 +    }
  10.908 +
  10.909 +    private static void setHasGoto(final Node node) { //, final boolean hasGoto) {
  10.910 +        LOG.info("hasGoto = true for " + node);
  10.911 +        node.setHasGoto();
  10.912 +    }
  10.913 +
  10.914 +    private static void copyTerminal(final Node node, final Node sourceNode) {
  10.915 +        LOG.info("copy terminal flags " + sourceNode + " -> " + node);
  10.916 +        node.copyTerminalFlags(sourceNode);
  10.917 +    }
  10.918 +
  10.919 +    private void addStatement(final Node statement, final boolean storeInLastStatement) {
  10.920 +        LOG.info("add statement = " + statement + " (lastStatement = " + lastStatement + ")");
  10.921 +        statements.add(statement);
  10.922 +        if (storeInLastStatement) {
  10.923 +            lastStatement = statement;
  10.924 +        }
  10.925 +    }
  10.926 +
  10.927 +    private void addStatement(final Node statement) {
  10.928 +        addStatement(statement, true);
  10.929 +    }
  10.930 +
  10.931      /**
  10.932       * Determine if Try block is inside target block.
  10.933       *
  10.934 @@ -316,271 +909,15 @@
  10.935          return false;
  10.936      }
  10.937  
  10.938 -    @Override
  10.939 -    public Node enter(final BreakNode breakNode) {
  10.940 -        final TryNode tryNode = breakNode.getTryChain();
  10.941 -
  10.942 -        if (tryNode != null && copyFinally(tryNode, breakNode.getTargetNode())) {
  10.943 +    private Node enterBreakOrContinue(final LabeledNode labeledNode) {
  10.944 +        final TryNode tryNode = labeledNode.getTryChain();
  10.945 +        if (tryNode != null && copyFinally(tryNode, labeledNode.getTargetNode())) {
  10.946              return null;
  10.947          }
  10.948 -
  10.949 -        statements.add(breakNode);
  10.950 -
  10.951 +        addStatement(labeledNode);
  10.952          return null;
  10.953      }
  10.954  
  10.955 -    /**
  10.956 -     * Blesses nodes with an expectant type, converting if necessary.
  10.957 -     *
  10.958 -     * @param node Node to be blest.
  10.959 -     * @param type Type class expected.
  10.960 -     *
  10.961 -     * @return Converted node or original node if no conversion is needed.
  10.962 -     */
  10.963 -    private Node convert(final Node node, final Type type) {
  10.964 -
  10.965 -        final Symbol       symbol       = node.getSymbol();
  10.966 -        final FunctionNode functionNode = getCurrentFunctionNode();
  10.967 -
  10.968 -        assert !type.isUnknown() : "unknown";
  10.969 -
  10.970 -        /*
  10.971 -         * Conversions are now mandatory, have to be placed at code time and
  10.972 -         * cannot be removed as there might be cases like:
  10.973 -         *
  10.974 -         * var x = 17; if (x + 1) { ... }
  10.975 -         *
  10.976 -         * x = Number(4711); if (x + 1) { ... }
  10.977 -         *
  10.978 -         * In the old world this behaved as follows:
  10.979 -         *
  10.980 -         * Here, x is originally inferred type to a number, then the if does a
  10.981 -         * double add without a cast. However, the next statement turns x into
  10.982 -         * an object, and this messes up the original. If we would now suddenly
  10.983 -         * need an explicit cast for the first addition, given that we don't do
  10.984 -         * fancy stuff like splitting live range.
  10.985 -         *
  10.986 -         * Even worse is the case where we have an eval that modifies local
  10.987 -         * variables in the middle of a function and may widen a type suspected
  10.988 -         * to be at most e.g. NUMBER to e.g. OBJECT.
  10.989 -         *
  10.990 -         * There are a few local optimizations we can do. If we want to do an
  10.991 -         * OBJECT to OBJECT cast, for example, we can skip it as already is
  10.992 -         * maximally wide, except if we are in a method with an eval where
  10.993 -         * everything is possible...
  10.994 -         *
  10.995 -         * @see test/test262/test/suite/ch07/7.2/S7.2_A1.4_T2.js for an example
  10.996 -         * of this.
  10.997 -         */
  10.998 -
  10.999 -        assert symbol != null : "no symbol for " + node;
 10.1000 -
 10.1001 -        /* check object to object cast */
 10.1002 -        if (!functionNode.hasEval() && node.getType().isEquivalentTo(Type.OBJECT) && type.isEquivalentTo(Type.OBJECT)) {
 10.1003 -            return node;
 10.1004 -        }
 10.1005 -
 10.1006 -        Node resultNode = node;
 10.1007 -
 10.1008 -        // Literal nodes may be converted directly
 10.1009 -
 10.1010 -        if (node instanceof LiteralNode) {
 10.1011 -            final LiteralNode<?> convertedLiteral = new LiteralNodeConstantEvaluator((LiteralNode<?>)node, type).eval();
 10.1012 -            if (convertedLiteral != null) {
 10.1013 -                resultNode = newLiteral(convertedLiteral);
 10.1014 -            }
 10.1015 -            // object literals still need the cast
 10.1016 -            if (type.isObject()) {
 10.1017 -                resultNode = new UnaryNode(source, Token.recast(node.getToken(), TokenType.CONVERT), node);
 10.1018 -            }
 10.1019 -        } else {
 10.1020 -            if (resultNode.getSymbol().isParam()) {
 10.1021 -                resultNode.getSymbol().setType(type);
 10.1022 -            }
 10.1023 -             resultNode = new UnaryNode(source, Token.recast(node.getToken(), TokenType.CONVERT), resultNode);
 10.1024 -        }
 10.1025 -
 10.1026 -        functionNode.newTemporary(type, resultNode);
 10.1027 -        resultNode.copyTerminalFlags(node);
 10.1028 -
 10.1029 -        return resultNode;
 10.1030 -    }
 10.1031 -
 10.1032 -    /**
 10.1033 -     * Accept and convert all arguments to type Object. If we have a
 10.1034 -     * specialization profile for this function, we instead try to specialize
 10.1035 -     * the arguments before the casts based on their current types and values.
 10.1036 -     *
 10.1037 -     * @param callNode function call
 10.1038 -     * @return return type for call
 10.1039 -     */
 10.1040 -    private Type acceptArgs(final CallNode callNode) {
 10.1041 -        final List<Node> oldArgs = callNode.getArgs();
 10.1042 -        final List<Node> acceptedArgs = new ArrayList<>(oldArgs.size());
 10.1043 -
 10.1044 -        for (final Node arg : oldArgs) {
 10.1045 -            //acceptedArgs.add(convert(arg.accept(this), OBJECT));
 10.1046 -            acceptedArgs.add(arg.accept(this));
 10.1047 -        }
 10.1048 -        callNode.setArgs(acceptedArgs);
 10.1049 -
 10.1050 -        return Type.OBJECT;
 10.1051 -    }
 10.1052 -
 10.1053 -    private static String evalLocation(final IdentNode node) {
 10.1054 -        final StringBuilder sb = new StringBuilder(node.getSource().getName());
 10.1055 -
 10.1056 -        sb.append('#');
 10.1057 -        sb.append(node.getSource().getLine(node.position()));
 10.1058 -        sb.append("<eval>");
 10.1059 -
 10.1060 -        return sb.toString();
 10.1061 -    }
 10.1062 -
 10.1063 -    private void checkEval(final CallNode callNode) {
 10.1064 -        if (callNode.getFunction() instanceof IdentNode) {
 10.1065 -
 10.1066 -            final List<Node> args   = callNode.getArgs();
 10.1067 -            final IdentNode  callee = (IdentNode)callNode.getFunction();
 10.1068 -
 10.1069 -            // 'eval' call with atleast one argument
 10.1070 -            if (args.size() >= 1 && EVAL.tag().equals(callee.getName())) {
 10.1071 -                final CallNode.EvalArgs evalArgs = new CallNode.EvalArgs();
 10.1072 -                // code that is evaluated
 10.1073 -                evalArgs.code = args.get(0).clone();
 10.1074 -                evalArgs.code.accept(this);
 10.1075 -                // 'this' to be passed to evaluated code
 10.1076 -                evalArgs.evalThis = new IdentNode(getCurrentFunctionNode().getThisNode());
 10.1077 -                // location string of the eval call
 10.1078 -                evalArgs.location = evalLocation(callee);
 10.1079 -                // strict mode context or not?
 10.1080 -                evalArgs.strictMode = getCurrentFunctionNode().isStrictMode();
 10.1081 -                callNode.setEvalArgs(evalArgs);
 10.1082 -            }
 10.1083 -        }
 10.1084 -    }
 10.1085 -
 10.1086 -    private static Node markerFunction(final Node function) {
 10.1087 -        if (function instanceof IdentNode) {
 10.1088 -            return new IdentNode((IdentNode)function) {
 10.1089 -                @Override
 10.1090 -                public boolean isFunction() {
 10.1091 -                    return true;
 10.1092 -                }
 10.1093 -            };
 10.1094 -        } else if (function instanceof AccessNode) {
 10.1095 -            return new AccessNode((AccessNode)function) {
 10.1096 -                @Override
 10.1097 -                public boolean isFunction() {
 10.1098 -                    return true;
 10.1099 -                }
 10.1100 -            };
 10.1101 -        } else if (function instanceof IndexNode) {
 10.1102 -            return new IndexNode((IndexNode)function) {
 10.1103 -                @Override
 10.1104 -                public boolean isFunction() {
 10.1105 -                    return true;
 10.1106 -                }
 10.1107 -            };
 10.1108 -        }
 10.1109 -
 10.1110 -        return function;
 10.1111 -    }
 10.1112 -
 10.1113 -    @Override
 10.1114 -    public Node enter(final CallNode callNode) {
 10.1115 -        final Node function       = callNode.getFunction();
 10.1116 -        final Node markedFunction = markerFunction(function);
 10.1117 -
 10.1118 -        callNode.setFunction(markedFunction.accept(this));
 10.1119 -
 10.1120 -        checkEval(callNode);
 10.1121 -
 10.1122 -        final Type returnType = acceptArgs(callNode);
 10.1123 -        getCurrentFunctionNode().newTemporary(returnType, callNode);
 10.1124 -        callNode.getFunction().getSymbol().setType(returnType);
 10.1125 -
 10.1126 -        return null;
 10.1127 -    }
 10.1128 -
 10.1129 -    @Override
 10.1130 -    public Node leave(final CaseNode caseNode) {
 10.1131 -        caseNode.copyTerminalFlags(caseNode.getBody());
 10.1132 -
 10.1133 -        return caseNode;
 10.1134 -    }
 10.1135 -
 10.1136 -    @Override
 10.1137 -    public Node enter(final CatchNode catchNode) {
 10.1138 -        final IdentNode ident = catchNode.getException();
 10.1139 -        final Block     block = getCurrentBlock();
 10.1140 -
 10.1141 -        // define block-local exception variable
 10.1142 -        block.defineSymbol(ident.getName(), IS_VAR | IS_LET, ident).setType(Type.OBJECT);
 10.1143 -        localDefs.add(ident.getName());
 10.1144 -
 10.1145 -        return catchNode;
 10.1146 -    }
 10.1147 -
 10.1148 -    @Override
 10.1149 -    public Node leave(final CatchNode catchNode) {
 10.1150 -        final Node exceptionCondition = catchNode.getExceptionCondition();
 10.1151 -        if (exceptionCondition != null) {
 10.1152 -            catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
 10.1153 -        }
 10.1154 -
 10.1155 -        catchNode.copyTerminalFlags(catchNode.getBody());
 10.1156 -
 10.1157 -        statements.add(catchNode);
 10.1158 -
 10.1159 -        return catchNode;
 10.1160 -    }
 10.1161 -
 10.1162 -    @Override
 10.1163 -    public Node enter(final ContinueNode continueNode) {
 10.1164 -        final TryNode tryNode = continueNode.getTryChain();
 10.1165 -        final Node target = continueNode.getTargetNode();
 10.1166 -
 10.1167 -        if (tryNode != null && copyFinally(tryNode, target)) {
 10.1168 -            return null;
 10.1169 -        }
 10.1170 -
 10.1171 -        statements.add(continueNode);
 10.1172 -
 10.1173 -        return null;
 10.1174 -    }
 10.1175 -
 10.1176 -    @Override
 10.1177 -    public Node enter(final DoWhileNode whileNode) {
 10.1178 -        return enter((WhileNode)whileNode);
 10.1179 -    }
 10.1180 -
 10.1181 -    @Override
 10.1182 -    public Node leave(final DoWhileNode whileNode) {
 10.1183 -        return leave((WhileNode)whileNode);
 10.1184 -    }
 10.1185 -
 10.1186 -    @Override
 10.1187 -    public Node enter(final EmptyNode emptyNode) {
 10.1188 -        return null;
 10.1189 -    }
 10.1190 -
 10.1191 -    /**
 10.1192 -     * Is this an assignment to the special variable that hosts scripting eval
 10.1193 -     * results?
 10.1194 -     *
 10.1195 -     * @param expression expression to check whether it is $evalresult = X
 10.1196 -     *
 10.1197 -     * @return true if an assignment to eval result, false otherwise
 10.1198 -     */
 10.1199 -    private boolean isEvalResultAssignment(final Node expression) {
 10.1200 -        Node e = expression;
 10.1201 -        if (e.tokenType() == TokenType.DISCARD) {
 10.1202 -            e = ((UnaryNode)expression).rhs();
 10.1203 -        }
 10.1204 -        final Node resultNode = getCurrentFunctionNode().getResultNode();
 10.1205 -        return e instanceof BinaryNode && ((BinaryNode)e).lhs().equals(resultNode);
 10.1206 -    }
 10.1207  
 10.1208      /**
 10.1209       * An internal expression has a symbol that is tagged internal. Check if
 10.1210 @@ -595,2543 +932,41 @@
 10.1211      }
 10.1212  
 10.1213      /**
 10.1214 -     * Discard the result of the expression.
 10.1215 +     * Is this an assignment to the special variable that hosts scripting eval
 10.1216 +     * results?
 10.1217       *
 10.1218 -     * @param expression Expression to discard.
 10.1219 -     *
 10.1220 -     * @return Discard node.
 10.1221 +     * @param expression expression to check whether it is $evalresult = X
 10.1222 +     * @return true if an assignment to eval result, false otherwise
 10.1223       */
 10.1224 -    private Node discard(final Node expression) {
 10.1225 -        expression.setDiscard(true);
 10.1226 -
 10.1227 -        if (expression.getSymbol() != null) {
 10.1228 -            final Node discard = new UnaryNode(source, Token.recast(expression.getToken(), TokenType.DISCARD), expression);
 10.1229 -            discard.copyTerminalFlags(expression);
 10.1230 -
 10.1231 -            return discard;
 10.1232 +    private boolean isEvalResultAssignment(final Node expression) {
 10.1233 +        Node e = expression;
 10.1234 +        if (e.tokenType() == TokenType.DISCARD) {
 10.1235 +            e = ((UnaryNode)expression).rhs();
 10.1236          }
 10.1237 -
 10.1238 -        return expression;
 10.1239 +        final Node resultNode = getCurrentFunctionNode().getResultNode();
 10.1240 +        return e instanceof BinaryNode && ((BinaryNode)e).lhs().equals(resultNode);
 10.1241      }
 10.1242  
 10.1243      /**
 10.1244 -     * ExecuteNodes are needed to actually generate code, with a few exceptions
 10.1245 -     * such as ReturnNodes and ThrowNodes and various control flow that can
 10.1246 -     * standalone. Every other kind of statement needs to be wrapped in an
 10.1247 -     * ExecuteNode in order to become code
 10.1248 -     *
 10.1249 -     * @param executeNode  the execute node to visit
 10.1250 +     * Prepare special function nodes.
 10.1251 +     * TODO : only create those that are needed.
 10.1252 +     * TODO : make sure slot numbering is not hardcoded in {@link CompilerConstants} - now creation order is significant
 10.1253       */
 10.1254 -    @Override
 10.1255 -    public Node leave(final ExecuteNode executeNode) {
 10.1256 -
 10.1257 -        Node expression = executeNode.getExpression();
 10.1258 -
 10.1259 -        /*
 10.1260 -         * Handle the eval result for scripts. Every statement has to write its
 10.1261 -         * return value to a special variable that is the result of the script.
 10.1262 -         */
 10.1263 -        if (getCurrentFunctionNode().isScript() && !(expression instanceof Block) && !isEvalResultAssignment(expression) && !isInternalExpression(expression)) {
 10.1264 -            final Node resultNode = getCurrentFunctionNode().getResultNode();
 10.1265 -            expression = new BinaryNode(source, Token.recast(executeNode.getToken(), TokenType.ASSIGN), resultNode, convert(expression, resultNode.getType()));
 10.1266 -
 10.1267 -            getCurrentFunctionNode().newTemporary(Type.OBJECT, expression);
 10.1268 -        }
 10.1269 -
 10.1270 -        expression = discard(expression);
 10.1271 -        executeNode.setExpression(expression);
 10.1272 -        executeNode.copyTerminalFlags(expression);
 10.1273 -
 10.1274 -        statements.add(executeNode);
 10.1275 -
 10.1276 -        return executeNode;
 10.1277 -    }
 10.1278 -
 10.1279 -    /**
 10.1280 -     * Helper that given a loop body makes sure that it is not terminal if it
 10.1281 -     * has a continue that leads to the loop header or to outer loops' loop
 10.1282 -     * headers. This means that, even if the body ends with a terminal
 10.1283 -     * statement, we cannot tag it as terminal
 10.1284 -     *
 10.1285 -     * @param loopBody the loop body to check
 10.1286 -     */
 10.1287 -    private boolean controlFlowEscapes(final Node loopBody) {
 10.1288 -        final List<Node> escapes = new ArrayList<>();
 10.1289 -
 10.1290 -        loopBody.accept(new NodeVisitor() {
 10.1291 -            @Override
 10.1292 -            public Node leave(final BreakNode node) {
 10.1293 -                escapes.add(node);
 10.1294 -                return node;
 10.1295 -            }
 10.1296 -
 10.1297 -            @Override
 10.1298 -            public Node leave(final ContinueNode node) {
 10.1299 -                // all inner loops have been popped.
 10.1300 -                if (nesting.contains(node.getTargetNode())) {
 10.1301 -                    escapes.add(node);
 10.1302 -                }
 10.1303 -                return node;
 10.1304 -            }
 10.1305 -        });
 10.1306 -
 10.1307 -        return !escapes.isEmpty();
 10.1308 -    }
 10.1309 -
 10.1310 -    @Override
 10.1311 -    public Node enter(final ForNode forNode) {
 10.1312 -        // push the loop to the loop context
 10.1313 -        nest(forNode);
 10.1314 -        return forNode;
 10.1315 -    }
 10.1316 -
 10.1317 -    private static boolean conservativeAlwaysTrue(final Node node) {
 10.1318 -        return node == null || ((node instanceof LiteralNode) && Boolean.TRUE.equals(((LiteralNode<?>)node).getValue()));
 10.1319 -    }
 10.1320 -
 10.1321 -    @Override
 10.1322 -    public Node leave(final ForNode forNode) {
 10.1323 -        final Node init   = forNode.getInit();
 10.1324 -        final Node test   = forNode.getTest();
 10.1325 -        final Node modify = forNode.getModify();
 10.1326 -
 10.1327 -        if (forNode.isForIn()) {
 10.1328 -            final String name = compiler.uniqueName(ITERATOR_PREFIX.tag());
 10.1329 -            // DEFINE SYMBOL: may be any type, not local var
 10.1330 -            final Symbol iter = getCurrentFunctionNode().defineSymbol(name, IS_VAR | IS_INTERNAL, null);
 10.1331 -            iter.setType(Type.OBJECT); // NASHORN-73
 10.1332 -            forNode.setIterator(iter);
 10.1333 -            forNode.setModify(convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400
 10.1334 -
 10.1335 -            /*
 10.1336 -             * Iterators return objects, so we need to widen the scope of the
 10.1337 -             * init variable if it, for example, has been assigned double type
 10.1338 -             * see NASHORN-50
 10.1339 -             */
 10.1340 -            forNode.getInit().getSymbol().setType(Type.OBJECT);
 10.1341 -        } else {
 10.1342 -            /* Normal for node, not for in */
 10.1343 -
 10.1344 -            if (init != null) {
 10.1345 -                forNode.setInit(discard(init));
 10.1346 -            }
 10.1347 -
 10.1348 -            if (test != null) {
 10.1349 -                forNode.setTest(convert(test, Type.BOOLEAN));
 10.1350 -            } else {
 10.1351 -                forNode.setHasGoto();
 10.1352 -            }
 10.1353 -
 10.1354 -            if (modify != null) {
 10.1355 -                forNode.setModify(discard(modify));
 10.1356 -            }
 10.1357 -        }
 10.1358 -
 10.1359 -        final Block body = forNode.getBody();
 10.1360 -
 10.1361 -        final boolean escapes = controlFlowEscapes(body);
 10.1362 -        if (escapes) {
 10.1363 -            body.setIsTerminal(false);
 10.1364 -        }
 10.1365 -
 10.1366 -        // pop the loop from the loop context
 10.1367 -        unnest();
 10.1368 -
 10.1369 -        if (!forNode.isForIn() && conservativeAlwaysTrue(test)) {
 10.1370 -            forNode.setTest(null);
 10.1371 -            forNode.setIsTerminal(!escapes);
 10.1372 -        }
 10.1373 -
 10.1374 -        statements.add(forNode);
 10.1375 -
 10.1376 -        return forNode;
 10.1377 -    }
 10.1378 -
 10.1379 -    /**
 10.1380 -     * Initialize this symbol and variable for function node
 10.1381 -     *
 10.1382 -     * @param functionNode the function node
 10.1383 -     */
 10.1384 -    private void initThis(final FunctionNode functionNode) {
 10.1385 -        final long token = functionNode.getToken();
 10.1386 -        final int finish = functionNode.getFinish();
 10.1387 -
 10.1388 -        final Symbol thisSymbol = functionNode.defineSymbol(THIS.tag(), IS_PARAM | IS_THIS, null);
 10.1389 -        final IdentNode thisNode = new IdentNode(source, token, finish, thisSymbol.getName());
 10.1390 -
 10.1391 -        thisSymbol.setType(Type.OBJECT);
 10.1392 -        thisSymbol.setNeedsSlot(true);
 10.1393 -
 10.1394 -        thisNode.setSymbol(thisSymbol);
 10.1395 -
 10.1396 -        functionNode.setThisNode(thisNode);
 10.1397 -    }
 10.1398 -
 10.1399 -    /**
 10.1400 -     * Initialize scope symbol and variable for function node
 10.1401 -     *
 10.1402 -     * @param functionNode the function node
 10.1403 -     */
 10.1404 -    private void initScope(final FunctionNode functionNode) {
 10.1405 -        final long token = functionNode.getToken();
 10.1406 -        final int finish = functionNode.getFinish();
 10.1407 -
 10.1408 -        final Symbol scopeSymbol = functionNode.defineSymbol(SCOPE.tag(), IS_VAR | IS_INTERNAL, null);
 10.1409 -        final IdentNode scopeNode = new IdentNode(source, token, finish, scopeSymbol.getName());
 10.1410 -
 10.1411 -        scopeSymbol.setType(ScriptObject.class);
 10.1412 -        scopeSymbol.setNeedsSlot(true);
 10.1413 -
 10.1414 -        scopeNode.setSymbol(scopeSymbol);
 10.1415 -
 10.1416 -        functionNode.setScopeNode(scopeNode);
 10.1417 -    }
 10.1418 -
 10.1419 -    /**
 10.1420 -     * Initialize return symbol and variable for function node
 10.1421 -     *
 10.1422 -     * @param functionNode the function node
 10.1423 -     */
 10.1424 -    private void initReturn(final FunctionNode functionNode) {
 10.1425 -        final long token = functionNode.getToken();
 10.1426 -        final int finish = functionNode.getFinish();
 10.1427 -
 10.1428 -        final Symbol returnSymbol = functionNode.defineSymbol(SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null);
 10.1429 -        final IdentNode returnNode = new IdentNode(source, token, finish, returnSymbol.getName());
 10.1430 -
 10.1431 -        returnSymbol.setType(Object.class);
 10.1432 -        returnSymbol.setNeedsSlot(true);
 10.1433 -
 10.1434 -        returnNode.setSymbol(returnSymbol);
 10.1435 -
 10.1436 -        functionNode.setResultNode(returnNode);
 10.1437 -    }
 10.1438 -
 10.1439 -    /**
 10.1440 -     * Initialize varargs for function node, if applicable
 10.1441 -     *
 10.1442 -     * @param functionNode
 10.1443 -     */
 10.1444 -    private void initVarArg(final FunctionNode functionNode) {
 10.1445 +    private void initFunctionNode(final FunctionNode functionNode) {
 10.1446          final long token  = functionNode.getToken();
 10.1447          final int  finish = functionNode.getFinish();
 10.1448  
 10.1449 -        assert functionNode.getCalleeNode() != null;
 10.1450 +        LOG.info("Init this, scope, result, callee, varargs and argument for " + functionNode.getName());
 10.1451  
 10.1452 -        final Symbol    varArgsSymbol = functionNode.defineSymbol(VARARGS.tag(), IS_PARAM | IS_INTERNAL, null);
 10.1453 -        final IdentNode varArgsNode   = new IdentNode(source, token, finish, varArgsSymbol.getName());
 10.1454 -
 10.1455 -        varArgsSymbol.setType(Type.OBJECT_ARRAY);
 10.1456 -        varArgsSymbol.setNeedsSlot(true);
 10.1457 -
 10.1458 -        varArgsNode.setSymbol(varArgsSymbol);
 10.1459 -
 10.1460 -        functionNode.setVarArgsNode(varArgsNode);
 10.1461 -
 10.1462 -        final String    argumentsName    = ARGUMENTS.tag();
 10.1463 -        final String    name             = functionNode.hideArguments() ? functionNode.uniqueName("$" + argumentsName) : argumentsName;
 10.1464 -        final Symbol    argumentsSymbol  = functionNode.defineSymbol(name, IS_PARAM | IS_INTERNAL, null);
 10.1465 -        final IdentNode argumentsNode    = new IdentNode(source, token, finish, argumentsSymbol.getName());
 10.1466 -
 10.1467 -        argumentsSymbol.setType(Type.OBJECT);
 10.1468 -        argumentsSymbol.setNeedsSlot(true);
 10.1469 -
 10.1470 -        argumentsNode.setSymbol(argumentsSymbol);
 10.1471 -
 10.1472 -        functionNode.setArgumentsNode(argumentsNode);
 10.1473 +        functionNode.setThisNode(new IdentNode(source, token, finish, THIS.tag()));
 10.1474 +        functionNode.setScopeNode(new IdentNode(source, token, finish, SCOPE.tag()));
 10.1475 +        functionNode.setResultNode(new IdentNode(source, token, finish, SCRIPT_RETURN.tag()));
 10.1476 +        functionNode.setCalleeNode(new IdentNode(source, token, finish, CALLEE.tag()));
 10.1477 +        functionNode.setVarArgsNode(new IdentNode(source, token, finish, VARARGS.tag()));
 10.1478 +        functionNode.setArgumentsNode(new IdentNode(source, token, finish, functionNode.hideArguments() ? compiler.uniqueName('$' + ARGUMENTS.tag()) : ARGUMENTS.tag()));
 10.1479      }
 10.1480  
 10.1481 -    private void initCallee(final FunctionNode functionNode) {
 10.1482 -        if (functionNode.getCalleeNode() != null) {
 10.1483 -            return;
 10.1484 -        }
 10.1485 +}
 10.1486  
 10.1487 -        final long token = functionNode.getToken();
 10.1488 -        final int finish = functionNode.getFinish();
 10.1489  
 10.1490 -        final Symbol    calleeSymbol = functionNode.defineSymbol(CALLEE.tag(), IS_PARAM | IS_INTERNAL, null);
 10.1491 -        final IdentNode calleeNode   = new IdentNode(source, token, finish, calleeSymbol.getName());
 10.1492  
 10.1493 -        calleeSymbol.setType(ScriptFunction.class);
 10.1494 -        calleeSymbol.setNeedsSlot(true);
 10.1495 -
 10.1496 -        calleeNode.setSymbol(calleeSymbol);
 10.1497 -
 10.1498 -        functionNode.setCalleeNode(calleeNode);
 10.1499 -    }
 10.1500 -
 10.1501 -    /**
 10.1502 -     * Initialize parameters for function node. This may require specializing
 10.1503 -     * types if a specialization profile is known
 10.1504 -     *
 10.1505 -     * @param functionNode the function node
 10.1506 -     */
 10.1507 -    private void initParameters(final FunctionNode functionNode) {
 10.1508 -        /*
 10.1509 -         * If a function is specialized, we don't need to tag either it return
 10.1510 -         * type or its parameters with the widest (OBJECT) type for safety.
 10.1511 -         */
 10.1512 -        functionNode.setReturnType(Type.UNKNOWN);
 10.1513 -
 10.1514 -        for (final IdentNode ident : functionNode.getParameters()) {
 10.1515 -            localDefs.add(ident.getName());
 10.1516 -            final Symbol paramSymbol = functionNode.defineSymbol(ident.getName(), IS_PARAM, ident);
 10.1517 -            if (paramSymbol != null) {
 10.1518 -                paramSymbol.setType(Type.UNKNOWN);
 10.1519 -            }
 10.1520 -        }
 10.1521 -    }
 10.1522 -
 10.1523 -    /**
 10.1524 -     * This has to run before fix assignment types, store any type specializations for
 10.1525 -     * paramters, then turn then to objects for the generic version of this method
 10.1526 -     *
 10.1527 -     * @param functionNode functionNode
 10.1528 -     */
 10.1529 -    private static void fixParameters(final FunctionNode functionNode) {
 10.1530 -        boolean nonObjectParams = false;
 10.1531 -        List<Type> paramSpecializations = new ArrayList<>();
 10.1532 -
 10.1533 -        for (final IdentNode ident : functionNode.getParameters()) {
 10.1534 -            final Symbol paramSymbol = ident.getSymbol();
 10.1535 -            if (paramSymbol != null) {
 10.1536 -                Type type = paramSymbol.getSymbolType();
 10.1537 -                if (type.isUnknown()) {
 10.1538 -                    type = Type.OBJECT;
 10.1539 -                }
 10.1540 -                paramSpecializations.add(type);
 10.1541 -                if (!type.isObject()) {
 10.1542 -                    nonObjectParams = true;
 10.1543 -                }
 10.1544 -                paramSymbol.setType(Type.OBJECT);
 10.1545 -            }
 10.1546 -        }
 10.1547 -
 10.1548 -        if (!nonObjectParams) {
 10.1549 -            paramSpecializations = null;
 10.1550 -            /*
 10.1551 -             * Later, when resolving a call to this method, the linker can say "I have a double, an int and an object" as parameters
 10.1552 -             * here. If the callee has parameter specializations, we can regenerate it with those particular types for speed.
 10.1553 -             */
 10.1554 -        } else {
 10.1555 -            LOG.info("parameter specialization possible: " + functionNode.getName() + " " + paramSpecializations);
 10.1556 -        }
 10.1557 -
 10.1558 -        // parameters should not be slots for a vararg function, make sure this is the case
 10.1559 -        if (functionNode.isVarArg()) {
 10.1560 -            for (final IdentNode param : functionNode.getParameters()) {
 10.1561 -                param.getSymbol().setNeedsSlot(false);
 10.1562 -            }
 10.1563 -        }
 10.1564 -    }
 10.1565 -
 10.1566 -    private LiteralNode<Undefined> undefined() {
 10.1567 -        return LiteralNode.newInstance(source, 0, 0, UNDEFINED);
 10.1568 -    }
 10.1569 -
 10.1570 -    private void guaranteeReturn(final FunctionNode functionNode) {
 10.1571 -        Node resultNode;
 10.1572 -
 10.1573 -        if (functionNode.isScript()) {
 10.1574 -            resultNode = functionNode.getResultNode();
 10.1575 -        } else {
 10.1576 -            final Node lastStatement = Node.lastStatement(functionNode.getStatements());
 10.1577 -            if (lastStatement != null && (lastStatement.isTerminal() || lastStatement instanceof ReturnNode)) {
 10.1578 -                return; // return already in place, as it should be for a non-undefined returning function
 10.1579 -            }
 10.1580 -            resultNode = undefined().accept(this);
 10.1581 -        }
 10.1582 -
 10.1583 -        new ReturnNode(source, functionNode.getLastToken(), functionNode.getFinish(), resultNode, null).accept(this);
 10.1584 -
 10.1585 -        functionNode.setReturnType(Type.OBJECT);
 10.1586 -    }
 10.1587 -
 10.1588 -    /**
 10.1589 -     * Fix return types for a node. The return type is the widest of all known
 10.1590 -     * return expressions in the function, and has to be the same for all return
 10.1591 -     * nodes, thus we need to traverse all of them in case some of them must be
 10.1592 -     * upcast
 10.1593 -     *
 10.1594 -     * @param node function node to scan return types for
 10.1595 -     */
 10.1596 -    private void fixReturnTypes(final FunctionNode node) {
 10.1597 -
 10.1598 -        if (node.getReturnType().isUnknown()) {
 10.1599 -            node.setReturnType(Type.OBJECT); // for example, infinite loops
 10.1600 -        }
 10.1601 -
 10.1602 -        node.accept(new NodeVisitor() {
 10.1603 -            @Override
 10.1604 -            public Node enter(final FunctionNode subFunction) {
 10.1605 -                //leave subfunctions alone. their return values are already specialized and should not
 10.1606 -                //be touched.
 10.1607 -                return null;
 10.1608 -            }
 10.1609 -            @Override
 10.1610 -            public Node leave(final ReturnNode returnNode) {
 10.1611 -                if (returnNode.hasExpression()) {
 10.1612 -                    returnNode.setExpression(convert(returnNode.getExpression(), node.getReturnType()));
 10.1613 -                }
 10.1614 -                return returnNode;
 10.1615 -            }
 10.1616 -        });
 10.1617 -    }
 10.1618 -
 10.1619 -    /**
 10.1620 -     * Augment assignments with casts after traversing a function node.
 10.1621 -     * Assignment nodes are special, as they require entire scope for type
 10.1622 -     * inference.
 10.1623 -     *
 10.1624 -     * Consider e.g.
 10.1625 -     *
 10.1626 -     * var x = 18.5; //double
 10.1627 -     * for (...) {
 10.1628 -     *      var y = x; //initially y is inferred to be double y = func(x) //y changes to object, but above assignment is unaware that it needs to be var y = (object)x instaed
 10.1629 -     */
 10.1630 -
 10.1631 -    private void fixAssignmentTypes(final FunctionNode node, final List<Symbol> declaredSymbols) {
 10.1632 -
 10.1633 -        // Make sure all unknown symbols are OBJECT types now. No UNKNOWN may survive lower.
 10.1634 -        for (final Symbol symbol : declaredSymbols) {
 10.1635 -            if (symbol.getSymbolType().isUnknown()) {
 10.1636 -                LOG.finest("fixAssignmentTypes: widening " + symbol + " to object " + symbol + " in " + getCurrentFunctionNode());
 10.1637 -                symbol.setType(Type.OBJECT);
 10.1638 -                symbol.setCanBeUndefined();
 10.1639 -            }
 10.1640 -
 10.1641 -            if (symbol.canBeUndefined()) {
 10.1642 -                /*
 10.1643 -                 * Ideally we'd like to only widen to the narrowest
 10.1644 -                 * possible type that supports local variables, i.e. doubles for
 10.1645 -                 * numerics, but
 10.1646 -                 *
 10.1647 -                 * var x;
 10.1648 -                 *
 10.1649 -                 * if (x !== undefined) do something
 10.1650 -                 *
 10.1651 -                 * x++;
 10.1652 -                 *
 10.1653 -                 * Screws this up, as x is determined to be a double even though
 10.1654 -                 * the use is undefined This can be fixed with better use
 10.1655 -                 * analysis in the IdentNode visitor.
 10.1656 -                 *
 10.1657 -                 * This actually seems to be superseded with calls to ensureTypeNotUnknown
 10.1658 -                 */
 10.1659 -                if (!Type.areEquivalent(symbol.getSymbolType(), Type.OBJECT)) {
 10.1660 -                    debug(symbol + " in " + getCurrentFunctionNode() + " can be undefined. Widening to object");
 10.1661 -                    symbol.setType(Type.OBJECT);
 10.1662 -                }
 10.1663 -            }
 10.1664 -        }
 10.1665 -
 10.1666 -        node.accept(new NodeVisitor() {
 10.1667 -
 10.1668 -            private void fix(final Assignment<? extends Node> assignment) {
 10.1669 -                final Node src  = assignment.getAssignmentSource();
 10.1670 -                final Node dest = assignment.getAssignmentDest();
 10.1671 -
 10.1672 -                if (src == null) {
 10.1673 -                    return;
 10.1674 -                }
 10.1675 -
 10.1676 -                //we don't know about scope yet so this is too conservative. AccessSpecialized will remove casts that are not required
 10.1677 -
 10.1678 -                final Type srcType  = src.getType();
 10.1679 -                Type destType = dest.getType();
 10.1680 -
 10.1681 -                //we can only narrow an operation type if the variable doesn't have a slot
 10.1682 -                if (!dest.getSymbol().hasSlot() && !node.hasDeepWithOrEval()) {
 10.1683 -                    destType = Type.narrowest(((Node)assignment).getWidestOperationType(), destType);
 10.1684 -                }
 10.1685 -
 10.1686 -                if (!Type.areEquivalent(destType, srcType)) {
 10.1687 -                    LOG.finest("fixAssignment " + assignment + " type = " + src.getType() + "=>" + dest.getType());
 10.1688 -                    assignment.setAssignmentSource(convert(src, destType));
 10.1689 -                }
 10.1690 -            }
 10.1691 -
 10.1692 -            private Node checkAssignment(final Node assignNode) {
 10.1693 -                if (!assignNode.isAssignment()) {
 10.1694 -                    return assignNode;
 10.1695 -                }
 10.1696 -                fix((Assignment<?>)assignNode);
 10.1697 -                return assignNode;
 10.1698 -            }
 10.1699 -
 10.1700 -
 10.1701 -            @Override
 10.1702 -            public Node leave(final UnaryNode unaryNode) {
 10.1703 -                return checkAssignment(unaryNode);
 10.1704 -            }
 10.1705 -
 10.1706 -            @Override
 10.1707 -            public Node leave(final BinaryNode binaryNode) {
 10.1708 -                return checkAssignment(binaryNode);
 10.1709 -            }
 10.1710 -
 10.1711 -            @Override
 10.1712 -            public Node leave(final VarNode varNode) {
 10.1713 -                return checkAssignment(varNode);
 10.1714 -            }
 10.1715 -        });
 10.1716 -    }
 10.1717 -
 10.1718 -    /*
 10.1719 -     * For a script, add scope symbols as defined in the property map
 10.1720 -     */
 10.1721 -    private static void initFromPropertyMap(final Context context, final FunctionNode functionNode) {
 10.1722 -        assert functionNode.isScript();
 10.1723 -
 10.1724 -        final PropertyMap map = context.getGlobalMap();
 10.1725 -
 10.1726 -        for (final Property property : map.getProperties()) {
 10.1727 -            final String key = property.getKey();
 10.1728 -            functionNode.defineSymbol(key, IS_GLOBAL, null).setType(Type.OBJECT);
 10.1729 -        }
 10.1730 -    }
 10.1731 -
 10.1732 -    @Override
 10.1733 -    public Node enter(final FunctionNode functionNode) {
 10.1734 -        LOG.info("START FunctionNode: " + functionNode.getName());
 10.1735 -
 10.1736 -        Node initialEvalResult = undefined();
 10.1737 -
 10.1738 -        nest(functionNode);
 10.1739 -
 10.1740 -        localDefs = new HashSet<>();
 10.1741 -        localUses = new HashSet<>();
 10.1742 -
 10.1743 -        functionNode.setFrame(functionNode.pushFrame());
 10.1744 -
 10.1745 -        initThis(functionNode);
 10.1746 -        initCallee(functionNode);
 10.1747 -        if (functionNode.isVarArg()) {
 10.1748 -            initVarArg(functionNode);
 10.1749 -        }
 10.1750 -
 10.1751 -        initParameters(functionNode);
 10.1752 -        initScope(functionNode);
 10.1753 -        initReturn(functionNode);
 10.1754 -
 10.1755 -        /*
 10.1756 -         * Add all nested functions as symbols in this function
 10.1757 -         */
 10.1758 -        for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
 10.1759 -            final IdentNode ident = nestedFunction.getIdent();
 10.1760 -
 10.1761 -            // for initial eval result is the last declared function
 10.1762 -            if (ident != null && nestedFunction.isStatement()) {
 10.1763 -                final Symbol functionSymbol = functionNode.defineSymbol(ident.getName(), IS_VAR, nestedFunction);
 10.1764 -
 10.1765 -                functionSymbol.setType(ScriptFunction.class);
 10.1766 -                initialEvalResult = new IdentNode(ident);
 10.1767 -            }
 10.1768 -        }
 10.1769 -
 10.1770 -        if (functionNode.isScript()) {
 10.1771 -            initFromPropertyMap(compiler.getContext(), functionNode);
 10.1772 -        }
 10.1773 -
 10.1774 -        // Add function name as local symbol
 10.1775 -        if (!functionNode.isStatement() && !functionNode.isAnonymous() && !functionNode.isScript()) {
 10.1776 -            final Symbol selfSymbol = functionNode.defineSymbol(functionNode.getIdent().getName(), IS_VAR, functionNode);
 10.1777 -            selfSymbol.setType(Type.OBJECT);
 10.1778 -            selfSymbol.setNode(functionNode);
 10.1779 -        }
 10.1780 -
 10.1781 -        /*
 10.1782 -         * As we are evaluating a nested structure, we need to store the
 10.1783 -         * statement list for the surrounding block and restore it when the
 10.1784 -         * function is done
 10.1785 -         */
 10.1786 -        final List<Node> savedStatements = statements;
 10.1787 -        statements = new ArrayList<>();
 10.1788 -
 10.1789 -        /*
 10.1790 -         * This pushes all declarations (except for non-statements, i.e. for
 10.1791 -         * node temporaries) to the top of the function scope. This way we can
 10.1792 -         * get around problems like
 10.1793 -         *
 10.1794 -         * while (true) {
 10.1795 -         *   break;
 10.1796 -         *   if (true) {
 10.1797 -         *     var s;
 10.1798 -         *   }
 10.1799 -         * }
 10.1800 -         *
 10.1801 -         * to an arbitrary nesting depth.
 10.1802 -         *
 10.1803 -         * @see NASHORN-73
 10.1804 -         */
 10.1805 -
 10.1806 -        final List<Symbol> declaredSymbols = new ArrayList<>();
 10.1807 -        for (final VarNode decl : functionNode.getDeclarations()) {
 10.1808 -            final IdentNode ident = decl.getName();
 10.1809 -            // any declared symbols that aren't visited need to be typed as
 10.1810 -            // well, hence the list
 10.1811 -            declaredSymbols.add(functionNode.defineSymbol(ident.getName(), IS_VAR, new IdentNode(ident)));
 10.1812 -        }
 10.1813 -
 10.1814 -        declaredSymbolsLocal = new ArrayList<>();
 10.1815 -
 10.1816 -        /*
 10.1817 -         * Main function code lowering
 10.1818 -         */
 10.1819 -        try {
 10.1820 -            /*
 10.1821 -             * Every nested function needs a definition in the outer function
 10.1822 -             * with its name. Add these.
 10.1823 -             */
 10.1824 -            for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
 10.1825 -                final VarNode varNode = nestedFunction.getFunctionVarNode();
 10.1826 -                if (varNode != null) {
 10.1827 -                    final LineNumberNode lineNumberNode = nestedFunction.getFunctionVarLineNumberNode();
 10.1828 -                    if (lineNumberNode != null) {
 10.1829 -                        lineNumberNode.accept(this);
 10.1830 -                    }
 10.1831 -                    varNode.accept(this);
 10.1832 -                    varNode.setIsFunctionVarNode();
 10.1833 -                }
 10.1834 -            }
 10.1835 -
 10.1836 -            if (functionNode.isScript()) {
 10.1837 -                new ExecuteNode(source, functionNode.getFirstToken(), functionNode.getFinish(), initialEvalResult).accept(this);
 10.1838 -            }
 10.1839 -
 10.1840 -            /*
 10.1841 -             * Now we do the statements. This fills the block with code
 10.1842 -             */
 10.1843 -            for (final Node statement : functionNode.getStatements()) {
 10.1844 -                statement.accept(this);
 10.1845 -
 10.1846 -                final Node lastStatement = Node.lastStatement(statements);
 10.1847 -                if (lastStatement != null && lastStatement.hasTerminalFlags()) {
 10.1848 -                    functionNode.copyTerminalFlags(lastStatement);
 10.1849 -                    break;
 10.1850 -                }
 10.1851 -            }
 10.1852 -
 10.1853 -            functionNode.setStatements(statements);
 10.1854 -
 10.1855 -            /*
 10.1856 -             * If there are unusedterminated enpoints in the function, we need
 10.1857 -             * to add a "return undefined" in those places for correct semantics
 10.1858 -             */
 10.1859 -            if (!functionNode.isTerminal()) {
 10.1860 -                guaranteeReturn(functionNode);
 10.1861 -            }
 10.1862 -
 10.1863 -            /*
 10.1864 -             * Emit all nested functions
 10.1865 -             */
 10.1866 -            for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
 10.1867 -                nestedFunction.accept(this);
 10.1868 -            }
 10.1869 -
 10.1870 -            fixReturnTypes(functionNode);
 10.1871 -
 10.1872 -            if (functionNode.needsSelfSymbol()) {
 10.1873 -                final IdentNode selfSlotNode = new IdentNode(functionNode.getIdent());
 10.1874 -                selfSlotNode.setSymbol(functionNode.findSymbol(functionNode.getIdent().getName()));
 10.1875 -                final Node functionRef = new IdentNode(functionNode.getCalleeNode());
 10.1876 -                statements.add(0, new VarNode(source, functionNode.getToken(), functionNode.getFinish(), selfSlotNode, functionRef, false).accept(this));
 10.1877 -            }
 10.1878 -        } finally {
 10.1879 -            /*
 10.1880 -             * Restore statement for outer block that we were working on
 10.1881 -             */
 10.1882 -            statements = savedStatements;
 10.1883 -        }
 10.1884 -
 10.1885 -        unnest();
 10.1886 -
 10.1887 -        fixParameters(functionNode);
 10.1888 -
 10.1889 -        /*
 10.1890 -         * Fix assignment issues. assignments are troublesome as they can be on
 10.1891 -         * the form "dest = dest op source" where the type is different for the
 10.1892 -         * two dest:s: right now this is a post pass that handles putting casts
 10.1893 -         * in the correct places, but it can be implemented as a bottom up AST
 10.1894 -         * traversal on the fly. TODO.
 10.1895 -         */
 10.1896 -        fixAssignmentTypes(functionNode, declaredSymbols);
 10.1897 -
 10.1898 -        /*
 10.1899 -         * Set state of function to lowered and pop the frame
 10.1900 -         */
 10.1901 -        functionNode.setIsLowered(true);
 10.1902 -        functionNode.popFrame();
 10.1903 -
 10.1904 -        LOG.info("END FunctionNode: " + functionNode.getName());
 10.1905 -
 10.1906 -        return null;
 10.1907 -    }
 10.1908 -
 10.1909 -    @Override
 10.1910 -    public Node enter(final IdentNode identNode) {
 10.1911 -        final String name = identNode.getName();
 10.1912 -
 10.1913 -        if (identNode.isPropertyName()) {
 10.1914 -            // assign a pseudo symbol to property name
 10.1915 -            identNode.setSymbol(new Symbol(name, 0, Type.OBJECT));
 10.1916 -            return null;
 10.1917 -        }
 10.1918 -
 10.1919 -        final Block block = getCurrentBlock();
 10.1920 -        final Symbol oldSymbol = identNode.getSymbol();
 10.1921 -        Symbol symbol = block.findSymbol(name);
 10.1922 -
 10.1923 -        /*
 10.1924 -         * If an existing symbol with the name is found, use that otherwise,
 10.1925 -         * declare a new one
 10.1926 -         */
 10.1927 -
 10.1928 -        if (symbol != null) {
 10.1929 -            if (isFunctionExpressionSelfReference(symbol)) {
 10.1930 -                ((FunctionNode) symbol.getNode()).setNeedsSelfSymbol();
 10.1931 -            }
 10.1932 -
 10.1933 -            if (!identNode.isInitializedHere()) { // NASHORN-448
 10.1934 -                // here is a use outside the local def scope
 10.1935 -                if (!localDefs.contains(name)) {
 10.1936 -                    symbol.setType(Type.OBJECT);
 10.1937 -                    symbol.setCanBeUndefined();
 10.1938 -                }
 10.1939 -            }
 10.1940 -
 10.1941 -            identNode.setSymbol(symbol);
 10.1942 -            if (!getCurrentFunctionNode().isLocal(symbol)) {
 10.1943 -                // non-local: we need to put symbol in scope (if it isn't already)
 10.1944 -                if (!symbol.isScope()) {
 10.1945 -                    final List<Block> lookupBlocks = findLookupBlocksHelper(getCurrentFunctionNode(), symbol.findFunction());
 10.1946 -                    for (final Block lookupBlock : lookupBlocks) {
 10.1947 -                        final Symbol refSymbol = lookupBlock.findSymbol(name);
 10.1948 -                        if (refSymbol != null) { // See NASHORN-837, function declaration in lexical scope: try {} catch (x){ function f() { use(x) } } f()
 10.1949 -                            LOG.finest("Found a ref symbol that must be scope " + refSymbol);
 10.1950 -                            refSymbol.setIsScope();
 10.1951 -                        }
 10.1952 -                    }
 10.1953 -                }
 10.1954 -            }
 10.1955 -        } else {
 10.1956 -            symbol = block.useSymbol(name, identNode);
 10.1957 -            // we have never seen this before, it can be undefined
 10.1958 -            symbol.setType(Type.OBJECT); // TODO unknown -we have explicit casts anyway?
 10.1959 -            symbol.setCanBeUndefined();
 10.1960 -        }
 10.1961 -
 10.1962 -        if (symbol != oldSymbol && !identNode.isInitializedHere()) {
 10.1963 -            symbol.increaseUseCount();
 10.1964 -        }
 10.1965 -        localUses.add(identNode.getName());
 10.1966 -
 10.1967 -        return null;
 10.1968 -    }
 10.1969 -
 10.1970 -    private static List<Block> findLookupBlocksHelper(final FunctionNode currentFunction, final FunctionNode topFunction) {
 10.1971 -        if (currentFunction.findParentFunction() == topFunction) {
 10.1972 -            final List<Block> blocks = new LinkedList<>();
 10.1973 -
 10.1974 -            blocks.add(currentFunction.getParent());
 10.1975 -            blocks.addAll(currentFunction.getReferencingParentBlocks());
 10.1976 -            return blocks;
 10.1977 -        }
 10.1978 -        /**
 10.1979 -         * assumption: all parent blocks of an inner function will always be in the same outer function;
 10.1980 -         * therefore we can simply skip through intermediate functions.
 10.1981 -         * @see FunctionNode#addReferencingParentBlock(Block)
 10.1982 -         */
 10.1983 -        return findLookupBlocksHelper(currentFunction.findParentFunction(), topFunction);
 10.1984 -    }
 10.1985 -
 10.1986 -    private static boolean isFunctionExpressionSelfReference(final Symbol symbol) {
 10.1987 -        if (symbol.isVar() && symbol.getNode() == symbol.getBlock() && symbol.getNode() instanceof FunctionNode) {
 10.1988 -            return ((FunctionNode) symbol.getNode()).getIdent().getName().equals(symbol.getName());
 10.1989 -        }
 10.1990 -        return false;
 10.1991 -    }
 10.1992 -
 10.1993 -    @Override
 10.1994 -    public Node enter(final IfNode ifNode) {
 10.1995 -        nest(ifNode);
 10.1996 -        return ifNode;
 10.1997 -    }
 10.1998 -
 10.1999 -    @Override
 10.2000 -    public Node leave(final IfNode ifNode) {
 10.2001 -
 10.2002 -        final Node test = convert(ifNode.getTest(), Type.BOOLEAN);
 10.2003 -
 10.2004 -        /*
 10.2005 -         * constant if checks should short circuit into just one of the
 10.2006 -         * pass/fail blocks
 10.2007 -         */
 10.2008 -        if (test.getSymbol().isConstant()) {
 10.2009 -            assert test instanceof LiteralNode<?>;
 10.2010 -            final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
 10.2011 -            if (shortCut != null) {
 10.2012 -                for (final Node statement : shortCut.getStatements()) {
 10.2013 -                    statements.add(statement);
 10.2014 -                }
 10.2015 -            }
 10.2016 -            return null;
 10.2017 -        }
 10.2018 -
 10.2019 -        final Node pass = ifNode.getPass();
 10.2020 -        final Node fail = ifNode.getFail();
 10.2021 -
 10.2022 -        if (pass.isTerminal() && fail != null && fail.isTerminal()) {
 10.2023 -            ifNode.setIsTerminal(true);
 10.2024 -        }
 10.2025 -
 10.2026 -        ifNode.setTest(test);
 10.2027 -        statements.add(ifNode);
 10.2028 -
 10.2029 -        unnest();
 10.2030 -
 10.2031 -        return ifNode;
 10.2032 -    }
 10.2033 -
 10.2034 -    @Override
 10.2035 -    public Node leave(final IndexNode indexNode) {
 10.2036 -        getCurrentFunctionNode().newTemporary(Type.OBJECT, indexNode);
 10.2037 -
 10.2038 -        return indexNode;
 10.2039 -    }
 10.2040 -
 10.2041 -    @Override
 10.2042 -    public Node enter(final LabelNode labeledNode) {
 10.2043 -        // Don't want a symbol for label.
 10.2044 -        final Block body = labeledNode.getBody();
 10.2045 -        body.accept(this);
 10.2046 -        labeledNode.copyTerminalFlags(body);
 10.2047 -        statements.add(labeledNode);
 10.2048 -
 10.2049 -        return null;
 10.2050 -    }
 10.2051 -
 10.2052 -    @Override
 10.2053 -    public Node enter(final LineNumberNode lineNumberNode) {
 10.2054 -        statements.add(lineNumberNode);
 10.2055 -        return null;
 10.2056 -    }
 10.2057 -
 10.2058 -    /**
 10.2059 -     * Generate a new literal symbol.
 10.2060 -     *
 10.2061 -     * @param literalNode LiteralNode needing symbol.
 10.2062 -     * @return The literal node augmented with the symbol
 10.2063 -     */
 10.2064 -    private LiteralNode<?> newLiteral(final LiteralNode<?> literalNode) {
 10.2065 -        return newLiteral(getCurrentFunctionNode(), literalNode);
 10.2066 -    }
 10.2067 -
 10.2068 -    private static LiteralNode<?> newLiteral(final FunctionNode functionNode, final LiteralNode<?> literalNode) {
 10.2069 -        functionNode.newLiteral(literalNode);
 10.2070 -        return literalNode;
 10.2071 -    }
 10.2072 -
 10.2073 -    @SuppressWarnings("rawtypes")
 10.2074 -    @Override
 10.2075 -    public Node enter(final LiteralNode literalNode) {
 10.2076 -        if (literalNode.isTokenType(TokenType.THIS)) {
 10.2077 -            literalNode.setSymbol(getCurrentFunctionNode().getThisNode().getSymbol());
 10.2078 -            return null;
 10.2079 -        }
 10.2080 -
 10.2081 -        if (literalNode instanceof ArrayLiteralNode) {
 10.2082 -            final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
 10.2083 -            final Node[] array = arrayLiteralNode.getValue();
 10.2084 -
 10.2085 -            for (int i = 0; i < array.length; i++) {
 10.2086 -                final Node element = array[i];
 10.2087 -                if (element != null) {
 10.2088 -                    array[i] = array[i].accept(this);
 10.2089 -                }
 10.2090 -            }
 10.2091 -
 10.2092 -            arrayLiteralNode.analyze();
 10.2093 -            final Type elementType = arrayLiteralNode.getElementType();
 10.2094 -
 10.2095 -            // we only have types after all elements are accepted
 10.2096 -            for (int i = 0; i < array.length; i++) {
 10.2097 -                final Node element = array[i];
 10.2098 -                if (element != null) {
 10.2099 -                    array[i] = convert(element, elementType);
 10.2100 -                }
 10.2101 -            }
 10.2102 -        } else {
 10.2103 -            final Object value = literalNode.getValue();
 10.2104 -
 10.2105 -            if (value instanceof Node) {
 10.2106 -                final Node node = ((Node)value).accept(this);
 10.2107 -                if (node != null) {
 10.2108 -                    return newLiteral(LiteralNode.newInstance(source, node.getToken(), node.getFinish(), node));
 10.2109 -                }
 10.2110 -            }
 10.2111 -        }
 10.2112 -
 10.2113 -        newLiteral(literalNode);
 10.2114 -
 10.2115 -        return null;
 10.2116 -    }
 10.2117 -
 10.2118 -    @Override
 10.2119 -    public Node leave(final ObjectNode objectNode) {
 10.2120 -        getCurrentFunctionNode().newTemporary(Type.OBJECT, objectNode);
 10.2121 -        return objectNode;
 10.2122 -    }
 10.2123 -
 10.2124 -    @Override
 10.2125 -    public Node enter(final PropertyNode propertyNode) {
 10.2126 -        // assign a pseudo symbol to property name, see NASHORN-710
 10.2127 -        propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
 10.2128 -        return propertyNode;
 10.2129 -    }
 10.2130 -
 10.2131 -    @Override
 10.2132 -    public Node enter(final ReferenceNode referenceNode) {
 10.2133 -        final FunctionNode functionNode = referenceNode.getReference();
 10.2134 -        if (functionNode != null) {
 10.2135 -            functionNode.addReferencingParentBlock(getCurrentBlock());
 10.2136 -        }
 10.2137 -        return referenceNode;
 10.2138 -    }
 10.2139 -
 10.2140 -    @Override
 10.2141 -    public Node leave(final ReferenceNode referenceNode) {
 10.2142 -        getCurrentFunctionNode().newTemporary(Type.OBJECT, referenceNode);
 10.2143 -        return referenceNode;
 10.2144 -    }
 10.2145 -
 10.2146 -    /**
 10.2147 -     * For each return node we need to set a return expression of the correct
 10.2148 -     * type. In the non-specializing world, we can always upcast to object and
 10.2149 -     * ignore the rest, but in the specializing world we have to keep track of
 10.2150 -     * the widest return type so far, which is the common one for this method.
 10.2151 -     *
 10.2152 -     * @param returnNode  the return node we are generating
 10.2153 -     * @param expression  the expression to return from this code
 10.2154 -     */
 10.2155 -    private void setReturnExpression(final ReturnNode returnNode, final Node expression) {
 10.2156 -        final FunctionNode functionNode = getCurrentFunctionNode();
 10.2157 -
 10.2158 -        returnNode.setExpression(expression);
 10.2159 -
 10.2160 -        final Symbol symbol = expression.getSymbol();
 10.2161 -        if (expression.getType().isUnknown() && symbol.isParam()) {
 10.2162 -            symbol.setType(Type.OBJECT);
 10.2163 -        }
 10.2164 -        functionNode.setReturnType(Type.widest(expression.getType(), functionNode.getReturnType()));
 10.2165 -    }
 10.2166 -
 10.2167 -    @Override
 10.2168 -    public Node enter(final ReturnNode returnNode) {
 10.2169 -        final TryNode tryNode = returnNode.getTryChain();
 10.2170 -        final Node expression = returnNode.getExpression();
 10.2171 -
 10.2172 -        if (tryNode != null) {
 10.2173 -            if (expression != null) {
 10.2174 -                final long token = returnNode.getToken();
 10.2175 -                final Node resultNode = getCurrentFunctionNode().getResultNode();
 10.2176 -                new ExecuteNode(source, token, Token.descPosition(token), new BinaryNode(source, Token.recast(token, TokenType.ASSIGN), resultNode, expression)).accept(this);
 10.2177 -
 10.2178 -                if (copyFinally(tryNode, null)) {
 10.2179 -                    return null;
 10.2180 -                }
 10.2181 -
 10.2182 -                setReturnExpression(returnNode, resultNode);
 10.2183 -            } else if (copyFinally(tryNode, null)) {
 10.2184 -                return null;
 10.2185 -            }
 10.2186 -        } else if (expression != null) {
 10.2187 -            setReturnExpression(returnNode, expression.accept(this));
 10.2188 -        }
 10.2189 -
 10.2190 -        statements.add(returnNode);
 10.2191 -
 10.2192 -        return null;
 10.2193 -    }
 10.2194 -
 10.2195 -    @Override
 10.2196 -    public Node leave(final RuntimeNode runtimeNode) {
 10.2197 -        for (final Node arg : runtimeNode.getArgs()) {
 10.2198 -            ensureTypeNotUnknown(arg);
 10.2199 -        }
 10.2200 -
 10.2201 -        getCurrentFunctionNode().newTemporary(runtimeNode.getRequest().getReturnType(), runtimeNode);
 10.2202 -
 10.2203 -        return runtimeNode;
 10.2204 -    }
 10.2205 -
 10.2206 -    @Override
 10.2207 -    public Node enter(final SwitchNode switchNode) {
 10.2208 -        nest(switchNode);
 10.2209 -        return switchNode;
 10.2210 -    }
 10.2211 -
 10.2212 -    @Override
 10.2213 -    public Node leave(final SwitchNode switchNode) {
 10.2214 -        unnest();
 10.2215 -
 10.2216 -        final Node           expression  = switchNode.getExpression();
 10.2217 -        final List<CaseNode> cases       = switchNode.getCases();
 10.2218 -        final CaseNode       defaultCase = switchNode.getDefaultCase();
 10.2219 -        final boolean        hasDefault  = defaultCase != null;
 10.2220 -        final int            n           =  cases.size() + (hasDefault ? -1 : 0);
 10.2221 -
 10.2222 -        boolean allTerminal = !cases.isEmpty();
 10.2223 -        boolean allInteger  = n > 1;
 10.2224 -
 10.2225 -        for (final CaseNode caseNode : cases) {
 10.2226 -            allTerminal &= caseNode.isTerminal();
 10.2227 -            final Node test = caseNode.getTest();
 10.2228 -
 10.2229 -            // Skip default.
 10.2230 -            if (test == null) {
 10.2231 -                continue;
 10.2232 -            }
 10.2233 -
 10.2234 -            // If not a number.
 10.2235 -            if (!(test instanceof LiteralNode) || !test.getType().isNumeric()) {
 10.2236 -                allInteger = false;
 10.2237 -                continue;
 10.2238 -            }
 10.2239 -
 10.2240 -            final LiteralNode<?> testLiteral = (LiteralNode<?>)test;
 10.2241 -
 10.2242 -            // If a potential integer.
 10.2243 -            if (!(testLiteral.getValue() instanceof Integer)) {
 10.2244 -                // If not an integer value.
 10.2245 -                if (!JSType.isRepresentableAsInt(testLiteral.getNumber())) {
 10.2246 -                    allInteger = false;
 10.2247 -                    continue;
 10.2248 -                }
 10.2249 -
 10.2250 -                // Guarantee all case literals are Integers (simplifies sorting in code gen.)
 10.2251 -                caseNode.setTest(newLiteral(LiteralNode.newInstance(source, testLiteral.getToken(), testLiteral.getFinish(), testLiteral.getInt32())));
 10.2252 -            }
 10.2253 -        }
 10.2254 -
 10.2255 -        if (allTerminal && defaultCase != null && defaultCase.isTerminal()) {
 10.2256 -            switchNode.setIsTerminal(true);
 10.2257 -        }
 10.2258 -
 10.2259 -        if (!allInteger) {
 10.2260 -            switchNode.setExpression(convert(expression, Type.OBJECT));
 10.2261 -
 10.2262 -            for (final CaseNode caseNode : cases) {
 10.2263 -                final Node test = caseNode.getTest();
 10.2264 -
 10.2265 -                if (test != null) {
 10.2266 -                    caseNode.setTest(convert(test, Type.OBJECT));
 10.2267 -                }
 10.2268 -            }
 10.2269 -        }
 10.2270 -
 10.2271 -        final String name = compiler.uniqueName(SWITCH_TAG_PREFIX.tag());
 10.2272 -        final Symbol tag  = getCurrentFunctionNode().defineSymbol(name, IS_VAR | IS_INTERNAL, null);
 10.2273 -
 10.2274 -        tag.setType(allInteger ? Type.INT : Type.OBJECT);
 10.2275 -        switchNode.setTag(tag);
 10.2276 -
 10.2277 -        statements.add(switchNode);
 10.2278 -
 10.2279 -        return switchNode;
 10.2280 -    }
 10.2281 -
 10.2282 -    @Override
 10.2283 -    public Node leave(final ThrowNode throwNode) {
 10.2284 -        throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT));
 10.2285 -        statements.add(throwNode);
 10.2286 -
 10.2287 -        return throwNode;
 10.2288 -    }
 10.2289 -
 10.2290 -    @Override
 10.2291 -    public Node enter(final TryNode tryNode) {
 10.2292 -        final Block  finallyBody   = tryNode.getFinallyBody();
 10.2293 -        final Source tryNodeSource = tryNode.getSource();
 10.2294 -        final long   token         = tryNode.getToken();
 10.2295 -        final int    finish        = tryNode.getFinish();
 10.2296 -
 10.2297 -        nest(tryNode);
 10.2298 -
 10.2299 -        if (finallyBody == null) {
 10.2300 -            return tryNode;
 10.2301 -        }
 10.2302 -
 10.2303 -        /**
 10.2304 -         * We have a finally clause.
 10.2305 -         *
 10.2306 -         * Transform to do finally tail duplication as follows:
 10.2307 -         *
 10.2308 -         * <pre>
 10.2309 -         *  try {
 10.2310 -         *    try_body
 10.2311 -         *  } catch e1 {
 10.2312 -         *    catchbody_1
 10.2313 -         *  }
 10.2314 -         *  ...
 10.2315 -         *  } catch en {
 10.2316 -         *    catchbody_n
 10.2317 -         *  } finally {
 10.2318 -         *    finally_body
 10.2319 -         *  }
 10.2320 -         *
 10.2321 -         *  (where e1 ... en are optional)
 10.2322 -         *
 10.2323 -         *  turns into
 10.2324 -         *
 10.2325 -         *  try {
 10.2326 -         *    try {
 10.2327 -         *      try_body
 10.2328 -         *    } catch e1 {
 10.2329 -         *      catchbody1
 10.2330 -         *      //nothing inlined explicitly here, return, break other
 10.2331 -         *      //terminals may inline the finally body
 10.2332 -         *      ...
 10.2333 -         *    } catch en {
 10.2334 -         *      catchbody2
 10.2335 -         *      //nothing inlined explicitly here, return, break other
 10.2336 -         *      //terminals may inline the finally body
 10.2337 -         *    }
 10.2338 -         *  } catch all ex {
 10.2339 -         *      finally_body_inlined
 10.2340 -         *      rethrow ex
 10.2341 -         *  }
 10.2342 -         *  finally_body_inlined
 10.2343 -         * </pre>
 10.2344 -         *
 10.2345 -         * If tries are catches are terminal, visitors for return, break &
 10.2346 -         * continue will handle the tail duplications. Throw needs to be
 10.2347 -         * treated specially with the catchall as described in the above
 10.2348 -         * ASCII art.
 10.2349 -         *
 10.2350 -         * If the try isn't terminal we do the finally_body_inlined at the
 10.2351 -         * end. If the try is terminated with continue/break/return the
 10.2352 -         * existing visitor logic will inline the finally before that
 10.2353 -         * operation. if the try is terminated with a throw, the catches e1
 10.2354 -         * ... en will have a chance to process the exception. If the
 10.2355 -         * appropriate catch e1..en is non terminal we fall through to the
 10.2356 -         * last finally_body_inlined. if the catch e1...en IS terminal with
 10.2357 -         * continue/break/return existing visitor logic will fix it. If they
 10.2358 -         * are terminal with another throw it goes to the catchall and the
 10.2359 -         * finally_body_inlined marked (*) will fix it before rethrowing
 10.2360 -         * whatever problem there was for identical semantic.
 10.2361 -         */
 10.2362 -
 10.2363 -        // if try node does not contain a catch we can skip creation of a new
 10.2364 -        // try node and just append our synthetic catch to the existing try node.
 10.2365 -        if (!tryNode.getCatchBlocks().isEmpty()) {
 10.2366 -            // insert an intermediate try-catch* node, where we move the body and all catch blocks.
 10.2367 -            // the original try node become a try-finally container for the new try-catch* node.
 10.2368 -            // because we don't clone (to avoid deep copy), we have to fix the block chain in the end.
 10.2369 -            final TryNode innerTryNode = new TryNode(tryNodeSource, token, finish, tryNode.getNext());
 10.2370 -            innerTryNode.setBody(tryNode.getBody());
 10.2371 -            innerTryNode.setCatchBlocks(tryNode.getCatchBlocks());
 10.2372 -
 10.2373 -            // set outer tryNode's body to innerTryNode
 10.2374 -            final Block outerBody = new Block(tryNodeSource, token, finish, tryNode.getBody().getParent(), getCurrentFunctionNode());
 10.2375 -            outerBody.setStatements(new ArrayList<Node>(Arrays.asList(innerTryNode)));
 10.2376 -            tryNode.setBody(outerBody);
 10.2377 -            tryNode.setCatchBlocks(null);
 10.2378 -
 10.2379 -            // now before we go on, we have to fix the block parents
 10.2380 -            // (we repair the block tree after the insertion so that all references are intact)
 10.2381 -            innerTryNode.getBody().setParent(tryNode.getBody());
 10.2382 -            for (final Block block : innerTryNode.getCatchBlocks()) {
 10.2383 -                block.setParent(tryNode.getBody());
 10.2384 -            }
 10.2385 -        }
 10.2386 -
 10.2387 -        // create a catch-all that inlines finally and rethrows
 10.2388 -        final String name = compiler.uniqueName(EXCEPTION_PREFIX.tag());
 10.2389 -
 10.2390 -        final IdentNode exception = new IdentNode(tryNodeSource, token, finish, name);
 10.2391 -        exception.accept(this);
 10.2392 -
 10.2393 -        final Block catchBlock      = new Block(tryNodeSource, token, finish, getCurrentBlock(), getCurrentFunctionNode());
 10.2394 -        final Block catchBody       = new Block(tryNodeSource, token, finish, catchBlock, getCurrentFunctionNode());
 10.2395 -        final Node  catchAllFinally = finallyBody.clone();
 10.2396 -
 10.2397 -        catchBody.addStatement(new ExecuteNode(tryNodeSource, finallyBody.getToken(), finallyBody.getFinish(), catchAllFinally));
 10.2398 -        catchBody.setIsTerminal(true);
 10.2399 -
 10.2400 -        final CatchNode catchNode = new CatchNode(tryNodeSource, token, finish, new IdentNode(exception), null, catchBody);
 10.2401 -        catchNode.setIsSyntheticRethrow();
 10.2402 -        catchBlock.addStatement(catchNode);
 10.2403 -
 10.2404 -        // replace all catches of outer tryNode with the catch-all
 10.2405 -        tryNode.setCatchBlocks(new ArrayList<>(Arrays.asList(catchBlock)));
 10.2406 -
 10.2407 -        /*
 10.2408 -         * We leave the finally block for the original try in place for now
 10.2409 -         * so that children visitations will work. It is removed and placed
 10.2410 -         * afterwards in the else case below, after all children are visited
 10.2411 -         */
 10.2412 -
 10.2413 -        return tryNode;
 10.2414 -    }
 10.2415 -
 10.2416 -    @Override
 10.2417 -    public Node leave(final TryNode tryNode) {
 10.2418 -        final Block finallyBody   = tryNode.getFinallyBody();
 10.2419 -
 10.2420 -        boolean allTerminal = tryNode.getBody().isTerminal() && (finallyBody == null || finallyBody.isTerminal());
 10.2421 -
 10.2422 -        for (final Block catchBlock : tryNode.getCatchBlocks()) {
 10.2423 -            allTerminal &= catchBlock.isTerminal();
 10.2424 -        }
 10.2425 -
 10.2426 -        tryNode.setIsTerminal(allTerminal);
 10.2427 -
 10.2428 -        final String name      = compiler.uniqueName(EXCEPTION_PREFIX.tag());
 10.2429 -        final Symbol exception = getCurrentFunctionNode().defineSymbol(name, IS_VAR | IS_INTERNAL, null);
 10.2430 -
 10.2431 -        exception.setType(ECMAException.class);
 10.2432 -        tryNode.setException(exception);
 10.2433 -
 10.2434 -        statements.add(tryNode);
 10.2435 -
 10.2436 -        unnest();
 10.2437 -
 10.2438 -        // if finally body is present, place it after the tryNode
 10.2439 -        if (finallyBody != null) {
 10.2440 -            tryNode.setFinallyBody(null);
 10.2441 -            statements.add(finallyBody);
 10.2442 -        }
 10.2443 -
 10.2444 -        return tryNode;
 10.2445 -    }
 10.2446 -
 10.2447 -    @Override
 10.2448 -    public Node enter(final VarNode varNode) {
 10.2449 -        final IdentNode ident = varNode.getName();
 10.2450 -        final String    name  = ident.getName();
 10.2451 -
 10.2452 -        final Symbol symbol = getCurrentBlock().defineSymbol(name, IS_VAR, ident);
 10.2453 -        assert symbol != null;
 10.2454 -
 10.2455 -        varNode.setSymbol(symbol);
 10.2456 -        declaredSymbolsLocal.add(symbol);
 10.2457 -
 10.2458 -        // NASHORN-467 - use before definition of vars - conservative
 10.2459 -        if (localUses.contains(ident.getName())) {
 10.2460 -            symbol.setType(Type.OBJECT);
 10.2461 -            symbol.setCanBeUndefined();
 10.2462 -        }
 10.2463 -
 10.2464 -        return varNode;
 10.2465 -    }
 10.2466 -
 10.2467 -    private static boolean isScopeOrGlobal(final Symbol symbol) {
 10.2468 -        return symbol.getBlock().getFunction().isScript(); //we can't do explicit isScope checks as early as lower, which is why AccessSpecializer is afterwards as well.
 10.2469 -    }
 10.2470 -
 10.2471 -    @Override
 10.2472 -    public Node leave(final VarNode varNode) {
 10.2473 -        final Node      init  = varNode.getInit();
 10.2474 -        final IdentNode ident = varNode.getName();
 10.2475 -        final String    name  = ident.getName();
 10.2476 -
 10.2477 -        if (init != null) {
 10.2478 -            localDefs.add(name);
 10.2479 -        }
 10.2480 -
 10.2481 -        if (varNode.shouldAppend()) {
 10.2482 -            statements.add(varNode);
 10.2483 -        }
 10.2484 -
 10.2485 -        if (init == null) {
 10.2486 -            // var x; with no init will be treated like a use of x by
 10.2487 -            // visit(IdentNode) unless we remove the name
 10.2488 -            // from the localdef list.
 10.2489 -            localDefs.remove(name);
 10.2490 -            return varNode;
 10.2491 -        }
 10.2492 -
 10.2493 -        final Symbol symbol = varNode.getSymbol();
 10.2494 -        if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScopeOrGlobal(symbol)) { //see NASHORN-56
 10.2495 -            // Forbid integers as local vars for now as we have no way to treat them as undefined
 10.2496 -            final Type type = Compiler.shouldUseIntegers() ? init.getType() : Type.NUMBER;
 10.2497 -            varNode.setInit(convert(init, type));
 10.2498 -            symbol.setType(type);
 10.2499 -        } else {
 10.2500 -            symbol.setType(Type.OBJECT); // var x = obj;, x is an "object" //TODO too conservative now?
 10.2501 -        }
 10.2502 -
 10.2503 -        return varNode;
 10.2504 -    }
 10.2505 -
 10.2506 -    @Override
 10.2507 -    public Node enter(final WhileNode whileNode) {
 10.2508 -        // push the loop to the loop context
 10.2509 -        nest(whileNode);
 10.2510 -
 10.2511 -        return whileNode;
 10.2512 -    }
 10.2513 -
 10.2514 -    @Override
 10.2515 -    public Node leave(final WhileNode whileNode) {
 10.2516 -        final Node test = whileNode.getTest();
 10.2517 -
 10.2518 -        if (test != null) {
 10.2519 -            whileNode.setTest(convert(test, Type.BOOLEAN));
 10.2520 -        } else {
 10.2521 -            whileNode.setHasGoto();
 10.2522 -        }
 10.2523 -
 10.2524 -        Node returnNode = whileNode;
 10.2525 -
 10.2526 -        final Block   body    = whileNode.getBody();
 10.2527 -        final boolean escapes = controlFlowEscapes(body);
 10.2528 -        if (escapes) {
 10.2529 -            body.setIsTerminal(false);
 10.2530 -        }
 10.2531 -
 10.2532 -        if (body.isTerminal()) {
 10.2533 -            if (whileNode instanceof DoWhileNode) {
 10.2534 -                whileNode.setIsTerminal(true);
 10.2535 -            } else if (conservativeAlwaysTrue(test)) {
 10.2536 -                returnNode = new ForNode(source, whileNode.getToken(), whileNode.getFinish());
 10.2537 -                ((ForNode)returnNode).setBody(body);
 10.2538 -                returnNode.setIsTerminal(!escapes);
 10.2539 -            }
 10.2540 -        }
 10.2541 -
 10.2542 -        // pop the loop from the loop context
 10.2543 -        unnest();
 10.2544 -        statements.add(returnNode);
 10.2545 -
 10.2546 -        return returnNode;
 10.2547 -    }
 10.2548 -
 10.2549 -    @Override
 10.2550 -    public Node leave(final WithNode withNode) {
 10.2551 -        withNode.setExpression(convert(withNode.getExpression(), Type.OBJECT));
 10.2552 -
 10.2553 -        if (withNode.getBody().isTerminal()) {
 10.2554 -            withNode.setIsTerminal(true);
 10.2555 -        }
 10.2556 -
 10.2557 -        statements.add(withNode);
 10.2558 -
 10.2559 -        return withNode;
 10.2560 -    }
 10.2561 -
 10.2562 -    /*
 10.2563 -     * Unary visits.
 10.2564 -     */
 10.2565 -
 10.2566 -    /**
 10.2567 -     * Visit unary node and set symbols and inferred type
 10.2568 -     *
 10.2569 -     * @param unaryNode  unary node to visit
 10.2570 -     * @param type       The narrowest allowed type for this node
 10.2571 -     *
 10.2572 -     * @return the final node, or replacement thereof
 10.2573 -     */
 10.2574 -    public Node leaveUnary(final UnaryNode unaryNode, final Type type) {
 10.2575 -        /* Try to eliminate the unary node if the expression is constant */
 10.2576 -        final LiteralNode<?> literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval();
 10.2577 -        if (literalNode != null) {
 10.2578 -            return newLiteral(literalNode);
 10.2579 -        }
 10.2580 -
 10.2581 -        /* Add explicit conversion */
 10.2582 -        unaryNode.setRHS(convert(unaryNode.rhs(), type));
 10.2583 -        getCurrentFunctionNode().newTemporary(type, unaryNode);
 10.2584 -
 10.2585 -        return unaryNode;
 10.2586 -    }
 10.2587 -
 10.2588 -    @Override
 10.2589 -    public Node leaveADD(final UnaryNode unaryNode) {
 10.2590 -        return leaveUnary(unaryNode, Type.NUMBER);
 10.2591 -    }
 10.2592 -
 10.2593 -    @Override
 10.2594 -    public Node leaveBIT_NOT(final UnaryNode unaryNode) {
 10.2595 -        return leaveUnary(unaryNode, Type.INT);
 10.2596 -    }
 10.2597 -
 10.2598 -    @Override
 10.2599 -    public Node leaveCONVERT(final UnaryNode unaryNode) {
 10.2600 -        final Node rhs = unaryNode.rhs();
 10.2601 -
 10.2602 -        if (rhs.isTokenType(TokenType.CONVERT)) {
 10.2603 -            rhs.setSymbol(unaryNode.getSymbol());
 10.2604 -            return rhs;
 10.2605 -        }
 10.2606 -
 10.2607 -        return unaryNode;
 10.2608 -    }
 10.2609 -
 10.2610 -    /**
 10.2611 -     * In an assignment, recursively make sure that there are slots for
 10.2612 -     * everything that has to be laid out as temporary storage, which is the
 10.2613 -     * case if we are assign-op:ing a BaseNode subclass. This has to be
 10.2614 -     * recursive to handle things like multi dimensional arrays as lhs
 10.2615 -     *
 10.2616 -     * see NASHORN-258
 10.2617 -     *
 10.2618 -     * @param functionNode   the current function node (has to be passed as it changes in the visitor below)
 10.2619 -     * @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes
 10.2620 -     */
 10.2621 -    private static void ensureAssignmentSlots(final FunctionNode functionNode, final Node assignmentDest) {
 10.2622 -
 10.2623 -        assignmentDest.accept(new NodeVisitor() {
 10.2624 -
 10.2625 -            @Override
 10.2626 -            public Node leave(final AccessNode accessNode) {
 10.2627 -                final Node base = accessNode.getBase();
 10.2628 -                if (base.getSymbol().isThis()) {
 10.2629 -                    functionNode.addThisProperty(accessNode.getProperty().getName(), accessNode);
 10.2630 -                }
 10.2631 -
 10.2632 -                return accessNode;
 10.2633 -            }
 10.2634 -
 10.2635 -            @Override
 10.2636 -            public Node leave(final IndexNode indexNode) {
 10.2637 -                final Node index = indexNode.getIndex();
 10.2638 -                index.getSymbol().setNeedsSlot(!index.getSymbol().isConstant());
 10.2639 -
 10.2640 -                return indexNode;
 10.2641 -            }
 10.2642 -
 10.2643 -        });
 10.2644 -    }
 10.2645 -
 10.2646 -    @Override
 10.2647 -    public Node leaveDECINC(final UnaryNode unaryNode) {
 10.2648 -        // @see assignOffset
 10.2649 -        ensureAssignmentSlots(getCurrentFunctionNode(), unaryNode.rhs());
 10.2650 -        final Type type = Compiler.shouldUseIntegerArithmetic() ? Type.INT : Type.NUMBER;
 10.2651 -
 10.2652 -        unaryNode.rhs().getSymbol().setType(type);
 10.2653 -        getCurrentFunctionNode().newTemporary(type, unaryNode);
 10.2654 -
 10.2655 -        return unaryNode;
 10.2656 -    }
 10.2657 -
 10.2658 -    /**
 10.2659 -     * Helper class for wrapping a result
 10.2660 -     */
 10.2661 -    private abstract static class ResultNodeVisitor extends NodeVisitor {
 10.2662 -
 10.2663 -        private Node resultNode;
 10.2664 -
 10.2665 -        ResultNodeVisitor(final Node resultNode) {
 10.2666 -            this.resultNode = resultNode;
 10.2667 -        }
 10.2668 -
 10.2669 -        Node getResultNode() {
 10.2670 -            return resultNode;
 10.2671 -        }
 10.2672 -
 10.2673 -        void setResultNode(final Node resultNode) {
 10.2674 -            this.resultNode = resultNode;
 10.2675 -        }
 10.2676 -    }
 10.2677 -
 10.2678 -    @Override
 10.2679 -    public Node leaveDELETE(final UnaryNode unaryNode) {
 10.2680 -        final boolean              strictMode     = getCurrentFunctionNode().isStrictMode();
 10.2681 -        final Node                 rhs            = unaryNode.rhs();
 10.2682 -        final long                 token          = unaryNode.getToken();
 10.2683 -        final int                  finish         = unaryNode.getFinish();
 10.2684 -        final LiteralNode<Boolean> trueNode       = LiteralNode.newInstance(source, token, finish, true);
 10.2685 -        final LiteralNode<Boolean> strictFlagNode = LiteralNode.newInstance(source, token, finish, strictMode);
 10.2686 -
 10.2687 -        newLiteral(trueNode);
 10.2688 -        newLiteral(strictFlagNode);
 10.2689 -
 10.2690 -        final NodeVisitor  lower = this;
 10.2691 -        final FunctionNode currentFunctionNode = getCurrentFunctionNode();
 10.2692 -
 10.2693 -        final ResultNodeVisitor visitor = new ResultNodeVisitor(trueNode) {
 10.2694 -
 10.2695 -            private void initRuntimeNode(final RuntimeNode node) {
 10.2696 -                node.accept(lower);
 10.2697 -                currentFunctionNode.newTemporary(Type.BOOLEAN, unaryNode);
 10.2698 -                node.setSymbol(unaryNode.getSymbol());
 10.2699 -
 10.2700 -                setResultNode(node);
 10.2701 -            }
 10.2702 -
 10.2703 -            @Override
 10.2704 -            public Node enter(final IdentNode node) {
 10.2705 -                // If this is a declared variable or a function parameter, delete always fails (except for globals).
 10.2706 -                final boolean failDelete =
 10.2707 -                        strictMode ||
 10.2708 -                        node.getSymbol().isParam() ||
 10.2709 -                        (node.getSymbol().isVar() && !node.getSymbol().isTopLevel());
 10.2710 -
 10.2711 -                final Node literalNode =
 10.2712 -                    newLiteral(
 10.2713 -                        currentFunctionNode,
 10.2714 -                        LiteralNode.newInstance(
 10.2715 -                            source,
 10.2716 -                            node.getToken(),
 10.2717 -                            node.getFinish(),
 10.2718 -                            node.getName()));
 10.2719 -
 10.2720 -                if (failDelete) {
 10.2721 -                    if (THIS.tag().equals(node.getName())) {
 10.2722 -                        statements.add(new ExecuteNode(source, token, finish, discard(node)));
 10.2723 -                        currentFunctionNode.newTemporary(Type.BOOLEAN, trueNode);
 10.2724 -                        return null; //trueNode it is
 10.2725 -                    }
 10.2726 -                }
 10.2727 -
 10.2728 -                final List<Node> args = new ArrayList<>();
 10.2729 -                args.add(convert(currentFunctionNode.getScopeNode(), Type.OBJECT));
 10.2730 -                args.add(convert(literalNode, Type.OBJECT));
 10.2731 -                args.add(strictFlagNode);
 10.2732 -
 10.2733 -                initRuntimeNode(
 10.2734 -                    new RuntimeNode(
 10.2735 -                        source,
 10.2736 -                        token,
 10.2737 -                        finish,
 10.2738 -                        failDelete ? FAIL_DELETE : DELETE,
 10.2739 -                        args));
 10.2740 -
 10.2741 -                return null;
 10.2742 -            }
 10.2743 -
 10.2744 -            @Override
 10.2745 -            public Node enter(final AccessNode node) {
 10.2746 -                final IdentNode property = node.getProperty();
 10.2747 -
 10.2748 -                initRuntimeNode(
 10.2749 -                    new RuntimeNode(
 10.2750 -                        source,
 10.2751 -                        token,
 10.2752 -                        finish,
 10.2753 -                        DELETE,
 10.2754 -                        convert(node.getBase(), Type.OBJECT),
 10.2755 -                        convert(
 10.2756 -                            newLiteral(
 10.2757 -                                currentFunctionNode,
 10.2758 -                                LiteralNode.newInstance(
 10.2759 -                                    source,
 10.2760 -                                    property.getToken(),
 10.2761 -                                    property.getFinish(),
 10.2762 -                                    property.getName())),
 10.2763 -                            Type.OBJECT),
 10.2764 -                        strictFlagNode));
 10.2765 -
 10.2766 -                return null;
 10.2767 -            }
 10.2768 -
 10.2769 -            @Override
 10.2770 -            public Node enter(final IndexNode node) {
 10.2771 -                initRuntimeNode(
 10.2772 -                    new RuntimeNode(
 10.2773 -                        source,
 10.2774 -                        token,
 10.2775 -                        finish,
 10.2776 -                        DELETE,
 10.2777 -                        convert(node.getBase(), Type.OBJECT),
 10.2778 -                        convert(node.getIndex(), Type.OBJECT),
 10.2779 -                        strictFlagNode));
 10.2780 -
 10.2781 -                return null;
 10.2782 -            }
 10.2783 -
 10.2784 -            @Override
 10.2785 -            public Node enterDefault(final Node node) {
 10.2786 -                statements.add(new ExecuteNode(source, token, finish, discard(node)));
 10.2787 -                currentFunctionNode.newTemporary(Type.BOOLEAN, trueNode);
 10.2788 -                //just return trueNode which is the default
 10.2789 -                return null;
 10.2790 -            }
 10.2791 -        };
 10.2792 -
 10.2793 -        rhs.accept(visitor);
 10.2794 -
 10.2795 -        return visitor.getResultNode();
 10.2796 -    }
 10.2797 -
 10.2798 -    @Override
 10.2799 -    public Node enterNEW(final UnaryNode unaryNode) {
 10.2800 -        final CallNode callNode = (CallNode)unaryNode.rhs();
 10.2801 -
 10.2802 -        callNode.setIsNew();
 10.2803 -
 10.2804 -        final Node function = callNode.getFunction();
 10.2805 -        final Node markedFunction = markerFunction(function);
 10.2806 -
 10.2807 -        callNode.setFunction(markedFunction.accept(this));
 10.2808 -
 10.2809 -        acceptArgs(callNode);
 10.2810 -
 10.2811 -        getCurrentFunctionNode().newTemporary(Type.OBJECT, unaryNode);
 10.2812 -
 10.2813 -        return null;
 10.2814 -    }
 10.2815 -
 10.2816 -    @Override
 10.2817 -    public Node leaveNOT(final UnaryNode unaryNode) {
 10.2818 -        return leaveUnary(unaryNode, Type.BOOLEAN);
 10.2819 -    }
 10.2820 -
 10.2821 -    /**
 10.2822 -     * Create a null literal
 10.2823 -     *
 10.2824 -     * @param parent node to inherit token from.
 10.2825 -     * @return the new null literal
 10.2826 -     */
 10.2827 -    private LiteralNode<?> newNullLiteral(final Node parent) {
 10.2828 -        return newLiteral(LiteralNode.newInstance(parent.getSource(), parent.getToken(), parent.getFinish()));
 10.2829 -    }
 10.2830 -
 10.2831 -    @Override
 10.2832 -    public Node leaveTYPEOF(final UnaryNode unaryNode) {
 10.2833 -        final Node rhs    = unaryNode.rhs();
 10.2834 -        final long token  = unaryNode.getToken();
 10.2835 -        final int  finish = unaryNode.getFinish();
 10.2836 -
 10.2837 -        RuntimeNode runtimeNode;
 10.2838 -
 10.2839 -        if (rhs instanceof IdentNode) {
 10.2840 -            final IdentNode ident = (IdentNode)rhs;
 10.2841 -
 10.2842 -            if (ident.getSymbol().isParam() || ident.getSymbol().isVar()) {
 10.2843 -                runtimeNode = new RuntimeNode(
 10.2844 -                    source,
 10.2845 -                    token,
 10.2846 -                    finish,
 10.2847 -                    TYPEOF,
 10.2848 -                    convert(
 10.2849 -                        rhs,
 10.2850 -                        Type.OBJECT),
 10.2851 -                    newNullLiteral(unaryNode));
 10.2852 -            } else {
 10.2853 -                runtimeNode = new RuntimeNode(
 10.2854 -                    source,
 10.2855 -                    token,
 10.2856 -                    finish,
 10.2857 -                    TYPEOF,
 10.2858 -                    convert(
 10.2859 -                        getCurrentFunctionNode().getScopeNode(),
 10.2860 -                        Type.OBJECT),
 10.2861 -                    convert(
 10.2862 -                        newLiteral(
 10.2863 -                            LiteralNode.newInstance(
 10.2864 -                                source,
 10.2865 -                                ident.getToken(),
 10.2866 -                                ident.getFinish(),
 10.2867 -                                ident.getName())),
 10.2868 -                    Type.OBJECT));
 10.2869 -            }
 10.2870 -        }  else {
 10.2871 -            runtimeNode = new RuntimeNode(
 10.2872 -                source,
 10.2873 -                token,
 10.2874 -                finish,
 10.2875 -                TYPEOF,
 10.2876 -                convert(
 10.2877 -                    rhs,
 10.2878 -                    Type.OBJECT),
 10.2879 -                newNullLiteral(unaryNode));
 10.2880 -        }
 10.2881 -
 10.2882 -        runtimeNode.accept(this);
 10.2883 -
 10.2884 -        getCurrentFunctionNode().newTemporary(Type.OBJECT, unaryNode);
 10.2885 -        runtimeNode.setSymbol(unaryNode.getSymbol());
 10.2886 -
 10.2887 -        return runtimeNode;
 10.2888 -    }
 10.2889 -
 10.2890 -    @Override
 10.2891 -    public Node leaveSUB(final UnaryNode unaryNode) {
 10.2892 -        return leaveUnary(unaryNode, Type.NUMBER);
 10.2893 -    }
 10.2894 -
 10.2895 -    @Override
 10.2896 -    public Node leaveVOID(final UnaryNode unaryNode) {
 10.2897 -        final Node rhs = unaryNode.rhs();
 10.2898 -        getCurrentFunctionNode().newTemporary(Type.OBJECT, unaryNode);
 10.2899 -
 10.2900 -        // Set up request.
 10.2901 -        final RuntimeNode runtimeNode = new RuntimeNode(source, unaryNode.getToken(), unaryNode.getFinish(), VOID, convert(rhs, Type.OBJECT));
 10.2902 -
 10.2903 -        // Use same symbol as unary node.
 10.2904 -        runtimeNode.setSymbol(unaryNode.getSymbol());
 10.2905 -
 10.2906 -        return runtimeNode;
 10.2907 -    }
 10.2908 -
 10.2909 -    /**
 10.2910 -     * Compute the narrowest possible type for a binaryNode, based on its
 10.2911 -     * contents.
 10.2912 -     *
 10.2913 -     * @param binaryNode the binary node
 10.2914 -     * @return the narrowest possible type
 10.2915 -     */
 10.2916 -    private static Type binaryType(final BinaryNode binaryNode) {
 10.2917 -        final Node lhs = binaryNode.lhs();
 10.2918 -        assert lhs.hasType();
 10.2919 -
 10.2920 -        final Node rhs = binaryNode.rhs();
 10.2921 -        assert rhs.hasType();
 10.2922 -
 10.2923 -        // actually bitwise assignments are ok for ints. TODO
 10.2924 -        switch (binaryNode.tokenType()) {
 10.2925 -        case ASSIGN_BIT_AND:
 10.2926 -        case ASSIGN_BIT_OR:
 10.2927 -        case ASSIGN_BIT_XOR:
 10.2928 -        case ASSIGN_SHL:
 10.2929 -        case ASSIGN_SAR:
 10.2930 -            return Compiler.shouldUseIntegers() ? Type.widest(lhs.getType(), rhs.getType(), Type.INT) : Type.INT;
 10.2931 -        case ASSIGN_SHR:
 10.2932 -            return Type.LONG;
 10.2933 -        case ASSIGN:
 10.2934 -            return Compiler.shouldUseIntegers() ? Type.widest(lhs.getType(), rhs.getType(), Type.NUMBER) : Type.NUMBER;
 10.2935 -        default:
 10.2936 -            return binaryArithType(lhs.getType(), rhs.getType());
 10.2937 -        }
 10.2938 -    }
 10.2939 -
 10.2940 -    private static Type binaryArithType(final Type lhsType, final Type rhsType) {
 10.2941 -         if (!Compiler.shouldUseIntegerArithmetic()) {
 10.2942 -             return Type.NUMBER;
 10.2943 -         }
 10.2944 -         return Type.widest(lhsType, rhsType, Type.NUMBER);
 10.2945 -     }
 10.2946 -
 10.2947 -    /**
 10.2948 -     * Visit binary node and set symbols and inferred type
 10.2949 -     *
 10.2950 -     * @param binaryNode unary node to visit
 10.2951 -     * @param type       The narrowest allowed type for this node
 10.2952 -     *
 10.2953 -     * @return the final node, or replacement thereof
 10.2954 -     */
 10.2955 -    private Node leaveBinary(final BinaryNode binaryNode, final Type type) {
 10.2956 -        return leaveBinary(binaryNode, type, type, type);
 10.2957 -    }
 10.2958 -
 10.2959 -    /**
 10.2960 -     * Visit a binary node, specifying types for rhs, rhs and destType.
 10.2961 -     *
 10.2962 -     * @param binaryNode the binary node
 10.2963 -     * @param destType destination type
 10.2964 -     * @param lhsType type for left hand side
 10.2965 -     * @param rhsType type for right hand side
 10.2966 -     *
 10.2967 -     * @return resulting binary node
 10.2968 -     */
 10.2969 -    private Node leaveBinary(final BinaryNode binaryNode, final Type destType, final Type lhsType, final Type rhsType) {
 10.2970 -        /* Attempt to turn this binary expression into a constant */
 10.2971 -        final LiteralNode<?> literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval();
 10.2972 -        if (literalNode != null) {
 10.2973 -            return newLiteral(literalNode);
 10.2974 -        }
 10.2975 -
 10.2976 -        if (lhsType != null) {
 10.2977 -            binaryNode.setLHS(convert(binaryNode.lhs(), lhsType));
 10.2978 -        }
 10.2979 -
 10.2980 -        if (rhsType != null) {
 10.2981 -            binaryNode.setRHS(convert(binaryNode.rhs(), rhsType));
 10.2982 -        }
 10.2983 -
 10.2984 -        getCurrentFunctionNode().newTemporary(destType, binaryNode);
 10.2985 -
 10.2986 -        return binaryNode;
 10.2987 -    }
 10.2988 -
 10.2989 -    /**
 10.2990 -     * Determine if the outcome of + operator is a string.
 10.2991 -     *
 10.2992 -     * @param node
 10.2993 -     *            Node to test.
 10.2994 -     * @return true if a string result.
 10.2995 -     */
 10.2996 -    private boolean isAddString(final Node node) {
 10.2997 -        if (node instanceof BinaryNode && node.isTokenType(TokenType.ADD)) {
 10.2998 -            final BinaryNode binaryNode = (BinaryNode)node;
 10.2999 -            final Node lhs = binaryNode.lhs();
 10.3000 -            final Node rhs = binaryNode.rhs();
 10.3001 -
 10.3002 -            return isAddString(lhs) || isAddString(rhs);
 10.3003 -        }
 10.3004 -
 10.3005 -        return node instanceof LiteralNode<?> && ((LiteralNode<?>)node).getObject() instanceof String;
 10.3006 -    }
 10.3007 -
 10.3008 -    /**
 10.3009 -     * Helper for creating a new runtime node from a parent node, inheriting its
 10.3010 -     * types and tokens
 10.3011 -     *
 10.3012 -     * @param parent   Parent node.
 10.3013 -     * @param args     Runtime request arguments.
 10.3014 -     * @param request  Runtime request type.
 10.3015 -     * @return New {@link RuntimeNode}.
 10.3016 -     */
 10.3017 -
 10.3018 -    private RuntimeNode newRuntime(final Node parent, final List<Node> args, final Request request) {
 10.3019 -        final RuntimeNode runtimeNode = new RuntimeNode(source, parent.getToken(), parent.getFinish(), request, args);
 10.3020 -        runtimeNode.setStart(parent.getStart());
 10.3021 -        runtimeNode.setFinish(parent.getFinish());
 10.3022 -
 10.3023 -        // Use same symbol as parent node.
 10.3024 -        runtimeNode.accept(this);
 10.3025 -        runtimeNode.setSymbol(parent.getSymbol());
 10.3026 -
 10.3027 -        return runtimeNode;
 10.3028 -    }
 10.3029 -
 10.3030 -    /**
 10.3031 -     * Helper for creating a new runtime node from a binary node
 10.3032 -     *
 10.3033 -     * @param binaryNode {@link RuntimeNode} expression.
 10.3034 -     * @param request    Runtime request type.
 10.3035 -     * @return New {@link RuntimeNode}.
 10.3036 -     */
 10.3037 -    private RuntimeNode newRuntime(final BinaryNode binaryNode, final Request request) {
 10.3038 -        return newRuntime(binaryNode, Arrays.asList(new Node[] { binaryNode.lhs(), binaryNode.rhs() }), request);
 10.3039 -    }
 10.3040 -
 10.3041 -    /**
 10.3042 -     * Add is a special binary, as it works not only on arithmetic, but for
 10.3043 -     * strings etc as well.
 10.3044 -     */
 10.3045 -    @Override
 10.3046 -    public Node leaveADD(final BinaryNode binaryNode) {
 10.3047 -        final Node lhs = binaryNode.lhs();
 10.3048 -        final Node rhs = binaryNode.rhs();
 10.3049 -
 10.3050 -        //parameters must be blown up to objects
 10.3051 -        ensureTypeNotUnknown(lhs);
 10.3052 -        ensureTypeNotUnknown(rhs);
 10.3053 -
 10.3054 -        if ((lhs.getType().isNumeric() || lhs.getType().isBoolean()) && (rhs.getType().isNumeric() || rhs.getType().isBoolean())) {
 10.3055 -            return leaveBinary(binaryNode, binaryType(binaryNode));
 10.3056 -        } else if (isAddString(binaryNode)) {
 10.3057 -            binaryNode.setLHS(convert(lhs, Type.OBJECT));
 10.3058 -            binaryNode.setRHS(convert(rhs, Type.OBJECT));
 10.3059 -            getCurrentFunctionNode().newTemporary(Type.OBJECT, binaryNode);
 10.3060 -        } else {
 10.3061 -            getCurrentFunctionNode().newTemporary(Type.OBJECT, binaryNode);
 10.3062 -            return newRuntime(binaryNode, ADD);
 10.3063 -        }
 10.3064 -
 10.3065 -        return binaryNode;
 10.3066 -    }
 10.3067 -
 10.3068 -    @Override
 10.3069 -    public Node leaveAND(final BinaryNode binaryNode) {
 10.3070 -        return leaveBinary(binaryNode, Type.OBJECT, null, null);
 10.3071 -    }
 10.3072 -
 10.3073 -    /**
 10.3074 -     * This is a helper called before an assignment.
 10.3075 -     * @param binaryNode assignment node
 10.3076 -     */
 10.3077 -    private Node enterAssign(final BinaryNode binaryNode) {
 10.3078 -        final Node lhs = binaryNode.lhs();
 10.3079 -
 10.3080 -        if (!(lhs instanceof IdentNode)) {
 10.3081 -            return binaryNode;
 10.3082 -        }
 10.3083 -
 10.3084 -        final Block     block = getCurrentBlock();
 10.3085 -        final IdentNode ident = (IdentNode)lhs;
 10.3086 -        final String    name  = ident.getName();
 10.3087 -
 10.3088 -        Symbol symbol = getCurrentBlock().findSymbol(name);
 10.3089 -
 10.3090 -        if (symbol == null) {
 10.3091 -            symbol = block.defineSymbol(name, IS_GLOBAL, ident);
 10.3092 -            binaryNode.setSymbol(symbol);
 10.3093 -        } else if (!getCurrentFunctionNode().isLocal(symbol)) {
 10.3094 -            symbol.setIsScope();
 10.3095 -        }
 10.3096 -
 10.3097 -        localDefs.add(name);
 10.3098 -
 10.3099 -        return binaryNode;
 10.3100 -    }
 10.3101 -
 10.3102 -    /**
 10.3103 -     * This assign helper is called after an assignment, when all children of
 10.3104 -     * the assign has been processed. It fixes the types and recursively makes
 10.3105 -     * sure that everyhing has slots that should have them in the chain.
 10.3106 -     *
 10.3107 -     * @param binaryNode assignment node
 10.3108 -     * @param destType   destination type of assignment
 10.3109 -     */
 10.3110 -    private Node leaveAssign(final BinaryNode binaryNode, final Type destType) {
 10.3111 -        binaryNode.lhs().getSymbol().setType(destType); // lhs inherits dest type
 10.3112 -        getCurrentFunctionNode().newTemporary(destType, binaryNode); // as does destination
 10.3113 -
 10.3114 -        ensureAssignmentSlots(getCurrentFunctionNode(), binaryNode.lhs());
 10.3115 -        return binaryNode;
 10.3116 -    }
 10.3117 -
 10.3118 -    @Override
 10.3119 -    public Node enterASSIGN(final BinaryNode binaryNode) {
 10.3120 -        return enterAssign(binaryNode);
 10.3121 -    }
 10.3122 -
 10.3123 -    @Override
 10.3124 -    public Node leaveASSIGN(final BinaryNode binaryNode) {
 10.3125 -        final Node lhs = binaryNode.lhs();
 10.3126 -        final Node rhs = binaryNode.rhs();
 10.3127 -
 10.3128 -        if (rhs.getType().isNumeric()) {
 10.3129 -            final Symbol lhsSymbol = lhs.getSymbol();
 10.3130 -            final Type lhsType = Type.widest(lhs.getType(), binaryType(binaryNode));
 10.3131 -
 10.3132 -            // for index nodes, we can set anything
 10.3133 -            lhsSymbol.setType(lhsType);
 10.3134 -            getCurrentFunctionNode().newTemporary(lhs.getType(), binaryNode);
 10.3135 -            if (!(lhs instanceof IndexNode)) {
 10.3136 -                binaryNode.setRHS(convert(rhs, lhsType));
 10.3137 -            }
 10.3138 -        } else {
 10.3139 -            // Force symbol to be object if not numeric assignment.
 10.3140 -            binaryNode.setRHS(convert(rhs, Type.OBJECT));
 10.3141 -            getCurrentFunctionNode().newTemporary(Type.OBJECT, binaryNode);
 10.3142 -
 10.3143 -            if (lhs instanceof IdentNode) {
 10.3144 -                lhs.getSymbol().setType(Type.OBJECT);
 10.3145 -            }
 10.3146 -        }
 10.3147 -
 10.3148 -        if (lhs instanceof AccessNode) {
 10.3149 -            final Node baseNode = ((AccessNode)lhs).getBase();
 10.3150 -
 10.3151 -            if (baseNode.getSymbol().isThis()) {
 10.3152 -                final IdentNode property = ((AccessNode)lhs).getProperty();
 10.3153 -                getCurrentFunctionNode().addThisProperty(property.getName(), property);
 10.3154 -            }
 10.3155 -        }
 10.3156 -
 10.3157 -        return binaryNode;
 10.3158 -    }
 10.3159 -
 10.3160 -    @Override
 10.3161 -    public Node enterASSIGN_ADD(final BinaryNode binaryNode) {
 10.3162 -        return enterAssign(binaryNode);
 10.3163 -    }
 10.3164 -
 10.3165 -    @Override
 10.3166 -    public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
 10.3167 -        final Node lhs = binaryNode.lhs();
 10.3168 -        final Node rhs = binaryNode.rhs();
 10.3169 -        final boolean bothNumeric = lhs.getType().isNumeric() && rhs.getType().isNumeric();
 10.3170 -
 10.3171 -        /*
 10.3172 -         * In the case of bothNumeric,
 10.3173 -         * compute type for lhs += rhs. Assign type to lhs. Assign type to
 10.3174 -         * temporary for this node. Convert rhs from whatever it was to this
 10.3175 -         * type. Legacy wise dest has always been narrowed. It should
 10.3176 -         * actually only be the lhs that is the double, or other narrower
 10.3177 -         * type than OBJECT
 10.3178 -         */
 10.3179 -        return leaveAssign(binaryNode, bothNumeric ? binaryType(binaryNode) : Type.OBJECT);
 10.3180 -    }
 10.3181 -
 10.3182 -    @Override
 10.3183 -    public Node enterASSIGN_BIT_AND(final BinaryNode binaryNode) {
 10.3184 -        return enterAssign(binaryNode);
 10.3185 -    }
 10.3186 -
 10.3187 -    @Override
 10.3188 -    public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) {
 10.3189 -        return leaveAssign(binaryNode, binaryType(binaryNode));
 10.3190 -    }
 10.3191 -
 10.3192 -    @Override
 10.3193 -    public Node enterASSIGN_BIT_OR(final BinaryNode binaryNode) {
 10.3194 -        return enterAssign(binaryNode);
 10.3195 -    }
 10.3196 -
 10.3197 -    @Override
 10.3198 -    public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) {
 10.3199 -        return leaveAssign(binaryNode, binaryType(binaryNode));
 10.3200 -    }
 10.3201 -
 10.3202 -    @Override
 10.3203 -    public Node enterASSIGN_BIT_XOR(final BinaryNode binaryNode) {
 10.3204 -        return enterAssign(binaryNode);
 10.3205 -    }
 10.3206 -
 10.3207 -    @Override
 10.3208 -    public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) {
 10.3209 -        return leaveAssign(binaryNode, binaryType(binaryNode));
 10.3210 -    }
 10.3211 -
 10.3212 -    @Override
 10.3213 -    public Node enterASSIGN_DIV(final BinaryNode binaryNode) {
 10.3214 -        return enterAssign(binaryNode);
 10.3215 -    }
 10.3216 -
 10.3217 -    @Override
 10.3218 -    public Node leaveASSIGN_DIV(final BinaryNode binaryNode) {
 10.3219 -        return leaveAssign(binaryNode, binaryType(binaryNode));
 10.3220 -    }
 10.3221 -
 10.3222 -    @Override
 10.3223 -    public Node enterASSIGN_MOD(final BinaryNode binaryNode) {
 10.3224 -        return enterAssign(binaryNode);
 10.3225 -    }
 10.3226 -
 10.3227 -    @Override
 10.3228 -    public Node leaveASSIGN_MOD(final BinaryNode binaryNode) {
 10.3229 -        return leaveAssign(binaryNode, binaryType(binaryNode));
 10.3230 -    }
 10.3231 -
 10.3232 -    @Override
 10.3233 -    public Node enterASSIGN_MUL(final BinaryNode binaryNode) {
 10.3234 -        return enterAssign(binaryNode);
 10.3235 -    }
 10.3236 -
 10.3237 -    @Override
 10.3238 -    public Node leaveASSIGN_MUL(final BinaryNode binaryNode) {
 10.3239 -        return leaveAssign(binaryNode, binaryType(binaryNode));
 10.3240 -    }
 10.3241 -
 10.3242 -    @Override
 10.3243 -    public Node enterASSIGN_SAR(final BinaryNode binaryNode) {
 10.3244 -        return enterAssign(binaryNode);
 10.3245 -    }
 10.3246 -
 10.3247 -    @Override
 10.3248 -    public Node leaveASSIGN_SAR(final BinaryNode binaryNode) {
 10.3249 -        return leaveAssign(binaryNode, binaryType(binaryNode));
 10.3250 -    }
 10.3251 -
 10.3252 -    @Override
 10.3253 -    public Node enterASSIGN_SHL(final BinaryNode binaryNode) {
 10.3254 -        return enterAssign(binaryNode);
 10.3255 -    }
 10.3256 -
 10.3257 -    @Override
 10.3258 -    public Node leaveASSIGN_SHL(final BinaryNode binaryNode) {
 10.3259 -        return leaveAssign(binaryNode, binaryType(binaryNode));
 10.3260 -    }
 10.3261 -
 10.3262 -    @Override
 10.3263 -    public Node enterASSIGN_SHR(final BinaryNode binaryNode) {
 10.3264 -        return enterAssign(binaryNode);
 10.3265 -    }
 10.3266 -
 10.3267 -    @Override
 10.3268 -    public Node leaveASSIGN_SHR(final BinaryNode binaryNode) {
 10.3269 -        return leaveAssign(binaryNode, binaryType(binaryNode));
 10.3270 -    }
 10.3271 -
 10.3272 -    @Override
 10.3273 -    public Node enterASSIGN_SUB(final BinaryNode binaryNode) {
 10.3274 -        return enterAssign(binaryNode);
 10.3275 -    }
 10.3276 -
 10.3277 -    @Override
 10.3278 -    public Node leaveASSIGN_SUB(final BinaryNode binaryNode) {
 10.3279 -        return leaveAssign(binaryNode, binaryType(binaryNode));
 10.3280 -    }
 10.3281 -
 10.3282 -    @Override
 10.3283 -    public Node leaveBIT_AND(final BinaryNode binaryNode) {
 10.3284 -        return leaveBinary(binaryNode, Type.INT);
 10.3285 -    }
 10.3286 -
 10.3287 -    @Override
 10.3288 -    public Node leaveBIT_OR(final BinaryNode binaryNode) {
 10.3289 -        return leaveBinary(binaryNode, Type.INT);
 10.3290 -    }
 10.3291 -
 10.3292 -    @Override
 10.3293 -    public Node leaveBIT_XOR(final BinaryNode binaryNode) {
 10.3294 -        return leaveBinary(binaryNode, Type.INT);
 10.3295 -    }
 10.3296 -
 10.3297 -    @Override
 10.3298 -    public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
 10.3299 -        binaryNode.setLHS(discard(binaryNode.lhs()));
 10.3300 -        getCurrentFunctionNode().newTemporary(binaryNode.rhs().getType(), binaryNode);
 10.3301 -
 10.3302 -        return binaryNode;
 10.3303 -    }
 10.3304 -
 10.3305 -    @Override
 10.3306 -    public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
 10.3307 -        binaryNode.setRHS(discard(binaryNode.rhs()));
 10.3308 -        getCurrentFunctionNode().newTemporary(binaryNode.lhs().getType(), binaryNode);
 10.3309 -
 10.3310 -        return binaryNode;
 10.3311 -    }
 10.3312 -
 10.3313 -    @Override
 10.3314 -    public Node leaveDIV(final BinaryNode binaryNode) {
 10.3315 -        return leaveBinary(binaryNode, binaryType(binaryNode));
 10.3316 -    }
 10.3317 -
 10.3318 -    @Override
 10.3319 -    public Node leaveEQ(final BinaryNode binaryNode) {
 10.3320 -        return leaveCmp(binaryNode, EQ);
 10.3321 -    }
 10.3322 -
 10.3323 -    @Override
 10.3324 -    public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
 10.3325 -        return leaveCmp(binaryNode, EQ_STRICT);
 10.3326 -    }
 10.3327 -
 10.3328 -    private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) {
 10.3329 -        final Node lhs = binaryNode.lhs();
 10.3330 -        final Node rhs = binaryNode.rhs();
 10.3331 -
 10.3332 -        /* Attempt to turn this comparison into a constant and collapse it */
 10.3333 -        final LiteralNode<?> literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval();
 10.3334 -        if (literalNode != null) {
 10.3335 -            return newLiteral(literalNode);
 10.3336 -        }
 10.3337 -
 10.3338 -        // another case where dest != source operand types always a boolean
 10.3339 -        getCurrentFunctionNode().newTemporary(request.getReturnType(), binaryNode);
 10.3340 -
 10.3341 -        ensureTypeNotUnknown(lhs);
 10.3342 -        ensureTypeNotUnknown(rhs);
 10.3343 -        final Type type = Type.widest(lhs.getType(), rhs.getType());
 10.3344 -
 10.3345 -        if (type.isObject()) {
 10.3346 -            return newRuntime(binaryNode, request);
 10.3347 -        }
 10.3348 -
 10.3349 -        if ((request.equals(EQ_STRICT) || request.equals(NE_STRICT)) && lhs.getType().isBoolean() != rhs.getType().isBoolean()) {
 10.3350 -            // special case: number compared against boolean => never equal. must not convert!
 10.3351 -            final boolean              result     = request.equals(NE_STRICT);
 10.3352 -            final LiteralNode<Boolean> resultNode = LiteralNode.newInstance(source, 0, 0, result);
 10.3353 -            final boolean              canSkipLHS = (lhs instanceof LiteralNode);
 10.3354 -            final boolean              canSkipRHS = (rhs instanceof LiteralNode);
 10.3355 -
 10.3356 -            if (canSkipLHS && canSkipRHS) {
 10.3357 -                return resultNode.accept(this);
 10.3358 -            }
 10.3359 -
 10.3360 -            final Node argNode;
 10.3361 -
 10.3362 -            if (!canSkipLHS && !canSkipRHS) {
 10.3363 -                argNode = new BinaryNode(source, Token.recast(binaryNode.getToken(), TokenType.COMMARIGHT), lhs, rhs);
 10.3364 -            } else {
 10.3365 -                argNode = !canSkipLHS ? lhs : rhs;
 10.3366 -            }
 10.3367 -
 10.3368 -            return new BinaryNode(source, Token.recast(binaryNode.getToken(), TokenType.COMMARIGHT), argNode, resultNode).accept(this);
 10.3369 -        }
 10.3370 -
 10.3371 -        binaryNode.setLHS(convert(lhs, type));
 10.3372 -        binaryNode.setRHS(convert(rhs, type));
 10.3373 -
 10.3374 -        return binaryNode;
 10.3375 -    }
 10.3376 -
 10.3377 -    @Override
 10.3378 -    public Node leaveGE(final BinaryNode binaryNode) {
 10.3379 -        return leaveCmp(binaryNode, GE);
 10.3380 -    }
 10.3381 -
 10.3382 -    @Override
 10.3383 -    public Node leaveGT(final BinaryNode binaryNode) {
 10.3384 -        return leaveCmp(binaryNode, GT);
 10.3385 -    }
 10.3386 -
 10.3387 -    private Node exitIN_INSTANCEOF(final BinaryNode binaryNode, final Request request) {
 10.3388 -        getCurrentFunctionNode().newTemporary(request.getReturnType(), binaryNode);
 10.3389 -        return newRuntime(binaryNode, request);
 10.3390 -    }
 10.3391 -
 10.3392 -    @Override
 10.3393 -    public Node leaveIN(final BinaryNode binaryNode) {
 10.3394 -        return exitIN_INSTANCEOF(binaryNode, IN);
 10.3395 -    }
 10.3396 -
 10.3397 -    @Override
 10.3398 -    public Node leaveINSTANCEOF(final BinaryNode binaryNode) {
 10.3399 -        return exitIN_INSTANCEOF(binaryNode, INSTANCEOF);
 10.3400 -    }
 10.3401 -
 10.3402 -    @Override
 10.3403 -    public Node leaveLE(final BinaryNode binaryNode) {
 10.3404 -        return leaveCmp(binaryNode, LE);
 10.3405 -    }
 10.3406 -
 10.3407 -    @Override
 10.3408 -    public Node leaveLT(final BinaryNode binaryNode) {
 10.3409 -        return leaveCmp(binaryNode, LT);
 10.3410 -    }
 10.3411 -
 10.3412 -    @Override
 10.3413 -    public Node leaveMOD(final BinaryNode binaryNode) {
 10.3414 -        return leaveBinary(binaryNode, binaryType(binaryNode));
 10.3415 -    }
 10.3416 -
 10.3417 -    @Override
 10.3418 -    public Node leaveMUL(final BinaryNode binaryNode) {
 10.3419 -        return leaveBinary(binaryNode,  binaryType(binaryNode));
 10.3420 -    }
 10.3421 -
 10.3422 -    @Override
 10.3423 -    public Node leaveNE(final BinaryNode binaryNode) {
 10.3424 -        return leaveCmp(binaryNode, NE);
 10.3425 -    }
 10.3426 -
 10.3427 -    @Override
 10.3428 -    public Node leaveNE_STRICT(final BinaryNode binaryNode) {
 10.3429 -        return leaveCmp(binaryNode, NE_STRICT);
 10.3430 -    }
 10.3431 -
 10.3432 -    @Override
 10.3433 -    public Node leaveOR(final BinaryNode binaryNode) {
 10.3434 -        return leaveBinary(binaryNode, Type.OBJECT, null, null);
 10.3435 -    }
 10.3436 -
 10.3437 -    @Override
 10.3438 -    public Node leaveSAR(final BinaryNode binaryNode) {
 10.3439 -        return leaveBinary(binaryNode, Type.INT);
 10.3440 -    }
 10.3441 -
 10.3442 -    @Override
 10.3443 -    public Node leaveSHL(final BinaryNode binaryNode) {
 10.3444 -        return leaveBinary(binaryNode, Type.INT);
 10.3445 -    }
 10.3446 -
 10.3447 -    @Override
 10.3448 -    public Node leaveSHR(final BinaryNode binaryNode) {
 10.3449 -        return leaveBinary(binaryNode, Type.LONG, Type.INT, Type.INT);
 10.3450 -    }
 10.3451 -
 10.3452 -    @Override
 10.3453 -    public Node leaveSUB(final BinaryNode binaryNode) {
 10.3454 -        return leaveBinary(binaryNode, binaryType(binaryNode));
 10.3455 -    }
 10.3456 -
 10.3457 -    @Override
 10.3458 -    public Node leave(final TernaryNode ternaryNode) {
 10.3459 -        final Node test = ternaryNode.lhs();
 10.3460 -        final Node lhs  = ternaryNode.rhs();
 10.3461 -        final Node rhs  = ternaryNode.third();
 10.3462 -
 10.3463 -        ensureTypeNotUnknown(lhs);
 10.3464 -        ensureTypeNotUnknown(rhs);
 10.3465 -        final Type type = Type.widest(lhs.getType(), rhs.getType());
 10.3466 -
 10.3467 -        ternaryNode.setRHS(convert(lhs, type));
 10.3468 -        ternaryNode.setThird(convert(rhs, type));
 10.3469 -
 10.3470 -        // optimize away the ternary if the test is constant.
 10.3471 -        if (test.getSymbol().isConstant()) {
 10.3472 -            return ((LiteralNode<?>)test).isTrue() ? lhs : rhs;
 10.3473 -        }
 10.3474 -
 10.3475 -        ternaryNode.setLHS(convert(test, Type.BOOLEAN));
 10.3476 -
 10.3477 -        getCurrentFunctionNode().newTemporary(type, ternaryNode);
 10.3478 -
 10.3479 -        return ternaryNode;
 10.3480 -    }
 10.3481 -
 10.3482 -    private static void ensureTypeNotUnknown(final Node node) {
 10.3483 -        final Symbol symbol = node.getSymbol();
 10.3484 -
 10.3485 -        /*
 10.3486 -         * Note that not just unknowns, but params need to be blown
 10.3487 -         * up to objects, because we can have something like
 10.3488 -         *
 10.3489 -         * function f(a) {
 10.3490 -         *    var b = ~a; //b and a are inferred to be int
 10.3491 -         *    return b;
 10.3492 -         * }
 10.3493 -         *
 10.3494 -         * In this case, it would be correct to say that "if you have
 10.3495 -         * an int at the callsite, just pass it".
 10.3496 -         *
 10.3497 -         * However
 10.3498 -         *
 10.3499 -         * function f(a) {
 10.3500 -         *    var b = ~a;      //b and a are inferred to be int
 10.3501 -         *    return b == 17;  //b is still inferred to be int.
 10.3502 -         * }
 10.3503 -         *
 10.3504 -         * can be called with f("17") and if we assume that b is an
 10.3505 -         * int and don't blow it up to an object in the comparison, we
 10.3506 -         * are screwed. I hate JavaScript.
 10.3507 -         *
 10.3508 -         * This check has to be done for any operation that might take
 10.3509 -         * objects as parameters, for example +, but not *, which is known
 10.3510 -         * to coerce types into doubles
 10.3511 -         */
 10.3512 -        if (node.getType().isUnknown() || symbol.isParam()) {
 10.3513 -            symbol.setType(Type.OBJECT);
 10.3514 -            symbol.setCanBeUndefined();
 10.3515 -         }
 10.3516 -    }
 10.3517 -
 10.3518 -    /**
 10.3519 -     * A simple node visitor that ensure that scope and slot information is correct.
 10.3520 -     * This is run as a post pass after we know all scope changing information about
 10.3521 -     * the Lowering. This is also called after potential mutations like splitting
 10.3522 -     * have taken place, as splitting forces scope.
 10.3523 -     *
 10.3524 -     * This was previously done on a per functionNode basis in {@link CodeGenerator},
 10.3525 -     * but this is too late for type information to be used in {@link AccessSpecializer}
 10.3526 -     */
 10.3527 -    static class FinalizeSymbols extends NodeVisitor {
 10.3528 -        @Override
 10.3529 -        public Node leave(final Block block) {
 10.3530 -            return updateSymbols(block);
 10.3531 -        }
 10.3532 -
 10.3533 -        @Override
 10.3534 -        public Node leave(final FunctionNode function) {
 10.3535 -            return updateSymbols(function);
 10.3536 -        }
 10.3537 -
 10.3538 -        private static void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) {
 10.3539 -            if (!symbol.isScope()) {
 10.3540 -                LOG.finest("updateSymbols: " + symbol + " => scope, because all vars in " + functionNode.getName() + " are in scope");
 10.3541 -            }
 10.3542 -            if (loseSlot && symbol.hasSlot()) {
 10.3543 -                LOG.finest("updateSymbols: " + symbol + " => no slot, because all vars in " + functionNode.getName() + " are in scope");
 10.3544 -            }
 10.3545 -        }
 10.3546 -
 10.3547 -        // called after a block or function node (subclass of block) is finished
 10.3548 -        // to correct scope and slot assignment for variables
 10.3549 -        private static Block updateSymbols(final Block block) {
 10.3550 -
 10.3551 -            if (!block.needsScope()) {
 10.3552 -                return block; // nothing to do
 10.3553 -            }
 10.3554 -
 10.3555 -            assert !(block instanceof FunctionNode) || block.getFunction() == block;
 10.3556 -
 10.3557 -            final FunctionNode functionNode   = block.getFunction();
 10.3558 -            final List<Symbol> symbols        = block.getFrame().getSymbols();
 10.3559 -            final boolean      allVarsInScope = functionNode.varsInScope();
 10.3560 -            final boolean      isVarArg       = functionNode.isVarArg();
 10.3561 -
 10.3562 -            for (final Symbol symbol : symbols) {
 10.3563 -                if (symbol.isInternal() || symbol.isThis()) {
 10.3564 -                    continue;
 10.3565 -                }
 10.3566 -
 10.3567 -                if (symbol.isVar()) {
 10.3568 -                    if (allVarsInScope || symbol.isScope()) {
 10.3569 -                        updateSymbolsLog(functionNode, symbol, true);
 10.3570 -                        symbol.setIsScope();
 10.3571 -                        symbol.setNeedsSlot(false);
 10.3572 -                    } else {
 10.3573 -                        assert symbol.hasSlot() : symbol + " should have a slot only, no scope";
 10.3574 -                    }
 10.3575 -                } else if (symbol.isParam() && (allVarsInScope || isVarArg || symbol.isScope())) {
 10.3576 -                    updateSymbolsLog(functionNode, symbol, isVarArg);
 10.3577 -                    symbol.setIsScope();
 10.3578 -                    symbol.setNeedsSlot(!isVarArg);
 10.3579 -                }
 10.3580 -            }
 10.3581 -
 10.3582 -            return block;
 10.3583 -        }
 10.3584 -    }
 10.3585 -
 10.3586 -    /**
 10.3587 -     * Helper class to evaluate constant expressions at compile time This is
 10.3588 -     * also a simplifier used by BinaryNode visits, UnaryNode visits and
 10.3589 -     * conversions.
 10.3590 -     */
 10.3591 -    private abstract static class ConstantEvaluator<T extends Node> {
 10.3592 -        protected T            parent;
 10.3593 -        protected final Source source;
 10.3594 -        protected final long   token;
 10.3595 -        protected final int    finish;
 10.3596 -
 10.3597 -        protected ConstantEvaluator(final T parent) {
 10.3598 -            this.parent  = parent;
 10.3599 -            this.source  = parent.getSource();
 10.3600 -            this.token   = parent.getToken();
 10.3601 -            this.finish  = parent.getFinish();
 10.3602 -        }
 10.3603 -
 10.3604 -        /**
 10.3605 -         * Returns a literal node that replaces the given parent node, or null if replacement
 10.3606 -         * is impossible
 10.3607 -         * @return the literal node
 10.3608 -         */
 10.3609 -        protected abstract LiteralNode<?> eval();
 10.3610 -    }
 10.3611 -
 10.3612 -    static class LiteralNodeConstantEvaluator extends ConstantEvaluator<LiteralNode<?>> {
 10.3613 -        private final Type type;
 10.3614 -
 10.3615 -        LiteralNodeConstantEvaluator(final LiteralNode<?> parent, final Type type) {
 10.3616 -            super(parent);
 10.3617 -            this.type = type;
 10.3618 -        }
 10.3619 -
 10.3620 -        @Override
 10.3621 -        protected LiteralNode<?> eval() {
 10.3622 -            final Object value = ((LiteralNode<?>)parent).getValue();
 10.3623 -
 10.3624 -            LiteralNode<?> literalNode = null;
 10.3625 -
 10.3626 -            if (type.isString()) {
 10.3627 -                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toString(value));
 10.3628 -            } else if (type.isBoolean()) {
 10.3629 -                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toBoolean(value));
 10.3630 -            } else if (type.isInteger()) {
 10.3631 -                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toInt32(value));
 10.3632 -            } else if (type.isLong()) {
 10.3633 -                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toLong(value));
 10.3634 -            } else if (type.isNumber() || parent.getType().isNumeric() && !parent.getType().isNumber()) {
 10.3635 -                literalNode = LiteralNode.newInstance(source, token, finish, JSType.toNumber(value));
 10.3636 -            }
 10.3637 -
 10.3638 -            return literalNode;
 10.3639 -        }
 10.3640 -    }
 10.3641 -
 10.3642 -    private static class UnaryNodeConstantEvaluator extends ConstantEvaluator<UnaryNode> {
 10.3643 -        UnaryNodeConstantEvaluator(final UnaryNode parent) {
 10.3644 -            super(parent);
 10.3645 -        }
 10.3646 -
 10.3647 -        @Override
 10.3648 -        protected LiteralNode<?> eval() {
 10.3649 -            final Node rhsNode = parent.rhs();
 10.3650 -
 10.3651 -            if (!rhsNode.getSymbol().isConstant()) {
 10.3652 -                return null;
 10.3653 -            }
 10.3654 -
 10.3655 -            final LiteralNode<?> rhs = (LiteralNode<?>)rhsNode;
 10.3656 -            final boolean rhsInteger = rhs.getType().isInteger();
 10.3657 -
 10.3658 -            LiteralNode<?> literalNode;
 10.3659 -
 10.3660 -            switch (parent.tokenType()) {
 10.3661 -            case ADD:
 10.3662 -                if (rhsInteger) {
 10.3663 -                    literalNode = LiteralNode.newInstance(source, token, finish, rhs.getInt32());
 10.3664 -                } else {
 10.3665 -                    literalNode = LiteralNode.newInstance(source, token, finish, rhs.getNumber());
 10.3666 -                }
 10.3667 -                break;
 10.3668 -            case SUB:
 10.3669 -                if (rhsInteger && rhs.getInt32() != 0) { // @see test/script/basic/minuszero.js
 10.3670 -                    literalNode = LiteralNode.newInstance(source, token, finish, -rhs.getInt32());
 10.3671 -                } else {
 10.3672 -                    literalNode = LiteralNode.newInstance(source, token, finish, -rhs.getNumber());
 10.3673 -                }
 10.3674 -                break;
 10.3675 -            case NOT:
 10.3676 -                literalNode = LiteralNode.newInstance(source, token, finish, !rhs.getBoolean());
 10.3677 -                break;
 10.3678 -            case BIT_NOT:
 10.3679 -                literalNode = LiteralNode.newInstance(source, token, finish, ~rhs.getInt32());
 10.3680 -                break;
 10.3681 -            default:
 10.3682 -                return null;
 10.3683 -            }
 10.3684 -
 10.3685 -            return literalNode;
 10.3686 -        }
 10.3687 -    }
 10.3688 -
 10.3689 -    private static class BinaryNodeConstantEvaluator extends ConstantEvaluator<BinaryNode> {
 10.3690 -        BinaryNodeConstantEvaluator(final BinaryNode parent) {
 10.3691 -            super(parent);
 10.3692 -        }
 10.3693 -
 10.3694 -        @Override
 10.3695 -        protected LiteralNode<?> eval() {
 10.3696 -
 10.3697 -            if (!parent.lhs().getSymbol().isConstant() || !parent.rhs().getSymbol().isConstant()) {
 10.3698 -                return null;
 10.3699 -            }
 10.3700 -
 10.3701 -            final LiteralNode<?> lhs = (LiteralNode<?>)parent.lhs();
 10.3702 -            final LiteralNode<?> rhs = (LiteralNode<?>)parent.rhs();
 10.3703 -
 10.3704 -            final Type widest = Type.widest(lhs.getType(), rhs.getType());
 10.3705 -
 10.3706 -            boolean isInteger = widest.isInteger();
 10.3707 -            boolean isLong    = widest.isLong();
 10.3708 -
 10.3709 -            double value;
 10.3710 -
 10.3711 -            switch (parent.tokenType()) {
 10.3712 -            case AND:
 10.3713 -                return JSType.toBoolean(lhs.getObject()) ? rhs : lhs;
 10.3714 -            case OR:
 10.3715 -                return JSType.toBoolean(lhs.getObject()) ? lhs : rhs;
 10.3716 -            case DIV:
 10.3717 -                value = lhs.getNumber() / rhs.getNumber();
 10.3718 -                break;
 10.3719 -            case ADD:
 10.3720 -                value = lhs.getNumber() + rhs.getNumber();
 10.3721 -                break;
 10.3722 -            case MUL:
 10.3723 -                value = lhs.getNumber() * rhs.getNumber();
 10.3724 -                break;
 10.3725 -            case MOD:
 10.3726 -                value = lhs.getNumber() % rhs.getNumber();
 10.3727 -                break;
 10.3728 -            case SUB:
 10.3729 -                value = lhs.getNumber() - rhs.getNumber();
 10.3730 -                break;
 10.3731 -            case SHR:
 10.3732 -                return LiteralNode.newInstance(source, token, finish, (lhs.getInt32() >>> rhs.getInt32()) & 0xffff_ffffL);
 10.3733 -            case SAR:
 10.3734 -                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() >> rhs.getInt32());
 10.3735 -            case SHL:
 10.3736 -                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() << rhs.getInt32());
 10.3737 -            case BIT_XOR:
 10.3738 -                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() ^ rhs.getInt32());
 10.3739 -            case BIT_AND:
 10.3740 -                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() & rhs.getInt32());
 10.3741 -            case BIT_OR:
 10.3742 -                return LiteralNode.newInstance(source, token, finish, lhs.getInt32() | rhs.getInt32());
 10.3743 -            case GE:
 10.3744 -                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.GE(lhs.getObject(), rhs.getObject()));
 10.3745 -            case LE:
 10.3746 -                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.LE(lhs.getObject(), rhs.getObject()));
 10.3747 -            case GT:
 10.3748 -                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.GT(lhs.getObject(), rhs.getObject()));
 10.3749 -            case LT:
 10.3750 -                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.LT(lhs.getObject(), rhs.getObject()));
 10.3751 -            case NE:
 10.3752 -                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.NE(lhs.getObject(), rhs.getObject()));
 10.3753 -            case NE_STRICT:
 10.3754 -                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.NE_STRICT(lhs.getObject(), rhs.getObject()));
 10.3755 -            case EQ:
 10.3756 -                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.EQ(lhs.getObject(), rhs.getObject()));
 10.3757 -            case EQ_STRICT:
 10.3758 -                return LiteralNode.newInstance(source, token, finish, ScriptRuntime.EQ_STRICT(lhs.getObject(), rhs.getObject()));
 10.3759 -            default:
 10.3760 -                return null;
 10.3761 -            }
 10.3762 -
 10.3763 -            isInteger &= value != 0.0 && JSType.isRepresentableAsInt(value);
 10.3764 -            isLong    &= value != 0.0 && JSType.isRepresentableAsLong(value);
 10.3765 -
 10.3766 -            if (isInteger) {
 10.3767 -                return LiteralNode.newInstance(source, token, finish, JSType.toInt32(value));
 10.3768 -            } else if (isLong) {
 10.3769 -                return LiteralNode.newInstance(source, token, finish, JSType.toLong(value));
 10.3770 -            }
 10.3771 -
 10.3772 -            return LiteralNode.newInstance(source, token, finish, value);
 10.3773 -        }
 10.3774 -    }
 10.3775 -}
    11.1 --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue Jan 29 14:25:39 2013 -0400
    11.2 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Wed Jan 30 12:26:45 2013 +0100
    11.3 @@ -929,7 +929,7 @@
    11.4       */
    11.5      public MethodEmitter loadCallee() {
    11.6          debug("load callee " + functionNode.getCalleeNode().getSymbol());
    11.7 -        assert functionNode.getCalleeNode().getSymbol().getSlot() != 0;
    11.8 +        assert functionNode.getCalleeNode().getSymbol().getSlot() != 0 : "callee has wrong slot " + functionNode.getCalleeNode().getSymbol().getSlot() + " in " + functionNode.getName();
    11.9  
   11.10          return load(functionNode.getCalleeNode().getSymbol());
   11.11      }
   11.12 @@ -992,7 +992,7 @@
   11.13       * @param symbol symbol to store stack to
   11.14       */
   11.15      public void store(final Symbol symbol) {
   11.16 -        assert symbol != null;
   11.17 +        assert symbol != null : "No symbol to store";
   11.18          if (symbol.hasSlot()) {
   11.19              debug("store", symbol);
   11.20              popType(symbol.getSymbolType()).store(method, symbol.getSlot());
   11.21 @@ -1558,7 +1558,7 @@
   11.22              label.setStack(stack.clone());
   11.23              return;
   11.24          }
   11.25 -        assert stacksEquivalent(stack, labelStack);
   11.26 +        assert stacksEquivalent(stack, labelStack) : "stacks " + stack + " is not equivalent with " + labelStack + " at join point";
   11.27      }
   11.28  
   11.29      /**
    12.1 --- a/src/jdk/nashorn/internal/codegen/SharedScopeCall.java	Tue Jan 29 14:25:39 2013 -0400
    12.2 +++ b/src/jdk/nashorn/internal/codegen/SharedScopeCall.java	Wed Jan 30 12:26:45 2013 +0100
    12.3 @@ -159,7 +159,9 @@
    12.4              int slot = 2;
    12.5              for (final Type type : paramTypes) {
    12.6                  method.load(type, slot++);
    12.7 -                if (type == Type.NUMBER || type == Type.LONG) slot++;
    12.8 +                if (type == Type.NUMBER || type == Type.LONG) {
    12.9 +                    slot++;
   12.10 +                }
   12.11              }
   12.12              method.dynamicCall(returnType, paramTypes.length, flags);
   12.13          }
    13.1 --- a/src/jdk/nashorn/internal/codegen/WeighNodes.java	Tue Jan 29 14:25:39 2013 -0400
    13.2 +++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java	Wed Jan 30 12:26:45 2013 +0100
    13.3 @@ -27,6 +27,8 @@
    13.4  
    13.5  import java.util.List;
    13.6  import java.util.Map;
    13.7 +
    13.8 +import jdk.nashorn.internal.codegen.types.Type;
    13.9  import jdk.nashorn.internal.ir.AccessNode;
   13.10  import jdk.nashorn.internal.ir.BinaryNode;
   13.11  import jdk.nashorn.internal.ir.Block;
   13.12 @@ -53,17 +55,18 @@
   13.13  import jdk.nashorn.internal.ir.SwitchNode;
   13.14  import jdk.nashorn.internal.ir.ThrowNode;
   13.15  import jdk.nashorn.internal.ir.TryNode;
   13.16 +import jdk.nashorn.internal.ir.UnaryNode;
   13.17  import jdk.nashorn.internal.ir.VarNode;
   13.18  import jdk.nashorn.internal.ir.WhileNode;
   13.19  import jdk.nashorn.internal.ir.WithNode;
   13.20 -import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   13.21 -import jdk.nashorn.internal.parser.TokenType;
   13.22 +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
   13.23 +
   13.24  
   13.25  /**
   13.26   * Computes the "byte code" weight of an AST segment. This is used
   13.27   * for Splitting too large class files
   13.28   */
   13.29 -public class WeighNodes extends NodeVisitor {
   13.30 +public class WeighNodes extends NodeOperatorVisitor {
   13.31      /*
   13.32       * Weight constants.
   13.33       */
   13.34 @@ -77,6 +80,7 @@
   13.35      private static final long IF_WEIGHT        = 2;
   13.36      private static final long LITERAL_WEIGHT   = 10;
   13.37      private static final long LOOP_WEIGHT      = 4;
   13.38 +    private static final long NEW_WEIGHT       = 6;
   13.39      private static final long REFERENCE_WEIGHT = 20;
   13.40      private static final long RETURN_WEIGHT    = 2;
   13.41      private static final long SPLIT_WEIGHT     = 40;
   13.42 @@ -120,21 +124,7 @@
   13.43      }
   13.44  
   13.45      @Override
   13.46 -    public Node leave(final BinaryNode binaryNode) {
   13.47 -        final TokenType tokenType = binaryNode.tokenType();
   13.48 -
   13.49 -        if (tokenType == TokenType.ADD || tokenType == TokenType.ASSIGN_ADD) {
   13.50 -            weight += ADD_WEIGHT;
   13.51 -        } else {
   13.52 -            weight += 1;
   13.53 -        }
   13.54 -
   13.55 -        return binaryNode;
   13.56 -    }
   13.57 -
   13.58 -    @Override
   13.59      public Node enter(final Block block) {
   13.60 -
   13.61          if (weightCache != null && weightCache.containsKey(block)) {
   13.62              weight += weightCache.get(block);
   13.63              return null;
   13.64 @@ -305,4 +295,274 @@
   13.65          weight += WITH_WEIGHT;
   13.66          return withNode;
   13.67      }
   13.68 +
   13.69 +    @Override
   13.70 +    public Node leaveADD(final UnaryNode unaryNode) {
   13.71 +        return unaryNodeWeight(unaryNode);
   13.72 +    }
   13.73 +
   13.74 +    @Override
   13.75 +    public Node leaveBIT_NOT(final UnaryNode unaryNode) {
   13.76 +        return unaryNodeWeight(unaryNode);
   13.77 +    }
   13.78 +
   13.79 +    @Override
   13.80 +    public Node leaveCONVERT(final UnaryNode unaryNode) {
   13.81 +        return unaryNodeWeight(unaryNode);
   13.82 +    }
   13.83 +
   13.84 +    @Override
   13.85 +    public Node leaveDECINC(final UnaryNode unaryNode) {
   13.86 +         return unaryNodeWeight(unaryNode);
   13.87 +    }
   13.88 +
   13.89 +    @Override
   13.90 +    public Node leaveDELETE(final UnaryNode unaryNode) {
   13.91 +        return runtimeNodeWeight(unaryNode);
   13.92 +    }
   13.93 +
   13.94 +    @Override
   13.95 +    public Node leaveDISCARD(final UnaryNode unaryNode) {
   13.96 +        return unaryNodeWeight(unaryNode);
   13.97 +    }
   13.98 +
   13.99 +    @Override
  13.100 +    public Node leaveNEW(final UnaryNode unaryNode) {
  13.101 +        weight += NEW_WEIGHT;
  13.102 +        return unaryNode;
  13.103 +    }
  13.104 +
  13.105 +    @Override
  13.106 +    public Node leaveNOT(final UnaryNode unaryNode) {
  13.107 +        return unaryNodeWeight(unaryNode);
  13.108 +    }
  13.109 +
  13.110 +    @Override
  13.111 +    public Node leaveSUB(final UnaryNode unaryNode) {
  13.112 +        return unaryNodeWeight(unaryNode);
  13.113 +    }
  13.114 +
  13.115 +    @Override
  13.116 +    public Node leaveTYPEOF(final UnaryNode unaryNode) {
  13.117 +        return runtimeNodeWeight(unaryNode);
  13.118 +    }
  13.119 +
  13.120 +    @Override
  13.121 +    public Node leaveVOID(final UnaryNode unaryNode) {
  13.122 +        return unaryNodeWeight(unaryNode);
  13.123 +    }
  13.124 +
  13.125 +    @Override
  13.126 +    public Node leaveADD(final BinaryNode binaryNode) {
  13.127 +        weight += ADD_WEIGHT;
  13.128 +        return binaryNode;
  13.129 +    }
  13.130 +
  13.131 +    @Override
  13.132 +    public Node leaveAND(final BinaryNode binaryNode) {
  13.133 +        return binaryNodeWeight(binaryNode);
  13.134 +    }
  13.135 +
  13.136 +    @Override
  13.137 +    public Node leaveASSIGN(final BinaryNode binaryNode) {
  13.138 +        return binaryNodeWeight(binaryNode);
  13.139 +    }
  13.140 +
  13.141 +    @Override
  13.142 +    public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
  13.143 +        weight += ADD_WEIGHT;
  13.144 +        return binaryNode;
  13.145 +    }
  13.146 +
  13.147 +    @Override
  13.148 +    public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) {
  13.149 +        return binaryNodeWeight(binaryNode);
  13.150 +    }
  13.151 +
  13.152 +    @Override
  13.153 +    public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) {
  13.154 +        return binaryNodeWeight(binaryNode);
  13.155 +    }
  13.156 +
  13.157 +    @Override
  13.158 +    public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) {
  13.159 +        return binaryNodeWeight(binaryNode);
  13.160 +    }
  13.161 +
  13.162 +    @Override
  13.163 +    public Node leaveASSIGN_DIV(final BinaryNode binaryNode) {
  13.164 +        return binaryNodeWeight(binaryNode);
  13.165 +    }
  13.166 +
  13.167 +    @Override
  13.168 +    public Node leaveASSIGN_MOD(final BinaryNode binaryNode) {
  13.169 +        return binaryNodeWeight(binaryNode);
  13.170 +    }
  13.171 +
  13.172 +    @Override
  13.173 +    public Node leaveASSIGN_MUL(final BinaryNode binaryNode) {
  13.174 +        return binaryNodeWeight(binaryNode);
  13.175 +    }
  13.176 +
  13.177 +    @Override
  13.178 +    public Node leaveASSIGN_SAR(final BinaryNode binaryNode) {
  13.179 +        return binaryNodeWeight(binaryNode);
  13.180 +    }
  13.181 +
  13.182 +    @Override
  13.183 +    public Node leaveASSIGN_SHL(final BinaryNode binaryNode) {
  13.184 +        return binaryNodeWeight(binaryNode);
  13.185 +    }
  13.186 +
  13.187 +    @Override
  13.188 +    public Node leaveASSIGN_SHR(final BinaryNode binaryNode) {
  13.189 +        return binaryNodeWeight(binaryNode);
  13.190 +    }
  13.191 +
  13.192 +    @Override
  13.193 +    public Node leaveASSIGN_SUB(final BinaryNode binaryNode) {
  13.194 +        return binaryNodeWeight(binaryNode);
  13.195 +    }
  13.196 +
  13.197 +    @Override
  13.198 +    public Node leaveBIND(final BinaryNode binaryNode) {
  13.199 +        return binaryNodeWeight(binaryNode);
  13.200 +    }
  13.201 +
  13.202 +    @Override
  13.203 +    public Node leaveBIT_AND(final BinaryNode binaryNode) {
  13.204 +        return binaryNodeWeight(binaryNode);
  13.205 +    }
  13.206 +
  13.207 +    @Override
  13.208 +    public Node leaveBIT_OR(final BinaryNode binaryNode) {
  13.209 +        return binaryNodeWeight(binaryNode);
  13.210 +    }
  13.211 +
  13.212 +    @Override
  13.213 +    public Node leaveBIT_XOR(final BinaryNode binaryNode) {
  13.214 +        return binaryNodeWeight(binaryNode);
  13.215 +    }
  13.216 +
  13.217 +    @Override
  13.218 +    public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
  13.219 +        return binaryNodeWeight(binaryNode);
  13.220 +    }
  13.221 +
  13.222 +    @Override
  13.223 +    public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
  13.224 +        return binaryNodeWeight(binaryNode);
  13.225 +    }
  13.226 +
  13.227 +    @Override
  13.228 +    public Node leaveDIV(final BinaryNode binaryNode) {
  13.229 +        return binaryNodeWeight(binaryNode);
  13.230 +    }
  13.231 +
  13.232 +    @Override
  13.233 +    public Node leaveEQ(final BinaryNode binaryNode) {
  13.234 +        return runtimeNodeWeight(binaryNode);
  13.235 +    }
  13.236 +
  13.237 +    @Override
  13.238 +    public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
  13.239 +        return runtimeNodeWeight(binaryNode);
  13.240 +    }
  13.241 +
  13.242 +    @Override
  13.243 +    public Node leaveGE(final BinaryNode binaryNode) {
  13.244 +        return runtimeNodeWeight(binaryNode);
  13.245 +    }
  13.246 +
  13.247 +    @Override
  13.248 +    public Node leaveGT(final BinaryNode binaryNode) {
  13.249 +        return runtimeNodeWeight(binaryNode);
  13.250 +    }
  13.251 +
  13.252 +    @Override
  13.253 +    public Node leaveIN(final BinaryNode binaryNode) {
  13.254 +        weight += CALL_WEIGHT;
  13.255 +        return binaryNode;
  13.256 +    }
  13.257 +
  13.258 +    @Override
  13.259 +    public Node leaveINSTANCEOF(final BinaryNode binaryNode) {
  13.260 +        weight += CALL_WEIGHT;
  13.261 +        return binaryNode;
  13.262 +    }
  13.263 +
  13.264 +    @Override
  13.265 +    public Node leaveLE(final BinaryNode binaryNode) {
  13.266 +        return runtimeNodeWeight(binaryNode);
  13.267 +    }
  13.268 +
  13.269 +    @Override
  13.270 +    public Node leaveLT(final BinaryNode binaryNode) {
  13.271 +        return runtimeNodeWeight(binaryNode);
  13.272 +    }
  13.273 +
  13.274 +    @Override
  13.275 +    public Node leaveMOD(final BinaryNode binaryNode) {
  13.276 +        return binaryNodeWeight(binaryNode);
  13.277 +    }
  13.278 +
  13.279 +    @Override
  13.280 +    public Node leaveMUL(final BinaryNode binaryNode) {
  13.281 +        return binaryNodeWeight(binaryNode);
  13.282 +    }
  13.283 +
  13.284 +    @Override
  13.285 +    public Node leaveNE(final BinaryNode binaryNode) {
  13.286 +        return runtimeNodeWeight(binaryNode);
  13.287 +    }
  13.288 +
  13.289 +    @Override
  13.290 +    public Node leaveNE_STRICT(final BinaryNode binaryNode) {
  13.291 +        return runtimeNodeWeight(binaryNode);
  13.292 +    }
  13.293 +
  13.294 +    @Override
  13.295 +    public Node leaveOR(final BinaryNode binaryNode) {
  13.296 +        return binaryNodeWeight(binaryNode);
  13.297 +    }
  13.298 +
  13.299 +    @Override
  13.300 +    public Node leaveSAR(final BinaryNode binaryNode) {
  13.301 +        return binaryNodeWeight(binaryNode);
  13.302 +    }
  13.303 +
  13.304 +    @Override
  13.305 +    public Node leaveSHL(final BinaryNode binaryNode) {
  13.306 +        return binaryNodeWeight(binaryNode);
  13.307 +    }
  13.308 +
  13.309 +    @Override
  13.310 +    public Node leaveSHR(final BinaryNode binaryNode) {
  13.311 +        return binaryNodeWeight(binaryNode);
  13.312 +    }
  13.313 +
  13.314 +    @Override
  13.315 +    public Node leaveSUB(final BinaryNode binaryNode) {
  13.316 +        return binaryNodeWeight(binaryNode);
  13.317 +    }
  13.318 +
  13.319 +    private Node unaryNodeWeight(final UnaryNode unaryNode) {
  13.320 +        weight += 1;
  13.321 +        return unaryNode;
  13.322 +    }
  13.323 +
  13.324 +    private Node binaryNodeWeight(final BinaryNode binaryNode) {
  13.325 +        weight += 1;
  13.326 +        return binaryNode;
  13.327 +    }
  13.328 +
  13.329 +    private Node runtimeNodeWeight(final UnaryNode unaryNode) {
  13.330 +        weight += CALL_WEIGHT;
  13.331 +        return unaryNode;
  13.332 +    }
  13.333 +
  13.334 +    private Node runtimeNodeWeight(final BinaryNode binaryNode) {
  13.335 +        weight += Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()).isObject() ? CALL_WEIGHT : 1;
  13.336 +        return binaryNode;
  13.337 +    }
  13.338  }
    14.1 --- a/src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java	Tue Jan 29 14:25:39 2013 -0400
    14.2 +++ b/src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java	Wed Jan 30 12:26:45 2013 +0100
    14.3 @@ -33,8 +33,9 @@
    14.4  import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
    14.5  
    14.6  import java.lang.invoke.MethodHandle;
    14.7 +import java.util.ArrayList;
    14.8  import java.util.EnumSet;
    14.9 -import java.util.List;
   14.10 +
   14.11  import jdk.nashorn.internal.codegen.CodeGenerator;
   14.12  import jdk.nashorn.internal.codegen.FunctionSignature;
   14.13  import jdk.nashorn.internal.codegen.MethodEmitter;
   14.14 @@ -61,11 +62,9 @@
   14.15       *
   14.16       * @param codegen      the code generator
   14.17       * @param functionNode the function node to turn into a ScriptFunction implementation
   14.18 -     * @param keys         initial keys for the object map
   14.19 -     * @param symbols      corresponding initial symbols for object map
   14.20       */
   14.21 -    public FunctionObjectCreator(final CodeGenerator codegen, final FunctionNode functionNode, final List<String> keys, final List<Symbol> symbols) {
   14.22 -        super(codegen, keys, symbols, false, false);
   14.23 +    public FunctionObjectCreator(final CodeGenerator codegen, final FunctionNode functionNode) {
   14.24 +        super(codegen, new ArrayList<String>(), new ArrayList<Symbol>(), false, false);
   14.25          this.functionNode = functionNode;
   14.26      }
   14.27  
    15.1 --- a/src/jdk/nashorn/internal/ir/Block.java	Tue Jan 29 14:25:39 2013 -0400
    15.2 +++ b/src/jdk/nashorn/internal/ir/Block.java	Wed Jan 30 12:26:45 2013 +0100
    15.3 @@ -35,11 +35,11 @@
    15.4  
    15.5  import java.io.PrintWriter;
    15.6  import java.util.ArrayList;
    15.7 -import java.util.Collection;
    15.8  import java.util.Collections;
    15.9 +import java.util.Comparator;
   15.10  import java.util.HashMap;
   15.11  import java.util.List;
   15.12 -import java.util.Map;
   15.13 +
   15.14  import jdk.nashorn.internal.codegen.Frame;
   15.15  import jdk.nashorn.internal.codegen.MethodEmitter.Label;
   15.16  import jdk.nashorn.internal.ir.annotations.Ignore;
   15.17 @@ -287,7 +287,7 @@
   15.18  
   15.19          for (Block block = this; block != null; block = block.getParent()) {
   15.20              // Find name.
   15.21 -            final Symbol symbol = block.getSymbols().get(name);
   15.22 +            final Symbol symbol = block.symbols.get(name);
   15.23              // If found then we are good.
   15.24              if (symbol != null) {
   15.25                  return symbol;
   15.26 @@ -307,7 +307,7 @@
   15.27          // Search up block chain to locate symbol.
   15.28          for (Block block = this; block != null; block = block.getParent()) {
   15.29              // Find name.
   15.30 -            final Symbol symbol = block.getSymbols().get(name);
   15.31 +            final Symbol symbol = block.symbols.get(name);
   15.32              // If found then we are good.
   15.33              if (symbol != null) {
   15.34                  return symbol;
   15.35 @@ -458,14 +458,22 @@
   15.36      }
   15.37  
   15.38      /**
   15.39 -     * Print symbols in block (debugging.)
   15.40 +     * Print symbols in block in alphabetical order, sorted on name
   15.41 +     * Used for debugging, see the --print-symbols flag
   15.42       *
   15.43       * @param stream print writer to output symbols to
   15.44       *
   15.45       * @return true if symbols were found
   15.46       */
   15.47      public boolean printSymbols(final PrintWriter stream) {
   15.48 -        final Collection<Symbol> values = symbols.values();
   15.49 +        final List<Symbol> values = new ArrayList<>(symbols.values());
   15.50 +
   15.51 +        Collections.sort(values, new Comparator<Symbol>() {
   15.52 +            @Override
   15.53 +            public int compare(final Symbol s0, final Symbol s1) {
   15.54 +                return s0.getName().compareTo(s1.getName());
   15.55 +            }
   15.56 +        });
   15.57  
   15.58          for (final Symbol symbol : values) {
   15.59              symbol.print(stream);
   15.60 @@ -564,15 +572,6 @@
   15.61      }
   15.62  
   15.63      /**
   15.64 -     * Get the symbol table for this block
   15.65 -     *
   15.66 -     * @return a symbol table, which is a map from symbol name to symbol.
   15.67 -     */
   15.68 -    private Map<String, Symbol> getSymbols() {
   15.69 -        return symbols;
   15.70 -    }
   15.71 -
   15.72 -    /**
   15.73       * Check whether scope is necessary for this Block
   15.74       *
   15.75       * @return true if this function needs a scope
    16.1 --- a/src/jdk/nashorn/internal/ir/CallNode.java	Tue Jan 29 14:25:39 2013 -0400
    16.2 +++ b/src/jdk/nashorn/internal/ir/CallNode.java	Wed Jan 30 12:26:45 2013 +0100
    16.3 @@ -28,7 +28,9 @@
    16.4  import java.util.ArrayList;
    16.5  import java.util.Collections;
    16.6  import java.util.List;
    16.7 +
    16.8  import jdk.nashorn.internal.codegen.types.Type;
    16.9 +import jdk.nashorn.internal.ir.annotations.Ignore;
   16.10  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   16.11  import jdk.nashorn.internal.runtime.Source;
   16.12  
   16.13 @@ -57,16 +59,83 @@
   16.14       */
   16.15      public static class EvalArgs {
   16.16          /** evaluated code */
   16.17 -        public Node    code;
   16.18 +        private Node code;
   16.19 +
   16.20          /** 'this' passed to evaluated code */
   16.21 -        public Node    evalThis;
   16.22 +        private IdentNode evalThis;
   16.23 +
   16.24          /** location string for the eval call */
   16.25 -        public String  location;
   16.26 +        final private String location;
   16.27 +
   16.28          /** is this call from a strict context? */
   16.29 -        public boolean strictMode;
   16.30 +        final private boolean strictMode;
   16.31 +
   16.32 +        /**
   16.33 +         * Constructor
   16.34 +         *
   16.35 +         * @param code       code to evaluate
   16.36 +         * @param evalThis   this node
   16.37 +         * @param location   location for the eval call
   16.38 +         * @param strictMode is this a call from a strict context?
   16.39 +         */
   16.40 +        public EvalArgs(final Node code, final IdentNode evalThis, final String location, final boolean strictMode) {
   16.41 +            this.code = code;
   16.42 +            this.evalThis = evalThis;
   16.43 +            this.location = location;
   16.44 +            this.strictMode = strictMode;
   16.45 +        }
   16.46 +
   16.47 +        /**
   16.48 +         * Return the code that is to be eval:ed by this eval function
   16.49 +         * @return code as an AST node
   16.50 +         */
   16.51 +        public Node getCode() {
   16.52 +            return code;
   16.53 +        }
   16.54 +
   16.55 +        /**
   16.56 +         * Set the code that is to be eval.ed by this eval function
   16.57 +         * @param code the code as an AST node
   16.58 +         */
   16.59 +        public void setCode(final Node code) {
   16.60 +            this.code = code;
   16.61 +        }
   16.62 +
   16.63 +        /**
   16.64 +         * Get the {@code this} symbol used to invoke this eval call
   16.65 +         * @return the {@code this} symbol
   16.66 +         */
   16.67 +        public IdentNode getThis() {
   16.68 +            return this.evalThis;
   16.69 +        }
   16.70 +
   16.71 +        /**
   16.72 +         * Set the {@code this} symbol used to invoke this eval call
   16.73 +         * @param evalThis the {@code this} symbol
   16.74 +         */
   16.75 +        public void setThis(final IdentNode evalThis) {
   16.76 +            this.evalThis = evalThis;
   16.77 +        }
   16.78 +
   16.79 +        /**
   16.80 +         * Get the human readable location for this eval call
   16.81 +         * @return the location
   16.82 +         */
   16.83 +        public String getLocation() {
   16.84 +            return this.location;
   16.85 +        }
   16.86 +
   16.87 +        /**
   16.88 +         * Check whether this eval call is executed in strict mode
   16.89 +         * @return true if executed in strict mode, false otherwise
   16.90 +         */
   16.91 +        public boolean getStrictMode() {
   16.92 +            return this.strictMode;
   16.93 +        }
   16.94      }
   16.95  
   16.96      /** arguments for 'eval' call. Non-null only if this call node is 'eval' */
   16.97 +    @Ignore
   16.98      private EvalArgs evalArgs;
   16.99  
  16.100      /**
    17.1 --- a/src/jdk/nashorn/internal/ir/CatchNode.java	Tue Jan 29 14:25:39 2013 -0400
    17.2 +++ b/src/jdk/nashorn/internal/ir/CatchNode.java	Wed Jan 30 12:26:45 2013 +0100
    17.3 @@ -57,7 +57,7 @@
    17.4       * @param body               catch body
    17.5       */
    17.6      public CatchNode(final Source source, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) {
    17.7 -        super (source, token, finish);
    17.8 +        super(source, token, finish);
    17.9  
   17.10          this.exception          = exception;
   17.11          this.exceptionCondition = exceptionCondition;
    18.1 --- a/src/jdk/nashorn/internal/ir/ExecuteNode.java	Tue Jan 29 14:25:39 2013 -0400
    18.2 +++ b/src/jdk/nashorn/internal/ir/ExecuteNode.java	Wed Jan 30 12:26:45 2013 +0100
    18.3 @@ -47,14 +47,22 @@
    18.4       */
    18.5      public ExecuteNode(final Source source, final long token, final int finish, final Node expression) {
    18.6          super(source, token, finish);
    18.7 +        this.expression = expression;
    18.8 +    }
    18.9  
   18.10 +    /**
   18.11 +     * Constructor
   18.12 +     *
   18.13 +     * @param expression an expression to wrap, from which source, tokens and finish are also inherited
   18.14 +     */
   18.15 +    public ExecuteNode(final Node expression) {
   18.16 +        super(expression.getSource(), expression.getToken(), expression.getFinish());
   18.17          this.expression = expression;
   18.18      }
   18.19  
   18.20      private ExecuteNode(final ExecuteNode executeNode, final CopyState cs) {
   18.21          super(executeNode);
   18.22 -
   18.23 -        expression = cs.existingOrCopy(executeNode.expression);
   18.24 +        this.expression = cs.existingOrCopy(executeNode.expression);
   18.25      }
   18.26  
   18.27      @Override
    19.1 --- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Tue Jan 29 14:25:39 2013 -0400
    19.2 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Wed Jan 30 12:26:45 2013 +0100
    19.3 @@ -32,10 +32,8 @@
    19.4  
    19.5  import java.util.ArrayList;
    19.6  import java.util.Collections;
    19.7 -import java.util.LinkedHashMap;
    19.8  import java.util.LinkedList;
    19.9  import java.util.List;
   19.10 -import java.util.Map;
   19.11  import java.util.Stack;
   19.12  import jdk.nashorn.internal.codegen.CompileUnit;
   19.13  import jdk.nashorn.internal.codegen.Compiler;
   19.14 @@ -126,9 +124,6 @@
   19.15      @Ignore
   19.16      private IdentNode varArgsNode;
   19.17  
   19.18 -    /** this access properties. */
   19.19 -    private final LinkedHashMap<String, Node> thisProperties;
   19.20 -
   19.21      /** Pending label list. */
   19.22      private final Stack<LabelNode> labelStack;
   19.23  
   19.24 @@ -147,6 +142,10 @@
   19.25      @Ignore
   19.26      private LineNumberNode funcVarLineNumberNode;
   19.27  
   19.28 +    /** Initializer var func = __callee__, where applicable */
   19.29 +    @Ignore
   19.30 +    private Node selfSymbolInit;
   19.31 +
   19.32      /** Function flags. */
   19.33      private int flags;
   19.34  
   19.35 @@ -183,7 +182,7 @@
   19.36      private static final int NEEDS_SCOPE           = HAS_ALL_VARS_IN_SCOPE | IS_VAR_ARG;
   19.37  
   19.38      /** What is the return type of this function? */
   19.39 -    private Type returnType = Type.OBJECT;
   19.40 +    private Type returnType = Type.UNKNOWN;
   19.41  
   19.42      /**
   19.43       * Used to keep track of a function's parent blocks.
   19.44 @@ -216,7 +215,6 @@
   19.45          this.firstToken        = token;
   19.46          this.lastToken         = token;
   19.47          this.namespace         = new Namespace(compiler.getNamespace().getParent());
   19.48 -        this.thisProperties    = new LinkedHashMap<>();
   19.49          this.labelStack        = new Stack<>();
   19.50          this.controlStack      = new Stack<>();
   19.51          this.declarations      = new ArrayList<>();
   19.52 @@ -249,7 +247,6 @@
   19.53          this.argumentsNode     = (IdentNode)cs.existingOrCopy(functionNode.argumentsNode);
   19.54          this.varArgsNode       = (IdentNode)cs.existingOrCopy(functionNode.varArgsNode);
   19.55          this.calleeNode        = (IdentNode)cs.existingOrCopy(functionNode.calleeNode);
   19.56 -        this.thisProperties    = new LinkedHashMap<>();
   19.57          this.labelStack        = new Stack<>();
   19.58          this.controlStack      = new Stack<>();
   19.59          this.declarations      = new ArrayList<>();
   19.60 @@ -372,30 +369,44 @@
   19.61      /**
   19.62       * Create a temporary variable to the current frame.
   19.63       *
   19.64 +     * @param currentFrame Frame to add to - defaults to current function frame
   19.65       * @param type  Strong type of symbol.
   19.66       * @param node  Primary node to use symbol.
   19.67       *
   19.68       * @return Symbol used.
   19.69       */
   19.70 -    public Symbol newTemporary(final Type type, final Node node) {
   19.71 -        Symbol sym = node.getSymbol();
   19.72 +    public Symbol newTemporary(final Frame currentFrame, final Type type, final Node node) {
   19.73 +        assert currentFrame != null;
   19.74 +        Symbol symbol = node.getSymbol();
   19.75  
   19.76          // If no symbol already present.
   19.77 -        if (sym == null) {
   19.78 +        if (symbol == null) {
   19.79              final String uname = uniqueName(TEMP_PREFIX.tag());
   19.80 -            sym = new Symbol(uname, IS_TEMP, type);
   19.81 -            sym.setNode(node);
   19.82 +            symbol = new Symbol(uname, IS_TEMP, type);
   19.83 +            symbol.setNode(node);
   19.84          }
   19.85  
   19.86          // Assign a slot if it doesn't have one.
   19.87 -        if (!sym.hasSlot()) {
   19.88 -            frames.addSymbol(sym);
   19.89 +        if (!symbol.hasSlot()) {
   19.90 +            currentFrame.addSymbol(symbol);
   19.91          }
   19.92  
   19.93          // Set symbol to node.
   19.94 -        node.setSymbol(sym);
   19.95 +        node.setSymbol(symbol);
   19.96  
   19.97 -        return sym;
   19.98 +        return symbol;
   19.99 +    }
  19.100 +
  19.101 +    /**
  19.102 +     * Add a new temporary variable to the current frame
  19.103 +     *
  19.104 +     * @param type Strong type of symbol
  19.105 +     * @param node Primary node to use symbol
  19.106 +     *
  19.107 +     * @return symbol used
  19.108 +     */
  19.109 +    public Symbol newTemporary(final Type type, final Node node) {
  19.110 +        return newTemporary(frames, type, node);
  19.111      }
  19.112  
  19.113      /**
  19.114 @@ -414,22 +425,13 @@
  19.115          return sym;
  19.116      }
  19.117  
  19.118 -    /**
  19.119 -     * Add a property to the constructor (function) based on this.x usage.
  19.120 -     *
  19.121 -     * @param key  Name of property.
  19.122 -     * @param node Value node (has type.)
  19.123 -     */
  19.124 -    public void addThisProperty(final String key, final Node node) {
  19.125 -        if (node == null) {
  19.126 -            return;
  19.127 -        }
  19.128 -
  19.129 -        thisProperties.put(key, node);
  19.130 -    }
  19.131 -
  19.132      @Override
  19.133      public void toString(final StringBuilder sb) {
  19.134 +        sb.append('[');
  19.135 +        sb.append(returnType);
  19.136 +        sb.append(']');
  19.137 +        sb.append(' ');
  19.138 +
  19.139          sb.append("function");
  19.140  
  19.141          if (ident != null) {
  19.142 @@ -872,11 +874,22 @@
  19.143      }
  19.144  
  19.145      /**
  19.146 +     * Get the initializer statement for the __callee__ variable, where applicable
  19.147 +     * for self references
  19.148 +     * @return initialization
  19.149 +     */
  19.150 +    public Node getSelfSymbolInit() {
  19.151 +        return this.selfSymbolInit;
  19.152 +    }
  19.153 +
  19.154 +    /**
  19.155       * Flag the function as needing a self symbol. This is needed only for
  19.156       * self referring functions
  19.157 +     * @param selfSymbolInit initialization expression for self symbol
  19.158       */
  19.159 -    public void setNeedsSelfSymbol() {
  19.160 +    public void setNeedsSelfSymbol(final Node selfSymbolInit) {
  19.161          this.flags |= NEEDS_SELF_SYMBOL;
  19.162 +        this.selfSymbolInit = selfSymbolInit;
  19.163      }
  19.164  
  19.165      /**
  19.166 @@ -942,16 +955,6 @@
  19.167      }
  19.168  
  19.169      /**
  19.170 -     * Get a all properties accessed with {@code this} used as a base in this
  19.171 -     * function - the map is ordered upon assignment order in the control flow
  19.172 -     *
  19.173 -     * @return map a map of property name to node mapping for this accesses
  19.174 -     */
  19.175 -    public Map<String, Node> getThisProperties() {
  19.176 -        return Collections.unmodifiableMap(thisProperties);
  19.177 -    }
  19.178 -
  19.179 -    /**
  19.180       * Get the namespace this function uses for its symbols
  19.181       * @return the namespace
  19.182       */
  19.183 @@ -984,11 +987,7 @@
  19.184          //we never bother with object types narrower than objects, that will lead to byte code verification errors
  19.185          //as for instance even if we know we are returning a string from a method, the code generator will always
  19.186          //treat it as an object, at least for now
  19.187 -        this.returnType = returnType.isObject() ? Type.OBJECT : returnType;
  19.188 -        // Adjust type of result node symbol
  19.189 -        if (returnType != Type.UNKNOWN) {
  19.190 -            resultNode.getSymbol().setTypeOverride(this.returnType);
  19.191 -        }
  19.192 +        this.returnType = Type.widest(this.returnType,  returnType.isObject() ? Type.OBJECT : returnType);
  19.193      }
  19.194  
  19.195      /**
  19.196 @@ -1010,15 +1009,13 @@
  19.197  
  19.198      /**
  19.199       * Set the lowered state
  19.200 -     *
  19.201 -     * @param isLowered lowered state
  19.202       */
  19.203 -    public void setIsLowered(final boolean isLowered) {
  19.204 -        flags = isLowered ? flags | IS_LOWERED : flags & ~IS_LOWERED;
  19.205 +    public void setIsLowered() {
  19.206 +        flags |= IS_LOWERED;
  19.207      }
  19.208  
  19.209      /**
  19.210 -     * Get the lowered
  19.211 +     * Get the lowered state
  19.212       *
  19.213       * @return true if function is lowered
  19.214       */
  19.215 @@ -1077,22 +1074,6 @@
  19.216      }
  19.217  
  19.218      /**
  19.219 -     * @return the unit index
  19.220 -     */
  19.221 -//    public int getUnit() {
  19.222 - //       return unit;
  19.223 - //   }
  19.224 -
  19.225 -    /**
  19.226 -     * Set the index of this function's compile unit. Used by splitter.
  19.227 -     * @see Splitter
  19.228 -     * @param unit the unit index
  19.229 -     */
  19.230 -//    public void setUnit(final int unit) {
  19.231 -//        this.unit = unit;
  19.232 -//    }
  19.233 -
  19.234 -    /**
  19.235       * Get the compile unit used to compile this function
  19.236       * @see Compiler
  19.237       * @see Splitter
    20.1 --- a/src/jdk/nashorn/internal/ir/LiteralNode.java	Tue Jan 29 14:25:39 2013 -0400
    20.2 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java	Wed Jan 30 12:26:45 2013 +0100
    20.3 @@ -32,8 +32,10 @@
    20.4  import jdk.nashorn.internal.codegen.types.Type;
    20.5  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    20.6  import jdk.nashorn.internal.parser.Lexer.LexerToken;
    20.7 +import jdk.nashorn.internal.parser.Token;
    20.8  import jdk.nashorn.internal.parser.TokenType;
    20.9  import jdk.nashorn.internal.runtime.JSType;
   20.10 +import jdk.nashorn.internal.runtime.ScriptRuntime;
   20.11  import jdk.nashorn.internal.runtime.Source;
   20.12  import jdk.nashorn.internal.runtime.Undefined;
   20.13  
   20.14 @@ -200,6 +202,15 @@
   20.15      }
   20.16  
   20.17      /**
   20.18 +     * Test if tha value is a number
   20.19 +     *
   20.20 +     * @return True if value is a number
   20.21 +     */
   20.22 +    public boolean isNumeric() {
   20.23 +        return value instanceof Number;
   20.24 +    }
   20.25 +
   20.26 +    /**
   20.27       * Assist in IR navigation.
   20.28       *
   20.29       * @param visitor IR navigating visitor.
   20.30 @@ -240,16 +251,49 @@
   20.31       * @return the new literal node
   20.32       */
   20.33      public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish) {
   20.34 -        return new LiteralNode<Node>(source, token, finish, null) {
   20.35 -            @Override
   20.36 -            protected Node copy(final CopyState cs) {
   20.37 -                return LiteralNode.newInstance(getSource(), getToken(), getFinish());
   20.38 -            }
   20.39 -            @Override
   20.40 -            public Type getType() {
   20.41 -                return Type.OBJECT;
   20.42 -            }
   20.43 -        };
   20.44 +        return new NodeLiteralNode(source, token, finish);
   20.45 +    }
   20.46 +
   20.47 +    /**
   20.48 +     * Create a new null literal based on a parent node (source, token, finish)
   20.49 +     *
   20.50 +     * @param parent parent node
   20.51 +     *
   20.52 +     * @return the new literal node
   20.53 +     */
   20.54 +    public static LiteralNode<?> newInstance(final Node parent) {
   20.55 +        return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish());
   20.56 +    }
   20.57 +
   20.58 +    private static class BooleanLiteralNode extends LiteralNode<Boolean> {
   20.59 +
   20.60 +        private BooleanLiteralNode(final Source source, final long token, final int finish, final boolean value) {
   20.61 +            super(source, Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
   20.62 +        }
   20.63 +
   20.64 +        private BooleanLiteralNode(final BooleanLiteralNode literalNode) {
   20.65 +            super(literalNode);
   20.66 +        }
   20.67 +
   20.68 +        @Override
   20.69 +        protected Node copy(final CopyState cs) {
   20.70 +            return new BooleanLiteralNode(this);
   20.71 +        }
   20.72 +
   20.73 +        @Override
   20.74 +        public boolean isTrue() {
   20.75 +            return value;
   20.76 +        }
   20.77 +
   20.78 +        @Override
   20.79 +        public Type getType() {
   20.80 +            return Type.BOOLEAN;
   20.81 +        }
   20.82 +
   20.83 +        @Override
   20.84 +        public Type getWidestOperationType() {
   20.85 +            return Type.BOOLEAN;
   20.86 +        }
   20.87      }
   20.88  
   20.89      /**
   20.90 @@ -263,29 +307,63 @@
   20.91       * @return the new literal node
   20.92       */
   20.93      public static LiteralNode<Boolean> newInstance(final Source source, final long token, final int finish, final boolean value) {
   20.94 -        return new LiteralNode<Boolean>(source, token, finish, value) {
   20.95 -            @Override
   20.96 -            protected Node copy(final CopyState cs) {
   20.97 -                return LiteralNode.newInstance(getSource(), getToken(), getFinish(), getValue());
   20.98 +        return new BooleanLiteralNode(source, token,  finish, value);
   20.99 +    }
  20.100 +
  20.101 +    /**
  20.102 +     * Create a new boolean literal based on a parent node (source, token, finish)
  20.103 +     *
  20.104 +     * @param parent parent node
  20.105 +     * @param value  true or false
  20.106 +     *
  20.107 +     * @return the new literal node
  20.108 +     */
  20.109 +    public static LiteralNode<?> newInstance(final Node parent, final boolean value) {
  20.110 +        return new BooleanLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
  20.111 +    }
  20.112 +
  20.113 +    private static class NumberLiteralNode extends LiteralNode<Number> {
  20.114 +
  20.115 +        private final Type type = numberGetType(value);
  20.116 +
  20.117 +        private NumberLiteralNode(final Source source, final long token, final int finish, final Number value) {
  20.118 +            super(source, Token.recast(token, TokenType.DECIMAL), finish, value);
  20.119 +        }
  20.120 +
  20.121 +        private NumberLiteralNode(final NumberLiteralNode literalNode) {
  20.122 +            super(literalNode);
  20.123 +        }
  20.124 +
  20.125 +        private static Type numberGetType(final Number number) {
  20.126 +            if (number instanceof Integer) {
  20.127 +                return Type.INT;
  20.128 +            } else if (number instanceof Long) {
  20.129 +                return Type.LONG;
  20.130 +            } else if (number instanceof Double) {
  20.131 +                return Type.NUMBER;
  20.132 +            } else {
  20.133 +                assert false;
  20.134              }
  20.135  
  20.136 -            @Override
  20.137 -            public boolean isTrue() {
  20.138 -                return value;
  20.139 -            }
  20.140 +            return null;
  20.141 +        }
  20.142  
  20.143 -            @Override
  20.144 -            public Type getType() {
  20.145 -                return Type.BOOLEAN;
  20.146 -            }
  20.147 +        @Override
  20.148 +        protected Node copy(final CopyState cs) {
  20.149 +            return new NumberLiteralNode(this);
  20.150 +        }
  20.151  
  20.152 -            @Override
  20.153 -            public Type getWidestOperationType() {
  20.154 -                return Type.BOOLEAN;
  20.155 -            }
  20.156 -        };
  20.157 +        @Override
  20.158 +        public Type getType() {
  20.159 +            return type;
  20.160 +        }
  20.161 +
  20.162 +        @Override
  20.163 +        public Type getWidestOperationType() {
  20.164 +            return getType();
  20.165 +        }
  20.166 +
  20.167      }
  20.168 -
  20.169      /**
  20.170       * Create a new number literal
  20.171       *
  20.172 @@ -297,40 +375,34 @@
  20.173       * @return the new literal node
  20.174       */
  20.175      public static LiteralNode<Number> newInstance(final Source source, final long token, final int finish, final Number value) {
  20.176 -        return new LiteralNode<Number>(source, token, finish, value) {
  20.177 +        return new NumberLiteralNode(source, token, finish, value);
  20.178 +    }
  20.179  
  20.180 -            private Type numberGetType(final Number number) {
  20.181 -                if (number instanceof Integer) {
  20.182 -                    return Type.INT;
  20.183 -                } else if (number instanceof Long) {
  20.184 -                    return Type.LONG;
  20.185 -                } else if (number instanceof Double) {
  20.186 -                    return Type.NUMBER;
  20.187 -                } else {
  20.188 -                    assert false;
  20.189 -                }
  20.190 +    /**
  20.191 +     * Create a new number literal based on a parent node (source, token, finish)
  20.192 +     *
  20.193 +     * @param parent parent node
  20.194 +     * @param value  literal value
  20.195 +     *
  20.196 +     * @return the new literal node
  20.197 +     */
  20.198 +    public static LiteralNode<?> newInstance(final Node parent, final Number value) {
  20.199 +        return new NumberLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
  20.200 +    }
  20.201  
  20.202 -                return null;
  20.203 -            }
  20.204 +    private static class UndefinedLiteralNode extends LiteralNode<Undefined> {
  20.205 +        private UndefinedLiteralNode(final Source source, final long token, final int finish) {
  20.206 +            super(source, Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
  20.207 +        }
  20.208  
  20.209 -            private final Type type = numberGetType(value);
  20.210 +        private UndefinedLiteralNode(final UndefinedLiteralNode literalNode) {
  20.211 +            super(literalNode);
  20.212 +        }
  20.213  
  20.214 -            @Override
  20.215 -            protected Node copy(final CopyState cs) {
  20.216 -                return LiteralNode.newInstance(getSource(), getToken(), getFinish(), getValue());
  20.217 -            }
  20.218 -
  20.219 -            @Override
  20.220 -            public Type getType() {
  20.221 -                return type;
  20.222 -            }
  20.223 -
  20.224 -            @Override
  20.225 -            public Type getWidestOperationType() {
  20.226 -                return getType();
  20.227 -            }
  20.228 -
  20.229 -        };
  20.230 +        @Override
  20.231 +        protected Node copy(final CopyState cs) {
  20.232 +            return new UndefinedLiteralNode(this);
  20.233 +        }
  20.234      }
  20.235  
  20.236      /**
  20.237 @@ -344,12 +416,41 @@
  20.238       * @return the new literal node
  20.239       */
  20.240      public static LiteralNode<Undefined> newInstance(final Source source, final long token, final int finish, final Undefined value) {
  20.241 -        return new LiteralNode<Undefined>(source, token, finish, value) {
  20.242 -            @Override
  20.243 -            protected Node copy(final CopyState cs) {
  20.244 -                return LiteralNode.newInstance(getSource(), getToken(), getFinish(), getValue());
  20.245 -            }
  20.246 -        };
  20.247 +        return new UndefinedLiteralNode(source, token, finish);
  20.248 +    }
  20.249 +
  20.250 +    /**
  20.251 +     * Create a new null literal based on a parent node (source, token, finish)
  20.252 +     *
  20.253 +     * @param parent parent node
  20.254 +     * @param value  undefined value
  20.255 +     *
  20.256 +     * @return the new literal node
  20.257 +     */
  20.258 +    public static LiteralNode<?> newInstance(final Node parent, final Undefined value) {
  20.259 +        return new UndefinedLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish());
  20.260 +    }
  20.261 +
  20.262 +    private static class StringLiteralNode extends LiteralNode<String> {
  20.263 +        private StringLiteralNode(final Source source, final long token, final int finish, final String value) {
  20.264 +            super(source, Token.recast(token, TokenType.STRING), finish, value);
  20.265 +        }
  20.266 +
  20.267 +        private StringLiteralNode(final StringLiteralNode literalNode) {
  20.268 +            super(literalNode);
  20.269 +        }
  20.270 +
  20.271 +        @Override
  20.272 +        protected Node copy(final CopyState cs) {
  20.273 +            return new StringLiteralNode(this);
  20.274 +        }
  20.275 +
  20.276 +        @Override
  20.277 +        public void toString(final StringBuilder sb) {
  20.278 +            sb.append('\"');
  20.279 +            sb.append(value);
  20.280 +            sb.append('\"');
  20.281 +        }
  20.282      }
  20.283  
  20.284      /**
  20.285 @@ -363,19 +464,39 @@
  20.286       * @return the new literal node
  20.287       */
  20.288      public static LiteralNode<String> newInstance(final Source source, final long token, final int finish, final String value) {
  20.289 -        return new LiteralNode<String>(source, token, finish, value) {
  20.290 -            @Override
  20.291 -            protected Node copy(final CopyState cs) {
  20.292 -                return LiteralNode.newInstance(getSource(), getToken(), getFinish(), getValue());
  20.293 -            }
  20.294 +        return new StringLiteralNode(source, token, finish, value);
  20.295 +    }
  20.296  
  20.297 -            @Override
  20.298 -            public void toString(final StringBuilder sb) {
  20.299 -                sb.append('\"');
  20.300 -                sb.append(value);
  20.301 -                sb.append('\"');
  20.302 -            }
  20.303 -        };
  20.304 +    /**
  20.305 +     * Create a new String literal based on a parent node (source, token, finish)
  20.306 +     *
  20.307 +     * @param parent parent node
  20.308 +     * @param value  string value
  20.309 +     *
  20.310 +     * @return the new literal node
  20.311 +     */
  20.312 +    public static LiteralNode<?> newInstance(final Node parent, final String value) {
  20.313 +        return new StringLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
  20.314 +    }
  20.315 +
  20.316 +    private static class LexerTokenLiteralNode extends LiteralNode<LexerToken> {
  20.317 +        private LexerTokenLiteralNode(final Source source, final long token, final int finish, final LexerToken value) {
  20.318 +            super(source, Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here?
  20.319 +        }
  20.320 +
  20.321 +        private LexerTokenLiteralNode(final LexerTokenLiteralNode literalNode) {
  20.322 +            super(literalNode);
  20.323 +        }
  20.324 +
  20.325 +        @Override
  20.326 +        protected Node copy(final CopyState cs) {
  20.327 +            return new LexerTokenLiteralNode(this);
  20.328 +        }
  20.329 +
  20.330 +        @Override
  20.331 +        public void toString(final StringBuilder sb) {
  20.332 +            sb.append(value.toString());
  20.333 +        }
  20.334      }
  20.335  
  20.336      /**
  20.337 @@ -389,22 +510,65 @@
  20.338       * @return the new literal node
  20.339       */
  20.340      public static LiteralNode<LexerToken> newInstance(final Source source, final long token, final int finish, final LexerToken value) {
  20.341 -        return new LiteralNode<LexerToken>(source, token, finish, value) {
  20.342 -            @Override
  20.343 -            protected Node copy(final CopyState cs) {
  20.344 -                return LiteralNode.newInstance(getSource(), getToken(), getFinish(), getValue());
  20.345 -            }
  20.346 -
  20.347 -
  20.348 -            @Override
  20.349 -            public void toString(final StringBuilder sb) {
  20.350 -                sb.append(value.toString());
  20.351 -            }
  20.352 -        };
  20.353 +        return new LexerTokenLiteralNode(source, token, finish, value);
  20.354      }
  20.355  
  20.356      /**
  20.357 -     * Create a new array for an arbitrary node
  20.358 +     * Create a new lexer token literal based on a parent node (source, token, finish)
  20.359 +     *
  20.360 +     * @param parent parent node
  20.361 +     * @param value  lexer token
  20.362 +     *
  20.363 +     * @return the new literal node
  20.364 +     */
  20.365 +    public static LiteralNode<?> newInstance(final Node parent, final LexerToken value) {
  20.366 +        return new LexerTokenLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
  20.367 +    }
  20.368 +
  20.369 +    private static class NodeLiteralNode extends LiteralNode<Node> {
  20.370 +
  20.371 +        private NodeLiteralNode(final Source source, final long token, final int finish) {
  20.372 +            this(source, token, finish, null);
  20.373 +        }
  20.374 +
  20.375 +        private NodeLiteralNode(final Source source, final long token, final int finish, final Node value) {
  20.376 +            super(source, Token.recast(token, TokenType.OBJECT), finish, value);
  20.377 +        }
  20.378 +
  20.379 +        private NodeLiteralNode(final LiteralNode<Node> literalNode) {
  20.380 +            super(literalNode);
  20.381 +        }
  20.382 +
  20.383 +        @Override
  20.384 +        protected Node copy(final CopyState cs) {
  20.385 +            return new NodeLiteralNode(this);
  20.386 +        }
  20.387 +
  20.388 +        @Override
  20.389 +        public Node accept(final NodeVisitor visitor) {
  20.390 +            if (visitor.enter(this) != null) {
  20.391 +                if (value != null) {
  20.392 +                    value = value.accept(visitor);
  20.393 +                }
  20.394 +                return visitor.leave(this);
  20.395 +            }
  20.396 +
  20.397 +            return this;
  20.398 +        }
  20.399 +
  20.400 +        @Override
  20.401 +        public Type getType() {
  20.402 +            return value == null ? Type.OBJECT : super.getType();
  20.403 +        }
  20.404 +
  20.405 +        @Override
  20.406 +        public Type getWidestOperationType() {
  20.407 +            return value == null ? Type.OBJECT : value.getWidestOperationType();
  20.408 +        }
  20.409 +
  20.410 +    }
  20.411 +    /**
  20.412 +     * Create a new node literal for an arbitrary node
  20.413       *
  20.414       * @param source  the source
  20.415       * @param token   token
  20.416 @@ -414,33 +578,19 @@
  20.417       * @return the new literal node
  20.418       */
  20.419      public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish, final Node value) {
  20.420 -        return new LiteralNode<Node>(source, token, finish, value) {
  20.421 -            @Override
  20.422 -            protected Node copy(final CopyState cs) {
  20.423 -                return LiteralNode.newInstance(getSource(), getToken(), getFinish(), getValue());
  20.424 -            }
  20.425 +        return new NodeLiteralNode(source, token, finish, value);
  20.426 +    }
  20.427  
  20.428 -            @Override
  20.429 -            public Node accept(final NodeVisitor visitor) {
  20.430 -                if (visitor.enter(this) != null) {
  20.431 -                    value = value.accept(visitor);
  20.432 -                    return visitor.leave(this);
  20.433 -                }
  20.434 -
  20.435 -                return this;
  20.436 -            }
  20.437 -
  20.438 -            @Override
  20.439 -            public void toString(final StringBuilder sb) {
  20.440 -                value.toString(sb);
  20.441 -            }
  20.442 -
  20.443 -            @Override
  20.444 -            public Type getWidestOperationType() {
  20.445 -                return value.getWidestOperationType();
  20.446 -            }
  20.447 -
  20.448 -        };
  20.449 +    /**
  20.450 +     * Create a new node literal based on a parent node (source, token, finish)
  20.451 +     *
  20.452 +     * @param parent parent node
  20.453 +     * @param value  node value
  20.454 +     *
  20.455 +     * @return the new literal node
  20.456 +     */
  20.457 +    public static LiteralNode<?> newInstance(final Node parent, final Node value) {
  20.458 +        return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
  20.459      }
  20.460  
  20.461      /**
  20.462 @@ -521,8 +671,7 @@
  20.463           * @param value   array literal value, a Node array
  20.464           */
  20.465          protected ArrayLiteralNode(final Source source, final long token, final int finish, final Node[] value) {
  20.466 -            super(source, token, finish, value);
  20.467 -
  20.468 +            super(source, Token.recast(token, TokenType.ARRAY), finish, value);
  20.469              this.elementType = Type.UNKNOWN;
  20.470          }
  20.471  
  20.472 @@ -530,13 +679,14 @@
  20.473           * Copy constructor
  20.474           * @param node source array literal node
  20.475           */
  20.476 -        protected ArrayLiteralNode(final LiteralNode<Node[]> node) {
  20.477 +        protected ArrayLiteralNode(final ArrayLiteralNode node) {
  20.478              super(node);
  20.479 +            this.elementType = node.elementType;
  20.480          }
  20.481  
  20.482          @Override
  20.483          protected Node copy(final CopyState cs) {
  20.484 -            return LiteralNode.newInstance(getSource(), getToken(), getFinish(), getValue());
  20.485 +            return new ArrayLiteralNode(this);
  20.486          }
  20.487  
  20.488          /**
  20.489 @@ -769,6 +919,19 @@
  20.490          return new ArrayLiteralNode(source, token, finish, value.toArray(new Node[value.size()]));
  20.491      }
  20.492  
  20.493 +
  20.494 +    /**
  20.495 +     * Create a new array literal based on a parent node (source, token, finish)
  20.496 +     *
  20.497 +     * @param parent parent node
  20.498 +     * @param value  literal value list
  20.499 +     *
  20.500 +     * @return the new literal node
  20.501 +     */
  20.502 +    public static LiteralNode<?> newInstance(final Node parent, final List<Node> value) {
  20.503 +        return new ArrayLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value.toArray(new Node[value.size()]));
  20.504 +    }
  20.505 +
  20.506      /**
  20.507       * Create a new array literal of Nodes
  20.508       *
    21.1 --- a/src/jdk/nashorn/internal/ir/Node.java	Tue Jan 29 14:25:39 2013 -0400
    21.2 +++ b/src/jdk/nashorn/internal/ir/Node.java	Wed Jan 30 12:26:45 2013 +0100
    21.3 @@ -26,7 +26,7 @@
    21.4  package jdk.nashorn.internal.ir;
    21.5  
    21.6  import java.util.IdentityHashMap;
    21.7 -import java.util.List;
    21.8 +
    21.9  import jdk.nashorn.internal.codegen.types.Type;
   21.10  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   21.11  import jdk.nashorn.internal.parser.Token;
   21.12 @@ -38,7 +38,7 @@
   21.13   */
   21.14  public abstract class Node extends Location {
   21.15      /** Node symbol. */
   21.16 -    private Symbol nodeSymbol;
   21.17 +    private Symbol symbol;
   21.18  
   21.19      /** Start of source range. */
   21.20      protected int start;
   21.21 @@ -68,7 +68,7 @@
   21.22      public Node(final Source source, final long token, final int finish) {
   21.23          super(source, token);
   21.24  
   21.25 -        start  = Token.descPosition(token);
   21.26 +        this.start  = Token.descPosition(token);
   21.27          this.finish = finish;
   21.28      }
   21.29  
   21.30 @@ -80,7 +80,7 @@
   21.31      protected Node(final Node node) {
   21.32          super(node);
   21.33  
   21.34 -        this.nodeSymbol    = node.nodeSymbol;
   21.35 +        this.symbol        = node.symbol;
   21.36          this.isResolved    = node.isResolved;
   21.37          this.isTerminal    = node.isTerminal;
   21.38          this.hasGoto       = node.hasGoto;
   21.39 @@ -107,8 +107,8 @@
   21.40       * @return the type of the node.
   21.41       */
   21.42      public Type getType() {
   21.43 -        assert hasType();
   21.44 -        return nodeSymbol.getSymbolType();
   21.45 +        assert hasType() : this + " has no type";
   21.46 +        return symbol.getSymbolType();
   21.47      }
   21.48  
   21.49      /**
   21.50 @@ -379,7 +379,7 @@
   21.51       * @return the symbol
   21.52       */
   21.53      public Symbol getSymbol() {
   21.54 -        return nodeSymbol;
   21.55 +        return symbol;
   21.56      }
   21.57  
   21.58      /**
   21.59 @@ -389,7 +389,7 @@
   21.60       * @param symbol the symbol
   21.61       */
   21.62      public void setSymbol(final Symbol symbol) {
   21.63 -        nodeSymbol = symbol;
   21.64 +        this.symbol = symbol;
   21.65      }
   21.66  
   21.67      /**
   21.68 @@ -412,21 +412,4 @@
   21.69          this.isTerminal = isTerminal;
   21.70      }
   21.71  
   21.72 -    /**
   21.73 -     * Return last node in a statement list.
   21.74 -     *
   21.75 -     * @param statements Statement list.
   21.76 -     *
   21.77 -     * @return Last (non-debug) statement or null if empty block.
   21.78 -     */
   21.79 -    public static Node lastStatement(final List<Node> statements) {
   21.80 -        for (int lastIndex = statements.size() - 1; lastIndex >= 0; lastIndex--) {
   21.81 -            final Node node = statements.get(lastIndex);
   21.82 -            if (!node.isDebug()) {
   21.83 -                return node;
   21.84 -            }
   21.85 -        }
   21.86 -
   21.87 -        return null;
   21.88 -    }
   21.89  }
    22.1 --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java	Tue Jan 29 14:25:39 2013 -0400
    22.2 +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java	Wed Jan 30 12:26:45 2013 +0100
    22.3 @@ -257,6 +257,9 @@
    22.4      /** Call site override - e.g. we know that a ScriptRuntime.ADD will return an int */
    22.5      private Type callSiteType;
    22.6  
    22.7 +    /** is final - i.e. may not be removed again, lower in the code pipeline */
    22.8 +    private boolean isFinal;
    22.9 +
   22.10      /**
   22.11       * Constructor
   22.12       *
   22.13 @@ -286,6 +289,51 @@
   22.14          this(source, token, finish, request, Arrays.asList(args));
   22.15      }
   22.16  
   22.17 +    /**
   22.18 +     * Constructor
   22.19 +     *
   22.20 +     * @param parent  parent node from which to inherit source, token, finish
   22.21 +     * @param request the request
   22.22 +     * @param args    arguments to request
   22.23 +     */
   22.24 +    public RuntimeNode(final Node parent, final Request request, final Node... args) {
   22.25 +        this(parent, request, Arrays.asList(args));
   22.26 +    }
   22.27 +
   22.28 +    /**
   22.29 +     * Constructor
   22.30 +     *
   22.31 +     * @param parent  parent node from which to inherit source, token, finish
   22.32 +     * @param request the request
   22.33 +     * @param args    arguments to request
   22.34 +     */
   22.35 +    public RuntimeNode(final Node parent, final Request request, final List<Node> args) {
   22.36 +        super(parent);
   22.37 +
   22.38 +        this.request = request;
   22.39 +        this.args    = args;
   22.40 +    }
   22.41 +
   22.42 +    /**
   22.43 +     * Constructor
   22.44 +     *
   22.45 +     * @param parent  parent node from which to inherit source, token, finish and arguments
   22.46 +     * @param request the request
   22.47 +     */
   22.48 +    public RuntimeNode(final UnaryNode parent, final Request request) {
   22.49 +        this(parent, request, parent.rhs());
   22.50 +    }
   22.51 +
   22.52 +    /**
   22.53 +     * Constructor
   22.54 +     *
   22.55 +     * @param parent  parent node from which to inherit source, token, finish and arguments
   22.56 +     * @param request the request
   22.57 +     */
   22.58 +    public RuntimeNode(final BinaryNode parent, final Request request) {
   22.59 +        this(parent, request, parent.lhs(), parent.rhs());
   22.60 +    }
   22.61 +
   22.62      private RuntimeNode(final RuntimeNode runtimeNode, final CopyState cs) {
   22.63          super(runtimeNode);
   22.64  
   22.65 @@ -300,6 +348,21 @@
   22.66          this.callSiteType = runtimeNode.callSiteType;
   22.67      }
   22.68  
   22.69 +    /**
   22.70 +     * Is this node final - i.e. it can never be replaced with other nodes again
   22.71 +     * @return true if final
   22.72 +     */
   22.73 +    public boolean isFinal() {
   22.74 +        return isFinal;
   22.75 +    }
   22.76 +
   22.77 +    /**
   22.78 +     * Flag this node as final - i.e it may never be replaced with other nodes again
   22.79 +     */
   22.80 +    public void setIsFinal() {
   22.81 +        this.isFinal = true;
   22.82 +    }
   22.83 +
   22.84      @Override
   22.85      protected Node copy(final CopyState cs) {
   22.86          return new RuntimeNode(this, cs);
    23.1 --- a/src/jdk/nashorn/internal/ir/Symbol.java	Tue Jan 29 14:25:39 2013 -0400
    23.2 +++ b/src/jdk/nashorn/internal/ir/Symbol.java	Wed Jan 30 12:26:45 2013 +0100
    23.3 @@ -26,6 +26,10 @@
    23.4  package jdk.nashorn.internal.ir;
    23.5  
    23.6  import java.io.PrintWriter;
    23.7 +import java.util.HashSet;
    23.8 +import java.util.Set;
    23.9 +import java.util.StringTokenizer;
   23.10 +
   23.11  import jdk.nashorn.internal.codegen.types.Type;
   23.12  import jdk.nashorn.internal.runtime.Context;
   23.13  import jdk.nashorn.internal.runtime.options.Options;
   23.14 @@ -46,7 +50,7 @@
   23.15      /** Is this a constant */
   23.16      public static final int IS_CONSTANT = 0b0000_0101;
   23.17  
   23.18 -    static final int KINDMASK    = 0b0000_1111;
   23.19 +    static final int KINDMASK = 0b0000_1111;
   23.20  
   23.21      /** Is this scope */
   23.22      public static final int IS_SCOPE         = 0b0000_0001_0000;
   23.23 @@ -85,8 +89,33 @@
   23.24      /** Number of times this symbol is used in code */
   23.25      private int useCount;
   23.26  
   23.27 -    /** Debugging option - dump info and stack trace when a symbol with a given name is manipulated */
   23.28 -    private static final String TRACE_SYMBOL = Options.getStringProperty("nashorn.compiler.symbol.trace", null);
   23.29 +    /** Debugging option - dump info and stack trace when symbols with given names are manipulated */
   23.30 +    private static final Set<String> TRACE_SYMBOLS;
   23.31 +    private static final Set<String> TRACE_SYMBOLS_STACKTRACE;
   23.32 +
   23.33 +    static {
   23.34 +        final String stacktrace = Options.getStringProperty("nashorn.compiler.symbol.stacktrace", null);
   23.35 +        final String trace;
   23.36 +        if (stacktrace != null) {
   23.37 +            trace = stacktrace; //stacktrace always implies trace as well
   23.38 +            TRACE_SYMBOLS_STACKTRACE = new HashSet<>();
   23.39 +            for (StringTokenizer st = new StringTokenizer(stacktrace, ","); st.hasMoreTokens(); ) {
   23.40 +                TRACE_SYMBOLS_STACKTRACE.add(st.nextToken());
   23.41 +            }
   23.42 +        } else {
   23.43 +            trace = Options.getStringProperty("nashorn.compiler.symbol.trace", null);
   23.44 +            TRACE_SYMBOLS_STACKTRACE = null;
   23.45 +        }
   23.46 +
   23.47 +        if (trace != null) {
   23.48 +            TRACE_SYMBOLS = new HashSet<>();
   23.49 +            for (StringTokenizer st = new StringTokenizer(trace, ","); st.hasMoreTokens(); ) {
   23.50 +                TRACE_SYMBOLS.add(st.nextToken());
   23.51 +            }
   23.52 +        } else {
   23.53 +            TRACE_SYMBOLS = null;
   23.54 +        }
   23.55 +    }
   23.56  
   23.57      /**
   23.58       * Constructor
   23.59 @@ -106,6 +135,7 @@
   23.60          this.type       = type;
   23.61          this.slot       = slot;
   23.62          this.fieldIndex = -1;
   23.63 +        trace("CREATE SYMBOL");
   23.64      }
   23.65  
   23.66      /**
   23.67 @@ -135,7 +165,7 @@
   23.68          final StringBuilder sb = new StringBuilder();
   23.69          sb.append(string.substring(0, Math.min(string.length(), max)));
   23.70  
   23.71 -        while (sb.length () < max) {
   23.72 +        while (sb.length() < max) {
   23.73              sb.append(' ');
   23.74          }
   23.75          return sb.toString();
   23.76 @@ -263,6 +293,23 @@
   23.77          return name.hashCode() ^ block.hashCode();
   23.78      }
   23.79  
   23.80 +    private static String type(final String desc) {
   23.81 +        switch (desc.charAt(desc.length() - 1)) {
   23.82 +        case ';':
   23.83 +            return desc;//"obj";
   23.84 +        case 'D':
   23.85 +            return "double";
   23.86 +        case 'I':
   23.87 +            return "int";
   23.88 +        case 'J':
   23.89 +            return "long";
   23.90 +        case 'Z':
   23.91 +            return "boolean";
   23.92 +        default:
   23.93 +            return "UNKNOWN";
   23.94 +        }
   23.95 +    }
   23.96 +
   23.97      @Override
   23.98      public String toString() {
   23.99          final StringBuilder sb   = new StringBuilder();
  23.100 @@ -270,8 +317,8 @@
  23.101  
  23.102          sb.append(name).
  23.103              append(' ').
  23.104 -            append("(type=").
  23.105 -            append(desc.charAt(desc.length() - 1) == ';' ? 'O' : desc).
  23.106 +            append('(').
  23.107 +            append(type(desc)).
  23.108              append(')');
  23.109  
  23.110          if (hasSlot()) {
  23.111 @@ -602,10 +649,13 @@
  23.112          return block instanceof FunctionNode && ((FunctionNode) block).isScript();
  23.113      }
  23.114  
  23.115 +
  23.116      private void trace(final String desc) {
  23.117 -        if (TRACE_SYMBOL != null && TRACE_SYMBOL.equals(name)) {
  23.118 +        if (TRACE_SYMBOLS != null && (TRACE_SYMBOLS.isEmpty() || TRACE_SYMBOLS.contains(name))) {
  23.119              Context.err("SYMBOL: '" + name + "' " + desc);
  23.120 -            new Throwable().printStackTrace(Context.getCurrentErr());
  23.121 +            if (TRACE_SYMBOLS_STACKTRACE != null && (TRACE_SYMBOLS_STACKTRACE.isEmpty() || TRACE_SYMBOLS_STACKTRACE.contains(name))) {
  23.122 +                new Throwable().printStackTrace(Context.getContext().getErr());
  23.123 +            }
  23.124          }
  23.125      }
  23.126  }
    24.1 --- a/src/jdk/nashorn/internal/ir/TryNode.java	Tue Jan 29 14:25:39 2013 -0400
    24.2 +++ b/src/jdk/nashorn/internal/ir/TryNode.java	Wed Jan 30 12:26:45 2013 +0100
    24.3 @@ -56,6 +56,9 @@
    24.4      /** Exception symbol. */
    24.5      private Symbol exception;
    24.6  
    24.7 +    /** Catchall exception for finally expansion, where applicable */
    24.8 +    private Symbol finallyCatchAll;
    24.9 +
   24.10      /**
   24.11       * Constructor
   24.12       *
   24.13 @@ -184,6 +187,23 @@
   24.14      }
   24.15  
   24.16      /**
   24.17 +     * Get the catch all symbol for this try block
   24.18 +     * @return catch all symbol
   24.19 +     */
   24.20 +    public Symbol getFinallyCatchAll() {
   24.21 +        return this.finallyCatchAll;
   24.22 +    }
   24.23 +
   24.24 +    /**
   24.25 +     * If a finally block exists, the synthetic catchall needs another symbol to
   24.26 +     * store its throwable
   24.27 +     * @param finallyCatchAll a symbol for the finally catch all exception
   24.28 +     */
   24.29 +    public void setFinallyCatchAll(final Symbol finallyCatchAll) {
   24.30 +        this.finallyCatchAll = finallyCatchAll;
   24.31 +    }
   24.32 +
   24.33 +    /**
   24.34       * Get the exit label for this try block
   24.35       * @return exit label
   24.36       */
    25.1 --- a/src/jdk/nashorn/internal/ir/VarNode.java	Tue Jan 29 14:25:39 2013 -0400
    25.2 +++ b/src/jdk/nashorn/internal/ir/VarNode.java	Wed Jan 30 12:26:45 2013 +0100
    25.3 @@ -41,9 +41,6 @@
    25.4      /** Is this a function var node */
    25.5      private boolean isFunctionVarNode;
    25.6  
    25.7 -    /** Should append VarNode to statement list? */
    25.8 -    private final boolean shouldAppend;
    25.9 -
   25.10      /**
   25.11       * Constructor
   25.12       *
   25.13 @@ -54,25 +51,10 @@
   25.14       * @param init   init node or null if just a declaration
   25.15       */
   25.16      public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) {
   25.17 -        this(source, token, finish, name, init, true);
   25.18 -    }
   25.19 -
   25.20 -    /**
   25.21 -     * Constructor
   25.22 -     *
   25.23 -     * @param source the source
   25.24 -     * @param token  token
   25.25 -     * @param finish finish
   25.26 -     * @param name   name of variable
   25.27 -     * @param init   init node or null if just a declaration
   25.28 -     * @param shouldAppend should this turn into explicit code, like if it were an ExecuteNode
   25.29 -     */
   25.30 -    public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, final boolean shouldAppend) {
   25.31          super(source, token, finish);
   25.32  
   25.33          this.name  = name;
   25.34          this.init  = init;
   25.35 -        this.shouldAppend = shouldAppend;
   25.36          if (init != null) {
   25.37              this.name.setIsInitializedHere();
   25.38          }
   25.39 @@ -83,7 +65,6 @@
   25.40  
   25.41          this.name = (IdentNode)cs.existingOrCopy(varNode.name);
   25.42          this.init = cs.existingOrCopy(varNode.init);
   25.43 -        this.shouldAppend = varNode.shouldAppend;
   25.44      }
   25.45  
   25.46      @Override
   25.47 @@ -116,7 +97,6 @@
   25.48          setInit(source);
   25.49      }
   25.50  
   25.51 -
   25.52      /**
   25.53       * Does this variable declaration have an init value
   25.54       * @return true if an init exists, false otherwise
   25.55 @@ -235,15 +215,4 @@
   25.56          this.isFunctionVarNode = true;
   25.57      }
   25.58  
   25.59 -    /**
   25.60 -     * Is this the var for a for-in node or other construct that means
   25.61 -     * manual or no appends of this varNode to the statement list in
   25.62 -     * Lower? The default is yes as most VarNodes are auto-append to
   25.63 -     * the end of the statement list when lowered
   25.64 -     *
   25.65 -     * @return should compiler append var node to statement list
   25.66 -     */
   25.67 -    public boolean shouldAppend() {
   25.68 -        return shouldAppend;
   25.69 -    }
   25.70  }
    26.1 --- a/src/jdk/nashorn/internal/ir/debug/ASTWriter.java	Tue Jan 29 14:25:39 2013 -0400
    26.2 +++ b/src/jdk/nashorn/internal/ir/debug/ASTWriter.java	Wed Jan 30 12:26:45 2013 +0100
    26.3 @@ -113,8 +113,8 @@
    26.4              status += " Goto ";
    26.5          }
    26.6  
    26.7 -        if (node.getSymbol() != null && node.getSymbol().hasSlot()) {
    26.8 -            status += " Slot " + node.getSymbol();
    26.9 +        if (node.getSymbol() != null) {
   26.10 +            status += node.getSymbol();
   26.11          }
   26.12  
   26.13          status = status.trim();
    27.1 --- a/src/jdk/nashorn/internal/objects/NativeJSON.java	Tue Jan 29 14:25:39 2013 -0400
    27.2 +++ b/src/jdk/nashorn/internal/objects/NativeJSON.java	Wed Jan 30 12:26:45 2013 +0100
    27.3 @@ -265,7 +265,7 @@
    27.4  
    27.5         if (node instanceof LiteralNode) {
    27.6              // check for array literal
    27.7 -            if (node.tokenType() == TokenType.LBRACKET) {
    27.8 +            if (node.tokenType() == TokenType.ARRAY) {
    27.9                  assert node instanceof ArrayLiteralNode;
   27.10                  final Node[] elements = ((ArrayLiteralNode)node).getValue();
   27.11  
    28.1 --- a/src/jdk/nashorn/internal/objects/NativeString.java	Tue Jan 29 14:25:39 2013 -0400
    28.2 +++ b/src/jdk/nashorn/internal/objects/NativeString.java	Wed Jan 30 12:26:45 2013 +0100
    28.3 @@ -789,6 +789,7 @@
    28.4       *
    28.5       * @param self  self reference
    28.6       * @param start start position for slice
    28.7 +     * @param end   end position for slice
    28.8       * @return sliced out substring
    28.9       */
   28.10      @SpecializedFunction
   28.11 @@ -808,6 +809,7 @@
   28.12       *
   28.13       * @param self  self reference
   28.14       * @param start start position for slice
   28.15 +     * @param end   end position for slice
   28.16       * @return sliced out substring
   28.17       */
   28.18      @SpecializedFunction
   28.19 @@ -843,9 +845,8 @@
   28.20      }
   28.21  
   28.22      private static Object splitString(String str, String separator, long limit) {
   28.23 -
   28.24 -        if (separator.equals("")) {
   28.25 -            Object[] array = new Object[str.length()];
   28.26 +        if (separator.isEmpty()) {
   28.27 +            final Object[] array = new Object[str.length()];
   28.28              for (int i = 0; i < array.length; i++) {
   28.29                  array[i] = String.valueOf(str.charAt(i));
   28.30              }
   28.31 @@ -856,18 +857,18 @@
   28.32          final int strLength = str.length();
   28.33          final int sepLength = separator.length();
   28.34          int pos = 0;
   28.35 -        int count = 0;
   28.36 +        int n = 0;
   28.37  
   28.38 -        while (pos < strLength && count < limit) {
   28.39 +        while (pos < strLength && n < limit) {
   28.40              int found = str.indexOf(separator, pos);
   28.41              if (found == -1) {
   28.42                  break;
   28.43              }
   28.44              elements.add(str.substring(pos, found));
   28.45 -            count++;
   28.46 +            n++;
   28.47              pos = found + sepLength;
   28.48          }
   28.49 -        if (pos <= strLength && count < limit) {
   28.50 +        if (pos <= strLength && n < limit) {
   28.51              elements.add(str.substring(pos));
   28.52          }
   28.53  
   28.54 @@ -963,9 +964,8 @@
   28.55  
   28.56          if (validStart < validEnd) {
   28.57              return str.substring(validStart, validEnd);
   28.58 -        } else {
   28.59 -            return str.substring(validEnd, validStart);
   28.60          }
   28.61 +        return str.substring(validEnd, validStart);
   28.62      }
   28.63  
   28.64      /**
    29.1 --- a/src/jdk/nashorn/internal/parser/AbstractParser.java	Tue Jan 29 14:25:39 2013 -0400
    29.2 +++ b/src/jdk/nashorn/internal/parser/AbstractParser.java	Wed Jan 30 12:26:45 2013 +0100
    29.3 @@ -96,11 +96,6 @@
    29.4          this.token        = Token.toDesc(EOL, 0, 1);
    29.5          this.type         = EOL;
    29.6          this.last         = EOL;
    29.7 -        this.start        = 0;
    29.8 -        this.finish       = 0;
    29.9 -        this.line         = 0;
   29.10 -        this.linePosition = 0;
   29.11 -        this.lexer        = null;
   29.12          this.isStrictMode = strict;
   29.13      }
   29.14  
    30.1 --- a/src/jdk/nashorn/internal/parser/Parser.java	Tue Jan 29 14:25:39 2013 -0400
    30.2 +++ b/src/jdk/nashorn/internal/parser/Parser.java	Wed Jan 30 12:26:45 2013 +0100
    30.3 @@ -587,8 +587,6 @@
    30.4          script.setLastToken(token);
    30.5          script.setFinish(source.getLength() - 1);
    30.6  
    30.7 -        block.addStatement(lineNumber());
    30.8 -
    30.9          return script;
   30.10      }
   30.11  
   30.12 @@ -617,6 +615,24 @@
   30.13      }
   30.14  
   30.15      /**
   30.16 +     * Return last node in a statement list.
   30.17 +     *
   30.18 +     * @param statements Statement list.
   30.19 +     *
   30.20 +     * @return Last (non-debug) statement or null if empty block.
   30.21 +     */
   30.22 +    private static Node lastStatement(final List<Node> statements) {
   30.23 +        for (int lastIndex = statements.size() - 1; lastIndex >= 0; lastIndex--) {
   30.24 +            final Node node = statements.get(lastIndex);
   30.25 +            if (!node.isDebug()) {
   30.26 +                return node;
   30.27 +            }
   30.28 +        }
   30.29 +
   30.30 +        return null;
   30.31 +    }
   30.32 +
   30.33 +    /**
   30.34       * SourceElements :
   30.35       *      SourceElement
   30.36       *      SourceElements SourceElement
   30.37 @@ -645,7 +661,7 @@
   30.38                      // check for directive prologues
   30.39                      if (checkDirective) {
   30.40                          // skip any debug statement like line number to get actual first line
   30.41 -                        final Node lastStatement = Node.lastStatement(block.getStatements());
   30.42 +                        final Node lastStatement = lastStatement(block.getStatements());
   30.43  
   30.44                          // get directive prologue, if any
   30.45                          final String directive = getDirective(lastStatement);
   30.46 @@ -677,7 +693,7 @@
   30.47                                      }
   30.48  
   30.49                                      // verify that function name as well as parameter names
   30.50 -                                    // satisfystrict mode restrictions.
   30.51 +                                    // satisfy strict mode restrictions.
   30.52                                      verifyStrictIdent(function.getIdent(), "function name");
   30.53                                      for (final IdentNode param : function.getParameters()) {
   30.54                                          verifyStrictIdent(param, "function parameter");
   30.55 @@ -2628,12 +2644,12 @@
   30.56                  // just expression as function body
   30.57                  final Node expr = expression();
   30.58  
   30.59 -                // create a return statement
   30.60 -                final ReturnNode  returnNode  = new ReturnNode(source, expr.getToken(), finish, expr, null);
   30.61 -                final ExecuteNode executeNode = new ExecuteNode(source, returnNode.getToken(), finish, returnNode);
   30.62 +                // create a return statement - this creates code in itself and does not need to be
   30.63 +                // wrapped into an ExecuteNode
   30.64 +                final ReturnNode  returnNode = new ReturnNode(source, expr.getToken(), finish, expr, null);
   30.65  
   30.66                  // add the return statement
   30.67 -                functionNode.addStatement(executeNode);
   30.68 +                functionNode.addStatement(returnNode);
   30.69                  functionNode.setLastToken(token);
   30.70                  functionNode.setFinish(Token.descPosition(token) + Token.descLength(token));
   30.71  
   30.72 @@ -2648,8 +2664,6 @@
   30.73                  functionNode.setFinish(finish);
   30.74  
   30.75              }
   30.76 -
   30.77 -            block.addStatement(lineNumber());
   30.78          } finally {
   30.79              restoreBlock();
   30.80          }
    31.1 --- a/src/jdk/nashorn/internal/parser/TokenType.java	Tue Jan 29 14:25:39 2013 -0400
    31.2 +++ b/src/jdk/nashorn/internal/parser/TokenType.java	Wed Jan 30 12:26:45 2013 +0100
    31.3 @@ -171,6 +171,8 @@
    31.4      IDENT          (LITERAL,  null),
    31.5      REGEX          (LITERAL,  null),
    31.6      XML            (LITERAL,  null),
    31.7 +    OBJECT         (LITERAL,  null),
    31.8 +    ARRAY          (LITERAL,  null),
    31.9  
   31.10      COMMALEFT      (IR,       null),
   31.11      CONVERT        (IR,       null),
    32.1 --- a/src/jdk/nashorn/internal/runtime/Context.java	Tue Jan 29 14:25:39 2013 -0400
    32.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java	Wed Jan 30 12:26:45 2013 +0100
    32.3 @@ -478,11 +478,11 @@
    32.4          return _timezone;
    32.5      }
    32.6  
    32.7 -    /*
    32.8 +    /**
    32.9       * Get the PropertyMap of the current global scope
   32.10       * @return the property map of the current global scope
   32.11       */
   32.12 -    public PropertyMap getGlobalMap() {
   32.13 +    public static PropertyMap getGlobalMap() {
   32.14          return Context.getGlobalTrusted().getMap();
   32.15      }
   32.16  
    33.1 --- a/src/jdk/nashorn/internal/runtime/DebugLogger.java	Tue Jan 29 14:25:39 2013 -0400
    33.2 +++ b/src/jdk/nashorn/internal/runtime/DebugLogger.java	Wed Jan 30 12:26:45 2013 +0100
    33.3 @@ -41,6 +41,8 @@
    33.4  
    33.5      private int indent;
    33.6  
    33.7 +    private static final int INDENT_SPACE = 4;
    33.8 +
    33.9      /**
   33.10       * Constructor
   33.11       *
   33.12 @@ -93,7 +95,24 @@
   33.13       */
   33.14      public void indent(final int pos) {
   33.15          if (isEnabled) {
   33.16 -           indent += pos * 4;
   33.17 +           indent += pos * INDENT_SPACE;
   33.18 +        }
   33.19 +    }
   33.20 +
   33.21 +    /**
   33.22 +     * Add an indent position
   33.23 +     */
   33.24 +    public void indent() {
   33.25 +        indent += INDENT_SPACE;
   33.26 +    }
   33.27 +
   33.28 +    /**
   33.29 +     * Unindent a position
   33.30 +     */
   33.31 +    public void unindent() {
   33.32 +        indent -= INDENT_SPACE;
   33.33 +        if (indent < 0) {
   33.34 +            indent = 0;
   33.35          }
   33.36      }
   33.37  
    34.1 --- a/src/jdk/nashorn/internal/runtime/OptionsObject.java	Tue Jan 29 14:25:39 2013 -0400
    34.2 +++ b/src/jdk/nashorn/internal/runtime/OptionsObject.java	Wed Jan 30 12:26:45 2013 +0100
    34.3 @@ -106,6 +106,11 @@
    34.4      /** time zone for this context */
    34.5      public final TimeZone _timezone;
    34.6  
    34.7 +    /**
    34.8 +     * Constructor
    34.9 +     *
   34.10 +     * @param context a context
   34.11 +     */
   34.12      public OptionsObject(final Context context) {
   34.13          this._anon_functions = context._anon_functions;
   34.14          this._callsite_flags = context._callsite_flags;
    35.1 --- a/src/jdk/nashorn/internal/runtime/PropertyMap.java	Tue Jan 29 14:25:39 2013 -0400
    35.2 +++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java	Wed Jan 30 12:26:45 2013 +0100
    35.3 @@ -635,7 +635,13 @@
    35.4  
    35.5              sb.append(ScriptRuntime.safeToString(property.getKey()));
    35.6              final Class<?> ctype = property.getCurrentType();
    35.7 -            sb.append(" <" + property.getClass().getSimpleName() + ":" + (ctype == null ? "undefined" : ctype.getSimpleName()) + ">");
    35.8 +            sb.append(" <").
    35.9 +                append(property.getClass().getSimpleName()).
   35.10 +                append(':').
   35.11 +                append(ctype == null ?
   35.12 +                    "undefined" :
   35.13 +                    ctype.getSimpleName()).
   35.14 +                append('>');
   35.15          }
   35.16  
   35.17          sb.append(']');
    36.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Tue Jan 29 14:25:39 2013 -0400
    36.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Jan 30 12:26:45 2013 +0100
    36.3 @@ -1044,6 +1044,10 @@
    36.4          set(key, value, getContext()._strict);
    36.5      }
    36.6  
    36.7 +    /**
    36.8 +     * Return true if the script object context is strict
    36.9 +     * @return true if strict context
   36.10 +     */
   36.11      public final boolean isStrictContext() {
   36.12          return getContext()._strict;
   36.13      }
   36.14 @@ -1419,7 +1423,10 @@
   36.15          return (flags & IS_SCOPE) != 0;
   36.16      }
   36.17  
   36.18 -    // java.util.Map-like methods to help ScriptObjectMirror implementation
   36.19 +    /**
   36.20 +     * Clears the properties from a ScriptObject
   36.21 +     * (java.util.Map-like method to help ScriptObjectMirror implementation)
   36.22 +     */
   36.23      public void clear() {
   36.24          final boolean strict = getContext()._strict;
   36.25          final Iterator<String> iter = propertyIterator();
   36.26 @@ -1428,10 +1435,24 @@
   36.27          }
   36.28      }
   36.29  
   36.30 +    /**
   36.31 +     * Checks if a property with a given key is present in a ScriptObject
   36.32 +     * (java.util.Map-like method to help ScriptObjectMirror implementation)
   36.33 +     *
   36.34 +     * @param key the key to check for
   36.35 +     * @return true if a property with the given key exists, false otherwise
   36.36 +     */
   36.37      public boolean containsKey(final Object key) {
   36.38          return has(key);
   36.39      }
   36.40  
   36.41 +    /**
   36.42 +     * Checks if a property with a given value is present in a ScriptObject
   36.43 +     * (java.util.Map-like method to help ScriptObjectMirror implementation)
   36.44 +     *
   36.45 +     * @param value value to check for
   36.46 +     * @return true if a property with the given value exists, false otherwise
   36.47 +     */
   36.48      public boolean containsValue(final Object value) {
   36.49          final Iterator<Object> iter = valueIterator();
   36.50          while (iter.hasNext()) {
   36.51 @@ -1442,6 +1463,13 @@
   36.52          return false;
   36.53      }
   36.54  
   36.55 +    /**
   36.56 +     * Returns the set of <property, value> entries that make up this
   36.57 +     * ScriptObject's properties
   36.58 +     * (java.util.Map-like method to help ScriptObjectMirror implementation)
   36.59 +     *
   36.60 +     * @return an entry set of all the properties in this object
   36.61 +     */
   36.62      public Set<Map.Entry<Object, Object>> entrySet() {
   36.63          final Iterator<String> iter = propertyIterator();
   36.64          final Set<Map.Entry<Object, Object>> entries = new HashSet<>();
   36.65 @@ -1452,10 +1480,23 @@
   36.66          return Collections.unmodifiableSet(entries);
   36.67      }
   36.68  
   36.69 +    /**
   36.70 +     * Check whether a ScriptObject contains no properties
   36.71 +     * (java.util.Map-like method to help ScriptObjectMirror implementation)
   36.72 +     *
   36.73 +     * @return true if object has no properties
   36.74 +     */
   36.75      public boolean isEmpty() {
   36.76          return !propertyIterator().hasNext();
   36.77      }
   36.78  
   36.79 +    /**
   36.80 +     * Return the set of keys (property names) for all properties
   36.81 +     * in this ScriptObject
   36.82 +     * (java.util.Map-like method to help ScriptObjectMirror implementation)
   36.83 +     *
   36.84 +     * @return keySet of this ScriptObject
   36.85 +     */
   36.86      public Set<Object> keySet() {
   36.87          final Iterator<String> iter = propertyIterator();
   36.88          final Set<Object> keySet = new HashSet<>();
   36.89 @@ -1465,12 +1506,27 @@
   36.90          return Collections.unmodifiableSet(keySet);
   36.91      }
   36.92  
   36.93 +    /**
   36.94 +     * Put a property in the ScriptObject
   36.95 +     * (java.util.Map-like method to help ScriptObjectMirror implementation)
   36.96 +     *
   36.97 +     * @param key property key
   36.98 +     * @param value property value
   36.99 +     * @return oldValue if property with same key existed already
  36.100 +     */
  36.101      public Object put(final Object key, final Object value) {
  36.102          final Object oldValue = get(key);
  36.103          set(key, value, getContext()._strict);
  36.104          return oldValue;
  36.105      }
  36.106  
  36.107 +    /**
  36.108 +     * Put several properties in the ScriptObject given a mapping
  36.109 +     * of their keys to their values
  36.110 +     * (java.util.Map-like method to help ScriptObjectMirror implementation)
  36.111 +     *
  36.112 +     * @param otherMap a <key,value> map of properties to add
  36.113 +     */
  36.114      public void putAll(final Map<?, ?> otherMap) {
  36.115          final boolean strict = getContext()._strict;
  36.116          for (final Map.Entry<?, ?> entry : otherMap.entrySet()) {
  36.117 @@ -1478,12 +1534,26 @@
  36.118          }
  36.119      }
  36.120  
  36.121 +    /**
  36.122 +     * Remove a property from the ScriptObject.
  36.123 +     * (java.util.Map-like method to help ScriptObjectMirror implementation)
  36.124 +     *
  36.125 +     * @param key the key of the property
  36.126 +     * @return the oldValue of the removed property
  36.127 +     */
  36.128      public Object remove(final Object key) {
  36.129          final Object oldValue = get(key);
  36.130          delete(key, getContext()._strict);
  36.131          return oldValue;
  36.132      }
  36.133  
  36.134 +    /**
  36.135 +     * Return the size of the ScriptObject - i.e. the number of properties
  36.136 +     * it contains
  36.137 +     * (java.util.Map-like method to help ScriptObjectMirror implementation)
  36.138 +     *
  36.139 +     * @return number of properties in ScriptObject
  36.140 +     */
  36.141      public int size() {
  36.142          int n = 0;
  36.143          for (final Iterator<String> iter = propertyIterator(); iter.hasNext(); iter.next()) {
  36.144 @@ -1492,6 +1562,12 @@
  36.145          return n;
  36.146      }
  36.147  
  36.148 +    /**
  36.149 +     * Return the values of the properties in the ScriptObject
  36.150 +     * (java.util.Map-like method to help ScriptObjectMirror implementation)
  36.151 +     *
  36.152 +     * @return collection of values for the properties in this ScriptObject
  36.153 +     */
  36.154      public Collection<Object> values() {
  36.155          final List<Object>     values = new ArrayList<>(size());
  36.156          final Iterator<Object> iter   = valueIterator();
    37.1 --- a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java	Tue Jan 29 14:25:39 2013 -0400
    37.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java	Wed Jan 30 12:26:45 2013 +0100
    37.3 @@ -41,13 +41,13 @@
    37.4   */
    37.5  public class ScriptingFunctions {
    37.6  
    37.7 -    /** Handle to implementation of {@link ScriptingFunctions#read} - Nashorn extension */
    37.8 +    /** Handle to implementation of {@link ScriptingFunctions#readLine} - Nashorn extension */
    37.9      public static final MethodHandle READLINE = findOwnMH("readLine", Object.class, Object.class);
   37.10  
   37.11      /** Handle to implementation of {@link ScriptingFunctions#readFully} - Nashorn extension */
   37.12      public static final MethodHandle READFULLY = findOwnMH("readFully",     Object.class, Object.class, Object.class);
   37.13  
   37.14 -    /** Handle to implementation of {@link ScriptingFunctions#read} - Nashorn extension */
   37.15 +    /** Handle to implementation of {@link ScriptingFunctions#quit} - Nashorn extension */
   37.16      public static final MethodHandle QUIT = findOwnMH("quit",     Object.class, Object.class, Object.class);
   37.17  
   37.18      private ScriptingFunctions() {
    38.1 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java	Tue Jan 29 14:25:39 2013 -0400
    38.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java	Wed Jan 30 12:26:45 2013 +0100
    38.3 @@ -25,7 +25,6 @@
    38.4  
    38.5  package jdk.nashorn.internal.runtime.arrays;
    38.6  
    38.7 -import jdk.nashorn.internal.runtime.Context;
    38.8  import jdk.nashorn.internal.runtime.ScriptObject;
    38.9  
   38.10  /**
    39.1 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java	Tue Jan 29 14:25:39 2013 -0400
    39.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java	Wed Jan 30 12:26:45 2013 +0100
    39.3 @@ -26,7 +26,6 @@
    39.4  package jdk.nashorn.internal.runtime.arrays;
    39.5  
    39.6  import java.util.Iterator;
    39.7 -import jdk.nashorn.internal.runtime.Context;
    39.8  import jdk.nashorn.internal.runtime.JSType;
    39.9  import jdk.nashorn.internal.runtime.ScriptObject;
   39.10  
    40.1 --- a/src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java	Tue Jan 29 14:25:39 2013 -0400
    40.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java	Wed Jan 30 12:26:45 2013 +0100
    40.3 @@ -27,7 +27,6 @@
    40.4  
    40.5  import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
    40.6  
    40.7 -import jdk.nashorn.internal.runtime.Context;
    40.8  import jdk.nashorn.internal.runtime.GlobalObject;
    40.9  import jdk.nashorn.internal.runtime.PropertyDescriptor;
   40.10  
    41.1 --- a/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java	Tue Jan 29 14:25:39 2013 -0400
    41.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java	Wed Jan 30 12:26:45 2013 +0100
    41.3 @@ -27,7 +27,6 @@
    41.4  
    41.5  import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
    41.6  
    41.7 -import jdk.nashorn.internal.runtime.Context;
    41.8  import jdk.nashorn.internal.runtime.GlobalObject;
    41.9  import jdk.nashorn.internal.runtime.PropertyDescriptor;
   41.10  
    42.1 --- a/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Tue Jan 29 14:25:39 2013 -0400
    42.2 +++ b/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Wed Jan 30 12:26:45 2013 +0100
    42.3 @@ -446,7 +446,7 @@
    42.4           *
    42.5           * @throws Throwable if invocation fails or throws exception/error
    42.6           */
    42.7 -        @SuppressWarnings("unused")
    42.8 +        @SuppressWarnings({"unused", "resource"})
    42.9          public Object traceObject(final MethodHandle mh, final Object... args) throws Throwable {
   42.10              final PrintWriter out = Context.getCurrentErr();
   42.11              tracePrint(out, "ENTER ", args, null);
   42.12 @@ -464,7 +464,7 @@
   42.13           *
   42.14           * @throws Throwable if invocation fails or throws exception/error
   42.15           */
   42.16 -        @SuppressWarnings("unused")
   42.17 +        @SuppressWarnings({"unused", "resource"})
   42.18          public void traceVoid(final MethodHandle mh, final Object... args) throws Throwable {
   42.19              final PrintWriter out = Context.getCurrentErr();
   42.20              tracePrint(out, "ENTER ", args, null);
    43.1 --- a/src/jdk/nashorn/internal/runtime/options/Options.java	Tue Jan 29 14:25:39 2013 -0400
    43.2 +++ b/src/jdk/nashorn/internal/runtime/options/Options.java	Wed Jan 30 12:26:45 2013 +0100
    43.3 @@ -416,7 +416,7 @@
    43.4                      System.setProperty(value.substring(0, eq), value.substring(eq + 1));
    43.5                  } else {
    43.6                      // -Dfoo is fine. Set System property "foo" with "" as it's value
    43.7 -                    if (!value.equals("")) {
    43.8 +                    if (!value.isEmpty()) {
    43.9                          System.setProperty(value, "");
   43.10                      } else {
   43.11                          // do not allow empty property name
    44.1 --- a/src/jdk/nashorn/tools/Shell.java	Tue Jan 29 14:25:39 2013 -0400
    44.2 +++ b/src/jdk/nashorn/tools/Shell.java	Wed Jan 30 12:26:45 2013 +0100
    44.3 @@ -178,7 +178,7 @@
    44.4       * @return null if there are problems with option parsing.
    44.5       */
    44.6      @SuppressWarnings("resource")
    44.7 -    private Context makeContext(final InputStream in, final OutputStream out, final OutputStream err, final String[] args) {
    44.8 +    private static Context makeContext(final InputStream in, final OutputStream out, final OutputStream err, final String[] args) {
    44.9          final PrintStream pout = out instanceof PrintStream ? (PrintStream) out : new PrintStream(out);
   44.10          final PrintStream perr = err instanceof PrintStream ? (PrintStream) err : new PrintStream(err);
   44.11          final PrintWriter wout = new PrintWriter(pout, true);
   44.12 @@ -230,7 +230,7 @@
   44.13       * @return error code
   44.14       * @throws IOException when any script file read results in I/O error
   44.15       */
   44.16 -    private int compileScripts(final Context context, final ScriptObject global, final List<String> files) throws IOException {
   44.17 +    private static int compileScripts(final Context context, final ScriptObject global, final List<String> files) throws IOException {
   44.18          final ScriptObject oldGlobal = Context.getGlobal();
   44.19          final boolean globalChanged = (oldGlobal != global);
   44.20          try {
   44.21 @@ -330,7 +330,7 @@
   44.22       * @return return code
   44.23       */
   44.24      @SuppressWarnings("resource")
   44.25 -    private int readEvalPrint(final Context context, final ScriptObject global) {
   44.26 +    private static int readEvalPrint(final Context context, final ScriptObject global) {
   44.27          final String prompt = bundle.getString("shell.prompt");
   44.28          final BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
   44.29          final PrintWriter err = context.getErr();
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/test/script/basic/access-specializer.js	Wed Jan 30 12:26:45 2013 +0100
    45.3 @@ -0,0 +1,43 @@
    45.4 +/*
    45.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
    45.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    45.7 + * 
    45.8 + * This code is free software; you can redistribute it and/or modify it
    45.9 + * under the terms of the GNU General Public License version 2 only, as
   45.10 + * published by the Free Software Foundation.
   45.11 + * 
   45.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   45.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   45.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   45.15 + * version 2 for more details (a copy is included in the LICENSE file that
   45.16 + * accompanied this code).
   45.17 + * 
   45.18 + * You should have received a copy of the GNU General Public License version
   45.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   45.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   45.21 + * 
   45.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   45.23 + * or visit www.oracle.com if you need additional information or have any
   45.24 + * questions.
   45.25 + */
   45.26 +
   45.27 +/**
   45.28 + * This is a simple test that checks that access specialization in FinalizeTypes is consistent.
   45.29 + * Here, a2 = 0 will be turned int {I}a2 = 0, and all would be fine and well, only we can't change
   45.30 + * the symbol type for a2 from double, and we can't as it's not a temporary. Either we have to put 
   45.31 + * a temporary in at the late finalize stage and add another assignment, or we genericize the check
   45.32 + * in CodeGenerator#Store so we detect whether a target is of the wrong type before storing. It 
   45.33 + * is hopefully very rare, and will only be a problem when assignment results that have been
   45.34 + * specialized live on the stack
   45.35 + *
   45.36 + * @test
   45.37 + * @run
   45.38 + */
   45.39 +
   45.40 +function f() {
   45.41 +    var a0 = a1 = a2 = 0;
   45.42 +    a0 = 16.1;
   45.43 +    a1 = 17.1;
   45.44 +    a2 = 18.1;
   45.45 +}
   45.46 +f();
    46.1 --- a/test/script/basic/compile-octane.js.EXPECTED	Tue Jan 29 14:25:39 2013 -0400
    46.2 +++ b/test/script/basic/compile-octane.js.EXPECTED	Wed Jan 30 12:26:45 2013 +0100
    46.3 @@ -1,12 +1,36 @@
    46.4 +Compiling... box2d.js
    46.5  Compiled OK: box2d.js
    46.6 +
    46.7 +Compiling... code-load.js
    46.8  Compiled OK: code-load.js
    46.9 +
   46.10 +Compiling... crypto.js
   46.11  Compiled OK: crypto.js
   46.12 +
   46.13 +Compiling... deltablue.js
   46.14  Compiled OK: deltablue.js
   46.15 +
   46.16 +Compiling... earley-boyer.js
   46.17  Compiled OK: earley-boyer.js
   46.18 +
   46.19 +Compiling... gbemu.js
   46.20  Compiled OK: gbemu.js
   46.21 +
   46.22 +Compiling... navier-stokes.js
   46.23  Compiled OK: navier-stokes.js
   46.24 +
   46.25 +Compiling... pdfjs.js
   46.26  Compiled OK: pdfjs.js
   46.27 +
   46.28 +Compiling... raytrace.js
   46.29  Compiled OK: raytrace.js
   46.30 +
   46.31 +Compiling... regexp.js
   46.32  Compiled OK: regexp.js
   46.33 +
   46.34 +Compiling... richards.js
   46.35  Compiled OK: richards.js
   46.36 +
   46.37 +Compiling... splay.js
   46.38  Compiled OK: splay.js
   46.39 +
    47.1 --- a/test/script/basic/run-octane.js	Tue Jan 29 14:25:39 2013 -0400
    47.2 +++ b/test/script/basic/run-octane.js	Wed Jan 30 12:26:45 2013 +0100
    47.3 @@ -65,11 +65,7 @@
    47.4  
    47.5  function run_one_benchmark(arg, iters) {
    47.6  
    47.7 -    load(path + 'base.js');
    47.8 -    load(arg);
    47.9 -
   47.10      var file_name;
   47.11 -
   47.12      var file = arg.split('/');
   47.13      if (file.length == 1) {
   47.14          file = arg.split('\\');
   47.15 @@ -80,9 +76,17 @@
   47.16  	file.pop();
   47.17      }
   47.18      file_name = file[file.length - 1];
   47.19 +
   47.20 +    if (typeof compile_only !== 'undefined') {
   47.21 +	print("Compiling... " + file_name);
   47.22 +    }
   47.23 +
   47.24 +    load(path + 'base.js');
   47.25 +    load(arg);
   47.26      
   47.27      if (typeof compile_only !== 'undefined') {
   47.28  	print("Compiled OK: " + file_name);
   47.29 +	print("");
   47.30  	return;
   47.31      }
   47.32      
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/test/script/basic/typecoerce.js	Wed Jan 30 12:26:45 2013 +0100
    48.3 @@ -0,0 +1,53 @@
    48.4 +/*
    48.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
    48.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    48.7 + * 
    48.8 + * This code is free software; you can redistribute it and/or modify it
    48.9 + * under the terms of the GNU General Public License version 2 only, as
   48.10 + * published by the Free Software Foundation.
   48.11 + * 
   48.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   48.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   48.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   48.15 + * version 2 for more details (a copy is included in the LICENSE file that
   48.16 + * accompanied this code).
   48.17 + * 
   48.18 + * You should have received a copy of the GNU General Public License version
   48.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   48.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   48.21 + * 
   48.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   48.23 + * or visit www.oracle.com if you need additional information or have any
   48.24 + * questions.
   48.25 + */
   48.26 +
   48.27 +/**
   48.28 + * There was a bug in the old Lower that didn't fully propagate type information
   48.29 + * by way of assignment. 'q' in the example below would have finished a double
   48.30 + * even though it can get an object value through the assignment 'q = l' 
   48.31 + * 
   48.32 + * Furthermore, this caused type coercion to be done at q = l, and not a q = q * 2, 
   48.33 + * which is a bug. This test ensures it happens in the correct order
   48.34 + *
   48.35 + * @test
   48.36 + * @run
   48.37 + */
   48.38 +
   48.39 +function createObject() {
   48.40 +    var obj = { valueOf: function() { print("toNumber coercion"); return 17; }}
   48.41 +    return obj;
   48.42 +}
   48.43 +
   48.44 +function f() {
   48.45 +    var l = 1.2; //number
   48.46 +    var q = 2.3; //number
   48.47 +    for (var i = 0; i < 2; i++) {
   48.48 +	q = l; // q = toNumber(l), no coercion here
   48.49 +	print("assignment done");
   48.50 +	q = q * 2; // q = q * 2, coercion here
   48.51 +	print("multiplication done");
   48.52 +	l = createObject();
   48.53 +    }
   48.54 +}
   48.55 +
   48.56 +f();
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/test/script/basic/typecoerce.js.EXPECTED	Wed Jan 30 12:26:45 2013 +0100
    49.3 @@ -0,0 +1,5 @@
    49.4 +assignment done
    49.5 +multiplication done
    49.6 +assignment done
    49.7 +toNumber coercion
    49.8 +multiplication done

mercurial