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 initInteger(Node
* node
, uint32_t useCount
, GPRReg gpr
)
75 m_useCount
= useCount
;
76 m_registerFormat
= DataFormatInteger
;
77 m_spillFormat
= DataFormatNone
;
85 void initJSValue(Node
* node
, uint32_t useCount
, GPRReg gpr
, DataFormat format
= DataFormatJS
)
87 ASSERT(format
& DataFormatJS
);
90 m_useCount
= useCount
;
91 m_registerFormat
= format
;
92 m_spillFormat
= DataFormatNone
;
99 #elif USE(JSVALUE32_64)
100 void initJSValue(Node
* node
, uint32_t useCount
, GPRReg tagGPR
, GPRReg payloadGPR
, DataFormat format
= DataFormatJS
)
102 ASSERT(format
& DataFormatJS
);
105 m_useCount
= useCount
;
106 m_registerFormat
= format
;
107 m_spillFormat
= DataFormatNone
;
110 u
.v
.payloadGPR
= payloadGPR
;
111 m_bornForOSR
= false;
112 m_isConstant
= false;
116 void initCell(Node
* node
, uint32_t useCount
, GPRReg gpr
)
119 m_useCount
= useCount
;
120 m_registerFormat
= DataFormatCell
;
121 m_spillFormat
= DataFormatNone
;
124 m_bornForOSR
= false;
125 m_isConstant
= false;
128 void initBoolean(Node
* node
, uint32_t useCount
, GPRReg gpr
)
131 m_useCount
= useCount
;
132 m_registerFormat
= DataFormatBoolean
;
133 m_spillFormat
= DataFormatNone
;
136 m_bornForOSR
= false;
137 m_isConstant
= false;
140 void initDouble(Node
* node
, uint32_t useCount
, FPRReg fpr
)
142 ASSERT(fpr
!= InvalidFPRReg
);
144 m_useCount
= useCount
;
145 m_registerFormat
= DataFormatDouble
;
146 m_spillFormat
= DataFormatNone
;
149 m_bornForOSR
= false;
150 m_isConstant
= false;
153 void initStorage(Node
* node
, uint32_t useCount
, GPRReg gpr
)
156 m_useCount
= useCount
;
157 m_registerFormat
= DataFormatStorage
;
158 m_spillFormat
= DataFormatNone
;
161 m_bornForOSR
= false;
162 m_isConstant
= false;
166 // Get the node that produced this value.
167 Node
* node() { return m_node
; }
169 void noticeOSRBirth(VariableEventStream
& stream
, Node
* node
, VirtualRegister virtualRegister
)
182 if (m_registerFormat
!= DataFormatNone
)
183 appendFill(BirthToFill
, stream
);
184 else if (m_spillFormat
!= DataFormatNone
)
185 appendSpill(BirthToSpill
, stream
, virtualRegister
);
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
)
194 bool result
= !--m_useCount
;
196 if (result
&& m_bornForOSR
) {
198 stream
.appendAndLog(VariableEvent::death(MinifiedID(m_node
)));
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.
210 return m_useCount
== 1;
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
; }
218 bool isJSFormat(DataFormat expectedFormat
)
220 return JSC::isJSFormat(registerFormat(), expectedFormat
) || JSC::isJSFormat(spillFormat(), expectedFormat
);
225 return isJSFormat(DataFormatJSInteger
);
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 // Record that this value is filled into machine registers,
309 // tracking which registers, and what format the value has.
311 void fillJSValue(VariableEventStream
& stream
, GPRReg gpr
, DataFormat format
= DataFormatJS
)
313 ASSERT(format
& DataFormatJS
);
314 m_registerFormat
= format
;
318 appendFill(Fill
, stream
);
320 #elif USE(JSVALUE32_64)
321 void fillJSValue(VariableEventStream
& stream
, GPRReg tagGPR
, GPRReg payloadGPR
, DataFormat format
= DataFormatJS
)
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
;
329 appendFill(Fill
, stream
);
331 void fillCell(VariableEventStream
& stream
, GPRReg gpr
)
333 m_registerFormat
= DataFormatCell
;
337 appendFill(Fill
, stream
);
340 void fillInteger(VariableEventStream
& stream
, GPRReg gpr
)
342 m_registerFormat
= DataFormatInteger
;
346 appendFill(Fill
, stream
);
348 void fillBoolean(VariableEventStream
& stream
, GPRReg gpr
)
350 m_registerFormat
= DataFormatBoolean
;
354 appendFill(Fill
, stream
);
356 void fillDouble(VariableEventStream
& stream
, FPRReg fpr
)
358 ASSERT(fpr
!= InvalidFPRReg
);
359 m_registerFormat
= DataFormatDouble
;
363 appendFill(Fill
, stream
);
365 void fillStorage(VariableEventStream
& stream
, GPRReg gpr
)
367 m_registerFormat
= DataFormatStorage
;
371 appendFill(Fill
, stream
);
380 void appendFill(VariableEventKind kind
, VariableEventStream
& stream
)
382 ASSERT(m_bornForOSR
);
384 if (m_registerFormat
== DataFormatDouble
) {
385 stream
.appendAndLog(VariableEvent::fillFPR(kind
, MinifiedID(m_node
), u
.fpr
));
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
));
394 stream
.appendAndLog(VariableEvent::fillGPR(kind
, MinifiedID(m_node
), u
.gpr
, m_registerFormat
));
397 void appendSpill(VariableEventKind kind
, VariableEventStream
& stream
, VirtualRegister virtualRegister
)
399 stream
.appendAndLog(VariableEvent::spill(kind
, MinifiedID(m_node
), virtualRegister
, m_spillFormat
));
402 // The node whose result is stored in this virtual register.
405 DataFormat m_registerFormat
;
406 DataFormat m_spillFormat
;
413 #if USE(JSVALUE32_64)
422 } } // namespace JSC::DFG