d9bd029521273c2d82caa132fde59490d9ec7fd0
[WebKit-https.git] / Source / JavaScriptCore / b3 / B3Procedure.h
1 /*
2  * Copyright (C) 2015-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 #ifndef B3Procedure_h
27 #define B3Procedure_h
28
29 #if ENABLE(B3_JIT)
30
31 #include "B3OpaqueByproducts.h"
32 #include "B3Origin.h"
33 #include "B3PCToOriginMap.h"
34 #include "B3SparseCollection.h"
35 #include "B3Type.h"
36 #include "B3ValueKey.h"
37 #include "PureNaN.h"
38 #include "RegisterAtOffsetList.h"
39 #include <wtf/Bag.h>
40 #include <wtf/FastMalloc.h>
41 #include <wtf/HashSet.h>
42 #include <wtf/Noncopyable.h>
43 #include <wtf/PrintStream.h>
44 #include <wtf/SharedTask.h>
45 #include <wtf/TriState.h>
46 #include <wtf/Vector.h>
47
48 namespace JSC { namespace B3 {
49
50 class BasicBlock;
51 class BlockInsertionSet;
52 class CFG;
53 class Dominators;
54 class StackSlot;
55 class Value;
56 class Variable;
57
58 namespace Air { class Code; }
59
60 class Procedure {
61     WTF_MAKE_NONCOPYABLE(Procedure);
62     WTF_MAKE_FAST_ALLOCATED;
63 public:
64
65     JS_EXPORT_PRIVATE Procedure();
66     JS_EXPORT_PRIVATE ~Procedure();
67
68     template<typename Callback>
69     void setOriginPrinter(Callback&& callback)
70     {
71         m_originPrinter = createSharedTask<void(PrintStream&, Origin)>(
72             std::forward<Callback>(callback));
73     }
74
75     // Usually you use this via OriginDump, though it's cool to use it directly.
76     void printOrigin(PrintStream& out, Origin origin) const;
77
78     // This is a debugging hack. Sometimes while debugging B3 you need to break the abstraction
79     // and get at the DFG Graph, or whatever data structure the frontend used to describe the
80     // program. The FTL passes the DFG Graph.
81     void setFrontendData(const void* value) { m_frontendData = value; }
82     const void* frontendData() const { return m_frontendData; }
83
84     JS_EXPORT_PRIVATE BasicBlock* addBlock(double frequency = 1);
85
86     // Changes the order of basic blocks to be as in the supplied vector. The vector does not
87     // need to mention every block in the procedure. Blocks not mentioned will be placed after
88     // these blocks in the same order as they were in originally.
89     template<typename BlockIterable>
90     void setBlockOrder(const BlockIterable& iterable)
91     {
92         Vector<BasicBlock*> blocks;
93         for (BasicBlock* block : iterable)
94             blocks.append(block);
95         setBlockOrderImpl(blocks);
96     }
97
98     JS_EXPORT_PRIVATE StackSlot* addStackSlot(unsigned byteSize);
99     JS_EXPORT_PRIVATE Variable* addVariable(Type);
100     
101     template<typename ValueType, typename... Arguments>
102     ValueType* add(Arguments...);
103
104     Value* clone(Value*);
105
106     Value* addIntConstant(Origin, Type, int64_t value);
107     Value* addIntConstant(Value*, int64_t value);
108
109     Value* addBottom(Origin, Type);
110     Value* addBottom(Value*);
111
112     // Returns null for MixedTriState.
113     Value* addBoolConstant(Origin, TriState);
114
115     void resetValueOwners();
116     JS_EXPORT_PRIVATE void resetReachability();
117
118     // This destroys CFG analyses. If we ask for them again, we will recompute them. Usually you
119     // should call this anytime you call resetReachability().
120     void invalidateCFG();
121
122     JS_EXPORT_PRIVATE void dump(PrintStream&) const;
123
124     unsigned size() const { return m_blocks.size(); }
125     BasicBlock* at(unsigned index) const { return m_blocks[index].get(); }
126     BasicBlock* operator[](unsigned index) const { return at(index); }
127
128     class iterator {
129     public:
130         iterator()
131             : m_procedure(nullptr)
132             , m_index(0)
133         {
134         }
135
136         iterator(const Procedure& procedure, unsigned index)
137             : m_procedure(&procedure)
138             , m_index(findNext(index))
139         {
140         }
141
142         BasicBlock* operator*()
143         {
144             return m_procedure->at(m_index);
145         }
146
147         iterator& operator++()
148         {
149             m_index = findNext(m_index + 1);
150             return *this;
151         }
152
153         bool operator==(const iterator& other) const
154         {
155             ASSERT(m_procedure == other.m_procedure);
156             return m_index == other.m_index;
157         }
158         
159         bool operator!=(const iterator& other) const
160         {
161             return !(*this == other);
162         }
163
164     private:
165         unsigned findNext(unsigned index)
166         {
167             while (index < m_procedure->size() && !m_procedure->at(index))
168                 index++;
169             return index;
170         }
171
172         const Procedure* m_procedure;
173         unsigned m_index;
174     };
175
176     iterator begin() const { return iterator(*this, 0); }
177     iterator end() const { return iterator(*this, size()); }
178
179     Vector<BasicBlock*> blocksInPreOrder();
180     Vector<BasicBlock*> blocksInPostOrder();
181
182     SparseCollection<StackSlot>& stackSlots() { return m_stackSlots; }
183     const SparseCollection<StackSlot>& stackSlots() const { return m_stackSlots; }
184
185     // Short for stackSlots().remove(). It's better to call this method since it's out of line.
186     void deleteStackSlot(StackSlot*);
187
188     SparseCollection<Variable>& variables() { return m_variables; }
189     const SparseCollection<Variable>& variables() const { return m_variables; }
190
191     // Short for variables().remove(). It's better to call this method since it's out of line.
192     void deleteVariable(Variable*);
193
194     SparseCollection<Value>& values() { return m_values; }
195     const SparseCollection<Value>& values() const { return m_values; }
196
197     // Short for values().remove(). It's better to call this method since it's out of line.
198     void deleteValue(Value*);
199
200     // A valid procedure cannot contain any orphan values. An orphan is a value that is not in
201     // any basic block. It is possible to create an orphan value during code generation or during
202     // transformation. If you know that you may have created some, you can call this method to
203     // delete them, making the procedure valid again.
204     void deleteOrphans();
205
206     CFG& cfg() const { return *m_cfg; }
207
208     Dominators& dominators();
209
210     void addFastConstant(const ValueKey&);
211     bool isFastConstant(const ValueKey&);
212
213     // The name has to be a string literal, since we don't do any memory management for the string.
214     void setLastPhaseName(const char* name)
215     {
216         m_lastPhaseName = name;
217     }
218
219     const char* lastPhaseName() const { return m_lastPhaseName; }
220
221     // Allocates a slab of memory that will be kept alive by anyone who keeps the resulting code
222     // alive. Great for compiler-generated data sections, like switch jump tables and constant pools.
223     // This returns memory that has been zero-initialized.
224     JS_EXPORT_PRIVATE void* addDataSection(size_t);
225
226     OpaqueByproducts& byproducts() { return *m_byproducts; }
227
228     // Below are methods that make sense to call after you have generated code for the procedure.
229
230     // You have to call this method after calling generate(). The code generated by B3::generate()
231     // will require you to keep this object alive for as long as that code is runnable. Usually, this
232     // just keeps alive things like the double constant pool and switch lookup tables. If this sounds
233     // confusing, you should probably be using the B3::Compilation API to compile code. If you use
234     // that API, then you don't have to worry about this.
235     std::unique_ptr<OpaqueByproducts> releaseByproducts() { return WTFMove(m_byproducts); }
236
237     // This gives you direct access to Code. However, the idea is that clients of B3 shouldn't have to
238     // call this. So, Procedure has some methods (below) that expose some Air::Code functionality.
239     const Air::Code& code() const { return *m_code; }
240     Air::Code& code() { return *m_code; }
241
242     unsigned callArgAreaSize() const;
243     void requestCallArgAreaSize(unsigned size);
244
245     JS_EXPORT_PRIVATE unsigned frameSize() const;
246     const RegisterAtOffsetList& calleeSaveRegisters() const;
247
248     PCToOriginMap& pcToOriginMap() { return m_pcToOriginMap; }
249     PCToOriginMap releasePCToOriginMap() { return WTFMove(m_pcToOriginMap); }
250
251 private:
252     friend class BlockInsertionSet;
253
254     JS_EXPORT_PRIVATE Value* addValueImpl(Value*);
255     void setBlockOrderImpl(Vector<BasicBlock*>&);
256
257     SparseCollection<StackSlot> m_stackSlots;
258     SparseCollection<Variable> m_variables;
259     Vector<std::unique_ptr<BasicBlock>> m_blocks;
260     SparseCollection<Value> m_values;
261     std::unique_ptr<CFG> m_cfg;
262     std::unique_ptr<Dominators> m_dominators;
263     HashSet<ValueKey> m_fastConstants;
264     const char* m_lastPhaseName;
265     std::unique_ptr<OpaqueByproducts> m_byproducts;
266     std::unique_ptr<Air::Code> m_code;
267     RefPtr<SharedTask<void(PrintStream&, Origin)>> m_originPrinter;
268     const void* m_frontendData;
269     PCToOriginMap m_pcToOriginMap;
270 };
271
272 } } // namespace JSC::B3
273
274 #endif // ENABLE(B3_JIT)
275
276 #endif // B3Procedure_h
277