Replace WTF::move with WTFMove
[WebKit-https.git] / Source / JavaScriptCore / b3 / B3Procedure.h
1 /*
2  * Copyright (C) 2015 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 "B3Type.h"
34 #include "B3ValueKey.h"
35 #include "PureNaN.h"
36 #include "RegisterAtOffsetList.h"
37 #include <wtf/Bag.h>
38 #include <wtf/FastMalloc.h>
39 #include <wtf/HashSet.h>
40 #include <wtf/Noncopyable.h>
41 #include <wtf/PrintStream.h>
42 #include <wtf/SharedTask.h>
43 #include <wtf/TriState.h>
44 #include <wtf/Vector.h>
45
46 namespace JSC { namespace B3 {
47
48 class BasicBlock;
49 class BlockInsertionSet;
50 class CFG;
51 class Dominators;
52 class Value;
53
54 namespace Air { class Code; }
55
56 class Procedure {
57     WTF_MAKE_NONCOPYABLE(Procedure);
58     WTF_MAKE_FAST_ALLOCATED;
59 public:
60
61     JS_EXPORT_PRIVATE Procedure();
62     JS_EXPORT_PRIVATE ~Procedure();
63
64     template<typename Callback>
65     void setOriginPrinter(Callback&& callback)
66     {
67         m_originPrinter = createSharedTask<void(PrintStream&, Origin)>(
68             std::forward<Callback>(callback));
69     }
70
71     // Usually you use this via OriginDump, though it's cool to use it directly.
72     void printOrigin(PrintStream& out, Origin origin) const;
73
74     JS_EXPORT_PRIVATE BasicBlock* addBlock(double frequency = 1);
75     
76     template<typename ValueType, typename... Arguments>
77     ValueType* add(Arguments...);
78
79     Value* addIntConstant(Origin, Type, int64_t value);
80     Value* addIntConstant(Value*, int64_t value);
81
82     // Returns null for MixedTriState.
83     Value* addBoolConstant(Origin, TriState);
84
85     void resetValueOwners();
86     void resetReachability();
87
88     // This destroys CFG analyses. If we ask for them again, we will recompute them. Usually you
89     // should call this anytime you call resetReachability().
90     void invalidateCFG();
91
92     JS_EXPORT_PRIVATE void dump(PrintStream&) const;
93
94     unsigned size() const { return m_blocks.size(); }
95     BasicBlock* at(unsigned index) const { return m_blocks[index].get(); }
96     BasicBlock* operator[](unsigned index) const { return at(index); }
97
98     class iterator {
99     public:
100         iterator()
101             : m_procedure(nullptr)
102             , m_index(0)
103         {
104         }
105
106         iterator(const Procedure& procedure, unsigned index)
107             : m_procedure(&procedure)
108             , m_index(findNext(index))
109         {
110         }
111
112         BasicBlock* operator*()
113         {
114             return m_procedure->at(m_index);
115         }
116
117         iterator& operator++()
118         {
119             m_index = findNext(m_index + 1);
120             return *this;
121         }
122
123         bool operator==(const iterator& other) const
124         {
125             ASSERT(m_procedure == other.m_procedure);
126             return m_index == other.m_index;
127         }
128         
129         bool operator!=(const iterator& other) const
130         {
131             return !(*this == other);
132         }
133
134     private:
135         unsigned findNext(unsigned index)
136         {
137             while (index < m_procedure->size() && !m_procedure->at(index))
138                 index++;
139             return index;
140         }
141
142         const Procedure* m_procedure;
143         unsigned m_index;
144     };
145
146     iterator begin() const { return iterator(*this, 0); }
147     iterator end() const { return iterator(*this, size()); }
148
149     Vector<BasicBlock*> blocksInPreOrder();
150     Vector<BasicBlock*> blocksInPostOrder();
151
152     class ValuesCollection {
153     public:
154         ValuesCollection(const Procedure& procedure)
155             : m_procedure(procedure)
156         {
157         }
158
159         class iterator {
160         public:
161             iterator()
162                 : m_procedure(nullptr)
163                 , m_index(0)
164             {
165             }
166
167             iterator(const Procedure& procedure, unsigned index)
168                 : m_procedure(&procedure)
169                 , m_index(findNext(index))
170             {
171             }
172
173             Value* operator*() const
174             {
175                 return m_procedure->m_values[m_index].get();
176             }
177
178             iterator& operator++()
179             {
180                 m_index = findNext(m_index + 1);
181                 return *this;
182             }
183
184             bool operator==(const iterator& other) const
185             {
186                 ASSERT(m_procedure == other.m_procedure);
187                 return m_index == other.m_index;
188             }
189
190             bool operator!=(const iterator& other) const
191             {
192                 return !(*this == other);
193             }
194
195         private:
196             unsigned findNext(unsigned index)
197             {
198                 while (index < m_procedure->m_values.size() && !m_procedure->m_values[index])
199                     index++;
200                 return index;
201             }
202
203             const Procedure* m_procedure;
204             unsigned m_index;
205         };
206
207         iterator begin() const { return iterator(m_procedure, 0); }
208         iterator end() const { return iterator(m_procedure, m_procedure.m_values.size()); }
209
210         unsigned size() const { return m_procedure.m_values.size(); }
211         Value* at(unsigned index) const { return m_procedure.m_values[index].get(); }
212         Value* operator[](unsigned index) const { return at(index); }
213         
214     private:
215         const Procedure& m_procedure;
216     };
217
218     ValuesCollection values() const { return ValuesCollection(*this); }
219
220     void deleteValue(Value*);
221
222     CFG& cfg() const { return *m_cfg; }
223
224     Dominators& dominators();
225
226     void addFastConstant(const ValueKey&);
227     bool isFastConstant(const ValueKey&);
228
229     // The name has to be a string literal, since we don't do any memory management for the string.
230     void setLastPhaseName(const char* name)
231     {
232         m_lastPhaseName = name;
233     }
234
235     const char* lastPhaseName() const { return m_lastPhaseName; }
236
237     void* addDataSection(size_t size);
238
239     OpaqueByproducts& byproducts() { return *m_byproducts; }
240
241     // Below are methods that make sense to call after you have generated code for the procedure.
242
243     // You have to call this method after calling generate(). The code generated by B3::generate()
244     // will require you to keep this object alive for as long as that code is runnable. Usually, this
245     // just keeps alive things like the double constant pool and switch lookup tables. If this sounds
246     // confusing, you should probably be using the B3::Compilation API to compile code. If you use
247     // that API, then you don't have to worry about this.
248     std::unique_ptr<OpaqueByproducts> releaseByproducts() { return WTFMove(m_byproducts); }
249
250     // This gives you direct access to Code. However, the idea is that clients of B3 shouldn't have to
251     // call this. So, Procedure has some methods (below) that expose some Air::Code functionality.
252     const Air::Code& code() const { return *m_code; }
253     Air::Code& code() { return *m_code; }
254
255     unsigned callArgAreaSize() const;
256     void requestCallArgAreaSize(unsigned size);
257
258     JS_EXPORT_PRIVATE unsigned frameSize() const;
259     const RegisterAtOffsetList& calleeSaveRegisters() const;
260
261 private:
262     friend class BlockInsertionSet;
263     
264     JS_EXPORT_PRIVATE size_t addValueIndex();
265     
266     Vector<std::unique_ptr<BasicBlock>> m_blocks;
267     Vector<std::unique_ptr<Value>> m_values;
268     Vector<size_t> m_valueIndexFreeList;
269     std::unique_ptr<CFG> m_cfg;
270     std::unique_ptr<Dominators> m_dominators;
271     HashSet<ValueKey> m_fastConstants;
272     const char* m_lastPhaseName;
273     std::unique_ptr<OpaqueByproducts> m_byproducts;
274     std::unique_ptr<Air::Code> m_code;
275     RefPtr<SharedTask<void(PrintStream&, Origin)>> m_originPrinter;
276 };
277
278 } } // namespace JSC::B3
279
280 #endif // ENABLE(B3_JIT)
281
282 #endif // B3Procedure_h
283