ValueRecovery should be moved out of the DFG JIT
[WebKit-https.git] / 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 "DataFormat.h"
32 #include <dfg/DFGJITCompiler.h>
33
34 namespace JSC { namespace DFG {
35
36 // === GenerationInfo ===
37 //
38 // This class is used to track the current status of a live values during code generation.
39 // Can provide information as to whether a value is in machine registers, and if so which,
40 // whether a value has been spilled to the RegsiterFile, and if so may be able to provide
41 // details of the format in memory (all values are spilled in a boxed form, but we may be
42 // able to track the type of box), and tracks how many outstanding uses of a value remain,
43 // so that we know when the value is dead and the machine registers associated with it
44 // may be released.
45 class GenerationInfo {
46 public:
47     GenerationInfo()
48         : m_nodeIndex(NoNode)
49         , m_useCount(0)
50         , m_registerFormat(DataFormatNone)
51         , m_spillFormat(DataFormatNone)
52         , m_canFill(false)
53     {
54     }
55
56     void initConstant(NodeIndex nodeIndex, uint32_t useCount)
57     {
58         m_nodeIndex = nodeIndex;
59         m_useCount = useCount;
60         m_registerFormat = DataFormatNone;
61         m_spillFormat = DataFormatNone;
62         m_canFill = true;
63     }
64     void initInteger(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
65     {
66         m_nodeIndex = nodeIndex;
67         m_useCount = useCount;
68         m_registerFormat = DataFormatInteger;
69         m_spillFormat = DataFormatNone;
70         m_canFill = false;
71         u.gpr = gpr;
72     }
73 #if USE(JSVALUE64)
74     void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
75     {
76         ASSERT(format & DataFormatJS);
77
78         m_nodeIndex = nodeIndex;
79         m_useCount = useCount;
80         m_registerFormat = format;
81         m_spillFormat = DataFormatNone;
82         m_canFill = false;
83         u.gpr = gpr;
84     }
85 #elif USE(JSVALUE32_64)
86     void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
87     {
88         ASSERT(format & DataFormatJS);
89
90         m_nodeIndex = nodeIndex;
91         m_useCount = useCount;
92         m_registerFormat = format;
93         m_spillFormat = DataFormatNone;
94         m_canFill = false;
95         u.v.tagGPR = tagGPR;
96         u.v.payloadGPR = payloadGPR;
97     }
98 #endif
99     void initCell(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
100     {
101         m_nodeIndex = nodeIndex;
102         m_useCount = useCount;
103         m_registerFormat = DataFormatCell;
104         m_spillFormat = DataFormatNone;
105         m_canFill = false;
106         u.gpr = gpr;
107     }
108     void initBoolean(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
109     {
110         m_nodeIndex = nodeIndex;
111         m_useCount = useCount;
112         m_registerFormat = DataFormatBoolean;
113         m_spillFormat = DataFormatNone;
114         m_canFill = false;
115         u.gpr = gpr;
116     }
117     void initDouble(NodeIndex nodeIndex, uint32_t useCount, FPRReg fpr)
118     {
119         ASSERT(fpr != InvalidFPRReg);
120         m_nodeIndex = nodeIndex;
121         m_useCount = useCount;
122         m_registerFormat = DataFormatDouble;
123         m_spillFormat = DataFormatNone;
124         m_canFill = false;
125         u.fpr = fpr;
126     }
127     void initStorage(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
128     {
129         m_nodeIndex = nodeIndex;
130         m_useCount = useCount;
131         m_registerFormat = DataFormatStorage;
132         m_spillFormat = DataFormatNone;
133         m_canFill = false;
134         u.gpr = gpr;
135     }
136
137     // Get the index of the node that produced this value.
138     NodeIndex nodeIndex() { return m_nodeIndex; }
139
140     // Mark the value as having been used (decrement the useCount).
141     // Returns true if this was the last use of the value, and any
142     // associated machine registers may be freed.
143     bool use()
144     {
145         return !--m_useCount;
146     }
147
148     // Used to check the operands of operations to see if they are on
149     // their last use; in some cases it may be safe to reuse the same
150     // machine register for the result of the operation.
151     bool canReuse()
152     {
153         ASSERT(m_useCount);
154         return m_useCount == 1;
155     }
156
157     // Get the format of the value in machine registers (or 'none').
158     DataFormat registerFormat() { return m_registerFormat; }
159     // Get the format of the value as it is spilled in the RegisterFile (or 'none').
160     DataFormat spillFormat() { return m_spillFormat; }
161     
162     bool isJSFormat(DataFormat expectedFormat)
163     {
164         return JSC::isJSFormat(registerFormat(), expectedFormat) || JSC::isJSFormat(spillFormat(), expectedFormat);
165     }
166     
167     bool isJSInteger()
168     {
169         return isJSFormat(DataFormatJSInteger);
170     }
171     
172     bool isJSDouble()
173     {
174         return isJSFormat(DataFormatJSDouble);
175     }
176     
177     bool isJSCell()
178     {
179         return isJSFormat(DataFormatJSCell);
180     }
181     
182     bool isJSBoolean()
183     {
184         return isJSFormat(DataFormatJSBoolean);
185     }
186     
187     bool isUnknownJS()
188     {
189         return registerFormat() == DataFormatNone || registerFormat() == DataFormatJS
190             || spillFormat() == DataFormatNone || spillFormat() == DataFormatJS;
191     }
192
193     // Get the machine resister currently holding the value.
194 #if USE(JSVALUE64)
195     GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
196     FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
197     JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.gpr); }
198 #elif USE(JSVALUE32_64)
199     GPRReg gpr() { ASSERT(!(m_registerFormat & DataFormatJS) && m_registerFormat != DataFormatDouble); return u.gpr; }
200     GPRReg tagGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.tagGPR; }
201     GPRReg payloadGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.payloadGPR; }
202     FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble || m_registerFormat == DataFormatJSDouble); return u.fpr; }
203     JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.v.tagGPR, u.v.payloadGPR); }
204 #endif
205
206     // Check whether a value needs spilling in order to free up any associated machine registers.
207     bool needsSpill()
208     {
209         // This should only be called on values that are currently in a register.
210         ASSERT(m_registerFormat != DataFormatNone);
211         // Constants do not need spilling, nor do values that have already been
212         // spilled to the RegisterFile.
213         return !m_canFill;
214     }
215
216     // Called when a VirtualRegister is being spilled to the RegisterFile for the first time.
217     void spill(DataFormat spillFormat)
218     {
219         // We shouldn't be spill values that don't need spilling.
220         ASSERT(!m_canFill);
221         ASSERT(m_spillFormat == DataFormatNone);
222         // We should only be spilling values that are currently in machine registers.
223         ASSERT(m_registerFormat != DataFormatNone);
224         // We only spill values that have been boxed as a JSValue because historically
225         // we assumed that the GC would want to be able to precisely identify heap
226         // pointers. This is not true anymore, but we still assume, in the fill code,
227         // that any spill slot for a JS value is boxed. For storage pointers, there is
228         // nothing we can do to box them, so we allow that to be an exception.
229         ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatStorage || spillFormat == DataFormatInteger || spillFormat == DataFormatDouble);
230
231         m_registerFormat = DataFormatNone;
232         m_spillFormat = spillFormat;
233         m_canFill = true;
234     }
235
236     // Called on values that don't need spilling (constants and values that have
237     // already been spilled), to mark them as no longer being in machine registers.
238     void setSpilled()
239     {
240         // Should only be called on values that don't need spilling, and are currently in registers.
241         ASSERT(m_canFill && m_registerFormat != DataFormatNone);
242         m_registerFormat = DataFormatNone;
243     }
244     
245     void killSpilled()
246     {
247         m_spillFormat = DataFormatNone;
248         m_canFill = false;
249     }
250
251     // Record that this value is filled into machine registers,
252     // tracking which registers, and what format the value has.
253 #if USE(JSVALUE64)
254     void fillJSValue(GPRReg gpr, DataFormat format = DataFormatJS)
255     {
256         ASSERT(format & DataFormatJS);
257         m_registerFormat = format;
258         u.gpr = gpr;
259     }
260 #elif USE(JSVALUE32_64)
261     void fillJSValue(GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
262     {
263         ASSERT(format & DataFormatJS);
264         m_registerFormat = format;
265         u.v.tagGPR = tagGPR; // FIXME: for JSValues with known type (boolean, integer, cell etc.) no tagGPR is needed?
266         u.v.payloadGPR = payloadGPR;
267     }
268     void fillCell(GPRReg gpr)
269     {
270         m_registerFormat = DataFormatCell;
271         u.gpr = gpr;
272     }
273 #endif
274     void fillInteger(GPRReg gpr)
275     {
276         m_registerFormat = DataFormatInteger;
277         u.gpr = gpr;
278     }
279     void fillBoolean(GPRReg gpr)
280     {
281         m_registerFormat = DataFormatBoolean;
282         u.gpr = gpr;
283     }
284     void fillDouble(FPRReg fpr)
285     {
286         ASSERT(fpr != InvalidFPRReg);
287         m_registerFormat = DataFormatDouble;
288         u.fpr = fpr;
289     }
290     void fillStorage(GPRReg gpr)
291     {
292         m_registerFormat = DataFormatStorage;
293         u.gpr = gpr;
294     }
295
296     bool alive()
297     {
298         return m_useCount;
299     }
300
301 private:
302     // The index of the node whose result is stored in this virtual register.
303     NodeIndex m_nodeIndex;
304     uint32_t m_useCount;
305     DataFormat m_registerFormat;
306     DataFormat m_spillFormat;
307     bool m_canFill;
308     union {
309         GPRReg gpr;
310         FPRReg fpr;
311 #if USE(JSVALUE32_64)
312         struct {
313             GPRReg tagGPR;
314             GPRReg payloadGPR;
315         } v;
316 #endif
317     } u;
318 };
319
320 } } // namespace JSC::DFG
321
322 #endif
323 #endif