8006069: Range analysis first iteration, runtime specializations

Mon, 20 May 2013 16:38:38 +0200

author
lagergren
date
Mon, 20 May 2013 16:38:38 +0200
changeset 277
92164a5742db
parent 276
1d5a8f1f416e
child 278
b558e19d5de5

8006069: Range analysis first iteration, runtime specializations
Reviewed-by: jlaskey, sundar

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/CompilerConstants.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/MethodEmitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/RangeAnalyzer.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/types/Range.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/types/Type.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/BinaryNode.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/Node.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Symbol.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/CompiledFunction.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.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/ScriptFunctionData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/resources/Options.properties file | annotate | diff | comparison | revisions
test/script/basic/ranges_disabled.js file | annotate | diff | comparison | revisions
test/script/basic/ranges_disabled.js.EXPECTED file | annotate | diff | comparison | revisions
test/script/basic/ranges_enabled.js file | annotate | diff | comparison | revisions
test/script/basic/ranges_enabled.js.EXPECTED file | annotate | diff | comparison | revisions
test/script/basic/ranges_payload.js file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Fri May 17 16:44:22 2013 -0300
     1.2 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Mon May 20 16:38:38 2013 +0200
     1.3 @@ -11,13 +11,21 @@
     1.4  import java.io.File;
     1.5  import java.io.FileOutputStream;
     1.6  import java.io.IOException;
     1.7 +import java.util.ArrayDeque;
     1.8 +import java.util.ArrayList;
     1.9 +import java.util.Deque;
    1.10  import java.util.EnumSet;
    1.11  import java.util.HashSet;
    1.12 +import java.util.List;
    1.13  import java.util.Set;
    1.14 +
    1.15 +import jdk.nashorn.internal.codegen.types.Range;
    1.16  import jdk.nashorn.internal.codegen.types.Type;
    1.17  import jdk.nashorn.internal.ir.Block;
    1.18  import jdk.nashorn.internal.ir.CallNode;
    1.19  import jdk.nashorn.internal.ir.FunctionNode;
    1.20 +import jdk.nashorn.internal.ir.ReturnNode;
    1.21 +import jdk.nashorn.internal.ir.Symbol;
    1.22  import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    1.23  import jdk.nashorn.internal.ir.LexicalContext;
    1.24  import jdk.nashorn.internal.ir.Node;
    1.25 @@ -174,7 +182,7 @@
    1.26          FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
    1.27              final TemporarySymbols ts = compiler.getTemporarySymbols();
    1.28              final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(ts));
    1.29 -            if(compiler.getEnv()._print_mem_usage) {
    1.30 +            if (compiler.getEnv()._print_mem_usage) {
    1.31                  Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount());
    1.32              }
    1.33              return newFunctionNode;
    1.34 @@ -208,6 +216,89 @@
    1.35      },
    1.36  
    1.37      /*
    1.38 +     * Range analysis
    1.39 +     *    Conservatively prove that certain variables can be narrower than
    1.40 +     *    the most generic number type
    1.41 +     */
    1.42 +    RANGE_ANALYSIS_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR)) {
    1.43 +        @Override
    1.44 +        FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
    1.45 +            if (!compiler.getEnv()._range_analysis) {
    1.46 +                return fn;
    1.47 +            }
    1.48 +
    1.49 +            FunctionNode newFunctionNode = (FunctionNode)fn.accept(new RangeAnalyzer());
    1.50 +            final List<ReturnNode> returns = new ArrayList<>();
    1.51 +
    1.52 +            newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor() {
    1.53 +                private final Deque<ArrayList<ReturnNode>> returnStack = new ArrayDeque<>();
    1.54 +
    1.55 +                @Override
    1.56 +                public boolean enterFunctionNode(final FunctionNode functionNode) {
    1.57 +                    returnStack.push(new ArrayList<ReturnNode>());
    1.58 +                    return true;
    1.59 +                }
    1.60 +
    1.61 +                @Override
    1.62 +                public Node leaveFunctionNode(final FunctionNode functionNode) {
    1.63 +                    Type returnType = Type.UNKNOWN;
    1.64 +                    for (final ReturnNode ret : returnStack.pop()) {
    1.65 +                        if (ret.getExpression() == null) {
    1.66 +                            returnType = Type.OBJECT;
    1.67 +                            break;
    1.68 +                        }
    1.69 +                        returnType = Type.widest(returnType, ret.getExpression().getType());
    1.70 +                    }
    1.71 +                    return functionNode.setReturnType(getLexicalContext(), returnType);
    1.72 +                }
    1.73 +
    1.74 +                @Override
    1.75 +                public Node leaveReturnNode(final ReturnNode returnNode) {
    1.76 +                    final ReturnNode result = (ReturnNode)leaveDefault(returnNode);
    1.77 +                    returns.add(result);
    1.78 +                    return result;
    1.79 +                }
    1.80 +
    1.81 +                @Override
    1.82 +                public Node leaveDefault(final Node node) {
    1.83 +                    final Symbol symbol = node.getSymbol();
    1.84 +                    if (symbol != null) {
    1.85 +                        final Range range  = symbol.getRange();
    1.86 +                        final Type  symbolType = symbol.getSymbolType();
    1.87 +                        if (!symbolType.isNumeric()) {
    1.88 +                            return node;
    1.89 +                        }
    1.90 +                        final Type  rangeType  = range.getType();
    1.91 +                        if (!Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range
    1.92 +                            RangeAnalyzer.LOG.info("[", getLexicalContext().getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange());
    1.93 +                            return node.setSymbol(getLexicalContext(), symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols()));
    1.94 +                        }
    1.95 +                    }
    1.96 +                    return node;
    1.97 +                }
    1.98 +            });
    1.99 +
   1.100 +            Type returnType = Type.UNKNOWN;
   1.101 +            for (final ReturnNode node : returns) {
   1.102 +                if (node.getExpression() != null) {
   1.103 +                    returnType = Type.widest(returnType, node.getExpression().getType());
   1.104 +                } else {
   1.105 +                    returnType = Type.OBJECT;
   1.106 +                    break;
   1.107 +                }
   1.108 +            }
   1.109 +
   1.110 +            return newFunctionNode.setReturnType(null, returnType);
   1.111 +        }
   1.112 +
   1.113 +        @Override
   1.114 +        public String toString() {
   1.115 +            return "[Range Analysis]";
   1.116 +        }
   1.117 +    },
   1.118 +
   1.119 +
   1.120 +    /*
   1.121       * Splitter Split the AST into several compile units based on a size
   1.122       * heuristic Splitter needs attributed AST for weight calculations (e.g. is
   1.123       * a + b a ScriptRuntime.ADD with call overhead or a dadd with much less).
   1.124 @@ -218,7 +309,6 @@
   1.125          FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
   1.126              final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName());
   1.127  
   1.128 -//            assert fn.isProgram() ;
   1.129              final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn);
   1.130  
   1.131              assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
     2.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java	Fri May 17 16:44:22 2013 -0300
     2.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Mon May 20 16:38:38 2013 +0200
     2.3 @@ -99,7 +99,7 @@
     2.4  
     2.5      private boolean strict;
     2.6  
     2.7 -    private CodeInstaller<ScriptEnvironment> installer;
     2.8 +    private final CodeInstaller<ScriptEnvironment> installer;
     2.9  
    2.10      private final TemporarySymbols temporarySymbols = new TemporarySymbols();
    2.11  
    2.12 @@ -219,6 +219,7 @@
    2.13          CompilationPhase.CONSTANT_FOLDING_PHASE,
    2.14          CompilationPhase.LOWERING_PHASE,
    2.15          CompilationPhase.ATTRIBUTION_PHASE,
    2.16 +        CompilationPhase.RANGE_ANALYSIS_PHASE,
    2.17          CompilationPhase.SPLITTING_PHASE,
    2.18          CompilationPhase.TYPE_FINALIZATION_PHASE,
    2.19          CompilationPhase.BYTECODE_GENERATION_PHASE);
    2.20 @@ -384,6 +385,8 @@
    2.21          if (info) {
    2.22              final StringBuilder sb = new StringBuilder();
    2.23              sb.append("Compile job for '").
    2.24 +                append(newFunctionNode.getSource()).
    2.25 +                append(':').
    2.26                  append(newFunctionNode.getName()).
    2.27                  append("' finished");
    2.28  
    2.29 @@ -487,7 +490,7 @@
    2.30          }
    2.31  
    2.32          if (sb != null) {
    2.33 -            LOG.info(sb);
    2.34 +            LOG.fine(sb);
    2.35          }
    2.36  
    2.37          return rootClass;
     3.1 --- a/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Fri May 17 16:44:22 2013 -0300
     3.2 +++ b/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Mon May 20 16:38:38 2013 +0200
     3.3 @@ -262,7 +262,7 @@
     3.4       * @return the internal descriptor for this type
     3.5       */
     3.6      public static String typeDescriptor(final Class<?> clazz) {
     3.7 -        return Type.getDescriptor(clazz);
     3.8 +        return Type.typeFor(clazz).getDescriptor();
     3.9      }
    3.10  
    3.11      /**
     4.1 --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Fri May 17 16:44:22 2013 -0300
     4.2 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Mon May 20 16:38:38 2013 +0200
     4.3 @@ -2081,7 +2081,9 @@
     4.4       * @param args debug information to print
     4.5       */
     4.6      private void debug(final Object... args) {
     4.7 -        debug(30, args);
     4.8 +        if (DEBUG) {
     4.9 +            debug(30, args);
    4.10 +        }
    4.11      }
    4.12  
    4.13      /**
    4.14 @@ -2091,7 +2093,9 @@
    4.15       * @param args debug information to print
    4.16       */
    4.17      private void debug_label(final Object... args) {
    4.18 -        debug(26, args);
    4.19 +        if (DEBUG) {
    4.20 +            debug(22, args);
    4.21 +        }
    4.22      }
    4.23  
    4.24      private void debug(final int padConstant, final Object... args) {
    4.25 @@ -2164,7 +2168,6 @@
    4.26                      new Throwable().printStackTrace(LOG.getOutputStream());
    4.27                  }
    4.28              }
    4.29 -
    4.30          }
    4.31      }
    4.32  
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java	Mon May 20 16:38:38 2013 +0200
     5.3 @@ -0,0 +1,474 @@
     5.4 +/*
     5.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.  Oracle designates this
    5.11 + * particular file as subject to the "Classpath" exception as provided
    5.12 + * by Oracle in the LICENSE file that accompanied this code.
    5.13 + *
    5.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.17 + * version 2 for more details (a copy is included in the LICENSE file that
    5.18 + * accompanied this code).
    5.19 + *
    5.20 + * You should have received a copy of the GNU General Public License version
    5.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.23 + *
    5.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.25 + * or visit www.oracle.com if you need additional information or have any
    5.26 + * questions.
    5.27 + */
    5.28 +
    5.29 +package jdk.nashorn.internal.codegen;
    5.30 +
    5.31 +import java.util.HashMap;
    5.32 +import java.util.HashSet;
    5.33 +import java.util.Map;
    5.34 +
    5.35 +import jdk.nashorn.internal.codegen.types.Range;
    5.36 +import jdk.nashorn.internal.codegen.types.Type;
    5.37 +import jdk.nashorn.internal.ir.Assignment;
    5.38 +import jdk.nashorn.internal.ir.BinaryNode;
    5.39 +import jdk.nashorn.internal.ir.ForNode;
    5.40 +import jdk.nashorn.internal.ir.IdentNode;
    5.41 +import jdk.nashorn.internal.ir.LiteralNode;
    5.42 +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
    5.43 +import jdk.nashorn.internal.ir.LoopNode;
    5.44 +import jdk.nashorn.internal.ir.Node;
    5.45 +import jdk.nashorn.internal.ir.RuntimeNode;
    5.46 +import jdk.nashorn.internal.ir.Symbol;
    5.47 +import jdk.nashorn.internal.ir.UnaryNode;
    5.48 +import jdk.nashorn.internal.ir.VarNode;
    5.49 +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
    5.50 +import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    5.51 +import jdk.nashorn.internal.parser.TokenType;
    5.52 +import jdk.nashorn.internal.runtime.DebugLogger;
    5.53 +
    5.54 +/**
    5.55 + * Range analysis and narrowing of type where it can be proven
    5.56 + * that there is no spillover, e.g.
    5.57 + *
    5.58 + *  function func(c) {
    5.59 + *    var v = c & 0xfff;
    5.60 + *    var w = c & 0xeee;
    5.61 + *    var x = v * w;
    5.62 + *    return x;
    5.63 + *  }
    5.64 + *
    5.65 + *  Proves that the multiplication never exceeds 24 bits and can thus be an int
    5.66 + */
    5.67 +final class RangeAnalyzer extends NodeOperatorVisitor {
    5.68 +    static final DebugLogger LOG = new DebugLogger("ranges");
    5.69 +
    5.70 +    private static final Range.Functionality RANGE = new Range.Functionality(LOG);
    5.71 +
    5.72 +    private final Map<LoopNode, Symbol> loopCounters = new HashMap<>();
    5.73 +
    5.74 +    RangeAnalyzer() {
    5.75 +    }
    5.76 +
    5.77 +    @Override
    5.78 +    public boolean enterForNode(final ForNode forNode) {
    5.79 +        //conservatively attempt to identify the loop counter. Null means that it wasn't
    5.80 +        //properly identified and that no optimizations can be made with it - its range is
    5.81 +        //simply unknown in that case, if it is assigned in the loop
    5.82 +        final Symbol counter = findLoopCounter(forNode);
    5.83 +        LOG.fine("Entering forNode " + forNode + " counter = " + counter);
    5.84 +        if (counter != null && !assignedInLoop(forNode,  counter)) {
    5.85 +            loopCounters.put(forNode, counter);
    5.86 +        }
    5.87 +        return true;
    5.88 +    }
    5.89 +
    5.90 +    //destination visited
    5.91 +    private Symbol setRange(final Node dest, final Range range) {
    5.92 +        if (range.isUnknown()) {
    5.93 +            return null;
    5.94 +        }
    5.95 +
    5.96 +        final Symbol symbol = dest.getSymbol();
    5.97 +        assert symbol != null : dest + " " + dest.getClass() + " has no symbol";
    5.98 +        assert symbol.getRange() != null : symbol + " has no range";
    5.99 +        final Range symRange = RANGE.join(symbol.getRange(), range);
   5.100 +
   5.101 +        //anything assigned in the loop, not being the safe loop counter(s) invalidates its entire range
   5.102 +        if (getLexicalContext().inLoop() && !isLoopCounter(getLexicalContext().getCurrentLoop(), symbol)) {
   5.103 +            symbol.setRange(Range.createGenericRange());
   5.104 +            return symbol;
   5.105 +        }
   5.106 +
   5.107 +        if (!symRange.equals(symbol.getRange())) {
   5.108 +            LOG.fine("Modify range for " + dest + " " + symbol + " from " + symbol.getRange() + " to " + symRange + " (in node = " + dest + ")" );
   5.109 +            symbol.setRange(symRange);
   5.110 +        }
   5.111 +
   5.112 +        return null;
   5.113 +    }
   5.114 +
   5.115 +    @Override
   5.116 +    public Node leaveADD(final BinaryNode node) {
   5.117 +        setRange(node, RANGE.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.118 +        return node;
   5.119 +    }
   5.120 +
   5.121 +    @Override
   5.122 +    public Node leaveSUB(final BinaryNode node) {
   5.123 +        setRange(node, RANGE.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.124 +        return node;
   5.125 +    }
   5.126 +
   5.127 +    @Override
   5.128 +    public Node leaveMUL(final BinaryNode node) {
   5.129 +        setRange(node, RANGE.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.130 +        return node;
   5.131 +    }
   5.132 +
   5.133 +    @Override
   5.134 +    public Node leaveDIV(final BinaryNode node) {
   5.135 +        setRange(node, RANGE.div(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.136 +        return node;
   5.137 +    }
   5.138 +
   5.139 +    @Override
   5.140 +    public Node leaveMOD(final BinaryNode node) {
   5.141 +        setRange(node, RANGE.mod(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.142 +        return node;
   5.143 +    }
   5.144 +
   5.145 +    @Override
   5.146 +    public Node leaveBIT_AND(final BinaryNode node) {
   5.147 +        setRange(node, RANGE.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.148 +        return node;
   5.149 +    }
   5.150 +
   5.151 +    @Override
   5.152 +    public Node leaveBIT_OR(final BinaryNode node) {
   5.153 +        setRange(node, RANGE.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.154 +        return node;
   5.155 +    }
   5.156 +
   5.157 +    @Override
   5.158 +    public Node leaveBIT_XOR(final BinaryNode node) {
   5.159 +        setRange(node, RANGE.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.160 +        return node;
   5.161 +    }
   5.162 +
   5.163 +    @Override
   5.164 +    public Node leaveSAR(final BinaryNode node) {
   5.165 +        setRange(node, RANGE.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.166 +        return node;
   5.167 +    }
   5.168 +
   5.169 +    @Override
   5.170 +    public Node leaveSHL(final BinaryNode node) {
   5.171 +        setRange(node, RANGE.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.172 +        return node;
   5.173 +    }
   5.174 +
   5.175 +    @Override
   5.176 +    public Node leaveSHR(final BinaryNode node) {
   5.177 +        setRange(node, RANGE.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.178 +        return node;
   5.179 +    }
   5.180 +
   5.181 +    private Node leaveCmp(final BinaryNode node) {
   5.182 +        setRange(node, Range.createTypeRange(Type.BOOLEAN));
   5.183 +        return node;
   5.184 +    }
   5.185 +
   5.186 +    @Override
   5.187 +    public Node leaveEQ(final BinaryNode node) {
   5.188 +        return leaveCmp(node);
   5.189 +    }
   5.190 +
   5.191 +    @Override
   5.192 +    public Node leaveEQ_STRICT(final BinaryNode node) {
   5.193 +        return leaveCmp(node);
   5.194 +    }
   5.195 +
   5.196 +    @Override
   5.197 +    public Node leaveNE(final BinaryNode node) {
   5.198 +        return leaveCmp(node);
   5.199 +    }
   5.200 +
   5.201 +    @Override
   5.202 +    public Node leaveNE_STRICT(final BinaryNode node) {
   5.203 +        return leaveCmp(node);
   5.204 +    }
   5.205 +
   5.206 +    @Override
   5.207 +    public Node leaveLT(final BinaryNode node) {
   5.208 +        return leaveCmp(node);
   5.209 +    }
   5.210 +
   5.211 +    @Override
   5.212 +    public Node leaveLE(final BinaryNode node) {
   5.213 +        return leaveCmp(node);
   5.214 +    }
   5.215 +
   5.216 +    @Override
   5.217 +    public Node leaveGT(final BinaryNode node) {
   5.218 +        return leaveCmp(node);
   5.219 +    }
   5.220 +
   5.221 +    @Override
   5.222 +    public Node leaveGE(final BinaryNode node) {
   5.223 +        return leaveCmp(node);
   5.224 +    }
   5.225 +
   5.226 +    @Override
   5.227 +    public Node leaveASSIGN(final BinaryNode node) {
   5.228 +        Range range = node.rhs().getSymbol().getRange();
   5.229 +        if (range.isUnknown()) {
   5.230 +            range = Range.createGenericRange();
   5.231 +        }
   5.232 +
   5.233 +        setRange(node.lhs(), range);
   5.234 +        setRange(node, range);
   5.235 +
   5.236 +        return node;
   5.237 +    }
   5.238 +
   5.239 +    private Node leaveSelfModifyingAssign(final BinaryNode node, final Range range) {
   5.240 +        setRange(node.lhs(), range);
   5.241 +        setRange(node, range);
   5.242 +        return node;
   5.243 +    }
   5.244 +
   5.245 +    private Node leaveSelfModifyingAssign(final UnaryNode node, final Range range) {
   5.246 +        setRange(node.rhs(), range);
   5.247 +        setRange(node, range);
   5.248 +        return node;
   5.249 +    }
   5.250 +
   5.251 +    @Override
   5.252 +    public Node leaveASSIGN_ADD(final BinaryNode node) {
   5.253 +        return leaveSelfModifyingAssign(node, RANGE.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.254 +    }
   5.255 +
   5.256 +    @Override
   5.257 +    public Node leaveASSIGN_SUB(final BinaryNode node) {
   5.258 +        return leaveSelfModifyingAssign(node, RANGE.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.259 +    }
   5.260 +
   5.261 +    @Override
   5.262 +    public Node leaveASSIGN_MUL(final BinaryNode node) {
   5.263 +        return leaveSelfModifyingAssign(node, RANGE.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.264 +    }
   5.265 +
   5.266 +    @Override
   5.267 +    public Node leaveASSIGN_DIV(final BinaryNode node) {
   5.268 +        return leaveSelfModifyingAssign(node, Range.createTypeRange(Type.NUMBER));
   5.269 +    }
   5.270 +
   5.271 +    @Override
   5.272 +    public Node leaveASSIGN_MOD(final BinaryNode node) {
   5.273 +        return leaveSelfModifyingAssign(node, Range.createTypeRange(Type.NUMBER));
   5.274 +    }
   5.275 +
   5.276 +    @Override
   5.277 +    public Node leaveASSIGN_BIT_AND(final BinaryNode node) {
   5.278 +        return leaveSelfModifyingAssign(node, RANGE.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.279 +    }
   5.280 +
   5.281 +    @Override
   5.282 +    public Node leaveASSIGN_BIT_OR(final BinaryNode node) {
   5.283 +        return leaveSelfModifyingAssign(node, RANGE.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.284 +    }
   5.285 +
   5.286 +    @Override
   5.287 +    public Node leaveASSIGN_BIT_XOR(final BinaryNode node) {
   5.288 +        return leaveSelfModifyingAssign(node, RANGE.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.289 +    }
   5.290 +
   5.291 +    @Override
   5.292 +    public Node leaveASSIGN_SAR(final BinaryNode node) {
   5.293 +        return leaveSelfModifyingAssign(node, RANGE.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.294 +    }
   5.295 +
   5.296 +    @Override
   5.297 +    public Node leaveASSIGN_SHR(final BinaryNode node) {
   5.298 +        return leaveSelfModifyingAssign(node, RANGE.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.299 +    }
   5.300 +
   5.301 +    @Override
   5.302 +    public Node leaveASSIGN_SHL(final BinaryNode node) {
   5.303 +        return leaveSelfModifyingAssign(node, RANGE.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange()));
   5.304 +    }
   5.305 +
   5.306 +    @Override
   5.307 +    public Node leaveDECINC(final UnaryNode node) {
   5.308 +        switch (node.tokenType()) {
   5.309 +        case DECPREFIX:
   5.310 +        case DECPOSTFIX:
   5.311 +            return leaveSelfModifyingAssign(node, RANGE.sub(node.rhs().getSymbol().getRange(), Range.createRange(1)));
   5.312 +        case INCPREFIX:
   5.313 +        case INCPOSTFIX:
   5.314 +            return leaveSelfModifyingAssign(node, RANGE.add(node.rhs().getSymbol().getRange(), Range.createRange(1)));
   5.315 +        default:
   5.316 +            assert false;
   5.317 +            return node;
   5.318 +        }
   5.319 +    }
   5.320 +
   5.321 +    @Override
   5.322 +    public Node leaveADD(final UnaryNode node) {
   5.323 +        Range range = node.rhs().getSymbol().getRange();
   5.324 +        if (!range.getType().isNumeric()) {
   5.325 +           range = Range.createTypeRange(Type.NUMBER);
   5.326 +        }
   5.327 +        setRange(node, range);
   5.328 +        return node;
   5.329 +    }
   5.330 +
   5.331 +    @Override
   5.332 +    public Node leaveBIT_NOT(final UnaryNode node) {
   5.333 +        setRange(node, Range.createTypeRange(Type.INT));
   5.334 +        return node;
   5.335 +    }
   5.336 +
   5.337 +    @Override
   5.338 +    public Node leaveNOT(final UnaryNode node) {
   5.339 +        setRange(node, Range.createTypeRange(Type.BOOLEAN));
   5.340 +        return node;
   5.341 +    }
   5.342 +
   5.343 +    @Override
   5.344 +    public Node leaveSUB(final UnaryNode node) {
   5.345 +        setRange(node, RANGE.neg(node.rhs().getSymbol().getRange()));
   5.346 +        return node;
   5.347 +    }
   5.348 +
   5.349 +    @Override
   5.350 +    public Node leaveVarNode(final VarNode node) {
   5.351 +        if (node.isAssignment()) {
   5.352 +            Range range = node.getInit().getSymbol().getRange();
   5.353 +            range = range.isUnknown() ? Range.createGenericRange() : range;
   5.354 +
   5.355 +            setRange(node.getName(), range);
   5.356 +            setRange(node, range);
   5.357 +        }
   5.358 +
   5.359 +        return node;
   5.360 +    }
   5.361 +
   5.362 +    @SuppressWarnings("rawtypes")
   5.363 +    @Override
   5.364 +    public boolean enterLiteralNode(final LiteralNode node) {
   5.365 +        // ignore array literals
   5.366 +        return !(node instanceof ArrayLiteralNode);
   5.367 +    }
   5.368 +
   5.369 +    @Override
   5.370 +    public Node leaveLiteralNode(@SuppressWarnings("rawtypes") final LiteralNode node) {
   5.371 +        if (node.getType().isInteger()) {
   5.372 +            setRange(node, Range.createRange(node.getInt32()));
   5.373 +        } else if (node.getType().isNumber()) {
   5.374 +            setRange(node, Range.createRange(node.getNumber()));
   5.375 +        } else if (node.getType().isLong()) {
   5.376 +            setRange(node, Range.createRange(node.getLong()));
   5.377 +        } else if (node.getType().isBoolean()) {
   5.378 +            setRange(node, Range.createTypeRange(Type.BOOLEAN));
   5.379 +        } else {
   5.380 +            setRange(node, Range.createGenericRange());
   5.381 +        }
   5.382 +        return node;
   5.383 +    }
   5.384 +
   5.385 +    @Override
   5.386 +    public boolean enterRuntimeNode(final RuntimeNode node) {
   5.387 +        // a runtime node that cannot be specialized is no point entering
   5.388 +        return node.getRequest().canSpecialize();
   5.389 +    }
   5.390 +
   5.391 +    /**
   5.392 +     * Check whether a symbol is unsafely assigned in a loop - i.e. repeteadly assigned and
   5.393 +     * not being identified as the loop counter. That means we don't really know anything
   5.394 +     * about its range.
   5.395 +     * @param loopNode loop node
   5.396 +     * @param symbol   symbol
   5.397 +     * @return true if assigned in loop
   5.398 +     */
   5.399 +    // TODO - this currently checks for nodes only - needs to be augmented for while nodes
   5.400 +    // assignment analysis is also very conservative
   5.401 +    private static boolean assignedInLoop(final LoopNode loopNode, final Symbol symbol) {
   5.402 +        final HashSet<Node> skip = new HashSet<>();
   5.403 +        final HashSet<Node> assignmentsInLoop = new HashSet<>();
   5.404 +
   5.405 +        loopNode.accept(new NodeVisitor() {
   5.406 +            private boolean assigns(final Node node, final Symbol s) {
   5.407 +                return node.isAssignment() && ((Assignment<?>)node).getAssignmentDest().getSymbol() == s;
   5.408 +            }
   5.409 +
   5.410 +            @Override
   5.411 +            public boolean enterForNode(final ForNode forNode) {
   5.412 +                if (forNode.getInit() != null) {
   5.413 +                    skip.add(forNode.getInit());
   5.414 +                }
   5.415 +                if (forNode.getModify() != null) {
   5.416 +                    skip.add(forNode.getModify());
   5.417 +                }
   5.418 +                return true;
   5.419 +            }
   5.420 +
   5.421 +            @Override
   5.422 +            public Node leaveDefault(final Node node) {
   5.423 +                //if this is an assignment to symbol
   5.424 +                if (!skip.contains(node) && assigns(node, symbol)) {
   5.425 +                    assignmentsInLoop.add(node);
   5.426 +                }
   5.427 +                return node;
   5.428 +            }
   5.429 +        });
   5.430 +
   5.431 +        return !assignmentsInLoop.isEmpty();
   5.432 +    }
   5.433 +
   5.434 +    /**
   5.435 +     * Check for a loop counter. This is currently quite conservative, in that it only handles
   5.436 +     * x <= counter and x < counter.
   5.437 +     *
   5.438 +     * @param node loop node to check
   5.439 +     * @return
   5.440 +     */
   5.441 +    private static Symbol findLoopCounter(final LoopNode node) {
   5.442 +        final Node test = node.getTest();
   5.443 +
   5.444 +        if (test != null && test.isComparison()) {
   5.445 +            final BinaryNode binaryNode = (BinaryNode)test;
   5.446 +            final Node lhs = binaryNode.lhs();
   5.447 +            final Node rhs = binaryNode.rhs();
   5.448 +
   5.449 +            //detect ident cmp int_literal
   5.450 +            if (lhs instanceof IdentNode && rhs instanceof LiteralNode && ((LiteralNode<?>)rhs).getType().isInteger()) {
   5.451 +                final Symbol    symbol = lhs.getSymbol();
   5.452 +                final int       margin = ((LiteralNode<?>)rhs).getInt32();
   5.453 +                final TokenType op     = test.tokenType();
   5.454 +
   5.455 +                switch (op) {
   5.456 +                case LT:
   5.457 +                case LE:
   5.458 +                    symbol.setRange(RANGE.join(symbol.getRange(), Range.createRange(op == TokenType.LT ? margin - 1 : margin)));
   5.459 +                    return symbol;
   5.460 +                case GT:
   5.461 +                case GE:
   5.462 +                    //setRange(lhs, Range.createRange(op == TokenType.GT ? margin + 1 : margin));
   5.463 +                    //return symbol;
   5.464 +                default:
   5.465 +                    break;
   5.466 +                }
   5.467 +            }
   5.468 +        }
   5.469 +
   5.470 +        return null;
   5.471 +    }
   5.472 +
   5.473 +    private boolean isLoopCounter(final LoopNode loopNode, final Symbol symbol) {
   5.474 +        //this only works if loop nodes aren't replaced by other ones during this transform, but they are not
   5.475 +        return loopCounters.get(loopNode) == symbol;
   5.476 +    }
   5.477 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/jdk/nashorn/internal/codegen/types/Range.java	Mon May 20 16:38:38 2013 +0200
     6.3 @@ -0,0 +1,705 @@
     6.4 +/*
     6.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     6.7 + *
     6.8 + * This code is free software; you can redistribute it and/or modify it
     6.9 + * under the terms of the GNU General Public License version 2 only, as
    6.10 + * published by the Free Software Foundation.  Oracle designates this
    6.11 + * particular file as subject to the "Classpath" exception as provided
    6.12 + * by Oracle in the LICENSE file that accompanied this code.
    6.13 + *
    6.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    6.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    6.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    6.17 + * version 2 for more details (a copy is included in the LICENSE file that
    6.18 + * accompanied this code).
    6.19 + *
    6.20 + * You should have received a copy of the GNU General Public License version
    6.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    6.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    6.23 + *
    6.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    6.25 + * or visit www.oracle.com if you need additional information or have any
    6.26 + * questions.
    6.27 + */
    6.28 +
    6.29 +package jdk.nashorn.internal.codegen.types;
    6.30 +
    6.31 +import java.util.Arrays;
    6.32 +import java.util.Collections;
    6.33 +import java.util.List;
    6.34 +
    6.35 +import jdk.nashorn.internal.runtime.DebugLogger;
    6.36 +import jdk.nashorn.internal.runtime.JSType;
    6.37 +
    6.38 +/**
    6.39 + * Represents the value range of a symbol.
    6.40 + */
    6.41 +public abstract class Range {
    6.42 +
    6.43 +    private static final Range GENERIC_RANGE = new Range() {
    6.44 +        @Override
    6.45 +        public Type getType() {
    6.46 +            return Type.OBJECT;
    6.47 +        }
    6.48 +    };
    6.49 +
    6.50 +    private static final Range NUMBER_RANGE = new Range() {
    6.51 +        @Override
    6.52 +        public Type getType() {
    6.53 +            return Type.NUMBER;
    6.54 +        }
    6.55 +    };
    6.56 +
    6.57 +    private static final Range UNKNOWN_RANGE = new Range() {
    6.58 +        @Override
    6.59 +        public Type getType() {
    6.60 +            return Type.UNKNOWN;
    6.61 +        }
    6.62 +
    6.63 +        @Override
    6.64 +        public boolean isUnknown() {
    6.65 +            return true;
    6.66 +        }
    6.67 +    };
    6.68 +
    6.69 +    private static class IntegerRange extends Range {
    6.70 +        private final long min;
    6.71 +        private final long max;
    6.72 +        private final Type type;
    6.73 +
    6.74 +        private IntegerRange(final long min, final long max) {
    6.75 +            assert min <= max;
    6.76 +            this.min  = min;
    6.77 +            this.max  = max;
    6.78 +            this.type = typeFromRange(min, max);
    6.79 +        }
    6.80 +
    6.81 +        private static Type typeFromRange(final long from, final long to) {
    6.82 +            if (from >= Integer.MIN_VALUE && to <= Integer.MAX_VALUE) {
    6.83 +                return Type.INT;
    6.84 +            }
    6.85 +            return Type.LONG;
    6.86 +        }
    6.87 +
    6.88 +        @Override
    6.89 +        public Type getType() {
    6.90 +            return type;
    6.91 +        }
    6.92 +
    6.93 +        public long getMin() {
    6.94 +            return min;
    6.95 +        }
    6.96 +
    6.97 +        public long getMax() {
    6.98 +            return max;
    6.99 +        }
   6.100 +
   6.101 +        @Override
   6.102 +        public boolean isIntegerConst() {
   6.103 +            return getMin() == getMax();
   6.104 +        }
   6.105 +
   6.106 +        private long getBitMask() {
   6.107 +            if (min == max) {
   6.108 +                return min;
   6.109 +            }
   6.110 +
   6.111 +            if (min < 0) {
   6.112 +                return ~0L;
   6.113 +            }
   6.114 +
   6.115 +            long mask = 1;
   6.116 +            while (mask < max) {
   6.117 +                mask = (mask << 1) | 1;
   6.118 +            }
   6.119 +            return mask;
   6.120 +        }
   6.121 +
   6.122 +        @Override
   6.123 +        public boolean equals(final Object obj) {
   6.124 +            if (obj instanceof IntegerRange) {
   6.125 +                final IntegerRange other = (IntegerRange)obj;
   6.126 +                return this.type == other.type && this.min == other.min && this.max == other.max;
   6.127 +            }
   6.128 +            return false;
   6.129 +        }
   6.130 +
   6.131 +        @Override
   6.132 +        public int hashCode() {
   6.133 +            return Long.hashCode(min) ^ Long.hashCode(max);
   6.134 +        }
   6.135 +
   6.136 +        @Override
   6.137 +        public String toString() {
   6.138 +            return super.toString() + "[" + min +", " + max + "]";
   6.139 +        }
   6.140 +    }
   6.141 +
   6.142 +    /**
   6.143 +     * Get narrowest type for this range
   6.144 +     * @return type
   6.145 +     */
   6.146 +    public abstract Type getType();
   6.147 +
   6.148 +    /**
   6.149 +     * Is this range unknown
   6.150 +     * @return true if unknown
   6.151 +     */
   6.152 +    public boolean isUnknown() {
   6.153 +        return false;
   6.154 +    }
   6.155 +
   6.156 +    /**
   6.157 +     * Check if an integer is enough to span this range
   6.158 +     * @return true if integer is enough
   6.159 +     */
   6.160 +    public boolean isIntegerType() {
   6.161 +        return this instanceof IntegerRange;
   6.162 +    }
   6.163 +
   6.164 +    /**
   6.165 +     * Check if an integer is enough to span this range
   6.166 +     * @return true if integer is enough
   6.167 +     */
   6.168 +    public boolean isIntegerConst() {
   6.169 +        return false;
   6.170 +    }
   6.171 +
   6.172 +    /**
   6.173 +     * Create an unknown range - this is most likely a singleton object
   6.174 +     * and it represents "we have no known range information"
   6.175 +     * @return the range
   6.176 +     */
   6.177 +    public static Range createUnknownRange() {
   6.178 +        return UNKNOWN_RANGE;
   6.179 +    }
   6.180 +
   6.181 +    /**
   6.182 +     * Create a constant range: [value, value]
   6.183 +     * @param value value
   6.184 +     * @return the range
   6.185 +     */
   6.186 +    public static Range createRange(final int value) {
   6.187 +        return createIntegerRange(value, value);
   6.188 +    }
   6.189 +
   6.190 +    /**
   6.191 +     * Create a constant range: [value, value]
   6.192 +     * @param value value
   6.193 +     * @return the range
   6.194 +     */
   6.195 +    public static Range createRange(final long value) {
   6.196 +        return createIntegerRange(value, value);
   6.197 +    }
   6.198 +
   6.199 +    /**
   6.200 +     * Create a constant range: [value, value]
   6.201 +     * @param value value
   6.202 +     * @return the range
   6.203 +     */
   6.204 +    public static Range createRange(final double value) {
   6.205 +        if (isRepresentableAsLong(value)) {
   6.206 +            return createIntegerRange((long) value, (long) value);
   6.207 +        }
   6.208 +        return createNumberRange();
   6.209 +    }
   6.210 +
   6.211 +    /**
   6.212 +     * Create a constant range: [value, value]
   6.213 +     * @param value value
   6.214 +     * @return the range
   6.215 +     */
   6.216 +    public static Range createRange(final Object value) {
   6.217 +        if (value instanceof Integer) {
   6.218 +            return createRange((int)value);
   6.219 +        } else if (value instanceof Long) {
   6.220 +            return createRange((long)value);
   6.221 +        } else if (value instanceof Double) {
   6.222 +            return createRange((double)value);
   6.223 +        }
   6.224 +
   6.225 +        return createGenericRange();
   6.226 +    }
   6.227 +
   6.228 +    /**
   6.229 +     * Create a generic range - object symbol that carries no range
   6.230 +     * information
   6.231 +     * @return the range
   6.232 +     */
   6.233 +    public static Range createGenericRange() {
   6.234 +        return GENERIC_RANGE;
   6.235 +    }
   6.236 +
   6.237 +    /**
   6.238 +     * Create a number range - number symbol that carries no range
   6.239 +     * information
   6.240 +     * @return the range
   6.241 +     */
   6.242 +    public static Range createNumberRange() {
   6.243 +        return NUMBER_RANGE;
   6.244 +    }
   6.245 +
   6.246 +    /**
   6.247 +     * Create an integer range [min, max]
   6.248 +     * @param min minimum value, inclusive
   6.249 +     * @param max maximum value, inclusive
   6.250 +     * @return the range
   6.251 +     */
   6.252 +    public static IntegerRange createIntegerRange(final long min, final long max) {
   6.253 +        return new IntegerRange(min, max);
   6.254 +    }
   6.255 +
   6.256 +    /**
   6.257 +     * Create an integer range of maximum type width for the given type
   6.258 +     * @param type the type
   6.259 +     * @return the range
   6.260 +     */
   6.261 +    public static IntegerRange createIntegerRange(final Type type) {
   6.262 +        assert type.isNumeric() && !type.isNumber();
   6.263 +        final long min;
   6.264 +        final long max;
   6.265 +        if (type.isInteger()) {
   6.266 +            min = Integer.MIN_VALUE;
   6.267 +            max = Integer.MAX_VALUE;
   6.268 +        } else if (type.isLong()) {
   6.269 +            min = Long.MIN_VALUE;
   6.270 +            max = Long.MAX_VALUE;
   6.271 +        } else {
   6.272 +            throw new AssertionError(); //type incompatible with integer range
   6.273 +        }
   6.274 +        return new IntegerRange(min, max);
   6.275 +    }
   6.276 +
   6.277 +    /**
   6.278 +     * Create an range of maximum type width for the given type
   6.279 +     * @param type the type
   6.280 +     * @return the range
   6.281 +     */
   6.282 +    public static Range createTypeRange(final Type type) {
   6.283 +        if (type.isNumber()) {
   6.284 +            return createNumberRange();
   6.285 +        } else if (type.isNumeric()) {
   6.286 +            return createIntegerRange(type);
   6.287 +        } else {
   6.288 +            return createGenericRange();
   6.289 +        }
   6.290 +    }
   6.291 +
   6.292 +    // check that add doesn't overflow
   6.293 +    private static boolean checkAdd(final long a, final long b) {
   6.294 +        final long result = a + b;
   6.295 +        return ((a ^ result) & (b ^ result)) >= 0;
   6.296 +    }
   6.297 +
   6.298 +    // check that sub doesn't overflow
   6.299 +    private static boolean checkSub(final long a, final long b) {
   6.300 +        final long result = a - b;
   6.301 +        return ((a ^ result) & (b ^ result)) >= 0;
   6.302 +    }
   6.303 +
   6.304 +    private static boolean checkMul(final long a, final long b) {
   6.305 +        // TODO correct overflow check
   6.306 +        return a >= Integer.MIN_VALUE && a <= Integer.MAX_VALUE && b >= Integer.MIN_VALUE && b <= Integer.MAX_VALUE;
   6.307 +    }
   6.308 +
   6.309 +    /**
   6.310 +     * The range functionality class responsible for merging ranges and drawing
   6.311 +     * range conclusions from operations executed
   6.312 +     */
   6.313 +    public static class Functionality {
   6.314 +        /** logger */
   6.315 +        protected final DebugLogger log;
   6.316 +
   6.317 +        /**
   6.318 +         * Constructor
   6.319 +         * @param log logger
   6.320 +         */
   6.321 +        public Functionality(final DebugLogger log) {
   6.322 +            this.log = log;
   6.323 +        }
   6.324 +
   6.325 +        /**
   6.326 +         * Join two ranges
   6.327 +         * @param a first range
   6.328 +         * @param b second range
   6.329 +         * @return the joined range
   6.330 +         */
   6.331 +        public Range join(final Range a, final Range b) {
   6.332 +            if (a.equals(b)) {
   6.333 +                return a;
   6.334 +            }
   6.335 +
   6.336 +            Type joinedType = a.getType();
   6.337 +            if (a.getType() != b.getType()) {
   6.338 +                if (a.isUnknown()) {
   6.339 +                    return b;
   6.340 +                }
   6.341 +                if (b.isUnknown()) {
   6.342 +                    return a;
   6.343 +                }
   6.344 +
   6.345 +                joinedType = Type.widest(a.getType(), b.getType());
   6.346 +            }
   6.347 +
   6.348 +            if (joinedType.isInteger() || joinedType.isLong()) {
   6.349 +                return createIntegerRange(
   6.350 +                        Math.min(((IntegerRange) a).getMin(), ((IntegerRange) b).getMin()),
   6.351 +                        Math.max(((IntegerRange) a).getMax(), ((IntegerRange) b).getMax()));
   6.352 +            }
   6.353 +
   6.354 +            return createTypeRange(joinedType);
   6.355 +        }
   6.356 +
   6.357 +        /**
   6.358 +         * Add operation
   6.359 +         * @param a range of first symbol to be added
   6.360 +         * @param b range of second symbol to be added
   6.361 +         * @return resulting range representing the value range after add
   6.362 +         */
   6.363 +        public Range add(final Range a, final Range b) {
   6.364 +            if (a.isIntegerType() && b.isIntegerType()) {
   6.365 +                final IntegerRange lhs = (IntegerRange)a;
   6.366 +                final IntegerRange rhs = (IntegerRange)b;
   6.367 +                if (checkAdd(lhs.getMin(), rhs.getMin()) && checkAdd(lhs.getMax(), rhs.getMax())) {
   6.368 +                    return createIntegerRange(lhs.getMin() + rhs.getMin(), lhs.getMax() + rhs.getMax());
   6.369 +                }
   6.370 +            }
   6.371 +
   6.372 +            if (a.getType().isNumeric() && b.getType().isNumeric()) {
   6.373 +                return createNumberRange();
   6.374 +            }
   6.375 +
   6.376 +            return createGenericRange();
   6.377 +        }
   6.378 +
   6.379 +        /**
   6.380 +         * Sub operation
   6.381 +         * @param a range of first symbol to be subtracted
   6.382 +         * @param b range of second symbol to be subtracted
   6.383 +         * @return resulting range representing the value range after subtraction
   6.384 +         */
   6.385 +        public Range sub(final Range a, final Range b) {
   6.386 +            if (a.isIntegerType() && b.isIntegerType()) {
   6.387 +                final IntegerRange lhs = (IntegerRange)a;
   6.388 +                final IntegerRange rhs = (IntegerRange)b;
   6.389 +                if (checkSub(lhs.getMin(), rhs.getMax()) && checkSub(lhs.getMax(), rhs.getMin())) {
   6.390 +                    return createIntegerRange(lhs.getMin() - rhs.getMax(), lhs.getMax() - rhs.getMin());
   6.391 +                }
   6.392 +            }
   6.393 +
   6.394 +            if (a.getType().isNumeric() && b.getType().isNumeric()) {
   6.395 +                return createNumberRange();
   6.396 +            }
   6.397 +
   6.398 +            return createGenericRange();
   6.399 +        }
   6.400 +
   6.401 +        /**
   6.402 +         * Mul operation
   6.403 +         * @param a range of first symbol to be multiplied
   6.404 +         * @param b range of second symbol to be multiplied
   6.405 +         * @return resulting range representing the value range after multiplication
   6.406 +         */
   6.407 +        public Range mul(final Range a, final Range b) {
   6.408 +            if (a.isIntegerType() && b.isIntegerType()) {
   6.409 +                final IntegerRange lhs = (IntegerRange)a;
   6.410 +                final IntegerRange rhs = (IntegerRange)b;
   6.411 +
   6.412 +                //ensure that nothing ever overflows or underflows
   6.413 +                if (checkMul(lhs.getMin(), rhs.getMin()) &&
   6.414 +                    checkMul(lhs.getMax(), rhs.getMax()) &&
   6.415 +                    checkMul(lhs.getMin(), rhs.getMax()) &&
   6.416 +                    checkMul(lhs.getMax(), rhs.getMin())) {
   6.417 +
   6.418 +                    final List<Long> results =
   6.419 +                        Arrays.asList(
   6.420 +                            lhs.getMin() * rhs.getMin(),
   6.421 +                            lhs.getMin() * rhs.getMax(),
   6.422 +                            lhs.getMax() * rhs.getMin(),
   6.423 +                            lhs.getMax() * rhs.getMax());
   6.424 +                    return createIntegerRange(Collections.min(results), Collections.max(results));
   6.425 +                }
   6.426 +            }
   6.427 +
   6.428 +            if (a.getType().isNumeric() && b.getType().isNumeric()) {
   6.429 +                return createNumberRange();
   6.430 +            }
   6.431 +
   6.432 +            return createGenericRange();
   6.433 +        }
   6.434 +
   6.435 +        /**
   6.436 +         * Neg operation
   6.437 +         * @param a range of value symbol to be negated
   6.438 +         * @return resulting range representing the value range after neg
   6.439 +         */
   6.440 +        public Range neg(final Range a) {
   6.441 +            if (a.isIntegerType()) {
   6.442 +                final IntegerRange rhs = (IntegerRange)a;
   6.443 +                if (rhs.getMin() != Long.MIN_VALUE && rhs.getMax() != Long.MIN_VALUE) {
   6.444 +                    return createIntegerRange(-rhs.getMax(), -rhs.getMin());
   6.445 +                }
   6.446 +            }
   6.447 +
   6.448 +            if (a.getType().isNumeric()) {
   6.449 +                return createNumberRange();
   6.450 +            }
   6.451 +
   6.452 +            return createGenericRange();
   6.453 +        }
   6.454 +
   6.455 +        /**
   6.456 +         * Bitwise and operation
   6.457 +         * @param a range of first symbol to be and:ed
   6.458 +         * @param b range of second symbol to be and:ed
   6.459 +         * @return resulting range representing the value range after and
   6.460 +         */
   6.461 +        public Range and(final Range a, final Range b) {
   6.462 +            if (a.isIntegerType() && b.isIntegerType()) {
   6.463 +                final int resultMask = (int) (((IntegerRange)a).getBitMask() & ((IntegerRange)b).getBitMask());
   6.464 +                if (resultMask >= 0) {
   6.465 +                    return createIntegerRange(0, resultMask);
   6.466 +                }
   6.467 +            } else if (a.isUnknown() && b.isIntegerType()) {
   6.468 +                final long operandMask = ((IntegerRange)b).getBitMask();
   6.469 +                if (operandMask >= 0) {
   6.470 +                    return createIntegerRange(0, operandMask);
   6.471 +                }
   6.472 +            } else if (a.isIntegerType() && b.isUnknown()) {
   6.473 +                final long operandMask = ((IntegerRange)a).getBitMask();
   6.474 +                if (operandMask >= 0) {
   6.475 +                    return createIntegerRange(0, operandMask);
   6.476 +                }
   6.477 +            }
   6.478 +
   6.479 +            return createTypeRange(Type.INT);
   6.480 +        }
   6.481 +
   6.482 +        /**
   6.483 +         * Bitwise or operation
   6.484 +         * @param a range of first symbol to be or:ed
   6.485 +         * @param b range of second symbol to be or:ed
   6.486 +         * @return resulting range representing the value range after or
   6.487 +         */
   6.488 +        public Range or(final Range a, final Range b) {
   6.489 +            if (a.isIntegerType() && b.isIntegerType()) {
   6.490 +                final int resultMask = (int)(((IntegerRange)a).getBitMask() | ((IntegerRange)b).getBitMask());
   6.491 +                if (resultMask >= 0) {
   6.492 +                    return createIntegerRange(0, resultMask);
   6.493 +                }
   6.494 +            }
   6.495 +
   6.496 +            return createTypeRange(Type.INT);
   6.497 +        }
   6.498 +
   6.499 +        /**
   6.500 +         * Bitwise xor operation
   6.501 +         * @param a range of first symbol to be xor:ed
   6.502 +         * @param b range of second symbol to be xor:ed
   6.503 +         * @return resulting range representing the value range after and
   6.504 +         */
   6.505 +        public Range xor(final Range a, final Range b) {
   6.506 +            if (a.isIntegerConst() && b.isIntegerConst()) {
   6.507 +                return createRange(((IntegerRange)a).getMin() ^ ((IntegerRange)b).getMin());
   6.508 +            }
   6.509 +
   6.510 +            if (a.isIntegerType() && b.isIntegerType()) {
   6.511 +                final int resultMask = (int)(((IntegerRange)a).getBitMask() | ((IntegerRange)b).getBitMask());
   6.512 +                if (resultMask >= 0) {
   6.513 +                    return createIntegerRange(0, createIntegerRange(0, resultMask).getBitMask());
   6.514 +                }
   6.515 +            }
   6.516 +            return createTypeRange(Type.INT);
   6.517 +        }
   6.518 +
   6.519 +        /**
   6.520 +         * Bitwise shl operation
   6.521 +         * @param a range of first symbol to be shl:ed
   6.522 +         * @param b range of second symbol to be shl:ed
   6.523 +         * @return resulting range representing the value range after shl
   6.524 +         */
   6.525 +        public Range shl(final Range a, final Range b) {
   6.526 +            if (b.isIntegerType() && b.isIntegerConst()) {
   6.527 +                final IntegerRange left  = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT));
   6.528 +                final int          shift = (int)((IntegerRange) b).getMin() & 0x1f;
   6.529 +                final int          min   = (int)left.getMin() << shift;
   6.530 +                final int          max   = (int)left.getMax() << shift;
   6.531 +                if (min >> shift == left.getMin() && max >> shift == left.getMax()) {
   6.532 +                    return createIntegerRange(min, max);
   6.533 +                }
   6.534 +            }
   6.535 +
   6.536 +            return createTypeRange(Type.INT);
   6.537 +        }
   6.538 +
   6.539 +        /**
   6.540 +         * Bitwise shr operation
   6.541 +         * @param a range of first symbol to be shr:ed
   6.542 +         * @param b range of second symbol to be shr:ed
   6.543 +         * @return resulting range representing the value range after shr
   6.544 +         */
   6.545 +        public Range shr(final Range a, final Range b) {
   6.546 +            if (b.isIntegerType() && b.isIntegerConst()) {
   6.547 +                final long         shift = ((IntegerRange) b).getMin() & 0x1f;
   6.548 +                final IntegerRange left  = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT));
   6.549 +                if (left.getMin() >= 0) {
   6.550 +                    long min = left.getMin() >>> shift;
   6.551 +                    long max = left.getMax() >>> shift;
   6.552 +                    return createIntegerRange(min, max);
   6.553 +                } else if (shift >= 1) {
   6.554 +                    return createIntegerRange(0, JSType.MAX_UINT >>> shift);
   6.555 +                }
   6.556 +            }
   6.557 +
   6.558 +            return createTypeRange(Type.INT);
   6.559 +        }
   6.560 +
   6.561 +        /**
   6.562 +         * Bitwise sar operation
   6.563 +         * @param a range of first symbol to be sar:ed
   6.564 +         * @param b range of second symbol to be sar:ed
   6.565 +         * @return resulting range representing the value range after sar
   6.566 +         */
   6.567 +        public Range sar(final Range a, final Range b) {
   6.568 +            if (b.isIntegerType() && b.isIntegerConst()) {
   6.569 +                final IntegerRange left  = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT));
   6.570 +                final long         shift = ((IntegerRange) b).getMin() & 0x1f;
   6.571 +                final long         min   = left.getMin() >> shift;
   6.572 +                final long         max   = left.getMax() >> shift;
   6.573 +                return createIntegerRange(min, max);
   6.574 +            }
   6.575 +
   6.576 +            return createTypeRange(Type.INT);
   6.577 +        }
   6.578 +
   6.579 +        /**
   6.580 +         * Modulo operation
   6.581 +         * @param a range of first symbol to the mod operation
   6.582 +         * @param b range of second symbol to be mod operation
   6.583 +         * @return resulting range representing the value range after mod
   6.584 +         */
   6.585 +        public Range mod(final Range a, final Range b) {
   6.586 +            if (a.isIntegerType() && b.isIntegerType()) {
   6.587 +                final IntegerRange rhs = (IntegerRange) b;
   6.588 +                if (rhs.getMin() > 0 || rhs.getMax() < 0) { // divisor range must not include 0
   6.589 +                    final long absmax = Math.max(Math.abs(rhs.getMin()), Math.abs(rhs.getMax())) - 1;
   6.590 +                    return createIntegerRange(rhs.getMin() > 0 ? 0 : -absmax, rhs.getMax() < 0 ? 0 : +absmax);
   6.591 +                }
   6.592 +            }
   6.593 +            return createTypeRange(Type.NUMBER);
   6.594 +        }
   6.595 +
   6.596 +        /**
   6.597 +         * Division operation
   6.598 +         * @param a range of first symbol to the division
   6.599 +         * @param b range of second symbol to be division
   6.600 +         * @return resulting range representing the value range after division
   6.601 +         */
   6.602 +        public Range div(final Range a, final Range b) {
   6.603 +            // TODO
   6.604 +            return createTypeRange(Type.NUMBER);
   6.605 +        }
   6.606 +    }
   6.607 +
   6.608 +    /**
   6.609 +     * Simple trace functionality that will log range creation
   6.610 +     */
   6.611 +    public static class TraceFunctionality extends Functionality {
   6.612 +        TraceFunctionality(final DebugLogger log) {
   6.613 +            super(log);
   6.614 +        }
   6.615 +
   6.616 +        private Range trace(final Range result, final String operation, final Range... operands) {
   6.617 +            log.fine("range::" + operation + Arrays.toString(operands) + " => " + result);
   6.618 +            return result;
   6.619 +        }
   6.620 +
   6.621 +        @Override
   6.622 +        public Range join(final Range a, final Range b) {
   6.623 +            final Range result = super.join(a, b);
   6.624 +            if (!a.equals(b)) {
   6.625 +                trace(result, "join", a, b);
   6.626 +            }
   6.627 +            return result;
   6.628 +        }
   6.629 +
   6.630 +        @Override
   6.631 +        public Range add(final Range a, final Range b) {
   6.632 +            return trace(super.add(a, b), "add", a, b);
   6.633 +        }
   6.634 +
   6.635 +        @Override
   6.636 +        public Range sub(final Range a, final Range b) {
   6.637 +            return trace(super.sub(a, b), "sub", a, b);
   6.638 +        }
   6.639 +
   6.640 +        @Override
   6.641 +        public Range mul(final Range a, final Range b) {
   6.642 +            return trace(super.mul(a, b), "mul", a, b);
   6.643 +        }
   6.644 +
   6.645 +        @Override
   6.646 +        public Range neg(final Range a) {
   6.647 +            return trace(super.neg(a), "neg", a);
   6.648 +        }
   6.649 +
   6.650 +        @Override
   6.651 +        public Range and(final Range a, final Range b) {
   6.652 +            return trace(super.and(a, b), "and", a, b);
   6.653 +        }
   6.654 +
   6.655 +        @Override
   6.656 +        public Range or(final Range a, final Range b) {
   6.657 +            return trace(super.or(a, b), "or", a, b);
   6.658 +        }
   6.659 +
   6.660 +        @Override
   6.661 +        public Range xor(final Range a, final Range b) {
   6.662 +            return trace(super.xor(a, b), "xor", a, b);
   6.663 +        }
   6.664 +
   6.665 +        @Override
   6.666 +        public Range shl(final Range a, final Range b) {
   6.667 +            return trace(super.shl(a, b), "shl", a, b);
   6.668 +        }
   6.669 +
   6.670 +        @Override
   6.671 +        public Range shr(final Range a, final Range b) {
   6.672 +            return trace(super.shr(a, b), "shr", a, b);
   6.673 +        }
   6.674 +
   6.675 +        @Override
   6.676 +        public Range sar(final Range a, final Range b) {
   6.677 +            return trace(super.sar(a, b), "sar", a, b);
   6.678 +        }
   6.679 +
   6.680 +        @Override
   6.681 +        public Range mod(final Range a, final Range b) {
   6.682 +            return trace(super.mod(a, b), "mod", a, b);
   6.683 +        }
   6.684 +
   6.685 +        @Override
   6.686 +        public Range div(final Range a, final Range b) {
   6.687 +            return trace(super.div(a, b), "div", a, b);
   6.688 +        }
   6.689 +    }
   6.690 +
   6.691 +    @Override
   6.692 +    public String toString() {
   6.693 +        return String.valueOf(getType());
   6.694 +    }
   6.695 +
   6.696 +    @SuppressWarnings("unused")
   6.697 +    private static boolean isRepresentableAsInt(final double number) {
   6.698 +        return (int)number == number && !isNegativeZero(number);
   6.699 +    }
   6.700 +
   6.701 +    private static boolean isRepresentableAsLong(final double number) {
   6.702 +        return (long)number == number && !isNegativeZero(number);
   6.703 +    }
   6.704 +
   6.705 +    private static boolean isNegativeZero(final double number) {
   6.706 +        return Double.doubleToLongBits(number) == Double.doubleToLongBits(-0.0);
   6.707 +    }
   6.708 +}
     7.1 --- a/src/jdk/nashorn/internal/codegen/types/Type.java	Fri May 17 16:44:22 2013 -0300
     7.2 +++ b/src/jdk/nashorn/internal/codegen/types/Type.java	Mon May 20 16:38:38 2013 +0200
     7.3 @@ -106,23 +106,13 @@
     7.4      Type(final String name, final Class<?> clazz, final int weight, final int slots) {
     7.5          this.name       = name;
     7.6          this.clazz      = clazz;
     7.7 -        this.descriptor = Type.getDescriptor(clazz);
     7.8 +        this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz);
     7.9          this.weight     = weight;
    7.10          assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight;
    7.11          this.slots      = slots;
    7.12      }
    7.13  
    7.14      /**
    7.15 -     * Return an internal descriptor for a type
    7.16 -     *
    7.17 -     * @param type the type
    7.18 -     * @return descriptor string
    7.19 -     */
    7.20 -    public static String getDescriptor(final Class<?> type) {
    7.21 -        return jdk.internal.org.objectweb.asm.Type.getDescriptor(type);
    7.22 -    }
    7.23 -
    7.24 -    /**
    7.25       * Get the weight of this type - use this e.g. for sorting method descriptors
    7.26       * @return the weight
    7.27       */
     8.1 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java	Fri May 17 16:44:22 2013 -0300
     8.2 +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java	Mon May 20 16:38:38 2013 +0200
     8.3 @@ -59,6 +59,23 @@
     8.4          this.rhs = rhs;
     8.5      }
     8.6  
     8.7 +    @Override
     8.8 +    public boolean isComparison() {
     8.9 +        switch (tokenType()) {
    8.10 +        case EQ:
    8.11 +        case EQ_STRICT:
    8.12 +        case NE:
    8.13 +        case NE_STRICT:
    8.14 +        case LE:
    8.15 +        case LT:
    8.16 +        case GE:
    8.17 +        case GT:
    8.18 +            return true;
    8.19 +        default:
    8.20 +            return false;
    8.21 +        }
    8.22 +    }
    8.23 +
    8.24      /**
    8.25       * Return the widest possible type for this operation. This is used for compile time
    8.26       * static type inference
     9.1 --- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Fri May 17 16:44:22 2013 -0300
     9.2 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Mon May 20 16:38:38 2013 +0200
     9.3 @@ -340,7 +340,7 @@
     9.4       * @return true if specialization is possible
     9.5       */
     9.6      public boolean canSpecialize() {
     9.7 -        return getFlag(CAN_SPECIALIZE);
     9.8 +        return snapshot != null && getFlag(CAN_SPECIALIZE);
     9.9      }
    9.10  
    9.11      /**
    10.1 --- a/src/jdk/nashorn/internal/ir/LexicalContext.java	Fri May 17 16:44:22 2013 -0300
    10.2 +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java	Mon May 20 16:38:38 2013 +0200
    10.3 @@ -440,6 +440,23 @@
    10.4      }
    10.5  
    10.6      /**
    10.7 +     * Check whether the lexical context is currently inside a loop
    10.8 +     * @return true if inside a loop
    10.9 +     */
   10.10 +    public boolean inLoop() {
   10.11 +        return getCurrentLoop() != null;
   10.12 +    }
   10.13 +
   10.14 +    /**
   10.15 +     * Returns the loop header of the current loop, or null if not inside a loop
   10.16 +     * @return loop header
   10.17 +     */
   10.18 +    public LoopNode getCurrentLoop() {
   10.19 +        final Iterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, getCurrentFunction());
   10.20 +        return iter.hasNext() ? iter.next() : null;
   10.21 +    }
   10.22 +
   10.23 +    /**
   10.24       * Find the breakable node corresponding to this label.
   10.25       * @param label label to search for, if null the closest breakable node will be returned unconditionally, e.g. a while loop with no label
   10.26       * @return closest breakable node
   10.27 @@ -461,8 +478,7 @@
   10.28      }
   10.29  
   10.30      private LoopNode getContinueTo() {
   10.31 -        final Iterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, getCurrentFunction());
   10.32 -        return iter.hasNext() ? iter.next() : null;
   10.33 +        return getCurrentLoop();
   10.34      }
   10.35  
   10.36      /**
    11.1 --- a/src/jdk/nashorn/internal/ir/Node.java	Fri May 17 16:44:22 2013 -0300
    11.2 +++ b/src/jdk/nashorn/internal/ir/Node.java	Mon May 20 16:38:38 2013 +0200
    11.3 @@ -153,6 +153,14 @@
    11.4      }
    11.5  
    11.6      /**
    11.7 +     * Returns true if this node represents a comparison operator
    11.8 +     * @return true if comparison
    11.9 +     */
   11.10 +    public boolean isComparison() {
   11.11 +        return false;
   11.12 +    }
   11.13 +
   11.14 +    /**
   11.15       * For reference copies - ensure that labels in the copy node are unique
   11.16       * using an appropriate copy constructor
   11.17       * @param lc lexical context
    12.1 --- a/src/jdk/nashorn/internal/ir/Symbol.java	Fri May 17 16:44:22 2013 -0300
    12.2 +++ b/src/jdk/nashorn/internal/ir/Symbol.java	Mon May 20 16:38:38 2013 +0200
    12.3 @@ -29,6 +29,8 @@
    12.4  import java.util.HashSet;
    12.5  import java.util.Set;
    12.6  import java.util.StringTokenizer;
    12.7 +
    12.8 +import jdk.nashorn.internal.codegen.types.Range;
    12.9  import jdk.nashorn.internal.codegen.types.Type;
   12.10  import jdk.nashorn.internal.runtime.Context;
   12.11  import jdk.nashorn.internal.runtime.Debug;
   12.12 @@ -89,6 +91,9 @@
   12.13      /** Number of times this symbol is used in code */
   12.14      private int useCount;
   12.15  
   12.16 +    /** Range for symbol */
   12.17 +    private Range range;
   12.18 +
   12.19      /** Debugging option - dump info and stack trace when symbols with given names are manipulated */
   12.20      private static final Set<String> TRACE_SYMBOLS;
   12.21      private static final Set<String> TRACE_SYMBOLS_STACKTRACE;
   12.22 @@ -131,6 +136,7 @@
   12.23          this.type       = type;
   12.24          this.slot       = slot;
   12.25          this.fieldIndex = -1;
   12.26 +        this.range      = Range.createUnknownRange();
   12.27          trace("CREATE SYMBOL");
   12.28      }
   12.29  
   12.30 @@ -157,12 +163,13 @@
   12.31  
   12.32      private Symbol(final Symbol base, final String name, final int flags) {
   12.33          this.flags = flags;
   12.34 -        this.name = name;
   12.35 +        this.name  = name;
   12.36  
   12.37          this.fieldIndex = base.fieldIndex;
   12.38 -        this.slot = base.slot;
   12.39 -        this.type = base.type;
   12.40 -        this.useCount = base.useCount;
   12.41 +        this.slot       = base.slot;
   12.42 +        this.type       = base.type;
   12.43 +        this.useCount   = base.useCount;
   12.44 +        this.range      = base.range;
   12.45      }
   12.46  
   12.47      private static String align(final String string, final int max) {
   12.48 @@ -276,7 +283,7 @@
   12.49  
   12.50      @Override
   12.51      public String toString() {
   12.52 -        final StringBuilder sb   = new StringBuilder();
   12.53 +        final StringBuilder sb = new StringBuilder();
   12.54  
   12.55          sb.append(name).
   12.56              append(' ').
   12.57 @@ -410,6 +417,22 @@
   12.58      }
   12.59  
   12.60      /**
   12.61 +     * Get the range for this symbol
   12.62 +     * @return range for symbol
   12.63 +     */
   12.64 +    public Range getRange() {
   12.65 +        return range;
   12.66 +    }
   12.67 +
   12.68 +    /**
   12.69 +     * Set the range for this symbol
   12.70 +     * @param range range
   12.71 +     */
   12.72 +    public void setRange(final Range range) {
   12.73 +        this.range = range;
   12.74 +    }
   12.75 +
   12.76 +    /**
   12.77       * Check if this symbol is a function parameter of known
   12.78       * narrowest type
   12.79       * @return true if parameter
    13.1 --- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Fri May 17 16:44:22 2013 -0300
    13.2 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Mon May 20 16:38:38 2013 +0200
    13.3 @@ -35,21 +35,27 @@
    13.4   */
    13.5  final class CompiledFunction implements Comparable<CompiledFunction> {
    13.6  
    13.7 +    /** The method type may be more specific than the invoker, if. e.g.
    13.8 +     *  the invoker is guarded, and a guard with a generic object only
    13.9 +     *  fallback, while the target is more specific, we still need the
   13.10 +     *  more specific type for sorting */
   13.11 +    private final MethodType   type;
   13.12      private final MethodHandle invoker;
   13.13      private MethodHandle constructor;
   13.14  
   13.15 -    CompiledFunction(final MethodHandle invoker) {
   13.16 -        this(invoker, null);
   13.17 +    CompiledFunction(final MethodType type, final MethodHandle invoker) {
   13.18 +        this(type, invoker, null);
   13.19      }
   13.20  
   13.21 -    CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) {
   13.22 -        this.invoker = invoker;
   13.23 -        this.constructor = constructor; //isConstructor
   13.24 +    CompiledFunction(final MethodType type, final MethodHandle invoker, final MethodHandle constructor) {
   13.25 +        this.type        = type;
   13.26 +        this.invoker     = invoker;
   13.27 +        this.constructor = constructor;
   13.28      }
   13.29  
   13.30      @Override
   13.31      public String toString() {
   13.32 -        return "<invoker=" + invoker + " ctor=" + constructor + ">";
   13.33 +        return "<callSiteType= " + type + " invoker=" + invoker + " ctor=" + constructor + ">";
   13.34      }
   13.35  
   13.36      MethodHandle getInvoker() {
   13.37 @@ -69,7 +75,7 @@
   13.38      }
   13.39  
   13.40      MethodType type() {
   13.41 -        return invoker.type();
   13.42 +        return type;
   13.43      }
   13.44  
   13.45      @Override
   13.46 @@ -103,8 +109,8 @@
   13.47          return weight() > o.weight();
   13.48      }
   13.49  
   13.50 -    boolean moreGenericThan(final MethodType type) {
   13.51 -        return weight() > weight(type);
   13.52 +    boolean moreGenericThan(final MethodType mt) {
   13.53 +        return weight() > weight(mt);
   13.54      }
   13.55  
   13.56      /**
   13.57 @@ -112,15 +118,15 @@
   13.58       * It is compatible if the types are narrower than the invocation type so that
   13.59       * a semantically equivalent linkage can be performed.
   13.60       *
   13.61 -     * @param typesc
   13.62 +     * @param mt type to check against
   13.63       * @return
   13.64       */
   13.65 -    boolean typeCompatible(final MethodType type) {
   13.66 -        final Class<?>[] wantedParams   = type.parameterArray();
   13.67 +    boolean typeCompatible(final MethodType mt) {
   13.68 +        final Class<?>[] wantedParams   = mt.parameterArray();
   13.69          final Class<?>[] existingParams = type().parameterArray();
   13.70  
   13.71          //if we are not examining a varargs type, the number of parameters must be the same
   13.72 -        if (wantedParams.length != existingParams.length && !isVarArgsType(type)) {
   13.73 +        if (wantedParams.length != existingParams.length && !isVarArgsType(mt)) {
   13.74              return false;
   13.75          }
   13.76  
    14.1 --- a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Fri May 17 16:44:22 2013 -0300
    14.2 +++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Mon May 20 16:38:38 2013 +0200
    14.3 @@ -78,9 +78,9 @@
    14.4              //only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor
    14.5              //is too conservative a check. However, isConstructor(mh) always implies isConstructor param
    14.6              assert isConstructor();
    14.7 -            code.add(new CompiledFunction(MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor
    14.8 +            code.add(new CompiledFunction(mh.type(), MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor
    14.9          } else {
   14.10 -            code.add(new CompiledFunction(mh));
   14.11 +            code.add(new CompiledFunction(mh.type(), mh));
   14.12          }
   14.13      }
   14.14  
    15.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Fri May 17 16:44:22 2013 -0300
    15.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Mon May 20 16:38:38 2013 +0200
    15.3 @@ -30,6 +30,8 @@
    15.4  import java.lang.invoke.MethodHandle;
    15.5  import java.lang.invoke.MethodHandles;
    15.6  import java.lang.invoke.MethodType;
    15.7 +import java.util.ArrayList;
    15.8 +import java.util.Arrays;
    15.9  import java.util.LinkedList;
   15.10  
   15.11  import jdk.nashorn.internal.codegen.Compiler;
   15.12 @@ -49,9 +51,16 @@
   15.13   */
   15.14  public final class RecompilableScriptFunctionData extends ScriptFunctionData {
   15.15  
   15.16 +    /** FunctionNode with the code for this ScriptFunction */
   15.17      private FunctionNode functionNode;
   15.18 -    private final PropertyMap  allocatorMap;
   15.19 +
   15.20 +    /** Allocator map from makeMap() */
   15.21 +    private final PropertyMap allocatorMap;
   15.22 +
   15.23 +    /** Code installer used for all further recompilation/specialization of this ScriptFunction */
   15.24      private final CodeInstaller<ScriptEnvironment> installer;
   15.25 +
   15.26 +    /** Name of class where allocator function resides */
   15.27      private final String allocatorClassName;
   15.28  
   15.29      /** lazily generated allocator */
   15.30 @@ -60,6 +69,23 @@
   15.31      private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
   15.32  
   15.33      /**
   15.34 +     * Used for specialization based on runtime arguments. Whenever we specialize on
   15.35 +     * callsite parameter types at runtime, we need to use a parameter type guard to
   15.36 +     * ensure that the specialized version of the script function continues to be
   15.37 +     * applicable for a particular callsite *
   15.38 +     */
   15.39 +    private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class,  Object[].class);
   15.40 +
   15.41 +    /**
   15.42 +     * It is usually a good gamble whever we detect a runtime callsite with a double
   15.43 +     * (or java.lang.Number instance) to specialize the parameter to an integer, if the
   15.44 +     * parameter in question can be represented as one. The double typically only exists
   15.45 +     * because the compiler doesn't know any better than "a number type" and conservatively
   15.46 +     * picks doubles when it can't prove that an integer addition wouldn't overflow
   15.47 +     */
   15.48 +    private static final MethodHandle ENSURE_INT = findOwnMH("ensureInt", int.class, Object.class);
   15.49 +
   15.50 +    /**
   15.51       * Constructor - public as scripts use it
   15.52       *
   15.53       * @param functionNode       functionNode that represents this function code
   15.54 @@ -141,14 +167,6 @@
   15.55               return; // nothing to do, we have code, at least some.
   15.56           }
   15.57  
   15.58 -         // check if function node is lazy, need to compile it.
   15.59 -         // note that currently function cloning is not working completely, which
   15.60 -         // means that the compiler will mutate the function node it has been given
   15.61 -         // once it has been compiled, it cannot be recompiled. This means that
   15.62 -         // lazy compilation works (not compiled yet) but e.g. specializations won't
   15.63 -         // until the copy-on-write changes for IR are in, making cloning meaningless.
   15.64 -         // therefore, currently method specialization is disabled. TODO
   15.65 -
   15.66           if (functionNode.isLazy()) {
   15.67               Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
   15.68               final Compiler compiler = new Compiler(installer);
   15.69 @@ -156,38 +174,55 @@
   15.70               assert !functionNode.isLazy();
   15.71               compiler.install(functionNode);
   15.72  
   15.73 -             // we don't need to update any flags - varArgs and needsCallee are instrincic
   15.74 -             // in the function world we need to get a destination node from the compile instead
   15.75 -             // and replace it with our function node. TODO
   15.76 +             /*
   15.77 +              * We don't need to update any flags - varArgs and needsCallee are instrincic
   15.78 +              * in the function world we need to get a destination node from the compile instead
   15.79 +              * and replace it with our function node. TODO
   15.80 +              */
   15.81           }
   15.82  
   15.83 -         // we can't get here unless we have bytecode, either from eager compilation or from
   15.84 -         // running a lazy compile on the lines above
   15.85 +         /*
   15.86 +          * We can't get to this program point unless we have bytecode, either from
   15.87 +          * eager compilation or from running a lazy compile on the lines above
   15.88 +          */
   15.89  
   15.90           assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
   15.91  
   15.92           // code exists - look it up and add it into the automatically sorted invoker list
   15.93 -         addCode(functionNode, null, null);
   15.94 +         addCode(functionNode);
   15.95      }
   15.96  
   15.97 -    private MethodHandle addCode(final FunctionNode fn, final MethodHandle guard, final MethodHandle fallback) {
   15.98 -        final MethodHandle target =
   15.99 +    private MethodHandle addCode(final FunctionNode fn) {
  15.100 +        return addCode(fn, null, null, null);
  15.101 +    }
  15.102 +
  15.103 +    private MethodHandle addCode(final FunctionNode fn, final MethodType runtimeType, final MethodHandle guard, final MethodHandle fallback) {
  15.104 +        final MethodType targetType = new FunctionSignature(fn).getMethodType();
  15.105 +        MethodHandle target =
  15.106              MH.findStatic(
  15.107                      LOOKUP,
  15.108                      fn.getCompileUnit().getCode(),
  15.109                      fn.getName(),
  15.110 -                    new FunctionSignature(fn).
  15.111 -                        getMethodType());
  15.112 -        MethodHandle mh = target;
  15.113 -        if (guard != null) {
  15.114 -            try {
  15.115 -                mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback);
  15.116 -            } catch (Throwable e) {
  15.117 -                e.printStackTrace();
  15.118 +                    targetType);
  15.119 +
  15.120 +        /*
  15.121 +         * For any integer argument. a double that is representable as an integer is OK.
  15.122 +         * otherwise the guard would have failed. in that case introduce a filter that
  15.123 +         * casts the double to an integer, which we know will preserve all precision.
  15.124 +         */
  15.125 +        for (int i = 0; i < targetType.parameterCount(); i++) {
  15.126 +            if (targetType.parameterType(i) == int.class) {
  15.127 +                //representable as int
  15.128 +                target = MH.filterArguments(target, i, ENSURE_INT);
  15.129              }
  15.130          }
  15.131  
  15.132 -        final CompiledFunction cf = new CompiledFunction(mh);
  15.133 +        MethodHandle mh = target;
  15.134 +        if (guard != null) {
  15.135 +            mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback);
  15.136 +        }
  15.137 +
  15.138 +        final CompiledFunction cf = new CompiledFunction(runtimeType == null ? targetType : runtimeType, mh);
  15.139          code.add(cf);
  15.140  
  15.141          return cf.getInvoker();
  15.142 @@ -212,69 +247,162 @@
  15.143          return Type.OBJECT;
  15.144      }
  15.145  
  15.146 -    @SuppressWarnings("unused")
  15.147 -    private static boolean paramTypeGuard(final Type[] compileTimeTypes, final Type[] runtimeTypes, Object... args) {
  15.148 -        //System.err.println("Param type guard " + Arrays.asList(args));
  15.149 +    private static boolean canCoerce(final Object arg, final Type type) {
  15.150 +        Type argType = runtimeType(arg);
  15.151 +        if (Type.widest(argType, type) == type || arg == ScriptRuntime.UNDEFINED) {
  15.152 +            return true;
  15.153 +        }
  15.154 +        System.err.println(arg + " does not fit in "+ argType + " " + type + " " + arg.getClass());
  15.155 +        new Throwable().printStackTrace();
  15.156          return false;
  15.157      }
  15.158  
  15.159 -    private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Type[].class, Object[].class);
  15.160 +    @SuppressWarnings("unused")
  15.161 +    private static boolean paramTypeGuard(final Type[] paramTypes, final Object... args) {
  15.162 +        final int length = args.length;
  15.163 +        assert args.length >= paramTypes.length;
  15.164 +
  15.165 +        //i==start, skip the this, callee params etc
  15.166 +        int start = args.length - paramTypes.length;
  15.167 +        for (int i = start; i < args.length; i++) {
  15.168 +            final Object arg = args[i];
  15.169 +            if (!canCoerce(arg, paramTypes[i - start])) {
  15.170 +                return false;
  15.171 +            }
  15.172 +        }
  15.173 +        return true;
  15.174 +    }
  15.175 +
  15.176 +    @SuppressWarnings("unused")
  15.177 +    private static int ensureInt(final Object arg) {
  15.178 +        if (arg instanceof Number) {
  15.179 +            return ((Number)arg).intValue();
  15.180 +        } else if (arg instanceof Undefined) {
  15.181 +            return 0;
  15.182 +        }
  15.183 +        throw new AssertionError(arg);
  15.184 +    }
  15.185 +
  15.186 +    /**
  15.187 +     * Given the runtime callsite args, compute a method type that is equivalent to what
  15.188 +     * was passed - this is typically a lot more specific that what the compiler has been
  15.189 +     * able to deduce
  15.190 +     * @param callSiteType callsite type for the compiled callsite target
  15.191 +     * @param args runtime arguments to the compiled callsite target
  15.192 +     * @return adjusted method type, narrowed as to conform to runtime callsite type instead
  15.193 +     */
  15.194 +    private static MethodType runtimeType(final MethodType callSiteType, final Object[] args) {
  15.195 +        if (args == null) {
  15.196 +            //for example bound, or otherwise runtime arguments to callsite unavailable, then
  15.197 +            //do not change the type
  15.198 +            return callSiteType;
  15.199 +        }
  15.200 +        final Class<?>[] paramTypes = new Class<?>[callSiteType.parameterCount()];
  15.201 +        final int        start      = args.length - callSiteType.parameterCount();
  15.202 +        for (int i = start; i < args.length; i++) {
  15.203 +            paramTypes[i - start] = runtimeType(args[i]).getTypeClass();
  15.204 +        }
  15.205 +        return MH.type(callSiteType.returnType(), paramTypes);
  15.206 +    }
  15.207 +
  15.208 +    private static ArrayList<Type> runtimeType(final MethodType mt) {
  15.209 +        final ArrayList<Type> type = new ArrayList<>();
  15.210 +        for (int i = 0; i < mt.parameterCount(); i++) {
  15.211 +            type.add(Type.typeFor(mt.parameterType(i)));
  15.212 +        }
  15.213 +        return type;
  15.214 +    }
  15.215  
  15.216      @Override
  15.217      MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
  15.218 -        final MethodHandle mh = super.getBestInvoker(callSiteType, args);
  15.219 +        final MethodType runtimeType = runtimeType(callSiteType, args);
  15.220 +        assert runtimeType.parameterCount() == callSiteType.parameterCount();
  15.221  
  15.222 -        if (!functionNode.canSpecialize() || !code.isLessSpecificThan(callSiteType)) {
  15.223 +        final MethodHandle mh = super.getBestInvoker(runtimeType, args);
  15.224 +
  15.225 +        /*
  15.226 +         * Not all functions can be specialized, for example, if we deemed memory
  15.227 +         * footprint too large to store a parse snapshot, or if it is meaningless
  15.228 +         * to do so, such as e.g. for runScript
  15.229 +         */
  15.230 +        if (!functionNode.canSpecialize()) {
  15.231              return mh;
  15.232          }
  15.233  
  15.234 -        final FunctionNode snapshot = functionNode.getSnapshot();
  15.235 -        if (snapshot == null) {
  15.236 +        /*
  15.237 +         * Check if best invoker is equally specific or more specific than runtime
  15.238 +         * type. In that case, we don't need further specialization, but can use
  15.239 +         * whatever we have already. We know that it will match callSiteType, or it
  15.240 +         * would not have been returned from getBestInvoker
  15.241 +         */
  15.242 +        if (!code.isLessSpecificThan(runtimeType)) {
  15.243              return mh;
  15.244          }
  15.245  
  15.246          int i;
  15.247 +        final FunctionNode snapshot = functionNode.getSnapshot();
  15.248 +        assert snapshot != null;
  15.249  
  15.250 -        //classes known at runtime
  15.251 -        final LinkedList<Type> runtimeArgs = new LinkedList<>();
  15.252 -        for (i = args.length - 1; i >= args.length - snapshot.getParameters().size(); i--) {
  15.253 -            runtimeArgs.addLast(runtimeType(args[i]));
  15.254 +        /*
  15.255 +         * Create a list of the arg types that the compiler knows about
  15.256 +         * typically, the runtime args are a lot more specific, and we should aggressively
  15.257 +         * try to use those whenever possible
  15.258 +         * We WILL try to make an aggressive guess as possible, and add guards if needed.
  15.259 +         * For example, if the compiler can deduce that we have a number type, but the runtime
  15.260 +         * passes and int, we might still want to keep it an int, and the gamble to
  15.261 +         * check that whatever is passed is int representable usually pays off
  15.262 +         * If the compiler only knows that a parameter is an "Object", it is still worth
  15.263 +         * it to try to specialize it by looking at the runtime arg.
  15.264 +         */
  15.265 +        final LinkedList<Type> compileTimeArgs = new LinkedList<>();
  15.266 +        for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) {
  15.267 +            compileTimeArgs.addFirst(Type.typeFor(callSiteType.parameterType(i)));
  15.268          }
  15.269  
  15.270 -        //classes known at compile time
  15.271 -        final LinkedList<Type> compileTimeArgs = new LinkedList<>();
  15.272 -        for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) {
  15.273 -            compileTimeArgs.addLast(Type.typeFor(callSiteType.parameterType(i)));
  15.274 +        /*
  15.275 +         * The classes known at compile time are a safe to generate as primitives without parameter guards
  15.276 +         * But the classes known at runtime (if more specific than compile time types) are safe to generate as primitives
  15.277 +         * IFF there are parameter guards
  15.278 +         */
  15.279 +        MethodHandle guard = null;
  15.280 +        final ArrayList<Type> runtimeParamTypes = runtimeType(runtimeType);
  15.281 +        while (runtimeParamTypes.size() > functionNode.getParameters().size()) {
  15.282 +            runtimeParamTypes.remove(0);
  15.283          }
  15.284 +        for (i = 0; i < compileTimeArgs.size(); i++) {
  15.285 +            final Type rparam = Type.typeFor(runtimeType.parameterType(i));
  15.286 +            final Type cparam = compileTimeArgs.get(i);
  15.287  
  15.288 -        //the classes known at compile time are a safe to generate as primitives without parameter guards
  15.289 -        //the classes known at runtime are safe to generate as primitives IFF there are parameter guards
  15.290 -        MethodHandle guard = null;
  15.291 -        for (i = 0; i < compileTimeArgs.size(); i++) {
  15.292 -            final Type runtimeType = runtimeArgs.get(i);
  15.293 -            final Type compileType = compileTimeArgs.get(i);
  15.294 -
  15.295 -            if (compileType.isObject() && !runtimeType.isObject()) {
  15.296 +            if (cparam.isObject() && !rparam.isObject()) {
  15.297 +                //check that the runtime object is still coercible to the runtime type, because compiler can't prove it's always primitive
  15.298                  if (guard == null) {
  15.299 -                    guard = PARAM_TYPE_GUARD;
  15.300 -                    guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()]));
  15.301 +                    guard = MH.insertArguments(PARAM_TYPE_GUARD, 0, (Object)runtimeParamTypes.toArray(new Type[runtimeParamTypes.size()]));
  15.302                  }
  15.303              }
  15.304          }
  15.305  
  15.306 -        //System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs);
  15.307 +        Compiler.LOG.info("Callsite specialized ", name, " runtimeType=", runtimeType, " parameters=", snapshot.getParameters(), " args=", Arrays.asList(args));
  15.308  
  15.309          assert snapshot != null;
  15.310          assert snapshot != functionNode;
  15.311  
  15.312          final Compiler compiler = new Compiler(installer);
  15.313 -        final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()]))));
  15.314  
  15.315 +        final FunctionNode compiledSnapshot = compiler.compile(
  15.316 +            snapshot.setHints(
  15.317 +                null,
  15.318 +                new Compiler.Hints(runtimeParamTypes.toArray(new Type[runtimeParamTypes.size()]))));
  15.319 +
  15.320 +        /*
  15.321 +         * No matter how narrow your types were, they can never be narrower than Attr during recompile made them. I.e. you
  15.322 +         * can put an int into the function here, if you see it as a runtime type, but if the function uses a multiplication
  15.323 +         * on it, it will still need to be a double. At least until we have overflow checks. Similarly, if an int is
  15.324 +         * passed but it is used as a string, it makes no sense to make the parameter narrower than Object. At least until
  15.325 +         * the "different types for one symbol in difference places" work is done
  15.326 +         */
  15.327          compiler.install(compiledSnapshot);
  15.328  
  15.329 -        final MethodHandle nmh = addCode(compiledSnapshot, guard, mh);
  15.330 -
  15.331 -        return nmh;
  15.332 +        return addCode(compiledSnapshot, runtimeType, guard, mh);
  15.333      }
  15.334  
  15.335      private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
    16.1 --- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Fri May 17 16:44:22 2013 -0300
    16.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Mon May 20 16:38:38 2013 +0200
    16.3 @@ -54,7 +54,7 @@
    16.4      private final Namespace namespace;
    16.5  
    16.6      /** Current Options object. */
    16.7 -    private Options options;
    16.8 +    private final Options options;
    16.9  
   16.10      /** Always allow functions as statements */
   16.11      public final boolean _anon_functions;
   16.12 @@ -155,6 +155,9 @@
   16.13      /** print symbols and their contents for the script */
   16.14      public final boolean _print_symbols;
   16.15  
   16.16 +    /** range analysis for known types */
   16.17 +    public final boolean _range_analysis;
   16.18 +
   16.19      /** is this environment in scripting mode? */
   16.20      public final boolean _scripting;
   16.21  
   16.22 @@ -219,6 +222,7 @@
   16.23          _print_parse          = options.getBoolean("print.parse");
   16.24          _print_lower_parse    = options.getBoolean("print.lower.parse");
   16.25          _print_symbols        = options.getBoolean("print.symbols");
   16.26 +        _range_analysis       = options.getBoolean("range.analysis");
   16.27          _scripting            = options.getBoolean("scripting");
   16.28          _strict               = options.getBoolean("strict");
   16.29          _version              = options.getBoolean("version");
    17.1 --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Fri May 17 16:44:22 2013 -0300
    17.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Mon May 20 16:38:38 2013 +0200
    17.3 @@ -91,12 +91,13 @@
    17.4      CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) {
    17.5          final MethodHandle boundInvoker = bindInvokeHandle(originalInv.getInvoker(), fn, self, args);
    17.6  
    17.7 +        //TODO the boundinvoker.type() could actually be more specific here
    17.8          if (isConstructor()) {
    17.9              ensureConstructor(originalInv);
   17.10 -            return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args));
   17.11 +            return new CompiledFunction(boundInvoker.type(), boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args));
   17.12          }
   17.13  
   17.14 -        return new CompiledFunction(boundInvoker);
   17.15 +        return new CompiledFunction(boundInvoker.type(), boundInvoker);
   17.16      }
   17.17  
   17.18      /**
    18.1 --- a/src/jdk/nashorn/internal/runtime/resources/Options.properties	Fri May 17 16:44:22 2013 -0300
    18.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties	Mon May 20 16:38:38 2013 +0200
    18.3 @@ -277,6 +277,12 @@
    18.4      desc="Print the symbol table." \
    18.5  }
    18.6  
    18.7 +nashorn.option.range.analysis = { \
    18.8 +    name="--range-analysis",      \
    18.9 +    is_undocumented=true,         \
   18.10 +    desc="Do range analysis using known compile time types, and try to narrow number types" \
   18.11 +}    
   18.12 +
   18.13  nashorn.option.D = {                                                          \
   18.14      name="-D",                                                                \
   18.15      desc="-Dname=value. Set a system property. This option can be repeated.", \
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/test/script/basic/ranges_disabled.js	Mon May 20 16:38:38 2013 +0200
    19.3 @@ -0,0 +1,32 @@
    19.4 +/*
    19.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
    19.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    19.7 + * 
    19.8 + * This code is free software; you can redistribute it and/or modify it
    19.9 + * under the terms of the GNU General Public License version 2 only, as
   19.10 + * published by the Free Software Foundation.
   19.11 + * 
   19.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   19.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   19.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   19.15 + * version 2 for more details (a copy is included in the LICENSE file that
   19.16 + * accompanied this code).
   19.17 + * 
   19.18 + * You should have received a copy of the GNU General Public License version
   19.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   19.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   19.21 + * 
   19.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   19.23 + * or visit www.oracle.com if you need additional information or have any
   19.24 + * questions.
   19.25 + */
   19.26 +
   19.27 +/**
   19.28 + * range analysis test. check that computation return values are correct
   19.29 + * both with and without range analysis
   19.30 + *
   19.31 + * @test 
   19.32 + * @run 
   19.33 + */
   19.34 +
   19.35 +load(__DIR__ + "ranges_payload.js");
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/test/script/basic/ranges_disabled.js.EXPECTED	Mon May 20 16:38:38 2013 +0200
    20.3 @@ -0,0 +1,4 @@
    20.4 +289
    20.5 +11094405
    20.6 +4294967293
    20.7 +-4722
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/test/script/basic/ranges_enabled.js	Mon May 20 16:38:38 2013 +0200
    21.3 @@ -0,0 +1,33 @@
    21.4 +/*
    21.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
    21.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    21.7 + * 
    21.8 + * This code is free software; you can redistribute it and/or modify it
    21.9 + * under the terms of the GNU General Public License version 2 only, as
   21.10 + * published by the Free Software Foundation.
   21.11 + * 
   21.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   21.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   21.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   21.15 + * version 2 for more details (a copy is included in the LICENSE file that
   21.16 + * accompanied this code).
   21.17 + * 
   21.18 + * You should have received a copy of the GNU General Public License version
   21.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   21.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   21.21 + * 
   21.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   21.23 + * or visit www.oracle.com if you need additional information or have any
   21.24 + * questions.
   21.25 + */
   21.26 +
   21.27 +/**
   21.28 + * range analysis test. check that computation return values are correct
   21.29 + * both with and without range analysis
   21.30 + *
   21.31 + * @test
   21.32 + * @option --range-analysis
   21.33 + * @run 
   21.34 + */
   21.35 +
   21.36 +load(__DIR__ + "ranges_payload.js");
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/test/script/basic/ranges_enabled.js.EXPECTED	Mon May 20 16:38:38 2013 +0200
    22.3 @@ -0,0 +1,4 @@
    22.4 +289
    22.5 +11094405
    22.6 +4294967293
    22.7 +-4722
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/test/script/basic/ranges_payload.js	Mon May 20 16:38:38 2013 +0200
    23.3 @@ -0,0 +1,74 @@
    23.4 +/*
    23.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
    23.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    23.7 + * 
    23.8 + * This code is free software; you can redistribute it and/or modify it
    23.9 + * under the terms of the GNU General Public License version 2 only, as
   23.10 + * published by the Free Software Foundation.
   23.11 + * 
   23.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   23.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   23.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   23.15 + * version 2 for more details (a copy is included in the LICENSE file that
   23.16 + * accompanied this code).
   23.17 + * 
   23.18 + * You should have received a copy of the GNU General Public License version
   23.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   23.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   23.21 + * 
   23.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   23.23 + * or visit www.oracle.com if you need additional information or have any
   23.24 + * questions.
   23.25 + */
   23.26 +
   23.27 +/**
   23.28 + * range analysis test. check that computation return values are correct
   23.29 + * both with and without range analysis
   23.30 + *
   23.31 + * @subtest
   23.32 + */
   23.33 +
   23.34 +function f(c) {
   23.35 +    var v = c & 0xffff;
   23.36 +    var w = v & 0xfff;
   23.37 +    var x = v * w;
   23.38 +    return x;
   23.39 +}
   23.40 +
   23.41 +function g() {
   23.42 +    var sum = 0;
   23.43 +    for (var x = 0; x < 4711; x++) {
   23.44 +	sum += x;
   23.45 +    }
   23.46 +    return sum;
   23.47 +}
   23.48 +
   23.49 +function g2() {
   23.50 +    var sum = 0;
   23.51 +    //make sure we overflow
   23.52 +    var displacement = 0x7ffffffe;
   23.53 +    for (var x = displacement; x < (displacement + 2); x++) {
   23.54 +	sum += x;
   23.55 +    }
   23.56 +    return sum;
   23.57 +}
   23.58 +
   23.59 +//mostly provide code coverage for all the range operations    
   23.60 +function h() {
   23.61 +    var sum = 0;
   23.62 +    sum += 4711;
   23.63 +    sum &= 0xffff;
   23.64 +    sum /= 2;
   23.65 +    sum *= 2;
   23.66 +    sum -= 4;
   23.67 +    sum |= 2;
   23.68 +    sum ^= 17;
   23.69 +    sum = sum % 10000;
   23.70 +    sum = -sum;
   23.71 +    return sum
   23.72 +}
   23.73 +
   23.74 +print(f(17));
   23.75 +print(g());
   23.76 +print(g2());
   23.77 +print(h());

mercurial