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 "DFGSpeculativeJIT.h"
31 #include "LinkBuffer.h"
33 namespace JSC
{ namespace DFG
{
35 // On Windows we need to wrap fmod; on other platforms we can call it directly.
36 // On ARMv7 we assert that all function pointers have to low bit set (point to thumb code).
37 #if CALLING_CONVENTION_IS_STDCALL || CPU(ARM_THUMB2)
38 static double DFG_OPERATION
fmodAsDFGOperation(double x
, double y
)
43 #define fmodAsDFGOperation fmod
46 void SpeculativeJIT::clearGenerationInfo()
48 for (unsigned i
= 0; i
< m_generationInfo
.size(); ++i
)
49 m_generationInfo
[i
] = GenerationInfo();
50 m_gprs
= RegisterBank
<GPRInfo
>();
51 m_fprs
= RegisterBank
<FPRInfo
>();
54 GPRReg
SpeculativeJIT::fillStorage(NodeIndex nodeIndex
)
56 Node
& node
= m_jit
.graph()[nodeIndex
];
57 VirtualRegister virtualRegister
= node
.virtualRegister();
58 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
60 switch (info
.registerFormat()) {
61 case DataFormatNone
: {
62 if (info
.spillFormat() == DataFormatStorage
) {
63 GPRReg gpr
= allocate();
64 m_gprs
.retain(gpr
, virtualRegister
, SpillOrderSpilled
);
65 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), gpr
);
66 info
.fillStorage(gpr
);
70 // Must be a cell; fill it as a cell and then return the pointer.
71 return fillSpeculateCell(nodeIndex
);
74 case DataFormatStorage
: {
75 GPRReg gpr
= info
.gpr();
81 return fillSpeculateCell(nodeIndex
);
85 void SpeculativeJIT::useChildren(Node
& node
)
87 if (node
.flags() & NodeHasVarArgs
) {
88 for (unsigned childIdx
= node
.firstChild(); childIdx
< node
.firstChild() + node
.numChildren(); childIdx
++)
89 use(m_jit
.graph().m_varArgChildren
[childIdx
]);
91 Edge child1
= node
.child1();
93 ASSERT(!node
.child2() && !node
.child3());
98 Edge child2
= node
.child2();
100 ASSERT(!node
.child3());
105 Edge child3
= node
.child3();
112 bool SpeculativeJIT::isStrictInt32(NodeIndex nodeIndex
)
114 if (isInt32Constant(nodeIndex
))
117 Node
& node
= m_jit
.graph()[nodeIndex
];
118 GenerationInfo
& info
= m_generationInfo
[node
.virtualRegister()];
120 return info
.registerFormat() == DataFormatInteger
;
123 bool SpeculativeJIT::isKnownInteger(NodeIndex nodeIndex
)
125 if (isInt32Constant(nodeIndex
))
128 Node
& node
= m_jit
.graph()[nodeIndex
];
130 if (node
.hasInt32Result())
133 GenerationInfo
& info
= m_generationInfo
[node
.virtualRegister()];
135 return info
.isJSInteger();
138 bool SpeculativeJIT::isKnownNumeric(NodeIndex nodeIndex
)
140 if (isInt32Constant(nodeIndex
) || isNumberConstant(nodeIndex
))
143 Node
& node
= m_jit
.graph()[nodeIndex
];
145 if (node
.hasNumberResult())
148 GenerationInfo
& info
= m_generationInfo
[node
.virtualRegister()];
150 return info
.isJSInteger() || info
.isJSDouble();
153 bool SpeculativeJIT::isKnownCell(NodeIndex nodeIndex
)
155 return m_generationInfo
[m_jit
.graph()[nodeIndex
].virtualRegister()].isJSCell();
158 bool SpeculativeJIT::isKnownNotCell(NodeIndex nodeIndex
)
160 Node
& node
= m_jit
.graph()[nodeIndex
];
161 VirtualRegister virtualRegister
= node
.virtualRegister();
162 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
163 if (node
.hasConstant() && !valueOfJSConstant(nodeIndex
).isCell())
165 return !(info
.isJSCell() || info
.isUnknownJS());
168 bool SpeculativeJIT::isKnownNotInteger(NodeIndex nodeIndex
)
170 Node
& node
= m_jit
.graph()[nodeIndex
];
171 VirtualRegister virtualRegister
= node
.virtualRegister();
172 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
174 return info
.isJSDouble() || info
.isJSCell() || info
.isJSBoolean()
175 || (node
.hasConstant() && !valueOfJSConstant(nodeIndex
).isInt32());
178 bool SpeculativeJIT::isKnownNotNumber(NodeIndex nodeIndex
)
180 Node
& node
= m_jit
.graph()[nodeIndex
];
181 VirtualRegister virtualRegister
= node
.virtualRegister();
182 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
184 return (!info
.isJSDouble() && !info
.isJSInteger() && !info
.isUnknownJS())
185 || (node
.hasConstant() && !isNumberConstant(nodeIndex
));
188 void SpeculativeJIT::writeBarrier(MacroAssembler
& jit
, GPRReg owner
, GPRReg scratch1
, GPRReg scratch2
, WriteBarrierUseKind useKind
)
192 UNUSED_PARAM(scratch1
);
193 UNUSED_PARAM(scratch2
);
194 UNUSED_PARAM(useKind
);
195 ASSERT(owner
!= scratch1
);
196 ASSERT(owner
!= scratch2
);
197 ASSERT(scratch1
!= scratch2
);
199 #if ENABLE(WRITE_BARRIER_PROFILING)
200 JITCompiler::emitCount(jit
, WriteBarrierCounters::jitCounterFor(useKind
));
202 markCellCard(jit
, owner
, scratch1
, scratch2
);
205 void SpeculativeJIT::markCellCard(MacroAssembler
& jit
, GPRReg owner
, GPRReg scratch1
, GPRReg scratch2
)
209 UNUSED_PARAM(scratch1
);
210 UNUSED_PARAM(scratch2
);
213 jit
.move(owner
, scratch1
);
214 jit
.andPtr(TrustedImm32(static_cast<int32_t>(MarkedBlock::blockMask
)), scratch1
);
215 jit
.move(owner
, scratch2
);
216 // consume additional 8 bits as we're using an approximate filter
217 jit
.rshift32(TrustedImm32(MarkedBlock::atomShift
+ 8), scratch2
);
218 jit
.andPtr(TrustedImm32(MarkedBlock::atomMask
>> 8), scratch2
);
219 MacroAssembler::Jump filter
= jit
.branchTest8(MacroAssembler::Zero
, MacroAssembler::BaseIndex(scratch1
, scratch2
, MacroAssembler::TimesOne
, MarkedBlock::offsetOfMarks()));
220 jit
.move(owner
, scratch2
);
221 jit
.rshift32(TrustedImm32(MarkedBlock::cardShift
), scratch2
);
222 jit
.andPtr(TrustedImm32(MarkedBlock::cardMask
), scratch2
);
223 jit
.store8(TrustedImm32(1), MacroAssembler::BaseIndex(scratch1
, scratch2
, MacroAssembler::TimesOne
, MarkedBlock::offsetOfCards()));
228 void SpeculativeJIT::writeBarrier(GPRReg ownerGPR
, GPRReg valueGPR
, Edge valueUse
, WriteBarrierUseKind useKind
, GPRReg scratch1
, GPRReg scratch2
)
230 UNUSED_PARAM(ownerGPR
);
231 UNUSED_PARAM(valueGPR
);
232 UNUSED_PARAM(scratch1
);
233 UNUSED_PARAM(scratch2
);
234 UNUSED_PARAM(useKind
);
236 if (isKnownNotCell(valueUse
.index()))
239 #if ENABLE(WRITE_BARRIER_PROFILING)
240 JITCompiler::emitCount(m_jit
, WriteBarrierCounters::jitCounterFor(useKind
));
246 if (scratch1
== InvalidGPRReg
) {
247 GPRTemporary
scratchGPR(this);
248 temp1
.adopt(scratchGPR
);
249 scratch1
= temp1
.gpr();
251 if (scratch2
== InvalidGPRReg
) {
252 GPRTemporary
scratchGPR(this);
253 temp2
.adopt(scratchGPR
);
254 scratch2
= temp2
.gpr();
257 JITCompiler::Jump rhsNotCell
;
258 bool hadCellCheck
= false;
259 if (!isKnownCell(valueUse
.index()) && !isCellPrediction(m_jit
.getPrediction(valueUse
.index()))) {
261 rhsNotCell
= m_jit
.branchIfNotCell(valueGPR
);
264 markCellCard(m_jit
, ownerGPR
, scratch1
, scratch2
);
267 rhsNotCell
.link(&m_jit
);
271 void SpeculativeJIT::writeBarrier(GPRReg ownerGPR
, JSCell
* value
, WriteBarrierUseKind useKind
, GPRReg scratch1
, GPRReg scratch2
)
273 UNUSED_PARAM(ownerGPR
);
275 UNUSED_PARAM(scratch1
);
276 UNUSED_PARAM(scratch2
);
277 UNUSED_PARAM(useKind
);
279 if (Heap::isMarked(value
))
282 #if ENABLE(WRITE_BARRIER_PROFILING)
283 JITCompiler::emitCount(m_jit
, WriteBarrierCounters::jitCounterFor(useKind
));
289 if (scratch1
== InvalidGPRReg
) {
290 GPRTemporary
scratchGPR(this);
291 temp1
.adopt(scratchGPR
);
292 scratch1
= temp1
.gpr();
294 if (scratch2
== InvalidGPRReg
) {
295 GPRTemporary
scratchGPR(this);
296 temp2
.adopt(scratchGPR
);
297 scratch2
= temp2
.gpr();
300 markCellCard(m_jit
, ownerGPR
, scratch1
, scratch2
);
304 void SpeculativeJIT::writeBarrier(JSCell
* owner
, GPRReg valueGPR
, Edge valueUse
, WriteBarrierUseKind useKind
, GPRReg scratch
)
307 UNUSED_PARAM(valueGPR
);
308 UNUSED_PARAM(scratch
);
309 UNUSED_PARAM(useKind
);
311 if (isKnownNotCell(valueUse
.index()))
314 #if ENABLE(WRITE_BARRIER_PROFILING)
315 JITCompiler::emitCount(m_jit
, WriteBarrierCounters::jitCounterFor(useKind
));
319 JITCompiler::Jump rhsNotCell
;
320 bool hadCellCheck
= false;
321 if (!isKnownCell(valueUse
.index()) && !isCellPrediction(m_jit
.getPrediction(valueUse
.index()))) {
323 rhsNotCell
= m_jit
.branchIfNotCell(valueGPR
);
327 if (scratch
== InvalidGPRReg
) {
328 GPRTemporary
scratchGPR(this);
329 temp
.adopt(scratchGPR
);
330 scratch
= temp
.gpr();
333 uint8_t* cardAddress
= Heap::addressOfCardFor(owner
);
334 m_jit
.move(JITCompiler::TrustedImmPtr(cardAddress
), scratch
);
335 m_jit
.store8(JITCompiler::TrustedImm32(1), JITCompiler::Address(scratch
));
338 rhsNotCell
.link(&m_jit
);
342 bool SpeculativeJIT::nonSpeculativeCompare(Node
& node
, MacroAssembler::RelationalCondition cond
, S_DFGOperation_EJJ helperFunction
)
344 unsigned branchIndexInBlock
= detectPeepHoleBranch();
345 if (branchIndexInBlock
!= UINT_MAX
) {
346 NodeIndex branchNodeIndex
= m_jit
.graph().m_blocks
[m_block
]->at(branchIndexInBlock
);
348 ASSERT(node
.adjustedRefCount() == 1);
350 nonSpeculativePeepholeBranch(node
, branchNodeIndex
, cond
, helperFunction
);
352 m_indexInBlock
= branchIndexInBlock
;
353 m_compileIndex
= branchNodeIndex
;
358 nonSpeculativeNonPeepholeCompare(node
, cond
, helperFunction
);
363 bool SpeculativeJIT::nonSpeculativeStrictEq(Node
& node
, bool invert
)
365 unsigned branchIndexInBlock
= detectPeepHoleBranch();
366 if (branchIndexInBlock
!= UINT_MAX
) {
367 NodeIndex branchNodeIndex
= m_jit
.graph().m_blocks
[m_block
]->at(branchIndexInBlock
);
369 ASSERT(node
.adjustedRefCount() == 1);
371 nonSpeculativePeepholeStrictEq(node
, branchNodeIndex
, invert
);
373 m_indexInBlock
= branchIndexInBlock
;
374 m_compileIndex
= branchNodeIndex
;
379 nonSpeculativeNonPeepholeStrictEq(node
, invert
);
385 static const char* dataFormatString(DataFormat format
)
387 // These values correspond to the DataFormat enum.
388 const char* strings
[] = {
406 return strings
[format
];
409 void SpeculativeJIT::dump(const char* label
)
412 dataLog("<%s>\n", label
);
418 dataLog(" VirtualRegisters:\n");
419 for (unsigned i
= 0; i
< m_generationInfo
.size(); ++i
) {
420 GenerationInfo
& info
= m_generationInfo
[i
];
422 dataLog(" % 3d:%s%s", i
, dataFormatString(info
.registerFormat()), dataFormatString(info
.spillFormat()));
424 dataLog(" % 3d:[__][__]", i
);
425 if (info
.registerFormat() == DataFormatDouble
)
426 dataLog(":fpr%d\n", info
.fpr());
427 else if (info
.registerFormat() != DataFormatNone
428 #if USE(JSVALUE32_64)
429 && !(info
.registerFormat() & DataFormatJS
)
432 ASSERT(info
.gpr() != InvalidGPRReg
);
433 dataLog(":%s\n", GPRInfo::debugName(info
.gpr()));
438 dataLog("</%s>\n", label
);
443 #if DFG_ENABLE(CONSISTENCY_CHECK)
444 void SpeculativeJIT::checkConsistency()
448 for (gpr_iterator iter
= m_gprs
.begin(); iter
!= m_gprs
.end(); ++iter
) {
449 if (iter
.isLocked()) {
450 dataLog("DFG_CONSISTENCY_CHECK failed: gpr %s is locked.\n", iter
.debugName());
454 for (fpr_iterator iter
= m_fprs
.begin(); iter
!= m_fprs
.end(); ++iter
) {
455 if (iter
.isLocked()) {
456 dataLog("DFG_CONSISTENCY_CHECK failed: fpr %s is locked.\n", iter
.debugName());
461 for (unsigned i
= 0; i
< m_generationInfo
.size(); ++i
) {
462 VirtualRegister virtualRegister
= (VirtualRegister
)i
;
463 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
466 switch (info
.registerFormat()) {
470 case DataFormatJSInteger
:
471 case DataFormatJSDouble
:
472 case DataFormatJSCell
:
473 case DataFormatJSBoolean
:
474 #if USE(JSVALUE32_64)
477 case DataFormatInteger
:
479 case DataFormatBoolean
:
480 case DataFormatStorage
: {
481 GPRReg gpr
= info
.gpr();
482 ASSERT(gpr
!= InvalidGPRReg
);
483 if (m_gprs
.name(gpr
) != virtualRegister
) {
484 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (gpr %s).\n", virtualRegister
, GPRInfo::debugName(gpr
));
489 case DataFormatDouble
: {
490 FPRReg fpr
= info
.fpr();
491 ASSERT(fpr
!= InvalidFPRReg
);
492 if (m_fprs
.name(fpr
) != virtualRegister
) {
493 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (fpr %s).\n", virtualRegister
, FPRInfo::debugName(fpr
));
501 for (gpr_iterator iter
= m_gprs
.begin(); iter
!= m_gprs
.end(); ++iter
) {
502 VirtualRegister virtualRegister
= iter
.name();
503 if (virtualRegister
== InvalidVirtualRegister
)
506 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
508 if (iter
.regID() != info
.gpr()) {
509 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter
.debugName(), virtualRegister
);
513 if (!(info
.registerFormat() & DataFormatJS
)) {
514 if (iter
.regID() != info
.gpr()) {
515 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter
.debugName(), virtualRegister
);
519 if (iter
.regID() != info
.tagGPR() && iter
.regID() != info
.payloadGPR()) {
520 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter
.debugName(), virtualRegister
);
527 for (fpr_iterator iter
= m_fprs
.begin(); iter
!= m_fprs
.end(); ++iter
) {
528 VirtualRegister virtualRegister
= iter
.name();
529 if (virtualRegister
== InvalidVirtualRegister
)
532 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
533 if (iter
.regID() != info
.fpr()) {
534 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for fpr %s (virtual register %d).\n", iter
.debugName(), virtualRegister
);
546 GPRTemporary::GPRTemporary()
548 , m_gpr(InvalidGPRReg
)
552 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
)
554 , m_gpr(InvalidGPRReg
)
556 m_gpr
= m_jit
->allocate();
559 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
, GPRReg specific
)
561 , m_gpr(InvalidGPRReg
)
563 m_gpr
= m_jit
->allocate(specific
);
566 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
, SpeculateIntegerOperand
& op1
)
568 , m_gpr(InvalidGPRReg
)
570 if (m_jit
->canReuse(op1
.index()))
571 m_gpr
= m_jit
->reuse(op1
.gpr());
573 m_gpr
= m_jit
->allocate();
576 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
, SpeculateIntegerOperand
& op1
, SpeculateIntegerOperand
& op2
)
578 , m_gpr(InvalidGPRReg
)
580 if (m_jit
->canReuse(op1
.index()))
581 m_gpr
= m_jit
->reuse(op1
.gpr());
582 else if (m_jit
->canReuse(op2
.index()))
583 m_gpr
= m_jit
->reuse(op2
.gpr());
585 m_gpr
= m_jit
->allocate();
588 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
, SpeculateStrictInt32Operand
& op1
)
590 , m_gpr(InvalidGPRReg
)
592 if (m_jit
->canReuse(op1
.index()))
593 m_gpr
= m_jit
->reuse(op1
.gpr());
595 m_gpr
= m_jit
->allocate();
598 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
, IntegerOperand
& op1
)
600 , m_gpr(InvalidGPRReg
)
602 if (m_jit
->canReuse(op1
.index()))
603 m_gpr
= m_jit
->reuse(op1
.gpr());
605 m_gpr
= m_jit
->allocate();
608 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
, IntegerOperand
& op1
, IntegerOperand
& op2
)
610 , m_gpr(InvalidGPRReg
)
612 if (m_jit
->canReuse(op1
.index()))
613 m_gpr
= m_jit
->reuse(op1
.gpr());
614 else if (m_jit
->canReuse(op2
.index()))
615 m_gpr
= m_jit
->reuse(op2
.gpr());
617 m_gpr
= m_jit
->allocate();
620 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
, SpeculateCellOperand
& op1
)
622 , m_gpr(InvalidGPRReg
)
624 if (m_jit
->canReuse(op1
.index()))
625 m_gpr
= m_jit
->reuse(op1
.gpr());
627 m_gpr
= m_jit
->allocate();
630 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
, SpeculateBooleanOperand
& op1
)
632 , m_gpr(InvalidGPRReg
)
634 if (m_jit
->canReuse(op1
.index()))
635 m_gpr
= m_jit
->reuse(op1
.gpr());
637 m_gpr
= m_jit
->allocate();
641 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
, JSValueOperand
& op1
)
643 , m_gpr(InvalidGPRReg
)
645 if (m_jit
->canReuse(op1
.index()))
646 m_gpr
= m_jit
->reuse(op1
.gpr());
648 m_gpr
= m_jit
->allocate();
651 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
, JSValueOperand
& op1
, bool tag
)
653 , m_gpr(InvalidGPRReg
)
655 if (!op1
.isDouble() && m_jit
->canReuse(op1
.index()))
656 m_gpr
= m_jit
->reuse(tag
? op1
.tagGPR() : op1
.payloadGPR());
658 m_gpr
= m_jit
->allocate();
662 GPRTemporary::GPRTemporary(SpeculativeJIT
* jit
, StorageOperand
& op1
)
664 , m_gpr(InvalidGPRReg
)
666 if (m_jit
->canReuse(op1
.index()))
667 m_gpr
= m_jit
->reuse(op1
.gpr());
669 m_gpr
= m_jit
->allocate();
672 void GPRTemporary::adopt(GPRTemporary
& other
)
675 ASSERT(m_gpr
== InvalidGPRReg
);
677 ASSERT(other
.m_gpr
!= InvalidGPRReg
);
681 other
.m_gpr
= InvalidGPRReg
;
684 FPRTemporary::FPRTemporary(SpeculativeJIT
* jit
)
686 , m_fpr(InvalidFPRReg
)
688 m_fpr
= m_jit
->fprAllocate();
691 FPRTemporary::FPRTemporary(SpeculativeJIT
* jit
, DoubleOperand
& op1
)
693 , m_fpr(InvalidFPRReg
)
695 if (m_jit
->canReuse(op1
.index()))
696 m_fpr
= m_jit
->reuse(op1
.fpr());
698 m_fpr
= m_jit
->fprAllocate();
701 FPRTemporary::FPRTemporary(SpeculativeJIT
* jit
, DoubleOperand
& op1
, DoubleOperand
& op2
)
703 , m_fpr(InvalidFPRReg
)
705 if (m_jit
->canReuse(op1
.index()))
706 m_fpr
= m_jit
->reuse(op1
.fpr());
707 else if (m_jit
->canReuse(op2
.index()))
708 m_fpr
= m_jit
->reuse(op2
.fpr());
710 m_fpr
= m_jit
->fprAllocate();
713 FPRTemporary::FPRTemporary(SpeculativeJIT
* jit
, SpeculateDoubleOperand
& op1
)
715 , m_fpr(InvalidFPRReg
)
717 if (m_jit
->canReuse(op1
.index()))
718 m_fpr
= m_jit
->reuse(op1
.fpr());
720 m_fpr
= m_jit
->fprAllocate();
723 FPRTemporary::FPRTemporary(SpeculativeJIT
* jit
, SpeculateDoubleOperand
& op1
, SpeculateDoubleOperand
& op2
)
725 , m_fpr(InvalidFPRReg
)
727 if (m_jit
->canReuse(op1
.index()))
728 m_fpr
= m_jit
->reuse(op1
.fpr());
729 else if (m_jit
->canReuse(op2
.index()))
730 m_fpr
= m_jit
->reuse(op2
.fpr());
732 m_fpr
= m_jit
->fprAllocate();
735 #if USE(JSVALUE32_64)
736 FPRTemporary::FPRTemporary(SpeculativeJIT
* jit
, JSValueOperand
& op1
)
738 , m_fpr(InvalidFPRReg
)
740 if (op1
.isDouble() && m_jit
->canReuse(op1
.index()))
741 m_fpr
= m_jit
->reuse(op1
.fpr());
743 m_fpr
= m_jit
->fprAllocate();
747 void ValueSource::dump(FILE* out
) const
751 fprintf(out
, "NotSet");
754 fprintf(out
, "IsDead");
756 case ValueInRegisterFile
:
757 fprintf(out
, "InRegFile");
759 case Int32InRegisterFile
:
760 fprintf(out
, "Int32");
762 case CellInRegisterFile
:
763 fprintf(out
, "Cell");
765 case BooleanInRegisterFile
:
766 fprintf(out
, "Bool");
768 case DoubleInRegisterFile
:
769 fprintf(out
, "Double");
772 fprintf(out
, "Node(%d)", m_nodeIndex
);
777 void SpeculativeJIT::compilePeepHoleDoubleBranch(Node
& node
, NodeIndex branchNodeIndex
, JITCompiler::DoubleCondition condition
)
779 Node
& branchNode
= at(branchNodeIndex
);
780 BlockIndex taken
= branchNode
.takenBlockIndex();
781 BlockIndex notTaken
= branchNode
.notTakenBlockIndex();
783 SpeculateDoubleOperand
op1(this, node
.child1());
784 SpeculateDoubleOperand
op2(this, node
.child2());
786 branchDouble(condition
, op1
.fpr(), op2
.fpr(), taken
);
790 void SpeculativeJIT::compilePeepHoleObjectEquality(Node
& node
, NodeIndex branchNodeIndex
, const ClassInfo
* classInfo
, PredictionChecker predictionCheck
)
792 Node
& branchNode
= at(branchNodeIndex
);
793 BlockIndex taken
= branchNode
.takenBlockIndex();
794 BlockIndex notTaken
= branchNode
.notTakenBlockIndex();
796 MacroAssembler::RelationalCondition condition
= MacroAssembler::Equal
;
798 if (taken
== (m_block
+ 1)) {
799 condition
= MacroAssembler::NotEqual
;
800 BlockIndex tmp
= taken
;
805 SpeculateCellOperand
op1(this, node
.child1());
806 SpeculateCellOperand
op2(this, node
.child2());
808 GPRReg op1GPR
= op1
.gpr();
809 GPRReg op2GPR
= op2
.gpr();
811 if (!predictionCheck(m_state
.forNode(node
.child1()).m_type
))
812 speculationCheck(BadType
, JSValueSource::unboxedCell(op1GPR
), node
.child1().index(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(op1GPR
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo
)));
813 if (!predictionCheck(m_state
.forNode(node
.child2()).m_type
))
814 speculationCheck(BadType
, JSValueSource::unboxedCell(op2GPR
), node
.child2().index(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(op2GPR
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo
)));
816 branchPtr(condition
, op1GPR
, op2GPR
, taken
);
820 void SpeculativeJIT::compilePeepHoleIntegerBranch(Node
& node
, NodeIndex branchNodeIndex
, JITCompiler::RelationalCondition condition
)
822 Node
& branchNode
= at(branchNodeIndex
);
823 BlockIndex taken
= branchNode
.takenBlockIndex();
824 BlockIndex notTaken
= branchNode
.notTakenBlockIndex();
826 // The branch instruction will branch to the taken block.
827 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
828 if (taken
== (m_block
+ 1)) {
829 condition
= JITCompiler::invert(condition
);
830 BlockIndex tmp
= taken
;
835 if (isInt32Constant(node
.child1().index())) {
836 int32_t imm
= valueOfInt32Constant(node
.child1().index());
837 SpeculateIntegerOperand
op2(this, node
.child2());
838 branch32(condition
, JITCompiler::Imm32(imm
), op2
.gpr(), taken
);
839 } else if (isInt32Constant(node
.child2().index())) {
840 SpeculateIntegerOperand
op1(this, node
.child1());
841 int32_t imm
= valueOfInt32Constant(node
.child2().index());
842 branch32(condition
, op1
.gpr(), JITCompiler::Imm32(imm
), taken
);
844 SpeculateIntegerOperand
op1(this, node
.child1());
845 SpeculateIntegerOperand
op2(this, node
.child2());
846 branch32(condition
, op1
.gpr(), op2
.gpr(), taken
);
852 // Returns true if the compare is fused with a subsequent branch.
853 bool SpeculativeJIT::compilePeepHoleBranch(Node
& node
, MacroAssembler::RelationalCondition condition
, MacroAssembler::DoubleCondition doubleCondition
, S_DFGOperation_EJJ operation
)
855 // Fused compare & branch.
856 unsigned branchIndexInBlock
= detectPeepHoleBranch();
857 if (branchIndexInBlock
!= UINT_MAX
) {
858 NodeIndex branchNodeIndex
= m_jit
.graph().m_blocks
[m_block
]->at(branchIndexInBlock
);
860 // detectPeepHoleBranch currently only permits the branch to be the very next node,
861 // so can be no intervening nodes to also reference the compare.
862 ASSERT(node
.adjustedRefCount() == 1);
864 if (Node::shouldSpeculateInteger(at(node
.child1()), at(node
.child2())))
865 compilePeepHoleIntegerBranch(node
, branchNodeIndex
, condition
);
866 else if (Node::shouldSpeculateNumber(at(node
.child1()), at(node
.child2())))
867 compilePeepHoleDoubleBranch(node
, branchNodeIndex
, doubleCondition
);
868 else if (node
.op() == CompareEq
) {
869 if (Node::shouldSpeculateFinalObject(
870 at(node
.child1()), at(node
.child2()))) {
871 compilePeepHoleObjectEquality(
872 node
, branchNodeIndex
, &JSFinalObject::s_info
,
873 isFinalObjectPrediction
);
874 } else if (Node::shouldSpeculateArray(
875 at(node
.child1()), at(node
.child2()))) {
876 compilePeepHoleObjectEquality(
877 node
, branchNodeIndex
, &JSArray::s_info
,
879 } else if (at(node
.child1()).shouldSpeculateFinalObject()
880 && at(node
.child2()).shouldSpeculateFinalObjectOrOther()) {
881 compilePeepHoleObjectToObjectOrOtherEquality(
882 node
.child1(), node
.child2(), branchNodeIndex
,
883 &JSFinalObject::s_info
, isFinalObjectPrediction
);
884 } else if (at(node
.child1()).shouldSpeculateFinalObjectOrOther()
885 && at(node
.child2()).shouldSpeculateFinalObject()) {
886 compilePeepHoleObjectToObjectOrOtherEquality(
887 node
.child2(), node
.child1(), branchNodeIndex
,
888 &JSFinalObject::s_info
, isFinalObjectPrediction
);
889 } else if (at(node
.child1()).shouldSpeculateArray()
890 && at(node
.child2()).shouldSpeculateArrayOrOther()) {
891 compilePeepHoleObjectToObjectOrOtherEquality(
892 node
.child1(), node
.child2(), branchNodeIndex
,
893 &JSArray::s_info
, isArrayPrediction
);
894 } else if (at(node
.child1()).shouldSpeculateArrayOrOther()
895 && at(node
.child2()).shouldSpeculateArray()) {
896 compilePeepHoleObjectToObjectOrOtherEquality(
897 node
.child2(), node
.child1(), branchNodeIndex
,
898 &JSArray::s_info
, isArrayPrediction
);
900 nonSpeculativePeepholeBranch(node
, branchNodeIndex
, condition
, operation
);
904 nonSpeculativePeepholeBranch(node
, branchNodeIndex
, condition
, operation
);
910 m_indexInBlock
= branchIndexInBlock
;
911 m_compileIndex
= branchNodeIndex
;
917 void SpeculativeJIT::compileMovHint(Node
& node
)
919 ASSERT(node
.op() == SetLocal
);
921 setNodeIndexForOperand(node
.child1().index(), node
.local());
922 m_lastSetOperand
= node
.local();
925 void SpeculativeJIT::compile(BasicBlock
& block
)
927 ASSERT(m_compileOkay
);
929 if (!block
.isReachable
)
932 m_blockHeads
[m_block
] = m_jit
.label();
933 #if DFG_ENABLE(JIT_BREAK_ON_EVERY_BLOCK)
937 m_jit
.jitAssertHasValidCallFrame();
939 ASSERT(m_arguments
.size() == block
.variablesAtHead
.numberOfArguments());
940 for (size_t i
= 0; i
< m_arguments
.size(); ++i
) {
941 NodeIndex nodeIndex
= block
.variablesAtHead
.argument(i
);
942 if (nodeIndex
== NoNode
|| m_jit
.graph().argumentIsCaptured(i
))
943 m_arguments
[i
] = ValueSource(ValueInRegisterFile
);
945 m_arguments
[i
] = ValueSource::forPrediction(at(nodeIndex
).variableAccessData()->prediction());
949 m_state
.beginBasicBlock(&block
);
951 ASSERT(m_variables
.size() == block
.variablesAtHead
.numberOfLocals());
952 for (size_t i
= 0; i
< m_variables
.size(); ++i
) {
953 NodeIndex nodeIndex
= block
.variablesAtHead
.local(i
);
954 if ((nodeIndex
== NoNode
|| !at(nodeIndex
).refCount()) && !m_jit
.graph().localIsCaptured(i
))
955 m_variables
[i
] = ValueSource(SourceIsDead
);
956 else if (m_jit
.graph().localIsCaptured(i
))
957 m_variables
[i
] = ValueSource(ValueInRegisterFile
);
958 else if (at(nodeIndex
).variableAccessData()->shouldUseDoubleFormat())
959 m_variables
[i
] = ValueSource(DoubleInRegisterFile
);
961 m_variables
[i
] = ValueSource::forPrediction(at(nodeIndex
).variableAccessData()->prediction());
964 m_lastSetOperand
= std::numeric_limits
<int>::max();
965 m_codeOriginForOSR
= CodeOrigin();
967 if (DFG_ENABLE_EDGE_CODE_VERIFICATION
) {
968 JITCompiler::Jump verificationSucceeded
=
969 m_jit
.branch32(JITCompiler::Equal
, GPRInfo::regT0
, TrustedImm32(m_block
));
971 verificationSucceeded
.link(&m_jit
);
974 for (m_indexInBlock
= 0; m_indexInBlock
< block
.size(); ++m_indexInBlock
) {
975 m_compileIndex
= block
[m_indexInBlock
];
976 Node
& node
= at(m_compileIndex
);
977 m_codeOriginForOSR
= node
.codeOrigin
;
978 if (!node
.shouldGenerate()) {
979 #if DFG_ENABLE(DEBUG_VERBOSE)
980 dataLog("SpeculativeJIT skipping Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex
, node
.codeOrigin
.bytecodeIndex
, m_jit
.debugOffset());
984 compileMovHint(node
);
988 InlineCallFrame
* inlineCallFrame
= node
.codeOrigin
.inlineCallFrame
;
989 int argumentCountIncludingThis
= inlineCallFrame
->arguments
.size();
990 for (int i
= 0; i
< argumentCountIncludingThis
; ++i
) {
991 ValueRecovery recovery
= computeValueRecoveryFor(m_variables
[inlineCallFrame
->stackOffset
+ CallFrame::argumentOffsetIncludingThis(i
)]);
992 // The recovery should refer either to something that has already been
993 // stored into the register file at the right place, or to a constant,
994 // since the Arguments code isn't smart enough to handle anything else.
995 // The exception is the this argument, which we don't really need to be
997 #if DFG_ENABLE(DEBUG_VERBOSE)
998 dataLog("\nRecovery for argument %d: ", i
);
999 recovery
.dump(WTF::dataFile());
1001 ASSERT(!i
|| (recovery
.isAlreadyInRegisterFile() || recovery
.isConstant()));
1002 inlineCallFrame
->arguments
[i
] = recovery
;
1012 #if DFG_ENABLE(DEBUG_VERBOSE)
1013 dataLog("SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex
, node
.codeOrigin
.bytecodeIndex
, m_jit
.debugOffset());
1015 #if DFG_ENABLE(JIT_BREAK_ON_EVERY_NODE)
1018 #if DFG_ENABLE(XOR_DEBUG_AID)
1019 m_jit
.xorPtr(JITCompiler::TrustedImm32(m_compileIndex
), GPRInfo::regT0
);
1020 m_jit
.xorPtr(JITCompiler::TrustedImm32(m_compileIndex
), GPRInfo::regT0
);
1024 if (!m_compileOkay
) {
1025 m_compileOkay
= true;
1026 clearGenerationInfo();
1030 #if DFG_ENABLE(DEBUG_VERBOSE)
1031 if (node
.hasResult()) {
1032 GenerationInfo
& info
= m_generationInfo
[node
.virtualRegister()];
1033 dataLog("-> %s, vr#%d", dataFormatToString(info
.registerFormat()), (int)node
.virtualRegister());
1034 if (info
.registerFormat() != DataFormatNone
) {
1035 if (info
.registerFormat() == DataFormatDouble
)
1036 dataLog(", %s", FPRInfo::debugName(info
.fpr()));
1037 #if USE(JSVALUE32_64)
1038 else if (info
.registerFormat() & DataFormatJS
)
1039 dataLog(", %s %s", GPRInfo::debugName(info
.tagGPR()), GPRInfo::debugName(info
.payloadGPR()));
1042 dataLog(", %s", GPRInfo::debugName(info
.gpr()));
1050 #if DFG_ENABLE(VERBOSE_VALUE_RECOVERIES)
1051 for (size_t i
= 0; i
< m_arguments
.size(); ++i
)
1052 computeValueRecoveryFor(argumentToOperand(i
)).dump(stderr
);
1056 for (int operand
= 0; operand
< (int)m_variables
.size(); ++operand
)
1057 computeValueRecoveryFor(operand
).dump(stderr
);
1060 #if DFG_ENABLE(DEBUG_VERBOSE)
1064 // Make sure that the abstract state is rematerialized for the next node.
1065 m_state
.execute(m_indexInBlock
);
1067 if (node
.shouldGenerate())
1071 // Perform the most basic verification that children have been used correctly.
1072 #if !ASSERT_DISABLED
1073 for (unsigned index
= 0; index
< m_generationInfo
.size(); ++index
) {
1074 GenerationInfo
& info
= m_generationInfo
[index
];
1075 ASSERT(!info
.alive());
1080 // If we are making type predictions about our arguments then
1081 // we need to check that they are correct on function entry.
1082 void SpeculativeJIT::checkArgumentTypes()
1084 ASSERT(!m_compileIndex
);
1085 m_codeOriginForOSR
= CodeOrigin(0);
1087 for (size_t i
= 0; i
< m_arguments
.size(); ++i
)
1088 m_arguments
[i
] = ValueSource(ValueInRegisterFile
);
1089 for (size_t i
= 0; i
< m_variables
.size(); ++i
)
1090 m_variables
[i
] = ValueSource(ValueInRegisterFile
);
1092 for (int i
= 0; i
< m_jit
.codeBlock()->numParameters(); ++i
) {
1093 NodeIndex nodeIndex
= m_jit
.graph().m_arguments
[i
];
1094 Node
& node
= at(nodeIndex
);
1095 ASSERT(node
.op() == SetArgument
);
1096 if (!node
.shouldGenerate()) {
1097 // The argument is dead. We don't do any checks for such arguments.
1101 VariableAccessData
* variableAccessData
= node
.variableAccessData();
1102 VirtualRegister virtualRegister
= variableAccessData
->local();
1103 PredictedType predictedType
= variableAccessData
->prediction();
1105 JSValueSource valueSource
= JSValueSource(JITCompiler::addressFor(virtualRegister
));
1108 if (isInt32Prediction(predictedType
))
1109 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::Below
, JITCompiler::addressFor(virtualRegister
), GPRInfo::tagTypeNumberRegister
));
1110 else if (isArrayPrediction(predictedType
)) {
1111 GPRTemporary
temp(this);
1112 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), temp
.gpr());
1113 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchTestPtr(MacroAssembler::NonZero
, temp
.gpr(), GPRInfo::tagMaskRegister
));
1114 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info
)));
1115 } else if (isBooleanPrediction(predictedType
)) {
1116 GPRTemporary
temp(this);
1117 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), temp
.gpr());
1118 m_jit
.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse
)), temp
.gpr());
1119 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchTestPtr(MacroAssembler::NonZero
, temp
.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
1120 } else if (isInt8ArrayPrediction(predictedType
)) {
1121 GPRTemporary
temp(this);
1122 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), temp
.gpr());
1123 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchTestPtr(MacroAssembler::NonZero
, temp
.gpr(), GPRInfo::tagMaskRegister
));
1124 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->int8ArrayDescriptor().m_classInfo
)));
1125 } else if (isInt16ArrayPrediction(predictedType
)) {
1126 GPRTemporary
temp(this);
1127 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), temp
.gpr());
1128 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchTestPtr(MacroAssembler::NonZero
, temp
.gpr(), GPRInfo::tagMaskRegister
));
1129 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->int16ArrayDescriptor().m_classInfo
)));
1130 } else if (isInt32ArrayPrediction(predictedType
)) {
1131 GPRTemporary
temp(this);
1132 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), temp
.gpr());
1133 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchTestPtr(MacroAssembler::NonZero
, temp
.gpr(), GPRInfo::tagMaskRegister
));
1134 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->int32ArrayDescriptor().m_classInfo
)));
1135 } else if (isUint8ArrayPrediction(predictedType
)) {
1136 GPRTemporary
temp(this);
1137 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), temp
.gpr());
1138 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchTestPtr(MacroAssembler::NonZero
, temp
.gpr(), GPRInfo::tagMaskRegister
));
1139 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->uint8ArrayDescriptor().m_classInfo
)));
1140 } else if (isUint8ClampedArrayPrediction(predictedType
)) {
1141 GPRTemporary
temp(this);
1142 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), temp
.gpr());
1143 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchTestPtr(MacroAssembler::NonZero
, temp
.gpr(), GPRInfo::tagMaskRegister
));
1144 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->uint8ClampedArrayDescriptor().m_classInfo
)));
1145 } else if (isUint16ArrayPrediction(predictedType
)) {
1146 GPRTemporary
temp(this);
1147 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), temp
.gpr());
1148 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchTestPtr(MacroAssembler::NonZero
, temp
.gpr(), GPRInfo::tagMaskRegister
));
1149 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->uint16ArrayDescriptor().m_classInfo
)));
1150 } else if (isUint32ArrayPrediction(predictedType
)) {
1151 GPRTemporary
temp(this);
1152 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), temp
.gpr());
1153 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchTestPtr(MacroAssembler::NonZero
, temp
.gpr(), GPRInfo::tagMaskRegister
));
1154 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->uint32ArrayDescriptor().m_classInfo
)));
1155 } else if (isFloat32ArrayPrediction(predictedType
)) {
1156 GPRTemporary
temp(this);
1157 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), temp
.gpr());
1158 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchTestPtr(MacroAssembler::NonZero
, temp
.gpr(), GPRInfo::tagMaskRegister
));
1159 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->float32ArrayDescriptor().m_classInfo
)));
1160 } else if (isFloat64ArrayPrediction(predictedType
)) {
1161 GPRTemporary
temp(this);
1162 m_jit
.loadPtr(JITCompiler::addressFor(virtualRegister
), temp
.gpr());
1163 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchTestPtr(MacroAssembler::NonZero
, temp
.gpr(), GPRInfo::tagMaskRegister
));
1164 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->float64ArrayDescriptor().m_classInfo
)));
1167 if (isInt32Prediction(predictedType
))
1168 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, JITCompiler::tagFor(virtualRegister
), TrustedImm32(JSValue::Int32Tag
)));
1169 else if (isArrayPrediction(predictedType
)) {
1170 GPRTemporary
temp(this);
1171 m_jit
.load32(JITCompiler::tagFor(virtualRegister
), temp
.gpr());
1172 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, temp
.gpr(), TrustedImm32(JSValue::CellTag
)));
1173 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), temp
.gpr());
1174 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info
)));
1175 } else if (isBooleanPrediction(predictedType
))
1176 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, JITCompiler::tagFor(virtualRegister
), TrustedImm32(JSValue::BooleanTag
)));
1177 else if (isInt8ArrayPrediction(predictedType
)) {
1178 GPRTemporary
temp(this);
1179 m_jit
.load32(JITCompiler::tagFor(virtualRegister
), temp
.gpr());
1180 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, temp
.gpr(), TrustedImm32(JSValue::CellTag
)));
1181 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), temp
.gpr());
1182 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->int8ArrayDescriptor().m_classInfo
)));
1183 } else if (isInt16ArrayPrediction(predictedType
)) {
1184 GPRTemporary
temp(this);
1185 m_jit
.load32(JITCompiler::tagFor(virtualRegister
), temp
.gpr());
1186 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, temp
.gpr(), TrustedImm32(JSValue::CellTag
)));
1187 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), temp
.gpr());
1188 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->int16ArrayDescriptor().m_classInfo
)));
1189 } else if (isInt32ArrayPrediction(predictedType
)) {
1190 GPRTemporary
temp(this);
1191 m_jit
.load32(JITCompiler::tagFor(virtualRegister
), temp
.gpr());
1192 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, temp
.gpr(), TrustedImm32(JSValue::CellTag
)));
1193 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), temp
.gpr());
1194 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->int32ArrayDescriptor().m_classInfo
)));
1195 } else if (isUint8ArrayPrediction(predictedType
)) {
1196 GPRTemporary
temp(this);
1197 m_jit
.load32(JITCompiler::tagFor(virtualRegister
), temp
.gpr());
1198 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, temp
.gpr(), TrustedImm32(JSValue::CellTag
)));
1199 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), temp
.gpr());
1200 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->uint8ArrayDescriptor().m_classInfo
)));
1201 } else if (isUint8ClampedArrayPrediction(predictedType
)) {
1202 GPRTemporary
temp(this);
1203 m_jit
.load32(JITCompiler::tagFor(virtualRegister
), temp
.gpr());
1204 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, temp
.gpr(), TrustedImm32(JSValue::CellTag
)));
1205 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), temp
.gpr());
1206 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->uint8ClampedArrayDescriptor().m_classInfo
)));
1207 } else if (isUint16ArrayPrediction(predictedType
)) {
1208 GPRTemporary
temp(this);
1209 m_jit
.load32(JITCompiler::tagFor(virtualRegister
), temp
.gpr());
1210 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, temp
.gpr(), TrustedImm32(JSValue::CellTag
)));
1211 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), temp
.gpr());
1212 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->uint16ArrayDescriptor().m_classInfo
)));
1213 } else if (isUint32ArrayPrediction(predictedType
)) {
1214 GPRTemporary
temp(this);
1215 m_jit
.load32(JITCompiler::tagFor(virtualRegister
), temp
.gpr());
1216 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, temp
.gpr(), TrustedImm32(JSValue::CellTag
)));
1217 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), temp
.gpr());
1218 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->uint32ArrayDescriptor().m_classInfo
)));
1219 } else if (isFloat32ArrayPrediction(predictedType
)) {
1220 GPRTemporary
temp(this);
1221 m_jit
.load32(JITCompiler::tagFor(virtualRegister
), temp
.gpr());
1222 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, temp
.gpr(), TrustedImm32(JSValue::CellTag
)));
1223 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), temp
.gpr());
1224 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->float32ArrayDescriptor().m_classInfo
)));
1225 } else if (isFloat64ArrayPrediction(predictedType
)) {
1226 GPRTemporary
temp(this);
1227 m_jit
.load32(JITCompiler::tagFor(virtualRegister
), temp
.gpr());
1228 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branch32(MacroAssembler::NotEqual
, temp
.gpr(), TrustedImm32(JSValue::CellTag
)));
1229 m_jit
.load32(JITCompiler::payloadFor(virtualRegister
), temp
.gpr());
1230 speculationCheck(BadType
, valueSource
, nodeIndex
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(temp
.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit
.globalData()->float64ArrayDescriptor().m_classInfo
)));
1236 bool SpeculativeJIT::compile()
1238 checkArgumentTypes();
1240 if (DFG_ENABLE_EDGE_CODE_VERIFICATION
)
1241 m_jit
.move(TrustedImm32(0), GPRInfo::regT0
);
1243 ASSERT(!m_compileIndex
);
1244 for (m_block
= 0; m_block
< m_jit
.graph().m_blocks
.size(); ++m_block
)
1245 compile(*m_jit
.graph().m_blocks
[m_block
]);
1250 void SpeculativeJIT::createOSREntries()
1252 for (BlockIndex blockIndex
= 0; blockIndex
< m_jit
.graph().m_blocks
.size(); ++blockIndex
) {
1253 BasicBlock
& block
= *m_jit
.graph().m_blocks
[blockIndex
];
1254 if (!block
.isOSRTarget
)
1257 // Currently we only need to create OSR entry trampolines when using edge code
1258 // verification. But in the future, we'll need this for other things as well (like
1259 // when we have global reg alloc).
1260 // If we don't need OSR entry trampolin
1261 if (!DFG_ENABLE_EDGE_CODE_VERIFICATION
) {
1262 m_osrEntryHeads
.append(m_blockHeads
[blockIndex
]);
1266 m_osrEntryHeads
.append(m_jit
.label());
1267 m_jit
.move(TrustedImm32(blockIndex
), GPRInfo::regT0
);
1268 m_jit
.jump().linkTo(m_blockHeads
[blockIndex
], &m_jit
);
1272 void SpeculativeJIT::linkOSREntries(LinkBuffer
& linkBuffer
)
1274 unsigned osrEntryIndex
= 0;
1275 for (BlockIndex blockIndex
= 0; blockIndex
< m_jit
.graph().m_blocks
.size(); ++blockIndex
) {
1276 BasicBlock
& block
= *m_jit
.graph().m_blocks
[blockIndex
];
1277 if (block
.isOSRTarget
)
1278 m_jit
.noticeOSREntry(block
, m_osrEntryHeads
[osrEntryIndex
++], linkBuffer
);
1280 ASSERT(osrEntryIndex
== m_osrEntryHeads
.size());
1283 ValueRecovery
SpeculativeJIT::computeValueRecoveryFor(const ValueSource
& valueSource
)
1285 switch (valueSource
.kind()) {
1287 return ValueRecovery::constant(jsUndefined());
1289 case ValueInRegisterFile
:
1290 return ValueRecovery::alreadyInRegisterFile();
1292 case Int32InRegisterFile
:
1293 return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32();
1295 case CellInRegisterFile
:
1296 return ValueRecovery::alreadyInRegisterFileAsUnboxedCell();
1298 case BooleanInRegisterFile
:
1299 return ValueRecovery::alreadyInRegisterFileAsUnboxedBoolean();
1301 case DoubleInRegisterFile
:
1302 return ValueRecovery::alreadyInRegisterFileAsUnboxedDouble();
1305 if (isConstant(valueSource
.nodeIndex()))
1306 return ValueRecovery::constant(valueOfJSConstant(valueSource
.nodeIndex()));
1308 Node
* nodePtr
= &at(valueSource
.nodeIndex());
1309 if (!nodePtr
->shouldGenerate()) {
1310 // It's legitimately dead. As in, nobody will ever use this node, or operand,
1311 // ever. Set it to Undefined to make the GC happy after the OSR.
1312 return ValueRecovery::constant(jsUndefined());
1315 GenerationInfo
* infoPtr
= &m_generationInfo
[nodePtr
->virtualRegister()];
1316 if (!infoPtr
->alive() || infoPtr
->nodeIndex() != valueSource
.nodeIndex()) {
1317 // Try to see if there is an alternate node that would contain the value we want.
1318 // There are four possibilities:
1320 // Int32ToDouble: We can use this in place of the original node, but
1321 // we'd rather not; so we use it only if it is the only remaining
1324 // ValueToInt32: If the only remaining live version of the value is
1325 // ValueToInt32, then we can use it.
1327 // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber
1328 // then the only remaining uses are ones that want a properly formed number
1329 // rather than a UInt32 intermediate.
1331 // The reverse of the above: This node could be a UInt32ToNumber, but its
1332 // alternative is still alive. This means that the only remaining uses of
1333 // the number would be fine with a UInt32 intermediate.
1335 // DoubleAsInt32: Same as UInt32ToNumber.
1340 if (nodePtr
->op() == UInt32ToNumber
|| nodePtr
->op() == DoubleAsInt32
) {
1341 NodeIndex nodeIndex
= nodePtr
->child1().index();
1342 nodePtr
= &at(nodeIndex
);
1343 infoPtr
= &m_generationInfo
[nodePtr
->virtualRegister()];
1344 if (infoPtr
->alive() && infoPtr
->nodeIndex() == nodeIndex
)
1349 NodeIndex int32ToDoubleIndex
= NoNode
;
1350 NodeIndex valueToInt32Index
= NoNode
;
1351 NodeIndex uint32ToNumberIndex
= NoNode
;
1352 NodeIndex doubleAsInt32Index
= NoNode
;
1354 for (unsigned virtualRegister
= 0; virtualRegister
< m_generationInfo
.size(); ++virtualRegister
) {
1355 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
1358 if (info
.nodeIndex() == NoNode
)
1360 Node
& node
= at(info
.nodeIndex());
1361 if (node
.child1Unchecked() != valueSource
.nodeIndex())
1363 switch (node
.op()) {
1365 int32ToDoubleIndex
= info
.nodeIndex();
1368 valueToInt32Index
= info
.nodeIndex();
1370 case UInt32ToNumber
:
1371 uint32ToNumberIndex
= info
.nodeIndex();
1374 doubleAsInt32Index
= info
.nodeIndex();
1380 NodeIndex nodeIndexToUse
;
1381 if (doubleAsInt32Index
!= NoNode
)
1382 nodeIndexToUse
= doubleAsInt32Index
;
1383 else if (int32ToDoubleIndex
!= NoNode
)
1384 nodeIndexToUse
= int32ToDoubleIndex
;
1385 else if (valueToInt32Index
!= NoNode
)
1386 nodeIndexToUse
= valueToInt32Index
;
1387 else if (uint32ToNumberIndex
!= NoNode
)
1388 nodeIndexToUse
= uint32ToNumberIndex
;
1390 nodeIndexToUse
= NoNode
;
1392 if (nodeIndexToUse
!= NoNode
) {
1393 nodePtr
= &at(nodeIndexToUse
);
1394 infoPtr
= &m_generationInfo
[nodePtr
->virtualRegister()];
1395 ASSERT(infoPtr
->alive() && infoPtr
->nodeIndex() == nodeIndexToUse
);
1401 return ValueRecovery::constant(jsUndefined());
1404 ASSERT(infoPtr
->alive());
1406 if (infoPtr
->registerFormat() != DataFormatNone
) {
1407 if (infoPtr
->registerFormat() == DataFormatDouble
)
1408 return ValueRecovery::inFPR(infoPtr
->fpr());
1409 #if USE(JSVALUE32_64)
1410 if (infoPtr
->registerFormat() & DataFormatJS
)
1411 return ValueRecovery::inPair(infoPtr
->tagGPR(), infoPtr
->payloadGPR());
1413 return ValueRecovery::inGPR(infoPtr
->gpr(), infoPtr
->registerFormat());
1415 if (infoPtr
->spillFormat() != DataFormatNone
)
1416 return ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister
>(nodePtr
->virtualRegister()), infoPtr
->spillFormat());
1418 ASSERT_NOT_REACHED();
1419 return ValueRecovery();
1423 ASSERT_NOT_REACHED();
1424 return ValueRecovery();
1428 void SpeculativeJIT::compileGetCharCodeAt(Node
& node
)
1430 ASSERT(node
.child3() == NoNode
);
1431 SpeculateCellOperand
string(this, node
.child1());
1432 SpeculateStrictInt32Operand
index(this, node
.child2());
1433 StorageOperand
storage(this, node
.child3());
1435 GPRReg stringReg
= string
.gpr();
1436 GPRReg indexReg
= index
.gpr();
1437 GPRReg storageReg
= storage
.gpr();
1439 if (!isStringPrediction(m_state
.forNode(node
.child1()).m_type
)) {
1440 ASSERT(!(at(node
.child1()).prediction() & PredictString
));
1441 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), NoNode
);
1442 noResult(m_compileIndex
);
1446 // unsigned comparison so we can filter out negative indices and indices that are too large
1447 speculationCheck(Uncountable
, JSValueRegs(), NoNode
, m_jit
.branch32(MacroAssembler::AboveOrEqual
, indexReg
, MacroAssembler::Address(stringReg
, JSString::offsetOfLength())));
1449 GPRTemporary
scratch(this);
1450 GPRReg scratchReg
= scratch
.gpr();
1452 m_jit
.loadPtr(MacroAssembler::Address(stringReg
, JSString::offsetOfValue()), scratchReg
);
1454 // Load the character into scratchReg
1455 JITCompiler::Jump is16Bit
= m_jit
.branchTest32(MacroAssembler::Zero
, MacroAssembler::Address(scratchReg
, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
1457 m_jit
.load8(MacroAssembler::BaseIndex(storageReg
, indexReg
, MacroAssembler::TimesOne
, 0), scratchReg
);
1458 JITCompiler::Jump cont8Bit
= m_jit
.jump();
1460 is16Bit
.link(&m_jit
);
1462 m_jit
.load16(MacroAssembler::BaseIndex(storageReg
, indexReg
, MacroAssembler::TimesTwo
, 0), scratchReg
);
1464 cont8Bit
.link(&m_jit
);
1466 integerResult(scratchReg
, m_compileIndex
);
1469 void SpeculativeJIT::compileGetByValOnString(Node
& node
)
1471 SpeculateCellOperand
base(this, node
.child1());
1472 SpeculateStrictInt32Operand
property(this, node
.child2());
1473 StorageOperand
storage(this, node
.child3());
1474 GPRReg baseReg
= base
.gpr();
1475 GPRReg propertyReg
= property
.gpr();
1476 GPRReg storageReg
= storage
.gpr();
1478 if (!isStringPrediction(m_state
.forNode(node
.child1()).m_type
)) {
1479 ASSERT(!(at(node
.child1()).prediction() & PredictString
));
1480 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), NoNode
);
1481 noResult(m_compileIndex
);
1485 // unsigned comparison so we can filter out negative indices and indices that are too large
1486 speculationCheck(Uncountable
, JSValueRegs(), NoNode
, m_jit
.branch32(MacroAssembler::AboveOrEqual
, propertyReg
, MacroAssembler::Address(baseReg
, JSString::offsetOfLength())));
1488 GPRTemporary
scratch(this);
1489 GPRReg scratchReg
= scratch
.gpr();
1491 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, JSString::offsetOfValue()), scratchReg
);
1493 // Load the character into scratchReg
1494 JITCompiler::Jump is16Bit
= m_jit
.branchTest32(MacroAssembler::Zero
, MacroAssembler::Address(scratchReg
, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
1496 m_jit
.load8(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesOne
, 0), scratchReg
);
1497 JITCompiler::Jump cont8Bit
= m_jit
.jump();
1499 is16Bit
.link(&m_jit
);
1501 m_jit
.load16(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesTwo
, 0), scratchReg
);
1503 // We only support ascii characters
1504 speculationCheck(Uncountable
, JSValueRegs(), NoNode
, m_jit
.branch32(MacroAssembler::AboveOrEqual
, scratchReg
, TrustedImm32(0x100)));
1506 // 8 bit string values don't need the isASCII check.
1507 cont8Bit
.link(&m_jit
);
1509 GPRTemporary
smallStrings(this);
1510 GPRReg smallStringsReg
= smallStrings
.gpr();
1511 m_jit
.move(MacroAssembler::TrustedImmPtr(m_jit
.globalData()->smallStrings
.singleCharacterStrings()), smallStringsReg
);
1512 m_jit
.loadPtr(MacroAssembler::BaseIndex(smallStringsReg
, scratchReg
, MacroAssembler::ScalePtr
, 0), scratchReg
);
1513 speculationCheck(Uncountable
, JSValueRegs(), NoNode
, m_jit
.branchTest32(MacroAssembler::Zero
, scratchReg
));
1514 cellResult(scratchReg
, m_compileIndex
);
1517 GeneratedOperandType
SpeculativeJIT::checkGeneratedTypeForToInt32(NodeIndex nodeIndex
)
1519 #if DFG_ENABLE(DEBUG_VERBOSE)
1520 dataLog("checkGeneratedTypeForToInt32@%d ", nodeIndex
);
1522 Node
& node
= at(nodeIndex
);
1523 VirtualRegister virtualRegister
= node
.virtualRegister();
1524 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
1526 if (info
.registerFormat() == DataFormatNone
) {
1527 if (node
.hasConstant()) {
1528 if (isInt32Constant(nodeIndex
))
1529 return GeneratedOperandInteger
;
1531 if (isNumberConstant(nodeIndex
))
1532 return GeneratedOperandDouble
;
1534 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), NoNode
);
1535 return GeneratedOperandTypeUnknown
;
1538 if (info
.spillFormat() == DataFormatDouble
)
1539 return GeneratedOperandDouble
;
1542 switch (info
.registerFormat()) {
1543 case DataFormatBoolean
: // This type never occurs.
1544 case DataFormatStorage
:
1545 ASSERT_NOT_REACHED();
1547 case DataFormatCell
:
1548 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), NoNode
);
1549 return GeneratedOperandTypeUnknown
;
1551 case DataFormatNone
:
1552 case DataFormatJSCell
:
1554 case DataFormatJSBoolean
:
1555 return GeneratedOperandJSValue
;
1557 case DataFormatJSInteger
:
1558 case DataFormatInteger
:
1559 return GeneratedOperandInteger
;
1561 case DataFormatJSDouble
:
1562 case DataFormatDouble
:
1563 return GeneratedOperandDouble
;
1566 ASSERT_NOT_REACHED();
1567 return GeneratedOperandTypeUnknown
;
1570 void SpeculativeJIT::compileValueToInt32(Node
& node
)
1572 if (at(node
.child1()).shouldSpeculateInteger()) {
1573 SpeculateIntegerOperand
op1(this, node
.child1());
1574 GPRTemporary
result(this, op1
);
1575 m_jit
.move(op1
.gpr(), result
.gpr());
1576 integerResult(result
.gpr(), m_compileIndex
, op1
.format());
1580 if (at(node
.child1()).shouldSpeculateNumber()) {
1581 switch (checkGeneratedTypeForToInt32(node
.child1().index())) {
1582 case GeneratedOperandInteger
: {
1583 SpeculateIntegerOperand
op1(this, node
.child1());
1584 GPRTemporary
result(this, op1
);
1585 m_jit
.move(op1
.gpr(), result
.gpr());
1586 integerResult(result
.gpr(), m_compileIndex
, op1
.format());
1589 case GeneratedOperandDouble
: {
1590 GPRTemporary
result(this);
1591 DoubleOperand
op1(this, node
.child1());
1592 FPRReg fpr
= op1
.fpr();
1593 GPRReg gpr
= result
.gpr();
1594 JITCompiler::Jump truncatedToInteger
= m_jit
.branchTruncateDoubleToInt32(fpr
, gpr
, JITCompiler::BranchIfTruncateSuccessful
);
1596 silentSpillAllRegisters(gpr
);
1597 callOperation(toInt32
, gpr
, fpr
);
1598 silentFillAllRegisters(gpr
);
1600 truncatedToInteger
.link(&m_jit
);
1601 integerResult(gpr
, m_compileIndex
);
1604 case GeneratedOperandJSValue
: {
1605 GPRTemporary
result(this);
1607 JSValueOperand
op1(this, node
.child1());
1609 GPRReg gpr
= op1
.gpr();
1610 GPRReg resultGpr
= result
.gpr();
1611 FPRTemporary
tempFpr(this);
1612 FPRReg fpr
= tempFpr
.fpr();
1614 JITCompiler::Jump isInteger
= m_jit
.branchPtr(MacroAssembler::AboveOrEqual
, gpr
, GPRInfo::tagTypeNumberRegister
);
1616 speculationCheck(BadType
, JSValueRegs(gpr
), node
.child1().index(), m_jit
.branchTestPtr(MacroAssembler::Zero
, gpr
, GPRInfo::tagTypeNumberRegister
));
1618 // First, if we get here we have a double encoded as a JSValue
1619 m_jit
.move(gpr
, resultGpr
);
1620 unboxDouble(resultGpr
, fpr
);
1622 silentSpillAllRegisters(resultGpr
);
1623 callOperation(toInt32
, resultGpr
, fpr
);
1624 silentFillAllRegisters(resultGpr
);
1626 JITCompiler::Jump converted
= m_jit
.jump();
1628 isInteger
.link(&m_jit
);
1629 m_jit
.zeroExtend32ToPtr(gpr
, resultGpr
);
1631 converted
.link(&m_jit
);
1633 Node
& childNode
= at(node
.child1().index());
1634 VirtualRegister virtualRegister
= childNode
.virtualRegister();
1635 GenerationInfo
& info
= m_generationInfo
[virtualRegister
];
1637 JSValueOperand
op1(this, node
.child1());
1639 GPRReg payloadGPR
= op1
.payloadGPR();
1640 GPRReg resultGpr
= result
.gpr();
1642 if (info
.registerFormat() == DataFormatJSInteger
)
1643 m_jit
.move(payloadGPR
, resultGpr
);
1645 GPRReg tagGPR
= op1
.tagGPR();
1646 FPRTemporary
tempFpr(this);
1647 FPRReg fpr
= tempFpr
.fpr();
1648 FPRTemporary
scratch(this);
1650 JITCompiler::Jump isInteger
= m_jit
.branch32(MacroAssembler::Equal
, tagGPR
, TrustedImm32(JSValue::Int32Tag
));
1652 speculationCheck(BadType
, JSValueRegs(tagGPR
, payloadGPR
), node
.child1().index(), m_jit
.branch32(MacroAssembler::AboveOrEqual
, tagGPR
, TrustedImm32(JSValue::LowestTag
)));
1654 unboxDouble(tagGPR
, payloadGPR
, fpr
, scratch
.fpr());
1656 silentSpillAllRegisters(resultGpr
);
1657 callOperation(toInt32
, resultGpr
, fpr
);
1658 silentFillAllRegisters(resultGpr
);
1660 JITCompiler::Jump converted
= m_jit
.jump();
1662 isInteger
.link(&m_jit
);
1663 m_jit
.move(payloadGPR
, resultGpr
);
1665 converted
.link(&m_jit
);
1668 integerResult(resultGpr
, m_compileIndex
);
1671 case GeneratedOperandTypeUnknown
:
1672 ASSERT_NOT_REACHED();
1677 if (at(node
.child1()).shouldSpeculateBoolean()) {
1678 SpeculateBooleanOperand
op1(this, node
.child1());
1679 GPRTemporary
result(this, op1
);
1681 m_jit
.and32(JITCompiler::TrustedImm32(1), op1
.gpr());
1683 integerResult(op1
.gpr(), m_compileIndex
);
1687 // Do it the safe way.
1688 nonSpeculativeValueToInt32(node
);
1692 void SpeculativeJIT::compileUInt32ToNumber(Node
& node
)
1694 if (!nodeCanSpeculateInteger(node
.arithNodeFlags())) {
1695 // We know that this sometimes produces doubles. So produce a double every
1696 // time. This at least allows subsequent code to not have weird conditionals.
1698 IntegerOperand
op1(this, node
.child1());
1699 FPRTemporary
result(this);
1701 GPRReg inputGPR
= op1
.gpr();
1702 FPRReg outputFPR
= result
.fpr();
1704 m_jit
.convertInt32ToDouble(inputGPR
, outputFPR
);
1706 JITCompiler::Jump positive
= m_jit
.branch32(MacroAssembler::GreaterThanOrEqual
, inputGPR
, TrustedImm32(0));
1707 m_jit
.addDouble(JITCompiler::AbsoluteAddress(&AssemblyHelpers::twoToThe32
), outputFPR
);
1708 positive
.link(&m_jit
);
1710 doubleResult(outputFPR
, m_compileIndex
);
1714 IntegerOperand
op1(this, node
.child1());
1715 GPRTemporary
result(this, op1
);
1717 // Test the operand is positive. This is a very special speculation check - we actually
1718 // use roll-forward speculation here, where if this fails, we jump to the baseline
1719 // instruction that follows us, rather than the one we're executing right now. We have
1720 // to do this because by this point, the original values necessary to compile whatever
1721 // operation the UInt32ToNumber originated from might be dead.
1722 forwardSpeculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branch32(MacroAssembler::LessThan
, op1
.gpr(), TrustedImm32(0)), ValueRecovery::uint32InGPR(op1
.gpr()));
1724 m_jit
.move(op1
.gpr(), result
.gpr());
1725 integerResult(result
.gpr(), m_compileIndex
, op1
.format());
1728 void SpeculativeJIT::compileDoubleAsInt32(Node
& node
)
1730 SpeculateDoubleOperand
op1(this, node
.child1());
1731 FPRTemporary
scratch(this);
1732 GPRTemporary
result(this);
1734 FPRReg valueFPR
= op1
.fpr();
1735 FPRReg scratchFPR
= scratch
.fpr();
1736 GPRReg resultGPR
= result
.gpr();
1738 JITCompiler::JumpList failureCases
;
1739 m_jit
.branchConvertDoubleToInt32(valueFPR
, resultGPR
, failureCases
, scratchFPR
);
1740 forwardSpeculationCheck(Overflow
, JSValueRegs(), NoNode
, failureCases
, ValueRecovery::inFPR(valueFPR
));
1742 integerResult(resultGPR
, m_compileIndex
);
1745 void SpeculativeJIT::compileInt32ToDouble(Node
& node
)
1748 // On JSVALUE64 we have a way of loading double constants in a more direct manner
1749 // than a int->double conversion. On 32_64, unfortunately, we currently don't have
1750 // any such mechanism - though we could have it, if we just provisioned some memory
1751 // in CodeBlock for the double form of integer constants.
1752 if (at(node
.child1()).hasConstant()) {
1753 ASSERT(isInt32Constant(node
.child1().index()));
1754 FPRTemporary
result(this);
1755 GPRTemporary
temp(this);
1756 m_jit
.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfNumberConstant(node
.child1().index())))), temp
.gpr());
1757 m_jit
.movePtrToDouble(temp
.gpr(), result
.fpr());
1758 doubleResult(result
.fpr(), m_compileIndex
);
1763 if (isInt32Prediction(m_state
.forNode(node
.child1()).m_type
)) {
1764 SpeculateIntegerOperand
op1(this, node
.child1());
1765 FPRTemporary
result(this);
1766 m_jit
.convertInt32ToDouble(op1
.gpr(), result
.fpr());
1767 doubleResult(result
.fpr(), m_compileIndex
);
1771 JSValueOperand
op1(this, node
.child1());
1772 FPRTemporary
result(this);
1775 GPRTemporary
temp(this);
1777 GPRReg op1GPR
= op1
.gpr();
1778 GPRReg tempGPR
= temp
.gpr();
1779 FPRReg resultFPR
= result
.fpr();
1781 JITCompiler::Jump isInteger
= m_jit
.branchPtr(
1782 MacroAssembler::AboveOrEqual
, op1GPR
, GPRInfo::tagTypeNumberRegister
);
1785 BadType
, JSValueRegs(op1GPR
), node
.child1(),
1786 m_jit
.branchTestPtr(MacroAssembler::Zero
, op1GPR
, GPRInfo::tagTypeNumberRegister
));
1788 m_jit
.move(op1GPR
, tempGPR
);
1789 unboxDouble(tempGPR
, resultFPR
);
1790 JITCompiler::Jump done
= m_jit
.jump();
1792 isInteger
.link(&m_jit
);
1793 m_jit
.convertInt32ToDouble(op1GPR
, resultFPR
);
1796 FPRTemporary
temp(this);
1798 GPRReg op1TagGPR
= op1
.tagGPR();
1799 GPRReg op1PayloadGPR
= op1
.payloadGPR();
1800 FPRReg tempFPR
= temp
.fpr();
1801 FPRReg resultFPR
= result
.fpr();
1803 JITCompiler::Jump isInteger
= m_jit
.branch32(
1804 MacroAssembler::Equal
, op1TagGPR
, TrustedImm32(JSValue::Int32Tag
));
1807 BadType
, JSValueRegs(op1TagGPR
, op1PayloadGPR
), node
.child1(),
1808 m_jit
.branch32(MacroAssembler::AboveOrEqual
, op1TagGPR
, TrustedImm32(JSValue::LowestTag
)));
1810 unboxDouble(op1TagGPR
, op1PayloadGPR
, resultFPR
, tempFPR
);
1811 JITCompiler::Jump done
= m_jit
.jump();
1813 isInteger
.link(&m_jit
);
1814 m_jit
.convertInt32ToDouble(op1PayloadGPR
, resultFPR
);
1818 doubleResult(resultFPR
, m_compileIndex
);
1821 static double clampDoubleToByte(double d
)
1831 static void compileClampIntegerToByte(JITCompiler
& jit
, GPRReg result
)
1833 MacroAssembler::Jump inBounds
= jit
.branch32(MacroAssembler::BelowOrEqual
, result
, JITCompiler::TrustedImm32(0xff));
1834 MacroAssembler::Jump tooBig
= jit
.branch32(MacroAssembler::GreaterThan
, result
, JITCompiler::TrustedImm32(0xff));
1835 jit
.xorPtr(result
, result
);
1836 MacroAssembler::Jump clamped
= jit
.jump();
1838 jit
.move(JITCompiler::TrustedImm32(255), result
);
1840 inBounds
.link(&jit
);
1843 static void compileClampDoubleToByte(JITCompiler
& jit
, GPRReg result
, FPRReg source
, FPRReg scratch
)
1845 // Unordered compare so we pick up NaN
1846 static const double zero
= 0;
1847 static const double byteMax
= 255;
1848 static const double half
= 0.5;
1849 jit
.loadDouble(&zero
, scratch
);
1850 MacroAssembler::Jump tooSmall
= jit
.branchDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered
, source
, scratch
);
1851 jit
.loadDouble(&byteMax
, scratch
);
1852 MacroAssembler::Jump tooBig
= jit
.branchDouble(MacroAssembler::DoubleGreaterThan
, source
, scratch
);
1854 jit
.loadDouble(&half
, scratch
);
1855 // FIXME: This should probably just use a floating point round!
1856 // https://bugs.webkit.org/show_bug.cgi?id=72054
1857 jit
.addDouble(source
, scratch
);
1858 jit
.truncateDoubleToInt32(scratch
, result
);
1859 MacroAssembler::Jump truncatedInt
= jit
.jump();
1861 tooSmall
.link(&jit
);
1862 jit
.xorPtr(result
, result
);
1863 MacroAssembler::Jump zeroed
= jit
.jump();
1866 jit
.move(JITCompiler::TrustedImm32(255), result
);
1868 truncatedInt
.link(&jit
);
1873 void SpeculativeJIT::compileGetTypedArrayLength(const TypedArrayDescriptor
& descriptor
, Node
& node
, bool needsSpeculationCheck
)
1875 SpeculateCellOperand
base(this, node
.child1());
1876 GPRTemporary
result(this);
1878 GPRReg baseGPR
= base
.gpr();
1879 GPRReg resultGPR
= result
.gpr();
1881 if (needsSpeculationCheck
)
1882 speculationCheck(BadType
, JSValueSource::unboxedCell(baseGPR
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseGPR
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
1884 m_jit
.load32(MacroAssembler::Address(baseGPR
, descriptor
.m_lengthOffset
), resultGPR
);
1886 integerResult(resultGPR
, m_compileIndex
);
1889 void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor
& descriptor
, Node
& node
, size_t elementSize
, TypedArraySpeculationRequirements speculationRequirements
, TypedArraySignedness signedness
)
1891 SpeculateCellOperand
base(this, node
.child1());
1892 SpeculateStrictInt32Operand
property(this, node
.child2());
1893 StorageOperand
storage(this, node
.child3());
1895 GPRReg baseReg
= base
.gpr();
1896 GPRReg propertyReg
= property
.gpr();
1897 GPRReg storageReg
= storage
.gpr();
1899 GPRTemporary
result(this);
1900 GPRReg resultReg
= result
.gpr();
1902 if (speculationRequirements
!= NoTypedArrayTypeSpecCheck
) {
1903 ASSERT_NOT_REACHED();
1904 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), NoNode
);
1905 noResult(m_compileIndex
);
1909 MacroAssembler::Jump inBounds
= m_jit
.branch32(MacroAssembler::Below
, propertyReg
, MacroAssembler::Address(baseReg
, descriptor
.m_lengthOffset
));
1910 m_jit
.xorPtr(resultReg
, resultReg
);
1911 MacroAssembler::Jump outOfBounds
= m_jit
.jump();
1912 inBounds
.link(&m_jit
);
1913 switch (elementSize
) {
1915 if (signedness
== SignedTypedArray
)
1916 m_jit
.load8Signed(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesOne
), resultReg
);
1918 m_jit
.load8(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesOne
), resultReg
);
1921 if (signedness
== SignedTypedArray
)
1922 m_jit
.load16Signed(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesTwo
), resultReg
);
1924 m_jit
.load16(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesTwo
), resultReg
);
1927 m_jit
.load32(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesFour
), resultReg
);
1930 ASSERT_NOT_REACHED();
1932 outOfBounds
.link(&m_jit
);
1933 if (elementSize
< 4 || signedness
== SignedTypedArray
) {
1934 integerResult(resultReg
, m_compileIndex
);
1938 ASSERT(elementSize
== 4 && signedness
== UnsignedTypedArray
);
1939 if (node
.shouldSpeculateInteger()) {
1940 forwardSpeculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branch32(MacroAssembler::LessThan
, resultReg
, TrustedImm32(0)), ValueRecovery::uint32InGPR(resultReg
));
1941 integerResult(resultReg
, m_compileIndex
);
1945 FPRTemporary
fresult(this);
1946 m_jit
.convertInt32ToDouble(resultReg
, fresult
.fpr());
1947 JITCompiler::Jump positive
= m_jit
.branch32(MacroAssembler::GreaterThanOrEqual
, resultReg
, TrustedImm32(0));
1948 m_jit
.addDouble(JITCompiler::AbsoluteAddress(&AssemblyHelpers::twoToThe32
), fresult
.fpr());
1949 positive
.link(&m_jit
);
1950 doubleResult(fresult
.fpr(), m_compileIndex
);
1953 void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor
& descriptor
, GPRReg base
, GPRReg property
, Node
& node
, size_t elementSize
, TypedArraySpeculationRequirements speculationRequirements
, TypedArraySignedness signedness
, TypedArrayRounding rounding
)
1955 Edge baseUse
= node
.child1();
1956 Edge valueUse
= node
.child3();
1958 if (speculationRequirements
!= NoTypedArrayTypeSpecCheck
)
1959 speculationCheck(BadType
, JSValueSource::unboxedCell(base
), baseUse
, m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(base
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
1963 if (at(valueUse
).isConstant()) {
1964 JSValue jsValue
= valueOfJSConstant(valueUse
.index());
1965 if (!jsValue
.isNumber()) {
1966 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), NoNode
);
1967 noResult(m_compileIndex
);
1970 double d
= jsValue
.asNumber();
1971 if (rounding
== ClampRounding
) {
1972 ASSERT(elementSize
== 1);
1973 d
= clampDoubleToByte(d
);
1975 GPRTemporary
scratch(this);
1976 GPRReg scratchReg
= scratch
.gpr();
1977 m_jit
.move(Imm32(toInt32(d
)), scratchReg
);
1978 value
.adopt(scratch
);
1979 valueGPR
= scratchReg
;
1980 } else if (at(valueUse
).shouldSpeculateInteger()) {
1981 SpeculateIntegerOperand
valueOp(this, valueUse
);
1982 GPRTemporary
scratch(this);
1983 GPRReg scratchReg
= scratch
.gpr();
1984 m_jit
.move(valueOp
.gpr(), scratchReg
);
1985 if (rounding
== ClampRounding
) {
1986 ASSERT(elementSize
== 1);
1987 compileClampIntegerToByte(m_jit
, scratchReg
);
1989 value
.adopt(scratch
);
1990 valueGPR
= scratchReg
;
1991 } else if (rounding
== ClampRounding
) {
1992 ASSERT(elementSize
== 1);
1993 SpeculateDoubleOperand
valueOp(this, valueUse
);
1994 GPRTemporary
result(this);
1995 FPRTemporary
floatScratch(this);
1996 FPRReg fpr
= valueOp
.fpr();
1997 GPRReg gpr
= result
.gpr();
1998 compileClampDoubleToByte(m_jit
, gpr
, fpr
, floatScratch
.fpr());
1999 value
.adopt(result
);
2002 SpeculateDoubleOperand
valueOp(this, valueUse
);
2003 GPRTemporary
result(this);
2004 FPRReg fpr
= valueOp
.fpr();
2005 GPRReg gpr
= result
.gpr();
2006 MacroAssembler::Jump notNaN
= m_jit
.branchDouble(MacroAssembler::DoubleEqual
, fpr
, fpr
);
2007 m_jit
.xorPtr(gpr
, gpr
);
2008 MacroAssembler::Jump fixed
= m_jit
.jump();
2009 notNaN
.link(&m_jit
);
2011 MacroAssembler::Jump done
;
2012 if (signedness
== SignedTypedArray
)
2013 done
= m_jit
.branchTruncateDoubleToInt32(fpr
, gpr
, MacroAssembler::BranchIfTruncateSuccessful
);
2015 done
= m_jit
.branchTruncateDoubleToUint32(fpr
, gpr
, MacroAssembler::BranchIfTruncateSuccessful
);
2017 silentSpillAllRegisters(gpr
);
2018 callOperation(toInt32
, gpr
, fpr
);
2019 silentFillAllRegisters(gpr
);
2023 value
.adopt(result
);
2026 ASSERT_UNUSED(valueGPR
, valueGPR
!= property
);
2027 ASSERT(valueGPR
!= base
);
2028 GPRTemporary
storage(this);
2029 GPRReg storageReg
= storage
.gpr();
2030 ASSERT(valueGPR
!= storageReg
);
2031 m_jit
.loadPtr(MacroAssembler::Address(base
, descriptor
.m_storageOffset
), storageReg
);
2032 MacroAssembler::Jump outOfBounds
;
2033 if (speculationRequirements
!= NoTypedArraySpecCheck
)
2034 outOfBounds
= m_jit
.branch32(MacroAssembler::AboveOrEqual
, property
, MacroAssembler::Address(base
, descriptor
.m_lengthOffset
));
2036 switch (elementSize
) {
2038 m_jit
.store8(value
.gpr(), MacroAssembler::BaseIndex(storageReg
, property
, MacroAssembler::TimesOne
));
2041 m_jit
.store16(value
.gpr(), MacroAssembler::BaseIndex(storageReg
, property
, MacroAssembler::TimesTwo
));
2044 m_jit
.store32(value
.gpr(), MacroAssembler::BaseIndex(storageReg
, property
, MacroAssembler::TimesFour
));
2047 ASSERT_NOT_REACHED();
2049 if (speculationRequirements
!= NoTypedArraySpecCheck
)
2050 outOfBounds
.link(&m_jit
);
2051 noResult(m_compileIndex
);
2054 void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor
& descriptor
, Node
& node
, size_t elementSize
, TypedArraySpeculationRequirements speculationRequirements
)
2056 SpeculateCellOperand
base(this, node
.child1());
2057 SpeculateStrictInt32Operand
property(this, node
.child2());
2058 StorageOperand
storage(this, node
.child3());
2060 GPRReg baseReg
= base
.gpr();
2061 GPRReg propertyReg
= property
.gpr();
2062 GPRReg storageReg
= storage
.gpr();
2064 if (speculationRequirements
!= NoTypedArrayTypeSpecCheck
) {
2065 ASSERT_NOT_REACHED();
2066 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), NoNode
);
2067 noResult(m_compileIndex
);
2071 FPRTemporary
result(this);
2072 FPRReg resultReg
= result
.fpr();
2073 ASSERT(speculationRequirements
!= NoTypedArraySpecCheck
);
2074 MacroAssembler::Jump inBounds
= m_jit
.branch32(MacroAssembler::Below
, propertyReg
, MacroAssembler::Address(baseReg
, descriptor
.m_lengthOffset
));
2075 static const double zero
= 0;
2076 m_jit
.loadDouble(&zero
, resultReg
);
2077 MacroAssembler::Jump outOfBounds
= m_jit
.jump();
2078 inBounds
.link(&m_jit
);
2079 switch (elementSize
) {
2081 m_jit
.loadFloat(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesFour
), resultReg
);
2082 m_jit
.convertFloatToDouble(resultReg
, resultReg
);
2085 m_jit
.loadDouble(MacroAssembler::BaseIndex(storageReg
, propertyReg
, MacroAssembler::TimesEight
), resultReg
);
2086 MacroAssembler::Jump notNaN
= m_jit
.branchDouble(MacroAssembler::DoubleEqual
, resultReg
, resultReg
);
2087 static const double NaN
= std::numeric_limits
<double>::quiet_NaN();
2088 m_jit
.loadDouble(&NaN
, resultReg
);
2089 notNaN
.link(&m_jit
);
2093 ASSERT_NOT_REACHED();
2095 outOfBounds
.link(&m_jit
);
2096 doubleResult(resultReg
, m_compileIndex
);
2099 void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescriptor
& descriptor
, GPRReg base
, GPRReg property
, Node
& node
, size_t elementSize
, TypedArraySpeculationRequirements speculationRequirements
)
2101 Edge baseUse
= node
.child1();
2102 Edge valueUse
= node
.child3();
2104 SpeculateDoubleOperand
valueOp(this, valueUse
);
2106 if (speculationRequirements
!= NoTypedArrayTypeSpecCheck
)
2107 speculationCheck(BadType
, JSValueSource::unboxedCell(base
), baseUse
.index(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(base
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
2109 GPRTemporary
result(this);
2111 GPRTemporary
storage(this);
2112 GPRReg storageReg
= storage
.gpr();
2114 m_jit
.loadPtr(MacroAssembler::Address(base
, descriptor
.m_storageOffset
), storageReg
);
2115 MacroAssembler::Jump outOfBounds
;
2116 if (speculationRequirements
!= NoTypedArraySpecCheck
)
2117 outOfBounds
= m_jit
.branch32(MacroAssembler::AboveOrEqual
, property
, MacroAssembler::Address(base
, descriptor
.m_lengthOffset
));
2119 switch (elementSize
) {
2121 FPRTemporary
scratch(this);
2122 m_jit
.moveDouble(valueOp
.fpr(), scratch
.fpr());
2123 m_jit
.convertDoubleToFloat(valueOp
.fpr(), scratch
.fpr());
2124 m_jit
.storeFloat(scratch
.fpr(), MacroAssembler::BaseIndex(storageReg
, property
, MacroAssembler::TimesFour
));
2128 m_jit
.storeDouble(valueOp
.fpr(), MacroAssembler::BaseIndex(storageReg
, property
, MacroAssembler::TimesEight
));
2131 ASSERT_NOT_REACHED();
2133 if (speculationRequirements
!= NoTypedArraySpecCheck
)
2134 outOfBounds
.link(&m_jit
);
2135 noResult(m_compileIndex
);
2138 void SpeculativeJIT::compileInstanceOfForObject(Node
&, GPRReg valueReg
, GPRReg prototypeReg
, GPRReg scratchReg
)
2140 // Check that prototype is an object.
2141 m_jit
.loadPtr(MacroAssembler::Address(prototypeReg
, JSCell::structureOffset()), scratchReg
);
2142 speculationCheck(BadType
, JSValueRegs(), NoNode
, m_jit
.branchIfNotObject(scratchReg
));
2144 // Initialize scratchReg with the value being checked.
2145 m_jit
.move(valueReg
, scratchReg
);
2147 // Walk up the prototype chain of the value (in scratchReg), comparing to prototypeReg.
2148 MacroAssembler::Label
loop(&m_jit
);
2149 m_jit
.loadPtr(MacroAssembler::Address(scratchReg
, JSCell::structureOffset()), scratchReg
);
2151 m_jit
.loadPtr(MacroAssembler::Address(scratchReg
, Structure::prototypeOffset()), scratchReg
);
2153 m_jit
.load32(MacroAssembler::Address(scratchReg
, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
)), scratchReg
);
2155 MacroAssembler::Jump isInstance
= m_jit
.branchPtr(MacroAssembler::Equal
, scratchReg
, prototypeReg
);
2157 m_jit
.branchTestPtr(MacroAssembler::Zero
, scratchReg
, GPRInfo::tagMaskRegister
).linkTo(loop
, &m_jit
);
2159 m_jit
.branchTest32(MacroAssembler::NonZero
, scratchReg
).linkTo(loop
, &m_jit
);
2162 // No match - result is false.
2164 m_jit
.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(false))), scratchReg
);
2166 m_jit
.move(MacroAssembler::TrustedImm32(0), scratchReg
);
2168 MacroAssembler::Jump putResult
= m_jit
.jump();
2170 isInstance
.link(&m_jit
);
2172 m_jit
.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(true))), scratchReg
);
2174 m_jit
.move(MacroAssembler::TrustedImm32(1), scratchReg
);
2177 putResult
.link(&m_jit
);
2180 void SpeculativeJIT::compileInstanceOf(Node
& node
)
2182 if ((!!(at(node
.child1()).prediction() & ~PredictCell
)
2183 && !!(m_state
.forNode(node
.child1()).m_type
& ~PredictCell
))
2184 || at(node
.child1()).adjustedRefCount() == 1) {
2185 // It might not be a cell. Speculate less aggressively.
2186 // Or: it might only be used once (i.e. by us), so we get zero benefit
2187 // from speculating any more aggressively than we absolutely need to.
2189 JSValueOperand
value(this, node
.child1());
2190 SpeculateCellOperand
prototype(this, node
.child3());
2191 GPRTemporary
scratch(this);
2193 GPRReg prototypeReg
= prototype
.gpr();
2194 GPRReg scratchReg
= scratch
.gpr();
2197 GPRReg valueReg
= value
.gpr();
2198 MacroAssembler::Jump isCell
= m_jit
.branchTestPtr(MacroAssembler::Zero
, valueReg
, GPRInfo::tagMaskRegister
);
2199 m_jit
.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(false))), scratchReg
);
2201 GPRReg valueTagReg
= value
.tagGPR();
2202 GPRReg valueReg
= value
.payloadGPR();
2203 MacroAssembler::Jump isCell
= m_jit
.branch32(MacroAssembler::Equal
, valueTagReg
, TrustedImm32(JSValue::CellTag
));
2204 m_jit
.move(MacroAssembler::TrustedImm32(0), scratchReg
);
2207 MacroAssembler::Jump done
= m_jit
.jump();
2209 isCell
.link(&m_jit
);
2211 compileInstanceOfForObject(node
, valueReg
, prototypeReg
, scratchReg
);
2216 jsValueResult(scratchReg
, m_compileIndex
, DataFormatJSBoolean
);
2218 booleanResult(scratchReg
, m_compileIndex
);
2223 SpeculateCellOperand
value(this, node
.child1());
2224 // Base unused since we speculate default InstanceOf behaviour in CheckHasInstance.
2225 SpeculateCellOperand
prototype(this, node
.child3());
2227 GPRTemporary
scratch(this);
2229 GPRReg valueReg
= value
.gpr();
2230 GPRReg prototypeReg
= prototype
.gpr();
2231 GPRReg scratchReg
= scratch
.gpr();
2233 compileInstanceOfForObject(node
, valueReg
, prototypeReg
, scratchReg
);
2236 jsValueResult(scratchReg
, m_compileIndex
, DataFormatJSBoolean
);
2238 booleanResult(scratchReg
, m_compileIndex
);
2242 void SpeculativeJIT::compileSoftModulo(Node
& node
)
2244 // In the fast path, the dividend value could be the final result
2245 // (in case of |dividend| < |divisor|), so we speculate it as strict int32.
2246 SpeculateStrictInt32Operand
op1(this, node
.child1());
2247 #if CPU(X86) || CPU(X86_64)
2248 if (isInt32Constant(node
.child2().index())) {
2249 int32_t divisor
= valueOfInt32Constant(node
.child2().index());
2251 GPRReg op1Gpr
= op1
.gpr();
2253 GPRTemporary
eax(this, X86Registers::eax
);
2254 GPRTemporary
edx(this, X86Registers::edx
);
2255 GPRTemporary
scratch(this);
2256 GPRReg scratchGPR
= scratch
.gpr();
2259 if (op1Gpr
== X86Registers::eax
|| op1Gpr
== X86Registers::edx
) {
2260 op1SaveGPR
= allocate();
2261 ASSERT(op1Gpr
!= op1SaveGPR
);
2262 m_jit
.move(op1Gpr
, op1SaveGPR
);
2264 op1SaveGPR
= op1Gpr
;
2265 ASSERT(op1SaveGPR
!= X86Registers::eax
);
2266 ASSERT(op1SaveGPR
!= X86Registers::edx
);
2268 m_jit
.move(op1Gpr
, eax
.gpr());
2269 m_jit
.move(TrustedImm32(divisor
), scratchGPR
);
2271 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branch32(JITCompiler::Equal
, eax
.gpr(), TrustedImm32(-2147483647-1)));
2272 m_jit
.assembler().cdq();
2273 m_jit
.assembler().idivl_r(scratchGPR
);
2274 // Check that we're not about to create negative zero.
2275 // FIXME: if the node use doesn't care about neg zero, we can do this more easily.
2276 JITCompiler::Jump numeratorPositive
= m_jit
.branch32(JITCompiler::GreaterThanOrEqual
, op1SaveGPR
, TrustedImm32(0));
2277 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchTest32(JITCompiler::Zero
, edx
.gpr()));
2278 numeratorPositive
.link(&m_jit
);
2280 if (op1SaveGPR
!= op1Gpr
)
2283 integerResult(edx
.gpr(), m_compileIndex
);
2289 SpeculateIntegerOperand
op2(this, node
.child2());
2290 #if CPU(X86) || CPU(X86_64)
2291 GPRTemporary
eax(this, X86Registers::eax
);
2292 GPRTemporary
edx(this, X86Registers::edx
);
2293 GPRReg op1GPR
= op1
.gpr();
2294 GPRReg op2GPR
= op2
.gpr();
2300 if (op2GPR
== X86Registers::eax
|| op2GPR
== X86Registers::edx
) {
2301 op2TempGPR
= allocate();
2304 op2TempGPR
= InvalidGPRReg
;
2305 if (op1GPR
== X86Registers::eax
)
2306 temp
= X86Registers::edx
;
2308 temp
= X86Registers::eax
;
2311 if (op1GPR
== X86Registers::eax
|| op1GPR
== X86Registers::edx
) {
2312 op1SaveGPR
= allocate();
2313 ASSERT(op1GPR
!= op1SaveGPR
);
2314 m_jit
.move(op1GPR
, op1SaveGPR
);
2316 op1SaveGPR
= op1GPR
;
2318 ASSERT(temp
!= op1GPR
);
2319 ASSERT(temp
!= op2GPR
);
2320 ASSERT(op1SaveGPR
!= X86Registers::eax
);
2321 ASSERT(op1SaveGPR
!= X86Registers::edx
);
2323 m_jit
.add32(JITCompiler::TrustedImm32(1), op2GPR
, temp
);
2325 JITCompiler::Jump safeDenominator
= m_jit
.branch32(JITCompiler::Above
, temp
, JITCompiler::TrustedImm32(1));
2327 JITCompiler::Jump done
;
2328 // FIXME: if the node is not used as number then we can do this more easily.
2329 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchTest32(JITCompiler::Zero
, op2GPR
));
2330 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branch32(JITCompiler::Equal
, op1GPR
, TrustedImm32(-2147483647-1)));
2332 safeDenominator
.link(&m_jit
);
2334 if (op2TempGPR
!= InvalidGPRReg
) {
2335 m_jit
.move(op2GPR
, op2TempGPR
);
2336 op2GPR
= op2TempGPR
;
2339 m_jit
.move(op1GPR
, eax
.gpr());
2340 m_jit
.assembler().cdq();
2341 m_jit
.assembler().idivl_r(op2GPR
);
2343 if (op2TempGPR
!= InvalidGPRReg
)
2346 // Check that we're not about to create negative zero.
2347 // FIXME: if the node use doesn't care about neg zero, we can do this more easily.
2348 JITCompiler::Jump numeratorPositive
= m_jit
.branch32(JITCompiler::GreaterThanOrEqual
, op1SaveGPR
, TrustedImm32(0));
2349 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchTest32(JITCompiler::Zero
, edx
.gpr()));
2350 numeratorPositive
.link(&m_jit
);
2352 if (op1SaveGPR
!= op1GPR
)
2355 integerResult(edx
.gpr(), m_compileIndex
);
2356 #else // CPU(X86) || CPU(X86_64) --> so not X86
2357 // Do this the *safest* way possible: call out to a C function that will do the modulo,
2358 // and then attempt to convert back.
2359 GPRReg op1GPR
= op1
.gpr();
2360 GPRReg op2GPR
= op2
.gpr();
2362 FPRResult
result(this);
2365 callOperation(operationFModOnInts
, result
.fpr(), op1GPR
, op2GPR
);
2367 FPRTemporary
scratch(this);
2368 GPRTemporary
intResult(this);
2369 JITCompiler::JumpList failureCases
;
2370 m_jit
.branchConvertDoubleToInt32(result
.fpr(), intResult
.gpr(), failureCases
, scratch
.fpr());
2371 speculationCheck(Overflow
, JSValueRegs(), NoNode
, failureCases
);
2373 integerResult(intResult
.gpr(), m_compileIndex
);
2374 #endif // CPU(X86) || CPU(X86_64)
2377 void SpeculativeJIT::compileAdd(Node
& node
)
2379 if (m_jit
.graph().addShouldSpeculateInteger(node
)) {
2380 if (isNumberConstant(node
.child1().index())) {
2381 int32_t imm1
= valueOfNumberConstantAsInt32(node
.child1().index());
2382 SpeculateIntegerOperand
op2(this, node
.child2());
2383 GPRTemporary
result(this);
2385 if (nodeCanTruncateInteger(node
.arithNodeFlags())) {
2386 m_jit
.move(op2
.gpr(), result
.gpr());
2387 m_jit
.add32(Imm32(imm1
), result
.gpr());
2389 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchAdd32(MacroAssembler::Overflow
, op2
.gpr(), Imm32(imm1
), result
.gpr()));
2391 integerResult(result
.gpr(), m_compileIndex
);
2395 if (isNumberConstant(node
.child2().index())) {
2396 SpeculateIntegerOperand
op1(this, node
.child1());
2397 int32_t imm2
= valueOfNumberConstantAsInt32(node
.child2().index());
2398 GPRTemporary
result(this);
2400 if (nodeCanTruncateInteger(node
.arithNodeFlags())) {
2401 m_jit
.move(op1
.gpr(), result
.gpr());
2402 m_jit
.add32(Imm32(imm2
), result
.gpr());
2404 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchAdd32(MacroAssembler::Overflow
, op1
.gpr(), Imm32(imm2
), result
.gpr()));
2406 integerResult(result
.gpr(), m_compileIndex
);
2410 SpeculateIntegerOperand
op1(this, node
.child1());
2411 SpeculateIntegerOperand
op2(this, node
.child2());
2412 GPRTemporary
result(this, op1
, op2
);
2414 GPRReg gpr1
= op1
.gpr();
2415 GPRReg gpr2
= op2
.gpr();
2416 GPRReg gprResult
= result
.gpr();
2418 if (nodeCanTruncateInteger(node
.arithNodeFlags())) {
2419 if (gpr1
== gprResult
)
2420 m_jit
.add32(gpr2
, gprResult
);
2422 m_jit
.move(gpr2
, gprResult
);
2423 m_jit
.add32(gpr1
, gprResult
);
2426 MacroAssembler::Jump check
= m_jit
.branchAdd32(MacroAssembler::Overflow
, gpr1
, gpr2
, gprResult
);
2428 if (gpr1
== gprResult
)
2429 speculationCheck(Overflow
, JSValueRegs(), NoNode
, check
, SpeculationRecovery(SpeculativeAdd
, gprResult
, gpr2
));
2430 else if (gpr2
== gprResult
)
2431 speculationCheck(Overflow
, JSValueRegs(), NoNode
, check
, SpeculationRecovery(SpeculativeAdd
, gprResult
, gpr1
));
2433 speculationCheck(Overflow
, JSValueRegs(), NoNode
, check
);
2436 integerResult(gprResult
, m_compileIndex
);
2440 if (Node::shouldSpeculateNumber(at(node
.child1()), at(node
.child2()))) {
2441 SpeculateDoubleOperand
op1(this, node
.child1());
2442 SpeculateDoubleOperand
op2(this, node
.child2());
2443 FPRTemporary
result(this, op1
, op2
);
2445 FPRReg reg1
= op1
.fpr();
2446 FPRReg reg2
= op2
.fpr();
2447 m_jit
.addDouble(reg1
, reg2
, result
.fpr());
2449 doubleResult(result
.fpr(), m_compileIndex
);
2453 if (node
.op() == ValueAdd
) {
2454 compileValueAdd(node
);
2458 // We don't handle this yet. :-(
2459 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), NoNode
);
2462 void SpeculativeJIT::compileArithSub(Node
& node
)
2464 if (m_jit
.graph().addShouldSpeculateInteger(node
)) {
2465 if (isNumberConstant(node
.child2().index())) {
2466 SpeculateIntegerOperand
op1(this, node
.child1());
2467 int32_t imm2
= valueOfNumberConstantAsInt32(node
.child2().index());
2468 GPRTemporary
result(this);
2470 if (nodeCanTruncateInteger(node
.arithNodeFlags())) {
2471 m_jit
.move(op1
.gpr(), result
.gpr());
2472 m_jit
.sub32(Imm32(imm2
), result
.gpr());
2474 #if ENABLE(JIT_CONSTANT_BLINDING)
2475 GPRTemporary
scratch(this);
2476 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchSub32(MacroAssembler::Overflow
, op1
.gpr(), Imm32(imm2
), result
.gpr(), scratch
.gpr()));
2478 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchSub32(MacroAssembler::Overflow
, op1
.gpr(), Imm32(imm2
), result
.gpr()));
2482 integerResult(result
.gpr(), m_compileIndex
);
2486 if (isNumberConstant(node
.child1().index())) {
2487 int32_t imm1
= valueOfNumberConstantAsInt32(node
.child1().index());
2488 SpeculateIntegerOperand
op2(this, node
.child2());
2489 GPRTemporary
result(this);
2491 m_jit
.move(Imm32(imm1
), result
.gpr());
2492 if (nodeCanTruncateInteger(node
.arithNodeFlags()))
2493 m_jit
.sub32(op2
.gpr(), result
.gpr());
2495 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchSub32(MacroAssembler::Overflow
, op2
.gpr(), result
.gpr()));
2497 integerResult(result
.gpr(), m_compileIndex
);
2501 SpeculateIntegerOperand
op1(this, node
.child1());
2502 SpeculateIntegerOperand
op2(this, node
.child2());
2503 GPRTemporary
result(this);
2505 if (nodeCanTruncateInteger(node
.arithNodeFlags())) {
2506 m_jit
.move(op1
.gpr(), result
.gpr());
2507 m_jit
.sub32(op2
.gpr(), result
.gpr());
2509 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchSub32(MacroAssembler::Overflow
, op1
.gpr(), op2
.gpr(), result
.gpr()));
2511 integerResult(result
.gpr(), m_compileIndex
);
2515 SpeculateDoubleOperand
op1(this, node
.child1());
2516 SpeculateDoubleOperand
op2(this, node
.child2());
2517 FPRTemporary
result(this, op1
);
2519 FPRReg reg1
= op1
.fpr();
2520 FPRReg reg2
= op2
.fpr();
2521 m_jit
.subDouble(reg1
, reg2
, result
.fpr());
2523 doubleResult(result
.fpr(), m_compileIndex
);
2526 void SpeculativeJIT::compileArithNegate(Node
& node
)
2528 if (m_jit
.graph().negateShouldSpeculateInteger(node
)) {
2529 SpeculateIntegerOperand
op1(this, node
.child1());
2530 GPRTemporary
result(this);
2532 m_jit
.move(op1
.gpr(), result
.gpr());
2534 if (nodeCanTruncateInteger(node
.arithNodeFlags()))
2535 m_jit
.neg32(result
.gpr());
2537 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchNeg32(MacroAssembler::Overflow
, result
.gpr()));
2538 if (!nodeCanIgnoreNegativeZero(node
.arithNodeFlags()))
2539 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchTest32(MacroAssembler::Zero
, result
.gpr()));
2542 integerResult(result
.gpr(), m_compileIndex
);
2546 SpeculateDoubleOperand
op1(this, node
.child1());
2547 FPRTemporary
result(this);
2549 m_jit
.negateDouble(op1
.fpr(), result
.fpr());
2551 doubleResult(result
.fpr(), m_compileIndex
);
2554 void SpeculativeJIT::compileArithMul(Node
& node
)
2556 if (Node::shouldSpeculateInteger(at(node
.child1()), at(node
.child2())) && node
.canSpeculateInteger()) {
2557 SpeculateIntegerOperand
op1(this, node
.child1());
2558 SpeculateIntegerOperand
op2(this, node
.child2());
2559 GPRTemporary
result(this);
2561 GPRReg reg1
= op1
.gpr();
2562 GPRReg reg2
= op2
.gpr();
2564 // What is unfortunate is that we cannot take advantage of nodeCanTruncateInteger()
2565 // here. A multiply on integers performed in the double domain and then truncated to
2566 // an integer will give a different result than a multiply performed in the integer
2567 // domain and then truncated, if the integer domain result would have resulted in
2568 // something bigger than what a 32-bit integer can hold. JavaScript mandates that
2569 // the semantics are always as if the multiply had been performed in the double
2572 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchMul32(MacroAssembler::Overflow
, reg1
, reg2
, result
.gpr()));
2574 // Check for negative zero, if the users of this node care about such things.
2575 if (!nodeCanIgnoreNegativeZero(node
.arithNodeFlags())) {
2576 MacroAssembler::Jump resultNonZero
= m_jit
.branchTest32(MacroAssembler::NonZero
, result
.gpr());
2577 speculationCheck(NegativeZero
, JSValueRegs(), NoNode
, m_jit
.branch32(MacroAssembler::LessThan
, reg1
, TrustedImm32(0)));
2578 speculationCheck(NegativeZero
, JSValueRegs(), NoNode
, m_jit
.branch32(MacroAssembler::LessThan
, reg2
, TrustedImm32(0)));
2579 resultNonZero
.link(&m_jit
);
2582 integerResult(result
.gpr(), m_compileIndex
);
2586 SpeculateDoubleOperand
op1(this, node
.child1());
2587 SpeculateDoubleOperand
op2(this, node
.child2());
2588 FPRTemporary
result(this, op1
, op2
);
2590 FPRReg reg1
= op1
.fpr();
2591 FPRReg reg2
= op2
.fpr();
2593 m_jit
.mulDouble(reg1
, reg2
, result
.fpr());
2595 doubleResult(result
.fpr(), m_compileIndex
);
2598 #if CPU(X86) || CPU(X86_64)
2599 void SpeculativeJIT::compileIntegerArithDivForX86(Node
& node
)
2601 SpeculateIntegerOperand
op1(this, node
.child1());
2602 SpeculateIntegerOperand
op2(this, node
.child2());
2603 GPRTemporary
eax(this, X86Registers::eax
);
2604 GPRTemporary
edx(this, X86Registers::edx
);
2605 GPRReg op1GPR
= op1
.gpr();
2606 GPRReg op2GPR
= op2
.gpr();
2610 if (op2GPR
== X86Registers::eax
|| op2GPR
== X86Registers::edx
) {
2611 op2TempGPR
= allocate();
2614 op2TempGPR
= InvalidGPRReg
;
2615 if (op1GPR
== X86Registers::eax
)
2616 temp
= X86Registers::edx
;
2618 temp
= X86Registers::eax
;
2621 ASSERT(temp
!= op1GPR
);
2622 ASSERT(temp
!= op2GPR
);
2624 m_jit
.add32(JITCompiler::TrustedImm32(1), op2GPR
, temp
);
2626 JITCompiler::Jump safeDenominator
= m_jit
.branch32(JITCompiler::Above
, temp
, JITCompiler::TrustedImm32(1));
2628 JITCompiler::Jump done
;
2629 if (nodeUsedAsNumber(node
.arithNodeFlags())) {
2630 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchTest32(JITCompiler::Zero
, op2GPR
));
2631 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branch32(JITCompiler::Equal
, op1GPR
, TrustedImm32(-2147483647-1)));
2633 JITCompiler::Jump zero
= m_jit
.branchTest32(JITCompiler::Zero
, op2GPR
);
2634 JITCompiler::Jump notNeg2ToThe31
= m_jit
.branch32(JITCompiler::Equal
, op1GPR
, TrustedImm32(-2147483647-1));
2636 m_jit
.move(TrustedImm32(0), eax
.gpr());
2637 done
= m_jit
.jump();
2638 notNeg2ToThe31
.link(&m_jit
);
2641 safeDenominator
.link(&m_jit
);
2643 // If the user cares about negative zero, then speculate that we're not about
2644 // to produce negative zero.
2645 if (!nodeCanIgnoreNegativeZero(node
.arithNodeFlags())) {
2646 MacroAssembler::Jump numeratorNonZero
= m_jit
.branchTest32(MacroAssembler::NonZero
, op1GPR
);
2647 speculationCheck(NegativeZero
, JSValueRegs(), NoNode
, m_jit
.branch32(MacroAssembler::LessThan
, op2GPR
, TrustedImm32(0)));
2648 numeratorNonZero
.link(&m_jit
);
2651 if (op2TempGPR
!= InvalidGPRReg
) {
2652 m_jit
.move(op2GPR
, op2TempGPR
);
2653 op2GPR
= op2TempGPR
;
2656 m_jit
.move(op1GPR
, eax
.gpr());
2657 m_jit
.assembler().cdq();
2658 m_jit
.assembler().idivl_r(op2GPR
);
2660 if (op2TempGPR
!= InvalidGPRReg
)
2663 // Check that there was no remainder. If there had been, then we'd be obligated to
2664 // produce a double result instead.
2665 if (nodeUsedAsNumber(node
.arithNodeFlags()))
2666 speculationCheck(Overflow
, JSValueRegs(), NoNode
, m_jit
.branchTest32(JITCompiler::NonZero
, edx
.gpr()));
2670 integerResult(eax
.gpr(), m_compileIndex
);
2672 #endif // CPU(X86) || CPU(X86_64)
2674 void SpeculativeJIT::compileArithMod(Node
& node
)
2676 if (Node::shouldSpeculateInteger(at(node
.child1()), at(node
.child2()))
2677 && node
.canSpeculateInteger()) {
2678 compileSoftModulo(node
);
2682 SpeculateDoubleOperand
op1(this, node
.child1());
2683 SpeculateDoubleOperand
op2(this, node
.child2());
2685 FPRReg op1FPR
= op1
.fpr();
2686 FPRReg op2FPR
= op2
.fpr();
2690 FPRResult
result(this);
2692 callOperation(fmodAsDFGOperation
, result
.fpr(), op1FPR
, op2FPR
);
2694 doubleResult(result
.fpr(), m_compileIndex
);
2697 // Returns true if the compare is fused with a subsequent branch.
2698 bool SpeculativeJIT::compare(Node
& node
, MacroAssembler::RelationalCondition condition
, MacroAssembler::DoubleCondition doubleCondition
, S_DFGOperation_EJJ operation
)
2700 if (compilePeepHoleBranch(node
, condition
, doubleCondition
, operation
))
2703 if (Node::shouldSpeculateInteger(at(node
.child1()), at(node
.child2()))) {
2704 compileIntegerCompare(node
, condition
);
2708 if (Node::shouldSpeculateNumber(at(node
.child1()), at(node
.child2()))) {
2709 compileDoubleCompare(node
, doubleCondition
);
2713 if (node
.op() == CompareEq
) {
2714 if (Node::shouldSpeculateFinalObject(at(node
.child1()), at(node
.child2()))) {
2715 compileObjectEquality(node
, &JSFinalObject::s_info
, isFinalObjectPrediction
);
2719 if (Node::shouldSpeculateArray(at(node
.child1()), at(node
.child2()))) {
2720 compileObjectEquality(node
, &JSArray::s_info
, isArrayPrediction
);
2724 if (at(node
.child1()).shouldSpeculateFinalObject()
2725 && at(node
.child2()).shouldSpeculateFinalObjectOrOther()) {
2726 compileObjectToObjectOrOtherEquality(
2727 node
.child1(), node
.child2(), &JSFinalObject::s_info
,
2728 isFinalObjectPrediction
);
2732 if (at(node
.child1()).shouldSpeculateFinalObjectOrOther()
2733 && at(node
.child2()).shouldSpeculateFinalObject()) {
2734 compileObjectToObjectOrOtherEquality(
2735 node
.child2(), node
.child1(), &JSFinalObject::s_info
,
2736 isFinalObjectPrediction
);
2740 if (at(node
.child1()).shouldSpeculateArray()
2741 && at(node
.child2()).shouldSpeculateArrayOrOther()) {
2742 compileObjectToObjectOrOtherEquality(
2743 node
.child1(), node
.child2(), &JSArray::s_info
,
2748 if (at(node
.child1()).shouldSpeculateArrayOrOther()
2749 && at(node
.child2()).shouldSpeculateArray()) {
2750 compileObjectToObjectOrOtherEquality(
2751 node
.child2(), node
.child1(), &JSArray::s_info
,
2757 nonSpeculativeNonPeepholeCompare(node
, condition
, operation
);
2761 bool SpeculativeJIT::compileStrictEqForConstant(Node
& node
, Edge value
, JSValue constant
)
2763 JSValueOperand
op1(this, value
);
2765 unsigned branchIndexInBlock
= detectPeepHoleBranch();
2766 if (branchIndexInBlock
!= UINT_MAX
) {
2767 NodeIndex branchNodeIndex
= m_jit
.graph().m_blocks
[m_block
]->at(branchIndexInBlock
);
2768 Node
& branchNode
= at(branchNodeIndex
);
2769 BlockIndex taken
= branchNode
.takenBlockIndex();
2770 BlockIndex notTaken
= branchNode
.notTakenBlockIndex();
2771 MacroAssembler::RelationalCondition condition
= MacroAssembler::Equal
;
2773 // The branch instruction will branch to the taken block.
2774 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
2775 if (taken
== (m_block
+ 1)) {
2776 condition
= MacroAssembler::NotEqual
;
2777 BlockIndex tmp
= taken
;
2783 branchPtr(condition
, op1
.gpr(), MacroAssembler::TrustedImmPtr(bitwise_cast
<void*>(JSValue::encode(constant
))), taken
);
2785 GPRReg payloadGPR
= op1
.payloadGPR();
2786 GPRReg tagGPR
= op1
.tagGPR();
2787 if (condition
== MacroAssembler::Equal
) {
2788 // Drop down if not equal, go elsewhere if equal.
2789 MacroAssembler::Jump notEqual
= m_jit
.branch32(MacroAssembler::NotEqual
, tagGPR
, MacroAssembler::Imm32(constant
.tag()));
2790 branch32(MacroAssembler::Equal
, payloadGPR
, MacroAssembler::Imm32(constant
.payload()), taken
);
2791 notEqual
.link(&m_jit
);
2793 // Drop down if equal, go elsehwere if not equal.
2794 branch32(MacroAssembler::NotEqual
, tagGPR
, MacroAssembler::Imm32(constant
.tag()), taken
);
2795 branch32(MacroAssembler::NotEqual
, payloadGPR
, MacroAssembler::Imm32(constant
.payload()), taken
);
2803 m_indexInBlock
= branchIndexInBlock
;
2804 m_compileIndex
= branchNodeIndex
;
2808 GPRTemporary
result(this);
2811 GPRReg op1GPR
= op1
.gpr();
2812 GPRReg resultGPR
= result
.gpr();
2813 m_jit
.move(MacroAssembler::TrustedImmPtr(bitwise_cast
<void*>(ValueFalse
)), resultGPR
);
2814 MacroAssembler::Jump notEqual
= m_jit
.branchPtr(MacroAssembler::NotEqual
, op1GPR
, MacroAssembler::TrustedImmPtr(bitwise_cast
<void*>(JSValue::encode(constant
))));
2815 m_jit
.or32(MacroAssembler::TrustedImm32(1), resultGPR
);
2816 notEqual
.link(&m_jit
);
2817 jsValueResult(resultGPR
, m_compileIndex
, DataFormatJSBoolean
);
2819 GPRReg op1PayloadGPR
= op1
.payloadGPR();
2820 GPRReg op1TagGPR
= op1
.tagGPR();
2821 GPRReg resultGPR
= result
.gpr();
2822 m_jit
.move(TrustedImm32(0), resultGPR
);
2823 MacroAssembler::JumpList notEqual
;
2824 notEqual
.append(m_jit
.branch32(MacroAssembler::NotEqual
, op1TagGPR
, MacroAssembler::Imm32(constant
.tag())));
2825 notEqual
.append(m_jit
.branch32(MacroAssembler::NotEqual
, op1PayloadGPR
, MacroAssembler::Imm32(constant
.payload())));
2826 m_jit
.move(TrustedImm32(1), resultGPR
);
2827 notEqual
.link(&m_jit
);
2828 booleanResult(resultGPR
, m_compileIndex
);
2834 bool SpeculativeJIT::compileStrictEq(Node
& node
)
2836 // 1) If either operand is a constant and that constant is not a double, integer,
2837 // or string, then do a JSValue comparison.
2839 if (isJSConstant(node
.child1().index())) {
2840 JSValue value
= valueOfJSConstant(node
.child1().index());
2841 if (!value
.isNumber() && !value
.isString())
2842 return compileStrictEqForConstant(node
, node
.child2(), value
);
2845 if (isJSConstant(node
.child2().index())) {
2846 JSValue value
= valueOfJSConstant(node
.child2().index());
2847 if (!value
.isNumber() && !value
.isString())
2848 return compileStrictEqForConstant(node
, node
.child1(), value
);
2851 // 2) If the operands are predicted integer, do an integer comparison.
2853 if (Node::shouldSpeculateInteger(at(node
.child1()), at(node
.child2()))) {
2854 unsigned branchIndexInBlock
= detectPeepHoleBranch();
2855 if (branchIndexInBlock
!= UINT_MAX
) {
2856 NodeIndex branchNodeIndex
= m_jit
.graph().m_blocks
[m_block
]->at(branchIndexInBlock
);
2857 compilePeepHoleIntegerBranch(node
, branchNodeIndex
, MacroAssembler::Equal
);
2860 m_indexInBlock
= branchIndexInBlock
;
2861 m_compileIndex
= branchNodeIndex
;
2864 compileIntegerCompare(node
, MacroAssembler::Equal
);
2868 // 3) If the operands are predicted double, do a double comparison.
2870 if (Node::shouldSpeculateNumber(at(node
.child1()), at(node
.child2()))) {
2871 unsigned branchIndexInBlock
= detectPeepHoleBranch();
2872 if (branchIndexInBlock
!= UINT_MAX
) {
2873 NodeIndex branchNodeIndex
= m_jit
.graph().m_blocks
[m_block
]->at(branchIndexInBlock
);
2874 compilePeepHoleDoubleBranch(node
, branchNodeIndex
, MacroAssembler::DoubleEqual
);
2877 m_indexInBlock
= branchIndexInBlock
;
2878 m_compileIndex
= branchNodeIndex
;
2881 compileDoubleCompare(node
, MacroAssembler::DoubleEqual
);
2885 // 4) If the operands are predicted final object or array, then do a final object
2886 // or array comparison.
2888 if (Node::shouldSpeculateFinalObject(at(node
.child1()), at(node
.child2()))) {
2889 unsigned branchIndexInBlock
= detectPeepHoleBranch();
2890 if (branchIndexInBlock
!= UINT_MAX
) {
2891 NodeIndex branchNodeIndex
= m_jit
.graph().m_blocks
[m_block
]->at(branchIndexInBlock
);
2892 compilePeepHoleObjectEquality(node
, branchNodeIndex
, &JSFinalObject::s_info
, isFinalObjectPrediction
);
2895 m_indexInBlock
= branchIndexInBlock
;
2896 m_compileIndex
= branchNodeIndex
;
2899 compileObjectEquality(node
, &JSFinalObject::s_info
, isFinalObjectPrediction
);
2903 if (Node::shouldSpeculateArray(at(node
.child1()), at(node
.child2()))) {
2904 unsigned branchIndexInBlock
= detectPeepHoleBranch();
2905 if (branchIndexInBlock
!= UINT_MAX
) {
2906 NodeIndex branchNodeIndex
= m_jit
.graph().m_blocks
[m_block
]->at(branchIndexInBlock
);
2907 compilePeepHoleObjectEquality(node
, branchNodeIndex
, &JSArray::s_info
, isArrayPrediction
);
2910 m_indexInBlock
= branchIndexInBlock
;
2911 m_compileIndex
= branchNodeIndex
;
2914 compileObjectEquality(node
, &JSArray::s_info
, isArrayPrediction
);
2918 // 5) Fall back to non-speculative strict equality.
2920 return nonSpeculativeStrictEq(node
);
2923 void SpeculativeJIT::compileGetIndexedPropertyStorage(Node
& node
)
2925 if (!node
.prediction() || !at(node
.child1()).prediction() || !at(node
.child2()).prediction()) {
2926 terminateSpeculativeExecution(InadequateCoverage
, JSValueRegs(), NoNode
);
2930 SpeculateCellOperand
base(this, node
.child1());
2931 GPRReg baseReg
= base
.gpr();
2933 PredictedType basePrediction
= at(node
.child2()).prediction();
2934 if (!(basePrediction
& PredictInt32
) && basePrediction
) {
2935 ASSERT_NOT_REACHED();
2936 terminateSpeculativeExecution(Uncountable
, JSValueRegs(), NoNode
);
2937 noResult(m_compileIndex
);
2941 GPRTemporary
storage(this);
2942 GPRReg storageReg
= storage
.gpr();
2943 if (at(node
.child1()).prediction() == PredictString
) {
2944 if (!isStringPrediction(m_state
.forNode(node
.child1()).m_type
))
2945 speculationCheck(BadType
, JSValueSource::unboxedCell(baseReg
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseReg
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSString::s_info
)));
2947 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, JSString::offsetOfValue()), storageReg
);
2949 // Speculate that we're not accessing a rope
2950 speculationCheck(Uncountable
, JSValueRegs(), NoNode
, m_jit
.branchTest32(MacroAssembler::Zero
, storageReg
));
2952 m_jit
.loadPtr(MacroAssembler::Address(storageReg
, StringImpl::dataOffset()), storageReg
);
2953 } else if (at(node
.child1()).shouldSpeculateInt8Array()) {
2954 const TypedArrayDescriptor
& descriptor
= m_jit
.globalData()->int8ArrayDescriptor();
2955 if (!isInt8ArrayPrediction(m_state
.forNode(node
.child1()).m_type
))
2956 speculationCheck(BadType
, JSValueSource::unboxedCell(baseReg
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseReg
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
2957 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, descriptor
.m_storageOffset
), storageReg
);
2958 } else if (at(node
.child1()).shouldSpeculateInt16Array()) {
2959 const TypedArrayDescriptor
& descriptor
= m_jit
.globalData()->int16ArrayDescriptor();
2960 if (!isInt16ArrayPrediction(m_state
.forNode(node
.child1()).m_type
))
2961 speculationCheck(BadType
, JSValueSource::unboxedCell(baseReg
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseReg
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
2962 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, descriptor
.m_storageOffset
), storageReg
);
2963 } else if (at(node
.child1()).shouldSpeculateInt32Array()) {
2964 const TypedArrayDescriptor
& descriptor
= m_jit
.globalData()->int32ArrayDescriptor();
2965 if (!isInt32ArrayPrediction(m_state
.forNode(node
.child1()).m_type
))
2966 speculationCheck(BadType
, JSValueSource::unboxedCell(baseReg
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseReg
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
2967 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, descriptor
.m_storageOffset
), storageReg
);
2968 } else if (at(node
.child1()).shouldSpeculateUint8Array()) {
2969 const TypedArrayDescriptor
& descriptor
= m_jit
.globalData()->uint8ArrayDescriptor();
2970 if (!isUint8ArrayPrediction(m_state
.forNode(node
.child1()).m_type
))
2971 speculationCheck(BadType
, JSValueSource::unboxedCell(baseReg
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseReg
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
2972 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, descriptor
.m_storageOffset
), storageReg
);
2973 } else if (at(node
.child1()).shouldSpeculateUint8ClampedArray()) {
2974 const TypedArrayDescriptor
& descriptor
= m_jit
.globalData()->uint8ClampedArrayDescriptor();
2975 if (!isUint8ClampedArrayPrediction(m_state
.forNode(node
.child1()).m_type
))
2976 speculationCheck(BadType
, JSValueSource::unboxedCell(baseReg
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseReg
), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
2977 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, descriptor
.m_storageOffset
), storageReg
);
2978 } else if (at(node
.child1()).shouldSpeculateUint16Array()) {
2979 const TypedArrayDescriptor
& descriptor
= m_jit
.globalData()->uint16ArrayDescriptor();
2980 if (!isUint16ArrayPrediction(m_state
.forNode(node
.child1()).m_type
))
2981 speculationCheck(BadType
, JSValueSource::unboxedCell(baseReg
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseReg
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
2982 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, descriptor
.m_storageOffset
), storageReg
);
2983 } else if (at(node
.child1()).shouldSpeculateUint32Array()) {
2984 const TypedArrayDescriptor
& descriptor
= m_jit
.globalData()->uint32ArrayDescriptor();
2985 if (!isUint32ArrayPrediction(m_state
.forNode(node
.child1()).m_type
))
2986 speculationCheck(BadType
, JSValueSource::unboxedCell(baseReg
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseReg
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
2987 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, descriptor
.m_storageOffset
), storageReg
);
2988 } else if (at(node
.child1()).shouldSpeculateFloat32Array()) {
2989 const TypedArrayDescriptor
& descriptor
= m_jit
.globalData()->float32ArrayDescriptor();
2990 if (!isFloat32ArrayPrediction(m_state
.forNode(node
.child1()).m_type
))
2991 speculationCheck(BadType
, JSValueSource::unboxedCell(baseReg
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseReg
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
2992 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, descriptor
.m_storageOffset
), storageReg
);
2993 } else if (at(node
.child1()).shouldSpeculateFloat64Array()) {
2994 const TypedArrayDescriptor
& descriptor
= m_jit
.globalData()->float64ArrayDescriptor();
2995 if (!isFloat64ArrayPrediction(m_state
.forNode(node
.child1()).m_type
))
2996 speculationCheck(BadType
, JSValueSource::unboxedCell(baseReg
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseReg
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor
.m_classInfo
)));
2997 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, descriptor
.m_storageOffset
), storageReg
);
2999 if (!isArrayPrediction(m_state
.forNode(node
.child1()).m_type
))
3000 speculationCheck(BadType
, JSValueSource::unboxedCell(baseReg
), node
.child1(), m_jit
.branchPtr(MacroAssembler::NotEqual
, MacroAssembler::Address(baseReg
, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info
)));
3001 m_jit
.loadPtr(MacroAssembler::Address(baseReg
, JSArray::storageOffset()), storageReg
);
3003 storageResult(storageReg
, m_compileIndex
);
3006 void SpeculativeJIT::compileNewFunctionNoCheck(Node
& node
)
3008 GPRResult
result(this);
3009 GPRReg resultGPR
= result
.gpr();
3012 operationNewFunction
, resultGPR
, m_jit
.codeBlock()->functionDecl(node
.functionDeclIndex()));
3013 cellResult(resultGPR
, m_compileIndex
);
3016 void SpeculativeJIT::compileNewFunctionExpression(Node
& node
)
3018 GPRResult
result(this);
3019 GPRReg resultGPR
= result
.gpr();
3022 operationNewFunctionExpression
,
3024 m_jit
.codeBlock()->functionExpr(node
.functionExprIndex()));
3025 cellResult(resultGPR
, m_compileIndex
);
3028 bool SpeculativeJIT::compileRegExpExec(Node
& node
)
3030 unsigned branchIndexInBlock
= detectPeepHoleBranch();
3031 if (branchIndexInBlock
== UINT_MAX
)
3033 NodeIndex branchNodeIndex
= m_jit
.graph().m_blocks
[m_block
]->at(branchIndexInBlock
);
3034 ASSERT(node
.adjustedRefCount() == 1);
3036 Node
& branchNode
= at(branchNodeIndex
);
3037 BlockIndex taken
= branchNode
.takenBlockIndex();
3038 BlockIndex notTaken
= branchNode
.notTakenBlockIndex();
3040 bool invert
= false;
3041 if (taken
== (m_block
+ 1)) {
3043 BlockIndex tmp
= taken
;
3048 SpeculateCellOperand
base(this, node
.child1());
3049 SpeculateCellOperand
argument(this, node
.child2());
3050 GPRReg baseGPR
= base
.gpr();
3051 GPRReg argumentGPR
= argument
.gpr();
3054 GPRResult
result(this);
3055 callOperation(operationRegExpTest
, result
.gpr(), baseGPR
, argumentGPR
);
3057 branchTest32(invert
? JITCompiler::Zero
: JITCompiler::NonZero
, result
.gpr(), taken
);
3062 m_indexInBlock
= branchIndexInBlock
;
3063 m_compileIndex
= branchNodeIndex
;
3068 } } // namespace JSC::DFG