1/*
2 * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#if ENABLE(DFG_JIT)
29
30#include "DFGAbstractValue.h"
31#include "DFGGraph.h"
32#include "DFGNode.h"
33#include "DFGNodeFlowProjection.h"
34#include "DFGPhiChildren.h"
35
36namespace JSC { namespace DFG {
37
38template<typename AbstractStateType>
39class AbstractInterpreter {
40 WTF_MAKE_FAST_ALLOCATED;
41public:
42 AbstractInterpreter(Graph&, AbstractStateType&);
43 ~AbstractInterpreter();
44
45 ALWAYS_INLINE AbstractValue& forNode(NodeFlowProjection node)
46 {
47 return m_state.forNode(node);
48 }
49
50 ALWAYS_INLINE AbstractValue& forNode(Edge edge)
51 {
52 return forNode(edge.node());
53 }
54
55 ALWAYS_INLINE void clearForNode(NodeFlowProjection node)
56 {
57 m_state.clearForNode(node);
58 }
59
60 ALWAYS_INLINE void clearForNode(Edge edge)
61 {
62 clearForNode(edge.node());
63 }
64
65 template<typename... Arguments>
66 ALWAYS_INLINE void setForNode(NodeFlowProjection node, Arguments&&... arguments)
67 {
68 m_state.setForNode(node, std::forward<Arguments>(arguments)...);
69 }
70
71 template<typename... Arguments>
72 ALWAYS_INLINE void setForNode(Edge edge, Arguments&&... arguments)
73 {
74 setForNode(edge.node(), std::forward<Arguments>(arguments)...);
75 }
76
77 template<typename... Arguments>
78 ALWAYS_INLINE void setTypeForNode(NodeFlowProjection node, Arguments&&... arguments)
79 {
80 m_state.setTypeForNode(node, std::forward<Arguments>(arguments)...);
81 }
82
83 template<typename... Arguments>
84 ALWAYS_INLINE void setTypeForNode(Edge edge, Arguments&&... arguments)
85 {
86 setTypeForNode(edge.node(), std::forward<Arguments>(arguments)...);
87 }
88
89 template<typename... Arguments>
90 ALWAYS_INLINE void setNonCellTypeForNode(NodeFlowProjection node, Arguments&&... arguments)
91 {
92 m_state.setNonCellTypeForNode(node, std::forward<Arguments>(arguments)...);
93 }
94
95 template<typename... Arguments>
96 ALWAYS_INLINE void setNonCellTypeForNode(Edge edge, Arguments&&... arguments)
97 {
98 setNonCellTypeForNode(edge.node(), std::forward<Arguments>(arguments)...);
99 }
100
101 ALWAYS_INLINE void makeBytecodeTopForNode(NodeFlowProjection node)
102 {
103 m_state.makeBytecodeTopForNode(node);
104 }
105
106 ALWAYS_INLINE void makeBytecodeTopForNode(Edge edge)
107 {
108 makeBytecodeTopForNode(edge.node());
109 }
110
111 ALWAYS_INLINE void makeHeapTopForNode(NodeFlowProjection node)
112 {
113 m_state.makeHeapTopForNode(node);
114 }
115
116 ALWAYS_INLINE void makeHeapTopForNode(Edge edge)
117 {
118 makeHeapTopForNode(edge.node());
119 }
120
121 bool needsTypeCheck(Node* node, SpeculatedType typesPassedThrough)
122 {
123 return !forNode(node).isType(typesPassedThrough);
124 }
125
126 bool needsTypeCheck(Edge edge, SpeculatedType typesPassedThrough)
127 {
128 return needsTypeCheck(edge.node(), typesPassedThrough);
129 }
130
131 bool needsTypeCheck(Edge edge)
132 {
133 return needsTypeCheck(edge, typeFilterFor(edge.useKind()));
134 }
135
136 // Abstractly executes the given node. The new abstract state is stored into an
137 // abstract stack stored in *this. Loads of local variables (that span
138 // basic blocks) interrogate the basic block's notion of the state at the head.
139 // Stores to local variables are handled in endBasicBlock(). This returns true
140 // if execution should continue past this node. Notably, it will return true
141 // for block terminals, so long as those terminals are not Return or Unreachable.
142 //
143 // This is guaranteed to be equivalent to doing:
144 //
145 // state.startExecuting()
146 // state.executeEdges(node);
147 // result = state.executeEffects(index);
148 bool execute(unsigned indexInBlock);
149 bool execute(Node*);
150
151 // Indicate the start of execution of a node. It resets any state in the node
152 // that is progressively built up by executeEdges() and executeEffects().
153 void startExecuting();
154
155 // Abstractly execute the edges of the given node. This runs filterEdgeByUse()
156 // on all edges of the node. You can skip this step, if you have already used
157 // filterEdgeByUse() (or some equivalent) on each edge.
158 void executeEdges(Node*);
159
160 void executeKnownEdgeTypes(Node*);
161
162 ALWAYS_INLINE void filterEdgeByUse(Edge& edge)
163 {
164 UseKind useKind = edge.useKind();
165 if (useKind == UntypedUse)
166 return;
167 filterByType(edge, typeFilterFor(useKind));
168 }
169
170 // Abstractly execute the effects of the given node. This changes the abstract
171 // state assuming that edges have already been filtered.
172 bool executeEffects(unsigned indexInBlock);
173 bool executeEffects(unsigned clobberLimit, Node*);
174
175 void dump(PrintStream& out) const;
176 void dump(PrintStream& out);
177
178 template<typename T>
179 FiltrationResult filter(T node, const RegisteredStructureSet& set, SpeculatedType admittedTypes = SpecNone)
180 {
181 return filter(forNode(node), set, admittedTypes);
182 }
183
184 template<typename T>
185 FiltrationResult filterArrayModes(T node, ArrayModes arrayModes)
186 {
187 return filterArrayModes(forNode(node), arrayModes);
188 }
189
190 template<typename T>
191 FiltrationResult filter(T node, SpeculatedType type)
192 {
193 return filter(forNode(node), type);
194 }
195
196 template<typename T>
197 FiltrationResult filterByValue(T node, FrozenValue value)
198 {
199 return filterByValue(forNode(node), value);
200 }
201
202 template<typename T>
203 FiltrationResult filterClassInfo(T node, const ClassInfo* classInfo)
204 {
205 return filterClassInfo(forNode(node), classInfo);
206 }
207
208 FiltrationResult filter(AbstractValue&, const RegisteredStructureSet&, SpeculatedType admittedTypes = SpecNone);
209 FiltrationResult filterArrayModes(AbstractValue&, ArrayModes);
210 FiltrationResult filter(AbstractValue&, SpeculatedType);
211 FiltrationResult filterByValue(AbstractValue&, FrozenValue);
212 FiltrationResult filterClassInfo(AbstractValue&, const ClassInfo*);
213
214 PhiChildren* phiChildren() { return m_phiChildren.get(); }
215
216 void filterICStatus(Node*);
217
218private:
219 void clobberWorld();
220 void didFoldClobberWorld();
221
222 bool handleConstantBinaryBitwiseOp(Node*);
223
224 template<typename Functor>
225 void forAllValues(unsigned indexInBlock, Functor&);
226
227 void clobberStructures();
228 void didFoldClobberStructures();
229
230 void observeTransition(unsigned indexInBlock, RegisteredStructure from, RegisteredStructure to);
231 void observeTransitions(unsigned indexInBlock, const TransitionVector&);
232
233 enum BooleanResult {
234 UnknownBooleanResult,
235 DefinitelyFalse,
236 DefinitelyTrue
237 };
238 BooleanResult booleanResult(Node*, AbstractValue&);
239
240 void setBuiltInConstant(Node* node, FrozenValue value)
241 {
242 AbstractValue& abstractValue = forNode(node);
243 abstractValue.set(m_graph, value, m_state.structureClobberState());
244 abstractValue.fixTypeForRepresentation(m_graph, node);
245 }
246
247 void setConstant(Node* node, FrozenValue value)
248 {
249 setBuiltInConstant(node, value);
250 m_state.setShouldTryConstantFolding(true);
251 }
252
253 ALWAYS_INLINE void filterByType(Edge& edge, SpeculatedType type);
254
255 void verifyEdge(Node*, Edge);
256 void verifyEdges(Node*);
257 void executeDoubleUnaryOpEffects(Node*, double(*equivalentFunction)(double));
258
259 bool handleConstantDivOp(Node*);
260
261 CodeBlock* m_codeBlock;
262 Graph& m_graph;
263 VM& m_vm;
264 AbstractStateType& m_state;
265 std::unique_ptr<PhiChildren> m_phiChildren;
266};
267
268} } // namespace JSC::DFG
269
270#endif // ENABLE(DFG_JIT)
271