2 * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #ifndef DFGGenerationInfo_h
27 #define DFGGenerationInfo_h
31 #include "DFGJITCompiler.h"
32 #include "DFGMinifiedID.h"
33 #include "DFGVariableEvent.h"
34 #include "DFGVariableEventStream.h"
35 #include "DataFormat.h"
37 namespace JSC
{ namespace DFG
{
39 // === GenerationInfo ===
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
48 class GenerationInfo
{
53 , m_registerFormat(DataFormatNone
)
54 , m_spillFormat(DataFormatNone
)
61 void initConstant(Node
* node
, uint32_t useCount
)
64 m_useCount
= useCount
;
65 m_registerFormat
= DataFormatNone
;
66 m_spillFormat
= DataFormatNone
;
72 void initGPR(Node
* node
, uint32_t useCount
, GPRReg gpr
, DataFormat format
)
74 ASSERT(gpr
!= InvalidGPRReg
);
76 m_useCount
= useCount
;
77 m_registerFormat
= format
;
78 m_spillFormat
= DataFormatNone
;
85 void initInt32(Node
* node
, uint32_t useCount
, GPRReg gpr
)
87 initGPR(node
, useCount
, gpr
, DataFormatInt32
);
89 void initInt52(Node
* node
, uint32_t useCount
, GPRReg reg
, DataFormat format
)
91 ASSERT(format
== DataFormatInt52
|| format
== DataFormatStrictInt52
);
92 initGPR(node
, useCount
, reg
, format
);
94 void initInt52(Node
* node
, uint32_t useCount
, GPRReg reg
)
96 initGPR(node
, useCount
, reg
, DataFormatInt52
);
98 void initStrictInt52(Node
* node
, uint32_t useCount
, GPRReg reg
)
100 initGPR(node
, useCount
, reg
, DataFormatStrictInt52
);
103 void initJSValue(Node
* node
, uint32_t useCount
, GPRReg gpr
, DataFormat format
= DataFormatJS
)
105 ASSERT(format
& DataFormatJS
);
106 initGPR(node
, useCount
, gpr
, format
);
108 #elif USE(JSVALUE32_64)
109 void initJSValue(Node
* node
, uint32_t useCount
, GPRReg tagGPR
, GPRReg payloadGPR
, DataFormat format
= DataFormatJS
)
111 ASSERT(format
& DataFormatJS
);
114 m_useCount
= useCount
;
115 m_registerFormat
= format
;
116 m_spillFormat
= DataFormatNone
;
119 u
.v
.payloadGPR
= payloadGPR
;
120 m_bornForOSR
= false;
121 m_isConstant
= false;
125 void initCell(Node
* node
, uint32_t useCount
, GPRReg gpr
)
127 initGPR(node
, useCount
, gpr
, DataFormatCell
);
129 void initBoolean(Node
* node
, uint32_t useCount
, GPRReg gpr
)
131 initGPR(node
, useCount
, gpr
, DataFormatBoolean
);
133 void initDouble(Node
* node
, uint32_t useCount
, FPRReg fpr
)
135 ASSERT(fpr
!= InvalidFPRReg
);
137 m_useCount
= useCount
;
138 m_registerFormat
= DataFormatDouble
;
139 m_spillFormat
= DataFormatNone
;
142 m_bornForOSR
= false;
143 m_isConstant
= false;
146 void initStorage(Node
* node
, uint32_t useCount
, GPRReg gpr
)
148 initGPR(node
, useCount
, gpr
, DataFormatStorage
);
151 // Get the node that produced this value.
152 Node
* node() { return m_node
; }
154 void noticeOSRBirth(VariableEventStream
& stream
, Node
* node
, VirtualRegister virtualRegister
)
167 if (m_registerFormat
!= DataFormatNone
)
168 appendFill(BirthToFill
, stream
);
169 else if (m_spillFormat
!= DataFormatNone
)
170 appendSpill(BirthToSpill
, stream
, virtualRegister
);
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.
176 bool use(VariableEventStream
& stream
)
179 bool result
= !--m_useCount
;
181 if (result
&& m_bornForOSR
) {
183 stream
.appendAndLog(VariableEvent::death(MinifiedID(m_node
)));
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.
195 return m_useCount
== 1;
198 // Get the format of the value in machine registers (or 'none').
199 DataFormat
registerFormat() { return m_registerFormat
; }
200 // Get the format of the value as it is spilled in the JSStack (or 'none').
201 DataFormat
spillFormat() { return m_spillFormat
; }
203 bool isFormat(DataFormat expectedFormat
)
205 return registerFormat() == expectedFormat
|| spillFormat() == expectedFormat
;
208 bool isJSFormat(DataFormat expectedFormat
)
210 return JSC::isJSFormat(registerFormat(), expectedFormat
) || JSC::isJSFormat(spillFormat(), expectedFormat
);
215 return isJSFormat(DataFormatJSInt32
);
220 return isFormat(DataFormatInt52
);
225 return isFormat(DataFormatStrictInt52
);
230 return isJSFormat(DataFormatJSDouble
);
235 return isJSFormat(DataFormatJSCell
);
240 return isJSFormat(DataFormatJSBoolean
);
245 return spillFormat() == DataFormatNone
246 ? registerFormat() == DataFormatJS
|| registerFormat() == DataFormatNone
247 : spillFormat() == DataFormatJS
;
250 // Get the machine resister currently holding the value.
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
); }
263 // Check whether a value needs spilling in order to free up any associated machine registers.
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.
273 // Called when a VirtualRegister is being spilled to the JSStack for the first time.
274 void spill(VariableEventStream
& stream
, VirtualRegister virtualRegister
, DataFormat spillFormat
)
276 // We shouldn't be spill values that don't need spilling.
278 ASSERT(m_spillFormat
== DataFormatNone
);
279 // We should only be spilling values that are currently in machine registers.
280 ASSERT(m_registerFormat
!= DataFormatNone
);
282 m_registerFormat
= DataFormatNone
;
283 m_spillFormat
= spillFormat
;
287 appendSpill(Spill
, stream
, virtualRegister
);
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
)
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
;
299 appendSpill(Spill
, stream
, virtualRegister
);
304 m_spillFormat
= DataFormatNone
;
308 void fillGPR(VariableEventStream
& stream
, GPRReg gpr
, DataFormat format
)
310 ASSERT(gpr
!= InvalidGPRReg
);
311 m_registerFormat
= format
;
314 appendFill(Fill
, stream
);
317 // Record that this value is filled into machine registers,
318 // tracking which registers, and what format the value has.
320 void fillJSValue(VariableEventStream
& stream
, GPRReg gpr
, DataFormat format
= DataFormatJS
)
322 ASSERT(format
& DataFormatJS
);
323 fillGPR(stream
, gpr
, format
);
325 #elif USE(JSVALUE32_64)
326 void fillJSValue(VariableEventStream
& stream
, GPRReg tagGPR
, GPRReg payloadGPR
, DataFormat format
= DataFormatJS
)
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
;
334 appendFill(Fill
, stream
);
336 void fillCell(VariableEventStream
& stream
, GPRReg gpr
)
338 fillGPR(stream
, gpr
, DataFormatCell
);
341 void fillInt32(VariableEventStream
& stream
, GPRReg gpr
)
343 fillGPR(stream
, gpr
, DataFormatInt32
);
345 void fillInt52(VariableEventStream
& stream
, GPRReg gpr
, DataFormat format
)
347 ASSERT(format
== DataFormatInt52
|| format
== DataFormatStrictInt52
);
348 fillGPR(stream
, gpr
, format
);
350 void fillInt52(VariableEventStream
& stream
, GPRReg gpr
)
352 fillGPR(stream
, gpr
, DataFormatInt52
);
354 void fillStrictInt52(VariableEventStream
& stream
, GPRReg gpr
)
356 fillGPR(stream
, gpr
, DataFormatStrictInt52
);
358 void fillBoolean(VariableEventStream
& stream
, GPRReg gpr
)
360 fillGPR(stream
, gpr
, DataFormatBoolean
);
362 void fillDouble(VariableEventStream
& stream
, FPRReg fpr
)
364 ASSERT(fpr
!= InvalidFPRReg
);
365 m_registerFormat
= DataFormatDouble
;
369 appendFill(Fill
, stream
);
371 void fillStorage(VariableEventStream
& stream
, GPRReg gpr
)
373 fillGPR(stream
, gpr
, DataFormatStorage
);
382 void appendFill(VariableEventKind kind
, VariableEventStream
& stream
)
384 ASSERT(m_bornForOSR
);
386 if (m_registerFormat
== DataFormatDouble
) {
387 stream
.appendAndLog(VariableEvent::fillFPR(kind
, MinifiedID(m_node
), u
.fpr
));
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
));
396 stream
.appendAndLog(VariableEvent::fillGPR(kind
, MinifiedID(m_node
), u
.gpr
, m_registerFormat
));
399 void appendSpill(VariableEventKind kind
, VariableEventStream
& stream
, VirtualRegister virtualRegister
)
401 stream
.appendAndLog(VariableEvent::spill(kind
, MinifiedID(m_node
), virtualRegister
, m_spillFormat
));
404 // The node whose result is stored in this virtual register.
407 DataFormat m_registerFormat
;
408 DataFormat m_spillFormat
;
415 #if USE(JSVALUE32_64)
424 } } // namespace JSC::DFG