Mon, 29 Dec 2014 19:40:21 -0800
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 +}