initial import
[vuplus_webkit] / Source / JavaScriptCore / dfg / DFGGenerationInfo.h
1 /*
2  * Copyright (C) 2011 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 DFGGenerationInfo_h
27 #define DFGGenerationInfo_h
28
29 #if ENABLE(DFG_JIT)
30
31 #include <dfg/DFGJITCompiler.h>
32
33 namespace JSC { namespace DFG {
34
35 // === DataFormat ===
36 //
37 // This enum tracks the current representation in which a value is being held.
38 // Values may be unboxed primitives (int32, double, or cell), or boxed as a JSValue.
39 // For boxed values, we may know the type of boxing that has taken place.
40 // (May also need bool, array, object, string types!)
41 enum DataFormat {
42     DataFormatNone = 0,
43     DataFormatInteger = 1,
44     DataFormatDouble = 2,
45     DataFormatBoolean = 3,
46     DataFormatCell = 4,
47     DataFormatJS = 8,
48     DataFormatJSInteger = DataFormatJS | DataFormatInteger,
49     DataFormatJSDouble = DataFormatJS | DataFormatDouble,
50     DataFormatJSCell = DataFormatJS | DataFormatCell,
51     DataFormatJSBoolean = DataFormatJS | DataFormatBoolean
52 };
53
54 #ifndef NDEBUG
55 inline const char* dataFormatToString(DataFormat dataFormat)
56 {
57     switch (dataFormat) {
58     case DataFormatNone:
59         return "None";
60     case DataFormatInteger:
61         return "Integer";
62     case DataFormatDouble:
63         return "Double";
64     case DataFormatCell:
65         return "Cell";
66     case DataFormatBoolean:
67         return "Boolean";
68     case DataFormatJS:
69         return "JS";
70     case DataFormatJSInteger:
71         return "JSInteger";
72     case DataFormatJSDouble:
73         return "JSDouble";
74     case DataFormatJSCell:
75         return "JSCell";
76     case DataFormatJSBoolean:
77         return "JSBoolean";
78     default:
79         return "Unknown";
80     }
81 }
82 #endif
83
84 inline bool needDataFormatConversion(DataFormat from, DataFormat to)
85 {
86     ASSERT(from != DataFormatNone);
87     ASSERT(to != DataFormatNone);
88     switch (from) {
89     case DataFormatInteger:
90     case DataFormatDouble:
91         return to != from;
92     case DataFormatCell:
93     case DataFormatJS:
94     case DataFormatJSInteger:
95     case DataFormatJSDouble:
96     case DataFormatJSCell:
97     case DataFormatJSBoolean:
98         switch (to) {
99         case DataFormatInteger:
100         case DataFormatDouble:
101             return true;
102         case DataFormatCell:
103         case DataFormatJS:
104         case DataFormatJSInteger:
105         case DataFormatJSDouble:
106         case DataFormatJSCell:
107         case DataFormatJSBoolean:
108             return false;
109         default:
110             // This captures DataFormatBoolean, which is currently unused.
111             ASSERT_NOT_REACHED();
112         }
113     default:
114         // This captures DataFormatBoolean, which is currently unused.
115         ASSERT_NOT_REACHED();
116     }
117     return true;
118 }
119
120 inline bool isJSFormat(DataFormat format, DataFormat expectedFormat)
121 {
122     ASSERT(expectedFormat & DataFormatJS);
123     return (format | DataFormatJS) == expectedFormat;
124 }
125
126 inline bool isJSInteger(DataFormat format)
127 {
128     return isJSFormat(format, DataFormatJSInteger);
129 }
130
131 inline bool isJSDouble(DataFormat format)
132 {
133     return isJSFormat(format, DataFormatJSDouble);
134 }
135
136 inline bool isJSCell(DataFormat format)
137 {
138     return isJSFormat(format, DataFormatJSCell);
139 }
140
141 inline bool isJSBoolean(DataFormat format)
142 {
143     return isJSFormat(format, DataFormatJSBoolean);
144 }
145
146 // === GenerationInfo ===
147 //
148 // This class is used to track the current status of a live values during code generation.
149 // Can provide information as to whether a value is in machine registers, and if so which,
150 // whether a value has been spilled to the RegsiterFile, and if so may be able to provide
151 // details of the format in memory (all values are spilled in a boxed form, but we may be
152 // able to track the type of box), and tracks how many outstanding uses of a value remain,
153 // so that we know when the value is dead and the machine registers associated with it
154 // may be released.
155 class GenerationInfo {
156 public:
157     GenerationInfo()
158         : m_nodeIndex(NoNode)
159         , m_useCount(0)
160         , m_registerFormat(DataFormatNone)
161         , m_spillFormat(DataFormatNone)
162         , m_canFill(false)
163     {
164     }
165
166     void initConstant(NodeIndex nodeIndex, uint32_t useCount)
167     {
168         m_nodeIndex = nodeIndex;
169         m_useCount = useCount;
170         m_registerFormat = DataFormatNone;
171         m_spillFormat = DataFormatNone;
172         m_canFill = true;
173     }
174     void initInteger(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
175     {
176         m_nodeIndex = nodeIndex;
177         m_useCount = useCount;
178         m_registerFormat = DataFormatInteger;
179         m_spillFormat = DataFormatNone;
180         m_canFill = false;
181         u.gpr = gpr;
182     }
183     void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
184     {
185         ASSERT(format & DataFormatJS);
186
187         m_nodeIndex = nodeIndex;
188         m_useCount = useCount;
189         m_registerFormat = format;
190         m_spillFormat = DataFormatNone;
191         m_canFill = false;
192         u.gpr = gpr;
193     }
194     void initCell(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
195     {
196         m_nodeIndex = nodeIndex;
197         m_useCount = useCount;
198         m_registerFormat = DataFormatCell;
199         m_spillFormat = DataFormatNone;
200         m_canFill = false;
201         u.gpr = gpr;
202     }
203     void initDouble(NodeIndex nodeIndex, uint32_t useCount, FPRReg fpr)
204     {
205         m_nodeIndex = nodeIndex;
206         m_useCount = useCount;
207         m_registerFormat = DataFormatDouble;
208         m_spillFormat = DataFormatNone;
209         m_canFill = false;
210         u.fpr = fpr;
211     }
212
213     // Get the index of the node that produced this value.
214     NodeIndex nodeIndex() { return m_nodeIndex; }
215
216     // Mark the value as having been used (decrement the useCount).
217     // Returns true if this was the last use of the value, and any
218     // associated machine registers may be freed.
219     bool use()
220     {
221         return !--m_useCount;
222     }
223
224     // Used to check the operands of operations to see if they are on
225     // their last use; in some cases it may be safe to reuse the same
226     // machine register for the result of the operation.
227     bool canReuse()
228     {
229         ASSERT(m_useCount);
230         return m_useCount == 1;
231     }
232
233     // Get the format of the value in machine registers (or 'none').
234     DataFormat registerFormat() { return m_registerFormat; }
235     // Get the format of the value as it is spilled in the RegisterFile (or 'none').
236     DataFormat spillFormat() { return m_spillFormat; }
237     
238     bool isJSFormat(DataFormat expectedFormat)
239     {
240         return DFG::isJSFormat(registerFormat(), expectedFormat) || DFG::isJSFormat(spillFormat(), expectedFormat);
241     }
242     
243     bool isJSInteger()
244     {
245         return isJSFormat(DataFormatJSInteger);
246     }
247     
248     bool isJSDouble()
249     {
250         return isJSFormat(DataFormatJSDouble);
251     }
252     
253     bool isJSCell()
254     {
255         return isJSFormat(DataFormatJSCell);
256     }
257     
258     bool isJSBoolean()
259     {
260         return isJSFormat(DataFormatJSBoolean);
261     }
262
263     // Get the machine resister currently holding the value.
264     GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
265     FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
266
267     // Check whether a value needs spilling in order to free up any associated machine registers.
268     bool needsSpill()
269     {
270         // This should only be called on values that are currently in a register.
271         ASSERT(m_registerFormat != DataFormatNone);
272         // Constants do not need spilling, nor do values that have already been
273         // spilled to the RegisterFile.
274         return !m_canFill;
275     }
276
277     // Called when a VirtualRegister is being spilled to the RegisterFile for the first time.
278     void spill(DataFormat spillFormat)
279     {
280         // We shouldn't be spill values that don't need spilling.
281         ASSERT(!m_canFill);
282         ASSERT(m_spillFormat == DataFormatNone);
283         // We should only be spilling values that are currently in machine registers.
284         ASSERT(m_registerFormat != DataFormatNone);
285         // We only spill values that have been boxed as a JSValue; otherwise the GC
286         // would need a way to distinguish cell pointers from numeric primitives.
287         ASSERT(spillFormat & DataFormatJS);
288
289         m_registerFormat = DataFormatNone;
290         m_spillFormat = spillFormat;
291         m_canFill = true;
292     }
293
294     // Called on values that don't need spilling (constants and values that have
295     // already been spilled), to mark them as no longer being in machine registers.
296     void setSpilled()
297     {
298         // Should only be called on values that don't need spilling, and are currently in registers.
299         ASSERT(m_canFill && m_registerFormat != DataFormatNone);
300         m_registerFormat = DataFormatNone;
301     }
302     
303     void killSpilled()
304     {
305         m_spillFormat = DataFormatNone;
306         m_canFill = false;
307     }
308
309     // Record that this value is filled into machine registers,
310     // tracking which registers, and what format the value has.
311     void fillJSValue(GPRReg gpr, DataFormat format = DataFormatJS)
312     {
313         ASSERT(format & DataFormatJS);
314         m_registerFormat = format;
315         u.gpr = gpr;
316     }
317     void fillInteger(GPRReg gpr)
318     {
319         m_registerFormat = DataFormatInteger;
320         u.gpr = gpr;
321     }
322     void fillDouble(FPRReg fpr)
323     {
324         m_registerFormat = DataFormatDouble;
325         u.fpr = fpr;
326     }
327
328     bool alive()
329     {
330         return m_useCount;
331     }
332
333 private:
334     // The index of the node whose result is stored in this virtual register.
335     // FIXME: Can we remove this? - this is currently only used when collecting
336     // snapshots of the RegisterBank for SpeculationCheck/EntryLocation. Could
337     // investigate storing NodeIndex as the name in RegsiterBank, instead of
338     // VirtualRegister.
339     NodeIndex m_nodeIndex;
340     uint32_t m_useCount;
341     DataFormat m_registerFormat;
342     DataFormat m_spillFormat;
343     bool m_canFill;
344     union {
345         GPRReg gpr;
346         FPRReg fpr;
347     } u;
348 };
349
350 } } // namespace JSC::DFG
351
352 #endif
353 #endif