2 * Copyright (C) 2011 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.
27 #include "DFGJITCodeGenerator.h"
31 #include "DFGNonSpeculativeJIT.h"
32 #include "DFGSpeculativeJIT.h"
33 #include "LinkBuffer.h"
35 namespace JSC
{ namespace DFG
{
37 GPRReg
JITCodeGenerator::fillInteger(NodeIndex nodeIndex
, DataFormat
& returnFormat
)
39 Node
& node
= m_jit
.graph()[nodeIndex
];
40 VirtualRegister virtualRegister
= node
.virtualRegister();
41 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
43 if (info
.registerFormat() == DataFormatNone
) {
44 GPRReg gpr
= allocate();
46 if (node
.isConstant()) {
47 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderConstant
);
48 if (isInt32Constant(nodeIndex
)) {
49 m_jit
.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex
)), gpr
);
50 info
.fillInteger(gpr
);
51 returnFormat
= DataFormatInteger
;
54 if (isDoubleConstant(nodeIndex
)) {
55 JSValue jsValue
= jsNumber(valueOfDoubleConstant(nodeIndex
));
56 m_jit
.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue
)), gpr
);
58 ASSERT(isJSConstant(nodeIndex
));
59 JSValue jsValue
= valueOfJSConstant(nodeIndex
);
60 m_jit
.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue
)), gpr
);
63 ASSERT(info
.spillFormat() == DataFormatJS
|| info
.spillFormat() == DataFormatJSInteger
);
64 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderSpilled
);
65 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), gpr
);
68 // Since we statically know that we're filling an integer, and values
69 // in the RegisterFile are boxed, this must be DataFormatJSInteger.
70 // We will check this with a jitAssert below.
71 info
.fillJSValue(gpr
, DataFormatJSInteger
);
75 switch (info
.registerFormat()) {
77 // Should have filled, above.
78 case DataFormatJSDouble
:
79 case DataFormatDouble
:
82 case DataFormatJSCell
:
83 // Should only be calling this function if we know this operand to be integer.
86 case DataFormatJSInteger
: {
87 GPRReg gpr
= info
.gpr();
89 m_jit
.jitAssertIsJSInt32(gpr
);
90 returnFormat
= DataFormatJSInteger
;
94 case DataFormatInteger
: {
95 GPRReg gpr
= info
.gpr();
97 m_jit
.jitAssertIsInt32(gpr
);
98 returnFormat
= DataFormatInteger
;
103 ASSERT_NOT_REACHED();
104 return InvalidGPRReg
;
107 FPRReg
JITCodeGenerator::fillDouble(NodeIndex nodeIndex
)
109 Node
& node
= m_jit
.graph()[nodeIndex
];
110 VirtualRegister virtualRegister
= node
.virtualRegister();
111 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
113 if (info
.registerFormat() == DataFormatNone
) {
114 GPRReg gpr
= allocate();
116 if (node
.isConstant()) {
117 if (isInt32Constant(nodeIndex
)) {
118 // FIXME: should not be reachable?
119 m_jit
.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex
)), gpr
);
120 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderConstant
);
121 info
.fillInteger(gpr
);
123 } else if (isDoubleConstant(nodeIndex
)) {
124 FPRReg fpr
= fprAllocate();
125 m_jit
.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfDoubleConstant(nodeIndex
)))), gpr
);
126 m_jit
.movePtrToDouble(gpr
, fpr
);
129 m_fprs
.retain(fpr
, virtualRegister
, SpillOrderDouble
);
130 info
.fillDouble(fpr
);
133 // FIXME: should not be reachable?
134 ASSERT(isJSConstant(nodeIndex
));
135 JSValue jsValue
= valueOfJSConstant(nodeIndex
);
136 m_jit
.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue
)), gpr
);
137 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderConstant
);
138 info
.fillJSValue(gpr
, DataFormatJS
);
142 DataFormat spillFormat
= info
.spillFormat();
143 ASSERT(spillFormat
& DataFormatJS
);
144 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderSpilled
);
145 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), gpr
);
146 info
.fillJSValue(gpr
, m_isSpeculative
? spillFormat
: DataFormatJS
);
151 switch (info
.registerFormat()) {
153 // Should have filled, above.
155 case DataFormatJSCell
:
156 // Should only be calling this function if we know this operand to be numeric.
157 ASSERT_NOT_REACHED();
160 GPRReg jsValueGpr
= info
.gpr();
161 m_gprs
.lock(jsValueGpr
);
162 FPRReg fpr
= fprAllocate();
163 GPRReg tempGpr
= allocate(); // FIXME: can we skip this allocation on the last use of the virtual register?
165 JITCompiler::Jump isInteger
= m_jit
.branchPtr(MacroAssembler::AboveOrEqual
, jsValueGpr
, GPRInfo::tagTypeNumberRegister
);
167 m_jit
.jitAssertIsJSDouble(jsValueGpr
);
169 // First, if we get here we have a double encoded as a JSValue
170 m_jit
.move(jsValueGpr
, tempGpr
);
171 m_jit
.addPtr(GPRInfo::tagTypeNumberRegister
, tempGpr
);
172 m_jit
.movePtrToDouble(tempGpr
, fpr
);
173 JITCompiler::Jump hasUnboxedDouble
= m_jit
.jump();
175 // Finally, handle integers.
176 isInteger
.link(&m_jit
);
177 m_jit
.convertInt32ToDouble(jsValueGpr
, fpr
);
178 hasUnboxedDouble
.link(&m_jit
);
180 m_gprs
.release(jsValueGpr
);
181 m_gprs
.unlock(jsValueGpr
);
182 m_gprs
.unlock(tempGpr
);
183 m_fprs
.retain(fpr
, virtualRegister
, SpillOrderDouble
);
184 info
.fillDouble(fpr
);
188 case DataFormatJSInteger
:
189 case DataFormatInteger
: {
190 FPRReg fpr
= fprAllocate();
191 GPRReg gpr
= info
.gpr();
194 m_jit
.convertInt32ToDouble(gpr
, fpr
);
198 m_fprs
.retain(fpr
, virtualRegister
, SpillOrderDouble
);
199 info
.fillDouble(fpr
);
204 case DataFormatJSDouble
: {
205 GPRReg gpr
= info
.gpr();
206 FPRReg fpr
= unboxDouble(gpr
);
209 m_fprs
.retain(fpr
, virtualRegister
, SpillOrderDouble
);
211 info
.fillDouble(fpr
);
215 case DataFormatDouble
: {
216 FPRReg fpr
= info
.fpr();
222 ASSERT_NOT_REACHED();
223 return InvalidFPRReg
;
226 GPRReg
JITCodeGenerator::fillJSValue(NodeIndex nodeIndex
)
228 Node
& node
= m_jit
.graph()[nodeIndex
];
229 VirtualRegister virtualRegister
= node
.virtualRegister();
230 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
232 switch (info
.registerFormat()) {
233 case DataFormatNone
: {
234 GPRReg gpr
= allocate();
236 if (node
.isConstant()) {
237 if (isInt32Constant(nodeIndex
)) {
238 info
.fillJSValue(gpr
, DataFormatJSInteger
);
239 JSValue jsValue
= jsNumber(valueOfInt32Constant(nodeIndex
));
240 m_jit
.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue
)), gpr
);
241 } else if (isDoubleConstant(nodeIndex
)) {
242 info
.fillJSValue(gpr
, DataFormatJSDouble
);
243 JSValue
jsValue(JSValue::EncodeAsDouble
, valueOfDoubleConstant(nodeIndex
));
244 m_jit
.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue
)), gpr
);
246 ASSERT(isJSConstant(nodeIndex
));
247 JSValue jsValue
= valueOfJSConstant(nodeIndex
);
248 m_jit
.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue
)), gpr
);
249 info
.fillJSValue(gpr
, DataFormatJS
);
252 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderConstant
);
254 DataFormat spillFormat
= info
.spillFormat();
255 ASSERT(spillFormat
& DataFormatJS
);
256 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderSpilled
);
257 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), gpr
);
258 info
.fillJSValue(gpr
, m_isSpeculative
? spillFormat
: DataFormatJS
);
263 case DataFormatInteger
: {
264 GPRReg gpr
= info
.gpr();
265 // If the register has already been locked we need to take a copy.
266 // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInteger, not DataFormatJSInteger.
267 if (m_gprs
.isLocked(gpr
)) {
268 GPRReg result
= allocate();
269 m_jit
.orPtr(GPRInfo::tagTypeNumberRegister
, gpr
, result
);
273 m_jit
.orPtr(GPRInfo::tagTypeNumberRegister
, gpr
);
274 info
.fillJSValue(gpr
, DataFormatJSInteger
);
278 case DataFormatDouble
: {
279 FPRReg fpr
= info
.fpr();
280 GPRReg gpr
= boxDouble(fpr
);
283 info
.fillJSValue(gpr
, DataFormatJSDouble
);
285 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderJS
);
291 // No retag required on JSVALUE64!
293 case DataFormatJSInteger
:
294 case DataFormatJSDouble
:
295 case DataFormatJSCell
: {
296 GPRReg gpr
= info
.gpr();
302 ASSERT_NOT_REACHED();
303 return InvalidGPRReg
;
306 void JITCodeGenerator::useChildren(Node
& node
)
308 NodeIndex child1
= node
.child1
;
309 if (child1
== NoNode
) {
310 ASSERT(node
.child2
== NoNode
&& node
.child3
== NoNode
);
315 NodeIndex child2
= node
.child2
;
316 if (child2
== NoNode
) {
317 ASSERT(node
.child3
== NoNode
);
322 NodeIndex child3
= node
.child3
;
323 if (child3
== NoNode
)
329 static const char* dataFormatString(DataFormat format
)
331 // These values correspond to the DataFormat enum.
332 const char* strings
[] = {
350 return strings
[format
];
353 void JITCodeGenerator::dump(const char* label
)
356 fprintf(stderr
, "<%s>\n", label
);
358 fprintf(stderr
, " gprs:\n");
360 fprintf(stderr
, " fprs:\n");
362 fprintf(stderr
, " VirtualRegisters:\n");
363 for (unsigned i
= 0; i
< m_generationInfo
.size(); ++i
) {
364 GenerationInfo
& info
= m_generationInfo
[i
];
366 fprintf(stderr
, " % 3d:%s%s", i
, dataFormatString(info
.registerFormat()), dataFormatString(info
.spillFormat()));
368 fprintf(stderr
, " % 3d:[__][__]", i
);
369 if (info
.registerFormat() == DataFormatDouble
)
370 fprintf(stderr
, ":fpr%d\n", info
.fpr());
371 else if (info
.registerFormat() != DataFormatNone
) {
372 ASSERT(info
.gpr() != InvalidGPRReg
);
373 fprintf(stderr
, ":%s\n", GPRInfo::debugName(info
.gpr()));
375 fprintf(stderr
, "\n");
378 fprintf(stderr
, "</%s>\n", label
);
383 #if DFG_CONSISTENCY_CHECK
384 void JITCodeGenerator::checkConsistency()
388 for (gpr_iterator iter
= m_gprs
.begin(); iter
!= m_gprs
.end(); ++iter
) {
389 if (iter
.isLocked()) {
390 fprintf(stderr
, "DFG_CONSISTENCY_CHECK failed: gpr %s is locked.\n", iter
.debugName());
394 for (fpr_iterator iter
= m_fprs
.begin(); iter
!= m_fprs
.end(); ++iter
) {
395 if (iter
.isLocked()) {
396 fprintf(stderr
, "DFG_CONSISTENCY_CHECK failed: fpr %s is locked.\n", iter
.debugName());
401 for (unsigned i
= 0; i
< m_generationInfo
.size(); ++i
) {
402 VirtualRegister virtualRegister
= (VirtualRegister
)i
;
403 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
406 switch (info
.registerFormat()) {
409 case DataFormatInteger
:
412 case DataFormatJSInteger
:
413 case DataFormatJSDouble
:
414 case DataFormatJSCell
: {
415 GPRReg gpr
= info
.gpr();
416 ASSERT(gpr
!= InvalidGPRReg
);
417 if (m_gprs
.name(gpr
) != virtualRegister
) {
418 fprintf(stderr
, "DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (gpr %s).\n", virtualRegister
, GPRInfo::debugName(gpr
));
423 case DataFormatDouble
: {
424 FPRReg fpr
= info
.fpr();
425 ASSERT(fpr
!= InvalidFPRReg
);
426 if (m_fprs
.name(fpr
) != virtualRegister
) {
427 fprintf(stderr
, "DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (fpr %s).\n", virtualRegister
, FPRInfo::debugName(fpr
));
435 for (gpr_iterator iter
= m_gprs
.begin(); iter
!= m_gprs
.end(); ++iter
) {
436 VirtualRegister virtualRegister
= iter
.name();
437 if (virtualRegister
== InvalidVirtualRegister
)
440 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
441 if (iter
.regID() != info
.gpr()) {
442 fprintf(stderr
, "DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter
.debugName(), virtualRegister
);
447 for (fpr_iterator iter
= m_fprs
.begin(); iter
!= m_fprs
.end(); ++iter
) {
448 VirtualRegister virtualRegister
= iter
.name();
449 if (virtualRegister
== InvalidVirtualRegister
)
452 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
453 if (iter
.regID() != info
.fpr()) {
454 fprintf(stderr
, "DFG_CONSISTENCY_CHECK failed: name mismatch for fpr %s (virtual register %d).\n", iter
.debugName(), virtualRegister
);
466 GPRTemporary::GPRTemporary(JITCodeGenerator
* jit
)
468 , m_gpr(InvalidGPRReg
)
470 m_gpr
= m_jit
->allocate();
473 GPRTemporary::GPRTemporary(JITCodeGenerator
* jit
, SpeculateIntegerOperand
& op1
)
475 , m_gpr(InvalidGPRReg
)
477 if (m_jit
->canReuse(op1
.index()))
478 m_gpr
= m_jit
->reuse(op1
.gpr());
480 m_gpr
= m_jit
->allocate();
483 GPRTemporary::GPRTemporary(JITCodeGenerator
* jit
, SpeculateIntegerOperand
& op1
, SpeculateIntegerOperand
& op2
)
485 , m_gpr(InvalidGPRReg
)
487 if (m_jit
->canReuse(op1
.index()))
488 m_gpr
= m_jit
->reuse(op1
.gpr());
489 else if (m_jit
->canReuse(op2
.index()))
490 m_gpr
= m_jit
->reuse(op2
.gpr());
492 m_gpr
= m_jit
->allocate();
495 GPRTemporary::GPRTemporary(JITCodeGenerator
* jit
, IntegerOperand
& op1
)
497 , m_gpr(InvalidGPRReg
)
499 if (m_jit
->canReuse(op1
.index()))
500 m_gpr
= m_jit
->reuse(op1
.gpr());
502 m_gpr
= m_jit
->allocate();
505 GPRTemporary::GPRTemporary(JITCodeGenerator
* jit
, IntegerOperand
& op1
, IntegerOperand
& op2
)
507 , m_gpr(InvalidGPRReg
)
509 if (m_jit
->canReuse(op1
.index()))
510 m_gpr
= m_jit
->reuse(op1
.gpr());
511 else if (m_jit
->canReuse(op2
.index()))
512 m_gpr
= m_jit
->reuse(op2
.gpr());
514 m_gpr
= m_jit
->allocate();
517 GPRTemporary::GPRTemporary(JITCodeGenerator
* jit
, SpeculateCellOperand
& op1
)
519 , m_gpr(InvalidGPRReg
)
521 if (m_jit
->canReuse(op1
.index()))
522 m_gpr
= m_jit
->reuse(op1
.gpr());
524 m_gpr
= m_jit
->allocate();
527 GPRTemporary::GPRTemporary(JITCodeGenerator
* jit
, JSValueOperand
& op1
)
529 , m_gpr(InvalidGPRReg
)
531 if (m_jit
->canReuse(op1
.index()))
532 m_gpr
= m_jit
->reuse(op1
.gpr());
534 m_gpr
= m_jit
->allocate();
537 FPRTemporary::FPRTemporary(JITCodeGenerator
* jit
)
539 , m_fpr(InvalidFPRReg
)
541 m_fpr
= m_jit
->fprAllocate();
544 FPRTemporary::FPRTemporary(JITCodeGenerator
* jit
, DoubleOperand
& op1
)
546 , m_fpr(InvalidFPRReg
)
548 if (m_jit
->canReuse(op1
.index()))
549 m_fpr
= m_jit
->reuse(op1
.fpr());
551 m_fpr
= m_jit
->fprAllocate();
554 FPRTemporary::FPRTemporary(JITCodeGenerator
* jit
, DoubleOperand
& op1
, DoubleOperand
& op2
)
556 , m_fpr(InvalidFPRReg
)
558 if (m_jit
->canReuse(op1
.index()))
559 m_fpr
= m_jit
->reuse(op1
.fpr());
560 else if (m_jit
->canReuse(op2
.index()))
561 m_fpr
= m_jit
->reuse(op2
.fpr());
563 m_fpr
= m_jit
->fprAllocate();
566 } } // namespace JSC::DFG