OptimisticTypesCalculator.java revision 1655:3ac5d360070e
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.IdentNode;
42import jdk.nashorn.internal.ir.IfNode;
43import jdk.nashorn.internal.ir.IndexNode;
44import jdk.nashorn.internal.ir.JoinPredecessorExpression;
45import jdk.nashorn.internal.ir.LoopNode;
46import jdk.nashorn.internal.ir.Node;
47import 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            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.isForInOrOf()) {
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}
255