Merge

Mon, 29 Dec 2014 19:40:21 -0800

author
lana
date
Mon, 29 Dec 2014 19:40:21 -0800
changeset 1210
59e4cf23697e
parent 1207
634ef69dfeb2
parent 1209
acb0b8f6540e
child 1211
ed00f1906e42
child 1212
0c0130c5ff1b

Merge

     1.1 --- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Wed Dec 17 14:46:42 2014 -0800
     1.2 +++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Mon Dec 29 19:40:21 2014 -0800
     1.3 @@ -40,21 +40,22 @@
     1.4  import java.util.List;
     1.5  import java.util.Map;
     1.6  import java.util.Set;
     1.7 -import java.util.function.Function;
     1.8  import jdk.nashorn.internal.codegen.types.Type;
     1.9  import jdk.nashorn.internal.ir.AccessNode;
    1.10 -import jdk.nashorn.internal.ir.BaseNode;
    1.11  import jdk.nashorn.internal.ir.BinaryNode;
    1.12  import jdk.nashorn.internal.ir.Block;
    1.13  import jdk.nashorn.internal.ir.BreakNode;
    1.14  import jdk.nashorn.internal.ir.BreakableNode;
    1.15 +import jdk.nashorn.internal.ir.CallNode;
    1.16  import jdk.nashorn.internal.ir.CaseNode;
    1.17  import jdk.nashorn.internal.ir.CatchNode;
    1.18  import jdk.nashorn.internal.ir.ContinueNode;
    1.19  import jdk.nashorn.internal.ir.Expression;
    1.20 +import jdk.nashorn.internal.ir.ExpressionStatement;
    1.21  import jdk.nashorn.internal.ir.ForNode;
    1.22  import jdk.nashorn.internal.ir.FunctionNode;
    1.23  import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    1.24 +import jdk.nashorn.internal.ir.GetSplitState;
    1.25  import jdk.nashorn.internal.ir.IdentNode;
    1.26  import jdk.nashorn.internal.ir.IfNode;
    1.27  import jdk.nashorn.internal.ir.IndexNode;
    1.28 @@ -65,9 +66,11 @@
    1.29  import jdk.nashorn.internal.ir.LexicalContext;
    1.30  import jdk.nashorn.internal.ir.LexicalContextNode;
    1.31  import jdk.nashorn.internal.ir.LiteralNode;
    1.32 +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
    1.33  import jdk.nashorn.internal.ir.LocalVariableConversion;
    1.34  import jdk.nashorn.internal.ir.LoopNode;
    1.35  import jdk.nashorn.internal.ir.Node;
    1.36 +import jdk.nashorn.internal.ir.ObjectNode;
    1.37  import jdk.nashorn.internal.ir.PropertyNode;
    1.38  import jdk.nashorn.internal.ir.ReturnNode;
    1.39  import jdk.nashorn.internal.ir.RuntimeNode;
    1.40 @@ -82,6 +85,7 @@
    1.41  import jdk.nashorn.internal.ir.UnaryNode;
    1.42  import jdk.nashorn.internal.ir.VarNode;
    1.43  import jdk.nashorn.internal.ir.WhileNode;
    1.44 +import jdk.nashorn.internal.ir.WithNode;
    1.45  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    1.46  import jdk.nashorn.internal.parser.TokenType;
    1.47  
    1.48 @@ -131,8 +135,44 @@
    1.49          OBJECT(Type.OBJECT);
    1.50  
    1.51          private final Type type;
    1.52 +        private final TypeHolderExpression typeExpression;
    1.53 +
    1.54          private LvarType(final Type type) {
    1.55              this.type = type;
    1.56 +            this.typeExpression = new TypeHolderExpression(type);
    1.57 +        }
    1.58 +    }
    1.59 +
    1.60 +    /**
    1.61 +     * A bogus Expression subclass that only reports its type. Used to interrogate BinaryNode and UnaryNode about their
    1.62 +     * types by creating temporary copies of them and replacing their operands with instances of these. An alternative
    1.63 +     * solution would be to add BinaryNode.getType(Type lhsType, Type rhsType) and UnaryNode.getType(Type exprType)
    1.64 +     * methods. For the time being though, this is easier to implement and is in fact fairly clean. It does result in
    1.65 +     * generation of higher number of temporary short lived nodes, though.
    1.66 +     */
    1.67 +    private static class TypeHolderExpression extends Expression {
    1.68 +        private static final long serialVersionUID = 1L;
    1.69 +
    1.70 +        private final Type type;
    1.71 +
    1.72 +        TypeHolderExpression(final Type type) {
    1.73 +            super(0L, 0, 0);
    1.74 +            this.type = type;
    1.75 +        }
    1.76 +
    1.77 +        @Override
    1.78 +        public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
    1.79 +            throw new AssertionError();
    1.80 +        }
    1.81 +
    1.82 +        @Override
    1.83 +        public Type getType() {
    1.84 +            return type;
    1.85 +        }
    1.86 +
    1.87 +        @Override
    1.88 +        public void toString(final StringBuilder sb, final boolean printType) {
    1.89 +            throw new AssertionError();
    1.90          }
    1.91      }
    1.92  
    1.93 @@ -359,6 +399,8 @@
    1.94      // allocates a new map. Immutability of maps allows for cheap snapshots by just keeping the reference to the current
    1.95      // value.
    1.96      private Map<Symbol, LvarType> localVariableTypes = new IdentityHashMap<>();
    1.97 +    // Stack for evaluated expression types.
    1.98 +    private final Deque<LvarType> typeStack = new ArrayDeque<>();
    1.99  
   1.100      // Whether the current point in the AST is reachable code
   1.101      private boolean reachable = true;
   1.102 @@ -375,8 +417,6 @@
   1.103      private final Map<IdentNode, LvarType> identifierLvarTypes = new IdentityHashMap<>();
   1.104      private final Map<Symbol, SymbolConversions> symbolConversions = new IdentityHashMap<>();
   1.105  
   1.106 -    private SymbolToType symbolToType = new SymbolToType();
   1.107 -
   1.108      // Stack of open labels for starts of catch blocks, one for every currently traversed try block; for inserting
   1.109      // control flow edges to them. Note that we currently don't insert actual control flow edges, but instead edges that
   1.110      // help us with type calculations. This means that some operations that can result in an exception being thrown
   1.111 @@ -400,62 +440,56 @@
   1.112      private void doesNotContinueSequentially() {
   1.113          reachable = false;
   1.114          localVariableTypes = Collections.emptyMap();
   1.115 +        assertTypeStackIsEmpty();
   1.116      }
   1.117  
   1.118 +    private boolean pushExpressionType(final Expression expr) {
   1.119 +        typeStack.push(toLvarType(expr.getType()));
   1.120 +        return false;
   1.121 +    }
   1.122 +
   1.123 +    @Override
   1.124 +    public boolean enterAccessNode(final AccessNode accessNode) {
   1.125 +        visitExpression(accessNode.getBase());
   1.126 +        return pushExpressionType(accessNode);
   1.127 +    }
   1.128  
   1.129      @Override
   1.130      public boolean enterBinaryNode(final BinaryNode binaryNode) {
   1.131          // NOTE: regardless of operator's lexical associativity, lhs is always evaluated first.
   1.132          final Expression lhs = binaryNode.lhs();
   1.133 -        final boolean isAssignment = binaryNode.isAssignment();
   1.134 -        LvarType lhsTypeOnLoad = null;
   1.135 -        if(isAssignment) {
   1.136 -            if(lhs instanceof BaseNode) {
   1.137 -                ((BaseNode)lhs).getBase().accept(this);
   1.138 -                if(lhs instanceof IndexNode) {
   1.139 -                    ((IndexNode)lhs).getIndex().accept(this);
   1.140 -                } else {
   1.141 -                    assert lhs instanceof AccessNode;
   1.142 -                }
   1.143 -            } else {
   1.144 -                assert lhs instanceof IdentNode;
   1.145 -                if(binaryNode.isSelfModifying()) {
   1.146 -                    final IdentNode ident = ((IdentNode)lhs);
   1.147 -                    ident.accept(this);
   1.148 -                    // Self-assignment can cause a change in the type of the variable. For purposes of evaluating
   1.149 -                    // the type of the operation, we must use its type as it was when it was loaded. If we didn't
   1.150 -                    // do this, some awkward expressions would end up being calculated incorrectly, e.g.
   1.151 -                    // "var x; x += x = 0;". In this case we have undefined+int so the result type is double (NaN).
   1.152 -                    // However, if we used the type of "x" on LHS after we evaluated RHS, we'd see int+int, so the
   1.153 -                    // result type would be either optimistic int or pessimistic long, which would be wrong.
   1.154 -                    lhsTypeOnLoad = getLocalVariableTypeIfBytecode(ident.getSymbol());
   1.155 -                }
   1.156 -            }
   1.157 +        final LvarType lhsType;
   1.158 +        if (!(lhs instanceof IdentNode && binaryNode.tokenType() == TokenType.ASSIGN)) {
   1.159 +            lhsType = visitExpression(lhs);
   1.160          } else {
   1.161 -            lhs.accept(this);
   1.162 +            // Can't visit IdentNode on LHS of a simple assignment, as visits imply use, and this is def.
   1.163 +            // The type is irrelevant, as only RHS is used to determine the type anyway.
   1.164 +            lhsType = LvarType.UNDEFINED;
   1.165          }
   1.166  
   1.167          final boolean isLogical = binaryNode.isLogical();
   1.168 -        assert !(isAssignment && isLogical); // there are no logical assignment operators in JS
   1.169          final Label joinLabel = isLogical ? new Label("") : null;
   1.170          if(isLogical) {
   1.171              jumpToLabel((JoinPredecessor)lhs, joinLabel);
   1.172          }
   1.173  
   1.174          final Expression rhs = binaryNode.rhs();
   1.175 -        rhs.accept(this);
   1.176 +        final LvarType rhsType = visitExpression(rhs);
   1.177          if(isLogical) {
   1.178              jumpToLabel((JoinPredecessor)rhs, joinLabel);
   1.179          }
   1.180          joinOnLabel(joinLabel);
   1.181  
   1.182 -        if(isAssignment && lhs instanceof IdentNode) {
   1.183 +        final LvarType type = toLvarType(binaryNode.setOperands(lhsType.typeExpression, rhsType.typeExpression).getType());
   1.184 +
   1.185 +        if(binaryNode.isAssignment() && lhs instanceof IdentNode) {
   1.186              if(binaryNode.isSelfModifying()) {
   1.187 -                onSelfAssignment((IdentNode)lhs, binaryNode, lhsTypeOnLoad);
   1.188 +                onSelfAssignment((IdentNode)lhs, type);
   1.189              } else {
   1.190 -                onAssignment((IdentNode)lhs, rhs);
   1.191 +                onAssignment((IdentNode)lhs, type);
   1.192              }
   1.193          }
   1.194 +        typeStack.push(type);
   1.195          return false;
   1.196      }
   1.197  
   1.198 @@ -475,6 +509,17 @@
   1.199      }
   1.200  
   1.201      @Override
   1.202 +    public boolean enterCallNode(final CallNode callNode) {
   1.203 +        visitExpression(callNode.getFunction());
   1.204 +        visitExpressions(callNode.getArgs());
   1.205 +        final CallNode.EvalArgs evalArgs = callNode.getEvalArgs();
   1.206 +        if (evalArgs != null) {
   1.207 +            visitExpressions(evalArgs.getArgs());
   1.208 +        }
   1.209 +        return pushExpressionType(callNode);
   1.210 +    }
   1.211 +
   1.212 +    @Override
   1.213      public boolean enterContinueNode(final ContinueNode continueNode) {
   1.214          return enterJumpStatement(continueNode);
   1.215      }
   1.216 @@ -483,6 +528,7 @@
   1.217          if(!reachable) {
   1.218              return false;
   1.219          }
   1.220 +        assertTypeStackIsEmpty();
   1.221          final BreakableNode target = jump.getTarget(lc);
   1.222          jumpToLabel(jump, jump.getTargetLabel(target), getBreakTargetTypes(target));
   1.223          doesNotContinueSequentially();
   1.224 @@ -495,6 +541,7 @@
   1.225      }
   1.226  
   1.227      private void enterDoWhileLoop(final WhileNode loopNode) {
   1.228 +        assertTypeStackIsEmpty();
   1.229          final JoinPredecessorExpression test = loopNode.getTest();
   1.230          final Block body = loopNode.getBody();
   1.231          final Label continueLabel = loopNode.getContinueLabel();
   1.232 @@ -512,7 +559,7 @@
   1.233              if(!reachable) {
   1.234                  break;
   1.235              }
   1.236 -            test.accept(this);
   1.237 +            visitExpressionOnEmptyStack(test);
   1.238              jumpToLabel(test, breakLabel);
   1.239              if(isAlwaysFalse(test)) {
   1.240                  break;
   1.241 @@ -535,6 +582,45 @@
   1.242      }
   1.243  
   1.244      @Override
   1.245 +    public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
   1.246 +        if (reachable) {
   1.247 +            visitExpressionOnEmptyStack(expressionStatement.getExpression());
   1.248 +        }
   1.249 +        return false;
   1.250 +    }
   1.251 +
   1.252 +    private void assertTypeStackIsEmpty() {
   1.253 +        assert typeStack.isEmpty();
   1.254 +    }
   1.255 +
   1.256 +    @Override
   1.257 +    protected Node leaveDefault(final Node node) {
   1.258 +        assert !(node instanceof Expression); // All expressions were handled
   1.259 +        assert !(node instanceof Statement) || typeStack.isEmpty(); // No statements leave with a non-empty stack
   1.260 +        return node;
   1.261 +    }
   1.262 +
   1.263 +    private LvarType visitExpressionOnEmptyStack(final Expression expr) {
   1.264 +        assertTypeStackIsEmpty();
   1.265 +        return visitExpression(expr);
   1.266 +    }
   1.267 +
   1.268 +    private LvarType visitExpression(final Expression expr) {
   1.269 +        final int stackSize = typeStack.size();
   1.270 +        expr.accept(this);
   1.271 +        assert typeStack.size() == stackSize + 1;
   1.272 +        return typeStack.pop();
   1.273 +    }
   1.274 +
   1.275 +    private void visitExpressions(final List<Expression> exprs) {
   1.276 +        for(final Expression expr: exprs) {
   1.277 +            if (expr != null) {
   1.278 +                visitExpression(expr);
   1.279 +            }
   1.280 +        }
   1.281 +    }
   1.282 +
   1.283 +    @Override
   1.284      public boolean enterForNode(final ForNode forNode) {
   1.285          if(!reachable) {
   1.286              return false;
   1.287 @@ -543,7 +629,7 @@
   1.288          final Expression init = forNode.getInit();
   1.289          if(forNode.isForIn()) {
   1.290              final JoinPredecessorExpression iterable = forNode.getModify();
   1.291 -            iterable.accept(this);
   1.292 +            visitExpression(iterable);
   1.293              enterTestFirstLoop(forNode, null, init,
   1.294                      // If we're iterating over property names, and we can discern from the runtime environment
   1.295                      // of the compilation that the object being iterated over must use strings for property
   1.296 @@ -552,16 +638,18 @@
   1.297                      !compiler.useOptimisticTypes() || (!forNode.isForEach() && compiler.hasStringPropertyIterator(iterable.getExpression())));
   1.298          } else {
   1.299              if(init != null) {
   1.300 -                init.accept(this);
   1.301 +                visitExpressionOnEmptyStack(init);
   1.302              }
   1.303              enterTestFirstLoop(forNode, forNode.getModify(), null, false);
   1.304          }
   1.305 +        assertTypeStackIsEmpty();
   1.306          return false;
   1.307      }
   1.308  
   1.309      @Override
   1.310      public boolean enterFunctionNode(final FunctionNode functionNode) {
   1.311          if(alreadyEnteredTopLevelFunction) {
   1.312 +            typeStack.push(LvarType.OBJECT);
   1.313              return false;
   1.314          }
   1.315          int pos = 0;
   1.316 @@ -603,11 +691,20 @@
   1.317      }
   1.318  
   1.319      @Override
   1.320 +    public boolean enterGetSplitState(final GetSplitState getSplitState) {
   1.321 +        return pushExpressionType(getSplitState);
   1.322 +    }
   1.323 +
   1.324 +    @Override
   1.325      public boolean enterIdentNode(final IdentNode identNode) {
   1.326          final Symbol symbol = identNode.getSymbol();
   1.327          if(symbol.isBytecodeLocal()) {
   1.328              symbolIsUsed(symbol);
   1.329 -            setIdentifierLvarType(identNode, getLocalVariableType(symbol));
   1.330 +            final LvarType type = getLocalVariableType(symbol);
   1.331 +            setIdentifierLvarType(identNode, type);
   1.332 +            typeStack.push(type);
   1.333 +        } else {
   1.334 +            pushExpressionType(identNode);
   1.335          }
   1.336          return false;
   1.337      }
   1.338 @@ -622,11 +719,12 @@
   1.339          final Block pass = ifNode.getPass();
   1.340          final Block fail = ifNode.getFail();
   1.341  
   1.342 -        test.accept(this);
   1.343 +        visitExpressionOnEmptyStack(test);
   1.344  
   1.345          final Map<Symbol, LvarType> afterTestLvarTypes = localVariableTypes;
   1.346          if(!isAlwaysFalse(test)) {
   1.347              pass.accept(this);
   1.348 +            assertTypeStackIsEmpty();
   1.349          }
   1.350          final Map<Symbol, LvarType> passLvarTypes = localVariableTypes;
   1.351          final boolean reachableFromPass = reachable;
   1.352 @@ -635,6 +733,7 @@
   1.353          localVariableTypes = afterTestLvarTypes;
   1.354          if(!isAlwaysTrue(test) && fail != null) {
   1.355              fail.accept(this);
   1.356 +            assertTypeStackIsEmpty();
   1.357              final boolean reachableFromFail = reachable;
   1.358              reachable |= reachableFromPass;
   1.359              if(!reachable) {
   1.360 @@ -667,15 +766,54 @@
   1.361      }
   1.362  
   1.363      @Override
   1.364 -    public boolean enterPropertyNode(final PropertyNode propertyNode) {
   1.365 -        // Avoid falsely adding property keys to the control flow graph
   1.366 -        if(propertyNode.getValue() != null) {
   1.367 -            propertyNode.getValue().accept(this);
   1.368 +    public boolean enterIndexNode(final IndexNode indexNode) {
   1.369 +        visitExpression(indexNode.getBase());
   1.370 +        visitExpression(indexNode.getIndex());
   1.371 +        return pushExpressionType(indexNode);
   1.372 +    }
   1.373 +
   1.374 +    @Override
   1.375 +    public boolean enterJoinPredecessorExpression(final JoinPredecessorExpression joinExpr) {
   1.376 +        final Expression expr = joinExpr.getExpression();
   1.377 +        if (expr != null) {
   1.378 +            expr.accept(this);
   1.379 +        } else {
   1.380 +            typeStack.push(LvarType.UNDEFINED);
   1.381          }
   1.382          return false;
   1.383      }
   1.384  
   1.385      @Override
   1.386 +    public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
   1.387 +        if (literalNode instanceof ArrayLiteralNode) {
   1.388 +            final List<Expression> expressions = ((ArrayLiteralNode)literalNode).getElementExpressions();
   1.389 +            if (expressions != null) {
   1.390 +                visitExpressions(expressions);
   1.391 +            }
   1.392 +        }
   1.393 +        pushExpressionType(literalNode);
   1.394 +        return false;
   1.395 +    }
   1.396 +
   1.397 +    @Override
   1.398 +    public boolean enterObjectNode(final ObjectNode objectNode) {
   1.399 +        for(final PropertyNode propertyNode: objectNode.getElements()) {
   1.400 +            // Avoid falsely adding property keys to the control flow graph
   1.401 +            final Expression value = propertyNode.getValue();
   1.402 +            if (value != null) {
   1.403 +                visitExpression(value);
   1.404 +            }
   1.405 +        }
   1.406 +        return pushExpressionType(objectNode);
   1.407 +    }
   1.408 +
   1.409 +    @Override
   1.410 +    public boolean enterPropertyNode(final PropertyNode propertyNode) {
   1.411 +        // Property nodes are only accessible through object literals, and we handled that case above
   1.412 +        throw new AssertionError();
   1.413 +    }
   1.414 +
   1.415 +    @Override
   1.416      public boolean enterReturnNode(final ReturnNode returnNode) {
   1.417          if(!reachable) {
   1.418              return false;
   1.419 @@ -684,9 +822,9 @@
   1.420          final Expression returnExpr = returnNode.getExpression();
   1.421          final Type returnExprType;
   1.422          if(returnExpr != null) {
   1.423 -            returnExpr.accept(this);
   1.424 -            returnExprType = getType(returnExpr);
   1.425 +            returnExprType = visitExpressionOnEmptyStack(returnExpr).type;
   1.426          } else {
   1.427 +            assertTypeStackIsEmpty();
   1.428              returnExprType = Type.UNDEFINED;
   1.429          }
   1.430          returnType = Type.widestReturnType(returnType, returnExprType);
   1.431 @@ -695,6 +833,12 @@
   1.432      }
   1.433  
   1.434      @Override
   1.435 +    public boolean enterRuntimeNode(final RuntimeNode runtimeNode) {
   1.436 +        visitExpressions(runtimeNode.getArgs());
   1.437 +        return pushExpressionType(runtimeNode);
   1.438 +    }
   1.439 +
   1.440 +    @Override
   1.441      public boolean enterSplitReturn(final SplitReturn splitReturn) {
   1.442          doesNotContinueSequentially();
   1.443          return false;
   1.444 @@ -706,8 +850,7 @@
   1.445              return false;
   1.446          }
   1.447  
   1.448 -        final Expression expr = switchNode.getExpression();
   1.449 -        expr.accept(this);
   1.450 +        visitExpressionOnEmptyStack(switchNode.getExpression());
   1.451  
   1.452          final List<CaseNode> cases = switchNode.getCases();
   1.453          if(cases.isEmpty()) {
   1.454 @@ -724,7 +867,7 @@
   1.455          for(final CaseNode caseNode: cases) {
   1.456              final Expression test = caseNode.getTest();
   1.457              if(!isInteger && test != null) {
   1.458 -                test.accept(this);
   1.459 +                visitExpressionOnEmptyStack(test);
   1.460                  if(!tagUsed) {
   1.461                      symbolIsUsed(switchNode.getTag(), LvarType.OBJECT);
   1.462                      tagUsed = true;
   1.463 @@ -769,29 +912,42 @@
   1.464          final Expression trueExpr = ternaryNode.getTrueExpression();
   1.465          final Expression falseExpr = ternaryNode.getFalseExpression();
   1.466  
   1.467 -        test.accept(this);
   1.468 +        visitExpression(test);
   1.469  
   1.470          final Map<Symbol, LvarType> testExitLvarTypes = localVariableTypes;
   1.471 +        final LvarType trueType;
   1.472          if(!isAlwaysFalse(test)) {
   1.473 -            trueExpr.accept(this);
   1.474 +            trueType = visitExpression(trueExpr);
   1.475 +        } else {
   1.476 +            trueType = null;
   1.477          }
   1.478          final Map<Symbol, LvarType> trueExitLvarTypes = localVariableTypes;
   1.479          localVariableTypes = testExitLvarTypes;
   1.480 +        final LvarType falseType;
   1.481          if(!isAlwaysTrue(test)) {
   1.482 -            falseExpr.accept(this);
   1.483 +            falseType = visitExpression(falseExpr);
   1.484 +        } else {
   1.485 +            falseType = null;
   1.486          }
   1.487          final Map<Symbol, LvarType> falseExitLvarTypes = localVariableTypes;
   1.488          localVariableTypes = getUnionTypes(trueExitLvarTypes, falseExitLvarTypes);
   1.489          setConversion((JoinPredecessor)trueExpr, trueExitLvarTypes, localVariableTypes);
   1.490          setConversion((JoinPredecessor)falseExpr, falseExitLvarTypes, localVariableTypes);
   1.491 +
   1.492 +        typeStack.push(trueType != null ? falseType != null ? widestLvarType(trueType, falseType) : trueType : assertNotNull(falseType));
   1.493          return false;
   1.494      }
   1.495  
   1.496 +    private static <T> T assertNotNull(final T t) {
   1.497 +        assert t != null;
   1.498 +        return t;
   1.499 +    }
   1.500 +
   1.501      private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify,
   1.502              final Expression iteratorValues, final boolean iteratorValuesAreObject) {
   1.503          final JoinPredecessorExpression test = loopNode.getTest();
   1.504          if(isAlwaysFalse(test)) {
   1.505 -            test.accept(this);
   1.506 +            visitExpressionOnEmptyStack(test);
   1.507              return;
   1.508          }
   1.509  
   1.510 @@ -804,7 +960,7 @@
   1.511              jumpToLabel(loopNode, repeatLabel, beforeLoopTypes);
   1.512              final Map<Symbol, LvarType> beforeRepeatTypes = localVariableTypes;
   1.513              if(test != null) {
   1.514 -                test.accept(this);
   1.515 +                visitExpressionOnEmptyStack(test);
   1.516              }
   1.517              if(!isAlwaysTrue(test)) {
   1.518                  jumpToLabel(test, breakLabel);
   1.519 @@ -827,7 +983,7 @@
   1.520                  break;
   1.521              }
   1.522              if(modify != null) {
   1.523 -                modify.accept(this);
   1.524 +                visitExpressionOnEmptyStack(modify);
   1.525                  jumpToLabel(modify, repeatLabel);
   1.526                  joinOnLabel(repeatLabel);
   1.527              }
   1.528 @@ -853,7 +1009,7 @@
   1.529              return false;
   1.530          }
   1.531  
   1.532 -        throwNode.getExpression().accept(this);
   1.533 +        visitExpressionOnEmptyStack(throwNode.getExpression());
   1.534          jumpToCatchBlock(throwNode);
   1.535          doesNotContinueSequentially();
   1.536          return false;
   1.537 @@ -892,7 +1048,7 @@
   1.538              onAssignment(exception, LvarType.OBJECT);
   1.539              final Expression condition = catchNode.getExceptionCondition();
   1.540              if(condition != null) {
   1.541 -                condition.accept(this);
   1.542 +                visitExpression(condition);
   1.543              }
   1.544              final Map<Symbol, LvarType> afterConditionTypes = localVariableTypes;
   1.545              final Block catchBody = catchNode.getBody();
   1.546 @@ -927,14 +1083,11 @@
   1.547      @Override
   1.548      public boolean enterUnaryNode(final UnaryNode unaryNode) {
   1.549          final Expression expr = unaryNode.getExpression();
   1.550 -        expr.accept(this);
   1.551 -
   1.552 -        if(unaryNode.isSelfModifying()) {
   1.553 -            if(expr instanceof IdentNode) {
   1.554 -                final IdentNode ident = (IdentNode)expr;
   1.555 -                onSelfAssignment(ident, unaryNode, getLocalVariableTypeIfBytecode(ident.getSymbol()));
   1.556 -            }
   1.557 +        final LvarType unaryType = toLvarType(unaryNode.setExpression(visitExpression(expr).typeExpression).getType());
   1.558 +        if(unaryNode.isSelfModifying() && expr instanceof IdentNode) {
   1.559 +            onSelfAssignment((IdentNode)expr, unaryType);
   1.560          }
   1.561 +        typeStack.push(unaryType);
   1.562          return false;
   1.563      }
   1.564  
   1.565 @@ -945,8 +1098,7 @@
   1.566          }
   1.567          final Expression init = varNode.getInit();
   1.568          if(init != null) {
   1.569 -            init.accept(this);
   1.570 -            onAssignment(varNode.getName(), init);
   1.571 +            onAssignment(varNode.getName(), visitExpression(init));
   1.572          }
   1.573          return false;
   1.574      }
   1.575 @@ -964,6 +1116,15 @@
   1.576          return false;
   1.577      }
   1.578  
   1.579 +    @Override
   1.580 +    public boolean enterWithNode(final WithNode withNode) {
   1.581 +        if (reachable) {
   1.582 +            visitExpression(withNode.getExpression());
   1.583 +            withNode.getBody().accept(this);
   1.584 +        }
   1.585 +        return false;
   1.586 +    };
   1.587 +
   1.588      private Map<Symbol, LvarType> getBreakTargetTypes(final BreakableNode target) {
   1.589          // Remove symbols defined in the the blocks that are being broken out of.
   1.590          Map<Symbol, LvarType> types = localVariableTypes;
   1.591 @@ -1002,18 +1163,6 @@
   1.592      }
   1.593  
   1.594      /**
   1.595 -     * Gets the type for a local variable if it is a bytecode local, otherwise null. Can be used in circumstances where
   1.596 -     * the type is irrelevant if the symbol is not a bytecode local. Note that for bytecode locals, it delegates to
   1.597 -     * {@link #getLocalVariableType(Symbol)}, so it will still assert that the type for such variable is already
   1.598 -     * defined (that is, not null).
   1.599 -     * @param symbol the symbol representing the variable.
   1.600 -     * @return the current variable type, if it is a bytecode local, otherwise null.
   1.601 -     */
   1.602 -    private LvarType getLocalVariableTypeIfBytecode(final Symbol symbol) {
   1.603 -        return symbol.isBytecodeLocal() ? getLocalVariableType(symbol) : null;
   1.604 -    }
   1.605 -
   1.606 -    /**
   1.607       * Gets the type for a variable represented by a symbol, or null if the type is not know. This is the least strict
   1.608       * of all local variable type getters, and as such its use is discouraged except in initialization scenarios (where
   1.609       * a just-defined symbol might still be null).
   1.610 @@ -1154,6 +1303,7 @@
   1.611       */
   1.612      private void leaveBreakable(final BreakableNode breakable) {
   1.613          joinOnLabel(breakable.getBreakLabel());
   1.614 +        assertTypeStackIsEmpty();
   1.615      }
   1.616  
   1.617      @Override
   1.618 @@ -1329,10 +1479,6 @@
   1.619          return conv == null || !conv.isLive();
   1.620      }
   1.621  
   1.622 -    private void onAssignment(final IdentNode identNode, final Expression rhs) {
   1.623 -        onAssignment(identNode, toLvarType(getType(rhs)));
   1.624 -    }
   1.625 -
   1.626      private void onAssignment(final IdentNode identNode, final LvarType type) {
   1.627          final Symbol symbol = identNode.getSymbol();
   1.628          assert symbol != null : identNode.getName();
   1.629 @@ -1400,13 +1546,12 @@
   1.630          jumpToCatchBlock(identNode);
   1.631      }
   1.632  
   1.633 -    private void onSelfAssignment(final IdentNode identNode, final Expression assignment, final LvarType typeOnLoad) {
   1.634 +    private void onSelfAssignment(final IdentNode identNode, final LvarType type) {
   1.635          final Symbol symbol = identNode.getSymbol();
   1.636          assert symbol != null : identNode.getName();
   1.637          if(!symbol.isBytecodeLocal()) {
   1.638              return;
   1.639          }
   1.640 -        final LvarType type = toLvarType(getType(assignment, symbol, typeOnLoad.type));
   1.641          // Self-assignment never produce either a boolean or undefined
   1.642          assert type != null && type != LvarType.UNDEFINED && type != LvarType.BOOLEAN;
   1.643          setType(symbol, type);
   1.644 @@ -1466,7 +1611,6 @@
   1.645       * @param symbol the symbol representing the variable
   1.646       * @param type the type
   1.647       */
   1.648 -    @SuppressWarnings("unused")
   1.649      private void setType(final Symbol symbol, final LvarType type) {
   1.650          if(getLocalVariableTypeOrNull(symbol) == type) {
   1.651              return;
   1.652 @@ -1486,77 +1630,4 @@
   1.653      private void symbolIsUsed(final Symbol symbol) {
   1.654          symbolIsUsed(symbol, getLocalVariableType(symbol));
   1.655      }
   1.656 -
   1.657 -    /**
   1.658 -     * Gets the type of the expression, dependent on the current types of the local variables.
   1.659 -     *
   1.660 -     * @param expr the expression
   1.661 -     * @return the current type of the expression dependent on the current types of the local variables.
   1.662 -     */
   1.663 -    private Type getType(final Expression expr) {
   1.664 -        return expr.getType(getSymbolToType());
   1.665 -    }
   1.666 -
   1.667 -    /**
   1.668 -     * Returns a function object from symbols to their types, used by the expressions to evaluate their type.
   1.669 -     * {@link BinaryNode} specifically uses identity of the function to cache type calculations. This method makes
   1.670 -     * sure to return the same function object while the local variable types don't change, and create a new function
   1.671 -     * object if the local variable types have been changed.
   1.672 -     * @return a function object representing a mapping from symbols to their types.
   1.673 -     */
   1.674 -    private Function<Symbol, Type> getSymbolToType() {
   1.675 -        if(symbolToType.isStale()) {
   1.676 -            symbolToType = new SymbolToType();
   1.677 -        }
   1.678 -        return symbolToType;
   1.679 -    }
   1.680 -
   1.681 -    private class SymbolToType implements Function<Symbol, Type> {
   1.682 -        private final Object boundTypes = localVariableTypes;
   1.683 -        @Override
   1.684 -        public Type apply(final Symbol t) {
   1.685 -            return getLocalVariableType(t).type;
   1.686 -        }
   1.687 -
   1.688 -        boolean isStale() {
   1.689 -            return boundTypes != localVariableTypes;
   1.690 -        }
   1.691 -    }
   1.692 -
   1.693 -    /**
   1.694 -     * Gets the type of the expression, dependent on the current types of the local variables and a single overridden
   1.695 -     * symbol type. Used by type calculation on compound operators to ensure the type of the LHS at the time it was
   1.696 -     * loaded (which can potentially be different after RHS evaluation, e.g. "var x; x += x = 0;") is preserved for
   1.697 -     * the calculation.
   1.698 -     *
   1.699 -     * @param expr the expression
   1.700 -     * @param overriddenSymbol the overridden symbol
   1.701 -     * @param overriddenType the overridden type
   1.702 -     * @return the current type of the expression dependent on the current types of the local variables and the single
   1.703 -     * potentially overridden type.
   1.704 -     */
   1.705 -    private Type getType(final Expression expr, final Symbol overriddenSymbol, final Type overriddenType) {
   1.706 -        return expr.getType(getSymbolToType(overriddenSymbol, overriddenType));
   1.707 -    }
   1.708 -
   1.709 -    private Function<Symbol, Type> getSymbolToType(final Symbol overriddenSymbol, final Type overriddenType) {
   1.710 -        return getLocalVariableType(overriddenSymbol).type == overriddenType ? getSymbolToType() :
   1.711 -            new SymbolToTypeOverride(overriddenSymbol, overriddenType);
   1.712 -    }
   1.713 -
   1.714 -    private class SymbolToTypeOverride implements Function<Symbol, Type> {
   1.715 -        private final Function<Symbol, Type> originalSymbolToType = getSymbolToType();
   1.716 -        private final Symbol overriddenSymbol;
   1.717 -        private final Type overriddenType;
   1.718 -
   1.719 -        SymbolToTypeOverride(final Symbol overriddenSymbol, final Type overriddenType) {
   1.720 -            this.overriddenSymbol = overriddenSymbol;
   1.721 -            this.overriddenType = overriddenType;
   1.722 -        }
   1.723 -
   1.724 -        @Override
   1.725 -        public Type apply(final Symbol symbol) {
   1.726 -            return symbol == overriddenSymbol ? overriddenType : originalSymbolToType.apply(symbol);
   1.727 -        }
   1.728 -    }
   1.729  }
     2.1 --- a/src/jdk/nashorn/internal/ir/BaseNode.java	Wed Dec 17 14:46:42 2014 -0800
     2.2 +++ b/src/jdk/nashorn/internal/ir/BaseNode.java	Mon Dec 29 19:40:21 2014 -0800
     2.3 @@ -27,7 +27,6 @@
     2.4  
     2.5  import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
     2.6  
     2.7 -import java.util.function.Function;
     2.8  import jdk.nashorn.internal.codegen.types.Type;
     2.9  import jdk.nashorn.internal.ir.annotations.Immutable;
    2.10  
    2.11 @@ -98,7 +97,7 @@
    2.12      }
    2.13  
    2.14      @Override
    2.15 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
    2.16 +    public Type getType() {
    2.17          return type == null ? getMostPessimisticType() : type;
    2.18      }
    2.19  
     3.1 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java	Wed Dec 17 14:46:42 2014 -0800
     3.2 +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java	Mon Dec 29 19:40:21 2014 -0800
     3.3 @@ -31,7 +31,6 @@
     3.4  import java.util.Collections;
     3.5  import java.util.HashSet;
     3.6  import java.util.Set;
     3.7 -import java.util.function.Function;
     3.8  import jdk.nashorn.internal.codegen.types.Type;
     3.9  import jdk.nashorn.internal.ir.annotations.Ignore;
    3.10  import jdk.nashorn.internal.ir.annotations.Immutable;
    3.11 @@ -57,9 +56,7 @@
    3.12      private final int programPoint;
    3.13  
    3.14      private final Type type;
    3.15 -
    3.16      private transient Type cachedType;
    3.17 -    private transient Object cachedTypeFunction;
    3.18  
    3.19      @Ignore
    3.20      private static final Set<TokenType> CAN_OVERFLOW =
    3.21 @@ -143,24 +140,6 @@
    3.22          }
    3.23      }
    3.24  
    3.25 -    private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
    3.26 -        @Override
    3.27 -        public Type apply(final Symbol t) {
    3.28 -            return null;
    3.29 -        }
    3.30 -    };
    3.31 -
    3.32 -    /**
    3.33 -     * Return the widest possible type for this operation. This is used for compile time
    3.34 -     * static type inference
    3.35 -     *
    3.36 -     * @return Type
    3.37 -     */
    3.38 -    @Override
    3.39 -    public Type getWidestOperationType() {
    3.40 -        return getWidestOperationType(UNKNOWN_LOCALS);
    3.41 -    }
    3.42 -
    3.43      /**
    3.44       * Return the widest possible operand type for this operation.
    3.45       *
    3.46 @@ -181,14 +160,15 @@
    3.47          }
    3.48      }
    3.49  
    3.50 -    private Type getWidestOperationType(final Function<Symbol, Type> localVariableTypes) {
    3.51 +    @Override
    3.52 +    public Type getWidestOperationType() {
    3.53          switch (tokenType()) {
    3.54          case ADD:
    3.55          case ASSIGN_ADD: {
    3.56              // Compare this logic to decideType(Type, Type); it's similar, but it handles the optimistic type
    3.57              // calculation case while this handles the conservative case.
    3.58 -            final Type lhsType = lhs.getType(localVariableTypes);
    3.59 -            final Type rhsType = rhs.getType(localVariableTypes);
    3.60 +            final Type lhsType = lhs.getType();
    3.61 +            final Type rhsType = rhs.getType();
    3.62              if(lhsType == Type.BOOLEAN && rhsType == Type.BOOLEAN) {
    3.63                  // Will always fit in an int, as the value range is [0, 1, 2]. If we didn't treat them specially here,
    3.64                  // they'd end up being treated as generic INT operands and their sum would be conservatively considered
    3.65 @@ -238,8 +218,8 @@
    3.66          case SUB:
    3.67          case ASSIGN_MUL:
    3.68          case ASSIGN_SUB: {
    3.69 -            final Type lhsType = lhs.getType(localVariableTypes);
    3.70 -            final Type rhsType = rhs.getType(localVariableTypes);
    3.71 +            final Type lhsType = lhs.getType();
    3.72 +            final Type rhsType = rhs.getType();
    3.73              if(lhsType == Type.BOOLEAN && rhsType == Type.BOOLEAN) {
    3.74                  return Type.INT;
    3.75              }
    3.76 @@ -253,20 +233,20 @@
    3.77              return Type.UNDEFINED;
    3.78          }
    3.79          case ASSIGN: {
    3.80 -            return rhs.getType(localVariableTypes);
    3.81 +            return rhs.getType();
    3.82          }
    3.83          case INSTANCEOF: {
    3.84              return Type.BOOLEAN;
    3.85          }
    3.86          case COMMALEFT: {
    3.87 -            return lhs.getType(localVariableTypes);
    3.88 +            return lhs.getType();
    3.89          }
    3.90          case COMMARIGHT: {
    3.91 -            return rhs.getType(localVariableTypes);
    3.92 +            return rhs.getType();
    3.93          }
    3.94          case AND:
    3.95          case OR:{
    3.96 -            return Type.widestReturnType(lhs.getType(localVariableTypes), rhs.getType(localVariableTypes));
    3.97 +            return Type.widestReturnType(lhs.getType(), rhs.getType());
    3.98          }
    3.99          default:
   3.100              if (isComparison()) {
   3.101 @@ -487,7 +467,7 @@
   3.102  
   3.103      /**
   3.104       * Set the right hand side expression for this node
   3.105 -     * @param rhs new left hand side expression
   3.106 +     * @param rhs new right hand side expression
   3.107       * @return a node equivalent to this one except for the requested change.
   3.108       */
   3.109      public BinaryNode setRHS(final Expression rhs) {
   3.110 @@ -497,6 +477,19 @@
   3.111          return new BinaryNode(this, lhs, rhs, type, programPoint);
   3.112      }
   3.113  
   3.114 +    /**
   3.115 +     * Set both the left and the right hand side expression for this node
   3.116 +     * @param lhs new left hand side expression
   3.117 +     * @param rhs new left hand side expression
   3.118 +     * @return a node equivalent to this one except for the requested change.
   3.119 +     */
   3.120 +    public BinaryNode setOperands(final Expression lhs, final Expression rhs) {
   3.121 +        if (this.lhs == lhs && this.rhs == rhs) {
   3.122 +            return this;
   3.123 +        }
   3.124 +        return new BinaryNode(this, lhs, rhs, type, programPoint);
   3.125 +    }
   3.126 +
   3.127      @Override
   3.128      public int getProgramPoint() {
   3.129          return programPoint;
   3.130 @@ -541,24 +534,22 @@
   3.131      }
   3.132  
   3.133      @Override
   3.134 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
   3.135 -        if(localVariableTypes == cachedTypeFunction) {
   3.136 -            return cachedType;
   3.137 +    public Type getType() {
   3.138 +        if (cachedType == null) {
   3.139 +            cachedType = getTypeUncached();
   3.140          }
   3.141 -        cachedType = getTypeUncached(localVariableTypes);
   3.142 -        cachedTypeFunction = localVariableTypes;
   3.143          return cachedType;
   3.144      }
   3.145  
   3.146 -    private Type getTypeUncached(final Function<Symbol, Type> localVariableTypes) {
   3.147 +    private Type getTypeUncached() {
   3.148          if(type == OPTIMISTIC_UNDECIDED_TYPE) {
   3.149 -            return decideType(lhs.getType(localVariableTypes), rhs.getType(localVariableTypes));
   3.150 +            return decideType(lhs.getType(), rhs.getType());
   3.151          }
   3.152 -        final Type widest = getWidestOperationType(localVariableTypes);
   3.153 +        final Type widest = getWidestOperationType();
   3.154          if(type == null) {
   3.155              return widest;
   3.156          }
   3.157 -        return Type.narrowest(widest, Type.widest(type, Type.widest(lhs.getType(localVariableTypes), rhs.getType(localVariableTypes))));
   3.158 +        return Type.narrowest(widest, Type.widest(type, Type.widest(lhs.getType(), rhs.getType())));
   3.159      }
   3.160  
   3.161      private static Type decideType(final Type lhsType, final Type rhsType) {
     4.1 --- a/src/jdk/nashorn/internal/ir/CallNode.java	Wed Dec 17 14:46:42 2014 -0800
     4.2 +++ b/src/jdk/nashorn/internal/ir/CallNode.java	Mon Dec 29 19:40:21 2014 -0800
     4.3 @@ -30,7 +30,6 @@
     4.4  import java.io.Serializable;
     4.5  import java.util.Collections;
     4.6  import java.util.List;
     4.7 -import java.util.function.Function;
     4.8  import jdk.nashorn.internal.codegen.types.Type;
     4.9  import jdk.nashorn.internal.ir.annotations.Ignore;
    4.10  import jdk.nashorn.internal.ir.annotations.Immutable;
    4.11 @@ -154,7 +153,7 @@
    4.12      }
    4.13  
    4.14      @Override
    4.15 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
    4.16 +    public Type getType() {
    4.17          return optimisticType == null ? Type.OBJECT : optimisticType;
    4.18      }
    4.19  
     5.1 --- a/src/jdk/nashorn/internal/ir/Expression.java	Wed Dec 17 14:46:42 2014 -0800
     5.2 +++ b/src/jdk/nashorn/internal/ir/Expression.java	Mon Dec 29 19:40:21 2014 -0800
     5.3 @@ -25,7 +25,6 @@
     5.4  
     5.5  package jdk.nashorn.internal.ir;
     5.6  
     5.7 -import java.util.function.Function;
     5.8  import jdk.nashorn.internal.codegen.types.Type;
     5.9  import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
    5.10  
    5.11 @@ -39,14 +38,7 @@
    5.12  
    5.13      static final String OPT_IDENTIFIER = "%";
    5.14  
    5.15 -    private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
    5.16 -        @Override
    5.17 -        public Type apply(final Symbol t) {
    5.18 -            return null;
    5.19 -        }
    5.20 -    };
    5.21 -
    5.22 -    Expression(final long token, final int start, final int finish) {
    5.23 +    protected Expression(final long token, final int start, final int finish) {
    5.24          super(token, start, finish);
    5.25      }
    5.26  
    5.27 @@ -63,18 +55,7 @@
    5.28       *
    5.29       * @return the type of the expression.
    5.30       */
    5.31 -    public final Type getType() {
    5.32 -        return getType(UNKNOWN_LOCALS);
    5.33 -    }
    5.34 -
    5.35 -    /**
    5.36 -     * Returns the type of the expression under the specified symbol-to-type mapping. By default delegates to
    5.37 -     * {@link #getType()} but expressions whose type depends on their subexpressions' types and expressions whose type
    5.38 -     * depends on symbol type ({@link IdentNode}) will have a special implementation.
    5.39 -     * @param localVariableTypes a mapping from symbols to their types, used for type calculation.
    5.40 -     * @return the type of the expression under the specified symbol-to-type mapping.
    5.41 -     */
    5.42 -    public abstract Type getType(final Function<Symbol, Type> localVariableTypes);
    5.43 +    public abstract Type getType();
    5.44  
    5.45      /**
    5.46       * Returns {@code true} if this expression depends exclusively on state that is constant
     6.1 --- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Wed Dec 17 14:46:42 2014 -0800
     6.2 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Mon Dec 29 19:40:21 2014 -0800
     6.3 @@ -36,7 +36,6 @@
     6.4  import java.util.EnumSet;
     6.5  import java.util.Iterator;
     6.6  import java.util.List;
     6.7 -import java.util.function.Function;
     6.8  import jdk.nashorn.internal.AssertsEnabled;
     6.9  import jdk.nashorn.internal.codegen.CompileUnit;
    6.10  import jdk.nashorn.internal.codegen.Compiler;
    6.11 @@ -1143,7 +1142,7 @@
    6.12      }
    6.13  
    6.14      @Override
    6.15 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
    6.16 +    public Type getType() {
    6.17          return FUNCTION_TYPE;
    6.18      }
    6.19  
     7.1 --- a/src/jdk/nashorn/internal/ir/GetSplitState.java	Wed Dec 17 14:46:42 2014 -0800
     7.2 +++ b/src/jdk/nashorn/internal/ir/GetSplitState.java	Mon Dec 29 19:40:21 2014 -0800
     7.3 @@ -25,7 +25,6 @@
     7.4  
     7.5  package jdk.nashorn.internal.ir;
     7.6  
     7.7 -import java.util.function.Function;
     7.8  import jdk.nashorn.internal.codegen.CompilerConstants;
     7.9  import jdk.nashorn.internal.codegen.types.Type;
    7.10  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    7.11 @@ -47,7 +46,7 @@
    7.12      }
    7.13  
    7.14      @Override
    7.15 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
    7.16 +    public Type getType() {
    7.17          return Type.INT;
    7.18      }
    7.19  
     8.1 --- a/src/jdk/nashorn/internal/ir/IdentNode.java	Wed Dec 17 14:46:42 2014 -0800
     8.2 +++ b/src/jdk/nashorn/internal/ir/IdentNode.java	Mon Dec 29 19:40:21 2014 -0800
     8.3 @@ -30,7 +30,6 @@
     8.4  import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__;
     8.5  import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
     8.6  
     8.7 -import java.util.function.Function;
     8.8  import jdk.nashorn.internal.codegen.types.Type;
     8.9  import jdk.nashorn.internal.ir.annotations.Immutable;
    8.10  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    8.11 @@ -118,14 +117,13 @@
    8.12      }
    8.13  
    8.14      @Override
    8.15 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
    8.16 +    public Type getType() {
    8.17          if(type != null) {
    8.18              return type;
    8.19          } else if(symbol != null && symbol.isScope()) {
    8.20              return Type.OBJECT;
    8.21          }
    8.22 -        final Type symbolType = localVariableTypes.apply(symbol);
    8.23 -        return symbolType == null ? Type.UNDEFINED : symbolType;
    8.24 +        return Type.UNDEFINED;
    8.25      }
    8.26  
    8.27      /**
     9.1 --- a/src/jdk/nashorn/internal/ir/JoinPredecessorExpression.java	Wed Dec 17 14:46:42 2014 -0800
     9.2 +++ b/src/jdk/nashorn/internal/ir/JoinPredecessorExpression.java	Mon Dec 29 19:40:21 2014 -0800
     9.3 @@ -25,7 +25,6 @@
     9.4  
     9.5  package jdk.nashorn.internal.ir;
     9.6  
     9.7 -import java.util.function.Function;
     9.8  import jdk.nashorn.internal.codegen.types.Type;
     9.9  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    9.10  
    9.11 @@ -71,8 +70,8 @@
    9.12      }
    9.13  
    9.14      @Override
    9.15 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
    9.16 -        return expression.getType(localVariableTypes);
    9.17 +    public Type getType() {
    9.18 +        return expression.getType();
    9.19      }
    9.20  
    9.21      @Override
    10.1 --- a/src/jdk/nashorn/internal/ir/LiteralNode.java	Wed Dec 17 14:46:42 2014 -0800
    10.2 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java	Mon Dec 29 19:40:21 2014 -0800
    10.3 @@ -29,7 +29,6 @@
    10.4  import java.util.Arrays;
    10.5  import java.util.Collections;
    10.6  import java.util.List;
    10.7 -import java.util.function.Function;
    10.8  import jdk.nashorn.internal.codegen.CompileUnit;
    10.9  import jdk.nashorn.internal.codegen.types.ArrayType;
   10.10  import jdk.nashorn.internal.codegen.types.Type;
   10.11 @@ -109,7 +108,7 @@
   10.12      }
   10.13  
   10.14      @Override
   10.15 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
   10.16 +    public Type getType() {
   10.17          return Type.typeFor(value.getClass());
   10.18      }
   10.19  
   10.20 @@ -164,16 +163,6 @@
   10.21      }
   10.22  
   10.23      /**
   10.24 -     * Get the array value of the node
   10.25 -     *
   10.26 -     * @return the array value
   10.27 -     */
   10.28 -    public Node[] getArray() {
   10.29 -        assert false : "not an array node";
   10.30 -        return null;
   10.31 -    }
   10.32 -
   10.33 -    /**
   10.34       * Fetch String value of node.
   10.35       *
   10.36       * @return String value of node.
   10.37 @@ -325,7 +314,7 @@
   10.38          }
   10.39  
   10.40          @Override
   10.41 -        public Type getType(final Function<Symbol, Type> localVariableTypes) {
   10.42 +        public Type getType() {
   10.43              return Type.BOOLEAN;
   10.44          }
   10.45  
   10.46 @@ -389,7 +378,7 @@
   10.47          }
   10.48  
   10.49          @Override
   10.50 -        public Type getType(final Function<Symbol, Type> localVariableTypes) {
   10.51 +        public Type getType() {
   10.52              return type;
   10.53          }
   10.54  
   10.55 @@ -519,7 +508,7 @@
   10.56          }
   10.57  
   10.58          @Override
   10.59 -        public Type getType(final Function<Symbol, Type> localVariableTypes) {
   10.60 +        public Type getType() {
   10.61              return Type.OBJECT;
   10.62          }
   10.63  
   10.64 @@ -589,7 +578,7 @@
   10.65          }
   10.66  
   10.67          @Override
   10.68 -        public Type getType(final Function<Symbol, Type> localVariableTypes) {
   10.69 +        public Type getType() {
   10.70              return Type.OBJECT;
   10.71          }
   10.72  
   10.73 @@ -840,9 +829,13 @@
   10.74              this.units       = units;
   10.75          }
   10.76  
   10.77 -        @Override
   10.78 -        public Node[] getArray() {
   10.79 -            return value;
   10.80 +        /**
   10.81 +         * Returns a list of array element expressions. Note that empty array elements manifest themselves as
   10.82 +         * null.
   10.83 +         * @return a list of array element expressions.
   10.84 +         */
   10.85 +        public List<Expression> getElementExpressions() {
   10.86 +            return Collections.unmodifiableList(Arrays.asList(value));
   10.87          }
   10.88  
   10.89          /**
   10.90 @@ -879,7 +872,7 @@
   10.91          }
   10.92  
   10.93          @Override
   10.94 -        public Type getType(final Function<Symbol, Type> localVariableTypes) {
   10.95 +        public Type getType() {
   10.96              return Type.typeFor(NativeArray.class);
   10.97          }
   10.98  
    11.1 --- a/src/jdk/nashorn/internal/ir/ObjectNode.java	Wed Dec 17 14:46:42 2014 -0800
    11.2 +++ b/src/jdk/nashorn/internal/ir/ObjectNode.java	Mon Dec 29 19:40:21 2014 -0800
    11.3 @@ -27,7 +27,6 @@
    11.4  
    11.5  import java.util.Collections;
    11.6  import java.util.List;
    11.7 -import java.util.function.Function;
    11.8  import jdk.nashorn.internal.codegen.types.Type;
    11.9  import jdk.nashorn.internal.ir.annotations.Immutable;
   11.10  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   11.11 @@ -69,7 +68,7 @@
   11.12      }
   11.13  
   11.14      @Override
   11.15 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
   11.16 +    public Type getType() {
   11.17          return Type.OBJECT;
   11.18      }
   11.19  
    12.1 --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java	Wed Dec 17 14:46:42 2014 -0800
    12.2 +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java	Mon Dec 29 19:40:21 2014 -0800
    12.3 @@ -30,7 +30,6 @@
    12.4  import java.util.Arrays;
    12.5  import java.util.Collections;
    12.6  import java.util.List;
    12.7 -import java.util.function.Function;
    12.8  import jdk.nashorn.internal.codegen.types.Type;
    12.9  import jdk.nashorn.internal.ir.annotations.Immutable;
   12.10  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   12.11 @@ -460,7 +459,7 @@
   12.12       * Return type for the ReferenceNode
   12.13       */
   12.14      @Override
   12.15 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
   12.16 +    public Type getType() {
   12.17          return request.getReturnType();
   12.18      }
   12.19  
    13.1 --- a/src/jdk/nashorn/internal/ir/TernaryNode.java	Wed Dec 17 14:46:42 2014 -0800
    13.2 +++ b/src/jdk/nashorn/internal/ir/TernaryNode.java	Mon Dec 29 19:40:21 2014 -0800
    13.3 @@ -25,7 +25,6 @@
    13.4  
    13.5  package jdk.nashorn.internal.ir;
    13.6  
    13.7 -import java.util.function.Function;
    13.8  import jdk.nashorn.internal.codegen.types.Type;
    13.9  import jdk.nashorn.internal.ir.annotations.Immutable;
   13.10  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   13.11 @@ -122,8 +121,8 @@
   13.12      }
   13.13  
   13.14      @Override
   13.15 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
   13.16 -        return Type.widestReturnType(getTrueExpression().getType(localVariableTypes), getFalseExpression().getType(localVariableTypes));
   13.17 +    public Type getType() {
   13.18 +        return Type.widestReturnType(getTrueExpression().getType(), getFalseExpression().getType());
   13.19      }
   13.20  
   13.21  
    14.1 --- a/src/jdk/nashorn/internal/ir/UnaryNode.java	Wed Dec 17 14:46:42 2014 -0800
    14.2 +++ b/src/jdk/nashorn/internal/ir/UnaryNode.java	Mon Dec 29 19:40:21 2014 -0800
    14.3 @@ -33,7 +33,6 @@
    14.4  import java.util.Arrays;
    14.5  import java.util.Collections;
    14.6  import java.util.List;
    14.7 -import java.util.function.Function;
    14.8  import jdk.nashorn.internal.codegen.types.Type;
    14.9  import jdk.nashorn.internal.ir.annotations.Ignore;
   14.10  import jdk.nashorn.internal.ir.annotations.Immutable;
   14.11 @@ -123,23 +122,11 @@
   14.12          return isAssignment();
   14.13      }
   14.14  
   14.15 -    private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
   14.16 -        @Override
   14.17 -        public Type apply(final Symbol t) {
   14.18 -            return null;
   14.19 -        }
   14.20 -    };
   14.21 -
   14.22 -
   14.23      @Override
   14.24      public Type getWidestOperationType() {
   14.25 -        return getWidestOperationType(UNKNOWN_LOCALS);
   14.26 -    }
   14.27 -
   14.28 -    private Type getWidestOperationType(final Function<Symbol, Type> localVariableTypes) {
   14.29          switch (tokenType()) {
   14.30          case ADD:
   14.31 -            final Type operandType = getExpression().getType(localVariableTypes);
   14.32 +            final Type operandType = getExpression().getType();
   14.33              if(operandType == Type.BOOLEAN) {
   14.34                  return Type.INT;
   14.35              } else if(operandType.isObject()) {
   14.36 @@ -326,12 +313,12 @@
   14.37      }
   14.38  
   14.39      @Override
   14.40 -    public Type getType(final Function<Symbol, Type> localVariableTypes) {
   14.41 -        final Type widest = getWidestOperationType(localVariableTypes);
   14.42 +    public Type getType() {
   14.43 +        final Type widest = getWidestOperationType();
   14.44          if(type == null) {
   14.45              return widest;
   14.46          }
   14.47 -        return Type.narrowest(widest, Type.widest(type, expression.getType(localVariableTypes)));
   14.48 +        return Type.narrowest(widest, Type.widest(type, expression.getType()));
   14.49      }
   14.50  
   14.51      @Override
    15.1 --- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Wed Dec 17 14:46:42 2014 -0800
    15.2 +++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Mon Dec 29 19:40:21 2014 -0800
    15.3 @@ -28,7 +28,6 @@
    15.4  import static jdk.nashorn.internal.runtime.Source.sourceFor;
    15.5  
    15.6  import java.util.ArrayList;
    15.7 -import java.util.Arrays;
    15.8  import java.util.List;
    15.9  import jdk.nashorn.internal.ir.AccessNode;
   15.10  import jdk.nashorn.internal.ir.BinaryNode;
   15.11 @@ -553,8 +552,7 @@
   15.12              type("ArrayExpression");
   15.13              comma();
   15.14  
   15.15 -            final Node[] value = literalNode.getArray();
   15.16 -            array("elements", Arrays.asList(value));
   15.17 +            array("elements", ((LiteralNode.ArrayLiteralNode)literalNode).getElementExpressions());
   15.18          } else {
   15.19              type("Literal");
   15.20              comma();
    16.1 --- a/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java	Wed Dec 17 14:46:42 2014 -0800
    16.2 +++ b/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java	Mon Dec 29 19:40:21 2014 -0800
    16.3 @@ -99,7 +99,7 @@
    16.4          MethodType newMethodType = descriptor.getMethodType().changeParameterType(0, callable.getClass());
    16.5          if (isCall) {
    16.6              // R(callable.class, T1, ...) => R(callable.class, boundThis.class, ...)
    16.7 -            newMethodType = newMethodType.changeParameterType(1, boundThis.getClass());
    16.8 +            newMethodType = newMethodType.changeParameterType(1, boundThis == null? Object.class : boundThis.getClass());
    16.9          }
   16.10          // R(callable.class[, boundThis.class], T2, ...) => R(callable.class[, boundThis.class], boundArg0.class, ..., boundArgn.class, T2, ...)
   16.11          for(int i = boundArgs.length; i-- > 0;) {
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/test/script/basic/JDK-8067774.js	Mon Dec 29 19:40:21 2014 -0800
    17.3 @@ -0,0 +1,37 @@
    17.4 +/*
    17.5 + * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
    17.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    17.7 + * 
    17.8 + * This code is free software; you can redistribute it and/or modify it
    17.9 + * under the terms of the GNU General Public License version 2 only, as
   17.10 + * published by the Free Software Foundation.
   17.11 + * 
   17.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   17.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   17.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   17.15 + * version 2 for more details (a copy is included in the LICENSE file that
   17.16 + * accompanied this code).
   17.17 + * 
   17.18 + * You should have received a copy of the GNU General Public License version
   17.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   17.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   17.21 + * 
   17.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   17.23 + * or visit www.oracle.com if you need additional information or have any
   17.24 + * questions.
   17.25 + */
   17.26 +
   17.27 +/**
   17.28 + * JDK-8067774: Use a stack of types when calculating local variable types
   17.29 + *
   17.30 + * @test
   17.31 + * @run
   17.32 + */
   17.33 +
   17.34 +print((function (p) {
   17.35 +    var a, b;
   17.36 +    
   17.37 +    a = p ? ((b = 1), b) : 0;
   17.38 +
   17.39 +    return a;
   17.40 +})(true));
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/test/script/basic/JDK-8067774.js.EXPECTED	Mon Dec 29 19:40:21 2014 -0800
    18.3 @@ -0,0 +1,1 @@
    18.4 +1
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/test/script/trusted/JDK-8067854.js	Mon Dec 29 19:40:21 2014 -0800
    19.3 @@ -0,0 +1,39 @@
    19.4 +/*
    19.5 + * Copyright (c) 2014, 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 + * JDK-8067854: bound java static method throws NPE when 'null' is used for this argument
   19.29 + *
   19.30 + * @test
   19.31 + * @run
   19.32 + */
   19.33 +
   19.34 +getProp = java.lang.System.getProperty;
   19.35 +
   19.36 +// bind this and an argument. "null" for this as getProperty is a
   19.37 +// static method of java.lang.System
   19.38 +getHome = Function.prototype.bind.call(getProp, null, "java.home");
   19.39 +
   19.40 +if (getHome() != getProp("java.home")) {
   19.41 +    fail("getHome() failed to get java.home");
   19.42 +}

mercurial