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
26 package jdk.nashorn.internal.codegen;
27
28 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
29
30 import java.util.ArrayDeque;
31 import java.util.BitSet;
32 import java.util.Deque;
33 import jdk.nashorn.internal.ir.AccessNode;
34 import jdk.nashorn.internal.ir.BinaryNode;
35 import jdk.nashorn.internal.ir.CallNode;
36 import jdk.nashorn.internal.ir.CatchNode;
37 import jdk.nashorn.internal.ir.Expression;
38 import jdk.nashorn.internal.ir.ExpressionStatement;
39 import jdk.nashorn.internal.ir.ForNode;
40 import jdk.nashorn.internal.ir.FunctionNode;
41 import jdk.nashorn.internal.ir.IdentNode;
42 import jdk.nashorn.internal.ir.IfNode;
43 import jdk.nashorn.internal.ir.IndexNode;
44 import jdk.nashorn.internal.ir.JoinPredecessorExpression;
45 import jdk.nashorn.internal.ir.LoopNode;
46 import jdk.nashorn.internal.ir.Node;
47 import jdk.nashorn.internal.ir.Optimistic;
48 import jdk.nashorn.internal.ir.PropertyNode;
49 import jdk.nashorn.internal.ir.Symbol;
50 import jdk.nashorn.internal.ir.TernaryNode;
51 import jdk.nashorn.internal.ir.UnaryNode;
52 import jdk.nashorn.internal.ir.VarNode;
53 import jdk.nashorn.internal.ir.WhileNode;
54 import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
55 import jdk.nashorn.internal.parser.TokenType;
56 import 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 */
63 final 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 tagNeverOptimistic(binaryNode.lhs());
104 tagNeverOptimistic(binaryNode.rhs());
105 }
106 return true;
107 }
108
109 @Override
110 public boolean enterCallNode(final CallNode callNode) {
111 tagNeverOptimistic(callNode.getFunction());
112 return true;
113 }
114
115 @Override
116 public boolean enterCatchNode(final CatchNode catchNode) {
117 // Condition is never optimistic (always coerced to boolean).
118 tagNeverOptimistic(catchNode.getExceptionCondition());
119 return true;
120 }
121
122 @Override
123 public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
124 final Expression expr = expressionStatement.getExpression();
125 if(!expr.isSelfModifying()) {
126 tagNeverOptimistic(expr);
127 }
128 return true;
129 }
130
131 @Override
132 public boolean enterForNode(final ForNode forNode) {
133 if(forNode.isForIn() || forNode.isForOf()) {
134 // for..in has the iterable in its "modify"
135 tagNeverOptimistic(forNode.getModify());
136 } else {
137 // Test is never optimistic (always coerced to boolean).
138 tagNeverOptimisticLoopTest(forNode);
139 }
140 return true;
141 }
142
143 @Override
144 public boolean enterFunctionNode(final FunctionNode functionNode) {
145 if (!neverOptimistic.isEmpty() && compiler.isOnDemandCompilation()) {
146 // This is a nested function, and we're doing on-demand compilation. In these compilations, we never descend
147 // into nested functions.
148 return false;
149 }
150 neverOptimistic.push(new BitSet());
151 return true;
152 }
153
154 @Override
155 public boolean enterIfNode(final IfNode ifNode) {
156 // Test is never optimistic (always coerced to boolean).
157 tagNeverOptimistic(ifNode.getTest());
158 return true;
159 }
160
161 @Override
162 public boolean enterIndexNode(final IndexNode indexNode) {
163 tagNeverOptimistic(indexNode.getBase());
164 return true;
165 }
166
167 @Override
168 public boolean enterTernaryNode(final TernaryNode ternaryNode) {
169 // Test is never optimistic (always coerced to boolean).
170 tagNeverOptimistic(ternaryNode.getTest());
171 return true;
172 }
173
174 @Override
175 public boolean enterUnaryNode(final UnaryNode unaryNode) {
176 if(unaryNode.isTokenType(TokenType.NOT) || unaryNode.isTokenType(TokenType.NEW)) {
177 // Operand of boolean negation is never optimistic (always coerced to boolean).
178 // Operand of "new" is never optimistic (always coerced to Object).
179 tagNeverOptimistic(unaryNode.getExpression());
180 }
181 return true;
182 }
183
184 @Override
185 public boolean enterVarNode(final VarNode varNode) {
186 tagNeverOptimistic(varNode.getName());
187 return true;
188 }
189
190 @Override
191 public boolean enterWhileNode(final WhileNode whileNode) {
192 // Test is never optimistic (always coerced to boolean).
193 tagNeverOptimisticLoopTest(whileNode);
194 return true;
195 }
196
197 @Override
198 protected Node leaveDefault(final Node node) {
199 if(node instanceof Optimistic) {
200 return leaveOptimistic((Optimistic)node);
201 }
202 return node;
203 }
204
205 @Override
206 public Node leaveFunctionNode(final FunctionNode functionNode) {
207 neverOptimistic.pop();
208 return functionNode;
209 }
210
211 @Override
212 public Node leaveIdentNode(final IdentNode identNode) {
213 final Symbol symbol = identNode.getSymbol();
214 if(symbol == null) {
215 assert identNode.isPropertyName();
216 return identNode;
217 } else if(symbol.isBytecodeLocal()) {
218 // Identifiers accessing bytecode local variables will never be optimistic, as type calculation phase over
219 // them will always assign them statically provable types. Note that access to function parameters can still
220 // be optimistic if the parameter needs to be in scope as it's used by a nested function.
221 return identNode;
222 } else if(symbol.isParam() && lc.getCurrentFunction().isVarArg()) {
223 // Parameters in vararg methods are not optimistic; we always access them using Object getters.
224 return identNode.setType(identNode.getMostPessimisticType());
225 } else {
226 assert symbol.isScope();
227 return leaveOptimistic(identNode);
228 }
229 }
230
231 private Expression leaveOptimistic(final Optimistic opt) {
232 final int pp = opt.getProgramPoint();
233 if(isValid(pp) && !neverOptimistic.peek().get(pp)) {
234 return (Expression)opt.setType(compiler.getOptimisticType(opt));
235 }
236 return (Expression)opt;
237 }
238
239 private void tagNeverOptimistic(final Expression expr) {
240 if(expr instanceof Optimistic) {
241 final int pp = ((Optimistic)expr).getProgramPoint();
242 if(isValid(pp)) {
243 neverOptimistic.peek().set(pp);
244 }
245 }
246 }
247
248 private void tagNeverOptimisticLoopTest(final LoopNode loopNode) {
249 final JoinPredecessorExpression test = loopNode.getTest();
250 if(test != null) {
251 tagNeverOptimistic(test.getExpression());
252 }
253 }
254 }
--- EOF ---