8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]

Fri, 03 May 2013 15:33:54 +0200

author
lagergren
date
Fri, 03 May 2013 15:33:54 +0200
changeset 247
5a3f7867e19c
parent 246
c8023561505b
child 248
829b06307fb2

8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
Reviewed-by: jlaskey, hannesw

bin/jjs file | annotate | diff | comparison | revisions
src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.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/CompilationPhase.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Compiler.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FinalizeTypes.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/ObjectCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Splitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Block.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/CatchNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/FunctionNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LexicalContext.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LexicalContextNode.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/Symbol.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeRegExp.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/runtime/CompiledFunction.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/CompiledFunctions.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/JSONFunctions.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptEnvironment.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/resources/Options.properties file | annotate | diff | comparison | revisions
src/jdk/nashorn/tools/Shell.java file | annotate | diff | comparison | revisions
test/script/basic/paramspec.js file | annotate | diff | comparison | revisions
test/script/basic/paramspec.js.EXPECTED file | annotate | diff | comparison | revisions
test/script/basic/runsunspider.js file | annotate | diff | comparison | revisions
test/script/currently-failing/logcoverage.js file | annotate | diff | comparison | revisions
test/script/trusted/logcoverage.js file | annotate | diff | comparison | revisions
     1.1 --- a/bin/jjs	Thu May 02 15:01:16 2013 -0300
     1.2 +++ b/bin/jjs	Fri May 03 15:33:54 2013 +0200
     1.3 @@ -26,4 +26,4 @@
     1.4  
     1.5  [ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1;
     1.6  
     1.7 -$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
     1.8 +$JAVA_HOME/bin/java -server -XX:+TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
     2.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Thu May 02 15:01:16 2013 -0300
     2.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Fri May 03 15:33:54 2013 +0200
     2.3 @@ -31,7 +31,6 @@
     2.4  import javax.script.ScriptEngine;
     2.5  import javax.script.ScriptEngineFactory;
     2.6  import jdk.nashorn.internal.runtime.Version;
     2.7 -import sun.reflect.Reflection;
     2.8  
     2.9  /**
    2.10   * JSR-223 compliant script engine factory for Nashorn. The engine answers for:
     3.1 --- a/src/jdk/nashorn/internal/codegen/Attr.java	Thu May 02 15:01:16 2013 -0300
     3.2 +++ b/src/jdk/nashorn/internal/codegen/Attr.java	Fri May 03 15:33:54 2013 +0200
     3.3 @@ -29,17 +29,21 @@
     3.4  import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
     3.5  import static jdk.nashorn.internal.codegen.CompilerConstants.EXCEPTION_PREFIX;
     3.6  import static jdk.nashorn.internal.codegen.CompilerConstants.ITERATOR_PREFIX;
     3.7 +import static jdk.nashorn.internal.codegen.CompilerConstants.LITERAL_PREFIX;
     3.8  import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
     3.9  import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
    3.10  import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX;
    3.11 +import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX;
    3.12  import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
    3.13  import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
    3.14 +import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT;
    3.15  import static jdk.nashorn.internal.ir.Symbol.IS_FUNCTION_SELF;
    3.16  import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
    3.17  import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
    3.18  import static jdk.nashorn.internal.ir.Symbol.IS_LET;
    3.19  import static jdk.nashorn.internal.ir.Symbol.IS_PARAM;
    3.20  import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE;
    3.21 +import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
    3.22  import static jdk.nashorn.internal.ir.Symbol.IS_THIS;
    3.23  import static jdk.nashorn.internal.ir.Symbol.IS_VAR;
    3.24  import static jdk.nashorn.internal.ir.Symbol.KINDMASK;
    3.25 @@ -51,6 +55,7 @@
    3.26  import java.util.Iterator;
    3.27  import java.util.List;
    3.28  import java.util.Set;
    3.29 +
    3.30  import jdk.nashorn.internal.codegen.types.Type;
    3.31  import jdk.nashorn.internal.ir.AccessNode;
    3.32  import jdk.nashorn.internal.ir.BinaryNode;
    3.33 @@ -90,7 +95,6 @@
    3.34  import jdk.nashorn.internal.runtime.JSType;
    3.35  import jdk.nashorn.internal.runtime.Property;
    3.36  import jdk.nashorn.internal.runtime.PropertyMap;
    3.37 -import jdk.nashorn.internal.runtime.ScriptFunction;
    3.38  import jdk.nashorn.internal.runtime.ScriptObject;
    3.39  
    3.40  /**
    3.41 @@ -133,9 +137,9 @@
    3.42       * Constructor.
    3.43       */
    3.44      Attr() {
    3.45 -        localDefs = new ArrayDeque<>();
    3.46 -        localUses = new ArrayDeque<>();
    3.47 -        returnTypes = new ArrayDeque<>();
    3.48 +        this.localDefs   = new ArrayDeque<>();
    3.49 +        this.localUses   = new ArrayDeque<>();
    3.50 +        this.returnTypes = new ArrayDeque<>();
    3.51      }
    3.52  
    3.53      @Override
    3.54 @@ -150,67 +154,48 @@
    3.55  
    3.56      @Override
    3.57      public Node leaveAccessNode(final AccessNode accessNode) {
    3.58 -        ensureSymbol(Type.OBJECT, accessNode);  //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this
    3.59 -        end(accessNode);
    3.60 -        return accessNode;
    3.61 +        //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this
    3.62 +        return end(ensureSymbol(Type.OBJECT, accessNode));
    3.63      }
    3.64  
    3.65 -    private void enterFunctionBody() {
    3.66 +    private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) {
    3.67 +        initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL, FunctionNode.FUNCTION_TYPE);
    3.68 +        initCompileConstant(THIS, body, IS_PARAM | IS_THIS, Type.OBJECT);
    3.69  
    3.70 -        final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
    3.71 -        final Block body = getLexicalContext().getCurrentBlock();
    3.72 -        initCallee(body);
    3.73 -        initThis(body);
    3.74          if (functionNode.isVarArg()) {
    3.75 -            initVarArg(body, functionNode.needsArguments());
    3.76 +            initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL, Type.OBJECT_ARRAY);
    3.77 +            if (functionNode.needsArguments()) {
    3.78 +                initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL, Type.typeFor(ScriptObject.class));
    3.79 +                addLocalDef(ARGUMENTS.symbolName());
    3.80 +            }
    3.81          }
    3.82  
    3.83          initParameters(functionNode, body);
    3.84 -        initScope(body);
    3.85 -        initReturn(body);
    3.86 +        initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL, Type.typeFor(ScriptObject.class));
    3.87 +        initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL, Type.OBJECT);
    3.88 +    }
    3.89  
    3.90 -        if (functionNode.isProgram()) {
    3.91 -            initFromPropertyMap(body);
    3.92 -        } else if(!functionNode.isDeclared()) {
    3.93 -            // It's neither declared nor program - it's a function expression then; assign it a self-symbol.
    3.94  
    3.95 -            if (functionNode.getSymbol() != null) {
    3.96 -                // a temporary left over from an earlier pass when the function was lazy
    3.97 -                assert functionNode.getSymbol().isTemp();
    3.98 -                // remove it
    3.99 -                functionNode.setSymbol(null);
   3.100 -            }
   3.101 -            final boolean anonymous = functionNode.isAnonymous();
   3.102 -            final String name = anonymous ? null : functionNode.getIdent().getName();
   3.103 -            if (anonymous || body.getExistingSymbol(name) != null) {
   3.104 -                // The function is either anonymous, or another local identifier already trumps its name on entry:
   3.105 -                // either it has the same name as one of its parameters, or is named "arguments" and also references the
   3.106 -                // "arguments" identifier in its body.
   3.107 -                ensureSymbol(functionNode, Type.typeFor(ScriptFunction.class), functionNode);
   3.108 -            } else {
   3.109 -                final Symbol selfSymbol = defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF, functionNode);
   3.110 -                assert selfSymbol.isFunctionSelf();
   3.111 -                newType(selfSymbol, Type.OBJECT);
   3.112 -            }
   3.113 -        }
   3.114 -
   3.115 -        /*
   3.116 -         * This pushes all declarations (except for non-statements, i.e. for
   3.117 -         * node temporaries) to the top of the function scope. This way we can
   3.118 -         * get around problems like
   3.119 -         *
   3.120 -         * while (true) {
   3.121 -         *   break;
   3.122 -         *   if (true) {
   3.123 -         *     var s;
   3.124 -         *   }
   3.125 -         * }
   3.126 -         *
   3.127 -         * to an arbitrary nesting depth.
   3.128 -         *
   3.129 -         * @see NASHORN-73
   3.130 -         */
   3.131 -
   3.132 +    /**
   3.133 +     * This pushes all declarations (except for non-statements, i.e. for
   3.134 +     * node temporaries) to the top of the function scope. This way we can
   3.135 +     * get around problems like
   3.136 +     *
   3.137 +     * while (true) {
   3.138 +     *   break;
   3.139 +     *   if (true) {
   3.140 +     *     var s;
   3.141 +     *   }
   3.142 +     * }
   3.143 +     *
   3.144 +     * to an arbitrary nesting depth.
   3.145 +     *
   3.146 +     * see NASHORN-73
   3.147 +     *
   3.148 +     * @param functionNode the FunctionNode we are entering
   3.149 +     * @param body the body of the FunctionNode we are entering
   3.150 +     */
   3.151 +    private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
   3.152          // This visitor will assign symbol to all declared variables, except function declarations (which are taken care
   3.153          // in a separate step above) and "var" declarations in for loop initializers.
   3.154          body.accept(new NodeOperatorVisitor() {
   3.155 @@ -220,27 +205,52 @@
   3.156              }
   3.157  
   3.158              @Override
   3.159 -            public boolean enterVarNode(final VarNode varNode) {
   3.160 -
   3.161 +            public Node leaveVarNode(final VarNode varNode) {
   3.162                  // any declared symbols that aren't visited need to be typed as well, hence the list
   3.163 -
   3.164                  if (varNode.isStatement()) {
   3.165 -
   3.166 -                    final IdentNode ident = varNode.getName();
   3.167 -                    final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR, new IdentNode(ident));
   3.168 +                    final IdentNode ident  = varNode.getName();
   3.169 +                    final Symbol    symbol = defineSymbol(body, ident.getName(), IS_VAR);
   3.170                      functionNode.addDeclaredSymbol(symbol);
   3.171                      if (varNode.isFunctionDeclaration()) {
   3.172                          newType(symbol, FunctionNode.FUNCTION_TYPE);
   3.173                      }
   3.174 +                    return varNode.setName((IdentNode)ident.setSymbol(getLexicalContext(), symbol));
   3.175                  }
   3.176 -                return false;
   3.177 +                return varNode;
   3.178              }
   3.179          });
   3.180      }
   3.181  
   3.182 +    private void enterFunctionBody() {
   3.183 +
   3.184 +        final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
   3.185 +        final Block body = getLexicalContext().getCurrentBlock();
   3.186 +
   3.187 +        initFunctionWideVariables(functionNode, body);
   3.188 +
   3.189 +        if (functionNode.isProgram()) {
   3.190 +            initFromPropertyMap(body);
   3.191 +        } else if (!functionNode.isDeclared()) {
   3.192 +            // It's neither declared nor program - it's a function expression then; assign it a self-symbol.
   3.193 +            assert functionNode.getSymbol() == null;
   3.194 +
   3.195 +            final boolean anonymous = functionNode.isAnonymous();
   3.196 +            final String  name      = anonymous ? null : functionNode.getIdent().getName();
   3.197 +            if (!(anonymous || body.getExistingSymbol(name) != null)) {
   3.198 +                assert !anonymous && name != null;
   3.199 +                newType(defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF), Type.OBJECT);
   3.200 +            }
   3.201 +        }
   3.202 +
   3.203 +        acceptDeclarations(functionNode, body);
   3.204 +    }
   3.205 +
   3.206      @Override
   3.207      public boolean enterBlock(final Block block) {
   3.208          start(block);
   3.209 +        //ensure that we don't use information from a previous compile. This is very ugly TODO
   3.210 +        //the symbols in the block should really be stateless
   3.211 +        block.clearSymbols();
   3.212  
   3.213          if (getLexicalContext().isFunctionBody()) {
   3.214              enterFunctionBody();
   3.215 @@ -257,14 +267,13 @@
   3.216      }
   3.217  
   3.218      @Override
   3.219 -    public Node leaveCallNode(final CallNode callNode) {
   3.220 -        ensureSymbol(callNode.getType(), callNode);
   3.221 -        return end(callNode);
   3.222 +    public boolean enterCallNode(final CallNode callNode) {
   3.223 +        return start(callNode);
   3.224      }
   3.225  
   3.226      @Override
   3.227 -    public boolean enterCallNode(final CallNode callNode) {
   3.228 -        return start(callNode);
   3.229 +    public Node leaveCallNode(final CallNode callNode) {
   3.230 +        return end(ensureSymbol(callNode.getType(), callNode));
   3.231      }
   3.232  
   3.233      @Override
   3.234 @@ -275,23 +284,31 @@
   3.235          start(catchNode);
   3.236  
   3.237          // define block-local exception variable
   3.238 -        final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception);
   3.239 +        final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET);
   3.240          newType(def, Type.OBJECT);
   3.241          addLocalDef(exception.getName());
   3.242  
   3.243          return true;
   3.244      }
   3.245  
   3.246 +    @Override
   3.247 +    public Node leaveCatchNode(final CatchNode catchNode) {
   3.248 +        final IdentNode exception = catchNode.getException();
   3.249 +        final Block  block        = getLexicalContext().getCurrentBlock();
   3.250 +        final Symbol symbol       = findSymbol(block, exception.getName());
   3.251 +        assert symbol != null;
   3.252 +        return end(catchNode.setException((IdentNode)exception.setSymbol(getLexicalContext(), symbol)));
   3.253 +    }
   3.254 +
   3.255      /**
   3.256       * Declare the definition of a new symbol.
   3.257       *
   3.258       * @param name         Name of symbol.
   3.259       * @param symbolFlags  Symbol flags.
   3.260 -     * @param node         Defining Node.
   3.261       *
   3.262       * @return Symbol for given name or null for redefinition.
   3.263       */
   3.264 -    private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) {
   3.265 +    private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) {
   3.266          int    flags  = symbolFlags;
   3.267          Symbol symbol = findSymbol(block, name); // Locate symbol.
   3.268  
   3.269 @@ -337,7 +354,7 @@
   3.270  
   3.271              // Create and add to appropriate block.
   3.272              symbol = new Symbol(name, flags);
   3.273 -            symbolBlock.putSymbol(name, symbol);
   3.274 +            symbolBlock.putSymbol(getLexicalContext(), symbol);
   3.275  
   3.276              if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
   3.277                  symbol.setNeedsSlot(true);
   3.278 @@ -346,10 +363,6 @@
   3.279              symbol.setFlags(flags);
   3.280          }
   3.281  
   3.282 -        if (node != null) {
   3.283 -            node.setSymbol(symbol);
   3.284 -        }
   3.285 -
   3.286          return symbol;
   3.287      }
   3.288  
   3.289 @@ -357,30 +370,22 @@
   3.290      public boolean enterFunctionNode(final FunctionNode functionNode) {
   3.291          start(functionNode, false);
   3.292  
   3.293 +        if (functionNode.isLazy()) {
   3.294 +            return false;
   3.295 +        }
   3.296 +
   3.297 +        //an outermost function in our lexical context that is not a program (runScript)
   3.298 +        //is possible - it is a function being compiled lazily
   3.299          if (functionNode.isDeclared()) {
   3.300              final Iterator<Block> blocks = getLexicalContext().getBlocks();
   3.301              if (blocks.hasNext()) {
   3.302 -                defineSymbol(
   3.303 -                    blocks.next(),
   3.304 -                    functionNode.getIdent().getName(),
   3.305 -                    IS_VAR,
   3.306 -                    functionNode);
   3.307 -            } else {
   3.308 -                // Q: What's an outermost function in a lexical context that is not a program?
   3.309 -                // A: It's a function being compiled lazily!
   3.310 -                assert getLexicalContext().getOutermostFunction() == functionNode && !functionNode.isProgram();
   3.311 +                defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR);
   3.312              }
   3.313          }
   3.314  
   3.315 -        if (functionNode.isLazy()) {
   3.316 -            LOG.info("LAZY: ", functionNode.getName(), " => Promoting to OBJECT");
   3.317 -            ensureSymbol(getLexicalContext().getCurrentFunction(), Type.OBJECT, functionNode);
   3.318 -            end(functionNode);
   3.319 -            return false;
   3.320 -        }
   3.321 -
   3.322          returnTypes.push(functionNode.getReturnType());
   3.323          pushLocalsFunction();
   3.324 +
   3.325          return true;
   3.326      }
   3.327  
   3.328 @@ -390,8 +395,29 @@
   3.329  
   3.330          final LexicalContext lc = getLexicalContext();
   3.331  
   3.332 +        final Block body = newFunctionNode.getBody();
   3.333 +
   3.334 +        //look for this function in the parent block
   3.335 +        if (functionNode.isDeclared()) {
   3.336 +            final Iterator<Block> blocks = getLexicalContext().getBlocks();
   3.337 +            if (blocks.hasNext()) {
   3.338 +                newFunctionNode = (FunctionNode)newFunctionNode.setSymbol(lc, findSymbol(blocks.next(), functionNode.getIdent().getName()));
   3.339 +            }
   3.340 +        } else if (!functionNode.isProgram()) {
   3.341 +            final boolean anonymous = functionNode.isAnonymous();
   3.342 +            final String  name      = anonymous ? null : functionNode.getIdent().getName();
   3.343 +            if (anonymous || body.getExistingSymbol(name) != null) {
   3.344 +                newFunctionNode = (FunctionNode)Attr.ensureSymbol(lc, body, FunctionNode.FUNCTION_TYPE, newFunctionNode);
   3.345 +            } else {
   3.346 +                assert name != null;
   3.347 +                final Symbol self = body.getExistingSymbol(name);
   3.348 +                assert self != null && self.isFunctionSelf();
   3.349 +                newFunctionNode = (FunctionNode)newFunctionNode.setSymbol(lc, body.getExistingSymbol(name));
   3.350 +            }
   3.351 +        }
   3.352 +
   3.353          //unknown parameters are promoted to object type.
   3.354 -        finalizeParameters(newFunctionNode);
   3.355 +        newFunctionNode = finalizeParameters(newFunctionNode);
   3.356          finalizeTypes(newFunctionNode);
   3.357          for (final Symbol symbol : newFunctionNode.getDeclaredSymbols()) {
   3.358              if (symbol.getSymbolType().isUnknown()) {
   3.359 @@ -400,8 +426,6 @@
   3.360              }
   3.361          }
   3.362  
   3.363 -        final Block body = newFunctionNode.getBody();
   3.364 -
   3.365          if (newFunctionNode.hasLazyChildren()) {
   3.366              //the final body has already been assigned as we have left the function node block body by now
   3.367              objectifySymbols(body);
   3.368 @@ -409,7 +433,7 @@
   3.369  
   3.370          if (body.getFlag(Block.NEEDS_SELF_SYMBOL)) {
   3.371              final IdentNode callee = compilerConstant(CALLEE);
   3.372 -            final VarNode selfInit =
   3.373 +            VarNode selfInit =
   3.374                  new VarNode(
   3.375                      newFunctionNode.getSource(),
   3.376                      newFunctionNode.getToken(),
   3.377 @@ -420,7 +444,6 @@
   3.378              LOG.info("Accepting self symbol init ", selfInit, " for ", newFunctionNode.getName());
   3.379  
   3.380              final List<Node> newStatements = new ArrayList<>();
   3.381 -            newStatements.add(selfInit);
   3.382              assert callee.getSymbol() != null && callee.getSymbol().hasSlot();
   3.383  
   3.384              final IdentNode name       = selfInit.getName();
   3.385 @@ -428,9 +451,10 @@
   3.386  
   3.387              assert nameSymbol != null;
   3.388  
   3.389 -            name.setSymbol(nameSymbol);
   3.390 -            selfInit.setSymbol(nameSymbol);
   3.391 +            selfInit = selfInit.setName((IdentNode)name.setSymbol(lc, nameSymbol));
   3.392 +            selfInit = (VarNode)selfInit.setSymbol(lc, nameSymbol);
   3.393  
   3.394 +            newStatements.add(selfInit);
   3.395              newStatements.addAll(body.getStatements());
   3.396              newFunctionNode = newFunctionNode.setBody(lc, body.setStatements(lc, newStatements));
   3.397          }
   3.398 @@ -447,34 +471,32 @@
   3.399  
   3.400          end(newFunctionNode, false);
   3.401  
   3.402 -        return newFunctionNode; //.setFlag(lc, lc.getFlags(functionNode));
   3.403 +        return newFunctionNode;
   3.404      }
   3.405  
   3.406      @Override
   3.407      public Node leaveCONVERT(final UnaryNode unaryNode) {
   3.408          assert false : "There should be no convert operators in IR during Attribution";
   3.409 -        end(unaryNode);
   3.410 -        return unaryNode;
   3.411 +        return end(unaryNode);
   3.412      }
   3.413  
   3.414      @Override
   3.415 -    public boolean enterIdentNode(final IdentNode identNode) {
   3.416 +    public Node leaveIdentNode(final IdentNode identNode) {
   3.417          final String name = identNode.getName();
   3.418  
   3.419          start(identNode);
   3.420  
   3.421 +        final LexicalContext lc = getLexicalContext();
   3.422 +
   3.423          if (identNode.isPropertyName()) {
   3.424              // assign a pseudo symbol to property name
   3.425              final Symbol pseudoSymbol = pseudoSymbol(name);
   3.426              LOG.info("IdentNode is property name -> assigning pseudo symbol ", pseudoSymbol);
   3.427              LOG.unindent();
   3.428 -            identNode.setSymbol(pseudoSymbol);
   3.429 -            return false;
   3.430 +            return identNode.setSymbol(lc, pseudoSymbol);
   3.431          }
   3.432  
   3.433 -        final LexicalContext lc        = getLexicalContext();
   3.434 -        final Block          block     = lc.getCurrentBlock();
   3.435 -        final Symbol         oldSymbol = identNode.getSymbol();
   3.436 +        final Block block = lc.getCurrentBlock();
   3.437  
   3.438          Symbol symbol = findSymbol(block, name);
   3.439  
   3.440 @@ -495,12 +517,11 @@
   3.441                  }
   3.442              }
   3.443  
   3.444 -            identNode.setSymbol(symbol);
   3.445              // if symbol is non-local or we're in a with block, we need to put symbol in scope (if it isn't already)
   3.446              maybeForceScope(symbol);
   3.447          } else {
   3.448              LOG.info("No symbol exists. Declare undefined: ", symbol);
   3.449 -            symbol = defineSymbol(block, name, IS_GLOBAL, identNode);
   3.450 +            symbol = defineSymbol(block, name, IS_GLOBAL);
   3.451              // we have never seen this before, it can be undefined
   3.452              newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway?
   3.453              symbol.setCanBeUndefined();
   3.454 @@ -509,14 +530,14 @@
   3.455  
   3.456          setBlockScope(name, symbol);
   3.457  
   3.458 -        if (symbol != oldSymbol && !identNode.isInitializedHere()) {
   3.459 +        if (symbol != null && !identNode.isInitializedHere()) {
   3.460              symbol.increaseUseCount();
   3.461          }
   3.462          addLocalUse(identNode.getName());
   3.463  
   3.464          end(identNode);
   3.465  
   3.466 -        return false;
   3.467 +        return identNode.setSymbol(lc, symbol);
   3.468      }
   3.469  
   3.470      /**
   3.471 @@ -525,7 +546,7 @@
   3.472       * @param symbol the symbol that might be scoped
   3.473       */
   3.474      private void maybeForceScope(final Symbol symbol) {
   3.475 -        if(!symbol.isScope() && symbolNeedsToBeScope(symbol)) {
   3.476 +        if (!symbol.isScope() && symbolNeedsToBeScope(symbol)) {
   3.477              Symbol.setSymbolIsScope(getLexicalContext(), symbol);
   3.478          }
   3.479      }
   3.480 @@ -612,11 +633,11 @@
   3.481      private Symbol findSymbol(final Block block, final String name) {
   3.482          // Search up block chain to locate symbol.
   3.483  
   3.484 -        for(final Iterator<Block> blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) {
   3.485 +        for (final Iterator<Block> blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) {
   3.486              // Find name.
   3.487              final Symbol symbol = blocks.next().getExistingSymbol(name);
   3.488              // If found then we are good.
   3.489 -            if(symbol != null) {
   3.490 +            if (symbol != null) {
   3.491                  return symbol;
   3.492              }
   3.493          }
   3.494 @@ -625,39 +646,19 @@
   3.495  
   3.496      @Override
   3.497      public Node leaveIndexNode(final IndexNode indexNode) {
   3.498 -        ensureSymbol(Type.OBJECT, indexNode); //TODO
   3.499 -        return indexNode;
   3.500 +        return end(ensureSymbol(Type.OBJECT, indexNode));
   3.501      }
   3.502  
   3.503      @SuppressWarnings("rawtypes")
   3.504      @Override
   3.505 -    public boolean enterLiteralNode(final LiteralNode literalNode) {
   3.506 -        try {
   3.507 -            start(literalNode);
   3.508 -            assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens
   3.509 -
   3.510 -            if (literalNode instanceof ArrayLiteralNode) {
   3.511 -                final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
   3.512 -                final Node[]           array            = arrayLiteralNode.getValue();
   3.513 -
   3.514 -                for (int i = 0; i < array.length; i++) {
   3.515 -                    final Node element = array[i];
   3.516 -                    if (element != null) {
   3.517 -                        array[i] = element.accept(this);
   3.518 -                    }
   3.519 -                }
   3.520 -                arrayLiteralNode.analyze();
   3.521 -                //array literal node now has an element type and all elements are attributed
   3.522 -            } else {
   3.523 -                assert !(literalNode.getValue() instanceof Node) : "literals with Node values not supported";
   3.524 -            }
   3.525 -
   3.526 -            getLexicalContext().getCurrentFunction().newLiteral(literalNode);
   3.527 -        } finally {
   3.528 -            end(literalNode);
   3.529 +    public Node leaveLiteralNode(final LiteralNode literalNode) {
   3.530 +        assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens
   3.531 +        assert literalNode instanceof ArrayLiteralNode || !(literalNode.getValue() instanceof Node) : "literals with Node values not supported";
   3.532 +        final Symbol symbol = new Symbol(getLexicalContext().getCurrentFunction().uniqueName(LITERAL_PREFIX.symbolName()), IS_CONSTANT, literalNode.getType());
   3.533 +        if (literalNode instanceof ArrayLiteralNode) {
   3.534 +            ((ArrayLiteralNode)literalNode).analyze();
   3.535          }
   3.536 -
   3.537 -        return false;
   3.538 +        return literalNode.setSymbol(getLexicalContext(), symbol);
   3.539      }
   3.540  
   3.541      @Override
   3.542 @@ -667,18 +668,13 @@
   3.543  
   3.544      @Override
   3.545      public Node leaveObjectNode(final ObjectNode objectNode) {
   3.546 -        ensureSymbol(Type.OBJECT, objectNode);
   3.547 -        return end(objectNode);
   3.548 +        return end(ensureSymbol(Type.OBJECT, objectNode));
   3.549      }
   3.550  
   3.551 -    //TODO is this correct why not leave?
   3.552      @Override
   3.553 -    public boolean enterPropertyNode(final PropertyNode propertyNode) {
   3.554 +    public Node leavePropertyNode(final PropertyNode propertyNode) {
   3.555          // assign a pseudo symbol to property name, see NASHORN-710
   3.556 -        start(propertyNode);
   3.557 -        propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
   3.558 -        end(propertyNode);
   3.559 -        return true;
   3.560 +        return propertyNode.setSymbol(getLexicalContext(), new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
   3.561      }
   3.562  
   3.563      @Override
   3.564 @@ -763,12 +759,9 @@
   3.565          final IdentNode ident = varNode.getName();
   3.566          final String    name  = ident.getName();
   3.567  
   3.568 -        final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR, ident);
   3.569 +        final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR);
   3.570          assert symbol != null;
   3.571  
   3.572 -        LOG.info("VarNode ", varNode, " set symbol ", symbol);
   3.573 -        varNode.setSymbol(symbol);
   3.574 -
   3.575          // NASHORN-467 - use before definition of vars - conservative
   3.576          if (isLocalUse(ident.getName())) {
   3.577              newType(symbol, Type.OBJECT);
   3.578 @@ -780,22 +773,31 @@
   3.579  
   3.580      @Override
   3.581      public Node leaveVarNode(final VarNode varNode) {
   3.582 -        final Node      init  = varNode.getInit();
   3.583 -        final IdentNode ident = varNode.getName();
   3.584 +        VarNode newVarNode = varNode;
   3.585 +
   3.586 +        final Node      init  = newVarNode.getInit();
   3.587 +        final IdentNode ident = newVarNode.getName();
   3.588          final String    name  = ident.getName();
   3.589  
   3.590          if (init == null) {
   3.591              // var x; with no init will be treated like a use of x by
   3.592 -            // visit(IdentNode) unless we remove the name
   3.593 -            // from the localdef list.
   3.594 +            // leaveIdentNode unless we remove the name from the localdef list.
   3.595              removeLocalDef(name);
   3.596 -            return varNode;
   3.597 +            return newVarNode;
   3.598          }
   3.599  
   3.600          addLocalDef(name);
   3.601  
   3.602 -        final Symbol  symbol   = varNode.getSymbol();
   3.603 -        final boolean isScript = getLexicalContext().getDefiningFunction(symbol).isProgram(); //see NASHORN-56
   3.604 +        final LexicalContext lc = getLexicalContext();
   3.605 +        final Symbol  symbol = findSymbol(lc.getCurrentBlock(), ident.getName());
   3.606 +        assert symbol != null;
   3.607 +
   3.608 +        final IdentNode newIdent = (IdentNode)ident.setSymbol(lc, symbol);
   3.609 +
   3.610 +        newVarNode = newVarNode.setName(newIdent);
   3.611 +        newVarNode = (VarNode)newVarNode.setSymbol(lc, symbol);
   3.612 +
   3.613 +        final boolean isScript = lc.getDefiningFunction(symbol).isProgram(); //see NASHORN-56
   3.614          if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) {
   3.615              // Forbid integers as local vars for now as we have no way to treat them as undefined
   3.616              newType(symbol, init.getType());
   3.617 @@ -803,25 +805,19 @@
   3.618              newType(symbol, Type.OBJECT);
   3.619          }
   3.620  
   3.621 -        assert varNode.hasType() : varNode;
   3.622 +        assert newVarNode.hasType() : newVarNode + " has no type";
   3.623  
   3.624 -        end(varNode);
   3.625 -
   3.626 -        return varNode;
   3.627 +        return end(newVarNode);
   3.628      }
   3.629  
   3.630      @Override
   3.631      public Node leaveADD(final UnaryNode unaryNode) {
   3.632 -        ensureSymbol(arithType(), unaryNode);
   3.633 -        end(unaryNode);
   3.634 -        return unaryNode;
   3.635 +        return end(ensureSymbol(arithType(), unaryNode));
   3.636      }
   3.637  
   3.638      @Override
   3.639      public Node leaveBIT_NOT(final UnaryNode unaryNode) {
   3.640 -        ensureSymbol(Type.INT, unaryNode);
   3.641 -        end(unaryNode);
   3.642 -        return unaryNode;
   3.643 +        return end(ensureSymbol(Type.INT, unaryNode));
   3.644      }
   3.645  
   3.646      @Override
   3.647 @@ -830,9 +826,7 @@
   3.648          ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), unaryNode.rhs());
   3.649          final Type type = arithType();
   3.650          newType(unaryNode.rhs().getSymbol(), type);
   3.651 -        ensureSymbol(type, unaryNode);
   3.652 -        end(unaryNode);
   3.653 -        return unaryNode;
   3.654 +        return end(ensureSymbol(type, unaryNode));
   3.655      }
   3.656  
   3.657      @Override
   3.658 @@ -908,23 +902,25 @@
   3.659  
   3.660      @Override
   3.661      public Node leaveNEW(final UnaryNode unaryNode) {
   3.662 -        ensureSymbol(Type.OBJECT, unaryNode);
   3.663 -        end(unaryNode);
   3.664 -        return unaryNode;
   3.665 +        return end(ensureSymbol(Type.OBJECT, unaryNode));
   3.666      }
   3.667  
   3.668      @Override
   3.669      public Node leaveNOT(final UnaryNode unaryNode) {
   3.670 -        ensureSymbol(Type.BOOLEAN, unaryNode);
   3.671 -        end(unaryNode);
   3.672 -        return unaryNode;
   3.673 +        return end(ensureSymbol(Type.BOOLEAN, unaryNode));
   3.674      }
   3.675  
   3.676      private IdentNode compilerConstant(CompilerConstants cc) {
   3.677          final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
   3.678 -        final IdentNode node = new IdentNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
   3.679 -        node.setSymbol(functionNode.compilerConstant(cc));
   3.680 -        return node;
   3.681 +        return (IdentNode)
   3.682 +            new IdentNode(
   3.683 +                functionNode.getSource(),
   3.684 +                functionNode.getToken(),
   3.685 +                functionNode.getFinish(),
   3.686 +                cc.symbolName()).
   3.687 +                setSymbol(
   3.688 +                    getLexicalContext(),
   3.689 +                    functionNode.compilerConstant(cc));
   3.690      }
   3.691  
   3.692      @Override
   3.693 @@ -952,15 +948,12 @@
   3.694  
   3.695      @Override
   3.696      public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
   3.697 -        ensureSymbol(runtimeNode.getRequest().getReturnType(), runtimeNode);
   3.698 -        return runtimeNode;
   3.699 +        return end(ensureSymbol(runtimeNode.getRequest().getReturnType(), runtimeNode));
   3.700      }
   3.701  
   3.702      @Override
   3.703      public Node leaveSUB(final UnaryNode unaryNode) {
   3.704 -        ensureSymbol(arithType(), unaryNode);
   3.705 -        end(unaryNode);
   3.706 -        return unaryNode;
   3.707 +        return end(ensureSymbol(arithType(), unaryNode));
   3.708      }
   3.709  
   3.710      @Override
   3.711 @@ -982,18 +975,16 @@
   3.712  
   3.713          ensureTypeNotUnknown(lhs);
   3.714          ensureTypeNotUnknown(rhs);
   3.715 -        ensureSymbol(Type.widest(lhs.getType(), rhs.getType()), binaryNode);
   3.716 -
   3.717 -        end(binaryNode);
   3.718 -
   3.719 -        return binaryNode;
   3.720 +        //even if we are adding two known types, this can overflow. i.e.
   3.721 +        //int and number -> number.
   3.722 +        //int and int are also number though.
   3.723 +        //something and object is object
   3.724 +        return end(ensureSymbol(Type.widest(arithType(), Type.widest(lhs.getType(), rhs.getType())), binaryNode));
   3.725      }
   3.726  
   3.727      @Override
   3.728      public Node leaveAND(final BinaryNode binaryNode) {
   3.729 -        ensureSymbol(Type.OBJECT, binaryNode);
   3.730 -        end(binaryNode);
   3.731 -        return binaryNode;
   3.732 +        return end(ensureSymbol(Type.OBJECT, binaryNode));
   3.733      }
   3.734  
   3.735      /**
   3.736 @@ -1013,8 +1004,7 @@
   3.737              Symbol symbol = findSymbol(block, name);
   3.738  
   3.739              if (symbol == null) {
   3.740 -                symbol = defineSymbol(block, name, IS_GLOBAL, ident);
   3.741 -                binaryNode.setSymbol(symbol);
   3.742 +                symbol = defineSymbol(block, name, IS_GLOBAL);
   3.743              } else {
   3.744                  maybeForceScope(symbol);
   3.745              }
   3.746 @@ -1025,6 +1015,31 @@
   3.747          return true;
   3.748      }
   3.749  
   3.750 +
   3.751 +    /**
   3.752 +     * This assign helper is called after an assignment, when all children of
   3.753 +     * the assign has been processed. It fixes the types and recursively makes
   3.754 +     * sure that everyhing has slots that should have them in the chain.
   3.755 +     *
   3.756 +     * @param binaryNode assignment node
   3.757 +     */
   3.758 +    private Node leaveAssignmentNode(final BinaryNode binaryNode) {
   3.759 +        BinaryNode newBinaryNode = binaryNode;
   3.760 +
   3.761 +        final Node lhs = binaryNode.lhs();
   3.762 +        final Node rhs = binaryNode.rhs();
   3.763 +        final Type type;
   3.764 +
   3.765 +        if (rhs.getType().isNumeric()) {
   3.766 +            type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
   3.767 +        } else {
   3.768 +            type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too.
   3.769 +        }
   3.770 +
   3.771 +        newType(lhs.getSymbol(), type);
   3.772 +        return end(ensureSymbol(type, newBinaryNode));
   3.773 +    }
   3.774 +
   3.775      private boolean isLocal(FunctionNode function, Symbol symbol) {
   3.776          final FunctionNode definingFn = getLexicalContext().getDefiningFunction(symbol);
   3.777          // Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local
   3.778 @@ -1173,14 +1188,12 @@
   3.779  
   3.780      @Override
   3.781      public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
   3.782 -        ensureSymbol(binaryNode.rhs().getType(), binaryNode);
   3.783 -        return binaryNode;
   3.784 +        return end(ensureSymbol(binaryNode.rhs().getType(), binaryNode));
   3.785      }
   3.786  
   3.787      @Override
   3.788      public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
   3.789 -        ensureSymbol(binaryNode.lhs().getType(), binaryNode);
   3.790 -        return binaryNode;
   3.791 +        return end(ensureSymbol(binaryNode.lhs().getType(), binaryNode));
   3.792      }
   3.793  
   3.794      @Override
   3.795 @@ -1189,15 +1202,10 @@
   3.796      }
   3.797  
   3.798      private Node leaveCmp(final BinaryNode binaryNode) {
   3.799 -        final Node lhs = binaryNode.lhs();
   3.800 -        final Node rhs = binaryNode.rhs();
   3.801 +        ensureTypeNotUnknown(binaryNode.lhs());
   3.802 +        ensureTypeNotUnknown(binaryNode.rhs());
   3.803  
   3.804 -        ensureSymbol(Type.BOOLEAN, binaryNode);
   3.805 -        ensureTypeNotUnknown(lhs);
   3.806 -        ensureTypeNotUnknown(rhs);
   3.807 -
   3.808 -        end(binaryNode);
   3.809 -        return binaryNode;
   3.810 +        return end(ensureSymbol(Type.BOOLEAN, binaryNode));
   3.811      }
   3.812  
   3.813      private Node coerce(final BinaryNode binaryNode, final Type operandType, final Type destType) {
   3.814 @@ -1207,11 +1215,9 @@
   3.815          // as, say, an int : function(x) { return x & 4711 }, and x is not defined in
   3.816          // the function. to make this work, uncomment the following two type inferences
   3.817          // and debug.
   3.818 -
   3.819          //newType(binaryNode.lhs().getSymbol(), operandType);
   3.820          //newType(binaryNode.rhs().getSymbol(), operandType);
   3.821 -        ensureSymbol(destType, binaryNode);
   3.822 -        return binaryNode;
   3.823 +        return ensureSymbol(destType, binaryNode);
   3.824      }
   3.825  
   3.826      private Node coerce(final BinaryNode binaryNode, final Type type) {
   3.827 @@ -1295,9 +1301,7 @@
   3.828  
   3.829      @Override
   3.830      public Node leaveOR(final BinaryNode binaryNode) {
   3.831 -        ensureSymbol(Type.OBJECT, binaryNode);
   3.832 -        end(binaryNode);
   3.833 -        return binaryNode;
   3.834 +        return end(ensureSymbol(Type.OBJECT, binaryNode));
   3.835      }
   3.836  
   3.837      @Override
   3.838 @@ -1346,50 +1350,13 @@
   3.839          ensureTypeNotUnknown(rhs);
   3.840  
   3.841          final Type type = Type.widest(lhs.getType(), rhs.getType());
   3.842 -        ensureSymbol(type, ternaryNode);
   3.843 -
   3.844 -        end(ternaryNode);
   3.845 -        assert ternaryNode.getSymbol() != null;
   3.846 -
   3.847 -        return ternaryNode;
   3.848 +        return end(ensureSymbol(type, ternaryNode));
   3.849      }
   3.850  
   3.851 -    private void initThis(final Block block) {
   3.852 -        final Symbol thisSymbol = defineSymbol(block, THIS.symbolName(), IS_PARAM | IS_THIS, null);
   3.853 -        newType(thisSymbol, Type.OBJECT);
   3.854 -        thisSymbol.setNeedsSlot(true);
   3.855 -    }
   3.856 -
   3.857 -    private void initScope(final Block block) {
   3.858 -        final Symbol scopeSymbol = defineSymbol(block, SCOPE.symbolName(), IS_VAR | IS_INTERNAL, null);
   3.859 -        newType(scopeSymbol, Type.typeFor(ScriptObject.class));
   3.860 -        scopeSymbol.setNeedsSlot(true);
   3.861 -    }
   3.862 -
   3.863 -    private void initReturn(final Block block) {
   3.864 -        final Symbol returnSymbol = defineSymbol(block, RETURN.symbolName(), IS_VAR | IS_INTERNAL, null);
   3.865 -        newType(returnSymbol, Type.OBJECT);
   3.866 -        returnSymbol.setNeedsSlot(true);
   3.867 -        //return symbol is always object as it's the __return__ thing. What returnType is is another matter though
   3.868 -    }
   3.869 -
   3.870 -    private void initVarArg(final Block block, final boolean needsArguments) {
   3.871 -        final Symbol varArgsSymbol = defineSymbol(block, VARARGS.symbolName(), IS_PARAM | IS_INTERNAL, null);
   3.872 -        varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY);
   3.873 -        varArgsSymbol.setNeedsSlot(true);
   3.874 -
   3.875 -        if (needsArguments) {
   3.876 -            final Symbol    argumentsSymbol = defineSymbol(block, ARGUMENTS.symbolName(), IS_VAR | IS_INTERNAL, null);
   3.877 -            newType(argumentsSymbol, Type.typeFor(ScriptObject.class));
   3.878 -            argumentsSymbol.setNeedsSlot(true);
   3.879 -            addLocalDef(ARGUMENTS.symbolName());
   3.880 -        }
   3.881 -    }
   3.882 -
   3.883 -    private void initCallee(final Block block) {
   3.884 -        final Symbol calleeSymbol = defineSymbol(block, CALLEE.symbolName(), IS_PARAM | IS_INTERNAL, null);
   3.885 -        newType(calleeSymbol, FunctionNode.FUNCTION_TYPE);
   3.886 -        calleeSymbol.setNeedsSlot(true);
   3.887 +    private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags, final Type type) {
   3.888 +        final Symbol symbol = defineSymbol(block, cc.symbolName(), flags);
   3.889 +        newType(symbol, type);
   3.890 +        symbol.setNeedsSlot(true);
   3.891      }
   3.892  
   3.893      /**
   3.894 @@ -1399,19 +1366,28 @@
   3.895       * @param functionNode the function node
   3.896       */
   3.897      private void initParameters(final FunctionNode functionNode, final Block body) {
   3.898 +        int pos = 0;
   3.899          for (final IdentNode param : functionNode.getParameters()) {
   3.900              addLocalDef(param.getName());
   3.901 -            final Symbol paramSymbol = defineSymbol(body, param.getName(), IS_PARAM, param);
   3.902 +
   3.903 +            final Type callSiteParamType = functionNode.getHints().getParameterType(pos);
   3.904 +            int flags = IS_PARAM;
   3.905 +            if (callSiteParamType != null) {
   3.906 +                LOG.info("Param ", param, " has a callsite type ", callSiteParamType, ". Using that.");
   3.907 +                flags |= Symbol.IS_SPECIALIZED_PARAM;
   3.908 +            }
   3.909 +
   3.910 +            final Symbol paramSymbol = defineSymbol(body, param.getName(), flags);
   3.911 +            assert paramSymbol != null;
   3.912 +
   3.913              if (paramSymbol != null) {
   3.914 -                final Type callSiteParamType = functionNode.getSpecializedType(param);
   3.915 -                if (callSiteParamType != null) {
   3.916 -                    LOG.info("Param ", paramSymbol, " has a callsite type ", callSiteParamType, ". Using that.");
   3.917 -                }
   3.918                  newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType);
   3.919              }
   3.920  
   3.921 -            LOG.info("Initialized param ", paramSymbol);
   3.922 +            LOG.info("Initialized param ", pos, "=", paramSymbol);
   3.923 +            pos++;
   3.924          }
   3.925 +
   3.926      }
   3.927  
   3.928      /**
   3.929 @@ -1420,14 +1396,19 @@
   3.930       *
   3.931       * @param functionNode functionNode
   3.932       */
   3.933 -    private static void finalizeParameters(final FunctionNode functionNode) {
   3.934 +    private FunctionNode finalizeParameters(final FunctionNode functionNode) {
   3.935 +        final List<IdentNode> newParams = new ArrayList<>();
   3.936          final boolean isVarArg = functionNode.isVarArg();
   3.937  
   3.938 -        for (final IdentNode ident : functionNode.getParameters()) {
   3.939 -            final Symbol paramSymbol = ident.getSymbol();
   3.940 +        int pos = 0;
   3.941 +        for (final IdentNode param : functionNode.getParameters()) {
   3.942 +            final Symbol paramSymbol = functionNode.getBody().getExistingSymbol(param.getName());
   3.943 +            assert paramSymbol != null;
   3.944 +            assert paramSymbol.isParam();
   3.945 +            newParams.add((IdentNode)param.setSymbol(getLexicalContext(), paramSymbol));
   3.946  
   3.947              assert paramSymbol != null;
   3.948 -            Type type = functionNode.getSpecializedType(ident);
   3.949 +            Type type = functionNode.getHints().getParameterType(pos);
   3.950              if (type == null) {
   3.951                  type = Type.OBJECT;
   3.952              }
   3.953 @@ -1436,7 +1417,7 @@
   3.954              // this function, we can tell the runtime system that no matter what the
   3.955              // call site is, use this information. TODO
   3.956              if (!paramSymbol.getSymbolType().isObject()) {
   3.957 -                LOG.finest("Parameter ", ident, " could profit from specialization to ", paramSymbol.getSymbolType());
   3.958 +                LOG.finest("Parameter ", param, " could profit from specialization to ", paramSymbol.getSymbolType());
   3.959              }
   3.960  
   3.961              newType(paramSymbol, Type.widest(type, paramSymbol.getSymbolType()));
   3.962 @@ -1445,7 +1426,11 @@
   3.963              if (isVarArg) {
   3.964                  paramSymbol.setNeedsSlot(false);
   3.965              }
   3.966 +
   3.967 +            pos++;
   3.968          }
   3.969 +
   3.970 +        return functionNode.setParameters(getLexicalContext(), newParams);
   3.971      }
   3.972  
   3.973      /**
   3.974 @@ -1459,7 +1444,7 @@
   3.975  
   3.976          for (final Property property : map.getProperties()) {
   3.977              final String key    = property.getKey();
   3.978 -            final Symbol symbol = defineSymbol(block, key, IS_GLOBAL, null);
   3.979 +            final Symbol symbol = defineSymbol(block, key, IS_GLOBAL);
   3.980              newType(symbol, Type.OBJECT);
   3.981              LOG.info("Added global symbol from property map ", symbol);
   3.982          }
   3.983 @@ -1498,7 +1483,7 @@
   3.984           * objects as parameters, for example +, but not *, which is known
   3.985           * to coerce types into doubles
   3.986           */
   3.987 -        if (node.getType().isUnknown() || symbol.isParam()) {
   3.988 +        if (node.getType().isUnknown() || (symbol.isParam() && !symbol.isSpecializedParam())) {
   3.989              newType(symbol, Type.OBJECT);
   3.990              symbol.setCanBeUndefined();
   3.991           }
   3.992 @@ -1614,29 +1599,6 @@
   3.993          } while (!changed.isEmpty());
   3.994      }
   3.995  
   3.996 -    /**
   3.997 -     * This assign helper is called after an assignment, when all children of
   3.998 -     * the assign has been processed. It fixes the types and recursively makes
   3.999 -     * sure that everyhing has slots that should have them in the chain.
  3.1000 -     *
  3.1001 -     * @param binaryNode assignment node
  3.1002 -     */
  3.1003 -    private Node leaveAssignmentNode(final BinaryNode binaryNode) {
  3.1004 -        final Node lhs = binaryNode.lhs();
  3.1005 -        final Node rhs = binaryNode.rhs();
  3.1006 -
  3.1007 -        final Type type;
  3.1008 -        if (rhs.getType().isNumeric()) {
  3.1009 -            type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
  3.1010 -        } else {
  3.1011 -            type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too.
  3.1012 -        }
  3.1013 -        ensureSymbol(type, binaryNode);
  3.1014 -        newType(lhs.getSymbol(), type);
  3.1015 -        end(binaryNode);
  3.1016 -        return binaryNode;
  3.1017 -    }
  3.1018 -
  3.1019      private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode) {
  3.1020          return leaveSelfModifyingAssignmentNode(binaryNode, binaryNode.getWidestOperationType());
  3.1021      }
  3.1022 @@ -1646,25 +1608,20 @@
  3.1023          final Node lhs = binaryNode.lhs();
  3.1024  
  3.1025          newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType
  3.1026 -        ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
  3.1027 +//        ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
  3.1028  
  3.1029          ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), binaryNode);
  3.1030  
  3.1031 -        end(binaryNode);
  3.1032 -        return binaryNode;
  3.1033 +        return end(ensureSymbol(destType, binaryNode));
  3.1034      }
  3.1035  
  3.1036 -    private Symbol ensureSymbol(final FunctionNode functionNode, final Type type, final Node node) {
  3.1037 -        LOG.info("New TEMPORARY added to ", functionNode.getName(), " type=", type);
  3.1038 -        return functionNode.ensureSymbol(getLexicalContext().getCurrentBlock(), type, node);
  3.1039 -    }
  3.1040 -
  3.1041 -    private Symbol ensureSymbol(final Type type, final Node node) {
  3.1042 -        return ensureSymbol(getLexicalContext().getCurrentFunction(), type, node);
  3.1043 +    private Node ensureSymbol(final Type type, final Node node) {
  3.1044 +        LOG.info("New TEMPORARY added to ", getLexicalContext().getCurrentFunction().getName(), " type=", type);
  3.1045 +        return Attr.ensureSymbol(getLexicalContext(), getLexicalContext().getCurrentBlock(), type, node);
  3.1046      }
  3.1047  
  3.1048      private Symbol newInternal(final String name, final Type type) {
  3.1049 -        final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL, null);
  3.1050 +        final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL);
  3.1051          iter.setType(type); // NASHORN-73
  3.1052          return iter;
  3.1053      }
  3.1054 @@ -1721,6 +1678,17 @@
  3.1055          localUses.peek().add(name);
  3.1056      }
  3.1057  
  3.1058 +    static Node ensureSymbol(final LexicalContext lc, final Block block, final Type type, final Node node) {
  3.1059 +        Symbol symbol = node.getSymbol();
  3.1060 +        if (symbol != null) {
  3.1061 +            return node;
  3.1062 +        }
  3.1063 +        final String uname = lc.getCurrentFunction().uniqueName(TEMP_PREFIX.symbolName());
  3.1064 +        symbol = new Symbol(uname, IS_TEMP, type);
  3.1065 +        block.putSymbol(lc, symbol);
  3.1066 +        return node.setSymbol(lc, symbol);
  3.1067 +    }
  3.1068 +
  3.1069      /**
  3.1070       * Pessimistically promote all symbols in current function node to Object types
  3.1071       * This is done when the function contains unevaluated black boxes such as
  3.1072 @@ -1731,8 +1699,7 @@
  3.1073      private static void objectifySymbols(final Block body) {
  3.1074          body.accept(new NodeVisitor() {
  3.1075              private void toObject(final Block block) {
  3.1076 -                for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext();) {
  3.1077 -                    final Symbol symbol = iter.next();
  3.1078 +                for (final Symbol symbol : block.getSymbols()) {
  3.1079                      if (!symbol.isTemp()) {
  3.1080                          newType(symbol, Type.OBJECT);
  3.1081                      }
     4.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu May 02 15:01:16 2013 -0300
     4.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri May 03 15:33:54 2013 +0200
     4.3 @@ -568,8 +568,7 @@
     4.4       * @param block block containing symbols.
     4.5       */
     4.6      private void symbolInfo(final Block block) {
     4.7 -        for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
     4.8 -            final Symbol symbol = iter.next();
     4.9 +        for (final Symbol symbol : block.getSymbols()) {
    4.10              if (symbol.hasSlot()) {
    4.11                  method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel());
    4.12              }
    4.13 @@ -937,11 +936,10 @@
    4.14  
    4.15      private static int assignSlots(final Block block, final int firstSlot) {
    4.16          int nextSlot = firstSlot;
    4.17 -        for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
    4.18 -            final Symbol next = iter.next();
    4.19 -            if (next.hasSlot()) {
    4.20 -                next.setSlot(nextSlot);
    4.21 -                nextSlot += next.slotCount();
    4.22 +        for (final Symbol symbol : block.getSymbols()) {
    4.23 +            if (symbol.hasSlot()) {
    4.24 +                symbol.setSlot(nextSlot);
    4.25 +                nextSlot += symbol.slotCount();
    4.26              }
    4.27          }
    4.28          return nextSlot;
    4.29 @@ -1002,10 +1000,7 @@
    4.30  
    4.31              final boolean hasArguments = function.needsArguments();
    4.32  
    4.33 -            final Iterator<Symbol> symbols = block.symbolIterator();
    4.34 -
    4.35 -            while (symbols.hasNext()) {
    4.36 -                final Symbol symbol = symbols.next();
    4.37 +            for (final Symbol symbol : block.getSymbols()) {
    4.38  
    4.39                  if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) {
    4.40                      continue;
    4.41 @@ -1076,12 +1071,7 @@
    4.42                  }
    4.43              }
    4.44  
    4.45 -            final Iterator<Symbol> iter = block.symbolIterator();
    4.46 -            final List<Symbol> symbols = new ArrayList<>();
    4.47 -            while (iter.hasNext()) {
    4.48 -                symbols.add(iter.next());
    4.49 -            }
    4.50 -            initSymbols(symbols);
    4.51 +            initSymbols(block.getSymbols());
    4.52          }
    4.53  
    4.54          // Debugging: print symbols? @see --print-symbols flag
    4.55 @@ -2364,7 +2354,6 @@
    4.56      public boolean enterDISCARD(final UnaryNode unaryNode) {
    4.57          final Node rhs = unaryNode.rhs();
    4.58  
    4.59 -       // System.err.println("**** Enter discard " + unaryNode);
    4.60          discard.push(rhs);
    4.61          load(rhs);
    4.62  
    4.63 @@ -2373,7 +2362,7 @@
    4.64              method.pop();
    4.65              discard.pop();
    4.66          }
    4.67 -       // System.err.println("**** Leave discard " + unaryNode);
    4.68 +
    4.69          return false;
    4.70      }
    4.71  
     5.1 --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Thu May 02 15:01:16 2013 -0300
     5.2 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Fri May 03 15:33:54 2013 +0200
     5.3 @@ -42,7 +42,7 @@
     5.4       */
     5.5      LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) {
     5.6          @Override
     5.7 -        FunctionNode transform(final Compiler compiler, final FunctionNode fn0) {
     5.8 +        FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
     5.9  
    5.10              /*
    5.11               * For lazy compilation, we might be given a node previously marked
    5.12 @@ -58,8 +58,7 @@
    5.13               * function from a trampoline
    5.14               */
    5.15  
    5.16 -            final FunctionNode outermostFunctionNode = compiler.getFunctionNode();
    5.17 -            assert outermostFunctionNode == fn0;
    5.18 +            final FunctionNode outermostFunctionNode = fn;
    5.19  
    5.20              final Set<FunctionNode> neverLazy = new HashSet<>();
    5.21              final Set<FunctionNode> lazy      = new HashSet<>();
    5.22 @@ -172,20 +171,26 @@
    5.23      ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) {
    5.24          @Override
    5.25          FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
    5.26 -            return (FunctionNode)initReturnTypes(fn).accept(new Attr());
    5.27 +            return (FunctionNode)enterAttr(fn).accept(new Attr());
    5.28          }
    5.29  
    5.30          /**
    5.31           * Pessimistically set all lazy functions' return types to Object
    5.32 +         * and the function symbols to object
    5.33           * @param functionNode node where to start iterating
    5.34           */
    5.35 -        private FunctionNode initReturnTypes(final FunctionNode functionNode) {
    5.36 +        private FunctionNode enterAttr(final FunctionNode functionNode) {
    5.37              return (FunctionNode)functionNode.accept(new NodeVisitor() {
    5.38                  @Override
    5.39                  public Node leaveFunctionNode(final FunctionNode node) {
    5.40 -                    return node.isLazy() ?
    5.41 -                           node.setReturnType(getLexicalContext(), Type.OBJECT) :
    5.42 -                           node.setReturnType(getLexicalContext(), Type.UNKNOWN);
    5.43 +                    final LexicalContext lc = getLexicalContext();
    5.44 +                    if (node.isLazy()) {
    5.45 +                        FunctionNode newNode = node.setReturnType(getLexicalContext(), Type.OBJECT);
    5.46 +                        return Attr.ensureSymbol(lc, lc.getCurrentBlock(), Type.OBJECT, newNode);
    5.47 +                    }
    5.48 +                    //node may have a reference here that needs to be nulled if it was referred to by
    5.49 +                    //its outer context, if it is lazy and not attributed
    5.50 +                    return node.setReturnType(lc, Type.UNKNOWN).setSymbol(lc, null);
    5.51                  }
    5.52              });
    5.53          }
    5.54 @@ -207,6 +212,7 @@
    5.55          FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
    5.56              final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName());
    5.57  
    5.58 +//            assert fn.isProgram() ;
    5.59              final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn);
    5.60  
    5.61              assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
    5.62 @@ -216,15 +222,6 @@
    5.63                  compiler.setStrictMode(true);
    5.64              }
    5.65  
    5.66 -            /*
    5.67 -            newFunctionNode.accept(new NodeVisitor() {
    5.68 -                @Override
    5.69 -                public boolean enterFunctionNode(final FunctionNode functionNode) {
    5.70 -                    assert functionNode.getCompileUnit() != null : functionNode.getName() + " " + Debug.id(functionNode) + " has no compile unit";
    5.71 -                    return true;
    5.72 -                }
    5.73 -            });*/
    5.74 -
    5.75              return newFunctionNode;
    5.76          }
    5.77  
     6.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java	Thu May 02 15:01:16 2013 -0300
     6.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Fri May 03 15:33:54 2013 +0200
     6.3 @@ -77,6 +77,8 @@
     6.4      /** Name of the objects package */
     6.5      public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects";
     6.6  
     6.7 +    private Source source;
     6.8 +
     6.9      private final Map<String, byte[]> bytecode;
    6.10  
    6.11      private final Set<CompileUnit> compileUnits;
    6.12 @@ -87,12 +89,10 @@
    6.13  
    6.14      private final ScriptEnvironment env;
    6.15  
    6.16 -    private final String scriptName;
    6.17 +    private String scriptName;
    6.18  
    6.19      private boolean strict;
    6.20  
    6.21 -    private FunctionNode functionNode;
    6.22 -
    6.23      private CodeInstaller<ScriptEnvironment> installer;
    6.24  
    6.25      /** logger for compiler, trampolines, splits and related code generation events
    6.26 @@ -168,6 +168,41 @@
    6.27      }
    6.28  
    6.29      /**
    6.30 +     * Environment information known to the compile, e.g. params
    6.31 +     */
    6.32 +    public static class Hints {
    6.33 +        private final Type[] paramTypes;
    6.34 +
    6.35 +        /** singleton empty hints */
    6.36 +        public static final Hints EMPTY = new Hints();
    6.37 +
    6.38 +        private Hints() {
    6.39 +            this.paramTypes = null;
    6.40 +        }
    6.41 +
    6.42 +        /**
    6.43 +         * Constructor
    6.44 +         * @param paramTypes known parameter types for this callsite
    6.45 +         */
    6.46 +        public Hints(final Type[] paramTypes) {
    6.47 +            this.paramTypes = paramTypes;
    6.48 +        }
    6.49 +
    6.50 +        /**
    6.51 +         * Get the parameter type for this parameter position, or
    6.52 +         * null if now known
    6.53 +         * @param pos position
    6.54 +         * @return parameter type for this callsite if known
    6.55 +         */
    6.56 +        public Type getParameterType(final int pos) {
    6.57 +            if (paramTypes != null && pos < paramTypes.length) {
    6.58 +                return paramTypes[pos];
    6.59 +            }
    6.60 +            return null;
    6.61 +        }
    6.62 +    }
    6.63 +
    6.64 +    /**
    6.65       * Standard (non-lazy) compilation, that basically will take an entire script
    6.66       * and JIT it at once. This can lead to long startup time and fewer type
    6.67       * specializations
    6.68 @@ -207,21 +242,22 @@
    6.69       * @param strict       should this compilation use strict mode semantics
    6.70       */
    6.71      //TODO support an array of FunctionNodes for batch lazy compilation
    6.72 -    Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final CompilationSequence sequence, final boolean strict) {
    6.73 +    Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final CompilationSequence sequence, final boolean strict) {
    6.74          this.env           = env;
    6.75 -        this.functionNode  = functionNode;
    6.76          this.sequence      = sequence;
    6.77          this.installer     = installer;
    6.78 -        this.strict        = strict || functionNode.isStrict();
    6.79          this.constantData  = new ConstantData();
    6.80          this.compileUnits  = new HashSet<>();
    6.81          this.bytecode      = new HashMap<>();
    6.82 +    }
    6.83  
    6.84 +    private void initCompiler(final FunctionNode functionNode) {
    6.85 +        this.strict        = strict || functionNode.isStrict();
    6.86          final StringBuilder sb = new StringBuilder();
    6.87          sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.symbolName() + lazyTag(functionNode))).
    6.88                  append('$').
    6.89                  append(safeSourceName(functionNode.getSource()));
    6.90 -
    6.91 +        this.source = functionNode.getSource();
    6.92          this.scriptName = sb.toString();
    6.93      }
    6.94  
    6.95 @@ -229,52 +265,43 @@
    6.96       * Constructor
    6.97       *
    6.98       * @param installer    code installer
    6.99 -     * @param functionNode function node (in any available {@link CompilationState}) to compile
   6.100       * @param strict       should this compilation use strict mode semantics
   6.101       */
   6.102 -    public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final boolean strict) {
   6.103 -        this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), strict);
   6.104 +    public Compiler(final CodeInstaller<ScriptEnvironment> installer, final boolean strict) {
   6.105 +        this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), strict);
   6.106      }
   6.107  
   6.108      /**
   6.109       * Constructor - compilation will use the same strict semantics as in script environment
   6.110       *
   6.111       * @param installer    code installer
   6.112 -     * @param functionNode function node (in any available {@link CompilationState}) to compile
   6.113       */
   6.114 -    public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode) {
   6.115 -        this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict);
   6.116 +    public Compiler(final CodeInstaller<ScriptEnvironment> installer) {
   6.117 +        this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict);
   6.118      }
   6.119  
   6.120      /**
   6.121       * Constructor - compilation needs no installer, but uses a script environment
   6.122       * Used in "compile only" scenarios
   6.123       * @param env a script environment
   6.124 -     * @param functionNode functionNode to compile
   6.125       */
   6.126 -    public Compiler(final ScriptEnvironment env, final FunctionNode functionNode) {
   6.127 -        this(env, null, functionNode, sequence(env._lazy_compilation), env._strict);
   6.128 +    public Compiler(final ScriptEnvironment env) {
   6.129 +        this(env, null, sequence(env._lazy_compilation), env._strict);
   6.130      }
   6.131  
   6.132      /**
   6.133       * Execute the compilation this Compiler was created with
   6.134 -     * @params param types if known, for specialization
   6.135 +     * @param functionNode function node to compile from its current state
   6.136       * @throws CompilationException if something goes wrong
   6.137       * @return function node that results from code transforms
   6.138       */
   6.139 -    public FunctionNode compile() throws CompilationException {
   6.140 -        return compile(null);
   6.141 -    }
   6.142 +    public FunctionNode compile(final FunctionNode functionNode) throws CompilationException {
   6.143 +        FunctionNode newFunctionNode = functionNode;
   6.144  
   6.145 -    /**
   6.146 -     * Execute the compilation this Compiler was created with
   6.147 -     * @param paramTypes param types if known, for specialization
   6.148 -     * @throws CompilationException if something goes wrong
   6.149 -     * @return function node that results from code transforms
   6.150 -     */
   6.151 -    public FunctionNode compile(final Class<?> paramTypes) throws CompilationException {
   6.152 +        initCompiler(newFunctionNode); //TODO move this state into functionnode?
   6.153 +
   6.154          for (final String reservedName : RESERVED_NAMES) {
   6.155 -            functionNode.uniqueName(reservedName);
   6.156 +            newFunctionNode.uniqueName(reservedName);
   6.157          }
   6.158  
   6.159          final boolean fine = !LOG.levelAbove(Level.FINE);
   6.160 @@ -283,7 +310,7 @@
   6.161          long time = 0L;
   6.162  
   6.163          for (final CompilationPhase phase : sequence) {
   6.164 -            this.functionNode = phase.apply(this, functionNode);
   6.165 +            newFunctionNode = phase.apply(this, newFunctionNode);
   6.166  
   6.167              final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L;
   6.168              time += duration;
   6.169 @@ -293,7 +320,7 @@
   6.170  
   6.171                  sb.append(phase.toString()).
   6.172                      append(" done for function '").
   6.173 -                    append(functionNode.getName()).
   6.174 +                    append(newFunctionNode.getName()).
   6.175                      append('\'');
   6.176  
   6.177                  if (duration > 0L) {
   6.178 @@ -309,7 +336,7 @@
   6.179          if (info) {
   6.180              final StringBuilder sb = new StringBuilder();
   6.181              sb.append("Compile job for '").
   6.182 -                append(functionNode.getName()).
   6.183 +                append(newFunctionNode.getName()).
   6.184                  append("' finished");
   6.185  
   6.186              if (time > 0L) {
   6.187 @@ -321,16 +348,15 @@
   6.188              LOG.info(sb);
   6.189          }
   6.190  
   6.191 -        return functionNode;
   6.192 +        return newFunctionNode;
   6.193      }
   6.194  
   6.195 -    private Class<?> install(final String className, final byte[] code) {
   6.196 +    private Class<?> install(final FunctionNode functionNode, final String className, final byte[] code) {
   6.197          LOG.fine("Installing class ", className);
   6.198  
   6.199          final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
   6.200  
   6.201          try {
   6.202 -            final Source   source    = getSource();
   6.203              final Object[] constants = getConstantData().toArray();
   6.204              // Need doPrivileged because these fields are private
   6.205              AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
   6.206 @@ -355,9 +381,10 @@
   6.207  
   6.208      /**
   6.209       * Install compiled classes into a given loader
   6.210 +     * @param functionNode function node to install - must be in {@link CompilationState#EMITTED} state
   6.211       * @return root script class - if there are several compile units they will also be installed
   6.212       */
   6.213 -    public Class<?> install() {
   6.214 +    public Class<?> install(final FunctionNode functionNode) {
   6.215          final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L;
   6.216  
   6.217          assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed";
   6.218 @@ -366,7 +393,7 @@
   6.219  
   6.220          final String   rootClassName = firstCompileUnitName();
   6.221          final byte[]   rootByteCode  = bytecode.get(rootClassName);
   6.222 -        final Class<?> rootClass     = install(rootClassName, rootByteCode);
   6.223 +        final Class<?> rootClass     = install(functionNode, rootClassName, rootByteCode);
   6.224  
   6.225          int length = rootByteCode.length;
   6.226  
   6.227 @@ -380,7 +407,7 @@
   6.228              final byte[] code = entry.getValue();
   6.229              length += code.length;
   6.230  
   6.231 -            installedClasses.put(className, install(className, code));
   6.232 +            installedClasses.put(className, install(functionNode, className, code));
   6.233          }
   6.234  
   6.235          for (final CompileUnit unit : compileUnits) {
   6.236 @@ -430,10 +457,6 @@
   6.237          this.strict = strict;
   6.238      }
   6.239  
   6.240 -    FunctionNode getFunctionNode() {
   6.241 -        return functionNode;
   6.242 -    }
   6.243 -
   6.244      ConstantData getConstantData() {
   6.245          return constantData;
   6.246      }
   6.247 @@ -442,10 +465,6 @@
   6.248          return installer;
   6.249      }
   6.250  
   6.251 -    Source getSource() {
   6.252 -        return functionNode.getSource();
   6.253 -    }
   6.254 -
   6.255      void addClass(final String name, final byte[] code) {
   6.256          bytecode.put(name, code);
   6.257      }
   6.258 @@ -496,7 +515,7 @@
   6.259      }
   6.260  
   6.261      private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) {
   6.262 -        final ClassEmitter classEmitter = new ClassEmitter(env, functionNode.getSource().getName(), unitClassName, strict);
   6.263 +        final ClassEmitter classEmitter = new ClassEmitter(env, source.getName(), unitClassName, strict);
   6.264          final CompileUnit  compileUnit  = new CompileUnit(unitClassName, classEmitter, initialWeight);
   6.265  
   6.266          classEmitter.begin();
     7.1 --- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Thu May 02 15:01:16 2013 -0300
     7.2 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Fri May 03 15:33:54 2013 +0200
     7.3 @@ -30,7 +30,6 @@
     7.4  
     7.5  import java.util.ArrayList;
     7.6  import java.util.HashSet;
     7.7 -import java.util.Iterator;
     7.8  import java.util.List;
     7.9  import jdk.nashorn.internal.codegen.types.Type;
    7.10  import jdk.nashorn.internal.ir.AccessNode;
    7.11 @@ -354,13 +353,6 @@
    7.12          return true;
    7.13      }
    7.14  
    7.15 -    /*
    7.16 -    @Override
    7.17 -    public Node leaveBlock(final Block block) {
    7.18 -        final LexicalContext lc = getLexicalContext();
    7.19 -        return block;//.setFlag(lc, lc.getFlags(block));
    7.20 -    }*/
    7.21 -
    7.22      @Override
    7.23      public Node leaveCatchNode(final CatchNode catchNode) {
    7.24          final Node exceptionCondition = catchNode.getExceptionCondition();
    7.25 @@ -551,8 +543,7 @@
    7.26          final boolean        allVarsInScope = functionNode.allVarsInScope();
    7.27          final boolean        isVarArg       = functionNode.isVarArg();
    7.28  
    7.29 -        for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
    7.30 -            final Symbol symbol = iter.next();
    7.31 +        for (final Symbol symbol : block.getSymbols()) {
    7.32              if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) {
    7.33                  continue;
    7.34              }
    7.35 @@ -812,14 +803,12 @@
    7.36  
    7.37          LOG.info("CONVERT('", node, "', ", to, ") => '", resultNode, "'");
    7.38  
    7.39 +        assert !node.isTerminal();
    7.40 +
    7.41          final LexicalContext lc = getLexicalContext();
    7.42          //This is the only place in this file that can create new temporaries
    7.43          //FinalizeTypes may not introduce ANY node that is not a conversion.
    7.44 -        lc.getCurrentFunction().ensureSymbol(lc.getCurrentBlock(), to, resultNode);
    7.45 -
    7.46 -        assert !node.isTerminal();
    7.47 -
    7.48 -        return resultNode;
    7.49 +        return Attr.ensureSymbol(lc, lc.getCurrentBlock(), to, resultNode);
    7.50      }
    7.51  
    7.52      private static Node discard(final Node node) {
    7.53 @@ -905,7 +894,7 @@
    7.54  
    7.55              if (literalNode != null) {
    7.56                  //inherit literal symbol for attr.
    7.57 -                literalNode.setSymbol(parent.getSymbol());
    7.58 +                literalNode = (LiteralNode<?>)literalNode.setSymbol(null, parent.getSymbol());
    7.59              }
    7.60  
    7.61              return literalNode;
     8.1 --- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Thu May 02 15:01:16 2013 -0300
     8.2 +++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Fri May 03 15:33:54 2013 +0200
     8.3 @@ -27,7 +27,6 @@
     8.4  
     8.5  import java.util.List;
     8.6  import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_PADDING;
     8.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_ROUNDING;
     8.8  import jdk.nashorn.internal.ir.Symbol;
     8.9  import jdk.nashorn.internal.runtime.Context;
    8.10  import jdk.nashorn.internal.runtime.PropertyMap;
     9.1 --- a/src/jdk/nashorn/internal/codegen/Splitter.java	Thu May 02 15:01:16 2013 -0300
     9.2 +++ b/src/jdk/nashorn/internal/codegen/Splitter.java	Fri May 03 15:33:54 2013 +0200
     9.3 @@ -75,7 +75,7 @@
     9.4       */
     9.5      public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) {
     9.6          this.compiler             = compiler;
     9.7 -        this.outermost = functionNode;
     9.8 +        this.outermost            = functionNode;
     9.9          this.outermostCompileUnit = outermostCompileUnit;
    9.10      }
    9.11  
    9.12 @@ -95,7 +95,7 @@
    9.13          final LexicalContext lc = getLexicalContext();
    9.14  
    9.15          long weight = WeighNodes.weigh(functionNode);
    9.16 -        final boolean top = compiler.getFunctionNode() == outermost;
    9.17 +        final boolean top = fn.isProgram(); //compiler.getFunctionNode() == outermost;
    9.18  
    9.19          if (weight >= SPLIT_THRESHOLD) {
    9.20              LOG.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD);
    9.21 @@ -273,7 +273,9 @@
    9.22              return literal;
    9.23          }
    9.24  
    9.25 -        getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT);
    9.26 +        final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
    9.27 +
    9.28 +        getLexicalContext().setFlag(functionNode, FunctionNode.IS_SPLIT);
    9.29  
    9.30          if (literal instanceof ArrayLiteralNode) {
    9.31              final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
    10.1 --- a/src/jdk/nashorn/internal/ir/Block.java	Thu May 02 15:01:16 2013 -0300
    10.2 +++ b/src/jdk/nashorn/internal/ir/Block.java	Fri May 03 15:33:54 2013 +0200
    10.3 @@ -30,7 +30,6 @@
    10.4  import java.util.Arrays;
    10.5  import java.util.Collections;
    10.6  import java.util.Comparator;
    10.7 -import java.util.Iterator;
    10.8  import java.util.LinkedHashMap;
    10.9  import java.util.List;
   10.10  import java.util.Map;
   10.11 @@ -104,18 +103,26 @@
   10.12          this(source, token, finish, statements.toArray(new Node[statements.size()]));
   10.13      }
   10.14  
   10.15 -    private Block(final Block block, final int finish, final List<Node> statements, final int flags) {
   10.16 +    private Block(final Block block, final int finish, final List<Node> statements, final int flags, final Map<String, Symbol> symbols) {
   10.17          super(block);
   10.18          this.statements = statements;
   10.19          this.flags      = flags;
   10.20 -        this.symbols    = block.symbols; //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
   10.21 +        this.symbols    = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
   10.22          this.entryLabel = new Label(block.entryLabel);
   10.23 -        this.finish = finish;
   10.24 +        this.finish     = finish;
   10.25 +    }
   10.26 +
   10.27 +    /**
   10.28 +     * Clear the symbols in a block
   10.29 +     * TODO: make this immutable
   10.30 +     */
   10.31 +    public void clearSymbols() {
   10.32 +        symbols.clear();
   10.33      }
   10.34  
   10.35      @Override
   10.36      public Node ensureUniqueLabels(final LexicalContext lc) {
   10.37 -        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags));
   10.38 +        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols));
   10.39      }
   10.40  
   10.41      /**
   10.42 @@ -137,15 +144,15 @@
   10.43       * Get an iterator for all the symbols defined in this block
   10.44       * @return symbol iterator
   10.45       */
   10.46 -    public Iterator<Symbol> symbolIterator() {
   10.47 -        return symbols.values().iterator();
   10.48 +    public List<Symbol> getSymbols() {
   10.49 +        return Collections.unmodifiableList(new ArrayList<>(symbols.values()));
   10.50      }
   10.51  
   10.52      /**
   10.53       * Retrieves an existing symbol defined in the current block.
   10.54       * @param name the name of the symbol
   10.55       * @return an existing symbol with the specified name defined in the current block, or null if this block doesn't
   10.56 -     * define a symbol with this name.
   10.57 +     * define a symbol with this name.T
   10.58       */
   10.59      public Symbol getExistingSymbol(final String name) {
   10.60          return symbols.get(name);
   10.61 @@ -241,17 +248,17 @@
   10.62          if (!statements.isEmpty()) {
   10.63              lastFinish = statements.get(statements.size() - 1).getFinish();
   10.64          }
   10.65 -        return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags));
   10.66 +        return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags, symbols));
   10.67      }
   10.68  
   10.69      /**
   10.70       * Add or overwrite an existing symbol in the block
   10.71       *
   10.72 -     * @param name   name of symbol
   10.73 +     * @param lc     get lexical context
   10.74       * @param symbol symbol
   10.75       */
   10.76 -    public void putSymbol(final String name, final Symbol symbol) {
   10.77 -        symbols.put(name, symbol);
   10.78 +    public void putSymbol(final LexicalContext lc, final Symbol symbol) {
   10.79 +        symbols.put(symbol.getName(), symbol);
   10.80      }
   10.81  
   10.82      /**
   10.83 @@ -268,7 +275,7 @@
   10.84          if (this.flags == flags) {
   10.85              return this;
   10.86          }
   10.87 -        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags));
   10.88 +        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols));
   10.89      }
   10.90  
   10.91      @Override
   10.92 @@ -296,7 +303,7 @@
   10.93              return this;
   10.94          }
   10.95  
   10.96 -        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE));
   10.97 +        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE, symbols));
   10.98      }
   10.99  
  10.100      /**
  10.101 @@ -306,13 +313,11 @@
  10.102       * @return next slot
  10.103       */
  10.104      public int nextSlot() {
  10.105 -        final Iterator<Symbol> iter = symbolIterator();
  10.106          int next = 0;
  10.107 -        while (iter.hasNext()) {
  10.108 -        final Symbol symbol = iter.next();
  10.109 -        if (symbol.hasSlot()) {
  10.110 -            next += symbol.slotCount();
  10.111 -        }
  10.112 +        for (final Symbol symbol : getSymbols()) {
  10.113 +            if (symbol.hasSlot()) {
  10.114 +                next += symbol.slotCount();
  10.115 +            }
  10.116          }
  10.117          return next;
  10.118      }
    11.1 --- a/src/jdk/nashorn/internal/ir/CatchNode.java	Thu May 02 15:01:16 2013 -0300
    11.2 +++ b/src/jdk/nashorn/internal/ir/CatchNode.java	Fri May 03 15:33:54 2013 +0200
    11.3 @@ -138,7 +138,12 @@
    11.4          return body;
    11.5      }
    11.6  
    11.7 -    private CatchNode setException(final IdentNode exception) {
    11.8 +    /**
    11.9 +     * Resets the exception of a catch block
   11.10 +     * @param exception new exception
   11.11 +     * @return new catch node if changed, same otherwise
   11.12 +     */
   11.13 +    public CatchNode setException(final IdentNode exception) {
   11.14          if (this.exception == exception) {
   11.15              return this;
   11.16          }
    12.1 --- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Thu May 02 15:01:16 2013 -0300
    12.2 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Fri May 03 15:33:54 2013 +0200
    12.3 @@ -25,16 +25,12 @@
    12.4  
    12.5  package jdk.nashorn.internal.ir;
    12.6  
    12.7 -import static jdk.nashorn.internal.codegen.CompilerConstants.LITERAL_PREFIX;
    12.8 -import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX;
    12.9 -import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT;
   12.10 -import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
   12.11 -
   12.12  import java.util.Collections;
   12.13  import java.util.EnumSet;
   12.14  import java.util.HashSet;
   12.15  import java.util.List;
   12.16  import java.util.Set;
   12.17 +
   12.18  import jdk.nashorn.internal.codegen.CompileUnit;
   12.19  import jdk.nashorn.internal.codegen.Compiler;
   12.20  import jdk.nashorn.internal.codegen.CompilerConstants;
   12.21 @@ -95,6 +91,10 @@
   12.22      @Ignore
   12.23      private final IdentNode ident;
   12.24  
   12.25 +    /** Parsed version of functionNode */
   12.26 +    @Ignore
   12.27 +    private final FunctionNode snapshot;
   12.28 +
   12.29      /** The body of the function node */
   12.30      private final Block body;
   12.31  
   12.32 @@ -127,6 +127,9 @@
   12.33      @Ignore
   12.34      private final EnumSet<CompilationState> compilationState;
   12.35  
   12.36 +    @Ignore
   12.37 +    private final Compiler.Hints hints;
   12.38 +
   12.39      /** Function flags. */
   12.40      private final int flags;
   12.41  
   12.42 @@ -176,6 +179,9 @@
   12.43      /** Does this function have nested declarations? */
   12.44      public static final int HAS_FUNCTION_DECLARATIONS   = 1 << 13;
   12.45  
   12.46 +    /** Can this function be specialized? */
   12.47 +    public static final int CAN_SPECIALIZE              = 1 << 14;
   12.48 +
   12.49      /** Does this function or any nested functions contain an eval? */
   12.50      private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
   12.51  
   12.52 @@ -219,37 +225,52 @@
   12.53          final int flags) {
   12.54          super(source, token, finish);
   12.55  
   12.56 -        this.ident             = ident;
   12.57 -        this.name              = name;
   12.58 -        this.kind              = kind;
   12.59 -        this.parameters        = parameters;
   12.60 -        this.firstToken        = firstToken;
   12.61 -        this.lastToken         = token;
   12.62 -        this.namespace         = namespace;
   12.63 -        this.compilationState  = EnumSet.of(CompilationState.INITIALIZED);
   12.64 -        this.declaredSymbols   = new HashSet<>();
   12.65 -        this.flags             = flags;
   12.66 -        this.compileUnit       = null;
   12.67 -        this.body              = null;
   12.68 +        this.ident            = ident;
   12.69 +        this.name             = name;
   12.70 +        this.kind             = kind;
   12.71 +        this.parameters       = parameters;
   12.72 +        this.firstToken       = firstToken;
   12.73 +        this.lastToken        = token;
   12.74 +        this.namespace        = namespace;
   12.75 +        this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
   12.76 +        this.declaredSymbols  = new HashSet<>();
   12.77 +        this.flags            = flags;
   12.78 +        this.compileUnit      = null;
   12.79 +        this.body             = null;
   12.80 +        this.snapshot         = null;
   12.81 +        this.hints            = null;
   12.82      }
   12.83  
   12.84 -    private FunctionNode(final FunctionNode functionNode, final long lastToken, final int flags, final Type returnType, final CompileUnit compileUnit, final EnumSet<CompilationState> compilationState, final Block body) {
   12.85 +    private FunctionNode(
   12.86 +        final FunctionNode functionNode,
   12.87 +        final long lastToken,
   12.88 +        final int flags,
   12.89 +        final Type returnType,
   12.90 +        final CompileUnit compileUnit,
   12.91 +        final EnumSet<CompilationState> compilationState,
   12.92 +        final Block body,
   12.93 +        final List<IdentNode> parameters,
   12.94 +        final FunctionNode snapshot,
   12.95 +        final Compiler.Hints hints) {
   12.96          super(functionNode);
   12.97 -        this.flags = flags;
   12.98 -        this.returnType = returnType;
   12.99 -        this.compileUnit = compileUnit;
  12.100 -        this.lastToken = lastToken;
  12.101 +
  12.102 +        this.flags            = flags;
  12.103 +        this.returnType       = returnType;
  12.104 +        this.compileUnit      = compileUnit;
  12.105 +        this.lastToken        = lastToken;
  12.106          this.compilationState = compilationState;
  12.107 -        this.body  = body;
  12.108 +        this.body             = body;
  12.109 +        this.parameters       = parameters;
  12.110 +        this.snapshot         = snapshot;
  12.111 +        this.hints            = hints;
  12.112  
  12.113          // the fields below never change - they are final and assigned in constructor
  12.114 -        this.name = functionNode.name;
  12.115 -        this.ident = functionNode.ident;
  12.116 -        this.namespace = functionNode.namespace;
  12.117 +        this.name            = functionNode.name;
  12.118 +        this.ident           = functionNode.ident;
  12.119 +        this.namespace       = functionNode.namespace;
  12.120          this.declaredSymbols = functionNode.declaredSymbols;
  12.121 -        this.kind  = functionNode.kind;
  12.122 -        this.parameters = functionNode.parameters;
  12.123 -        this.firstToken = functionNode.firstToken;
  12.124 +        this.kind            = functionNode.kind;
  12.125 +        this.firstToken      = functionNode.firstToken;
  12.126      }
  12.127  
  12.128      @Override
  12.129 @@ -261,6 +282,36 @@
  12.130      }
  12.131  
  12.132      /**
  12.133 +     * Get the version of this function node's code as it looked upon construction
  12.134 +     * i.e typically parsed and nothing else
  12.135 +     * @return initial version of function node
  12.136 +     */
  12.137 +    public FunctionNode getSnapshot() {
  12.138 +        return snapshot;
  12.139 +    }
  12.140 +
  12.141 +    /**
  12.142 +     * Take a snapshot of this function node at a given point in time
  12.143 +     * and store it in the function node
  12.144 +     * @param lc lexical context
  12.145 +     * @return function node
  12.146 +     */
  12.147 +    public FunctionNode snapshot(final LexicalContext lc) {
  12.148 +        if (this.snapshot == this) {
  12.149 +            return this;
  12.150 +        }
  12.151 +        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, this, hints));
  12.152 +    }
  12.153 +
  12.154 +    /**
  12.155 +     * Can this function node be regenerated with more specific type args?
  12.156 +     * @return true if specialization is possible
  12.157 +     */
  12.158 +    public boolean canSpecialize() {
  12.159 +        return getFlag(CAN_SPECIALIZE);
  12.160 +    }
  12.161 +
  12.162 +    /**
  12.163       * Get the compilation state of this function
  12.164       * @return the compilation state
  12.165       */
  12.166 @@ -307,7 +358,28 @@
  12.167          }
  12.168          final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
  12.169          newState.add(state);
  12.170 -        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body));
  12.171 +        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body, parameters, snapshot, hints));
  12.172 +    }
  12.173 +
  12.174 +    /**
  12.175 +     * Get any compiler hints that may associated with the function
  12.176 +     * @return compiler hints
  12.177 +     */
  12.178 +    public Compiler.Hints getHints() {
  12.179 +        return this.hints == null ? Compiler.Hints.EMPTY : hints;
  12.180 +    }
  12.181 +
  12.182 +    /**
  12.183 +     * Set compiler hints for this function
  12.184 +     * @param lc    lexical context
  12.185 +     * @param hints compiler hints
  12.186 +     * @return new function if hints changed
  12.187 +     */
  12.188 +    public FunctionNode setHints(final LexicalContext lc, final Compiler.Hints hints) {
  12.189 +        if (this.hints == hints) {
  12.190 +            return this;
  12.191 +        }
  12.192 +        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
  12.193      }
  12.194  
  12.195      /**
  12.196 @@ -319,20 +391,6 @@
  12.197          return namespace.uniqueName(base);
  12.198      }
  12.199  
  12.200 -    /**
  12.201 -     * Create a virtual symbol for a literal.
  12.202 -     *
  12.203 -     * @param literalNode Primary node to use symbol.
  12.204 -     *
  12.205 -     * @return Symbol used.
  12.206 -     */
  12.207 -    public Symbol newLiteral(final LiteralNode<?> literalNode) {
  12.208 -        final String uname = uniqueName(LITERAL_PREFIX.symbolName());
  12.209 -        final Symbol symbol = new Symbol(uname, IS_CONSTANT, literalNode.getType());
  12.210 -        literalNode.setSymbol(symbol);
  12.211 -
  12.212 -        return symbol;
  12.213 -    }
  12.214  
  12.215      @Override
  12.216      public void toString(final StringBuilder sb) {
  12.217 @@ -374,7 +432,7 @@
  12.218          if (this.flags == flags) {
  12.219              return this;
  12.220          }
  12.221 -        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
  12.222 +        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
  12.223      }
  12.224  
  12.225      @Override
  12.226 @@ -483,7 +541,7 @@
  12.227          if(this.body == body) {
  12.228              return this;
  12.229          }
  12.230 -        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
  12.231 +        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
  12.232      }
  12.233  
  12.234      /**
  12.235 @@ -551,7 +609,7 @@
  12.236          if (this.lastToken == lastToken) {
  12.237              return this;
  12.238          }
  12.239 -        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
  12.240 +        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
  12.241      }
  12.242  
  12.243      /**
  12.244 @@ -599,13 +657,17 @@
  12.245      }
  12.246  
  12.247      /**
  12.248 -     * Get a specialized type for an identity, if one exists
  12.249 -     * @param node node to check specialized type for
  12.250 -     * @return null if no specialization exists, otherwise type
  12.251 +     * Reset the compile unit used to compile this function
  12.252 +     * @see Compiler
  12.253 +     * @param  lc lexical context
  12.254 +     * @param  parameters the compile unit
  12.255 +     * @return function node or a new one if state was changed
  12.256       */
  12.257 -    @SuppressWarnings("static-method")
  12.258 -    public Type getSpecializedType(final IdentNode node) {
  12.259 -        return null; //TODO implement specialized types later
  12.260 +    public FunctionNode setParameters(final LexicalContext lc, final List<IdentNode> parameters) {
  12.261 +        if (this.parameters == parameters) {
  12.262 +            return this;
  12.263 +        }
  12.264 +        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
  12.265      }
  12.266  
  12.267      /**
  12.268 @@ -674,7 +736,10 @@
  12.269                      returnType),
  12.270                  compileUnit,
  12.271                  compilationState,
  12.272 -                body));
  12.273 +                body,
  12.274 +                parameters,
  12.275 +                snapshot,
  12.276 +                hints));
  12.277      }
  12.278  
  12.279      /**
  12.280 @@ -705,7 +770,7 @@
  12.281          if (this.compileUnit == compileUnit) {
  12.282              return this;
  12.283          }
  12.284 -        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
  12.285 +        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
  12.286      }
  12.287  
  12.288      /**
  12.289 @@ -717,19 +782,6 @@
  12.290       *
  12.291       * @return Symbol used.
  12.292       */
  12.293 -    public Symbol ensureSymbol(final Block block, final Type type, final Node node) {
  12.294 -        Symbol symbol = node.getSymbol();
  12.295 -
  12.296 -        // If no symbol already present.
  12.297 -        if (symbol == null) {
  12.298 -            final String uname = uniqueName(TEMP_PREFIX.symbolName());
  12.299 -            symbol = new Symbol(uname, IS_TEMP, type);
  12.300 -            block.putSymbol(uname, symbol);
  12.301 -            node.setSymbol(symbol);
  12.302 -        }
  12.303 -
  12.304 -        return symbol;
  12.305 -    }
  12.306  
  12.307      /**
  12.308       * Get the symbol for a compiler constant, or null if not available (yet)
    13.1 --- a/src/jdk/nashorn/internal/ir/LexicalContext.java	Thu May 02 15:01:16 2013 -0300
    13.2 +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java	Fri May 03 15:33:54 2013 +0200
    13.3 @@ -64,7 +64,6 @@
    13.4              for (int i = sp - 1; i >= 0; i--) {
    13.5                  if (stack[i] == node) {
    13.6                      flags[i] |= flag;
    13.7 -                    //System.err.println("Setting flag " + node + " " + flag);
    13.8                      return;
    13.9                  }
   13.10              }
   13.11 @@ -117,8 +116,6 @@
   13.12          return (FunctionNode)stack[0];
   13.13      }
   13.14  
   13.15 -
   13.16 -
   13.17      /**
   13.18       * Pushes a new block on top of the context, making it the innermost open block.
   13.19       * @param node the new node
    14.1 --- a/src/jdk/nashorn/internal/ir/LexicalContextNode.java	Thu May 02 15:01:16 2013 -0300
    14.2 +++ b/src/jdk/nashorn/internal/ir/LexicalContextNode.java	Fri May 03 15:33:54 2013 +0200
    14.3 @@ -70,4 +70,16 @@
    14.4          final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor);
    14.5          return lc.pop(newNode);
    14.6      }
    14.7 +
    14.8 +    /**
    14.9 +     * Set the symbol and replace in lexical context if applicable
   14.10 +     * @param lc     lexical context
   14.11 +     * @param symbol symbol
   14.12 +     * @return new node if symbol changed
   14.13 +     */
   14.14 +    @Override
   14.15 +    public Node setSymbol(final LexicalContext lc, final Symbol symbol) {
   14.16 +        return Node.replaceInLexicalContext(lc, this, (LexicalContextNode)super.setSymbol(null, symbol));
   14.17 +    }
   14.18 +
   14.19  }
    15.1 --- a/src/jdk/nashorn/internal/ir/LiteralNode.java	Thu May 02 15:01:16 2013 -0300
    15.2 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java	Fri May 03 15:33:54 2013 +0200
    15.3 @@ -659,9 +659,12 @@
    15.4           * Copy constructor
    15.5           * @param node source array literal node
    15.6           */
    15.7 -        protected ArrayLiteralNode(final ArrayLiteralNode node) {
    15.8 -            super(node);
    15.9 +        private ArrayLiteralNode(final ArrayLiteralNode node, final Node[] value) {
   15.10 +            super(node, value);
   15.11              this.elementType = node.elementType;
   15.12 +            this.presets     = node.presets;
   15.13 +            this.postsets    = node.postsets;
   15.14 +            this.units       = node.units;
   15.15          }
   15.16  
   15.17          /**
   15.18 @@ -750,9 +753,8 @@
   15.19                      break;
   15.20                  }
   15.21  
   15.22 -                final Symbol symbol = node.getSymbol();
   15.23 -                assert symbol != null; //don't run this on unresolved nodes or you are in trouble
   15.24 -                Type symbolType = symbol.getSymbolType();
   15.25 +                assert node.getSymbol() != null; //don't run this on unresolved nodes or you are in trouble
   15.26 +                Type symbolType = node.getSymbol().getSymbolType();
   15.27                  if (symbolType.isUnknown()) {
   15.28                      symbolType = Type.OBJECT;
   15.29                  }
   15.30 @@ -813,7 +815,8 @@
   15.31          }
   15.32  
   15.33          /**
   15.34 -         * Get indices of arrays containing computed post sets
   15.35 +         * Get indices of arrays containing computed post sets. post sets
   15.36 +         * are things like non literals e.g. "x+y" instead of i or 17
   15.37           * @return post set indices
   15.38           */
   15.39          public int[] getPostsets() {
   15.40 @@ -849,17 +852,17 @@
   15.41          @Override
   15.42          public Node accept(final NodeVisitor visitor) {
   15.43              if (visitor.enterLiteralNode(this)) {
   15.44 -                for (int i = 0; i < value.length; i++) {
   15.45 -                    final Node element = value[i];
   15.46 -                    if (element != null) {
   15.47 -                        value[i] = element.accept(visitor);
   15.48 -                    }
   15.49 -                }
   15.50 -                return visitor.leaveLiteralNode(this);
   15.51 +                final List<Node> oldValue = Arrays.asList(value);
   15.52 +                final List<Node> newValue = Node.accept(visitor, Node.class, oldValue);
   15.53 +                return visitor.leaveLiteralNode(oldValue != newValue ? setValue(newValue) : this);
   15.54              }
   15.55              return this;
   15.56          }
   15.57  
   15.58 +        private ArrayLiteralNode setValue(final List<Node> value) {
   15.59 +            return new ArrayLiteralNode(this, value.toArray(new Node[value.size()]));
   15.60 +        }
   15.61 +
   15.62          @Override
   15.63          public void toString(final StringBuilder sb) {
   15.64              sb.append('[');
    16.1 --- a/src/jdk/nashorn/internal/ir/Node.java	Thu May 02 15:01:16 2013 -0300
    16.2 +++ b/src/jdk/nashorn/internal/ir/Node.java	Fri May 03 15:33:54 2013 +0200
    16.3 @@ -252,10 +252,17 @@
    16.4       * Assign a symbol to this node. See {@link Node#getSymbol()} for explanation
    16.5       * of what a symbol is
    16.6       *
    16.7 +     * @param lc lexical context
    16.8       * @param symbol the symbol
    16.9 +     * @return new node
   16.10       */
   16.11 -    public void setSymbol(final Symbol symbol) {
   16.12 -        this.symbol = symbol;
   16.13 +    public Node setSymbol(final LexicalContext lc, final Symbol symbol) {
   16.14 +        if (this.symbol == symbol) {
   16.15 +            return this;
   16.16 +        }
   16.17 +        final Node newNode = (Node)clone();
   16.18 +        newNode.symbol = symbol;
   16.19 +        return newNode;
   16.20      }
   16.21  
   16.22      /**
   16.23 @@ -274,7 +281,7 @@
   16.24          final List<T> newList = new ArrayList<>();
   16.25  
   16.26          for (final Node node : list) {
   16.27 -            final T newNode = clazz.cast(node.accept(visitor));
   16.28 +            final T newNode = node == null ? null : clazz.cast(node.accept(visitor));
   16.29              if (newNode != node) {
   16.30                  changed = true;
   16.31              }
    17.1 --- a/src/jdk/nashorn/internal/ir/Symbol.java	Thu May 02 15:01:16 2013 -0300
    17.2 +++ b/src/jdk/nashorn/internal/ir/Symbol.java	Fri May 03 15:33:54 2013 +0200
    17.3 @@ -67,6 +67,8 @@
    17.4      public static final int IS_INTERNAL      = 1 << 9;
    17.5      /** Is this a function self-reference symbol */
    17.6      public static final int IS_FUNCTION_SELF = 1 << 10;
    17.7 +    /** Is this a specialized param? */
    17.8 +    public static final int IS_SPECIALIZED_PARAM = 1 << 11;
    17.9  
   17.10      /** Null or name identifying symbol. */
   17.11      private final String name;
   17.12 @@ -384,6 +386,15 @@
   17.13      }
   17.14  
   17.15      /**
   17.16 +     * Check if this symbol is a function parameter of known
   17.17 +     * narrowest type
   17.18 +     * @return true if parameter
   17.19 +     */
   17.20 +    public boolean isSpecializedParam() {
   17.21 +        return (flags & IS_SPECIALIZED_PARAM) == IS_SPECIALIZED_PARAM;
   17.22 +    }
   17.23 +
   17.24 +    /**
   17.25       * Check whether this symbol ever has primitive assignments. Conservative
   17.26       * @return true if primitive assignments exist
   17.27       */
    18.1 --- a/src/jdk/nashorn/internal/objects/NativeRegExp.java	Thu May 02 15:01:16 2013 -0300
    18.2 +++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java	Fri May 03 15:33:54 2013 +0200
    18.3 @@ -794,15 +794,15 @@
    18.4  
    18.5          RegExpResult match;
    18.6          final int inputLength = string.length();
    18.7 -        int lastLength = -1;
    18.8 -        int lastIndex = 0;
    18.9 -        int lastLastIndex = 0;
   18.10 +        int splitLastLength = -1;
   18.11 +        int splitLastIndex = 0;
   18.12 +        int splitLastLastIndex = 0;
   18.13  
   18.14 -        while ((match = execSplit(string, lastIndex)) != null) {
   18.15 -            lastIndex = match.getIndex() + match.length();
   18.16 +        while ((match = execSplit(string, splitLastIndex)) != null) {
   18.17 +            splitLastIndex = match.getIndex() + match.length();
   18.18  
   18.19 -            if (lastIndex > lastLastIndex) {
   18.20 -                matches.add(string.substring(lastLastIndex, match.getIndex()));
   18.21 +            if (splitLastIndex > splitLastLastIndex) {
   18.22 +                matches.add(string.substring(splitLastLastIndex, match.getIndex()));
   18.23                  final Object[] groups = match.getGroups();
   18.24                  if (groups.length > 1 && match.getIndex() < inputLength) {
   18.25                      for (int index = 1; index < groups.length && matches.size() < limit; index++) {
   18.26 @@ -810,7 +810,7 @@
   18.27                      }
   18.28                  }
   18.29  
   18.30 -                lastLength = match.length();
   18.31 +                splitLastLength = match.length();
   18.32  
   18.33                  if (matches.size() >= limit) {
   18.34                      break;
   18.35 @@ -818,10 +818,10 @@
   18.36              }
   18.37  
   18.38              // bump the index to avoid infinite loop
   18.39 -            if (lastIndex == lastLastIndex) {
   18.40 -                lastIndex++;
   18.41 +            if (splitLastIndex == splitLastLastIndex) {
   18.42 +                splitLastIndex++;
   18.43              } else {
   18.44 -                lastLastIndex = lastIndex;
   18.45 +                splitLastLastIndex = splitLastIndex;
   18.46              }
   18.47          }
   18.48  
   18.49 @@ -829,12 +829,12 @@
   18.50              // check special case if we need to append an empty string at the
   18.51              // end of the match
   18.52              // if the lastIndex was the entire string
   18.53 -            if (lastLastIndex == string.length()) {
   18.54 -                if (lastLength > 0 || execSplit("", 0) == null) {
   18.55 +            if (splitLastLastIndex == string.length()) {
   18.56 +                if (splitLastLength > 0 || execSplit("", 0) == null) {
   18.57                      matches.add("");
   18.58                  }
   18.59              } else {
   18.60 -                matches.add(string.substring(lastLastIndex, inputLength));
   18.61 +                matches.add(string.substring(splitLastLastIndex, inputLength));
   18.62              }
   18.63          }
   18.64  
   18.65 @@ -899,10 +899,6 @@
   18.66          }
   18.67      }
   18.68  
   18.69 -    private void setGlobal(final boolean global) {
   18.70 -        regexp.setGlobal(global);
   18.71 -    }
   18.72 -
   18.73      boolean getGlobal() {
   18.74          return regexp.isGlobal();
   18.75      }
    19.1 --- a/src/jdk/nashorn/internal/parser/AbstractParser.java	Thu May 02 15:01:16 2013 -0300
    19.2 +++ b/src/jdk/nashorn/internal/parser/AbstractParser.java	Fri May 03 15:33:54 2013 +0200
    19.3 @@ -249,6 +249,7 @@
    19.4       *
    19.5       * @param errorType  The error type of the warning
    19.6       * @param message    Warning message.
    19.7 +     * @param errorToken error token
    19.8       */
    19.9      protected final void warning(final JSErrorType errorType, final String message, final long errorToken) {
   19.10          errors.warning(error(errorType, message, errorToken));
    20.1 --- a/src/jdk/nashorn/internal/parser/Parser.java	Thu May 02 15:01:16 2013 -0300
    20.2 +++ b/src/jdk/nashorn/internal/parser/Parser.java	Fri May 03 15:33:54 2013 +0200
    20.3 @@ -305,6 +305,11 @@
    20.4          if (isStrictMode) {
    20.5              flags |= FunctionNode.IS_STRICT;
    20.6          }
    20.7 +        if (env._specialize_calls != null) {
    20.8 +            if (env._specialize_calls.contains(name)) {
    20.9 +                flags |= FunctionNode.CAN_SPECIALIZE;
   20.10 +            }
   20.11 +        }
   20.12  
   20.13          // Start new block.
   20.14          FunctionNode functionNode =
   20.15 @@ -320,11 +325,11 @@
   20.16                  kind,
   20.17                  flags);
   20.18  
   20.19 -        functionNode = functionNode.setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
   20.20          lc.push(functionNode);
   20.21          // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
   20.22          // FunctionNode.
   20.23          newBlock();
   20.24 +
   20.25          return functionNode;
   20.26      }
   20.27  
   20.28 @@ -332,14 +337,19 @@
   20.29       * Restore the current block.
   20.30       */
   20.31      private Block restoreBlock(final Block block) {
   20.32 -        return lc.pop(block);//.setFlag(lc, flags);
   20.33 +        return lc.pop(block);
   20.34      }
   20.35  
   20.36 +
   20.37      private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
   20.38          final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
   20.39  
   20.40 -        return lc.pop(functionNode).setBody(lc, newBody).setLastToken(lc, lastToken);
   20.41 -    }
   20.42 +        return lc.pop(functionNode).
   20.43 +            setBody(lc, newBody).
   20.44 +            setLastToken(lc, lastToken).
   20.45 +            setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED).
   20.46 +            snapshot(lc);
   20.47 +        }
   20.48  
   20.49      /**
   20.50       * Get the statements in a block.
   20.51 @@ -529,6 +539,7 @@
   20.52  
   20.53          script = restoreFunctionNode(script, token); //commit code
   20.54          script = script.setBody(lc, script.getBody().setNeedsScope(lc));
   20.55 +
   20.56          return script;
   20.57      }
   20.58  
   20.59 @@ -800,7 +811,6 @@
   20.60       * @param ident         Identifier that is verified
   20.61       * @param contextString String used in error message to give context to the user
   20.62       */
   20.63 -    @SuppressWarnings("fallthrough")
   20.64      private void verifyStrictIdent(final IdentNode ident, final String contextString) {
   20.65          if (isStrictMode) {
   20.66              switch (ident.getName()) {
    21.1 --- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Thu May 02 15:01:16 2013 -0300
    21.2 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Fri May 03 15:33:54 2013 +0200
    21.3 @@ -88,7 +88,7 @@
    21.4  
    21.5          int weight = Type.typeFor(type.returnType()).getWeight();
    21.6          for (final Class<?> paramType : type.parameterArray()) {
    21.7 -            final int pweight = Type.typeFor(paramType).getWeight();
    21.8 +            final int pweight = Type.typeFor(paramType).getWeight() * 2; //params are more important than call types as return values are always specialized
    21.9              weight += pweight;
   21.10          }
   21.11          return weight;
    22.1 --- a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java	Thu May 02 15:01:16 2013 -0300
    22.2 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java	Fri May 03 15:33:54 2013 +0200
    22.3 @@ -69,5 +69,4 @@
    22.4          return best(type).moreGenericThan(type);
    22.5      }
    22.6  
    22.7 -
    22.8  }
    23.1 --- a/src/jdk/nashorn/internal/runtime/Context.java	Thu May 02 15:01:16 2013 -0300
    23.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java	Fri May 03 15:33:54 2013 +0200
    23.3 @@ -411,7 +411,7 @@
    23.4          return ScriptRuntime.apply(func, evalThis);
    23.5      }
    23.6  
    23.7 -    private Source loadInternal(final String srcStr, final String prefix, final String resourcePath) {
    23.8 +    private static Source loadInternal(final String srcStr, final String prefix, final String resourcePath) {
    23.9          if (srcStr.startsWith(prefix)) {
   23.10              final String resource = resourcePath + srcStr.substring(prefix.length());
   23.11              // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme
   23.12 @@ -759,10 +759,10 @@
   23.13          final CodeSource   cs     = url == null ? null : new CodeSource(url, (CodeSigner[])null);
   23.14          final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
   23.15  
   23.16 -        final Compiler compiler = new Compiler(installer, functionNode, strict);
   23.17 +        final Compiler compiler = new Compiler(installer, strict);
   23.18  
   23.19 -        compiler.compile();
   23.20 -        script = compiler.install();
   23.21 +        final FunctionNode newFunctionNode = compiler.compile(functionNode);
   23.22 +        script = compiler.install(newFunctionNode);
   23.23  
   23.24          if (global != null) {
   23.25              global.cacheClass(source, script);
    24.1 --- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Thu May 02 15:01:16 2013 -0300
    24.2 +++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Fri May 03 15:33:54 2013 +0200
    24.3 @@ -25,8 +25,6 @@
    24.4  
    24.5  package jdk.nashorn.internal.runtime;
    24.6  
    24.7 -import static jdk.nashorn.internal.runtime.ScriptObject.isArray;
    24.8 -
    24.9  import java.lang.invoke.MethodHandle;
   24.10  import java.util.Iterator;
   24.11  import java.util.List;
    25.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu May 02 15:01:16 2013 -0300
    25.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Fri May 03 15:33:54 2013 +0200
    25.3 @@ -30,9 +30,12 @@
    25.4  import java.lang.invoke.MethodHandle;
    25.5  import java.lang.invoke.MethodHandles;
    25.6  import java.lang.invoke.MethodType;
    25.7 +import java.util.LinkedList;
    25.8 +
    25.9  import jdk.nashorn.internal.codegen.Compiler;
   25.10  import jdk.nashorn.internal.codegen.CompilerConstants;
   25.11  import jdk.nashorn.internal.codegen.FunctionSignature;
   25.12 +import jdk.nashorn.internal.codegen.types.Type;
   25.13  import jdk.nashorn.internal.ir.FunctionNode;
   25.14  import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
   25.15  import jdk.nashorn.internal.parser.Token;
   25.16 @@ -148,10 +151,10 @@
   25.17  
   25.18           if (functionNode.isLazy()) {
   25.19               Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
   25.20 -             final Compiler compiler = new Compiler(installer, functionNode);
   25.21 -             functionNode = compiler.compile();
   25.22 +             final Compiler compiler = new Compiler(installer);
   25.23 +             functionNode = compiler.compile(functionNode);
   25.24               assert !functionNode.isLazy();
   25.25 -             compiler.install();
   25.26 +             compiler.install(functionNode);
   25.27  
   25.28               // we don't need to update any flags - varArgs and needsCallee are instrincic
   25.29               // in the function world we need to get a destination node from the compile instead
   25.30 @@ -164,23 +167,114 @@
   25.31           assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
   25.32  
   25.33           // code exists - look it up and add it into the automatically sorted invoker list
   25.34 -         code.add(
   25.35 -            new CompiledFunction(
   25.36 -                MH.findStatic(
   25.37 +         addCode(functionNode, null, null);
   25.38 +    }
   25.39 +
   25.40 +    private MethodHandle addCode(final FunctionNode fn, final MethodHandle guard, final MethodHandle fallback) {
   25.41 +        final MethodHandle target =
   25.42 +            MH.findStatic(
   25.43                      LOOKUP,
   25.44 -                    functionNode.getCompileUnit().getCode(),
   25.45 -                    functionNode.getName(),
   25.46 -                    new FunctionSignature(functionNode).
   25.47 -                        getMethodType())));
   25.48 +                    fn.getCompileUnit().getCode(),
   25.49 +                    fn.getName(),
   25.50 +                    new FunctionSignature(fn).
   25.51 +                        getMethodType());
   25.52 +        MethodHandle mh = target;
   25.53 +        if (guard != null) {
   25.54 +            try {
   25.55 +                mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback);
   25.56 +            } catch (Throwable e) {
   25.57 +                e.printStackTrace();
   25.58 +            }
   25.59 +        }
   25.60 +
   25.61 +        final CompiledFunction cf = new CompiledFunction(mh);
   25.62 +        code.add(cf);
   25.63 +
   25.64 +        return cf.getInvoker();
   25.65      }
   25.66  
   25.67 +    private static Type runtimeType(final Object arg) {
   25.68 +        if (arg == null) {
   25.69 +            return Type.OBJECT;
   25.70 +        }
   25.71 +
   25.72 +        final Class<?> clazz = arg.getClass();
   25.73 +        assert !clazz.isPrimitive() : "always boxed";
   25.74 +        if (clazz == Double.class) {
   25.75 +            return JSType.isRepresentableAsInt((double)arg) ? Type.INT : Type.NUMBER;
   25.76 +        } else if (clazz == Integer.class) {
   25.77 +            return Type.INT;
   25.78 +        } else if (clazz == Long.class) {
   25.79 +            return Type.LONG;
   25.80 +        } else if (clazz == String.class) {
   25.81 +            return Type.STRING;
   25.82 +        }
   25.83 +        return Type.OBJECT;
   25.84 +    }
   25.85 +
   25.86 +    @SuppressWarnings("unused")
   25.87 +    private static boolean paramTypeGuard(final Type[] compileTimeTypes, final Type[] runtimeTypes, Object... args) {
   25.88 +        //System.err.println("Param type guard " + Arrays.asList(args));
   25.89 +        return false;
   25.90 +    }
   25.91 +
   25.92 +    private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Type[].class, Object[].class);
   25.93 +
   25.94      @Override
   25.95      MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
   25.96          final MethodHandle mh = super.getBestInvoker(callSiteType, args);
   25.97 -        if (code.isLessSpecificThan(callSiteType)) {
   25.98 -            // opportunity for code specialization - we can regenerate a better version of this method
   25.99 +
  25.100 +        if (!functionNode.canSpecialize() || !code.isLessSpecificThan(callSiteType)) {
  25.101 +            return mh;
  25.102          }
  25.103 -        return mh;
  25.104 +
  25.105 +        final FunctionNode snapshot = functionNode.getSnapshot();
  25.106 +        int i;
  25.107 +
  25.108 +        //classes known at runtime
  25.109 +        final LinkedList<Type> runtimeArgs = new LinkedList<>();
  25.110 +        for (i = args.length - 1; i >= args.length - snapshot.getParameters().size(); i--) {
  25.111 +            runtimeArgs.addLast(runtimeType(args[i]));
  25.112 +        }
  25.113 +
  25.114 +        //classes known at compile time
  25.115 +        final LinkedList<Type> compileTimeArgs = new LinkedList<>();
  25.116 +        for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) {
  25.117 +            compileTimeArgs.addLast(Type.typeFor(callSiteType.parameterType(i)));
  25.118 +        }
  25.119 +
  25.120 +        //the classes known at compile time are a safe to generate as primitives without parameter guards
  25.121 +        //the classes known at runtime are safe to generate as primitives IFF there are parameter guards
  25.122 +        MethodHandle guard = null;
  25.123 +        for (i = 0; i < compileTimeArgs.size(); i++) {
  25.124 +            final Type runtimeType = runtimeArgs.get(i);
  25.125 +            final Type compileType = compileTimeArgs.get(i);
  25.126 +
  25.127 +            if (compileType.isObject() && !runtimeType.isObject()) {
  25.128 +                if (guard == null) {
  25.129 +                    guard = PARAM_TYPE_GUARD;
  25.130 +                    guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()]));
  25.131 +                }
  25.132 +            }
  25.133 +        }
  25.134 +
  25.135 +        //System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs);
  25.136 +
  25.137 +        assert snapshot != null;
  25.138 +        assert snapshot != functionNode;
  25.139 +
  25.140 +        final Compiler compiler = new Compiler(installer);
  25.141 +        final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()]))));
  25.142 +
  25.143 +        compiler.install(compiledSnapshot);
  25.144 +
  25.145 +        final MethodHandle nmh = addCode(compiledSnapshot, guard, mh);
  25.146 +
  25.147 +        return nmh;
  25.148 +    }
  25.149 +
  25.150 +    private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
  25.151 +        return MH.findStatic(MethodHandles.lookup(), RecompilableScriptFunctionData.class, name, MH.type(rtype, types));
  25.152      }
  25.153  
  25.154  }
    26.1 --- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Thu May 02 15:01:16 2013 -0300
    26.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Fri May 03 15:33:54 2013 +0200
    26.3 @@ -26,9 +26,13 @@
    26.4  package jdk.nashorn.internal.runtime;
    26.5  
    26.6  import java.io.PrintWriter;
    26.7 +import java.util.HashSet;
    26.8  import java.util.List;
    26.9  import java.util.Locale;
   26.10 +import java.util.Set;
   26.11 +import java.util.StringTokenizer;
   26.12  import java.util.TimeZone;
   26.13 +
   26.14  import jdk.nashorn.internal.codegen.Namespace;
   26.15  import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
   26.16  import jdk.nashorn.internal.runtime.options.KeyValueOption;
   26.17 @@ -151,6 +155,9 @@
   26.18      /** is this environment in scripting mode? */
   26.19      public final boolean _scripting;
   26.20  
   26.21 +    /** is the JIT allowed to specializ calls based on callsite types? */
   26.22 +    public final Set<String> _specialize_calls;
   26.23 +
   26.24      /** is this environment in strict mode? */
   26.25      public final boolean _strict;
   26.26  
   26.27 @@ -213,6 +220,17 @@
   26.28          _version              = options.getBoolean("version");
   26.29          _verify_code          = options.getBoolean("verify.code");
   26.30  
   26.31 +        final String specialize = options.getString("specialize.calls");
   26.32 +        if (specialize == null) {
   26.33 +            _specialize_calls = null;
   26.34 +        } else {
   26.35 +            _specialize_calls = new HashSet<>();
   26.36 +            final StringTokenizer st = new StringTokenizer(specialize, ",");
   26.37 +            while (st.hasMoreElements()) {
   26.38 +                _specialize_calls.add(st.nextToken());
   26.39 +            }
   26.40 +        }
   26.41 +
   26.42          int callSiteFlags = 0;
   26.43          if (options.getBoolean("profile.callsites")) {
   26.44              callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE;
   26.45 @@ -247,6 +265,18 @@
   26.46      }
   26.47  
   26.48      /**
   26.49 +     * Can we specialize a particular method name?
   26.50 +     * @param functionName method name
   26.51 +     * @return true if we are allowed to generate versions of this method
   26.52 +     */
   26.53 +    public boolean canSpecialize(final String functionName) {
   26.54 +        if (_specialize_calls == null) {
   26.55 +            return false;
   26.56 +        }
   26.57 +        return _specialize_calls.isEmpty() || _specialize_calls.contains(functionName);
   26.58 +    }
   26.59 +
   26.60 +    /**
   26.61       * Get the output stream for this environment
   26.62       * @return output print writer
   26.63       */
    27.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu May 02 15:01:16 2013 -0300
    27.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Fri May 03 15:33:54 2013 +0200
    27.3 @@ -662,9 +662,9 @@
    27.4          }
    27.5  
    27.6          if (deep) {
    27.7 -            final ScriptObject proto = getProto();
    27.8 -            if(proto != null) {
    27.9 -                return proto.findProperty(key, deep, stopOnNonScope, start);
   27.10 +            final ScriptObject myProto = getProto();
   27.11 +            if (myProto != null) {
   27.12 +                return myProto.findProperty(key, deep, stopOnNonScope, start);
   27.13              }
   27.14          }
   27.15  
    28.1 --- a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java	Thu May 02 15:01:16 2013 -0300
    28.2 +++ b/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java	Fri May 03 15:33:54 2013 +0200
    28.3 @@ -107,16 +107,16 @@
    28.4  
    28.5      class DefaultMatcher implements RegExpMatcher {
    28.6          final String input;
    28.7 -        final Matcher matcher;
    28.8 +        final Matcher defaultMatcher;
    28.9  
   28.10          DefaultMatcher(final String input) {
   28.11              this.input = input;
   28.12 -            this.matcher = pattern.matcher(input);
   28.13 +            this.defaultMatcher = pattern.matcher(input);
   28.14          }
   28.15  
   28.16          @Override
   28.17          public boolean search(final int start) {
   28.18 -            return matcher.find(start);
   28.19 +            return defaultMatcher.find(start);
   28.20          }
   28.21  
   28.22          @Override
   28.23 @@ -126,37 +126,37 @@
   28.24  
   28.25          @Override
   28.26          public int start() {
   28.27 -            return matcher.start();
   28.28 +            return defaultMatcher.start();
   28.29          }
   28.30  
   28.31          @Override
   28.32          public int start(final int group) {
   28.33 -            return matcher.start(group);
   28.34 +            return defaultMatcher.start(group);
   28.35          }
   28.36  
   28.37          @Override
   28.38          public int end() {
   28.39 -            return matcher.end();
   28.40 +            return defaultMatcher.end();
   28.41          }
   28.42  
   28.43          @Override
   28.44          public int end(final int group) {
   28.45 -            return matcher.end(group);
   28.46 +            return defaultMatcher.end(group);
   28.47          }
   28.48  
   28.49          @Override
   28.50          public String group() {
   28.51 -            return matcher.group();
   28.52 +            return defaultMatcher.group();
   28.53          }
   28.54  
   28.55          @Override
   28.56          public String group(final int group) {
   28.57 -            return matcher.group(group);
   28.58 +            return defaultMatcher.group(group);
   28.59          }
   28.60  
   28.61          @Override
   28.62          public int groupCount() {
   28.63 -            return matcher.groupCount();
   28.64 +            return defaultMatcher.groupCount();
   28.65          }
   28.66      }
   28.67  
    29.1 --- a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java	Thu May 02 15:01:16 2013 -0300
    29.2 +++ b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java	Fri May 03 15:33:54 2013 +0200
    29.3 @@ -121,16 +121,16 @@
    29.4  
    29.5      class JoniMatcher implements RegExpMatcher {
    29.6          final String input;
    29.7 -        final Matcher matcher;
    29.8 +        final Matcher joniMatcher;
    29.9  
   29.10          JoniMatcher(final String input) {
   29.11              this.input = input;
   29.12 -            this.matcher = regex.matcher(input.toCharArray());
   29.13 +            this.joniMatcher = regex.matcher(input.toCharArray());
   29.14          }
   29.15  
   29.16          @Override
   29.17          public boolean search(final int start) {
   29.18 -            return matcher.search(start, input.length(), Option.NONE) > -1;
   29.19 +            return joniMatcher.search(start, input.length(), Option.NONE) > -1;
   29.20          }
   29.21  
   29.22          @Override
   29.23 @@ -140,27 +140,27 @@
   29.24  
   29.25          @Override
   29.26          public int start() {
   29.27 -            return matcher.getBegin();
   29.28 +            return joniMatcher.getBegin();
   29.29          }
   29.30  
   29.31          @Override
   29.32          public int start(final int group) {
   29.33 -            return group == 0 ? start() : matcher.getRegion().beg[group];
   29.34 +            return group == 0 ? start() : joniMatcher.getRegion().beg[group];
   29.35          }
   29.36  
   29.37          @Override
   29.38          public int end() {
   29.39 -            return matcher.getEnd();
   29.40 +            return joniMatcher.getEnd();
   29.41          }
   29.42  
   29.43          @Override
   29.44          public int end(final int group) {
   29.45 -            return group == 0 ? end() : matcher.getRegion().end[group];
   29.46 +            return group == 0 ? end() : joniMatcher.getRegion().end[group];
   29.47          }
   29.48  
   29.49          @Override
   29.50          public String group() {
   29.51 -            return input.substring(matcher.getBegin(), matcher.getEnd());
   29.52 +            return input.substring(joniMatcher.getBegin(), joniMatcher.getEnd());
   29.53          }
   29.54  
   29.55          @Override
   29.56 @@ -168,13 +168,13 @@
   29.57              if (group == 0) {
   29.58                  return group();
   29.59              }
   29.60 -            final Region region = matcher.getRegion();
   29.61 +            final Region region = joniMatcher.getRegion();
   29.62              return input.substring(region.beg[group], region.end[group]);
   29.63          }
   29.64  
   29.65          @Override
   29.66          public int groupCount() {
   29.67 -            final Region region = matcher.getRegion();
   29.68 +            final Region region = joniMatcher.getRegion();
   29.69              return region == null ? 0 : region.numRegs - 1;
   29.70          }
   29.71      }
    30.1 --- a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java	Thu May 02 15:01:16 2013 -0300
    30.2 +++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java	Fri May 03 15:33:54 2013 +0200
    30.3 @@ -934,7 +934,7 @@
    30.4          return true;
    30.5      }
    30.6  
    30.7 -    private void unicode(final int value, final StringBuilder buffer) {
    30.8 +    private static void unicode(final int value, final StringBuilder buffer) {
    30.9          final String hex = Integer.toHexString(value);
   30.10          buffer.append('u');
   30.11          for (int i = 0; i < 4 - hex.length(); i++) {
   30.12 @@ -944,7 +944,7 @@
   30.13      }
   30.14  
   30.15      // Convert what would have been a backreference into a unicode escape, or a number literal, or both.
   30.16 -    private void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) {
   30.17 +    private static void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) {
   30.18          final int length = numberLiteral.length();
   30.19          int octalValue = 0;
   30.20          int pos = 0;
    31.1 --- a/src/jdk/nashorn/internal/runtime/resources/Options.properties	Thu May 02 15:01:16 2013 -0300
    31.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties	Fri May 03 15:33:54 2013 +0200
    31.3 @@ -288,12 +288,12 @@
    31.4      dependency="--anon-functions=true"  \
    31.5  }
    31.6  
    31.7 -nashorn.option.timezone = {                    \
    31.8 -    name="-timezone",                          \
    31.9 -    short_name="-t",                           \
   31.10 -    params="<timezone>",                       \
   31.11 -    desc="Set timezone for script execution.", \
   31.12 -    type=TimeZone                              \
   31.13 +nashorn.option.specialize.calls = {                                                \
   31.14 +    name="--specialize-calls",                                                     \
   31.15 +    is_undocumented=true,                                                          \
   31.16 +    type=String,                                                                   \
   31.17 +    params="[=function_1,...,function_n]",                                         \
   31.18 +    desc="Specialize all or a set of method according to callsite parameter types" \
   31.19  }
   31.20  
   31.21  nashorn.option.stdout = {                                               \
   31.22 @@ -312,6 +312,14 @@
   31.23      desc="Redirect stderr to a filename or to another tty, e.g. stdout" \
   31.24  }
   31.25  
   31.26 +nashorn.option.timezone = {                    \
   31.27 +    name="-timezone",                          \
   31.28 +    short_name="-t",                           \
   31.29 +    params="<timezone>",                       \
   31.30 +    desc="Set timezone for script execution.", \
   31.31 +    type=TimeZone                              \
   31.32 +}
   31.33 +
   31.34  nashorn.option.trace.callsites = {                                              \
   31.35      name="--trace-callsites",                                                   \
   31.36      short_name="-tcs",                                                          \
    32.1 --- a/src/jdk/nashorn/tools/Shell.java	Thu May 02 15:01:16 2013 -0300
    32.2 +++ b/src/jdk/nashorn/tools/Shell.java	Fri May 03 15:33:54 2013 +0200
    32.3 @@ -270,7 +270,7 @@
    32.4                  }
    32.5  
    32.6                  //null - pass no code installer - this is compile only
    32.7 -                new Compiler(env, functionNode).compile();
    32.8 +                new Compiler(env).compile(functionNode);
    32.9              }
   32.10          } finally {
   32.11              env.getOut().flush();
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/test/script/basic/paramspec.js	Fri May 03 15:33:54 2013 +0200
    33.3 @@ -0,0 +1,38 @@
    33.4 +/*
    33.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
    33.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    33.7 + * 
    33.8 + * This code is free software; you can redistribute it and/or modify it
    33.9 + * under the terms of the GNU General Public License version 2 only, as
   33.10 + * published by the Free Software Foundation.
   33.11 + * 
   33.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   33.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   33.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   33.15 + * version 2 for more details (a copy is included in the LICENSE file that
   33.16 + * accompanied this code).
   33.17 + * 
   33.18 + * You should have received a copy of the GNU General Public License version
   33.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   33.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   33.21 + * 
   33.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   33.23 + * or visit www.oracle.com if you need additional information or have any
   33.24 + * questions.
   33.25 + */
   33.26 +
   33.27 +/**
   33.28 + * paramspec - test that Attr doesn't break parameters when specializing
   33.29 + *
   33.30 + * @run
   33.31 + * @test
   33.32 + */
   33.33 +
   33.34 +function f(a) {
   33.35 +    var b = ~a;
   33.36 +    return b == ~17;
   33.37 +}
   33.38 +
   33.39 +print(f("17"));
   33.40 +print(f(17));
   33.41 +
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/test/script/basic/paramspec.js.EXPECTED	Fri May 03 15:33:54 2013 +0200
    34.3 @@ -0,0 +1,2 @@
    34.4 +true
    34.5 +true
    35.1 --- a/test/script/basic/runsunspider.js	Thu May 02 15:01:16 2013 -0300
    35.2 +++ b/test/script/basic/runsunspider.js	Fri May 03 15:33:54 2013 +0200
    35.3 @@ -86,7 +86,7 @@
    35.4  	    changed = true;
    35.5  	}
    35.6      } catch (e) {
    35.7 -	print("error: " + e);
    35.8 +	print("error: " + e.printStackTrace());
    35.9  	if (e.toString().indexOf(tests) == 1) {
   35.10  	    throw e;
   35.11  	}
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/test/script/currently-failing/logcoverage.js	Fri May 03 15:33:54 2013 +0200
    36.3 @@ -0,0 +1,109 @@
    36.4 +/*
    36.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
    36.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    36.7 + * 
    36.8 + * This code is free software; you can redistribute it and/or modify it
    36.9 + * under the terms of the GNU General Public License version 2 only, as
   36.10 + * published by the Free Software Foundation.
   36.11 + * 
   36.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   36.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   36.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   36.15 + * version 2 for more details (a copy is included in the LICENSE file that
   36.16 + * accompanied this code).
   36.17 + * 
   36.18 + * You should have received a copy of the GNU General Public License version
   36.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   36.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   36.21 + * 
   36.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   36.23 + * or visit www.oracle.com if you need additional information or have any
   36.24 + * questions.
   36.25 + */
   36.26 +
   36.27 +/**
   36.28 + * mh_coverage.js
   36.29 + * Screen scrape various logs to ensure that we cover enough functionality, 
   36.30 + * e.g. method handle instrumentation
   36.31 + *
   36.32 + * @test
   36.33 + * @run
   36.34 + */
   36.35 +
   36.36 +/*
   36.37 + * creates new script engine initialized with given options and
   36.38 + * runs given code on it. Returns standard output captured.
   36.39 + */
   36.40 +
   36.41 +function runScriptEngine(opts, name) {
   36.42 +    var imports = new JavaImporter(
   36.43 +        Packages.jdk.nashorn.api.scripting,
   36.44 +        java.io, java.lang, java.util);
   36.45 +
   36.46 +    with(imports) {
   36.47 +        var fac = new NashornScriptEngineFactory();
   36.48 +        // get current System.err
   36.49 +        var oldErr = System.err;
   36.50 +	var oldOut = System.out;
   36.51 +        var baosErr = new ByteArrayOutputStream();
   36.52 +        var newErr = new PrintStream(baosErr);
   36.53 +        var baosOut = new ByteArrayOutputStream();
   36.54 +	var newOut = new PrintStream(baosOut);
   36.55 +        try {
   36.56 +            // set new standard err
   36.57 +            System.setErr(newErr);
   36.58 +            System.setOut(newOut);
   36.59 +            var strType = Java.type("java.lang.String");
   36.60 +            var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType));
   36.61 +	    var reader = new java.io.FileReader(name);
   36.62 +            engine.eval(reader);
   36.63 +            newErr.flush();
   36.64 +	    newOut.flush();
   36.65 +            return new java.lang.String(baosErr.toByteArray());
   36.66 +        } finally {
   36.67 +            // restore System.err to old value
   36.68 +            System.setErr(oldErr);
   36.69 +	    System.setOut(oldOut);
   36.70 +        }
   36.71 +    }
   36.72 +}
   36.73 +
   36.74 +var str;
   36.75 +
   36.76 +var methodsCalled = [
   36.77 +   'asCollector', 
   36.78 +   'asType', 
   36.79 +   'bindTo', 
   36.80 +   'dropArguments', 
   36.81 +   'explicitCastArguments', 
   36.82 +   'filterArguments', 
   36.83 +   'filterReturnValue', 
   36.84 +   'findStatic', 
   36.85 +   'findVirtual',  
   36.86 +   'foldArguments', 
   36.87 +   'getter', 
   36.88 +   'guardWithTest', 
   36.89 +   'insertArguments', 
   36.90 +   'methodType', 
   36.91 +   'setter'
   36.92 +];
   36.93 +
   36.94 +function check(str, strs) {
   36.95 +    for each (s in strs) {
   36.96 +       if (str.indexOf(s) !== -1) {
   36.97 +	   continue;
   36.98 +       }
   36.99 +       print(s + " not found");
  36.100 +       return;
  36.101 +    }
  36.102 +    print("check ok!");
  36.103 +}
  36.104 +
  36.105 +str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js");
  36.106 +str += runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/varargs.js");
  36.107 +
  36.108 +check(str, methodsCalled);
  36.109 +check(str, ['return', 'get', 'set', '[fields]']);
  36.110 +check(str, ['codegen']);
  36.111 +
  36.112 +print("hello, world!");
    37.1 --- a/test/script/trusted/logcoverage.js	Thu May 02 15:01:16 2013 -0300
    37.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.3 @@ -1,108 +0,0 @@
    37.4 -/*
    37.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
    37.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    37.7 - * 
    37.8 - * This code is free software; you can redistribute it and/or modify it
    37.9 - * under the terms of the GNU General Public License version 2 only, as
   37.10 - * published by the Free Software Foundation.
   37.11 - * 
   37.12 - * This code is distributed in the hope that it will be useful, but WITHOUT
   37.13 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   37.14 - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   37.15 - * version 2 for more details (a copy is included in the LICENSE file that
   37.16 - * accompanied this code).
   37.17 - * 
   37.18 - * You should have received a copy of the GNU General Public License version
   37.19 - * 2 along with this work; if not, write to the Free Software Foundation,
   37.20 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   37.21 - * 
   37.22 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   37.23 - * or visit www.oracle.com if you need additional information or have any
   37.24 - * questions.
   37.25 - */
   37.26 -
   37.27 -/**
   37.28 - * mh_coverage.js
   37.29 - * Screen scrape various logs to ensure that we cover enough functionality, 
   37.30 - * e.g. method handle instrumentation
   37.31 - *
   37.32 - * @test
   37.33 - * @run
   37.34 - */
   37.35 -
   37.36 -/*
   37.37 - * creates new script engine initialized with given options and
   37.38 - * runs given code on it. Returns standard output captured.
   37.39 - */
   37.40 -
   37.41 -function runScriptEngine(opts, name) {
   37.42 -    var imports = new JavaImporter(
   37.43 -        Packages.jdk.nashorn.api.scripting,
   37.44 -        java.io, java.lang, java.util);
   37.45 -
   37.46 -    with(imports) {
   37.47 -        var fac = new NashornScriptEngineFactory();
   37.48 -        // get current System.err
   37.49 -        var oldErr = System.err;
   37.50 -	var oldOut = System.out;
   37.51 -        var baosErr = new ByteArrayOutputStream();
   37.52 -        var newErr = new PrintStream(baosErr);
   37.53 -        var baosOut = new ByteArrayOutputStream();
   37.54 -	var newOut = new PrintStream(baosOut);
   37.55 -        try {
   37.56 -            // set new standard err
   37.57 -            System.setErr(newErr);
   37.58 -            System.setOut(newOut);
   37.59 -            var strType = Java.type("java.lang.String");
   37.60 -            var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType));
   37.61 -	    var reader = new java.io.FileReader(name);
   37.62 -            engine.eval(reader);
   37.63 -            newErr.flush();
   37.64 -	    newOut.flush();
   37.65 -            return new java.lang.String(baosErr.toByteArray());
   37.66 -        } finally {
   37.67 -            // restore System.err to old value
   37.68 -            System.setErr(oldErr);
   37.69 -	    System.setOut(oldOut);
   37.70 -        }
   37.71 -    }
   37.72 -}
   37.73 -
   37.74 -var str;
   37.75 -
   37.76 -var methodsCalled = [
   37.77 -   'asCollector', 
   37.78 -   'asType', 
   37.79 -   'bindTo', 
   37.80 -   'dropArguments', 
   37.81 -   'explicitCastArguments', 
   37.82 -   'filterArguments', 
   37.83 -   'filterReturnValue', 
   37.84 -   'findStatic', 
   37.85 -   'findVirtual',  
   37.86 -   'foldArguments', 
   37.87 -   'getter', 
   37.88 -   'guardWithTest', 
   37.89 -   'insertArguments', 
   37.90 -   'methodType', 
   37.91 -   'setter'
   37.92 -];
   37.93 -
   37.94 -function check(str, strs) {
   37.95 -    for each (s in strs) {
   37.96 -       if (s.indexOf(str) !== -1) {
   37.97 -	   continue;
   37.98 -       }
   37.99 -       print(method + "not found");
  37.100 -       return;
  37.101 -    }
  37.102 -    print("check ok!");
  37.103 -}
  37.104 -
  37.105 -str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js");
  37.106 -
  37.107 -check(str, methodsCalled);
  37.108 -check(str, ['return', 'get', 'set', '[fields]']);
  37.109 -check(str, ['codegen']);
  37.110 -
  37.111 -print("hello, world!");

mercurial