2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Intel Corporation. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "DFGSpeculativeJIT.h"
32 #include "JSByteArray.h"
34 namespace JSC { namespace DFG {
38 GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat)
40 Node& node = at(nodeIndex);
41 VirtualRegister virtualRegister = node.virtualRegister();
42 GenerationInfo& info = m_generationInfo[virtualRegister];
44 if (info.registerFormat() == DataFormatNone) {
45 GPRReg gpr = allocate();
47 if (node.hasConstant()) {
48 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
49 if (isInt32Constant(nodeIndex))
50 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
51 else if (isNumberConstant(nodeIndex))
54 ASSERT(isJSConstant(nodeIndex));
55 JSValue jsValue = valueOfJSConstant(nodeIndex);
56 m_jit.move(MacroAssembler::Imm32(jsValue.payload()), gpr);
59 ASSERT(info.spillFormat() == DataFormatJS || info.spillFormat() == DataFormatJSInteger);
60 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
61 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
64 info.fillInteger(gpr);
65 returnFormat = DataFormatInteger;
69 switch (info.registerFormat()) {
71 // Should have filled, above.
72 case DataFormatJSDouble:
73 case DataFormatDouble:
76 case DataFormatJSCell:
77 case DataFormatBoolean:
78 case DataFormatJSBoolean:
79 case DataFormatStorage:
80 // Should only be calling this function if we know this operand to be integer.
83 case DataFormatJSInteger: {
84 GPRReg tagGPR = info.tagGPR();
85 GPRReg payloadGPR = info.payloadGPR();
87 m_jit.jitAssertIsJSInt32(tagGPR);
88 m_gprs.unlock(tagGPR);
89 m_gprs.lock(payloadGPR);
90 m_gprs.release(tagGPR);
91 m_gprs.release(payloadGPR);
92 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderInteger);
93 info.fillInteger(payloadGPR);
94 returnFormat = DataFormatInteger;
98 case DataFormatInteger: {
99 GPRReg gpr = info.gpr();
101 m_jit.jitAssertIsInt32(gpr);
102 returnFormat = DataFormatInteger;
107 ASSERT_NOT_REACHED();
108 return InvalidGPRReg;
111 FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex)
113 Node& node = at(nodeIndex);
114 VirtualRegister virtualRegister = node.virtualRegister();
115 GenerationInfo& info = m_generationInfo[virtualRegister];
117 if (info.registerFormat() == DataFormatNone) {
119 if (node.hasConstant()) {
120 if (isInt32Constant(nodeIndex)) {
121 // FIXME: should not be reachable?
122 GPRReg gpr = allocate();
123 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
124 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
125 info.fillInteger(gpr);
127 } else if (isNumberConstant(nodeIndex)) {
128 FPRReg fpr = fprAllocate();
129 m_jit.loadDouble(addressOfDoubleConstant(nodeIndex), fpr);
130 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
131 info.fillDouble(fpr);
134 // FIXME: should not be reachable?
135 ASSERT_NOT_REACHED();
138 DataFormat spillFormat = info.spillFormat();
139 ASSERT(spillFormat & DataFormatJS);
140 if (spillFormat == DataFormatJSDouble) {
141 FPRReg fpr = fprAllocate();
142 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
143 m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
144 info.fillDouble(fpr);
148 FPRReg fpr = fprAllocate();
149 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag));
150 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
151 JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
153 isInteger.link(&m_jit);
154 m_jit.convertInt32ToDouble(JITCompiler::payloadFor(virtualRegister), fpr);
156 hasUnboxedDouble.link(&m_jit);
157 m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
158 info.fillDouble(fpr);
163 switch (info.registerFormat()) {
165 // Should have filled, above.
167 case DataFormatJSCell:
168 case DataFormatBoolean:
169 case DataFormatJSBoolean:
170 case DataFormatStorage:
171 // Should only be calling this function if we know this operand to be numeric.
172 ASSERT_NOT_REACHED();
174 case DataFormatJSInteger:
176 GPRReg tagGPR = info.tagGPR();
177 GPRReg payloadGPR = info.payloadGPR();
178 FPRReg fpr = fprAllocate();
180 m_gprs.lock(payloadGPR);
182 JITCompiler::Jump hasUnboxedDouble;
184 if (info.registerFormat() != DataFormatJSInteger) {
185 FPRTemporary scratch(this);
186 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
187 m_jit.jitAssertIsJSDouble(tagGPR);
188 unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr());
189 hasUnboxedDouble = m_jit.jump();
190 isInteger.link(&m_jit);
193 m_jit.convertInt32ToDouble(payloadGPR, fpr);
195 if (info.registerFormat() != DataFormatJSInteger)
196 hasUnboxedDouble.link(&m_jit);
198 m_gprs.release(tagGPR);
199 m_gprs.release(payloadGPR);
200 m_gprs.unlock(tagGPR);
201 m_gprs.unlock(payloadGPR);
202 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
203 info.fillDouble(fpr);
208 case DataFormatInteger: {
209 FPRReg fpr = fprAllocate();
210 GPRReg gpr = info.gpr();
212 m_jit.convertInt32ToDouble(gpr, fpr);
217 case DataFormatJSDouble:
218 case DataFormatDouble: {
219 FPRReg fpr = info.fpr();
225 ASSERT_NOT_REACHED();
226 return InvalidFPRReg;
229 bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& payloadGPR, FPRReg& fpr)
231 // FIXME: For double we could fill with a FPR.
234 Node& node = at(nodeIndex);
235 VirtualRegister virtualRegister = node.virtualRegister();
236 GenerationInfo& info = m_generationInfo[virtualRegister];
238 switch (info.registerFormat()) {
239 case DataFormatNone: {
241 if (node.hasConstant()) {
243 payloadGPR = allocate();
244 m_jit.move(Imm32(valueOfJSConstant(nodeIndex).tag()), tagGPR);
245 m_jit.move(Imm32(valueOfJSConstant(nodeIndex).payload()), payloadGPR);
246 m_gprs.retain(tagGPR, virtualRegister, SpillOrderConstant);
247 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderConstant);
248 info.fillJSValue(tagGPR, payloadGPR, isInt32Constant(nodeIndex) ? DataFormatJSInteger : DataFormatJS);
250 DataFormat spillFormat = info.spillFormat();
251 ASSERT(spillFormat & DataFormatJS);
253 payloadGPR = allocate();
254 m_jit.load32(JITCompiler::tagFor(virtualRegister), tagGPR);
255 m_jit.load32(JITCompiler::payloadFor(virtualRegister), payloadGPR);
256 m_gprs.retain(tagGPR, virtualRegister, SpillOrderSpilled);
257 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderSpilled);
258 info.fillJSValue(tagGPR, payloadGPR, spillFormat == DataFormatJSDouble ? DataFormatJS : spillFormat);
264 case DataFormatInteger:
266 case DataFormatBoolean: {
267 GPRReg gpr = info.gpr();
268 // If the register has already been locked we need to take a copy.
269 if (m_gprs.isLocked(gpr)) {
270 payloadGPR = allocate();
271 m_jit.move(gpr, payloadGPR);
277 uint32_t tag = JSValue::EmptyValueTag;
278 DataFormat fillFormat = DataFormatJS;
279 switch (info.registerFormat()) {
280 case DataFormatInteger:
281 tag = JSValue::Int32Tag;
282 fillFormat = DataFormatJSInteger;
285 tag = JSValue::CellTag;
286 fillFormat = DataFormatJSCell;
288 case DataFormatBoolean:
289 tag = JSValue::BooleanTag;
290 fillFormat = DataFormatJSBoolean;
293 ASSERT_NOT_REACHED();
296 m_jit.move(TrustedImm32(tag), tagGPR);
298 m_gprs.retain(tagGPR, virtualRegister, SpillOrderJS);
299 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderJS);
300 info.fillJSValue(tagGPR, payloadGPR, fillFormat);
304 case DataFormatJSDouble:
305 case DataFormatDouble: {
306 FPRReg oldFPR = info.fpr();
309 payloadGPR = allocate();
310 boxDouble(oldFPR, tagGPR, payloadGPR);
311 m_fprs.unlock(oldFPR);
312 m_fprs.release(oldFPR);
313 m_gprs.retain(tagGPR, virtualRegister, SpillOrderJS);
314 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderJS);
315 info.fillJSValue(tagGPR, payloadGPR, DataFormatJS);
320 case DataFormatJSInteger:
321 case DataFormatJSCell:
322 case DataFormatJSBoolean: {
323 tagGPR = info.tagGPR();
324 payloadGPR = info.payloadGPR();
326 m_gprs.lock(payloadGPR);
330 case DataFormatStorage:
331 // this type currently never occurs
332 ASSERT_NOT_REACHED();
335 ASSERT_NOT_REACHED();
339 void SpeculativeJIT::nonSpeculativeValueToNumber(Node& node)
341 if (isKnownNumeric(node.child1())) {
342 JSValueOperand op1(this, node.child1());
344 if (op1.isDouble()) {
345 FPRTemporary result(this, op1);
346 m_jit.moveDouble(op1.fpr(), result.fpr());
347 doubleResult(result.fpr(), m_compileIndex);
349 GPRTemporary resultTag(this, op1);
350 GPRTemporary resultPayload(this, op1, false);
351 m_jit.move(op1.tagGPR(), resultTag.gpr());
352 m_jit.move(op1.payloadGPR(), resultPayload.gpr());
353 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
358 JSValueOperand op1(this, node.child1());
359 GPRTemporary resultTag(this, op1);
360 GPRTemporary resultPayload(this, op1, false);
362 ASSERT(!isInt32Constant(node.child1()));
363 ASSERT(!isNumberConstant(node.child1()));
365 GPRReg tagGPR = op1.tagGPR();
366 GPRReg payloadGPR = op1.payloadGPR();
367 GPRReg resultTagGPR = resultTag.gpr();
368 GPRReg resultPayloadGPR = resultPayload.gpr();
371 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
372 JITCompiler::Jump nonNumeric = m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag));
374 // First, if we get here we have a double encoded as a JSValue
375 JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
377 // Next handle cells (& other JS immediates)
378 nonNumeric.link(&m_jit);
379 silentSpillAllRegisters(resultTagGPR, resultPayloadGPR);
380 callOperation(dfgConvertJSValueToNumber, FPRInfo::returnValueFPR, tagGPR, payloadGPR);
381 boxDouble(FPRInfo::returnValueFPR, resultTagGPR, resultPayloadGPR);
382 silentFillAllRegisters(resultTagGPR, resultPayloadGPR);
383 JITCompiler::Jump hasCalledToNumber = m_jit.jump();
385 // Finally, handle integers.
386 isInteger.link(&m_jit);
387 hasUnboxedDouble.link(&m_jit);
388 m_jit.move(tagGPR, resultTagGPR);
389 m_jit.move(payloadGPR, resultPayloadGPR);
390 hasCalledToNumber.link(&m_jit);
391 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
394 void SpeculativeJIT::nonSpeculativeValueToInt32(Node& node)
396 ASSERT(!isInt32Constant(node.child1()));
398 if (isKnownInteger(node.child1())) {
399 IntegerOperand op1(this, node.child1());
400 GPRTemporary result(this, op1);
401 m_jit.move(op1.gpr(), result.gpr());
402 integerResult(result.gpr(), m_compileIndex);
406 GenerationInfo& childInfo = m_generationInfo[at(node.child1()).virtualRegister()];
407 if (childInfo.isJSDouble()) {
408 DoubleOperand op1(this, node.child1());
409 GPRTemporary result(this);
410 FPRReg fpr = op1.fpr();
411 GPRReg gpr = result.gpr();
413 JITCompiler::Jump truncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateSuccessful);
415 silentSpillAllRegisters(gpr);
416 callOperation(toInt32, gpr, fpr);
417 silentFillAllRegisters(gpr);
419 truncatedToInteger.link(&m_jit);
420 integerResult(gpr, m_compileIndex, UseChildrenCalledExplicitly);
424 JSValueOperand op1(this, node.child1());
425 GPRTemporary result(this);
426 GPRReg tagGPR = op1.tagGPR();
427 GPRReg payloadGPR = op1.payloadGPR();
428 GPRReg resultGPR = result.gpr();
431 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
433 // First handle non-integers
434 silentSpillAllRegisters(resultGPR);
435 callOperation(dfgConvertJSValueToInt32, GPRInfo::returnValueGPR, tagGPR, payloadGPR);
436 m_jit.move(GPRInfo::returnValueGPR, resultGPR);
437 silentFillAllRegisters(resultGPR);
438 JITCompiler::Jump hasCalledToInt32 = m_jit.jump();
440 // Then handle integers.
441 isInteger.link(&m_jit);
442 m_jit.move(payloadGPR, resultGPR);
443 hasCalledToInt32.link(&m_jit);
444 integerResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
447 void SpeculativeJIT::nonSpeculativeUInt32ToNumber(Node& node)
449 IntegerOperand op1(this, node.child1());
450 FPRTemporary boxer(this);
451 GPRTemporary resultTag(this, op1);
452 GPRTemporary resultPayload(this);
454 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, op1.gpr(), TrustedImm32(0));
456 m_jit.convertInt32ToDouble(op1.gpr(), boxer.fpr());
457 m_jit.move(JITCompiler::TrustedImmPtr(&twoToThe32), resultPayload.gpr()); // reuse resultPayload register here.
458 m_jit.addDouble(JITCompiler::Address(resultPayload.gpr(), 0), boxer.fpr());
460 boxDouble(boxer.fpr(), resultTag.gpr(), resultPayload.gpr());
462 JITCompiler::Jump done = m_jit.jump();
464 positive.link(&m_jit);
466 m_jit.move(TrustedImm32(JSValue::Int32Tag), resultTag.gpr());
467 m_jit.move(op1.gpr(), resultPayload.gpr());
471 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
474 void SpeculativeJIT::nonSpeculativeKnownConstantArithOp(NodeType op, NodeIndex regChild, NodeIndex immChild, bool commute)
476 JSValueOperand regArg(this, regChild);
479 if (regArg.isDouble()) {
480 FPRReg regArgFPR = regArg.fpr();
481 FPRTemporary imm(this);
482 FPRTemporary result(this, regArg);
483 GPRTemporary scratch(this);
484 FPRReg immFPR = imm.fpr();
485 FPRReg resultFPR = result.fpr();
486 GPRReg scratchGPR = scratch.gpr();
490 int32_t imm32 = valueOfInt32Constant(immChild);
491 m_jit.move(TrustedImm32(imm32), scratchGPR);
492 m_jit.convertInt32ToDouble(scratchGPR, immFPR);
497 m_jit.addDouble(regArgFPR, immFPR, resultFPR);
501 m_jit.subDouble(regArgFPR, immFPR, resultFPR);
505 ASSERT_NOT_REACHED();
508 doubleResult(resultFPR, m_compileIndex, UseChildrenCalledExplicitly);
512 GPRReg regArgTagGPR = regArg.tagGPR();
513 GPRReg regArgPayloadGPR = regArg.payloadGPR();
514 GPRTemporary resultTag(this, regArg);
515 GPRTemporary resultPayload(this, regArg, false);
516 GPRReg resultTagGPR = resultTag.gpr();
517 GPRReg resultPayloadGPR = resultPayload.gpr();
518 FPRTemporary tmp1(this);
519 FPRTemporary tmp2(this);
520 FPRReg tmp1FPR = tmp1.fpr();
521 FPRReg tmp2FPR = tmp2.fpr();
525 JITCompiler::Jump notInt;
526 int32_t imm = valueOfInt32Constant(immChild);
528 if (!isKnownNumeric(regChild))
529 notInt = m_jit.branch32(MacroAssembler::NotEqual, regArgTagGPR, TrustedImm32(JSValue::Int32Tag));
531 JITCompiler::Jump overflow;
536 overflow = m_jit.branchAdd32(MacroAssembler::Overflow, regArgPayloadGPR, Imm32(imm), resultPayloadGPR);
540 overflow = m_jit.branchSub32(MacroAssembler::Overflow, regArgPayloadGPR, Imm32(imm), resultPayloadGPR);
544 ASSERT_NOT_REACHED();
547 m_jit.move(TrustedImm32(JSValue::Int32Tag), resultTagGPR);
548 JITCompiler::Jump done = m_jit.jump();
550 overflow.link(&m_jit);
551 // first deal with overflow case
552 m_jit.convertInt32ToDouble(regArgPayloadGPR, tmp2FPR);
553 m_jit.move(TrustedImm32(imm), resultPayloadGPR);
554 m_jit.convertInt32ToDouble(resultPayloadGPR, tmp1FPR);
558 m_jit.addDouble(tmp1FPR, tmp2FPR);
562 m_jit.subDouble(tmp1FPR, tmp2FPR);
566 ASSERT_NOT_REACHED();
569 JITCompiler::Jump doneCaseConvertedToInt;
571 if (op == ValueAdd) {
572 JITCompiler::JumpList failureCases;
573 m_jit.branchConvertDoubleToInt32(tmp2FPR, resultPayloadGPR, failureCases, tmp1FPR);
574 m_jit.move(TrustedImm32(JSValue::Int32Tag), resultTagGPR);
575 doneCaseConvertedToInt = m_jit.jump();
577 failureCases.link(&m_jit);
580 boxDouble(tmp2FPR, resultTagGPR, resultPayloadGPR);
582 if (!isKnownNumeric(regChild)) {
583 ASSERT(notInt.isSet());
584 ASSERT(op == ValueAdd);
586 JITCompiler::Jump doneCaseWasNumber = m_jit.jump();
590 silentSpillAllRegisters(resultTagGPR, resultPayloadGPR);
592 callOperation(operationValueAddNotNumber, resultTagGPR, resultPayloadGPR, MacroAssembler::Imm32(imm), regArgTagGPR, regArgPayloadGPR);
594 callOperation(operationValueAddNotNumber, resultTagGPR, resultPayloadGPR, regArgTagGPR, regArgPayloadGPR, MacroAssembler::Imm32(imm));
595 silentFillAllRegisters(resultTagGPR, resultPayloadGPR);
597 doneCaseWasNumber.link(&m_jit);
601 if (doneCaseConvertedToInt.isSet())
602 doneCaseConvertedToInt.link(&m_jit);
604 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
607 void SpeculativeJIT::nonSpeculativeBasicArithOp(NodeType op, Node &node)
609 JSValueOperand arg1(this, node.child1());
610 JSValueOperand arg2(this, node.child2());
614 if (arg1.isDouble() && arg2.isDouble()) {
615 FPRReg arg1FPR = arg1.fpr();
616 FPRReg arg2FPR = arg2.fpr();
617 FPRTemporary result(this, arg1);
623 m_jit.addDouble(arg1FPR, arg2FPR, result.fpr());
627 m_jit.subDouble(arg1FPR, arg2FPR, result.fpr());
631 m_jit.mulDouble(arg1FPR, arg2FPR, result.fpr());
635 ASSERT_NOT_REACHED();
638 doubleResult(result.fpr(), m_compileIndex, UseChildrenCalledExplicitly);
642 FPRTemporary tmp1(this);
643 FPRTemporary tmp2(this);
644 FPRReg tmp1FPR = tmp1.fpr();
645 FPRReg tmp2FPR = tmp2.fpr();
647 GPRTemporary resultTag(this, arg1.isDouble() ? arg2 : arg1);
648 GPRTemporary resultPayload(this, arg1.isDouble() ? arg2 : arg1, false);
649 GPRReg resultTagGPR = resultTag.gpr();
650 GPRReg resultPayloadGPR = resultPayload.gpr();
652 GPRReg arg1TagGPR = InvalidGPRReg;
653 GPRReg arg1PayloadGPR = InvalidGPRReg;
654 GPRReg arg2TagGPR = InvalidGPRReg;
655 GPRReg arg2PayloadGPR = InvalidGPRReg;
656 GPRTemporary tmpTag(this);
657 GPRTemporary tmpPayload(this);
659 if (arg1.isDouble()) {
660 arg1TagGPR = tmpTag.gpr();
661 arg1PayloadGPR = tmpPayload.gpr();
662 boxDouble(arg1.fpr(), arg1TagGPR, arg1PayloadGPR);
663 arg2TagGPR = arg2.tagGPR();
664 arg2PayloadGPR = arg2.payloadGPR();
665 } else if (arg2.isDouble()) {
666 arg1TagGPR = arg1.tagGPR();
667 arg1PayloadGPR = arg1.payloadGPR();
668 arg2TagGPR = tmpTag.gpr();
669 arg2PayloadGPR = tmpPayload.gpr();
670 boxDouble(arg2.fpr(), arg2TagGPR, arg2PayloadGPR);
672 arg1TagGPR = arg1.tagGPR();
673 arg1PayloadGPR = arg1.payloadGPR();
674 arg2TagGPR = arg2.tagGPR();
675 arg2PayloadGPR = arg2.payloadGPR();
681 JITCompiler::Jump child1NotInt;
682 JITCompiler::Jump child2NotInt;
683 JITCompiler::JumpList overflow;
685 if (!isKnownInteger(node.child1()))
686 child1NotInt = m_jit.branch32(MacroAssembler::NotEqual, arg1TagGPR, TrustedImm32(JSValue::Int32Tag));
688 if (!isKnownInteger(node.child2()))
689 child2NotInt = m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, TrustedImm32(JSValue::Int32Tag));
694 overflow.append(m_jit.branchAdd32(MacroAssembler::Overflow, arg1PayloadGPR, arg2PayloadGPR, resultPayloadGPR));
699 overflow.append(m_jit.branchSub32(MacroAssembler::Overflow, arg1PayloadGPR, arg2PayloadGPR, resultPayloadGPR));
704 overflow.append(m_jit.branchMul32(MacroAssembler::Overflow, arg1PayloadGPR, arg2PayloadGPR, resultPayloadGPR));
705 overflow.append(m_jit.branchTest32(MacroAssembler::Zero, resultPayloadGPR));
710 ASSERT_NOT_REACHED();
713 m_jit.move(TrustedImm32(JSValue::Int32Tag), resultTagGPR);
715 JITCompiler::Jump done = m_jit.jump();
717 JITCompiler::JumpList haveFPRArguments;
719 overflow.link(&m_jit);
721 // both arguments are integers
722 m_jit.convertInt32ToDouble(arg1PayloadGPR, tmp1FPR);
723 m_jit.convertInt32ToDouble(arg2PayloadGPR, tmp2FPR);
725 haveFPRArguments.append(m_jit.jump());
727 JITCompiler::JumpList notNumbers;
729 JITCompiler::Jump child2NotInt2;
731 if (!isKnownInteger(node.child1())) {
732 FPRTemporary scratch(this);
733 child1NotInt.link(&m_jit);
735 if (!isKnownNumeric(node.child1())) {
736 ASSERT(op == ValueAdd);
737 notNumbers.append(m_jit.branch32(MacroAssembler::AboveOrEqual, arg1TagGPR, TrustedImm32(JSValue::LowestTag)));
741 m_jit.moveDouble(arg1.fpr(), tmp1FPR);
743 unboxDouble(arg1TagGPR, arg1PayloadGPR, tmp1FPR, scratch.fpr());
745 // child1 is converted to a double; child2 may either be an int or
748 if (!isKnownInteger(node.child2())) {
749 if (isKnownNumeric(node.child2()))
750 child2NotInt2 = m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, TrustedImm32(JSValue::Int32Tag));
752 ASSERT(op == ValueAdd);
753 JITCompiler::Jump child2IsInt = m_jit.branch32(MacroAssembler::Equal, arg2TagGPR, TrustedImm32(JSValue::Int32Tag));
754 notNumbers.append(m_jit.branch32(MacroAssembler::AboveOrEqual, arg2TagGPR, TrustedImm32(JSValue::LowestTag)));
755 child2NotInt2 = m_jit.jump();
756 child2IsInt.link(&m_jit);
760 // child 2 is definitely an integer
761 m_jit.convertInt32ToDouble(arg2PayloadGPR, tmp2FPR);
763 haveFPRArguments.append(m_jit.jump());
766 if (!isKnownInteger(node.child2())) {
767 FPRTemporary scratch(this);
768 child2NotInt.link(&m_jit);
770 if (!isKnownNumeric(node.child2())) {
771 ASSERT(op == ValueAdd);
772 notNumbers.append(m_jit.branch32(MacroAssembler::AboveOrEqual, arg2TagGPR, TrustedImm32(JSValue::LowestTag)));
775 // child1 is definitely an integer, and child 2 is definitely not
776 m_jit.convertInt32ToDouble(arg1PayloadGPR, tmp1FPR);
778 if (child2NotInt2.isSet())
779 child2NotInt2.link(&m_jit);
782 m_jit.moveDouble(arg2.fpr(), tmp2FPR);
784 unboxDouble(arg2TagGPR, arg2PayloadGPR, tmp2FPR, scratch.fpr());
787 haveFPRArguments.link(&m_jit);
792 m_jit.addDouble(tmp2FPR, tmp1FPR);
796 m_jit.subDouble(tmp2FPR, tmp1FPR);
800 m_jit.mulDouble(tmp2FPR, tmp1FPR);
804 ASSERT_NOT_REACHED();
807 JITCompiler::Jump doneCaseConvertedToInt;
809 if (op == ValueAdd) {
810 JITCompiler::JumpList failureCases;
811 m_jit.branchConvertDoubleToInt32(tmp1FPR, resultPayloadGPR, failureCases, tmp2FPR);
812 m_jit.move(TrustedImm32(JSValue::Int32Tag), resultTagGPR);
814 doneCaseConvertedToInt = m_jit.jump();
816 failureCases.link(&m_jit);
819 boxDouble(tmp1FPR, resultTagGPR, resultPayloadGPR);
821 if (!notNumbers.empty()) {
822 ASSERT(op == ValueAdd);
824 JITCompiler::Jump doneCaseWasNumber = m_jit.jump();
826 notNumbers.link(&m_jit);
828 silentSpillAllRegisters(resultTagGPR, resultPayloadGPR);
829 callOperation(operationValueAddNotNumber, resultTagGPR, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
830 silentFillAllRegisters(resultTagGPR, resultPayloadGPR);
832 doneCaseWasNumber.link(&m_jit);
836 if (doneCaseConvertedToInt.isSet())
837 doneCaseConvertedToInt.link(&m_jit);
839 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
842 JITCompiler::Call SpeculativeJIT::cachedGetById(GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget)
844 m_jit.beginUninterruptedSequence();
845 JITCompiler::DataLabelPtr structureToCompare;
846 JITCompiler::Jump structureCheck = m_jit.branchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(basePayloadGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
847 m_jit.endUninterruptedSequence();
849 m_jit.loadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfPropertyStorage()), resultPayloadGPR);
850 JITCompiler::DataLabelCompact tagLoadWithPatch = m_jit.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
851 JITCompiler::DataLabelCompact payloadLoadWithPatch = m_jit.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
853 JITCompiler::Jump done = m_jit.jump();
855 structureCheck.link(&m_jit);
857 if (slowPathTarget.isSet())
858 slowPathTarget.link(&m_jit);
860 JITCompiler::Label slowCase = m_jit.label();
862 silentSpillAllRegisters(resultTagGPR, resultPayloadGPR);
863 JITCompiler::Call functionCall;
864 if (baseTagGPROrNone == InvalidGPRReg)
865 functionCall = callOperation(operationGetByIdOptimize, resultTagGPR, resultPayloadGPR, JSValue::CellTag, basePayloadGPR, identifier(identifierNumber));
867 functionCall = callOperation(operationGetByIdOptimize, resultTagGPR, resultPayloadGPR, baseTagGPROrNone, basePayloadGPR, identifier(identifierNumber));
868 silentFillAllRegisters(resultTagGPR, resultPayloadGPR);
872 JITCompiler::Label doneLabel = m_jit.label();
874 m_jit.addPropertyAccess(PropertyAccessRecord(structureToCompare, functionCall, structureCheck, tagLoadWithPatch, payloadLoadWithPatch, slowCase, doneLabel, safeCast<int8_t>(basePayloadGPR), safeCast<int8_t>(resultTagGPR), safeCast<int8_t>(resultPayloadGPR), safeCast<int8_t>(scratchGPR)));
879 void SpeculativeJIT::cachedPutById(GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget)
881 m_jit.beginUninterruptedSequence();
882 JITCompiler::DataLabelPtr structureToCompare;
883 JITCompiler::Jump structureCheck = m_jit.branchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(basePayloadGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
884 m_jit.endUninterruptedSequence();
886 writeBarrier(basePayloadGPR, valueTagGPR, valueIndex, WriteBarrierForPropertyAccess, scratchGPR);
888 m_jit.loadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
889 JITCompiler::DataLabel32 tagStoreWithPatch = m_jit.store32WithAddressOffsetPatch(valueTagGPR, JITCompiler::Address(scratchGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
890 JITCompiler::DataLabel32 payloadStoreWithPatch = m_jit.store32WithAddressOffsetPatch(valuePayloadGPR, JITCompiler::Address(scratchGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
892 JITCompiler::Jump done = m_jit.jump();
894 structureCheck.link(&m_jit);
896 if (slowPathTarget.isSet())
897 slowPathTarget.link(&m_jit);
899 JITCompiler::Label slowCase = m_jit.label();
901 silentSpillAllRegisters(InvalidGPRReg);
902 V_DFGOperation_EJCI optimizedCall;
903 if (m_jit.strictModeFor(at(m_compileIndex).codeOrigin)) {
904 if (putKind == Direct)
905 optimizedCall = operationPutByIdDirectStrictOptimize;
907 optimizedCall = operationPutByIdStrictOptimize;
909 if (putKind == Direct)
910 optimizedCall = operationPutByIdDirectNonStrictOptimize;
912 optimizedCall = operationPutByIdNonStrictOptimize;
914 JITCompiler::Call functionCall = callOperation(optimizedCall, valueTagGPR, valuePayloadGPR, basePayloadGPR, identifier(identifierNumber));
915 silentFillAllRegisters(InvalidGPRReg);
918 JITCompiler::Label doneLabel = m_jit.label();
920 m_jit.addPropertyAccess(PropertyAccessRecord(structureToCompare, functionCall, structureCheck, JITCompiler::DataLabelCompact(tagStoreWithPatch.label()), JITCompiler::DataLabelCompact(payloadStoreWithPatch.label()), slowCase, doneLabel, safeCast<int8_t>(basePayloadGPR), safeCast<int8_t>(valueTagGPR), safeCast<int8_t>(valuePayloadGPR), safeCast<int8_t>(scratchGPR)));
923 void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(NodeIndex operand, bool invert)
925 JSValueOperand arg(this, operand);
926 GPRReg argTagGPR = arg.tagGPR();
927 GPRReg argPayloadGPR = arg.payloadGPR();
929 GPRTemporary resultPayload(this, arg, false);
930 GPRReg resultPayloadGPR = resultPayload.gpr();
932 JITCompiler::Jump notCell;
933 if (!isKnownCell(operand))
934 notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
936 m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureOffset()), resultPayloadGPR);
937 m_jit.test8(invert ? JITCompiler::Zero : JITCompiler::NonZero, JITCompiler::Address(resultPayloadGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined), resultPayloadGPR);
939 if (!isKnownCell(operand)) {
940 JITCompiler::Jump done = m_jit.jump();
942 notCell.link(&m_jit);
943 // null or undefined?
944 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
945 m_jit.move(argTagGPR, resultPayloadGPR);
946 m_jit.or32(TrustedImm32(1), resultPayloadGPR);
947 m_jit.compare32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultPayloadGPR, TrustedImm32(JSValue::NullTag), resultPayloadGPR);
952 booleanResult(resultPayloadGPR, m_compileIndex);
955 void SpeculativeJIT::nonSpeculativePeepholeBranchNull(NodeIndex operand, NodeIndex branchNodeIndex, bool invert)
957 Node& branchNode = at(branchNodeIndex);
958 BlockIndex taken = branchNode.takenBlockIndex();
959 BlockIndex notTaken = branchNode.notTakenBlockIndex();
961 if (taken == (m_block + 1)) {
963 BlockIndex tmp = taken;
968 JSValueOperand arg(this, operand);
969 GPRReg argTagGPR = arg.tagGPR();
970 GPRReg argPayloadGPR = arg.payloadGPR();
972 GPRTemporary result(this, arg);
973 GPRReg resultGPR = result.gpr();
975 JITCompiler::Jump notCell;
977 if (!isKnownCell(operand))
978 notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
980 m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureOffset()), resultGPR);
981 addBranch(m_jit.branchTest8(invert ? JITCompiler::Zero : JITCompiler::NonZero, JITCompiler::Address(resultGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined)), taken);
983 if (!isKnownCell(operand)) {
984 addBranch(m_jit.jump(), notTaken);
986 notCell.link(&m_jit);
987 // null or undefined?
988 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
989 m_jit.move(argTagGPR, resultGPR);
990 m_jit.or32(TrustedImm32(1), resultGPR);
991 addBranch(m_jit.branch32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultGPR, JITCompiler::TrustedImm32(JSValue::NullTag)), taken);
994 if (notTaken != (m_block + 1))
995 addBranch(m_jit.jump(), notTaken);
998 bool SpeculativeJIT::nonSpeculativeCompareNull(Node& node, NodeIndex operand, bool invert)
1000 NodeIndex branchNodeIndex = detectPeepHoleBranch();
1001 if (branchNodeIndex != NoNode) {
1002 ASSERT(node.adjustedRefCount() == 1);
1004 nonSpeculativePeepholeBranchNull(operand, branchNodeIndex, invert);
1008 m_compileIndex = branchNodeIndex;
1013 nonSpeculativeNonPeepholeCompareNull(operand, invert);
1018 void SpeculativeJIT::nonSpeculativePeepholeBranch(Node& node, NodeIndex branchNodeIndex, MacroAssembler::RelationalCondition cond, S_DFGOperation_EJJ helperFunction)
1020 Node& branchNode = at(branchNodeIndex);
1021 BlockIndex taken = branchNode.takenBlockIndex();
1022 BlockIndex notTaken = branchNode.notTakenBlockIndex();
1024 JITCompiler::ResultCondition callResultCondition = JITCompiler::NonZero;
1026 // The branch instruction will branch to the taken block.
1027 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
1028 if (taken == (m_block + 1)) {
1029 cond = JITCompiler::invert(cond);
1030 callResultCondition = JITCompiler::Zero;
1031 BlockIndex tmp = taken;
1036 JSValueOperand arg1(this, node.child1());
1037 JSValueOperand arg2(this, node.child2());
1038 GPRReg arg1TagGPR = arg1.tagGPR();
1039 GPRReg arg1PayloadGPR = arg1.payloadGPR();
1040 GPRReg arg2TagGPR = arg2.tagGPR();
1041 GPRReg arg2PayloadGPR = arg2.payloadGPR();
1043 JITCompiler::JumpList slowPath;
1045 if (isKnownNotInteger(node.child1()) || isKnownNotInteger(node.child2())) {
1046 GPRResult result(this);
1047 GPRReg resultGPR = result.gpr();
1053 callOperation(helperFunction, resultGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
1055 addBranch(m_jit.branchTest32(callResultCondition, resultGPR), taken);
1057 GPRTemporary result(this);
1058 GPRReg resultGPR = result.gpr();
1063 if (!isKnownInteger(node.child1()))
1064 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg1TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
1065 if (!isKnownInteger(node.child2()))
1066 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
1068 addBranch(m_jit.branch32(cond, arg1PayloadGPR, arg2PayloadGPR), taken);
1070 if (!isKnownInteger(node.child1()) || !isKnownInteger(node.child2())) {
1071 addBranch(m_jit.jump(), notTaken);
1073 slowPath.link(&m_jit);
1075 silentSpillAllRegisters(resultGPR);
1076 callOperation(helperFunction, resultGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
1077 silentFillAllRegisters(resultGPR);
1079 addBranch(m_jit.branchTest32(callResultCondition, resultGPR), taken);
1083 if (notTaken != (m_block + 1))
1084 addBranch(m_jit.jump(), notTaken);
1087 void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node& node, MacroAssembler::RelationalCondition cond, S_DFGOperation_EJJ helperFunction)
1089 JSValueOperand arg1(this, node.child1());
1090 JSValueOperand arg2(this, node.child2());
1091 GPRReg arg1TagGPR = arg1.tagGPR();
1092 GPRReg arg1PayloadGPR = arg1.payloadGPR();
1093 GPRReg arg2TagGPR = arg2.tagGPR();
1094 GPRReg arg2PayloadGPR = arg2.payloadGPR();
1096 JITCompiler::JumpList slowPath;
1098 if (isKnownNotInteger(node.child1()) || isKnownNotInteger(node.child2())) {
1099 GPRResult result(this);
1100 GPRReg resultPayloadGPR = result.gpr();
1106 callOperation(helperFunction, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
1108 booleanResult(resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
1110 GPRTemporary resultPayload(this, arg1, false);
1111 GPRReg resultPayloadGPR = resultPayload.gpr();
1116 if (!isKnownInteger(node.child1()))
1117 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg1TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
1118 if (!isKnownInteger(node.child2()))
1119 slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, arg2TagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag)));
1121 m_jit.compare32(cond, arg1PayloadGPR, arg2PayloadGPR, resultPayloadGPR);
1123 if (!isKnownInteger(node.child1()) || !isKnownInteger(node.child2())) {
1124 JITCompiler::Jump haveResult = m_jit.jump();
1126 slowPath.link(&m_jit);
1128 silentSpillAllRegisters(resultPayloadGPR);
1129 callOperation(helperFunction, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
1130 silentFillAllRegisters(resultPayloadGPR);
1132 m_jit.andPtr(TrustedImm32(1), resultPayloadGPR);
1134 haveResult.link(&m_jit);
1137 booleanResult(resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
1141 void SpeculativeJIT::nonSpeculativePeepholeStrictEq(Node& node, NodeIndex branchNodeIndex, bool invert)
1143 Node& branchNode = at(branchNodeIndex);
1144 BlockIndex taken = branchNode.takenBlockIndex();
1145 BlockIndex notTaken = branchNode.notTakenBlockIndex();
1147 // The branch instruction will branch to the taken block.
1148 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
1149 if (taken == (m_block + 1)) {
1151 BlockIndex tmp = taken;
1156 JSValueOperand arg1(this, node.child1());
1157 JSValueOperand arg2(this, node.child2());
1158 GPRReg arg1TagGPR = arg1.tagGPR();
1159 GPRReg arg1PayloadGPR = arg1.payloadGPR();
1160 GPRReg arg2TagGPR = arg2.tagGPR();
1161 GPRReg arg2PayloadGPR = arg2.payloadGPR();
1163 GPRTemporary resultPayload(this, arg1, false);
1164 GPRReg resultPayloadGPR = resultPayload.gpr();
1169 if (isKnownCell(node.child1()) && isKnownCell(node.child2())) {
1170 // see if we get lucky: if the arguments are cells and they reference the same
1171 // cell, then they must be strictly equal.
1172 addBranch(m_jit.branchPtr(JITCompiler::Equal, arg1PayloadGPR, arg2PayloadGPR), invert ? notTaken : taken);
1174 silentSpillAllRegisters(resultPayloadGPR);
1175 callOperation(operationCompareStrictEqCell, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
1176 silentFillAllRegisters(resultPayloadGPR);
1178 addBranch(m_jit.branchTest32(invert ? JITCompiler::NonZero : JITCompiler::Zero, resultPayloadGPR), taken);
1180 // FIXME: Add fast paths for twoCells, number etc.
1182 silentSpillAllRegisters(resultPayloadGPR);
1183 callOperation(operationCompareStrictEq, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
1184 silentFillAllRegisters(resultPayloadGPR);
1186 addBranch(m_jit.branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultPayloadGPR), taken);
1189 if (notTaken != (m_block + 1))
1190 addBranch(m_jit.jump(), notTaken);
1193 void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node& node, bool invert)
1195 JSValueOperand arg1(this, node.child1());
1196 JSValueOperand arg2(this, node.child2());
1197 GPRReg arg1TagGPR = arg1.tagGPR();
1198 GPRReg arg1PayloadGPR = arg1.payloadGPR();
1199 GPRReg arg2TagGPR = arg2.tagGPR();
1200 GPRReg arg2PayloadGPR = arg2.payloadGPR();
1202 GPRTemporary resultPayload(this, arg1, false);
1203 GPRReg resultPayloadGPR = resultPayload.gpr();
1208 if (isKnownCell(node.child1()) && isKnownCell(node.child2())) {
1209 // see if we get lucky: if the arguments are cells and they reference the same
1210 // cell, then they must be strictly equal.
1211 JITCompiler::Jump notEqualCase = m_jit.branchPtr(JITCompiler::NotEqual, arg1PayloadGPR, arg2PayloadGPR);
1213 m_jit.move(JITCompiler::TrustedImm32(!invert), resultPayloadGPR);
1214 JITCompiler::Jump done = m_jit.jump();
1216 notEqualCase.link(&m_jit);
1218 silentSpillAllRegisters(resultPayloadGPR);
1219 callOperation(operationCompareStrictEqCell, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
1220 silentFillAllRegisters(resultPayloadGPR);
1222 m_jit.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR);
1226 // FIXME: Add fast paths.
1228 silentSpillAllRegisters(resultPayloadGPR);
1229 callOperation(operationCompareStrictEq, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR);
1230 silentFillAllRegisters(resultPayloadGPR);
1232 m_jit.andPtr(JITCompiler::TrustedImm32(1), resultPayloadGPR);
1235 booleanResult(resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
1238 void SpeculativeJIT::emitCall(Node& node)
1240 P_DFGOperation_E slowCallFunction;
1242 if (node.op == Call)
1243 slowCallFunction = operationLinkCall;
1245 ASSERT(node.op == Construct);
1246 slowCallFunction = operationLinkConstruct;
1249 // For constructors, the this argument is not passed but we have to make space
1251 int dummyThisArgument = node.op == Call ? 0 : 1;
1253 CallLinkInfo::CallType callType = node.op == Call ? CallLinkInfo::Call : CallLinkInfo::Construct;
1255 NodeIndex calleeNodeIndex = m_jit.graph().m_varArgChildren[node.firstChild()];
1256 JSValueOperand callee(this, calleeNodeIndex);
1257 GPRReg calleeTagGPR = callee.tagGPR();
1258 GPRReg calleePayloadGPR = callee.payloadGPR();
1259 use(calleeNodeIndex);
1261 // the call instruction's first child is either the function (normal call) or the
1262 // receiver (method call). subsequent children are the arguments.
1263 int numArgs = node.numChildren() - 1;
1265 // For constructors, the this argument is not passed but we have to make space
1267 int numPassedArgs = numArgs + dummyThisArgument;
1269 // amount of stuff (in units of sizeof(Register)) that we need to place at the
1270 // top of the JS stack.
1271 int callDataSize = 0;
1273 // first there are the arguments
1274 callDataSize += numPassedArgs;
1276 // and then there is the call frame header
1277 callDataSize += RegisterFile::CallFrameHeaderSize;
1279 m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), payloadOfCallData(RegisterFile::ArgumentCount));
1280 m_jit.store32(MacroAssembler::TrustedImm32(JSValue::Int32Tag), tagOfCallData(RegisterFile::ArgumentCount));
1281 m_jit.storePtr(GPRInfo::callFrameRegister, payloadOfCallData(RegisterFile::CallerFrame));
1282 m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), tagOfCallData(RegisterFile::CallerFrame));
1284 for (int argIdx = 0; argIdx < numArgs; argIdx++) {
1285 NodeIndex argNodeIndex = m_jit.graph().m_varArgChildren[node.firstChild() + 1 + argIdx];
1286 JSValueOperand arg(this, argNodeIndex);
1287 GPRReg argTagGPR = arg.tagGPR();
1288 GPRReg argPayloadGPR = arg.payloadGPR();
1291 m_jit.store32(argTagGPR, tagOfCallData(-callDataSize + argIdx + dummyThisArgument));
1292 m_jit.store32(argPayloadGPR, payloadOfCallData(-callDataSize + argIdx + dummyThisArgument));
1295 m_jit.store32(calleeTagGPR, tagOfCallData(RegisterFile::Callee));
1296 m_jit.store32(calleePayloadGPR, payloadOfCallData(RegisterFile::Callee));
1300 GPRResult resultPayload(this);
1301 GPRResult2 resultTag(this);
1302 GPRReg resultPayloadGPR = resultPayload.gpr();
1303 GPRReg resultTagGPR = resultTag.gpr();
1305 JITCompiler::DataLabelPtr targetToCheck;
1306 JITCompiler::Jump slowPath;
1308 slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck);
1309 m_jit.loadPtr(MacroAssembler::Address(calleePayloadGPR, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), resultPayloadGPR);
1310 m_jit.storePtr(resultPayloadGPR, payloadOfCallData(RegisterFile::ScopeChain));
1311 m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), tagOfCallData(RegisterFile::ScopeChain));
1313 m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
1315 JITCompiler::Call fastCall = m_jit.nearCall();
1316 m_jit.notifyCall(fastCall, at(m_compileIndex).codeOrigin);
1318 JITCompiler::Jump done = m_jit.jump();
1320 slowPath.link(&m_jit);
1322 m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
1323 m_jit.poke(GPRInfo::argumentGPR0);
1324 JITCompiler::Call slowCall = m_jit.addFastExceptionCheck(m_jit.appendCall(slowCallFunction), at(m_compileIndex).codeOrigin);
1325 m_jit.addPtr(Imm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
1326 m_jit.notifyCall(m_jit.call(GPRInfo::returnValueGPR), at(m_compileIndex).codeOrigin);
1330 setupResults(resultPayloadGPR, resultTagGPR);
1332 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, DataFormatJS, UseChildrenCalledExplicitly);
1334 m_jit.addJSCall(fastCall, slowCall, targetToCheck, callType, at(m_compileIndex).codeOrigin);
1337 template<bool strict>
1338 GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat)
1340 #if DFG_ENABLE(DEBUG_VERBOSE)
1341 fprintf(stderr, "SpecInt@%d ", nodeIndex);
1343 Node& node = at(nodeIndex);
1344 VirtualRegister virtualRegister = node.virtualRegister();
1345 GenerationInfo& info = m_generationInfo[virtualRegister];
1347 switch (info.registerFormat()) {
1348 case DataFormatNone: {
1349 GPRReg gpr = allocate();
1351 if (node.hasConstant()) {
1352 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1353 if (isInt32Constant(nodeIndex)) {
1354 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
1355 info.fillInteger(gpr);
1356 returnFormat = DataFormatInteger;
1359 terminateSpeculativeExecution(JSValueRegs(), NoNode);
1360 returnFormat = DataFormatInteger;
1364 DataFormat spillFormat = info.spillFormat();
1365 ASSERT(spillFormat & DataFormatJS);
1367 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1369 // If we know this was spilled as an integer we can fill without checking.
1370 if (spillFormat != DataFormatJSInteger)
1371 speculationCheck(JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
1373 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
1374 info.fillInteger(gpr);
1375 returnFormat = DataFormatInteger;
1379 case DataFormatJSInteger:
1380 case DataFormatJS: {
1381 // Check the value is an integer.
1382 GPRReg tagGPR = info.tagGPR();
1383 GPRReg payloadGPR = info.payloadGPR();
1384 m_gprs.lock(tagGPR);
1385 m_gprs.lock(payloadGPR);
1386 if (info.registerFormat() != DataFormatJSInteger)
1387 speculationCheck(JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::Int32Tag)));
1388 m_gprs.unlock(tagGPR);
1389 m_gprs.release(tagGPR);
1390 m_gprs.release(payloadGPR);
1391 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderInteger);
1392 info.fillInteger(payloadGPR);
1393 // If !strict we're done, return.
1394 returnFormat = DataFormatInteger;
1398 case DataFormatInteger: {
1399 GPRReg gpr = info.gpr();
1401 returnFormat = DataFormatInteger;
1405 case DataFormatDouble:
1406 case DataFormatCell:
1407 case DataFormatBoolean:
1408 case DataFormatJSDouble:
1409 case DataFormatJSCell:
1410 case DataFormatJSBoolean: {
1411 terminateSpeculativeExecution(JSValueRegs(), NoNode);
1412 returnFormat = DataFormatInteger;
1416 case DataFormatStorage:
1417 ASSERT_NOT_REACHED();
1420 ASSERT_NOT_REACHED();
1421 return InvalidGPRReg;
1424 GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat)
1426 return fillSpeculateIntInternal<false>(nodeIndex, returnFormat);
1429 GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex)
1431 DataFormat mustBeDataFormatInteger;
1432 GPRReg result = fillSpeculateIntInternal<true>(nodeIndex, mustBeDataFormatInteger);
1433 ASSERT(mustBeDataFormatInteger == DataFormatInteger);
1437 FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
1439 #if DFG_ENABLE(DEBUG_VERBOSE)
1440 fprintf(stderr, "SpecDouble@%d ", nodeIndex);
1442 Node& node = at(nodeIndex);
1443 VirtualRegister virtualRegister = node.virtualRegister();
1444 GenerationInfo& info = m_generationInfo[virtualRegister];
1446 if (info.registerFormat() == DataFormatNone) {
1448 if (node.hasConstant()) {
1449 if (isInt32Constant(nodeIndex)) {
1450 GPRReg gpr = allocate();
1451 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
1452 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1453 info.fillInteger(gpr);
1455 } else if (isNumberConstant(nodeIndex)) {
1456 FPRReg fpr = fprAllocate();
1457 m_jit.loadDouble(addressOfDoubleConstant(nodeIndex), fpr);
1458 m_fprs.retain(fpr, virtualRegister, SpillOrderConstant);
1459 info.fillDouble(fpr);
1462 terminateSpeculativeExecution(JSValueRegs(), NoNode);
1463 return fprAllocate();
1466 DataFormat spillFormat = info.spillFormat();
1467 ASSERT(spillFormat & DataFormatJS);
1468 if (spillFormat == DataFormatJSDouble) {
1469 FPRReg fpr = fprAllocate();
1470 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
1471 m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
1472 info.fillDouble(fpr);
1476 FPRReg fpr = fprAllocate();
1477 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag));
1478 speculationCheck(JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::LowestTag)));
1479 m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
1480 JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
1482 isInteger.link(&m_jit);
1483 m_jit.convertInt32ToDouble(JITCompiler::payloadFor(virtualRegister), fpr);
1485 hasUnboxedDouble.link(&m_jit);
1486 m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled);
1487 info.fillDouble(fpr);
1492 switch (info.registerFormat()) {
1493 case DataFormatNone:
1494 case DataFormatBoolean:
1495 case DataFormatStorage:
1496 // Should have filled, above.
1497 ASSERT_NOT_REACHED();
1499 case DataFormatCell:
1500 terminateSpeculativeExecution(JSValueRegs(), NoNode);
1501 return fprAllocate();
1503 case DataFormatJSCell:
1505 case DataFormatJSInteger:
1506 case DataFormatJSBoolean: {
1507 GPRReg tagGPR = info.tagGPR();
1508 GPRReg payloadGPR = info.payloadGPR();
1509 FPRReg fpr = fprAllocate();
1511 m_gprs.lock(tagGPR);
1512 m_gprs.lock(payloadGPR);
1514 JITCompiler::Jump hasUnboxedDouble;
1516 if (info.registerFormat() != DataFormatJSInteger) {
1517 FPRTemporary scratch(this);
1518 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
1519 speculationCheck(JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag)));
1520 unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr());
1521 hasUnboxedDouble = m_jit.jump();
1522 isInteger.link(&m_jit);
1525 m_jit.convertInt32ToDouble(payloadGPR, fpr);
1527 if (info.registerFormat() != DataFormatJSInteger)
1528 hasUnboxedDouble.link(&m_jit);
1530 m_gprs.release(tagGPR);
1531 m_gprs.release(payloadGPR);
1532 m_gprs.unlock(tagGPR);
1533 m_gprs.unlock(payloadGPR);
1534 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
1535 info.fillDouble(fpr);
1540 case DataFormatInteger: {
1541 FPRReg fpr = fprAllocate();
1542 GPRReg gpr = info.gpr();
1544 m_jit.convertInt32ToDouble(gpr, fpr);
1549 case DataFormatJSDouble:
1550 case DataFormatDouble: {
1551 FPRReg fpr = info.fpr();
1557 ASSERT_NOT_REACHED();
1558 return InvalidFPRReg;
1561 GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
1563 #if DFG_ENABLE(DEBUG_VERBOSE)
1564 fprintf(stderr, "SpecCell@%d ", nodeIndex);
1566 Node& node = at(nodeIndex);
1567 VirtualRegister virtualRegister = node.virtualRegister();
1568 GenerationInfo& info = m_generationInfo[virtualRegister];
1570 switch (info.registerFormat()) {
1571 case DataFormatNone: {
1573 GPRReg gpr = allocate();
1574 if (node.hasConstant()) {
1575 JSValue jsValue = valueOfJSConstant(nodeIndex);
1576 if (jsValue.isCell()) {
1577 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1578 m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr);
1582 terminateSpeculativeExecution(JSValueRegs(), NoNode);
1585 ASSERT(info.spillFormat() & DataFormatJS);
1586 if (info.spillFormat() != DataFormatJSCell)
1587 speculationCheck(JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag)));
1588 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
1589 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1594 case DataFormatCell: {
1595 GPRReg gpr = info.gpr();
1600 case DataFormatJSCell:
1601 case DataFormatJS: {
1602 GPRReg tagGPR = info.tagGPR();
1603 GPRReg payloadGPR = info.payloadGPR();
1604 m_gprs.lock(tagGPR);
1605 m_gprs.lock(payloadGPR);
1606 if (info.spillFormat() != DataFormatJSCell)
1607 speculationCheck(JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::CellTag)));
1608 m_gprs.unlock(tagGPR);
1609 m_gprs.release(tagGPR);
1610 m_gprs.release(payloadGPR);
1611 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderCell);
1612 info.fillCell(payloadGPR);
1616 case DataFormatJSInteger:
1617 case DataFormatInteger:
1618 case DataFormatJSDouble:
1619 case DataFormatDouble:
1620 case DataFormatJSBoolean:
1621 case DataFormatBoolean: {
1622 terminateSpeculativeExecution(JSValueRegs(), NoNode);
1626 case DataFormatStorage:
1627 ASSERT_NOT_REACHED();
1630 ASSERT_NOT_REACHED();
1631 return InvalidGPRReg;
1634 GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
1636 #if DFG_ENABLE(DEBUG_VERBOSE)
1637 fprintf(stderr, "SpecBool@%d ", nodeIndex);
1639 Node& node = at(nodeIndex);
1640 VirtualRegister virtualRegister = node.virtualRegister();
1641 GenerationInfo& info = m_generationInfo[virtualRegister];
1643 switch (info.registerFormat()) {
1644 case DataFormatNone: {
1645 GPRReg gpr = allocate();
1647 if (node.hasConstant()) {
1648 JSValue jsValue = valueOfJSConstant(nodeIndex);
1649 if (jsValue.isBoolean()) {
1650 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
1651 m_jit.move(MacroAssembler::TrustedImm32(jsValue.asBoolean()), gpr);
1652 info.fillBoolean(gpr);
1655 terminateSpeculativeExecution(JSValueRegs(), NoNode);
1658 ASSERT(info.spillFormat() & DataFormatJS);
1659 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
1661 if (info.spillFormat() != DataFormatJSBoolean)
1662 speculationCheck(JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
1664 m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
1665 info.fillBoolean(gpr);
1669 case DataFormatBoolean: {
1670 GPRReg gpr = info.gpr();
1675 case DataFormatJSBoolean:
1676 case DataFormatJS: {
1677 GPRReg tagGPR = info.tagGPR();
1678 GPRReg payloadGPR = info.payloadGPR();
1679 m_gprs.lock(tagGPR);
1680 m_gprs.lock(payloadGPR);
1681 if (info.registerFormat() != DataFormatJSBoolean)
1682 speculationCheck(JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::BooleanTag)));
1684 m_gprs.unlock(tagGPR);
1685 m_gprs.release(tagGPR);
1686 m_gprs.release(payloadGPR);
1687 m_gprs.retain(payloadGPR, virtualRegister, SpillOrderBoolean);
1688 info.fillBoolean(payloadGPR);
1692 case DataFormatJSInteger:
1693 case DataFormatInteger:
1694 case DataFormatJSDouble:
1695 case DataFormatDouble:
1696 case DataFormatJSCell:
1697 case DataFormatCell: {
1698 terminateSpeculativeExecution(JSValueRegs(), NoNode);
1702 case DataFormatStorage:
1703 ASSERT_NOT_REACHED();
1706 ASSERT_NOT_REACHED();
1707 return InvalidGPRReg;
1710 JITCompiler::Jump SpeculativeJIT::convertToDouble(JSValueOperand& op, FPRReg result)
1712 FPRTemporary scratch(this);
1714 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, op.tagGPR(), TrustedImm32(JSValue::Int32Tag));
1715 JITCompiler::Jump notNumber = m_jit.branch32(MacroAssembler::AboveOrEqual, op.payloadGPR(), TrustedImm32(JSValue::LowestTag));
1717 unboxDouble(op.tagGPR(), op.payloadGPR(), result, scratch.fpr());
1718 JITCompiler::Jump done = m_jit.jump();
1720 isInteger.link(&m_jit);
1721 m_jit.convertInt32ToDouble(op.payloadGPR(), result);
1728 void SpeculativeJIT::compileObjectEquality(Node& node, void* vptr, PredictionChecker predictionCheck)
1730 SpeculateCellOperand op1(this, node.child1());
1731 SpeculateCellOperand op2(this, node.child2());
1732 GPRTemporary resultPayload(this, op2);
1734 GPRReg op1GPR = op1.gpr();
1735 GPRReg op2GPR = op2.gpr();
1736 GPRReg resultPayloadGPR = resultPayload.gpr();
1738 if (!predictionCheck(m_state.forNode(node.child1()).m_type))
1739 speculationCheck(JSValueSource::unboxedCell(op1GPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR), MacroAssembler::TrustedImmPtr(vptr)));
1740 if (!predictionCheck(m_state.forNode(node.child2()).m_type))
1741 speculationCheck(JSValueSource::unboxedCell(op2GPR), node.child2(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR), MacroAssembler::TrustedImmPtr(vptr)));
1743 MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR);
1744 m_jit.move(Imm32(1), resultPayloadGPR);
1745 MacroAssembler::Jump done = m_jit.jump();
1746 falseCase.link(&m_jit);
1747 m_jit.move(Imm32(0), resultPayloadGPR);
1750 booleanResult(resultPayloadGPR, m_compileIndex);
1753 // Returns true if the compare is fused with a subsequent branch.
1754 bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_DFGOperation_EJJ operation)
1756 if (compilePeepHoleBranch(node, condition, doubleCondition, operation))
1759 if (Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2())))
1760 compileObjectEquality(node, m_jit.globalData()->jsFinalObjectVPtr, isFinalObjectPrediction);
1761 else if (Node::shouldSpeculateArray(at(node.child1()), at(node.child2())))
1762 compileObjectEquality(node, m_jit.globalData()->jsArrayVPtr, isArrayPrediction);
1763 else if (!at(node.child1()).shouldSpeculateNumber() && !at(node.child2()).shouldSpeculateNumber())
1764 nonSpeculativeNonPeepholeCompare(node, condition, operation);
1765 else if ((at(node.child1()).shouldSpeculateNumber() || at(node.child2()).shouldSpeculateNumber()) && !Node::shouldSpeculateInteger(at(node.child1()), at(node.child2()))) {
1766 // Normal case, not fused to branch.
1767 SpeculateDoubleOperand op1(this, node.child1());
1768 SpeculateDoubleOperand op2(this, node.child2());
1769 GPRTemporary resultPayload(this);
1771 m_jit.move(Imm32(1), resultPayload.gpr());
1772 MacroAssembler::Jump trueCase = m_jit.branchDouble(doubleCondition, op1.fpr(), op2.fpr());
1773 m_jit.move(Imm32(0), resultPayload.gpr());
1774 trueCase.link(&m_jit);
1776 booleanResult(resultPayload.gpr(), m_compileIndex);
1778 // Normal case, not fused to branch.
1779 SpeculateIntegerOperand op1(this, node.child1());
1780 SpeculateIntegerOperand op2(this, node.child2());
1781 GPRTemporary resultPayload(this);
1783 m_jit.compare32(condition, op1.gpr(), op2.gpr(), resultPayload.gpr());
1785 // If we add a DataFormatBool, we should use it here.
1786 booleanResult(resultPayload.gpr(), m_compileIndex);
1792 void SpeculativeJIT::compileValueAdd(Node& node)
1794 JSValueOperand op1(this, node.child1());
1795 JSValueOperand op2(this, node.child2());
1797 GPRReg op1TagGPR = op1.tagGPR();
1798 GPRReg op1PayloadGPR = op1.payloadGPR();
1799 GPRReg op2TagGPR = op2.tagGPR();
1800 GPRReg op2PayloadGPR = op2.payloadGPR();
1804 GPRResult2 resultTag(this);
1805 GPRResult resultPayload(this);
1806 if (isKnownNotNumber(node.child1()) || isKnownNotNumber(node.child2()))
1807 callOperation(operationValueAddNotNumber, resultTag.gpr(), resultPayload.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR);
1809 callOperation(operationValueAdd, resultTag.gpr(), resultPayload.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR);
1811 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
1814 void SpeculativeJIT::compileObjectOrOtherLogicalNot(NodeIndex nodeIndex, void* vptr, bool needSpeculationCheck)
1816 JSValueOperand value(this, nodeIndex);
1817 GPRTemporary resultPayload(this);
1818 GPRReg valueTagGPR = value.tagGPR();
1819 GPRReg valuePayloadGPR = value.payloadGPR();
1820 GPRReg resultPayloadGPR = resultPayload.gpr();
1822 MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
1823 if (needSpeculationCheck)
1824 speculationCheck(JSValueRegs(valueTagGPR, valuePayloadGPR), nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(valuePayloadGPR), MacroAssembler::TrustedImmPtr(vptr)));
1825 m_jit.move(TrustedImm32(0), resultPayloadGPR);
1826 MacroAssembler::Jump done = m_jit.jump();
1828 notCell.link(&m_jit);
1830 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
1831 if (needSpeculationCheck) {
1832 m_jit.move(valueTagGPR, resultPayloadGPR);
1833 m_jit.or32(TrustedImm32(1), resultPayloadGPR);
1834 speculationCheck(JSValueRegs(valueTagGPR, valuePayloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, resultPayloadGPR, TrustedImm32(JSValue::NullTag)));
1836 m_jit.move(TrustedImm32(1), resultPayloadGPR);
1840 booleanResult(resultPayloadGPR, m_compileIndex);
1843 void SpeculativeJIT::compileLogicalNot(Node& node)
1845 if (isKnownBoolean(node.child1()) || isBooleanPrediction(m_jit.getPrediction(node.child1()))) {
1846 SpeculateBooleanOperand value(this, node.child1());
1847 GPRTemporary result(this, value);
1848 m_jit.xor32(TrustedImm32(1), value.gpr(), result.gpr());
1849 booleanResult(result.gpr(), m_compileIndex);
1852 if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) {
1853 compileObjectOrOtherLogicalNot(node.child1(), m_jit.globalData()->jsFinalObjectVPtr, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type));
1856 if (at(node.child1()).shouldSpeculateArrayOrOther()) {
1857 compileObjectOrOtherLogicalNot(node.child1(), m_jit.globalData()->jsArrayVPtr, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type));
1860 if (at(node.child1()).shouldSpeculateInteger()) {
1861 SpeculateIntegerOperand value(this, node.child1());
1862 GPRTemporary resultPayload(this, value);
1863 m_jit.compare32(MacroAssembler::Equal, value.gpr(), MacroAssembler::TrustedImm32(0), resultPayload.gpr());
1864 booleanResult(resultPayload.gpr(), m_compileIndex);
1867 if (at(node.child1()).shouldSpeculateNumber()) {
1868 SpeculateDoubleOperand value(this, node.child1());
1869 FPRTemporary scratch(this);
1870 GPRTemporary resultPayload(this);
1871 m_jit.move(TrustedImm32(0), resultPayload.gpr());
1872 MacroAssembler::Jump nonZero = m_jit.branchDoubleNonZero(value.fpr(), scratch.fpr());
1873 m_jit.move(TrustedImm32(1), resultPayload.gpr());
1874 nonZero.link(&m_jit);
1875 booleanResult(resultPayload.gpr(), m_compileIndex);
1879 JSValueOperand value(this, node.child1());
1880 GPRTemporary resultPayload(this, value, false);
1881 speculationCheck(JSValueRegs(value.tagGPR(), value.payloadGPR()), node.child1(), m_jit.branch32(JITCompiler::NotEqual, value.tagGPR(), TrustedImm32(JSValue::BooleanTag)));
1882 m_jit.move(value.payloadGPR(), resultPayload.gpr());
1883 m_jit.xor32(TrustedImm32(1), resultPayload.gpr());
1884 booleanResult(resultPayload.gpr(), m_compileIndex);
1886 // This code is moved from nonSpeculativeLogicalNot, currently unused!
1888 JSValueOperand arg1(this, node.child1());
1889 GPRTemporary resultTag(this, arg1);
1890 GPRTemporary resultPayload(this, arg1, false);
1891 GPRReg arg1TagGPR = arg1.tagGPR();
1892 GPRReg arg1PayloadGPR = arg1.payloadGPR();
1893 GPRReg resultTagGPR = resultTag.gpr();
1894 GPRReg resultPayloadGPR = resultPayload.gpr();
1898 JITCompiler::Jump fastCase = m_jit.branch32(JITCompiler::Equal, arg1TagGPR, TrustedImm32(JSValue::BooleanTag));
1900 silentSpillAllRegisters(resultTagGPR, resultPayloadGPR);
1901 callOperation(dfgConvertJSValueToBoolean, resultPayloadGPR, arg1TagGPR, arg1PayloadGPR);
1902 silentFillAllRegisters(resultTagGPR, resultPayloadGPR);
1903 JITCompiler::Jump doNot = m_jit.jump();
1905 fastCase.link(&m_jit);
1906 m_jit.move(arg1PayloadGPR, resultPayloadGPR);
1909 m_jit.xor32(TrustedImm32(1), resultPayloadGPR);
1910 m_jit.move(TrustedImm32(JSValue::BooleanTag), resultTagGPR);
1911 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, DataFormatJSBoolean, UseChildrenCalledExplicitly);
1915 void SpeculativeJIT::emitObjectOrOtherBranch(NodeIndex nodeIndex, BlockIndex taken, BlockIndex notTaken, void *vptr, bool needSpeculationCheck)
1917 JSValueOperand value(this, nodeIndex);
1918 GPRTemporary scratch(this);
1919 GPRReg valueTagGPR = value.tagGPR();
1920 GPRReg valuePayloadGPR = value.payloadGPR();
1921 GPRReg scratchGPR = scratch.gpr();
1923 MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
1924 if (needSpeculationCheck)
1925 speculationCheck(JSValueRegs(valueTagGPR, valuePayloadGPR), nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(valuePayloadGPR), MacroAssembler::TrustedImmPtr(vptr)));
1926 addBranch(m_jit.jump(), taken);
1928 notCell.link(&m_jit);
1930 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
1931 if (needSpeculationCheck) {
1932 m_jit.move(valueTagGPR, scratchGPR);
1933 m_jit.or32(TrustedImm32(1), scratchGPR);
1934 speculationCheck(JSValueRegs(valueTagGPR, valuePayloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag)));
1937 if (notTaken != (m_block + 1))
1938 addBranch(m_jit.jump(), notTaken);
1940 noResult(m_compileIndex);
1943 void SpeculativeJIT::emitBranch(Node& node)
1945 BlockIndex taken = node.takenBlockIndex();
1946 BlockIndex notTaken = node.notTakenBlockIndex();
1948 if (isKnownBoolean(node.child1())) {
1949 SpeculateBooleanOperand value(this, node.child1());
1950 MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
1952 if (taken == (m_block + 1)) {
1953 condition = MacroAssembler::Zero;
1954 BlockIndex tmp = taken;
1959 addBranch(m_jit.branchTest32(condition, value.gpr(), TrustedImm32(1)), taken);
1960 if (notTaken != (m_block + 1))
1961 addBranch(m_jit.jump(), notTaken);
1963 noResult(m_compileIndex);
1964 } else if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) {
1965 emitObjectOrOtherBranch(node.child1(), taken, notTaken, m_jit.globalData()->jsFinalObjectVPtr, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type));
1966 } else if (at(node.child1()).shouldSpeculateArrayOrOther()) {
1967 emitObjectOrOtherBranch(node.child1(), taken, notTaken, m_jit.globalData()->jsArrayVPtr, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type));
1968 } else if (at(node.child1()).shouldSpeculateNumber()) {
1969 if (at(node.child1()).shouldSpeculateInteger()) {
1970 bool invert = false;
1972 if (taken == (m_block + 1)) {
1974 BlockIndex tmp = taken;
1979 SpeculateIntegerOperand value(this, node.child1());
1980 addBranch(m_jit.branchTest32(invert ? MacroAssembler::Zero : MacroAssembler::NonZero, value.gpr()), taken);
1982 SpeculateDoubleOperand value(this, node.child1());
1983 FPRTemporary scratch(this);
1984 addBranch(m_jit.branchDoubleNonZero(value.fpr(), scratch.fpr()), taken);
1987 if (notTaken != (m_block + 1))
1988 addBranch(m_jit.jump(), notTaken);
1990 noResult(m_compileIndex);
1992 JSValueOperand value(this, node.child1());
1994 GPRReg valueTagGPR = value.tagGPR();
1995 GPRReg valuePayloadGPR = value.payloadGPR();
1997 GPRTemporary result(this);
1998 GPRReg resultGPR = result.gpr();
2002 JITCompiler::Jump fastPath = m_jit.branch32(JITCompiler::Equal, valueTagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag));
2003 JITCompiler::Jump slowPath = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, JITCompiler::TrustedImm32(JSValue::BooleanTag));
2005 fastPath.link(&m_jit);
2006 addBranch(m_jit.branchTest32(JITCompiler::Zero, valuePayloadGPR), notTaken);
2007 addBranch(m_jit.jump(), taken);
2009 slowPath.link(&m_jit);
2010 silentSpillAllRegisters(resultGPR);
2011 callOperation(dfgConvertJSValueToBoolean, resultGPR, valueTagGPR, valuePayloadGPR);
2012 silentFillAllRegisters(resultGPR);
2014 addBranch(m_jit.branchTest32(JITCompiler::NonZero, resultGPR), taken);
2015 if (notTaken != (m_block + 1))
2016 addBranch(m_jit.jump(), notTaken);
2018 noResult(m_compileIndex, UseChildrenCalledExplicitly);
2022 void SpeculativeJIT::compile(Node& node)
2024 NodeType op = node.op;
2028 initConstantInfo(m_compileIndex);
2031 case WeakJSConstant:
2032 m_jit.addWeakReference(node.weakConstant());
2033 initConstantInfo(m_compileIndex);
2037 PredictedType prediction = node.variableAccessData()->prediction();
2038 AbstractValue& value = block()->valuesAtHead.operand(node.local());
2040 // If we have no prediction for this local, then don't attempt to compile.
2041 if (prediction == PredictNone) {
2042 terminateSpeculativeExecution(JSValueRegs(), NoNode);
2046 GPRTemporary result(this);
2047 if (isInt32Prediction(prediction)) {
2048 m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
2050 // Like integerResult, but don't useChildren - our children are phi nodes,
2051 // and don't represent values within this dataflow with virtual registers.
2052 VirtualRegister virtualRegister = node.virtualRegister();
2053 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);
2054 m_generationInfo[virtualRegister].initInteger(m_compileIndex, node.refCount(), result.gpr());
2058 if (isArrayPrediction(prediction) || isByteArrayPrediction(prediction)) {
2059 m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
2061 // Like cellResult, but don't useChildren - our children are phi nodes,
2062 // and don't represent values within this dataflow with virtual registers.
2063 VirtualRegister virtualRegister = node.virtualRegister();
2064 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderCell);
2065 m_generationInfo[virtualRegister].initCell(m_compileIndex, node.refCount(), result.gpr());
2069 if (isBooleanPrediction(prediction)) {
2070 m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
2072 // Like booleanResult, but don't useChildren - our children are phi nodes,
2073 // and don't represent values within this dataflow with virtual registers.
2074 VirtualRegister virtualRegister = node.virtualRegister();
2075 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderBoolean);
2076 m_generationInfo[virtualRegister].initBoolean(m_compileIndex, node.refCount(), result.gpr());
2080 GPRTemporary tag(this);
2081 m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
2082 m_jit.load32(JITCompiler::tagFor(node.local()), tag.gpr());
2084 // Like jsValueResult, but don't useChildren - our children are phi nodes,
2085 // and don't represent values within this dataflow with virtual registers.
2086 VirtualRegister virtualRegister = node.virtualRegister();
2087 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
2088 m_gprs.retain(tag.gpr(), virtualRegister, SpillOrderJS);
2090 DataFormat format = isCellPrediction(value.m_type) ? DataFormatJSCell : DataFormatJS;
2091 m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), tag.gpr(), result.gpr(), format);
2096 // SetLocal doubles as a hint as to where a node will be stored and
2097 // as a speculation point. So before we speculate make sure that we
2098 // know where the child of this node needs to go in the virtual
2100 compileMovHint(node);
2102 // As far as OSR is concerned, we're on the bytecode index corresponding
2103 // to the *next* instruction, since we've already "executed" the
2104 // SetLocal and whatever other DFG Nodes are associated with the same
2105 // bytecode index as the SetLocal.
2106 ASSERT(m_codeOriginForOSR == node.codeOrigin);
2107 Node& nextNode = at(m_compileIndex + 1);
2109 m_codeOriginForOSR = nextNode.codeOrigin;
2111 PredictedType predictedType = node.variableAccessData()->prediction();
2112 if (m_generationInfo[at(node.child1()).virtualRegister()].registerFormat() == DataFormatDouble) {
2113 DoubleOperand value(this, node.child1());
2114 m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local()));
2115 noResult(m_compileIndex);
2116 } else if (isInt32Prediction(predictedType)) {
2117 SpeculateIntegerOperand value(this, node.child1());
2118 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
2119 noResult(m_compileIndex);
2120 } else if (isArrayPrediction(predictedType)) {
2121 SpeculateCellOperand cell(this, node.child1());
2122 GPRReg cellGPR = cell.gpr();
2123 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
2124 speculationCheck(JSValueSource::unboxedCell(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
2125 m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local()));
2126 noResult(m_compileIndex);
2127 } else if (isByteArrayPrediction(predictedType)) {
2128 SpeculateCellOperand cell(this, node.child1());
2129 GPRReg cellGPR = cell.gpr();
2130 if (!isByteArrayPrediction(m_state.forNode(node.child1()).m_type))
2131 speculationCheck(JSValueSource::unboxedCell(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
2132 m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local()));
2133 noResult(m_compileIndex);
2134 } else if (isBooleanPrediction(predictedType)) {
2135 SpeculateBooleanOperand value(this, node.child1());
2136 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
2137 noResult(m_compileIndex);
2139 JSValueOperand value(this, node.child1());
2140 m_jit.store32(value.payloadGPR(), JITCompiler::payloadFor(node.local()));
2141 m_jit.store32(value.tagGPR(), JITCompiler::tagFor(node.local()));
2142 noResult(m_compileIndex);
2145 // Indicate that it's no longer necessary to retrieve the value of
2146 // this bytecode variable from registers or other locations in the register file.
2147 valueSourceReferenceForOperand(node.local()) = ValueSource::forPrediction(predictedType);
2152 // This is a no-op; it just marks the fact that the argument is being used.
2153 // But it may be profitable to use this as a hook to run speculation checks
2154 // on arguments, thereby allowing us to trivially eliminate such checks if
2155 // the argument is not used.
2161 if (isInt32Constant(node.child1())) {
2162 SpeculateIntegerOperand op2(this, node.child2());
2163 GPRTemporary result(this, op2);
2165 bitOp(op, valueOfInt32Constant(node.child1()), op2.gpr(), result.gpr());
2167 integerResult(result.gpr(), m_compileIndex);
2168 } else if (isInt32Constant(node.child2())) {
2169 SpeculateIntegerOperand op1(this, node.child1());
2170 GPRTemporary result(this, op1);
2172 bitOp(op, valueOfInt32Constant(node.child2()), op1.gpr(), result.gpr());
2174 integerResult(result.gpr(), m_compileIndex);
2176 SpeculateIntegerOperand op1(this, node.child1());
2177 SpeculateIntegerOperand op2(this, node.child2());
2178 GPRTemporary result(this, op1, op2);
2180 GPRReg reg1 = op1.gpr();
2181 GPRReg reg2 = op2.gpr();
2182 bitOp(op, reg1, reg2, result.gpr());
2184 integerResult(result.gpr(), m_compileIndex);
2191 if (isInt32Constant(node.child2())) {
2192 SpeculateIntegerOperand op1(this, node.child1());
2193 GPRTemporary result(this, op1);
2195 shiftOp(op, op1.gpr(), valueOfInt32Constant(node.child2()) & 0x1f, result.gpr());
2197 integerResult(result.gpr(), m_compileIndex);
2199 // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
2200 SpeculateIntegerOperand op1(this, node.child1());
2201 SpeculateIntegerOperand op2(this, node.child2());
2202 GPRTemporary result(this, op1);
2204 GPRReg reg1 = op1.gpr();
2205 GPRReg reg2 = op2.gpr();
2206 shiftOp(op, reg1, reg2, result.gpr());
2208 integerResult(result.gpr(), m_compileIndex);
2212 case UInt32ToNumber: {
2213 if (!nodeCanSpeculateInteger(node.arithNodeFlags())) {
2214 // We know that this sometimes produces doubles. So produce a double every
2215 // time. This at least allows subsequent code to not have weird conditionals.
2217 IntegerOperand op1(this, node.child1());
2218 FPRTemporary result(this);
2220 GPRReg inputGPR = op1.gpr();
2221 FPRReg outputFPR = result.fpr();
2223 m_jit.convertInt32ToDouble(inputGPR, outputFPR);
2225 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, inputGPR, TrustedImm32(0));
2226 m_jit.addDouble(JITCompiler::AbsoluteAddress(&twoToThe32), outputFPR);
2227 positive.link(&m_jit);
2229 doubleResult(outputFPR, m_compileIndex);
2233 IntegerOperand op1(this, node.child1());
2234 GPRTemporary result(this, op1);
2236 // Test the operand is positive.
2237 speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, op1.gpr(), TrustedImm32(0)));
2239 m_jit.move(op1.gpr(), result.gpr());
2240 integerResult(result.gpr(), m_compileIndex, op1.format());
2244 case ValueToInt32: {
2245 compileValueToInt32(node);
2249 case ValueToNumber: {
2250 if (at(node.child1()).shouldNotSpeculateInteger()) {
2251 SpeculateDoubleOperand op1(this, node.child1());
2252 FPRTemporary result(this, op1);
2253 m_jit.moveDouble(op1.fpr(), result.fpr());
2254 doubleResult(result.fpr(), m_compileIndex);
2258 SpeculateIntegerOperand op1(this, node.child1());
2259 GPRTemporary result(this, op1);
2260 m_jit.move(op1.gpr(), result.gpr());
2261 integerResult(result.gpr(), m_compileIndex, op1.format());
2265 case ValueToDouble: {
2266 SpeculateDoubleOperand op1(this, node.child1());
2267 FPRTemporary result(this, op1);
2268 m_jit.moveDouble(op1.fpr(), result.fpr());
2269 doubleResult(result.fpr(), m_compileIndex);
2275 if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
2276 if (isInt32Constant(node.child1())) {
2277 int32_t imm1 = valueOfInt32Constant(node.child1());
2278 SpeculateIntegerOperand op2(this, node.child2());
2279 GPRTemporary result(this);
2281 if (nodeCanTruncateInteger(node.arithNodeFlags())) {
2282 m_jit.move(op2.gpr(), result.gpr());
2283 m_jit.add32(Imm32(imm1), result.gpr());
2285 speculationCheck(JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr()));
2287 integerResult(result.gpr(), m_compileIndex);
2291 if (isInt32Constant(node.child2())) {
2292 SpeculateIntegerOperand op1(this, node.child1());
2293 int32_t imm2 = valueOfInt32Constant(node.child2());
2294 GPRTemporary result(this);
2296 if (nodeCanTruncateInteger(node.arithNodeFlags())) {
2297 m_jit.move(op1.gpr(), result.gpr());
2298 m_jit.add32(Imm32(imm2), result.gpr());
2300 speculationCheck(JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
2302 integerResult(result.gpr(), m_compileIndex);
2306 SpeculateIntegerOperand op1(this, node.child1());
2307 SpeculateIntegerOperand op2(this, node.child2());
2308 GPRTemporary result(this, op1, op2);
2310 GPRReg gpr1 = op1.gpr();
2311 GPRReg gpr2 = op2.gpr();
2312 GPRReg gprResult = result.gpr();
2314 if (nodeCanTruncateInteger(node.arithNodeFlags())) {
2315 if (gpr1 == gprResult)
2316 m_jit.add32(gpr2, gprResult);
2318 m_jit.move(gpr2, gprResult);
2319 m_jit.add32(gpr1, gprResult);
2322 MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult);
2324 if (gpr1 == gprResult)
2325 speculationCheck(JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
2326 else if (gpr2 == gprResult)
2327 speculationCheck(JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
2329 speculationCheck(JSValueRegs(), NoNode, check);
2332 integerResult(gprResult, m_compileIndex);
2336 if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
2337 SpeculateDoubleOperand op1(this, node.child1());
2338 SpeculateDoubleOperand op2(this, node.child2());
2339 FPRTemporary result(this, op1, op2);
2341 FPRReg reg1 = op1.fpr();
2342 FPRReg reg2 = op2.fpr();
2343 m_jit.addDouble(reg1, reg2, result.fpr());
2345 doubleResult(result.fpr(), m_compileIndex);
2349 ASSERT(op == ValueAdd);
2350 compileValueAdd(node);
2355 if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
2356 if (isInt32Constant(node.child2())) {
2357 SpeculateIntegerOperand op1(this, node.child1());
2358 int32_t imm2 = valueOfInt32Constant(node.child2());
2359 GPRTemporary result(this);
2361 if (nodeCanTruncateInteger(node.arithNodeFlags())) {
2362 m_jit.move(op1.gpr(), result.gpr());
2363 m_jit.sub32(Imm32(imm2), result.gpr());
2365 speculationCheck(JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
2367 integerResult(result.gpr(), m_compileIndex);
2371 SpeculateIntegerOperand op1(this, node.child1());
2372 SpeculateIntegerOperand op2(this, node.child2());
2373 GPRTemporary result(this);
2375 if (nodeCanTruncateInteger(node.arithNodeFlags())) {
2376 m_jit.move(op1.gpr(), result.gpr());
2377 m_jit.sub32(op2.gpr(), result.gpr());
2379 speculationCheck(JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr()));
2381 integerResult(result.gpr(), m_compileIndex);
2385 SpeculateDoubleOperand op1(this, node.child1());
2386 SpeculateDoubleOperand op2(this, node.child2());
2387 FPRTemporary result(this, op1);
2389 FPRReg reg1 = op1.fpr();
2390 FPRReg reg2 = op2.fpr();
2391 m_jit.subDouble(reg1, reg2, result.fpr());
2393 doubleResult(result.fpr(), m_compileIndex);
2398 compileArithMul(node);
2403 if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
2405 SpeculateIntegerOperand op1(this, node.child1());
2406 SpeculateIntegerOperand op2(this, node.child2());
2407 GPRTemporary eax(this, X86Registers::eax);
2408 GPRTemporary edx(this, X86Registers::edx);
2409 GPRReg op1GPR = op1.gpr();
2410 GPRReg op2GPR = op2.gpr();
2412 speculationCheck(JSValueRegs(), NoNode, m_jit.branchTest32(JITCompiler::Zero, op2GPR));
2414 // If the user cares about negative zero, then speculate that we're not about
2415 // to produce negative zero.
2416 if (!nodeCanIgnoreNegativeZero(node.arithNodeFlags())) {
2417 MacroAssembler::Jump numeratorNonZero = m_jit.branchTest32(MacroAssembler::NonZero, op1GPR);
2418 speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, op2GPR, TrustedImm32(0)));
2419 numeratorNonZero.link(&m_jit);
2422 GPRReg temp2 = InvalidGPRReg;
2423 if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) {
2425 m_jit.move(op2GPR, temp2);
2429 m_jit.move(op1GPR, eax.gpr());
2430 m_jit.assembler().cdq();
2431 m_jit.assembler().idivl_r(op2GPR);
2433 if (temp2 != InvalidGPRReg)
2436 // Check that there was no remainder. If there had been, then we'd be obligated to
2437 // produce a double result instead.
2438 speculationCheck(JSValueRegs(), NoNode, m_jit.branchTest32(JITCompiler::NonZero, edx.gpr()));
2440 integerResult(eax.gpr(), m_compileIndex);
2441 #else // CPU(X86) -> so non-X86 code follows
2442 SpeculateDoubleOperand op1(this, node.child1());
2443 SpeculateDoubleOperand op2(this, node.child2());
2444 FPRTemporary result(this);
2445 FPRTemporary scratch(this);
2446 GPRTemporary intResult(this);
2448 FPRReg op1FPR = op1.fpr();
2449 FPRReg op2FPR = op2.fpr();
2450 FPRReg resultFPR = result.fpr();
2451 FPRReg scratchFPR = scratch.fpr();
2452 GPRReg resultGPR = intResult.gpr();
2454 m_jit.divDouble(op1FPR, op2FPR, resultFPR);
2456 JITCompiler::JumpList failureCases;
2457 m_jit.branchConvertDoubleToInt32(resultFPR, resultGPR, failureCases, scratchFPR);
2458 speculationCheck(JSValueRegs(), NoNode, failureCases);
2460 integerResult(resultGPR, m_compileIndex);
2465 SpeculateDoubleOperand op1(this, node.child1());
2466 SpeculateDoubleOperand op2(this, node.child2());
2467 FPRTemporary result(this, op1);
2469 FPRReg reg1 = op1.fpr();
2470 FPRReg reg2 = op2.fpr();
2471 m_jit.divDouble(reg1, reg2, result.fpr());
2473 doubleResult(result.fpr(), m_compileIndex);
2478 compileArithMod(node);
2483 if (at(node.child1()).shouldSpeculateInteger() && node.canSpeculateInteger()) {
2484 SpeculateIntegerOperand op1(this, node.child1());
2485 GPRTemporary result(this);
2486 GPRTemporary scratch(this);
2488 m_jit.zeroExtend32ToPtr(op1.gpr(), result.gpr());
2489 m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
2490 m_jit.add32(scratch.gpr(), result.gpr());
2491 m_jit.xor32(scratch.gpr(), result.gpr());
2492 speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, result.gpr(), MacroAssembler::TrustedImm32(1 << 31)));
2493 integerResult(result.gpr(), m_compileIndex);
2497 SpeculateDoubleOperand op1(this, node.child1());
2498 FPRTemporary result(this);
2500 m_jit.absDouble(op1.fpr(), result.fpr());
2501 doubleResult(result.fpr(), m_compileIndex);
2507 if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
2508 SpeculateStrictInt32Operand op1(this, node.child1());
2509 SpeculateStrictInt32Operand op2(this, node.child2());
2510 GPRTemporary result(this, op1);
2512 MacroAssembler::Jump op1Less = m_jit.branch32(op == ArithMin ? MacroAssembler::LessThan : MacroAssembler::GreaterThan, op1.gpr(), op2.gpr());
2513 m_jit.move(op2.gpr(), result.gpr());
2514 if (op1.gpr() != result.gpr()) {
2515 MacroAssembler::Jump done = m_jit.jump();
2516 op1Less.link(&m_jit);
2517 m_jit.move(op1.gpr(), result.gpr());
2520 op1Less.link(&m_jit);
2522 integerResult(result.gpr(), m_compileIndex);
2526 SpeculateDoubleOperand op1(this, node.child1());
2527 SpeculateDoubleOperand op2(this, node.child2());
2528 FPRTemporary result(this, op1);
2530 MacroAssembler::JumpList done;
2532 MacroAssembler::Jump op1Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1.fpr(), op2.fpr());
2534 // op2 is eather the lesser one or one of then is NaN
2535 MacroAssembler::Jump op2Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleGreaterThanOrEqual : MacroAssembler::DoubleLessThanOrEqual, op1.fpr(), op2.fpr());
2537 // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
2538 // op1 + op2 and putting it into result.
2539 m_jit.addDouble(op1.fpr(), op2.fpr(), result.fpr());
2540 done.append(m_jit.jump());
2542 op2Less.link(&m_jit);
2543 m_jit.moveDouble(op2.fpr(), result.fpr());
2545 if (op1.fpr() != result.fpr()) {
2546 done.append(m_jit.jump());
2548 op1Less.link(&m_jit);
2549 m_jit.moveDouble(op1.fpr(), result.fpr());
2551 op1Less.link(&m_jit);
2555 doubleResult(result.fpr(), m_compileIndex);
2560 SpeculateDoubleOperand op1(this, node.child1());
2561 FPRTemporary result(this, op1);
2563 m_jit.sqrtDouble(op1.fpr(), result.fpr());
2565 doubleResult(result.fpr(), m_compileIndex);
2570 compileLogicalNot(node);
2574 if (compare(node, JITCompiler::LessThan, JITCompiler::DoubleLessThan, operationCompareLess))
2579 if (compare(node, JITCompiler::LessThanOrEqual, JITCompiler::DoubleLessThanOrEqual, operationCompareLessEq))
2583 case CompareGreater:
2584 if (compare(node, JITCompiler::GreaterThan, JITCompiler::DoubleGreaterThan, operationCompareGreater))
2588 case CompareGreaterEq:
2589 if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq))
2594 if (isNullConstant(node.child1())) {
2595 if (nonSpeculativeCompareNull(node, node.child2()))
2599 if (isNullConstant(node.child2())) {
2600 if (nonSpeculativeCompareNull(node, node.child1()))
2604 if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq))
2608 case CompareStrictEq:
2609 if (nonSpeculativeStrictEq(node))
2613 case StringCharCodeAt: {
2614 compileGetCharCodeAt(node);
2618 case StringCharAt: {
2619 // Relies on StringCharAt node having same basic layout as GetByVal
2620 compileGetByValOnString(node);
2625 PredictedType basePrediction = at(node.child2()).prediction();
2626 if (!(basePrediction & PredictInt32) && basePrediction) {
2627 SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right.
2628 JSValueOperand property(this, node.child2());
2629 GPRReg baseGPR = base.gpr();
2630 GPRReg propertyTagGPR = property.tagGPR();
2631 GPRReg propertyPayloadGPR = property.payloadGPR();
2634 GPRResult2 resultTag(this);
2635 GPRResult resultPayload(this);
2636 callOperation(operationGetByValCell, resultTag.gpr(), resultPayload.gpr(), baseGPR, propertyTagGPR, propertyPayloadGPR);
2638 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
2642 if (at(node.child1()).prediction() == PredictString) {
2643 compileGetByValOnString(node);
2649 if (at(node.child1()).shouldSpeculateByteArray()) {
2650 compileGetByValOnByteArray(node);
2656 ASSERT(node.child3() == NoNode);
2657 SpeculateCellOperand base(this, node.child1());
2658 SpeculateStrictInt32Operand property(this, node.child2());
2659 GPRTemporary storage(this);
2660 GPRTemporary resultTag(this);
2662 GPRReg baseReg = base.gpr();
2663 GPRReg propertyReg = property.gpr();
2664 GPRReg storageReg = storage.gpr();
2669 // Get the array storage. We haven't yet checked this is a JSArray, so this is only safe if
2670 // an access with offset JSArray::storageOffset() is valid for all JSCells!
2671 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
2673 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
2674 // If we have predicted the base to be type array, we can skip the check.
2675 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
2676 speculationCheck(JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
2677 speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
2679 // FIXME: In cases where there are subsequent by_val accesses to the same base it might help to cache
2680 // the storage pointer - especially if there happens to be another register free right now. If we do so,
2681 // then we'll need to allocate a new temporary for result.
2682 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr());
2683 speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag)));
2684 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), storageReg);
2686 jsValueResult(resultTag.gpr(), storageReg, m_compileIndex);
2691 PredictedType basePrediction = at(node.child2()).prediction();
2692 if (!(basePrediction & PredictInt32) && basePrediction) {
2693 SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right.
2694 JSValueOperand property(this, node.child2());
2695 JSValueOperand value(this, node.child3());
2696 GPRReg baseGPR = base.gpr();
2697 GPRReg propertyTagGPR = property.tagGPR();
2698 GPRReg propertyPayloadGPR = property.payloadGPR();
2699 GPRReg valueTagGPR = value.tagGPR();
2700 GPRReg valuePayloadGPR = value.payloadGPR();
2703 callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValCellStrict : operationPutByValCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR);
2705 noResult(m_compileIndex);
2709 SpeculateCellOperand base(this, node.child1());
2710 SpeculateStrictInt32Operand property(this, node.child2());
2711 if (at(node.child1()).shouldSpeculateByteArray()) {
2712 compilePutByValForByteArray(base.gpr(), property.gpr(), node);
2716 JSValueOperand value(this, node.child3());
2717 GPRTemporary scratch(this);
2719 // Map base, property & value into registers, allocate a scratch register.
2720 GPRReg baseReg = base.gpr();
2721 GPRReg propertyReg = property.gpr();
2722 GPRReg valueTagReg = value.tagGPR();
2723 GPRReg valuePayloadReg = value.payloadGPR();
2724 GPRReg scratchReg = scratch.gpr();
2729 writeBarrier(baseReg, valueTagReg, node.child3(), WriteBarrierForPropertyAccess, scratchReg);
2731 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
2732 // If we have predicted the base to be type array, we can skip the check.
2733 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
2734 speculationCheck(JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
2740 MacroAssembler::Jump withinArrayBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
2742 // Code to handle put beyond array bounds.
2743 silentSpillAllRegisters(scratchReg);
2744 callOperation(operationPutByValBeyondArrayBounds, baseReg, propertyReg, valueTagReg, valuePayloadReg);
2745 silentFillAllRegisters(scratchReg);
2746 JITCompiler::Jump wasBeyondArrayBounds = m_jit.jump();
2748 withinArrayBounds.link(&m_jit);
2750 // Get the array storage.
2751 GPRReg storageReg = scratchReg;
2752 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
2754 // Check if we're writing to a hole; if so increment m_numValuesInVector.
2755 MacroAssembler::Jump notHoleValue = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
2756 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
2758 // If we're writing to a hole we might be growing the array;
2759 MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
2760 m_jit.add32(TrustedImm32(1), propertyReg);
2761 m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
2762 m_jit.sub32(TrustedImm32(1), propertyReg);
2764 lengthDoesNotNeedUpdate.link(&m_jit);
2765 notHoleValue.link(&m_jit);
2767 // Store the value to the array.
2768 m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2769 m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2771 wasBeyondArrayBounds.link(&m_jit);
2773 noResult(m_compileIndex, UseChildrenCalledExplicitly);
2777 case PutByValAlias: {
2778 SpeculateCellOperand base(this, node.child1());
2779 SpeculateStrictInt32Operand property(this, node.child2());
2781 if (at(node.child1()).shouldSpeculateByteArray()) {
2782 compilePutByValForByteArray(base.gpr(), property.gpr(), node);
2786 JSValueOperand value(this, node.child3());
2787 GPRTemporary scratch(this, base);
2789 GPRReg baseReg = base.gpr();
2790 GPRReg scratchReg = scratch.gpr();
2792 writeBarrier(baseReg, value.tagGPR(), node.child3(), WriteBarrierForPropertyAccess, scratchReg);
2794 // Get the array storage.
2795 GPRReg storageReg = scratchReg;
2796 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
2798 // Store the value to the array.
2799 GPRReg propertyReg = property.gpr();
2800 m_jit.store32(value.tagGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2801 m_jit.store32(value.payloadGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2803 noResult(m_compileIndex);
2808 SpeculateCellOperand base(this, node.child1());
2809 JSValueOperand value(this, node.child2());
2810 GPRTemporary storage(this);
2811 GPRTemporary storageLength(this);
2813 GPRReg baseGPR = base.gpr();
2814 GPRReg valueTagGPR = value.tagGPR();
2815 GPRReg valuePayloadGPR = value.payloadGPR();
2816 GPRReg storageGPR = storage.gpr();
2817 GPRReg storageLengthGPR = storageLength.gpr();
2819 writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR);
2821 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
2822 speculationCheck(JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
2824 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
2825 m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
2827 // Refuse to handle bizarre lengths.
2828 speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe)));
2830 MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
2832 m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2833 m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
2835 m_jit.add32(Imm32(1), storageLengthGPR);
2836 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
2837 m_jit.add32(Imm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
2838 m_jit.move(Imm32(JSValue::Int32Tag), storageGPR);
2840 MacroAssembler::Jump done = m_jit.jump();
2842 slowPath.link(&m_jit);
2844 silentSpillAllRegisters(storageGPR, storageLengthGPR);
2845 callOperation(operationArrayPush, storageGPR, storageLengthGPR, valueTagGPR, valuePayloadGPR, baseGPR);
2846 silentFillAllRegisters(storageGPR, storageLengthGPR);
2850 jsValueResult(storageGPR, storageLengthGPR, m_compileIndex);
2855 SpeculateCellOperand base(this, node.child1());
2856 GPRTemporary valueTag(this);
2857 GPRTemporary valuePayload(this);
2858 GPRTemporary storage(this);
2859 GPRTemporary storageLength(this);
2861 GPRReg baseGPR = base.gpr();
2862 GPRReg valueTagGPR = valueTag.gpr();
2863 GPRReg valuePayloadGPR = valuePayload.gpr();
2864 GPRReg storageGPR = storage.gpr();
2865 GPRReg storageLengthGPR = storageLength.gpr();
2867 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
2868 speculationCheck(JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
2870 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
2871 m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
2873 MacroAssembler::Jump emptyArrayCase = m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR);
2875 m_jit.sub32(Imm32(1), storageLengthGPR);
2877 MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
2879 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), valueTagGPR);
2880 m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), valuePayloadGPR);
2882 m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
2884 MacroAssembler::Jump holeCase = m_jit.branch32(MacroAssembler::Equal, Imm32(JSValue::EmptyValueTag), valueTagGPR);
2886 m_jit.store32(TrustedImm32(JSValue::EmptyValueTag), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
2888 m_jit.sub32(MacroAssembler::Imm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
2890 MacroAssembler::JumpList done;
2892 done.append(m_jit.jump());
2894 holeCase.link(&m_jit);
2895 emptyArrayCase.link(&m_jit);
2896 m_jit.move(MacroAssembler::Imm32(jsUndefined().tag()), valueTagGPR);
2897 m_jit.move(MacroAssembler::Imm32(jsUndefined().payload()), valuePayloadGPR);
2898 done.append(m_jit.jump());
2900 slowCase.link(&m_jit);
2902 silentSpillAllRegisters(valueTagGPR, valuePayloadGPR);
2903 callOperation(operationArrayPop, valueTagGPR, valuePayloadGPR, baseGPR);
2904 silentFillAllRegisters(valueTagGPR, valuePayloadGPR);
2908 jsValueResult(valueTagGPR, valuePayloadGPR, m_compileIndex);
2913 BlockIndex taken = node.takenBlockIndex();
2914 if (taken != (m_block + 1))
2915 addBranch(m_jit.jump(), taken);
2916 noResult(m_compileIndex);
2921 if (isStrictInt32(node.child1()) || at(node.child1()).shouldSpeculateInteger()) {
2922 SpeculateIntegerOperand op(this, node.child1());
2924 BlockIndex taken = node.takenBlockIndex();
2925 BlockIndex notTaken = node.notTakenBlockIndex();
2927 MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
2929 if (taken == (m_block + 1)) {
2930 condition = MacroAssembler::Zero;
2931 BlockIndex tmp = taken;
2936 addBranch(m_jit.branchTest32(condition, op.gpr()), taken);
2937 if (notTaken != (m_block + 1))
2938 addBranch(m_jit.jump(), notTaken);
2940 noResult(m_compileIndex);
2947 ASSERT(GPRInfo::callFrameRegister != GPRInfo::regT2);
2948 ASSERT(GPRInfo::regT1 != GPRInfo::returnValueGPR);
2949 ASSERT(GPRInfo::returnValueGPR != GPRInfo::callFrameRegister);
2951 #if DFG_ENABLE(SUCCESS_STATS)
2952 static SamplingCounter counter("SpeculativeJIT");
2953 m_jit.emitCount(counter);
2956 // Return the result in returnValueGPR.
2957 JSValueOperand op1(this, node.child1());
2960 boxDouble(op1.fpr(), GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
2962 if (op1.payloadGPR() == GPRInfo::returnValueGPR2 && op1.tagGPR() == GPRInfo::returnValueGPR)
2963 m_jit.swap(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
2964 else if (op1.payloadGPR() == GPRInfo::returnValueGPR2) {
2965 m_jit.move(op1.payloadGPR(), GPRInfo::returnValueGPR);
2966 m_jit.move(op1.tagGPR(), GPRInfo::returnValueGPR2);
2968 m_jit.move(op1.tagGPR(), GPRInfo::returnValueGPR2);
2969 m_jit.move(op1.payloadGPR(), GPRInfo::returnValueGPR);
2973 // Grab the return address.
2974 m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, GPRInfo::regT2);
2975 // Restore our caller's "r".
2976 m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, GPRInfo::callFrameRegister);
2978 m_jit.restoreReturnAddressBeforeReturn(GPRInfo::regT2);
2981 noResult(m_compileIndex);
2986 case ThrowReferenceError: {
2987 // We expect that throw statements are rare and are intended to exit the code block
2988 // anyway, so we just OSR back to the old JIT for now.
2989 terminateSpeculativeExecution(JSValueRegs(), NoNode);
2994 if (at(node.child1()).shouldSpeculateInteger()) {
2995 // It's really profitable to speculate integer, since it's really cheap,
2996 // it means we don't have to do any real work, and we emit a lot less code.
2998 SpeculateIntegerOperand op1(this, node.child1());
2999 GPRTemporary result(this, op1);
3001 ASSERT(op1.format() == DataFormatInteger);
3002 m_jit.move(op1.gpr(), result.gpr());
3004 integerResult(result.gpr(), m_compileIndex);
3008 // FIXME: Add string speculation here.
3010 bool wasPrimitive = isKnownNumeric(node.child1()) || isKnownBoolean(node.child1());
3012 JSValueOperand op1(this, node.child1());
3013 GPRTemporary resultTag(this, op1);
3014 GPRTemporary resultPayload(this, op1, false);
3016 GPRReg op1TagGPR = op1.tagGPR();
3017 GPRReg op1PayloadGPR = op1.payloadGPR();
3018 GPRReg resultTagGPR = resultTag.gpr();
3019 GPRReg resultPayloadGPR = resultPayload.gpr();
3024 m_jit.move(op1TagGPR, resultTagGPR);
3025 m_jit.move(op1PayloadGPR, resultPayloadGPR);
3027 MacroAssembler::JumpList alreadyPrimitive;
3029 alreadyPrimitive.append(m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag)));
3030 alreadyPrimitive.append(m_jit.branchPtr(MacroAssembler::Equal, MacroAssembler::Address(op1PayloadGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsStringVPtr)));
3032 silentSpillAllRegisters(resultTagGPR, resultPayloadGPR);
3033 callOperation(operationToPrimitive, resultTagGPR, resultPayloadGPR, op1TagGPR, op1PayloadGPR);
3034 silentFillAllRegisters(resultTagGPR, resultPayloadGPR);
3036 MacroAssembler::Jump done = m_jit.jump();
3038 alreadyPrimitive.link(&m_jit);
3039 m_jit.move(op1TagGPR, resultTagGPR);
3040 m_jit.move(op1PayloadGPR, resultPayloadGPR);
3045 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
3051 // We really don't want to grow the register file just to do a StrCat or NewArray.
3052 // Say we have 50 functions on the stack that all have a StrCat in them that has
3053 // upwards of 10 operands. In the DFG this would mean that each one gets
3054 // some random virtual register, and then to do the StrCat we'd need a second
3055 // span of 10 operands just to have somewhere to copy the 10 operands to, where
3056 // they'd be contiguous and we could easily tell the C code how to find them.
3057 // Ugly! So instead we use the scratchBuffer infrastructure in JSGlobalData. That
3058 // way, those 50 functions will share the same scratchBuffer for offloading their
3059 // StrCat operands. It's about as good as we can do, unless we start doing
3060 // virtual register coalescing to ensure that operands to StrCat get spilled
3061 // in exactly the place where StrCat wants them, or else have the StrCat
3062 // refer to those operands' SetLocal instructions to force them to spill in
3063 // the right place. Basically, any way you cut it, the current approach
3064 // probably has the best balance of performance and sensibility in the sense
3065 // that it does not increase the complexity of the DFG JIT just to make StrCat
3068 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(m_jit.globalData()->scratchBufferForSize(sizeof(EncodedJSValue) * node.numChildren()));
3070 for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
3071 JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
3072 GPRReg opTagGPR = operand.tagGPR();
3073 GPRReg opPayloadGPR = operand.payloadGPR();
3076 m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
3077 m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
3082 GPRResult resultPayload(this);
3083 GPRResult2 resultTag(this);
3085 callOperation(op == StrCat ? operationStrCat : operationNewArray, resultTag.gpr(), resultPayload.gpr(), buffer, node.numChildren());
3087 // FIXME: make the callOperation above explicitly return a cell result, or jitAssert the tag is a cell tag.
3088 cellResult(resultPayload.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
3092 case NewArrayBuffer: {
3094 GPRResult resultPayload(this);
3095 GPRResult2 resultTag(this);
3097 callOperation(operationNewArrayBuffer, resultTag.gpr(), resultPayload.gpr(), node.startConstant(), node.numConstants());
3099 // FIXME: make the callOperation above explicitly return a cell result, or jitAssert the tag is a cell tag.
3100 cellResult(resultPayload.gpr(), m_compileIndex);
3106 GPRResult resultPayload(this);
3107 GPRResult2 resultTag(this);
3109 callOperation(operationNewRegexp, resultTag.gpr(), resultPayload.gpr(), m_jit.codeBlock()->regexp(node.regexpIndex()));
3111 // FIXME: make the callOperation above explicitly return a cell result, or jitAssert the tag is a cell tag.
3112 cellResult(resultPayload.gpr(), m_compileIndex);
3117 if (isObjectPrediction(m_state.forNode(node.child1()).m_type)) {
3118 SpeculateCellOperand thisValue(this, node.child1());
3119 GPRTemporary result(this, thisValue);
3120 m_jit.move(thisValue.gpr(), result.gpr());
3121 cellResult(result.gpr(), m_compileIndex);
3125 if (isOtherPrediction(at(node.child1()).prediction())) {
3126 JSValueOperand thisValue(this, node.child1());
3127 GPRTemporary scratch(this);
3129 GPRReg thisValueTagGPR = thisValue.tagGPR();
3130 GPRReg scratchGPR = scratch.gpr();
3132 COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
3133 m_jit.move(thisValueTagGPR, scratchGPR);
3134 m_jit.or32(TrustedImm32(1), scratchGPR);
3135 // This is hard. It would be better to save the value, but we can't quite do it,
3136 // since this operation does not otherwise get the payload.
3137 speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag)));
3139 m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), scratchGPR);
3140 cellResult(scratchGPR, m_compileIndex);
3144 if (isObjectPrediction(at(node.child1()).prediction())) {
3145 SpeculateCellOperand thisValue(this, node.child1());
3146 GPRTemporary result(this, thisValue);
3147 GPRReg thisValueGPR = thisValue.gpr();
3148 GPRReg resultGPR = result.gpr();
3150 if (!isObjectPrediction(m_state.forNode(node.child1()).m_type))
3151 speculationCheck(JSValueSource::unboxedCell(thisValueGPR), node.child1(), m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(thisValueGPR), JITCompiler::TrustedImmPtr(m_jit.globalData()->jsStringVPtr)));
3153 m_jit.move(thisValueGPR, resultGPR);
3154 cellResult(resultGPR, m_compileIndex);
3158 JSValueOperand thisValue(this, node.child1());
3159 GPRReg thisValueTagGPR = thisValue.tagGPR();
3160 GPRReg thisValuePayloadGPR = thisValue.payloadGPR();
3164 GPRResult2 resultTag(this);
3165 GPRResult resultPayload(this);
3166 callOperation(operationConvertThis, resultTag.gpr(), resultPayload.gpr(), thisValueTagGPR, thisValuePayloadGPR);
3168 cellResult(resultPayload.gpr(), m_compileIndex);
3173 // Note that there is not so much profit to speculate here. The only things we
3174 // speculate on are (1) that it's a cell, since that eliminates cell checks
3175 // later if the proto is reused, and (2) if we have a FinalObject prediction
3176 // then we speculate because we want to get recompiled if it isn't (since
3177 // otherwise we'd start taking slow path a lot).
3179 SpeculateCellOperand proto(this, node.child1());
3180 GPRTemporary result(this);
3181 GPRTemporary scratch(this);
3183 GPRReg protoGPR = proto.gpr();
3184 GPRReg resultGPR = result.gpr();
3185 GPRReg scratchGPR = scratch.gpr();
3189 MacroAssembler::JumpList slowPath;
3191 // Need to verify that the prototype is an object. If we have reason to believe
3192 // that it's a FinalObject then we speculate on that directly. Otherwise we
3193 // do the slow (structure-based) check.
3194 if (at(node.child1()).shouldSpeculateFinalObject()) {
3195 if (!isFinalObjectPrediction(m_state.forNode(node.child1()).m_type))
3196 speculationCheck(JSValueSource::unboxedCell(protoGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(protoGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr)));
3198 m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSCell::structureOffset()), scratchGPR);
3199 slowPath.append(m_jit.branch8(MacroAssembler::Below, MacroAssembler::Address(scratchGPR, Structure::typeInfoTypeOffset()), MacroAssembler::TrustedImm32(ObjectType)));
3202 // Load the inheritorID (the Structure that objects who have protoGPR as the prototype
3203 // use to refer to that prototype). If the inheritorID is not set, go to slow path.
3204 m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSObject::offsetOfInheritorID()), scratchGPR);
3205 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR));
3207 emitAllocateJSFinalObject(scratchGPR, resultGPR, scratchGPR, slowPath);
3209 MacroAssembler::Jump done = m_jit.jump();
3211 slowPath.link(&m_jit);
3213 silentSpillAllRegisters(resultGPR);
3214 if (node.codeOrigin.inlineCallFrame)
3215 callOperation(operationCreateThisInlined, resultGPR, protoGPR, node.codeOrigin.inlineCallFrame->callee.get());
3217 callOperation(operationCreateThis, resultGPR, protoGPR);
3218 silentFillAllRegisters(resultGPR);
3222 cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
3227 GPRTemporary result(this);
3228 GPRTemporary scratch(this);
3230 GPRReg resultGPR = result.gpr();
3231 GPRReg scratchGPR = scratch.gpr();
3233 MacroAssembler::JumpList slowPath;
3235 emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)->emptyObjectStructure()), resultGPR, scratchGPR, slowPath);
3237 MacroAssembler::Jump done = m_jit.jump();
3239 slowPath.link(&m_jit);
3241 silentSpillAllRegisters(resultGPR);
3242 callOperation(operationNewObject, resultGPR);
3243 silentFillAllRegisters(resultGPR);
3247 cellResult(resultGPR, m_compileIndex);
3252 GPRTemporary result(this);
3253 m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(RegisterFile::Callee)), result.gpr());
3254 cellResult(result.gpr(), m_compileIndex);
3258 case GetScopeChain: {
3259 GPRTemporary result(this);
3260 GPRReg resultGPR = result.gpr();
3262 m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(RegisterFile::ScopeChain)), resultGPR);
3263 bool checkTopLevel = m_jit.codeBlock()->codeType() == FunctionCode && m_jit.codeBlock()->needsFullScopeChain();
3264 int skip = node.scopeChainDepth();
3265 ASSERT(skip || !checkTopLevel);
3266 if (checkTopLevel && skip--) {
3267 JITCompiler::Jump activationNotCreated;
3269 activationNotCreated = m_jit.branchTestPtr(JITCompiler::Zero, JITCompiler::addressFor(static_cast<VirtualRegister>(m_jit.codeBlock()->activationRegister())));
3270 m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, next)), resultGPR);
3271 activationNotCreated.link(&m_jit);
3274 m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, next)), resultGPR);
3276 m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, object)), resultGPR);
3278 cellResult(resultGPR, m_compileIndex);
3281 case GetScopedVar: {
3282 SpeculateCellOperand scopeChain(this, node.child1());
3283 GPRTemporary resultTag(this);
3284 GPRTemporary resultPayload(this);
3285 GPRReg resultTagGPR = resultTag.gpr();
3286 GPRReg resultPayloadGPR = resultPayload.gpr();
3287 m_jit.loadPtr(JITCompiler::Address(scopeChain.gpr(), JSVariableObject::offsetOfRegisters()), resultPayloadGPR);
3288 m_jit.load32(JITCompiler::Address(resultPayloadGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
3289 m_jit.load32(JITCompiler::Address(resultPayloadGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
3290 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
3293 case PutScopedVar: {
3294 SpeculateCellOperand scopeChain(this, node.child1());
3295 GPRTemporary scratchRegister(this);
3296 GPRReg scratchGPR = scratchRegister.gpr();
3297 m_jit.loadPtr(JITCompiler::Address(scopeChain.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR);
3298 JSValueOperand value(this, node.child2());
3299 m_jit.store32(value.tagGPR(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
3300 m_jit.store32(value.payloadGPR(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
3301 writeBarrier(scopeChain.gpr(), value.tagGPR(), node.child2(), WriteBarrierForVariableAccess, scratchGPR);
3302 noResult(m_compileIndex);
3307 if (!node.prediction()) {
3308 terminateSpeculativeExecution(JSValueRegs(), NoNode);
3312 if (isCellPrediction(at(node.child1()).prediction())) {
3313 SpeculateCellOperand base(this, node.child1());
3314 GPRTemporary resultTag(this, base);
3315 GPRTemporary resultPayload(this);
3317 GPRReg baseGPR = base.gpr();
3318 GPRReg resultTagGPR = resultTag.gpr();
3319 GPRReg resultPayloadGPR = resultPayload.gpr();
3322 if (resultTagGPR == baseGPR)
3323 scratchGPR = resultPayloadGPR;
3325 scratchGPR = resultTagGPR;
3329 cachedGetById(InvalidGPRReg, baseGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber());
3331 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
3335 JSValueOperand base(this, node.child1());
3336 GPRTemporary resultTag(this, base);
3337 GPRTemporary resultPayload(this);
3339 GPRReg baseTagGPR = base.tagGPR();
3340 GPRReg basePayloadGPR = base.payloadGPR();
3341 GPRReg resultTagGPR = resultTag.gpr();
3342 GPRReg resultPayloadGPR = resultPayload.gpr();
3345 if (resultTagGPR == basePayloadGPR)
3346 scratchGPR = resultPayloadGPR;
3348 scratchGPR = resultTagGPR;
3352 JITCompiler::Jump notCell = m_jit.branch32(JITCompiler::NotEqual, baseTagGPR, TrustedImm32(JSValue::CellTag));
3354 cachedGetById(baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, scratchGPR, node.identifierNumber(), notCell);
3356 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, UseChildrenCalledExplicitly);
3360 case GetArrayLength: {
3361 SpeculateCellOperand base(this, node.child1());
3362 GPRTemporary result(this);
3364 GPRReg baseGPR = base.gpr();
3365 GPRReg resultGPR = result.gpr();
3367 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
3368 speculationCheck(JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
3370 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR);
3371 m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR);
3373 speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0)));
3375 integerResult(resultGPR, m_compileIndex);
3379 case GetStringLength: {
3380 SpeculateCellOperand base(this, node.child1());
3381 GPRTemporary result(this);
3383 GPRReg baseGPR = base.gpr();
3384 GPRReg resultGPR = result.gpr();
3386 if (!isStringPrediction(m_state.forNode(node.child1()).m_type))
3387 speculationCheck(JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsStringVPtr)));
3389 m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR);
3391 integerResult(resultGPR, m_compileIndex);
3395 case GetByteArrayLength: {
3396 SpeculateCellOperand base(this, node.child1());
3397 GPRTemporary result(this);
3399 GPRReg baseGPR = base.gpr();
3400 GPRReg resultGPR = result.gpr();
3402 if (!isByteArrayPrediction(m_state.forNode(node.child1()).m_type))
3403 speculationCheck(JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
3405 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSByteArray::offsetOfStorage()), resultGPR);
3406 m_jit.load32(MacroAssembler::Address(baseGPR, ByteArray::offsetOfSize()), resultGPR);
3408 integerResult(resultGPR, m_compileIndex);
3412 case CheckFunction: {
3413 SpeculateCellOperand function(this, node.child1());
3414 speculationCheck(JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function()));
3415 noResult(m_compileIndex);
3419 case CheckStructure: {
3420 if (m_state.forNode(node.child1()).m_structure.isSubsetOf(node.structureSet())) {
3421 noResult(m_compileIndex);
3425 SpeculateCellOperand base(this, node.child1());
3427 ASSERT(node.structureSet().size());
3429 if (node.structureSet().size() == 1)
3430 speculationCheck(JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, JITCompiler::Address(base.gpr(), JSCell::structureOffset()), node.structureSet()[0]));
3432 GPRTemporary structure(this);
3434 m_jit.loadPtr(JITCompiler::Address(base.gpr(), JSCell::structureOffset()), structure.gpr());
3436 JITCompiler::JumpList done;
3438 for (size_t i = 0; i < node.structureSet().size() - 1; ++i)
3439 done.append(m_jit.branchWeakPtr(JITCompiler::Equal, structure.gpr(), node.structureSet()[i]));
3441 speculationCheck(JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, structure.gpr(), node.structureSet().last()));
3446 noResult(m_compileIndex);
3450 case PutStructure: {
3451 SpeculateCellOperand base(this, node.child1());
3452 GPRReg baseGPR = base.gpr();
3454 m_jit.addWeakReferenceTransition(
3455 node.codeOrigin.codeOriginOwner(),
3456 node.structureTransitionData().previousStructure,
3457 node.structureTransitionData().newStructure);
3459 #if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING)
3460 // Must always emit this write barrier as the structure transition itself requires it
3461 writeBarrier(baseGPR, node.structureTransitionData().newStructure, WriteBarrierForGenericAccess);
3464 m_jit.storePtr(MacroAssembler::TrustedImmPtr(node.structureTransitionData().newStructure), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
3466 noResult(m_compileIndex);
3470 case GetPropertyStorage: {
3471 SpeculateCellOperand base(this, node.child1());
3472 GPRTemporary result(this, base);
3474 GPRReg baseGPR = base.gpr();
3475 GPRReg resultGPR = result.gpr();
3477 m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
3479 storageResult(resultGPR, m_compileIndex);
3484 StorageOperand storage(this, node.child1());
3485 GPRTemporary resultTag(this, storage);
3486 GPRTemporary resultPayload(this);
3488 GPRReg storageGPR = storage.gpr();
3489 GPRReg resultTagGPR = resultTag.gpr();
3490 GPRReg resultPayloadGPR = resultPayload.gpr();
3492 StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node.storageAccessDataIndex()];
3494 m_jit.load32(JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
3495 m_jit.load32(JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
3497 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
3502 #if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING)
3503 SpeculateCellOperand base(this, node.child1());
3505 StorageOperand storage(this, node.child2());
3506 JSValueOperand value(this, node.child3());
3508 GPRReg storageGPR = storage.gpr();
3509 GPRReg valueTagGPR = value.tagGPR();
3510 GPRReg valuePayloadGPR = value.payloadGPR();
3512 #if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING)
3513 writeBarrier(base.gpr(), valueTagGPR, node.child3(), WriteBarrierForPropertyAccess);
3516 StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node.storageAccessDataIndex()];
3518 m_jit.storePtr(valueTagGPR, JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
3519 m_jit.storePtr(valuePayloadGPR, JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
3521 noResult(m_compileIndex);
3526 SpeculateCellOperand base(this, node.child1());
3527 JSValueOperand value(this, node.child2());
3528 GPRTemporary scratch(this);
3530 GPRReg baseGPR = base.gpr();
3531 GPRReg valueTagGPR = value.tagGPR();
3532 GPRReg valuePayloadGPR = value.payloadGPR();
3533 GPRReg scratchGPR = scratch.gpr();
3538 cachedPutById(baseGPR, valueTagGPR, valuePayloadGPR, node.child2(), scratchGPR, node.identifierNumber(), NotDirect);
3540 noResult(m_compileIndex, UseChildrenCalledExplicitly);
3544 case PutByIdDirect: {
3545 SpeculateCellOperand base(this, node.child1());
3546 JSValueOperand value(this, node.child2());
3547 GPRTemporary scratch(this);
3549 GPRReg baseGPR = base.gpr();
3550 GPRReg valueTagGPR = value.tagGPR();
3551 GPRReg valuePayloadGPR = value.payloadGPR();
3552 GPRReg scratchGPR = scratch.gpr();
3557 cachedPutById(baseGPR, valueTagGPR, valuePayloadGPR, node.child2(), scratchGPR, node.identifierNumber(), Direct);
3559 noResult(m_compileIndex, UseChildrenCalledExplicitly);
3563 case GetGlobalVar: {
3564 GPRTemporary result(this);
3565 GPRTemporary scratch(this);
3567 JSVariableObject* globalObject = m_jit.globalObjectFor(node.codeOrigin);
3568 m_jit.loadPtr(const_cast<WriteBarrier<Unknown>**>(globalObject->addressOfRegisters()), result.gpr());
3569 m_jit.load32(JITCompiler::tagForGlobalVar(result.gpr(), node.varNumber()), scratch.gpr());
3570 m_jit.load32(JITCompiler::payloadForGlobalVar(result.gpr(), node.varNumber()), result.gpr());
3572 jsValueResult(scratch.gpr(), result.gpr(), m_compileIndex);
3576 case PutGlobalVar: {
3577 JSValueOperand value(this, node.child1());
3578 GPRTemporary globalObject(this);
3579 GPRTemporary scratch(this);
3581 GPRReg globalObjectReg = globalObject.gpr();
3582 GPRReg scratchReg = scratch.gpr();
3584 m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), globalObjectReg);
3586 writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.tagGPR(), node.child1(), WriteBarrierForVariableAccess, scratchReg);
3588 m_jit.loadPtr(MacroAssembler::Address(globalObjectReg, JSVariableObject::offsetOfRegisters()), scratchReg);
3589 m_jit.store32(value.tagGPR(), JITCompiler::tagForGlobalVar(scratchReg, node.varNumber()));
3590 m_jit.store32(value.payloadGPR(), JITCompiler::payloadForGlobalVar(scratchReg, node.varNumber()));
3592 noResult(m_compileIndex);
3596 case CheckHasInstance: {
3597 SpeculateCellOperand base(this, node.child1());
3598 GPRTemporary structure(this);
3600 // Speculate that base 'ImplementsDefaultHasInstance'.
3601 m_jit.loadPtr(MacroAssembler::Address(base.gpr(), JSCell::structureOffset()), structure.gpr());
3602 speculationCheck(JSValueRegs(), NoNode, m_jit.branchTest8(MacroAssembler::Zero, MacroAssembler::Address(structure.gpr(), Structure::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(ImplementsDefaultHasInstance)));
3604 noResult(m_compileIndex);
3609 compileInstanceOf(node);
3615 ASSERT_NOT_REACHED();
3618 #if ENABLE(DEBUG_WITH_BREAKPOINT)
3621 ASSERT_NOT_REACHED();
3632 GPRResult resultPayload(this);
3633 GPRResult2 resultTag(this);
3634 callOperation(operationResolve, resultTag.gpr(), resultPayload.gpr(), identifier(node.identifierNumber()));
3635 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
3641 GPRResult resultPayload(this);
3642 GPRResult2 resultTag(this);
3643 callOperation(operationResolveBase, resultTag.gpr(), resultPayload.gpr(), identifier(node.identifierNumber()));
3644 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
3648 case ResolveBaseStrictPut: {
3650 GPRResult resultPayload(this);
3651 GPRResult2 resultTag(this);
3652 callOperation(operationResolveBaseStrictPut, resultTag.gpr(), resultPayload.gpr(), identifier(node.identifierNumber()));
3653 jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
3657 case ResolveGlobal: {
3658 GPRTemporary globalObject(this);
3659 GPRTemporary resolveInfo(this);
3660 GPRTemporary resultTag(this);
3661 GPRTemporary resultPayload(this);
3663 GPRReg globalObjectGPR = globalObject.gpr();
3664 GPRReg resolveInfoGPR = resolveInfo.gpr();
3665 GPRReg resultTagGPR = resultTag.gpr();
3666 GPRReg resultPayloadGPR = resultPayload.gpr();
3668 ResolveGlobalData& data = m_jit.graph().m_resolveGlobalData[node.resolveGlobalDataIndex()];
3669 GlobalResolveInfo* resolveInfoAddress = &(m_jit.codeBlock()->globalResolveInfo(data.resolveInfoIndex));
3671 // Check Structure of global object
3672 m_jit.move(JITCompiler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), globalObjectGPR);
3673 m_jit.move(JITCompiler::TrustedImmPtr(resolveInfoAddress), resolveInfoGPR);
3674 m_jit.loadPtr(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, structure)), resultPayloadGPR);
3676 JITCompiler::Jump structuresNotMatch = m_jit.branchPtr(JITCompiler::NotEqual, resultPayloadGPR, JITCompiler::Address(globalObjectGPR, JSCell::structureOffset()));
3679 m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfPropertyStorage()), resultPayloadGPR);
3680 m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);
3681 m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
3682 m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
3684 JITCompiler::Jump wasFast = m_jit.jump();
3686 structuresNotMatch.link(&m_jit);
3687 silentSpillAllRegisters(resultTagGPR, resultPayloadGPR);
3688 callOperation(operationResolveGlobal, resultTagGPR, resultPayloadGPR, resolveInfoGPR, &m_jit.codeBlock()->identifier(data.identifierNumber));
3689 silentFillAllRegisters(resultTagGPR, resultPayloadGPR);
3691 wasFast.link(&m_jit);
3693 jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
3697 case ForceOSRExit: {
3698 terminateSpeculativeExecution(JSValueRegs(), NoNode);
3704 noResult(m_compileIndex);
3708 ASSERT_NOT_REACHED();
3712 if (node.hasResult() && node.mustGenerate())
3713 use(m_compileIndex);
3718 } } // namespace JSC::DFG