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