Harden how the compiler references GC objects
[WebKit.git] / Source / JavaScriptCore / dfg / DFGAbstractInterpreter.h
1 /*
2  * Copyright (C) 2013-2016 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 "DFGBranchDirection.h"
32 #include "DFGGraph.h"
33 #include "DFGNode.h"
34 #include "DFGNodeFlowProjection.h"
35 #include "DFGPhiChildren.h"
36
37 namespace JSC { namespace DFG {
38
39 template<typename AbstractStateType>
40 class AbstractInterpreter {
41 public:
42     AbstractInterpreter(Graph&, AbstractStateType&);
43     ~AbstractInterpreter();
44     
45     AbstractValue& forNode(NodeFlowProjection node)
46     {
47         return m_state.forNode(node);
48     }
49     
50     AbstractValue& forNode(Edge edge)
51     {
52         return forNode(edge.node());
53     }
54     
55     Operands<AbstractValue>& variables()
56     {
57         return m_state.variables();
58     }
59     
60     bool needsTypeCheck(Node* node, SpeculatedType typesPassedThrough)
61     {
62         return !forNode(node).isType(typesPassedThrough);
63     }
64     
65     bool needsTypeCheck(Edge edge, SpeculatedType typesPassedThrough)
66     {
67         return needsTypeCheck(edge.node(), typesPassedThrough);
68     }
69     
70     bool needsTypeCheck(Edge edge)
71     {
72         return needsTypeCheck(edge, typeFilterFor(edge.useKind()));
73     }
74     
75     // Abstractly executes the given node. The new abstract state is stored into an
76     // abstract stack stored in *this. Loads of local variables (that span
77     // basic blocks) interrogate the basic block's notion of the state at the head.
78     // Stores to local variables are handled in endBasicBlock(). This returns true
79     // if execution should continue past this node. Notably, it will return true
80     // for block terminals, so long as those terminals are not Return or Unreachable.
81     //
82     // This is guaranteed to be equivalent to doing:
83     //
84     // state.startExecuting()
85     // state.executeEdges(node);
86     // result = state.executeEffects(index);
87     bool execute(unsigned indexInBlock);
88     bool execute(Node*);
89     
90     // Indicate the start of execution of a node. It resets any state in the node
91     // that is progressively built up by executeEdges() and executeEffects().
92     void startExecuting();
93     
94     // Abstractly execute the edges of the given node. This runs filterEdgeByUse()
95     // on all edges of the node. You can skip this step, if you have already used
96     // filterEdgeByUse() (or some equivalent) on each edge.
97     void executeEdges(Node*);
98
99     void executeKnownEdgeTypes(Node*);
100     
101     ALWAYS_INLINE void filterEdgeByUse(Edge& edge)
102     {
103         filterByType(edge, typeFilterFor(edge.useKind()));
104     }
105     
106     // Abstractly execute the effects of the given node. This changes the abstract
107     // state assuming that edges have already been filtered.
108     bool executeEffects(unsigned indexInBlock);
109     bool executeEffects(unsigned clobberLimit, Node*);
110     
111     void dump(PrintStream& out) const;
112     void dump(PrintStream& out);
113     
114     template<typename T>
115     FiltrationResult filter(T node, const RegisteredStructureSet& set, SpeculatedType admittedTypes = SpecNone)
116     {
117         return filter(forNode(node), set, admittedTypes);
118     }
119     
120     template<typename T>
121     FiltrationResult filterArrayModes(T node, ArrayModes arrayModes)
122     {
123         return filterArrayModes(forNode(node), arrayModes);
124     }
125     
126     template<typename T>
127     FiltrationResult filter(T node, SpeculatedType type)
128     {
129         return filter(forNode(node), type);
130     }
131     
132     template<typename T>
133     FiltrationResult filterByValue(T node, FrozenValue value)
134     {
135         return filterByValue(forNode(node), value);
136     }
137     
138     template<typename T>
139     FiltrationResult filterClassInfo(T node, const ClassInfo* classInfo)
140     {
141         return filterClassInfo(forNode(node), classInfo);
142     }
143
144     FiltrationResult filter(AbstractValue&, const RegisteredStructureSet&, SpeculatedType admittedTypes = SpecNone);
145     FiltrationResult filterArrayModes(AbstractValue&, ArrayModes);
146     FiltrationResult filter(AbstractValue&, SpeculatedType);
147     FiltrationResult filterByValue(AbstractValue&, FrozenValue);
148     FiltrationResult filterClassInfo(AbstractValue&, const ClassInfo*);
149     
150     PhiChildren* phiChildren() { return m_phiChildren.get(); }
151     
152 private:
153     void clobberWorld(const CodeOrigin&, unsigned indexInBlock);
154     
155     template<typename Functor>
156     void forAllValues(unsigned indexInBlock, Functor&);
157     
158     void clobberStructures(unsigned indexInBlock);
159     void observeTransition(unsigned indexInBlock, RegisteredStructure from, RegisteredStructure to);
160     void observeTransitions(unsigned indexInBlock, const TransitionVector&);
161     void setDidClobber();
162     
163     enum BooleanResult {
164         UnknownBooleanResult,
165         DefinitelyFalse,
166         DefinitelyTrue
167     };
168     BooleanResult booleanResult(Node*, AbstractValue&);
169     
170     void setBuiltInConstant(Node* node, FrozenValue value)
171     {
172         AbstractValue& abstractValue = forNode(node);
173         abstractValue.set(m_graph, value, m_state.structureClobberState());
174         abstractValue.fixTypeForRepresentation(m_graph, node);
175     }
176     
177     void setConstant(Node* node, FrozenValue value)
178     {
179         setBuiltInConstant(node, value);
180         m_state.setFoundConstants(true);
181     }
182     
183     ALWAYS_INLINE void filterByType(Edge& edge, SpeculatedType type)
184     {
185         AbstractValue& value = forNode(edge);
186         if (!value.isType(type))
187             edge.setProofStatus(NeedsCheck);
188         else
189             edge.setProofStatus(IsProved);
190         
191         filter(value, type);
192     }
193     
194     void verifyEdge(Node*, Edge);
195     void verifyEdges(Node*);
196     void executeDoubleUnaryOpEffects(Node*, double(*equivalentFunction)(double));
197     
198     CodeBlock* m_codeBlock;
199     Graph& m_graph;
200     AbstractStateType& m_state;
201     std::unique_ptr<PhiChildren> m_phiChildren;
202 };
203
204 } } // namespace JSC::DFG
205
206 #endif // ENABLE(DFG_JIT)