]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGGenerationInfo.h
JavaScriptCore-1097.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGGenerationInfo.h
1
2 /*
3 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #ifndef DFGGenerationInfo_h
28 #define DFGGenerationInfo_h
29
30 #if ENABLE(DFG_JIT)
31
32 #include "DataFormat.h"
33 #include <dfg/DFGJITCompiler.h>
34
35 namespace JSC { namespace DFG {
36
37 // === GenerationInfo ===
38 //
39 // This class is used to track the current status of a 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 RegsiterFile, 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_nodeIndex(NoNode)
50 , m_useCount(0)
51 , m_registerFormat(DataFormatNone)
52 , m_spillFormat(DataFormatNone)
53 , m_canFill(false)
54 {
55 }
56
57 void initConstant(NodeIndex nodeIndex, uint32_t useCount)
58 {
59 m_nodeIndex = nodeIndex;
60 m_useCount = useCount;
61 m_registerFormat = DataFormatNone;
62 m_spillFormat = DataFormatNone;
63 m_canFill = true;
64 ASSERT(m_useCount);
65 }
66 void initInteger(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
67 {
68 m_nodeIndex = nodeIndex;
69 m_useCount = useCount;
70 m_registerFormat = DataFormatInteger;
71 m_spillFormat = DataFormatNone;
72 m_canFill = false;
73 u.gpr = gpr;
74 ASSERT(m_useCount);
75 }
76 #if USE(JSVALUE64)
77 void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
78 {
79 ASSERT(format & DataFormatJS);
80
81 m_nodeIndex = nodeIndex;
82 m_useCount = useCount;
83 m_registerFormat = format;
84 m_spillFormat = DataFormatNone;
85 m_canFill = false;
86 u.gpr = gpr;
87 ASSERT(m_useCount);
88 }
89 #elif USE(JSVALUE32_64)
90 void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
91 {
92 ASSERT(format & DataFormatJS);
93
94 m_nodeIndex = nodeIndex;
95 m_useCount = useCount;
96 m_registerFormat = format;
97 m_spillFormat = DataFormatNone;
98 m_canFill = false;
99 u.v.tagGPR = tagGPR;
100 u.v.payloadGPR = payloadGPR;
101 ASSERT(m_useCount);
102 }
103 #endif
104 void initCell(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
105 {
106 m_nodeIndex = nodeIndex;
107 m_useCount = useCount;
108 m_registerFormat = DataFormatCell;
109 m_spillFormat = DataFormatNone;
110 m_canFill = false;
111 u.gpr = gpr;
112 ASSERT(m_useCount);
113 }
114 void initBoolean(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
115 {
116 m_nodeIndex = nodeIndex;
117 m_useCount = useCount;
118 m_registerFormat = DataFormatBoolean;
119 m_spillFormat = DataFormatNone;
120 m_canFill = false;
121 u.gpr = gpr;
122 ASSERT(m_useCount);
123 }
124 void initDouble(NodeIndex nodeIndex, uint32_t useCount, FPRReg fpr)
125 {
126 ASSERT(fpr != InvalidFPRReg);
127 m_nodeIndex = nodeIndex;
128 m_useCount = useCount;
129 m_registerFormat = DataFormatDouble;
130 m_spillFormat = DataFormatNone;
131 m_canFill = false;
132 u.fpr = fpr;
133 ASSERT(m_useCount);
134 }
135 void initStorage(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
136 {
137 m_nodeIndex = nodeIndex;
138 m_useCount = useCount;
139 m_registerFormat = DataFormatStorage;
140 m_spillFormat = DataFormatNone;
141 m_canFill = false;
142 u.gpr = gpr;
143 ASSERT(m_useCount);
144 }
145
146 // Get the index of the node that produced this value.
147 NodeIndex nodeIndex() { return m_nodeIndex; }
148
149 // Mark the value as having been used (decrement the useCount).
150 // Returns true if this was the last use of the value, and any
151 // associated machine registers may be freed.
152 bool use()
153 {
154 ASSERT(m_useCount);
155 return !--m_useCount;
156 }
157
158 // Used to check the operands of operations to see if they are on
159 // their last use; in some cases it may be safe to reuse the same
160 // machine register for the result of the operation.
161 bool canReuse()
162 {
163 ASSERT(m_useCount);
164 return m_useCount == 1;
165 }
166
167 // Get the format of the value in machine registers (or 'none').
168 DataFormat registerFormat() { return m_registerFormat; }
169 // Get the format of the value as it is spilled in the RegisterFile (or 'none').
170 DataFormat spillFormat() { return m_spillFormat; }
171
172 bool isJSFormat(DataFormat expectedFormat)
173 {
174 return JSC::isJSFormat(registerFormat(), expectedFormat) || JSC::isJSFormat(spillFormat(), expectedFormat);
175 }
176
177 bool isJSInteger()
178 {
179 return isJSFormat(DataFormatJSInteger);
180 }
181
182 bool isJSDouble()
183 {
184 return isJSFormat(DataFormatJSDouble);
185 }
186
187 bool isJSCell()
188 {
189 return isJSFormat(DataFormatJSCell);
190 }
191
192 bool isJSBoolean()
193 {
194 return isJSFormat(DataFormatJSBoolean);
195 }
196
197 bool isUnknownJS()
198 {
199 return spillFormat() == DataFormatNone
200 ? registerFormat() == DataFormatJS || registerFormat() == DataFormatNone
201 : spillFormat() == DataFormatJS;
202 }
203
204 // Get the machine resister currently holding the value.
205 #if USE(JSVALUE64)
206 GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
207 FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
208 JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.gpr); }
209 #elif USE(JSVALUE32_64)
210 GPRReg gpr() { ASSERT(!(m_registerFormat & DataFormatJS) && m_registerFormat != DataFormatDouble); return u.gpr; }
211 GPRReg tagGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.tagGPR; }
212 GPRReg payloadGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.payloadGPR; }
213 FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble || m_registerFormat == DataFormatJSDouble); return u.fpr; }
214 JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.v.tagGPR, u.v.payloadGPR); }
215 #endif
216
217 // Check whether a value needs spilling in order to free up any associated machine registers.
218 bool needsSpill()
219 {
220 // This should only be called on values that are currently in a register.
221 ASSERT(m_registerFormat != DataFormatNone);
222 // Constants do not need spilling, nor do values that have already been
223 // spilled to the RegisterFile.
224 return !m_canFill;
225 }
226
227 // Called when a VirtualRegister is being spilled to the RegisterFile for the first time.
228 void spill(DataFormat spillFormat)
229 {
230 // We shouldn't be spill values that don't need spilling.
231 ASSERT(!m_canFill);
232 ASSERT(m_spillFormat == DataFormatNone);
233 // We should only be spilling values that are currently in machine registers.
234 ASSERT(m_registerFormat != DataFormatNone);
235
236 m_registerFormat = DataFormatNone;
237 m_spillFormat = spillFormat;
238 m_canFill = true;
239 }
240
241 // Called on values that don't need spilling (constants and values that have
242 // already been spilled), to mark them as no longer being in machine registers.
243 void setSpilled()
244 {
245 // Should only be called on values that don't need spilling, and are currently in registers.
246 ASSERT(m_canFill && m_registerFormat != DataFormatNone);
247 m_registerFormat = DataFormatNone;
248 }
249
250 void killSpilled()
251 {
252 m_spillFormat = DataFormatNone;
253 m_canFill = false;
254 }
255
256 // Record that this value is filled into machine registers,
257 // tracking which registers, and what format the value has.
258 #if USE(JSVALUE64)
259 void fillJSValue(GPRReg gpr, DataFormat format = DataFormatJS)
260 {
261 ASSERT(format & DataFormatJS);
262 m_registerFormat = format;
263 u.gpr = gpr;
264 }
265 #elif USE(JSVALUE32_64)
266 void fillJSValue(GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
267 {
268 ASSERT(format & DataFormatJS);
269 m_registerFormat = format;
270 u.v.tagGPR = tagGPR; // FIXME: for JSValues with known type (boolean, integer, cell etc.) no tagGPR is needed?
271 u.v.payloadGPR = payloadGPR;
272 }
273 void fillCell(GPRReg gpr)
274 {
275 m_registerFormat = DataFormatCell;
276 u.gpr = gpr;
277 }
278 #endif
279 void fillInteger(GPRReg gpr)
280 {
281 m_registerFormat = DataFormatInteger;
282 u.gpr = gpr;
283 }
284 void fillBoolean(GPRReg gpr)
285 {
286 m_registerFormat = DataFormatBoolean;
287 u.gpr = gpr;
288 }
289 void fillDouble(FPRReg fpr)
290 {
291 ASSERT(fpr != InvalidFPRReg);
292 m_registerFormat = DataFormatDouble;
293 u.fpr = fpr;
294 }
295 void fillStorage(GPRReg gpr)
296 {
297 m_registerFormat = DataFormatStorage;
298 u.gpr = gpr;
299 }
300
301 bool alive()
302 {
303 return m_useCount;
304 }
305
306 private:
307 // The index of the node whose result is stored in this virtual register.
308 NodeIndex m_nodeIndex;
309 uint32_t m_useCount;
310 DataFormat m_registerFormat;
311 DataFormat m_spillFormat;
312 bool m_canFill;
313 union {
314 GPRReg gpr;
315 FPRReg fpr;
316 #if USE(JSVALUE32_64)
317 struct {
318 GPRReg tagGPR;
319 GPRReg payloadGPR;
320 } v;
321 #endif
322 } u;
323 };
324
325 } } // namespace JSC::DFG
326
327 #endif
328 #endif