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