460b1bbfcbdea8b85ffa451e7217b7458e2bd5bd
[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 <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     DataFormatStorage = 5,
48     DataFormatJS = 8,
49     DataFormatJSInteger = DataFormatJS | DataFormatInteger,
50     DataFormatJSDouble = DataFormatJS | DataFormatDouble,
51     DataFormatJSCell = DataFormatJS | DataFormatCell,
52     DataFormatJSBoolean = DataFormatJS | DataFormatBoolean
53 };
54
55 #ifndef NDEBUG
56 inline const char* dataFormatToString(DataFormat dataFormat)
57 {
58     switch (dataFormat) {
59     case DataFormatNone:
60         return "None";
61     case DataFormatInteger:
62         return "Integer";
63     case DataFormatDouble:
64         return "Double";
65     case DataFormatCell:
66         return "Cell";
67     case DataFormatBoolean:
68         return "Boolean";
69     case DataFormatStorage:
70         return "Storage";
71     case DataFormatJS:
72         return "JS";
73     case DataFormatJSInteger:
74         return "JSInteger";
75     case DataFormatJSDouble:
76         return "JSDouble";
77     case DataFormatJSCell:
78         return "JSCell";
79     case DataFormatJSBoolean:
80         return "JSBoolean";
81     default:
82         return "Unknown";
83     }
84 }
85 #endif
86
87 #if USE(JSVALUE64)
88 inline bool needDataFormatConversion(DataFormat from, DataFormat to)
89 {
90     ASSERT(from != DataFormatNone);
91     ASSERT(to != DataFormatNone);
92     switch (from) {
93     case DataFormatInteger:
94     case DataFormatDouble:
95         return to != from;
96     case DataFormatCell:
97     case DataFormatJS:
98     case DataFormatJSInteger:
99     case DataFormatJSDouble:
100     case DataFormatJSCell:
101     case DataFormatJSBoolean:
102         switch (to) {
103         case DataFormatInteger:
104         case DataFormatDouble:
105             return true;
106         case DataFormatCell:
107         case DataFormatJS:
108         case DataFormatJSInteger:
109         case DataFormatJSDouble:
110         case DataFormatJSCell:
111         case DataFormatJSBoolean:
112             return false;
113         default:
114             // This captures DataFormatBoolean, which is currently unused.
115             ASSERT_NOT_REACHED();
116         }
117     case DataFormatStorage:
118         ASSERT(to == DataFormatStorage);
119         return false;
120     default:
121         // This captures DataFormatBoolean, which is currently unused.
122         ASSERT_NOT_REACHED();
123     }
124     return true;
125 }
126
127 #elif USE(JSVALUE32_64)
128 inline bool needDataFormatConversion(DataFormat from, DataFormat to)
129 {
130     ASSERT(from != DataFormatNone);
131     ASSERT(to != DataFormatNone);
132     switch (from) {
133     case DataFormatInteger:
134     case DataFormatCell:
135     case DataFormatBoolean:
136         return ((to & DataFormatJS) || to == DataFormatDouble);
137     case DataFormatDouble:
138     case DataFormatJSDouble:
139         return (to != DataFormatDouble && to != DataFormatJSDouble);
140     case DataFormatJS:
141     case DataFormatJSInteger:
142     case DataFormatJSCell:
143     case DataFormatJSBoolean:
144         return (!(to & DataFormatJS) || to == DataFormatJSDouble);
145     case DataFormatStorage:
146         ASSERT(to == DataFormatStorage);
147         return false;
148     default:
149         ASSERT_NOT_REACHED();
150     }
151     return true;
152 }
153 #endif
154
155 inline bool isJSFormat(DataFormat format, DataFormat expectedFormat)
156 {
157     ASSERT(expectedFormat & DataFormatJS);
158     return (format | DataFormatJS) == expectedFormat;
159 }
160
161 inline bool isJSInteger(DataFormat format)
162 {
163     return isJSFormat(format, DataFormatJSInteger);
164 }
165
166 inline bool isJSDouble(DataFormat format)
167 {
168     return isJSFormat(format, DataFormatJSDouble);
169 }
170
171 inline bool isJSCell(DataFormat format)
172 {
173     return isJSFormat(format, DataFormatJSCell);
174 }
175
176 inline bool isJSBoolean(DataFormat format)
177 {
178     return isJSFormat(format, DataFormatJSBoolean);
179 }
180
181 // === GenerationInfo ===
182 //
183 // This class is used to track the current status of a live values during code generation.
184 // Can provide information as to whether a value is in machine registers, and if so which,
185 // whether a value has been spilled to the RegsiterFile, and if so may be able to provide
186 // details of the format in memory (all values are spilled in a boxed form, but we may be
187 // able to track the type of box), and tracks how many outstanding uses of a value remain,
188 // so that we know when the value is dead and the machine registers associated with it
189 // may be released.
190 class GenerationInfo {
191 public:
192     GenerationInfo()
193         : m_nodeIndex(NoNode)
194         , m_useCount(0)
195         , m_registerFormat(DataFormatNone)
196         , m_spillFormat(DataFormatNone)
197         , m_canFill(false)
198     {
199     }
200
201     void initConstant(NodeIndex nodeIndex, uint32_t useCount)
202     {
203         m_nodeIndex = nodeIndex;
204         m_useCount = useCount;
205         m_registerFormat = DataFormatNone;
206         m_spillFormat = DataFormatNone;
207         m_canFill = true;
208     }
209     void initInteger(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
210     {
211         m_nodeIndex = nodeIndex;
212         m_useCount = useCount;
213         m_registerFormat = DataFormatInteger;
214         m_spillFormat = DataFormatNone;
215         m_canFill = false;
216         u.gpr = gpr;
217     }
218 #if USE(JSVALUE64)
219     void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
220     {
221         ASSERT(format & DataFormatJS);
222
223         m_nodeIndex = nodeIndex;
224         m_useCount = useCount;
225         m_registerFormat = format;
226         m_spillFormat = DataFormatNone;
227         m_canFill = false;
228         u.gpr = gpr;
229     }
230 #elif USE(JSVALUE32_64)
231     void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
232     {
233         ASSERT(format & DataFormatJS);
234
235         m_nodeIndex = nodeIndex;
236         m_useCount = useCount;
237         m_registerFormat = format;
238         m_spillFormat = DataFormatNone;
239         m_canFill = false;
240         u.v.tagGPR = tagGPR;
241         u.v.payloadGPR = payloadGPR;
242     }
243 #endif
244     void initCell(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
245     {
246         m_nodeIndex = nodeIndex;
247         m_useCount = useCount;
248         m_registerFormat = DataFormatCell;
249         m_spillFormat = DataFormatNone;
250         m_canFill = false;
251         u.gpr = gpr;
252     }
253     void initBoolean(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
254     {
255         m_nodeIndex = nodeIndex;
256         m_useCount = useCount;
257         m_registerFormat = DataFormatBoolean;
258         m_spillFormat = DataFormatNone;
259         m_canFill = false;
260         u.gpr = gpr;
261     }
262     void initDouble(NodeIndex nodeIndex, uint32_t useCount, FPRReg fpr)
263     {
264         ASSERT(fpr != InvalidFPRReg);
265         m_nodeIndex = nodeIndex;
266         m_useCount = useCount;
267         m_registerFormat = DataFormatDouble;
268         m_spillFormat = DataFormatNone;
269         m_canFill = false;
270         u.fpr = fpr;
271     }
272     void initStorage(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
273     {
274         m_nodeIndex = nodeIndex;
275         m_useCount = useCount;
276         m_registerFormat = DataFormatStorage;
277         m_spillFormat = DataFormatNone;
278         m_canFill = false;
279         u.gpr = gpr;
280     }
281
282     // Get the index of the node that produced this value.
283     NodeIndex nodeIndex() { return m_nodeIndex; }
284
285     // Mark the value as having been used (decrement the useCount).
286     // Returns true if this was the last use of the value, and any
287     // associated machine registers may be freed.
288     bool use()
289     {
290         return !--m_useCount;
291     }
292
293     // Used to check the operands of operations to see if they are on
294     // their last use; in some cases it may be safe to reuse the same
295     // machine register for the result of the operation.
296     bool canReuse()
297     {
298         ASSERT(m_useCount);
299         return m_useCount == 1;
300     }
301
302     // Get the format of the value in machine registers (or 'none').
303     DataFormat registerFormat() { return m_registerFormat; }
304     // Get the format of the value as it is spilled in the RegisterFile (or 'none').
305     DataFormat spillFormat() { return m_spillFormat; }
306     
307     bool isJSFormat(DataFormat expectedFormat)
308     {
309         return DFG::isJSFormat(registerFormat(), expectedFormat) || DFG::isJSFormat(spillFormat(), expectedFormat);
310     }
311     
312     bool isJSInteger()
313     {
314         return isJSFormat(DataFormatJSInteger);
315     }
316     
317     bool isJSDouble()
318     {
319         return isJSFormat(DataFormatJSDouble);
320     }
321     
322     bool isJSCell()
323     {
324         return isJSFormat(DataFormatJSCell);
325     }
326     
327     bool isJSBoolean()
328     {
329         return isJSFormat(DataFormatJSBoolean);
330     }
331     
332     bool isUnknownJS()
333     {
334         return registerFormat() == DataFormatNone || registerFormat() == DataFormatJS
335             || spillFormat() == DataFormatNone || spillFormat() == DataFormatJS;
336     }
337
338     // Get the machine resister currently holding the value.
339 #if USE(JSVALUE64)
340     GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
341     FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
342     JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.gpr); }
343 #elif USE(JSVALUE32_64)
344     GPRReg gpr() { ASSERT(!(m_registerFormat & DataFormatJS) && m_registerFormat != DataFormatDouble); return u.gpr; }
345     GPRReg tagGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.tagGPR; }
346     GPRReg payloadGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.payloadGPR; }
347     FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble || m_registerFormat == DataFormatJSDouble); return u.fpr; }
348     JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.v.tagGPR, u.v.payloadGPR); }
349 #endif
350
351     // Check whether a value needs spilling in order to free up any associated machine registers.
352     bool needsSpill()
353     {
354         // This should only be called on values that are currently in a register.
355         ASSERT(m_registerFormat != DataFormatNone);
356         // Constants do not need spilling, nor do values that have already been
357         // spilled to the RegisterFile.
358         return !m_canFill;
359     }
360
361     // Called when a VirtualRegister is being spilled to the RegisterFile for the first time.
362     void spill(DataFormat spillFormat)
363     {
364         // We shouldn't be spill values that don't need spilling.
365         ASSERT(!m_canFill);
366         ASSERT(m_spillFormat == DataFormatNone);
367         // We should only be spilling values that are currently in machine registers.
368         ASSERT(m_registerFormat != DataFormatNone);
369         // We only spill values that have been boxed as a JSValue because historically
370         // we assumed that the GC would want to be able to precisely identify heap
371         // pointers. This is not true anymore, but we still assume, in the fill code,
372         // that any spill slot for a JS value is boxed. For storage pointers, there is
373         // nothing we can do to box them, so we allow that to be an exception.
374         ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatStorage || spillFormat == DataFormatInteger || spillFormat == DataFormatDouble);
375
376         m_registerFormat = DataFormatNone;
377         m_spillFormat = spillFormat;
378         m_canFill = true;
379     }
380
381     // Called on values that don't need spilling (constants and values that have
382     // already been spilled), to mark them as no longer being in machine registers.
383     void setSpilled()
384     {
385         // Should only be called on values that don't need spilling, and are currently in registers.
386         ASSERT(m_canFill && m_registerFormat != DataFormatNone);
387         m_registerFormat = DataFormatNone;
388     }
389     
390     void killSpilled()
391     {
392         m_spillFormat = DataFormatNone;
393         m_canFill = false;
394     }
395
396     // Record that this value is filled into machine registers,
397     // tracking which registers, and what format the value has.
398 #if USE(JSVALUE64)
399     void fillJSValue(GPRReg gpr, DataFormat format = DataFormatJS)
400     {
401         ASSERT(format & DataFormatJS);
402         m_registerFormat = format;
403         u.gpr = gpr;
404     }
405 #elif USE(JSVALUE32_64)
406     void fillJSValue(GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
407     {
408         ASSERT(format & DataFormatJS);
409         m_registerFormat = format;
410         u.v.tagGPR = tagGPR; // FIXME: for JSValues with known type (boolean, integer, cell etc.) no tagGPR is needed?
411         u.v.payloadGPR = payloadGPR;
412     }
413     void fillCell(GPRReg gpr)
414     {
415         m_registerFormat = DataFormatCell;
416         u.gpr = gpr;
417     }
418 #endif
419     void fillInteger(GPRReg gpr)
420     {
421         m_registerFormat = DataFormatInteger;
422         u.gpr = gpr;
423     }
424     void fillBoolean(GPRReg gpr)
425     {
426         m_registerFormat = DataFormatBoolean;
427         u.gpr = gpr;
428     }
429     void fillDouble(FPRReg fpr)
430     {
431         ASSERT(fpr != InvalidFPRReg);
432         m_registerFormat = DataFormatDouble;
433         u.fpr = fpr;
434     }
435     void fillStorage(GPRReg gpr)
436     {
437         m_registerFormat = DataFormatStorage;
438         u.gpr = gpr;
439     }
440
441     bool alive()
442     {
443         return m_useCount;
444     }
445
446 private:
447     // The index of the node whose result is stored in this virtual register.
448     NodeIndex m_nodeIndex;
449     uint32_t m_useCount;
450     DataFormat m_registerFormat;
451     DataFormat m_spillFormat;
452     bool m_canFill;
453     union {
454         GPRReg gpr;
455         FPRReg fpr;
456 #if USE(JSVALUE32_64)
457         struct {
458             GPRReg tagGPR;
459             GPRReg payloadGPR;
460         } v;
461 #endif
462     } u;
463 };
464
465 } } // namespace JSC::DFG
466
467 #endif
468 #endif