Remove excessive headers from JavaScriptCore
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGGenerationInfo.h
1 /*
2  * Copyright (C) 2011, 2013 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 #pragma once
27
28 #if ENABLE(DFG_JIT)
29
30 #include "DFGMinifiedID.h"
31 #include "DFGVariableEvent.h"
32 #include "DFGVariableEventStream.h"
33 #include "DataFormat.h"
34
35 namespace JSC { namespace DFG {
36
37 // === GenerationInfo ===
38 //
39 // This class is used to track the current status of live values during code generation.
40 // Can provide information as to whether a value is in machine registers, and if so which,
41 // whether a value has been spilled to the RegisterFile, and if so may be able to provide
42 // details of the format in memory (all values are spilled in a boxed form, but we may be
43 // able to track the type of box), and tracks how many outstanding uses of a value remain,
44 // so that we know when the value is dead and the machine registers associated with it
45 // may be released.
46 class GenerationInfo {
47 public:
48     GenerationInfo()
49         : m_node(0)
50         , m_useCount(0)
51         , m_registerFormat(DataFormatNone)
52         , m_spillFormat(DataFormatNone)
53         , m_canFill(false)
54         , m_bornForOSR(false)
55         , m_isConstant(false)
56     {
57     }
58
59     void initConstant(Node* node, uint32_t useCount)
60     {
61         m_node = node;
62         m_useCount = useCount;
63         m_registerFormat = DataFormatNone;
64         m_spillFormat = DataFormatNone;
65         m_canFill = true;
66         m_bornForOSR = false;
67         m_isConstant = true;
68         ASSERT(m_useCount);
69     }
70     void initGPR(Node* node, uint32_t useCount, GPRReg gpr, DataFormat format)
71     {
72         ASSERT(gpr != InvalidGPRReg);
73         m_node = node;
74         m_useCount = useCount;
75         m_registerFormat = format;
76         m_spillFormat = DataFormatNone;
77         m_canFill = false;
78         u.gpr = gpr;
79         m_bornForOSR = false;
80         m_isConstant = false;
81         ASSERT(m_useCount);
82     }
83     void initInt32(Node* node, uint32_t useCount, GPRReg gpr)
84     {
85         initGPR(node, useCount, gpr, DataFormatInt32);
86     }
87     void initInt52(Node* node, uint32_t useCount, GPRReg reg, DataFormat format)
88     {
89         ASSERT(format == DataFormatInt52 || format == DataFormatStrictInt52);
90         initGPR(node, useCount, reg, format);
91     }
92     void initInt52(Node* node, uint32_t useCount, GPRReg reg)
93     {
94         initGPR(node, useCount, reg, DataFormatInt52);
95     }
96     void initStrictInt52(Node* node, uint32_t useCount, GPRReg reg)
97     {
98         initGPR(node, useCount, reg, DataFormatStrictInt52);
99     }
100 #if USE(JSVALUE64)
101     void initJSValue(Node* node, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
102     {
103         ASSERT(format & DataFormatJS);
104         initGPR(node, useCount, gpr, format);
105     }
106 #elif USE(JSVALUE32_64)
107     void initJSValue(Node* node, uint32_t useCount, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
108     {
109         ASSERT(format & DataFormatJS);
110
111         m_node = node;
112         m_useCount = useCount;
113         m_registerFormat = format;
114         m_spillFormat = DataFormatNone;
115         m_canFill = false;
116         u.v.tagGPR = tagGPR;
117         u.v.payloadGPR = payloadGPR;
118         m_bornForOSR = false;
119         m_isConstant = false;
120         ASSERT(m_useCount);
121     }
122 #endif
123     void initCell(Node* node, uint32_t useCount, GPRReg gpr)
124     {
125         initGPR(node, useCount, gpr, DataFormatCell);
126     }
127     void initBoolean(Node* node, uint32_t useCount, GPRReg gpr)
128     {
129         initGPR(node, useCount, gpr, DataFormatBoolean);
130     }
131     void initDouble(Node* node, uint32_t useCount, FPRReg fpr)
132     {
133         ASSERT(fpr != InvalidFPRReg);
134         m_node = node;
135         m_useCount = useCount;
136         m_registerFormat = DataFormatDouble;
137         m_spillFormat = DataFormatNone;
138         m_canFill = false;
139         u.fpr = fpr;
140         m_bornForOSR = false;
141         m_isConstant = false;
142         ASSERT(m_useCount);
143     }
144     void initStorage(Node* node, uint32_t useCount, GPRReg gpr)
145     {
146         initGPR(node, useCount, gpr, DataFormatStorage);
147     }
148
149     // Get the node that produced this value.
150     Node* node() { return m_node; }
151     
152     void noticeOSRBirth(VariableEventStream& stream, Node* node, VirtualRegister virtualRegister)
153     {
154         if (m_node != node)
155             return;
156         if (!alive())
157             return;
158         if (m_bornForOSR)
159             return;
160         
161         m_bornForOSR = true;
162         
163         if (m_isConstant)
164             appendBirth(stream);
165         else if (m_registerFormat != DataFormatNone)
166             appendFill(BirthToFill, stream);
167         else if (m_spillFormat != DataFormatNone)
168             appendSpill(BirthToSpill, stream, virtualRegister);
169     }
170
171     // Mark the value as having been used (decrement the useCount).
172     // Returns true if this was the last use of the value, and any
173     // associated machine registers may be freed.
174     bool use(VariableEventStream& stream)
175     {
176         ASSERT(m_useCount);
177         bool result = !--m_useCount;
178         
179         if (result && m_bornForOSR) {
180             ASSERT(m_node);
181             stream.appendAndLog(VariableEvent::death(MinifiedID(m_node)));
182         }
183         
184         return result;
185     }
186
187     // Used to check the operands of operations to see if they are on
188     // their last use; in some cases it may be safe to reuse the same
189     // machine register for the result of the operation.
190     uint32_t useCount()
191     {
192         ASSERT(m_useCount);
193         return m_useCount;
194     }
195
196     // Get the format of the value in machine registers (or 'none').
197     DataFormat registerFormat() { return m_registerFormat; }
198     // Get the format of the value as it is spilled in the JSStack (or 'none').
199     DataFormat spillFormat() { return m_spillFormat; }
200     
201     bool isFormat(DataFormat expectedFormat)
202     {
203         return registerFormat() == expectedFormat || spillFormat() == expectedFormat;
204     }
205     
206     bool isJSFormat(DataFormat expectedFormat)
207     {
208         return JSC::isJSFormat(registerFormat(), expectedFormat) || JSC::isJSFormat(spillFormat(), expectedFormat);
209     }
210     
211     bool isJSInt32()
212     {
213         return isJSFormat(DataFormatJSInt32);
214     }
215     
216     bool isInt52()
217     {
218         return isFormat(DataFormatInt52);
219     }
220     
221     bool isStrictInt52()
222     {
223         return isFormat(DataFormatStrictInt52);
224     }
225     
226     bool isJSDouble()
227     {
228         return isJSFormat(DataFormatJSDouble);
229     }
230     
231     bool isJSCell()
232     {
233         return isJSFormat(DataFormatJSCell);
234     }
235     
236     bool isJSBoolean()
237     {
238         return isJSFormat(DataFormatJSBoolean);
239     }
240     
241     bool isUnknownJS()
242     {
243         return spillFormat() == DataFormatNone
244             ? registerFormat() == DataFormatJS || registerFormat() == DataFormatNone
245             : spillFormat() == DataFormatJS;
246     }
247
248     // Get the machine resister currently holding the value.
249 #if USE(JSVALUE64)
250     GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
251     FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
252     JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.gpr); }
253 #elif USE(JSVALUE32_64)
254     GPRReg gpr() { ASSERT(!(m_registerFormat & DataFormatJS) && m_registerFormat != DataFormatDouble); return u.gpr; }
255     GPRReg tagGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.tagGPR; }
256     GPRReg payloadGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.payloadGPR; }
257     FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble || m_registerFormat == DataFormatJSDouble); return u.fpr; }
258     JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.v.tagGPR, u.v.payloadGPR); }
259 #endif
260
261     // Check whether a value needs spilling in order to free up any associated machine registers.
262     bool needsSpill()
263     {
264         // This should only be called on values that are currently in a register.
265         ASSERT(m_registerFormat != DataFormatNone);
266         // Constants do not need spilling, nor do values that have already been
267         // spilled to the JSStack.
268         return !m_canFill;
269     }
270
271     // Called when a VirtualRegister is being spilled to the JSStack for the first time.
272     void spill(VariableEventStream& stream, VirtualRegister virtualRegister, DataFormat spillFormat)
273     {
274         // We shouldn't be spill values that don't need spilling.
275         ASSERT(!m_canFill);
276         ASSERT(m_spillFormat == DataFormatNone);
277         // We should only be spilling values that are currently in machine registers.
278         ASSERT(m_registerFormat != DataFormatNone);
279
280         m_registerFormat = DataFormatNone;
281         m_spillFormat = spillFormat;
282         m_canFill = true;
283         
284         if (m_bornForOSR)
285             appendSpill(Spill, stream, virtualRegister);
286     }
287
288     // Called on values that don't need spilling (constants and values that have
289     // already been spilled), to mark them as no longer being in machine registers.
290     void setSpilled(VariableEventStream& stream, VirtualRegister virtualRegister)
291     {
292         // Should only be called on values that don't need spilling, and are currently in registers.
293         ASSERT(m_canFill && m_registerFormat != DataFormatNone);
294         m_registerFormat = DataFormatNone;
295         
296         if (m_bornForOSR)
297             appendSpill(Spill, stream, virtualRegister);
298     }
299     
300     void killSpilled()
301     {
302         m_spillFormat = DataFormatNone;
303         m_canFill = false;
304     }
305     
306     void fillGPR(VariableEventStream& stream, GPRReg gpr, DataFormat format)
307     {
308         ASSERT(gpr != InvalidGPRReg);
309         m_registerFormat = format;
310         u.gpr = gpr;
311         if (m_bornForOSR)
312             appendFill(Fill, stream);
313     }
314
315     // Record that this value is filled into machine registers,
316     // tracking which registers, and what format the value has.
317 #if USE(JSVALUE64)
318     void fillJSValue(VariableEventStream& stream, GPRReg gpr, DataFormat format = DataFormatJS)
319     {
320         ASSERT(format & DataFormatJS);
321         fillGPR(stream, gpr, format);
322     }
323 #elif USE(JSVALUE32_64)
324     void fillJSValue(VariableEventStream& stream, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
325     {
326         ASSERT(format & DataFormatJS);
327         m_registerFormat = format;
328         u.v.tagGPR = tagGPR; // FIXME: for JSValues with known type (boolean, integer, cell etc.) no tagGPR is needed?
329         u.v.payloadGPR = payloadGPR;
330         
331         if (m_bornForOSR)
332             appendFill(Fill, stream);
333     }
334     void fillCell(VariableEventStream& stream, GPRReg gpr)
335     {
336         fillGPR(stream, gpr, DataFormatCell);
337     }
338 #endif
339     void fillInt32(VariableEventStream& stream, GPRReg gpr)
340     {
341         fillGPR(stream, gpr, DataFormatInt32);
342     }
343     void fillInt52(VariableEventStream& stream, GPRReg gpr, DataFormat format)
344     {
345         ASSERT(format == DataFormatInt52 || format == DataFormatStrictInt52);
346         fillGPR(stream, gpr, format);
347     }
348     void fillInt52(VariableEventStream& stream, GPRReg gpr)
349     {
350         fillGPR(stream, gpr, DataFormatInt52);
351     }
352     void fillStrictInt52(VariableEventStream& stream, GPRReg gpr)
353     {
354         fillGPR(stream, gpr, DataFormatStrictInt52);
355     }
356     void fillBoolean(VariableEventStream& stream, GPRReg gpr)
357     {
358         fillGPR(stream, gpr, DataFormatBoolean);
359     }
360     void fillDouble(VariableEventStream& stream, FPRReg fpr)
361     {
362         ASSERT(fpr != InvalidFPRReg);
363         m_registerFormat = DataFormatDouble;
364         u.fpr = fpr;
365         
366         if (m_bornForOSR)
367             appendFill(Fill, stream);
368     }
369     void fillStorage(VariableEventStream& stream, GPRReg gpr)
370     {
371         fillGPR(stream, gpr, DataFormatStorage);
372     }
373
374     bool alive()
375     {
376         return m_useCount;
377     }
378
379     ValueRecovery recovery(VirtualRegister spillSlot) const
380     {
381         if (m_isConstant)
382             return ValueRecovery::constant(m_node->constant()->value());
383
384         if (m_registerFormat == DataFormatDouble)
385             return ValueRecovery::inFPR(u.fpr, DataFormatDouble);
386
387 #if USE(JSVALUE32_64)
388         if (m_registerFormat & DataFormatJS) {
389             if (m_registerFormat == DataFormatJS)
390                 return ValueRecovery::inPair(u.v.tagGPR, u.v.payloadGPR);
391             return ValueRecovery::inGPR(u.v.payloadGPR, static_cast<DataFormat>(m_registerFormat & ~DataFormatJS));
392         }
393 #endif
394         if (m_registerFormat)
395             return ValueRecovery::inGPR(u.gpr, m_registerFormat);
396
397         ASSERT(m_spillFormat);
398
399         return ValueRecovery::displacedInJSStack(spillSlot, m_spillFormat);
400     }
401
402 private:
403     void appendBirth(VariableEventStream& stream)
404     {
405         stream.appendAndLog(VariableEvent::birth(MinifiedID(m_node)));
406     }
407     
408     void appendFill(VariableEventKind kind, VariableEventStream& stream)
409     {
410         ASSERT(m_bornForOSR);
411         
412         if (m_registerFormat == DataFormatDouble) {
413             stream.appendAndLog(VariableEvent::fillFPR(kind, MinifiedID(m_node), u.fpr));
414             return;
415         }
416 #if USE(JSVALUE32_64)
417         if (m_registerFormat & DataFormatJS) {
418             stream.appendAndLog(VariableEvent::fillPair(kind, MinifiedID(m_node), u.v.tagGPR, u.v.payloadGPR));
419             return;
420         }
421 #endif
422         stream.appendAndLog(VariableEvent::fillGPR(kind, MinifiedID(m_node), u.gpr, m_registerFormat));
423     }
424     
425     void appendSpill(VariableEventKind kind, VariableEventStream& stream, VirtualRegister virtualRegister)
426     {
427         stream.appendAndLog(VariableEvent::spill(kind, MinifiedID(m_node), virtualRegister, m_spillFormat));
428     }
429     
430     // The node whose result is stored in this virtual register.
431     Node* m_node;
432     uint32_t m_useCount;
433     DataFormat m_registerFormat;
434     DataFormat m_spillFormat;
435     bool m_canFill;
436     bool m_bornForOSR;
437     bool m_isConstant;
438     union {
439         GPRReg gpr;
440         FPRReg fpr;
441 #if USE(JSVALUE32_64)
442         struct {
443             GPRReg tagGPR;
444             GPRReg payloadGPR;
445         } v;
446 #endif
447     } u;
448 };
449
450 } } // namespace JSC::DFG
451
452 #endif