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