0db7be89b011c8e87766060b9487f8c2a5449911
[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 "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* clone(Value*);
80
81     Value* addIntConstant(Origin, Type, int64_t value);
82     Value* addIntConstant(Value*, int64_t value);
83
84     Value* addBottom(Origin, Type);
85     Value* addBottom(Value*);
86
87     // Returns null for MixedTriState.
88     Value* addBoolConstant(Origin, TriState);
89
90     void resetValueOwners();
91     void resetReachability();
92
93     // This destroys CFG analyses. If we ask for them again, we will recompute them. Usually you
94     // should call this anytime you call resetReachability().
95     void invalidateCFG();
96
97     JS_EXPORT_PRIVATE void dump(PrintStream&) const;
98
99     unsigned size() const { return m_blocks.size(); }
100     BasicBlock* at(unsigned index) const { return m_blocks[index].get(); }
101     BasicBlock* operator[](unsigned index) const { return at(index); }
102
103     class iterator {
104     public:
105         iterator()
106             : m_procedure(nullptr)
107             , m_index(0)
108         {
109         }
110
111         iterator(const Procedure& procedure, unsigned index)
112             : m_procedure(&procedure)
113             , m_index(findNext(index))
114         {
115         }
116
117         BasicBlock* operator*()
118         {
119             return m_procedure->at(m_index);
120         }
121
122         iterator& operator++()
123         {
124             m_index = findNext(m_index + 1);
125             return *this;
126         }
127
128         bool operator==(const iterator& other) const
129         {
130             ASSERT(m_procedure == other.m_procedure);
131             return m_index == other.m_index;
132         }
133         
134         bool operator!=(const iterator& other) const
135         {
136             return !(*this == other);
137         }
138
139     private:
140         unsigned findNext(unsigned index)
141         {
142             while (index < m_procedure->size() && !m_procedure->at(index))
143                 index++;
144             return index;
145         }
146
147         const Procedure* m_procedure;
148         unsigned m_index;
149     };
150
151     iterator begin() const { return iterator(*this, 0); }
152     iterator end() const { return iterator(*this, size()); }
153
154     Vector<BasicBlock*> blocksInPreOrder();
155     Vector<BasicBlock*> blocksInPostOrder();
156
157     class ValuesCollection {
158     public:
159         ValuesCollection(const Procedure& procedure)
160             : m_procedure(procedure)
161         {
162         }
163
164         class iterator {
165         public:
166             iterator()
167                 : m_procedure(nullptr)
168                 , m_index(0)
169             {
170             }
171
172             iterator(const Procedure& procedure, unsigned index)
173                 : m_procedure(&procedure)
174                 , m_index(findNext(index))
175             {
176             }
177
178             Value* operator*() const
179             {
180                 return m_procedure->m_values[m_index].get();
181             }
182
183             iterator& operator++()
184             {
185                 m_index = findNext(m_index + 1);
186                 return *this;
187             }
188
189             bool operator==(const iterator& other) const
190             {
191                 ASSERT(m_procedure == other.m_procedure);
192                 return m_index == other.m_index;
193             }
194
195             bool operator!=(const iterator& other) const
196             {
197                 return !(*this == other);
198             }
199
200         private:
201             unsigned findNext(unsigned index)
202             {
203                 while (index < m_procedure->m_values.size() && !m_procedure->m_values[index])
204                     index++;
205                 return index;
206             }
207
208             const Procedure* m_procedure;
209             unsigned m_index;
210         };
211
212         iterator begin() const { return iterator(m_procedure, 0); }
213         iterator end() const { return iterator(m_procedure, m_procedure.m_values.size()); }
214
215         unsigned size() const { return m_procedure.m_values.size(); }
216         Value* at(unsigned index) const { return m_procedure.m_values[index].get(); }
217         Value* operator[](unsigned index) const { return at(index); }
218         
219     private:
220         const Procedure& m_procedure;
221     };
222
223     ValuesCollection values() const { return ValuesCollection(*this); }
224
225     void deleteValue(Value*);
226
227     // A valid procedure cannot contain any orphan values. An orphan is a value that is not in
228     // any basic block. It is possible to create an orphan value during code generation or during
229     // transformation. If you know that you may have created some, you can call this method to
230     // delete them, making the procedure valid again.
231     void deleteOrphans();
232
233     CFG& cfg() const { return *m_cfg; }
234
235     Dominators& dominators();
236
237     void addFastConstant(const ValueKey&);
238     bool isFastConstant(const ValueKey&);
239
240     // The name has to be a string literal, since we don't do any memory management for the string.
241     void setLastPhaseName(const char* name)
242     {
243         m_lastPhaseName = name;
244     }
245
246     const char* lastPhaseName() const { return m_lastPhaseName; }
247
248     void* addDataSection(size_t size);
249
250     OpaqueByproducts& byproducts() { return *m_byproducts; }
251
252     // Below are methods that make sense to call after you have generated code for the procedure.
253
254     // You have to call this method after calling generate(). The code generated by B3::generate()
255     // will require you to keep this object alive for as long as that code is runnable. Usually, this
256     // just keeps alive things like the double constant pool and switch lookup tables. If this sounds
257     // confusing, you should probably be using the B3::Compilation API to compile code. If you use
258     // that API, then you don't have to worry about this.
259     std::unique_ptr<OpaqueByproducts> releaseByproducts() { return WTFMove(m_byproducts); }
260
261     // This gives you direct access to Code. However, the idea is that clients of B3 shouldn't have to
262     // call this. So, Procedure has some methods (below) that expose some Air::Code functionality.
263     const Air::Code& code() const { return *m_code; }
264     Air::Code& code() { return *m_code; }
265
266     unsigned callArgAreaSize() const;
267     void requestCallArgAreaSize(unsigned size);
268
269     JS_EXPORT_PRIVATE unsigned frameSize() const;
270     const RegisterAtOffsetList& calleeSaveRegisters() const;
271
272 private:
273     friend class BlockInsertionSet;
274     
275     JS_EXPORT_PRIVATE size_t addValueIndex();
276     
277     Vector<std::unique_ptr<BasicBlock>> m_blocks;
278     Vector<std::unique_ptr<Value>> m_values;
279     Vector<size_t> m_valueIndexFreeList;
280     std::unique_ptr<CFG> m_cfg;
281     std::unique_ptr<Dominators> m_dominators;
282     HashSet<ValueKey> m_fastConstants;
283     const char* m_lastPhaseName;
284     std::unique_ptr<OpaqueByproducts> m_byproducts;
285     std::unique_ptr<Air::Code> m_code;
286     RefPtr<SharedTask<void(PrintStream&, Origin)>> m_originPrinter;
287 };
288
289 } } // namespace JSC::B3
290
291 #endif // ENABLE(B3_JIT)
292
293 #endif // B3Procedure_h
294