OptimisticTypesCalculator.java revision 1070:34d55faf0b3a
1/* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.nashorn.internal.codegen; 27 28import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; 29 30import java.util.ArrayDeque; 31import java.util.BitSet; 32import java.util.Deque; 33import jdk.nashorn.internal.ir.AccessNode; 34import jdk.nashorn.internal.ir.BinaryNode; 35import jdk.nashorn.internal.ir.CallNode; 36import jdk.nashorn.internal.ir.CatchNode; 37import jdk.nashorn.internal.ir.Expression; 38import jdk.nashorn.internal.ir.ExpressionStatement; 39import jdk.nashorn.internal.ir.ForNode; 40import jdk.nashorn.internal.ir.FunctionNode; 41import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 42import jdk.nashorn.internal.ir.IdentNode; 43import jdk.nashorn.internal.ir.IfNode; 44import jdk.nashorn.internal.ir.IndexNode; 45import jdk.nashorn.internal.ir.JoinPredecessorExpression; 46import jdk.nashorn.internal.ir.LexicalContext; 47import jdk.nashorn.internal.ir.LoopNode; 48import jdk.nashorn.internal.ir.Node; 49import jdk.nashorn.internal.ir.Optimistic; 50import jdk.nashorn.internal.ir.PropertyNode; 51import jdk.nashorn.internal.ir.Symbol; 52import jdk.nashorn.internal.ir.TernaryNode; 53import jdk.nashorn.internal.ir.UnaryNode; 54import jdk.nashorn.internal.ir.VarNode; 55import jdk.nashorn.internal.ir.WhileNode; 56import jdk.nashorn.internal.ir.visitor.NodeVisitor; 57import jdk.nashorn.internal.parser.TokenType; 58import jdk.nashorn.internal.runtime.ScriptObject; 59 60/** 61 * Assigns optimistic types to expressions that can have them. This class mainly contains logic for which expressions 62 * must not ever be marked as optimistic, assigning narrowest non-invalidated types to program points from the 63 * compilation environment, as well as initializing optimistic types of global properties for scripts. 64 */ 65final class OptimisticTypesCalculator extends NodeVisitor<LexicalContext> { 66 67 final Compiler compiler; 68 69 // Per-function bit set of program points that must never be optimistic. 70 final Deque<BitSet> neverOptimistic = new ArrayDeque<>(); 71 72 OptimisticTypesCalculator(final Compiler compiler) { 73 super(new LexicalContext()); 74 this.compiler = compiler; 75 } 76 77 @Override 78 public boolean enterAccessNode(final AccessNode accessNode) { 79 tagNeverOptimistic(accessNode.getBase()); 80 return true; 81 } 82 83 @Override 84 public boolean enterPropertyNode(final PropertyNode propertyNode) { 85 if(propertyNode.getKeyName().equals(ScriptObject.PROTO_PROPERTY_NAME)) { 86 tagNeverOptimistic(propertyNode.getValue()); 87 } 88 return super.enterPropertyNode(propertyNode); 89 } 90 91 @Override 92 public boolean enterBinaryNode(final BinaryNode binaryNode) { 93 if(binaryNode.isAssignment()) { 94 final Expression lhs = binaryNode.lhs(); 95 if(!binaryNode.isSelfModifying()) { 96 tagNeverOptimistic(lhs); 97 } 98 if(lhs instanceof IdentNode) { 99 final Symbol symbol = ((IdentNode)lhs).getSymbol(); 100 // Assignment to internal symbols is never optimistic, except for self-assignment expressions 101 if(symbol.isInternal() && !binaryNode.rhs().isSelfModifying()) { 102 tagNeverOptimistic(binaryNode.rhs()); 103 } 104 } 105 } else if(binaryNode.isTokenType(TokenType.INSTANCEOF)) { 106 tagNeverOptimistic(binaryNode.lhs()); 107 tagNeverOptimistic(binaryNode.rhs()); 108 } 109 return true; 110 } 111 112 @Override 113 public boolean enterCallNode(final CallNode callNode) { 114 tagNeverOptimistic(callNode.getFunction()); 115 return true; 116 } 117 118 @Override 119 public boolean enterCatchNode(final CatchNode catchNode) { 120 // Condition is never optimistic (always coerced to boolean). 121 tagNeverOptimistic(catchNode.getExceptionCondition()); 122 return true; 123 } 124 125 @Override 126 public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) { 127 final Expression expr = expressionStatement.getExpression(); 128 if(!expr.isSelfModifying()) { 129 tagNeverOptimistic(expr); 130 } 131 return true; 132 } 133 134 @Override 135 public boolean enterForNode(final ForNode forNode) { 136 if(forNode.isForIn()) { 137 // for..in has the iterable in its "modify" 138 tagNeverOptimistic(forNode.getModify()); 139 } else { 140 // Test is never optimistic (always coerced to boolean). 141 tagNeverOptimisticLoopTest(forNode); 142 } 143 return true; 144 } 145 146 @Override 147 public boolean enterFunctionNode(final FunctionNode functionNode) { 148 if (!neverOptimistic.isEmpty() && compiler.isOnDemandCompilation()) { 149 // This is a nested function, and we're doing on-demand compilation. In these compilations, we never descend 150 // into nested functions. 151 return false; 152 } 153 neverOptimistic.push(new BitSet()); 154 return true; 155 } 156 157 @Override 158 public boolean enterIfNode(final IfNode ifNode) { 159 // Test is never optimistic (always coerced to boolean). 160 tagNeverOptimistic(ifNode.getTest()); 161 return true; 162 } 163 164 @Override 165 public boolean enterIndexNode(final IndexNode indexNode) { 166 tagNeverOptimistic(indexNode.getBase()); 167 return true; 168 } 169 170 @Override 171 public boolean enterTernaryNode(final TernaryNode ternaryNode) { 172 // Test is never optimistic (always coerced to boolean). 173 tagNeverOptimistic(ternaryNode.getTest()); 174 return true; 175 } 176 177 @Override 178 public boolean enterUnaryNode(final UnaryNode unaryNode) { 179 if(unaryNode.isTokenType(TokenType.NOT) || unaryNode.isTokenType(TokenType.NEW)) { 180 // Operand of boolean negation is never optimistic (always coerced to boolean). 181 // Operand of "new" is never optimistic (always coerced to Object). 182 tagNeverOptimistic(unaryNode.getExpression()); 183 } 184 return true; 185 } 186 187 @Override 188 public boolean enterVarNode(final VarNode varNode) { 189 tagNeverOptimistic(varNode.getName()); 190 return true; 191 } 192 193 @Override 194 public boolean enterWhileNode(final WhileNode whileNode) { 195 // Test is never optimistic (always coerced to boolean). 196 tagNeverOptimisticLoopTest(whileNode); 197 return true; 198 } 199 200 @Override 201 protected Node leaveDefault(final Node node) { 202 if(node instanceof Optimistic) { 203 return leaveOptimistic((Optimistic)node); 204 } 205 return node; 206 } 207 208 @Override 209 public Node leaveFunctionNode(final FunctionNode functionNode) { 210 neverOptimistic.pop(); 211 return functionNode.setState(lc, CompilationState.OPTIMISTIC_TYPES_ASSIGNED); 212 } 213 214 @Override 215 public Node leaveIdentNode(final IdentNode identNode) { 216 final Symbol symbol = identNode.getSymbol(); 217 if(symbol == null) { 218 assert identNode.isPropertyName(); 219 return identNode; 220 } else if(symbol.isBytecodeLocal()) { 221 // Identifiers accessing bytecode local variables will never be optimistic, as type calculation phase over 222 // them will always assign them statically provable types. Note that access to function parameters can still 223 // be optimistic if the parameter needs to be in scope as it's used by a nested function. 224 return identNode; 225 } else if(symbol.isParam() && lc.getCurrentFunction().isVarArg()) { 226 // Parameters in vararg methods are not optimistic; we always access them using Object getters. 227 return identNode.setType(identNode.getMostPessimisticType()); 228 } else { 229 assert symbol.isScope(); 230 return leaveOptimistic(identNode); 231 } 232 } 233 234 private Expression leaveOptimistic(final Optimistic opt) { 235 final int pp = opt.getProgramPoint(); 236 if(isValid(pp) && !neverOptimistic.peek().get(pp)) { 237 return (Expression)opt.setType(compiler.getOptimisticType(opt)); 238 } 239 return (Expression)opt; 240 } 241 242 private void tagNeverOptimistic(final Expression expr) { 243 if(expr instanceof Optimistic) { 244 final int pp = ((Optimistic)expr).getProgramPoint(); 245 if(isValid(pp)) { 246 neverOptimistic.peek().set(pp); 247 } 248 } 249 } 250 251 private void tagNeverOptimisticLoopTest(final LoopNode loopNode) { 252 final JoinPredecessorExpression test = loopNode.getTest(); 253 if(test != null) { 254 tagNeverOptimistic(test.getExpression()); 255 } 256 } 257} 258