Unreviewed, partially revert r191952.
[WebKit-https.git] / Source / JavaScriptCore / b3 / air / AirCode.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 AirCode_h
27 #define AirCode_h
28
29 #if ENABLE(B3_JIT)
30
31 #include "AirBasicBlock.h"
32 #include "AirSpecial.h"
33 #include "AirStackSlot.h"
34 #include "RegisterAtOffsetList.h"
35 #include "StackAlignment.h"
36
37 namespace JSC { namespace B3 {
38
39 class Procedure;
40
41 namespace Air {
42
43 class CCallSpecial;
44
45 // This is an IR that is very close to the bare metal. It requires about 40x more bytes than the
46 // generated machine code - for example if you're generating 1MB of machine code, you need about
47 // 40MB of Air.
48
49 class Code {
50     WTF_MAKE_NONCOPYABLE(Code);
51     WTF_MAKE_FAST_ALLOCATED;
52 public:
53     Code();
54     ~Code();
55
56     BasicBlock* addBlock(double frequency = PNaN);
57
58     StackSlot* addStackSlot(unsigned byteSize, StackSlotKind, StackSlotValue* = nullptr);
59     StackSlot* addStackSlot(StackSlotValue*);
60
61     Special* addSpecial(std::unique_ptr<Special>);
62
63     // This is the special you need to make a C call!
64     CCallSpecial* cCallSpecial();
65
66     Tmp newTmp(Arg::Type type)
67     {
68         switch (type) {
69         case Arg::GP:
70             return Tmp::gpTmpForIndex(m_numGPTmps++);
71         case Arg::FP:
72             return Tmp::fpTmpForIndex(m_numFPTmps++);
73         }
74     }
75
76     unsigned numTmps(Arg::Type type)
77     {
78         switch (type) {
79         case Arg::GP:
80             return m_numGPTmps;
81         case Arg::FP:
82             return m_numFPTmps;
83         }
84     }
85
86     unsigned callArgAreaSize() const { return m_callArgAreaSize; }
87
88     // You can call this before code generation to force a minimum call arg area size.
89     void requestCallArgAreaSize(unsigned size)
90     {
91         m_callArgAreaSize = std::max(
92             m_callArgAreaSize,
93             static_cast<unsigned>(WTF::roundUpToMultipleOf(stackAlignmentBytes(), size)));
94     }
95
96     unsigned frameSize() const { return m_frameSize; }
97
98     // Only phases that do stack allocation are allowed to set this. Currently, only
99     // Air::allocateStack() does this.
100     void setFrameSize(unsigned frameSize)
101     {
102         m_frameSize = frameSize;
103     }
104
105     RegisterAtOffsetList& calleeSaveRegisters() { return m_calleeSaveRegisters; }
106
107     // Recomputes predecessors and deletes unreachable blocks.
108     void resetReachability();
109
110     void dump(PrintStream&) const;
111
112     unsigned size() const { return m_blocks.size(); }
113     BasicBlock* at(unsigned index) const { return m_blocks[index].get(); }
114     BasicBlock* operator[](unsigned index) const { return at(index); }
115
116     // Finds the smallest index' such that at(index') != null and index' >= index.
117     unsigned findFirstBlockIndex(unsigned index) const;
118
119     // Finds the smallest index' such that at(index') != null and index' > index.
120     unsigned findNextBlockIndex(unsigned index) const;
121
122     BasicBlock* findNextBlock(BasicBlock*) const;
123
124     class iterator {
125     public:
126         iterator()
127             : m_code(nullptr)
128             , m_index(0)
129         {
130         }
131
132         iterator(const Code& code, unsigned index)
133             : m_code(&code)
134             , m_index(m_code->findFirstBlockIndex(index))
135         {
136         }
137
138         BasicBlock* operator*()
139         {
140             return m_code->at(m_index);
141         }
142
143         iterator& operator++()
144         {
145             m_index = m_code->findFirstBlockIndex(m_index + 1);
146             return *this;
147         }
148
149         bool operator==(const iterator& other) const
150         {
151             return m_index == other.m_index;
152         }
153
154         bool operator!=(const iterator& other) const
155         {
156             return !(*this == other);
157         }
158
159     private:
160         const Code* m_code;
161         unsigned m_index;
162     };
163
164     iterator begin() const { return iterator(*this, 0); }
165     iterator end() const { return iterator(*this, size()); }
166
167     class StackSlotsCollection {
168     public:
169         StackSlotsCollection(const Code& code)
170             : m_code(code)
171         {
172         }
173
174         unsigned size() const { return m_code.m_stackSlots.size(); }
175         StackSlot* at(unsigned index) const { return m_code.m_stackSlots[index].get(); }
176         StackSlot* operator[](unsigned index) const { return at(index); }
177
178         class iterator {
179         public:
180             iterator()
181                 : m_collection(nullptr)
182                 , m_index(0)
183             {
184             }
185
186             iterator(const StackSlotsCollection& collection, unsigned index)
187                 : m_collection(&collection)
188                 , m_index(index)
189             {
190             }
191
192             StackSlot* operator*()
193             {
194                 return m_collection->at(m_index);
195             }
196
197             iterator& operator++()
198             {
199                 m_index++;
200                 return *this;
201             }
202
203             bool operator==(const iterator& other) const
204             {
205                 return m_index == other.m_index;
206             }
207
208             bool operator!=(const iterator& other) const
209             {
210                 return !(*this == other);
211             }
212
213         private:
214             const StackSlotsCollection* m_collection;
215             unsigned m_index;
216         };
217
218         iterator begin() const { return iterator(*this, 0); }
219         iterator end() const { return iterator(*this, size()); }
220
221     private:
222         const Code& m_code;
223     };
224
225     StackSlotsCollection stackSlots() const { return StackSlotsCollection(*this); }
226     
227     class SpecialsCollection {
228     public:
229         SpecialsCollection(const Code& code)
230             : m_code(code)
231         {
232         }
233
234         unsigned size() const { return m_code.m_specials.size(); }
235         Special* at(unsigned index) const { return m_code.m_specials[index].get(); }
236         Special* operator[](unsigned index) const { return at(index); }
237
238         class iterator {
239         public:
240             iterator()
241                 : m_collection(nullptr)
242                 , m_index(0)
243             {
244             }
245
246             iterator(const SpecialsCollection& collection, unsigned index)
247                 : m_collection(&collection)
248                 , m_index(index)
249             {
250             }
251
252             Special* operator*()
253             {
254                 return m_collection->at(m_index);
255             }
256
257             iterator& operator++()
258             {
259                 m_index++;
260                 return *this;
261             }
262
263             bool operator==(const iterator& other) const
264             {
265                 return m_index == other.m_index;
266             }
267
268             bool operator!=(const iterator& other) const
269             {
270                 return !(*this == other);
271             }
272
273         private:
274             const SpecialsCollection* m_collection;
275             unsigned m_index;
276         };
277
278         iterator begin() const { return iterator(*this, 0); }
279         iterator end() const { return iterator(*this, size()); }
280
281     private:
282         const Code& m_code;
283     };
284
285     SpecialsCollection specials() const { return SpecialsCollection(*this); }
286     
287     // The name has to be a string literal, since we don't do any memory management for the string.
288     void setLastPhaseName(const char* name)
289     {
290         m_lastPhaseName = name;
291     }
292
293     const char* lastPhaseName() const { return m_lastPhaseName; }
294
295 private:
296     Vector<std::unique_ptr<StackSlot>> m_stackSlots;
297     Vector<std::unique_ptr<BasicBlock>> m_blocks;
298     Vector<std::unique_ptr<Special>> m_specials;
299     CCallSpecial* m_cCallSpecial { nullptr };
300     unsigned m_numGPTmps { 0 };
301     unsigned m_numFPTmps { 0 };
302     unsigned m_frameSize { 0 };
303     unsigned m_callArgAreaSize { 0 };
304     RegisterAtOffsetList m_calleeSaveRegisters;
305     const char* m_lastPhaseName;
306 };
307
308 } } } // namespace JSC::B3::Air
309
310 #endif // ENABLE(B3_JIT)
311
312 #endif // AirCode_h
313