]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGGenerationInfo.h
JavaScriptCore-7600.1.4.15.12.tar.gz
[apple/javascriptcore.git] / dfg / DFGGenerationInfo.h
CommitLineData
14957cd0 1/*
93a37866 2 * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
14957cd0
A
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
93a37866
A
31#include "DFGJITCompiler.h"
32#include "DFGMinifiedID.h"
33#include "DFGVariableEvent.h"
34#include "DFGVariableEventStream.h"
6fe7ccc8 35#include "DataFormat.h"
14957cd0
A
36
37namespace JSC { namespace DFG {
38
14957cd0
A
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.
48class GenerationInfo {
49public:
50 GenerationInfo()
93a37866 51 : m_node(0)
14957cd0
A
52 , m_useCount(0)
53 , m_registerFormat(DataFormatNone)
54 , m_spillFormat(DataFormatNone)
55 , m_canFill(false)
93a37866
A
56 , m_bornForOSR(false)
57 , m_isConstant(false)
14957cd0
A
58 {
59 }
60
93a37866 61 void initConstant(Node* node, uint32_t useCount)
14957cd0 62 {
93a37866 63 m_node = node;
14957cd0
A
64 m_useCount = useCount;
65 m_registerFormat = DataFormatNone;
66 m_spillFormat = DataFormatNone;
67 m_canFill = true;
93a37866
A
68 m_bornForOSR = false;
69 m_isConstant = true;
6fe7ccc8 70 ASSERT(m_useCount);
14957cd0 71 }
81345200 72 void initGPR(Node* node, uint32_t useCount, GPRReg gpr, DataFormat format)
14957cd0 73 {
81345200 74 ASSERT(gpr != InvalidGPRReg);
93a37866 75 m_node = node;
14957cd0 76 m_useCount = useCount;
81345200 77 m_registerFormat = format;
14957cd0
A
78 m_spillFormat = DataFormatNone;
79 m_canFill = false;
80 u.gpr = gpr;
93a37866
A
81 m_bornForOSR = false;
82 m_isConstant = false;
6fe7ccc8 83 ASSERT(m_useCount);
14957cd0 84 }
81345200
A
85 void initInt32(Node* node, uint32_t useCount, GPRReg gpr)
86 {
87 initGPR(node, useCount, gpr, DataFormatInt32);
88 }
89 void initInt52(Node* node, uint32_t useCount, GPRReg reg, DataFormat format)
90 {
91 ASSERT(format == DataFormatInt52 || format == DataFormatStrictInt52);
92 initGPR(node, useCount, reg, format);
93 }
94 void initInt52(Node* node, uint32_t useCount, GPRReg reg)
95 {
96 initGPR(node, useCount, reg, DataFormatInt52);
97 }
98 void initStrictInt52(Node* node, uint32_t useCount, GPRReg reg)
99 {
100 initGPR(node, useCount, reg, DataFormatStrictInt52);
101 }
6fe7ccc8 102#if USE(JSVALUE64)
93a37866 103 void initJSValue(Node* node, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
14957cd0
A
104 {
105 ASSERT(format & DataFormatJS);
81345200 106 initGPR(node, useCount, gpr, format);
6fe7ccc8
A
107 }
108#elif USE(JSVALUE32_64)
93a37866 109 void initJSValue(Node* node, uint32_t useCount, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
6fe7ccc8
A
110 {
111 ASSERT(format & DataFormatJS);
112
93a37866 113 m_node = node;
6fe7ccc8
A
114 m_useCount = useCount;
115 m_registerFormat = format;
116 m_spillFormat = DataFormatNone;
117 m_canFill = false;
118 u.v.tagGPR = tagGPR;
119 u.v.payloadGPR = payloadGPR;
93a37866
A
120 m_bornForOSR = false;
121 m_isConstant = false;
6fe7ccc8 122 ASSERT(m_useCount);
14957cd0 123 }
6fe7ccc8 124#endif
93a37866 125 void initCell(Node* node, uint32_t useCount, GPRReg gpr)
14957cd0 126 {
81345200 127 initGPR(node, useCount, gpr, DataFormatCell);
6fe7ccc8 128 }
93a37866 129 void initBoolean(Node* node, uint32_t useCount, GPRReg gpr)
6fe7ccc8 130 {
81345200 131 initGPR(node, useCount, gpr, DataFormatBoolean);
14957cd0 132 }
93a37866 133 void initDouble(Node* node, uint32_t useCount, FPRReg fpr)
14957cd0 134 {
6fe7ccc8 135 ASSERT(fpr != InvalidFPRReg);
93a37866 136 m_node = node;
14957cd0
A
137 m_useCount = useCount;
138 m_registerFormat = DataFormatDouble;
139 m_spillFormat = DataFormatNone;
140 m_canFill = false;
141 u.fpr = fpr;
93a37866
A
142 m_bornForOSR = false;
143 m_isConstant = false;
6fe7ccc8
A
144 ASSERT(m_useCount);
145 }
93a37866 146 void initStorage(Node* node, uint32_t useCount, GPRReg gpr)
6fe7ccc8 147 {
81345200 148 initGPR(node, useCount, gpr, DataFormatStorage);
14957cd0
A
149 }
150
93a37866
A
151 // Get the node that produced this value.
152 Node* node() { return m_node; }
153
154 void noticeOSRBirth(VariableEventStream& stream, Node* node, VirtualRegister virtualRegister)
155 {
156 if (m_isConstant)
157 return;
158 if (m_node != node)
159 return;
160 if (!alive())
161 return;
162 if (m_bornForOSR)
163 return;
164
165 m_bornForOSR = true;
166
167 if (m_registerFormat != DataFormatNone)
168 appendFill(BirthToFill, stream);
169 else if (m_spillFormat != DataFormatNone)
170 appendSpill(BirthToSpill, stream, virtualRegister);
171 }
14957cd0
A
172
173 // Mark the value as having been used (decrement the useCount).
174 // Returns true if this was the last use of the value, and any
175 // associated machine registers may be freed.
93a37866 176 bool use(VariableEventStream& stream)
14957cd0 177 {
6fe7ccc8 178 ASSERT(m_useCount);
93a37866
A
179 bool result = !--m_useCount;
180
181 if (result && m_bornForOSR) {
182 ASSERT(m_node);
183 stream.appendAndLog(VariableEvent::death(MinifiedID(m_node)));
184 }
185
186 return result;
14957cd0
A
187 }
188
189 // Used to check the operands of operations to see if they are on
190 // their last use; in some cases it may be safe to reuse the same
191 // machine register for the result of the operation.
192 bool canReuse()
193 {
194 ASSERT(m_useCount);
195 return m_useCount == 1;
196 }
197
198 // Get the format of the value in machine registers (or 'none').
199 DataFormat registerFormat() { return m_registerFormat; }
93a37866 200 // Get the format of the value as it is spilled in the JSStack (or 'none').
14957cd0 201 DataFormat spillFormat() { return m_spillFormat; }
6fe7ccc8 202
81345200
A
203 bool isFormat(DataFormat expectedFormat)
204 {
205 return registerFormat() == expectedFormat || spillFormat() == expectedFormat;
206 }
207
6fe7ccc8
A
208 bool isJSFormat(DataFormat expectedFormat)
209 {
210 return JSC::isJSFormat(registerFormat(), expectedFormat) || JSC::isJSFormat(spillFormat(), expectedFormat);
211 }
212
81345200
A
213 bool isJSInt32()
214 {
215 return isJSFormat(DataFormatJSInt32);
216 }
217
218 bool isInt52()
6fe7ccc8 219 {
81345200
A
220 return isFormat(DataFormatInt52);
221 }
222
223 bool isStrictInt52()
224 {
225 return isFormat(DataFormatStrictInt52);
6fe7ccc8
A
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 }
14957cd0
A
249
250 // Get the machine resister currently holding the value.
6fe7ccc8 251#if USE(JSVALUE64)
14957cd0
A
252 GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
253 FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
6fe7ccc8
A
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
14957cd0
A
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
93a37866 269 // spilled to the JSStack.
14957cd0
A
270 return !m_canFill;
271 }
272
93a37866
A
273 // Called when a VirtualRegister is being spilled to the JSStack for the first time.
274 void spill(VariableEventStream& stream, VirtualRegister virtualRegister, DataFormat spillFormat)
14957cd0
A
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);
14957cd0
A
281
282 m_registerFormat = DataFormatNone;
283 m_spillFormat = spillFormat;
284 m_canFill = true;
93a37866
A
285
286 if (m_bornForOSR)
287 appendSpill(Spill, stream, virtualRegister);
14957cd0
A
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.
93a37866 292 void setSpilled(VariableEventStream& stream, VirtualRegister virtualRegister)
14957cd0
A
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;
93a37866
A
297
298 if (m_bornForOSR)
299 appendSpill(Spill, stream, virtualRegister);
14957cd0 300 }
6fe7ccc8
A
301
302 void killSpilled()
303 {
304 m_spillFormat = DataFormatNone;
305 m_canFill = false;
306 }
81345200
A
307
308 void fillGPR(VariableEventStream& stream, GPRReg gpr, DataFormat format)
309 {
310 ASSERT(gpr != InvalidGPRReg);
311 m_registerFormat = format;
312 u.gpr = gpr;
313 if (m_bornForOSR)
314 appendFill(Fill, stream);
315 }
14957cd0
A
316
317 // Record that this value is filled into machine registers,
318 // tracking which registers, and what format the value has.
6fe7ccc8 319#if USE(JSVALUE64)
93a37866 320 void fillJSValue(VariableEventStream& stream, GPRReg gpr, DataFormat format = DataFormatJS)
14957cd0
A
321 {
322 ASSERT(format & DataFormatJS);
81345200 323 fillGPR(stream, gpr, format);
14957cd0 324 }
6fe7ccc8 325#elif USE(JSVALUE32_64)
93a37866 326 void fillJSValue(VariableEventStream& stream, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
6fe7ccc8
A
327 {
328 ASSERT(format & DataFormatJS);
329 m_registerFormat = format;
330 u.v.tagGPR = tagGPR; // FIXME: for JSValues with known type (boolean, integer, cell etc.) no tagGPR is needed?
331 u.v.payloadGPR = payloadGPR;
93a37866
A
332
333 if (m_bornForOSR)
334 appendFill(Fill, stream);
6fe7ccc8 335 }
93a37866 336 void fillCell(VariableEventStream& stream, GPRReg gpr)
6fe7ccc8 337 {
81345200 338 fillGPR(stream, gpr, DataFormatCell);
6fe7ccc8
A
339 }
340#endif
81345200 341 void fillInt32(VariableEventStream& stream, GPRReg gpr)
14957cd0 342 {
81345200
A
343 fillGPR(stream, gpr, DataFormatInt32);
344 }
345 void fillInt52(VariableEventStream& stream, GPRReg gpr, DataFormat format)
346 {
347 ASSERT(format == DataFormatInt52 || format == DataFormatStrictInt52);
348 fillGPR(stream, gpr, format);
349 }
350 void fillInt52(VariableEventStream& stream, GPRReg gpr)
351 {
352 fillGPR(stream, gpr, DataFormatInt52);
353 }
354 void fillStrictInt52(VariableEventStream& stream, GPRReg gpr)
355 {
356 fillGPR(stream, gpr, DataFormatStrictInt52);
14957cd0 357 }
93a37866 358 void fillBoolean(VariableEventStream& stream, GPRReg gpr)
6fe7ccc8 359 {
81345200 360 fillGPR(stream, gpr, DataFormatBoolean);
6fe7ccc8 361 }
93a37866 362 void fillDouble(VariableEventStream& stream, FPRReg fpr)
14957cd0 363 {
6fe7ccc8 364 ASSERT(fpr != InvalidFPRReg);
14957cd0
A
365 m_registerFormat = DataFormatDouble;
366 u.fpr = fpr;
93a37866
A
367
368 if (m_bornForOSR)
369 appendFill(Fill, stream);
14957cd0 370 }
93a37866 371 void fillStorage(VariableEventStream& stream, GPRReg gpr)
6fe7ccc8 372 {
81345200 373 fillGPR(stream, gpr, DataFormatStorage);
6fe7ccc8 374 }
14957cd0 375
14957cd0
A
376 bool alive()
377 {
378 return m_useCount;
379 }
14957cd0
A
380
381private:
93a37866
A
382 void appendFill(VariableEventKind kind, VariableEventStream& stream)
383 {
384 ASSERT(m_bornForOSR);
385
386 if (m_registerFormat == DataFormatDouble) {
387 stream.appendAndLog(VariableEvent::fillFPR(kind, MinifiedID(m_node), u.fpr));
388 return;
389 }
390#if USE(JSVALUE32_64)
391 if (m_registerFormat & DataFormatJS) {
392 stream.appendAndLog(VariableEvent::fillPair(kind, MinifiedID(m_node), u.v.tagGPR, u.v.payloadGPR));
393 return;
394 }
395#endif
396 stream.appendAndLog(VariableEvent::fillGPR(kind, MinifiedID(m_node), u.gpr, m_registerFormat));
397 }
398
399 void appendSpill(VariableEventKind kind, VariableEventStream& stream, VirtualRegister virtualRegister)
400 {
401 stream.appendAndLog(VariableEvent::spill(kind, MinifiedID(m_node), virtualRegister, m_spillFormat));
402 }
403
404 // The node whose result is stored in this virtual register.
405 Node* m_node;
14957cd0
A
406 uint32_t m_useCount;
407 DataFormat m_registerFormat;
408 DataFormat m_spillFormat;
409 bool m_canFill;
93a37866
A
410 bool m_bornForOSR;
411 bool m_isConstant;
14957cd0
A
412 union {
413 GPRReg gpr;
414 FPRReg fpr;
6fe7ccc8
A
415#if USE(JSVALUE32_64)
416 struct {
417 GPRReg tagGPR;
418 GPRReg payloadGPR;
419 } v;
420#endif
14957cd0
A
421 } u;
422};
423
424} } // namespace JSC::DFG
425
426#endif
427#endif