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 {
40public:
41 AbstractInterpreter(Graph&, AbstractStateType&);
42 ~AbstractInterpreter();
43
44 ALWAYS_INLINE AbstractValue& forNode(NodeFlowProjection node)
45 {
46 return m_state.forNode(node);
47 }
48
49 ALWAYS_INLINE AbstractValue& forNode(Edge edge)
50 {
51 return forNode(edge.node());
52 }
53
54 ALWAYS_INLINE void clearForNode(NodeFlowProjection node)
55 {
56 m_state.clearForNode(node);
57 }
58
59 ALWAYS_INLINE void clearForNode(Edge edge)
60 {
61 clearForNode(edge.node());
62 }
63
64 template<typename... Arguments>
65 ALWAYS_INLINE void setForNode(NodeFlowProjection node, Arguments&&... arguments)
66 {
67 m_state.setForNode(node, std::forward<Arguments>(arguments)...);
68 }
69
70 template<typename... Arguments>
71 ALWAYS_INLINE void setForNode(Edge edge, Arguments&&... arguments)
72 {
73 setForNode(edge.node(), std::forward<Arguments>(arguments)...);
74 }
75
76 template<typename... Arguments>
77 ALWAYS_INLINE void setTypeForNode(NodeFlowProjection node, Arguments&&... arguments)
78 {
79 m_state.setTypeForNode(node, std::forward<Arguments>(arguments)...);
80 }
81
82 template<typename... Arguments>
83 ALWAYS_INLINE void setTypeForNode(Edge edge, Arguments&&... arguments)
84 {
85 setTypeForNode(edge.node(), std::forward<Arguments>(arguments)...);
86 }
87
88 template<typename... Arguments>
89 ALWAYS_INLINE void setNonCellTypeForNode(NodeFlowProjection node, Arguments&&... arguments)
90 {
91 m_state.setNonCellTypeForNode(node, std::forward<Arguments>(arguments)...);
92 }
93
94 template<typename... Arguments>
95 ALWAYS_INLINE void setNonCellTypeForNode(Edge edge, Arguments&&... arguments)
96 {
97 setNonCellTypeForNode(edge.node(), std::forward<Arguments>(arguments)...);
98 }
99
100 ALWAYS_INLINE void makeBytecodeTopForNode(NodeFlowProjection node)
101 {
102 m_state.makeBytecodeTopForNode(node);
103 }
104
105 ALWAYS_INLINE void makeBytecodeTopForNode(Edge edge)
106 {
107 makeBytecodeTopForNode(edge.node());
108 }
109
110 ALWAYS_INLINE void makeHeapTopForNode(NodeFlowProjection node)
111 {
112 m_state.makeHeapTopForNode(node);
113 }
114
115 ALWAYS_INLINE void makeHeapTopForNode(Edge edge)
116 {
117 makeHeapTopForNode(edge.node());
118 }
119
120 bool needsTypeCheck(Node* node, SpeculatedType typesPassedThrough)
121 {
122 return !forNode(node).isType(typesPassedThrough);
123 }
124
125 bool needsTypeCheck(Edge edge, SpeculatedType typesPassedThrough)
126 {
127 return needsTypeCheck(edge.node(), typesPassedThrough);
128 }
129
130 bool needsTypeCheck(Edge edge)
131 {
132 return needsTypeCheck(edge, typeFilterFor(edge.useKind()));
133 }
134
135 // Abstractly executes the given node. The new abstract state is stored into an
136 // abstract stack stored in *this. Loads of local variables (that span
137 // basic blocks) interrogate the basic block's notion of the state at the head.
138 // Stores to local variables are handled in endBasicBlock(). This returns true
139 // if execution should continue past this node. Notably, it will return true
140 // for block terminals, so long as those terminals are not Return or Unreachable.
141 //
142 // This is guaranteed to be equivalent to doing:
143 //
144 // state.startExecuting()
145 // state.executeEdges(node);
146 // result = state.executeEffects(index);
147 bool execute(unsigned indexInBlock);
148 bool execute(Node*);
149
150 // Indicate the start of execution of a node. It resets any state in the node
151 // that is progressively built up by executeEdges() and executeEffects().
152 void startExecuting();
153
154 // Abstractly execute the edges of the given node. This runs filterEdgeByUse()
155 // on all edges of the node. You can skip this step, if you have already used
156 // filterEdgeByUse() (or some equivalent) on each edge.
157 void executeEdges(Node*);
158
159 void executeKnownEdgeTypes(Node*);
160
161 ALWAYS_INLINE void filterEdgeByUse(Edge& edge)
162 {
163 UseKind useKind = edge.useKind();
164 if (useKind == UntypedUse)
165 return;
166 filterByType(edge, typeFilterFor(useKind));
167 }
168
169 // Abstractly execute the effects of the given node. This changes the abstract
170 // state assuming that edges have already been filtered.
171 bool executeEffects(unsigned indexInBlock);
172 bool executeEffects(unsigned clobberLimit, Node*);
173
174 void dump(PrintStream& out) const;
175 void dump(PrintStream& out);
176
177 template<typename T>
178 FiltrationResult filter(T node, const RegisteredStructureSet& set, SpeculatedType admittedTypes = SpecNone)
179 {
180 return filter(forNode(node), set, admittedTypes);
181 }
182
183 template<typename T>
184 FiltrationResult filterArrayModes(T node, ArrayModes arrayModes)
185 {
186 return filterArrayModes(forNode(node), arrayModes);
187 }
188
189 template<typename T>
190 FiltrationResult filter(T node, SpeculatedType type)
191 {
192 return filter(forNode(node), type);
193 }
194
195 template<typename T>
196 FiltrationResult filterByValue(T node, FrozenValue value)
197 {
198 return filterByValue(forNode(node), value);
199 }
200
201 template<typename T>
202 FiltrationResult filterClassInfo(T node, const ClassInfo* classInfo)
203 {
204 return filterClassInfo(forNode(node), classInfo);
205 }
206
207 FiltrationResult filter(AbstractValue&, const RegisteredStructureSet&, SpeculatedType admittedTypes = SpecNone);
208 FiltrationResult filterArrayModes(AbstractValue&, ArrayModes);
209 FiltrationResult filter(AbstractValue&, SpeculatedType);
210 FiltrationResult filterByValue(AbstractValue&, FrozenValue);
211 FiltrationResult filterClassInfo(AbstractValue&, const ClassInfo*);
212
213 PhiChildren* phiChildren() { return m_phiChildren.get(); }
214
215 void filterICStatus(Node*);
216
217private:
218 void clobberWorld();
219 void didFoldClobberWorld();
220
221 template<typename Functor>
222 void forAllValues(unsigned indexInBlock, Functor&);
223
224 void clobberStructures();
225 void didFoldClobberStructures();
226
227 void observeTransition(unsigned indexInBlock, RegisteredStructure from, RegisteredStructure to);
228 void observeTransitions(unsigned indexInBlock, const TransitionVector&);
229
230 enum BooleanResult {
231 UnknownBooleanResult,
232 DefinitelyFalse,
233 DefinitelyTrue
234 };
235 BooleanResult booleanResult(Node*, AbstractValue&);
236
237 void setBuiltInConstant(Node* node, FrozenValue value)
238 {
239 AbstractValue& abstractValue = forNode(node);
240 abstractValue.set(m_graph, value, m_state.structureClobberState());
241 abstractValue.fixTypeForRepresentation(m_graph, node);
242 }
243
244 void setConstant(Node* node, FrozenValue value)
245 {
246 setBuiltInConstant(node, value);
247 m_state.setFoundConstants(true);
248 }
249
250 ALWAYS_INLINE void filterByType(Edge& edge, SpeculatedType type);
251
252 void verifyEdge(Node*, Edge);
253 void verifyEdges(Node*);
254 void executeDoubleUnaryOpEffects(Node*, double(*equivalentFunction)(double));
255
256 bool handleConstantDivOp(Node*);
257
258 CodeBlock* m_codeBlock;
259 Graph& m_graph;
260 VM& m_vm;
261 AbstractStateType& m_state;
262 std::unique_ptr<PhiChildren> m_phiChildren;
263};
264
265} } // namespace JSC::DFG
266
267#endif // ENABLE(DFG_JIT)
268