+2011-09-15 Filip Pizlo <fpizlo@apple.com>
+
+ All of the functionality in the non-speculative JIT should be
+ available to the speculative JIT via helper methods
+ https://bugs.webkit.org/show_bug.cgi?id=68186
+
+ Reviewed by Oliver Hunt.
+
+ Stole all of the goodness from NonSpeculativeJIT and placed it
+ in JITCodeGenerator. Left all of the badness (i.e. subtle code
+ duplication with SpeculativeJIT, etc). This is in preparation
+ for removing the NonSpeculativeJIT entirely, but having its
+ goodness available for reuse in the SpeculativeJIT if necessary.
+
+ * dfg/DFGJITCodeGenerator.cpp:
+ (JSC::DFG::JITCodeGenerator::nonSpeculativeValueToNumber):
+ (JSC::DFG::JITCodeGenerator::nonSpeculativeValueToInt32):
+ (JSC::DFG::JITCodeGenerator::nonSpeculativeUInt32ToNumber):
+ (JSC::DFG::JITCodeGenerator::nonSpeculativeKnownConstantArithOp):
+ (JSC::DFG::JITCodeGenerator::nonSpeculativeBasicArithOp):
+ (JSC::DFG::JITCodeGenerator::nonSpeculativeArithMod):
+ (JSC::DFG::JITCodeGenerator::nonSpeculativeCheckHasInstance):
+ (JSC::DFG::JITCodeGenerator::nonSpeculativeInstanceOf):
+ * dfg/DFGJITCodeGenerator.h:
+ (JSC::DFG::JITCodeGenerator::nonSpeculativeAdd):
+ (JSC::DFG::JITCodeGenerator::nonSpeculativeArithSub):
+ * dfg/DFGNonSpeculativeJIT.cpp:
+ (JSC::DFG::NonSpeculativeJIT::compile):
+ * dfg/DFGNonSpeculativeJIT.h:
+
2011-09-15 Sheriff Bot <webkit.review.bot@gmail.com>
Unreviewed, rolling out r95167.
namespace JSC { namespace DFG {
+const double twoToThe32 = (double)0x100000000ull;
+
void JITCodeGenerator::clearGenerationInfo()
{
for (unsigned i = 0; i < m_generationInfo.size(); ++i)
return info.isJSBoolean();
}
+void JITCodeGenerator::nonSpeculativeValueToNumber(Node& node)
+{
+ if (isKnownNumeric(node.child1())) {
+ JSValueOperand op1(this, node.child1());
+ GPRTemporary result(this, op1);
+ m_jit.move(op1.gpr(), result.gpr());
+ jsValueResult(result.gpr(), m_compileIndex);
+ return;
+ }
+
+ JSValueOperand op1(this, node.child1());
+ GPRTemporary result(this);
+
+ ASSERT(!isInt32Constant(node.child1()));
+ ASSERT(!isNumberConstant(node.child1()));
+
+ GPRReg jsValueGpr = op1.gpr();
+ GPRReg gpr = result.gpr();
+ op1.use();
+
+ JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
+ JITCompiler::Jump nonNumeric = m_jit.branchTestPtr(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister);
+
+ // First, if we get here we have a double encoded as a JSValue
+ m_jit.move(jsValueGpr, gpr);
+ JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
+
+ // Next handle cells (& other JS immediates)
+ nonNumeric.link(&m_jit);
+ silentSpillAllRegisters(gpr);
+ m_jit.move(jsValueGpr, GPRInfo::argumentGPR1);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ appendCallWithExceptionCheck(dfgConvertJSValueToNumber);
+ boxDouble(FPRInfo::returnValueFPR, gpr);
+ silentFillAllRegisters(gpr);
+ JITCompiler::Jump hasCalledToNumber = m_jit.jump();
+
+ // Finally, handle integers.
+ isInteger.link(&m_jit);
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, jsValueGpr, gpr);
+ hasUnboxedDouble.link(&m_jit);
+ hasCalledToNumber.link(&m_jit);
+
+ jsValueResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
+}
+
+void JITCodeGenerator::nonSpeculativeValueToInt32(Node& node)
+{
+ ASSERT(!isInt32Constant(node.child1()));
+
+ if (isKnownInteger(node.child1())) {
+ IntegerOperand op1(this, node.child1());
+ GPRTemporary result(this, op1);
+ m_jit.move(op1.gpr(), result.gpr());
+ integerResult(result.gpr(), m_compileIndex);
+ return;
+ }
+
+ GenerationInfo& childInfo = m_generationInfo[m_jit.graph()[node.child1()].virtualRegister()];
+ if (isJSDouble(childInfo.registerFormat())) {
+ DoubleOperand op1(this, node.child1());
+ GPRTemporary result(this);
+ FPRReg fpr = op1.fpr();
+ GPRReg gpr = result.gpr();
+ op1.use();
+ JITCompiler::Jump truncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateSuccessful);
+
+ silentSpillAllRegisters(gpr);
+
+ m_jit.moveDouble(fpr, FPRInfo::argumentFPR0);
+ appendCallWithExceptionCheck(toInt32);
+ m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, gpr);
+
+ silentFillAllRegisters(gpr);
+
+ truncatedToInteger.link(&m_jit);
+ integerResult(gpr, m_compileIndex, UseChildrenCalledExplicitly);
+ return;
+ }
+
+ JSValueOperand op1(this, node.child1());
+ GPRTemporary result(this, op1);
+ GPRReg jsValueGpr = op1.gpr();
+ GPRReg resultGPR = result.gpr();
+ op1.use();
+
+ JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
+
+ // First handle non-integers
+ silentSpillAllRegisters(resultGPR);
+ m_jit.move(jsValueGpr, GPRInfo::argumentGPR1);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ appendCallWithExceptionCheck(dfgConvertJSValueToInt32);
+ m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, resultGPR);
+ silentFillAllRegisters(resultGPR);
+ JITCompiler::Jump hasCalledToInt32 = m_jit.jump();
+
+ // Then handle integers.
+ isInteger.link(&m_jit);
+ m_jit.zeroExtend32ToPtr(jsValueGpr, resultGPR);
+ hasCalledToInt32.link(&m_jit);
+ integerResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
+}
+
+void JITCodeGenerator::nonSpeculativeUInt32ToNumber(Node& node)
+{
+ IntegerOperand op1(this, node.child1());
+ FPRTemporary boxer(this);
+ GPRTemporary result(this, op1);
+
+ JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, op1.gpr(), TrustedImm32(0));
+
+ m_jit.convertInt32ToDouble(op1.gpr(), boxer.fpr());
+ m_jit.addDouble(JITCompiler::AbsoluteAddress(&twoToThe32), boxer.fpr());
+
+ boxDouble(boxer.fpr(), result.gpr());
+
+ JITCompiler::Jump done = m_jit.jump();
+
+ positive.link(&m_jit);
+
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, op1.gpr(), result.gpr());
+
+ done.link(&m_jit);
+
+ jsValueResult(result.gpr(), m_compileIndex);
+}
+
+void JITCodeGenerator::nonSpeculativeKnownConstantArithOp(NodeType op, NodeIndex regChild, NodeIndex immChild, bool commute)
+{
+ JSValueOperand regArg(this, regChild);
+ GPRReg regArgGPR = regArg.gpr();
+ GPRTemporary result(this);
+ GPRReg resultGPR = result.gpr();
+ FPRTemporary tmp1(this);
+ FPRTemporary tmp2(this);
+ FPRReg tmp1FPR = tmp1.fpr();
+ FPRReg tmp2FPR = tmp2.fpr();
+
+ regArg.use();
+ use(immChild);
+
+ JITCompiler::Jump notInt;
+
+ int32_t imm = valueOfInt32Constant(immChild);
+
+ if (!isKnownInteger(regChild))
+ notInt = m_jit.branchPtr(MacroAssembler::Below, regArgGPR, GPRInfo::tagTypeNumberRegister);
+
+ JITCompiler::Jump overflow;
+
+ switch (op) {
+ case ValueAdd:
+ case ArithAdd:
+ overflow = m_jit.branchAdd32(MacroAssembler::Overflow, regArgGPR, Imm32(imm), resultGPR);
+ break;
+
+ case ArithSub:
+ overflow = m_jit.branchSub32(MacroAssembler::Overflow, regArgGPR, Imm32(imm), resultGPR);
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
+
+ JITCompiler::Jump done = m_jit.jump();
+
+ overflow.link(&m_jit);
+
+ JITCompiler::Jump notNumber;
+
+ // first deal with overflow case
+ m_jit.convertInt32ToDouble(regArgGPR, tmp2FPR);
+
+ // now deal with not-int case, if applicable
+ if (!isKnownInteger(regChild)) {
+ JITCompiler::Jump haveValue = m_jit.jump();
+
+ notInt.link(&m_jit);
+
+ if (!isKnownNumeric(regChild)) {
+ ASSERT(op == ValueAdd);
+ notNumber = m_jit.branchTestPtr(MacroAssembler::Zero, regArgGPR, GPRInfo::tagTypeNumberRegister);
+ }
+
+ m_jit.move(regArgGPR, resultGPR);
+ m_jit.addPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
+ m_jit.movePtrToDouble(resultGPR, tmp2FPR);
+
+ haveValue.link(&m_jit);
+ }
+
+ m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfNumberConstant(immChild)))), resultGPR);
+ m_jit.movePtrToDouble(resultGPR, tmp1FPR);
+ switch (op) {
+ case ValueAdd:
+ case ArithAdd:
+ m_jit.addDouble(tmp1FPR, tmp2FPR);
+ break;
+
+ case ArithSub:
+ m_jit.subDouble(tmp1FPR, tmp2FPR);
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ JITCompiler::Jump doneCaseConvertedToInt;
+
+ if (op == ValueAdd) {
+ JITCompiler::JumpList failureCases;
+ m_jit.branchConvertDoubleToInt32(tmp2FPR, resultGPR, failureCases, tmp1FPR);
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
+
+ doneCaseConvertedToInt = m_jit.jump();
+
+ failureCases.link(&m_jit);
+ }
+
+ m_jit.moveDoubleToPtr(tmp2FPR, resultGPR);
+ m_jit.subPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
+
+ if (!isKnownNumeric(regChild)) {
+ ASSERT(notNumber.isSet());
+ ASSERT(op == ValueAdd);
+
+ JITCompiler::Jump doneCaseWasNumber = m_jit.jump();
+
+ notNumber.link(&m_jit);
+
+ silentSpillAllRegisters(resultGPR);
+ if (commute) {
+ m_jit.move(regArgGPR, GPRInfo::argumentGPR2);
+ m_jit.move(MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm)))), GPRInfo::argumentGPR1);
+ } else {
+ m_jit.move(regArgGPR, GPRInfo::argumentGPR1);
+ m_jit.move(MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm)))), GPRInfo::argumentGPR2);
+ }
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ appendCallWithExceptionCheck(operationValueAddNotNumber);
+ m_jit.move(GPRInfo::returnValueGPR, resultGPR);
+ silentFillAllRegisters(resultGPR);
+
+ doneCaseWasNumber.link(&m_jit);
+ }
+
+ done.link(&m_jit);
+ if (doneCaseConvertedToInt.isSet())
+ doneCaseConvertedToInt.link(&m_jit);
+
+ jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
+}
+
+void JITCodeGenerator::nonSpeculativeBasicArithOp(NodeType op, Node &node)
+{
+ JSValueOperand arg1(this, node.child1());
+ JSValueOperand arg2(this, node.child2());
+
+ FPRTemporary tmp1(this);
+ FPRTemporary tmp2(this);
+ FPRReg tmp1FPR = tmp1.fpr();
+ FPRReg tmp2FPR = tmp2.fpr();
+
+ GPRTemporary result(this);
+
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg arg2GPR = arg2.gpr();
+
+ GPRReg resultGPR = result.gpr();
+
+ arg1.use();
+ arg2.use();
+
+ JITCompiler::Jump child1NotInt;
+ JITCompiler::Jump child2NotInt;
+ JITCompiler::JumpList overflow;
+
+ if (!isKnownInteger(node.child1()))
+ child1NotInt = m_jit.branchPtr(MacroAssembler::Below, arg1GPR, GPRInfo::tagTypeNumberRegister);
+ if (!isKnownInteger(node.child2()))
+ child2NotInt = m_jit.branchPtr(MacroAssembler::Below, arg2GPR, GPRInfo::tagTypeNumberRegister);
+
+ switch (op) {
+ case ValueAdd:
+ case ArithAdd: {
+ overflow.append(m_jit.branchAdd32(MacroAssembler::Overflow, arg1GPR, arg2GPR, resultGPR));
+ break;
+ }
+
+ case ArithSub: {
+ overflow.append(m_jit.branchSub32(MacroAssembler::Overflow, arg1GPR, arg2GPR, resultGPR));
+ break;
+ }
+
+ case ArithMul: {
+ overflow.append(m_jit.branchMul32(MacroAssembler::Overflow, arg1GPR, arg2GPR, resultGPR));
+ overflow.append(m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
+ break;
+ }
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
+
+ JITCompiler::Jump done = m_jit.jump();
+
+ JITCompiler::JumpList haveFPRArguments;
+
+ overflow.link(&m_jit);
+
+ // both arguments are integers
+ m_jit.convertInt32ToDouble(arg1GPR, tmp1FPR);
+ m_jit.convertInt32ToDouble(arg2GPR, tmp2FPR);
+
+ haveFPRArguments.append(m_jit.jump());
+
+ JITCompiler::JumpList notNumbers;
+
+ JITCompiler::Jump child2NotInt2;
+
+ if (!isKnownInteger(node.child1())) {
+ child1NotInt.link(&m_jit);
+
+ if (!isKnownNumeric(node.child1())) {
+ ASSERT(op == ValueAdd);
+ notNumbers.append(m_jit.branchTestPtr(MacroAssembler::Zero, arg1GPR, GPRInfo::tagTypeNumberRegister));
+ }
+
+ m_jit.move(arg1GPR, resultGPR);
+ unboxDouble(resultGPR, tmp1FPR);
+
+ // child1 is converted to a double; child2 may either be an int or
+ // a boxed double
+
+ if (!isKnownInteger(node.child2())) {
+ if (isKnownNumeric(node.child2()))
+ child2NotInt2 = m_jit.branchPtr(MacroAssembler::Below, arg2GPR, GPRInfo::tagTypeNumberRegister);
+ else {
+ ASSERT(op == ValueAdd);
+ JITCompiler::Jump child2IsInt = m_jit.branchPtr(MacroAssembler::AboveOrEqual, arg2GPR, GPRInfo::tagTypeNumberRegister);
+ notNumbers.append(m_jit.branchTestPtr(MacroAssembler::Zero, arg2GPR, GPRInfo::tagTypeNumberRegister));
+ child2NotInt2 = m_jit.jump();
+ child2IsInt.link(&m_jit);
+ }
+ }
+
+ // child 2 is definitely an integer
+ m_jit.convertInt32ToDouble(arg2GPR, tmp2FPR);
+
+ haveFPRArguments.append(m_jit.jump());
+ }
+
+ if (!isKnownInteger(node.child2())) {
+ child2NotInt.link(&m_jit);
+
+ if (!isKnownNumeric(node.child2())) {
+ ASSERT(op == ValueAdd);
+ notNumbers.append(m_jit.branchTestPtr(MacroAssembler::Zero, arg2GPR, GPRInfo::tagTypeNumberRegister));
+ }
+
+ // child1 is definitely an integer, and child 2 is definitely not
+
+ m_jit.convertInt32ToDouble(arg1GPR, tmp1FPR);
+
+ if (child2NotInt2.isSet())
+ child2NotInt2.link(&m_jit);
+
+ m_jit.move(arg2GPR, resultGPR);
+ unboxDouble(resultGPR, tmp2FPR);
+ }
+
+ haveFPRArguments.link(&m_jit);
+
+ switch (op) {
+ case ValueAdd:
+ case ArithAdd:
+ m_jit.addDouble(tmp2FPR, tmp1FPR);
+ break;
+
+ case ArithSub:
+ m_jit.subDouble(tmp2FPR, tmp1FPR);
+ break;
+
+ case ArithMul:
+ m_jit.mulDouble(tmp2FPR, tmp1FPR);
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ JITCompiler::Jump doneCaseConvertedToInt;
+
+ if (op == ValueAdd) {
+ JITCompiler::JumpList failureCases;
+ m_jit.branchConvertDoubleToInt32(tmp1FPR, resultGPR, failureCases, tmp2FPR);
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
+
+ doneCaseConvertedToInt = m_jit.jump();
+
+ failureCases.link(&m_jit);
+ }
+
+ boxDouble(tmp1FPR, resultGPR);
+
+ if (!notNumbers.empty()) {
+ ASSERT(op == ValueAdd);
+
+ JITCompiler::Jump doneCaseWasNumber = m_jit.jump();
+
+ notNumbers.link(&m_jit);
+
+ silentSpillAllRegisters(resultGPR);
+ setupStubArguments(arg1GPR, arg2GPR);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ appendCallWithExceptionCheck(operationValueAddNotNumber);
+ m_jit.move(GPRInfo::returnValueGPR, resultGPR);
+ silentFillAllRegisters(resultGPR);
+
+ doneCaseWasNumber.link(&m_jit);
+ }
+
+ done.link(&m_jit);
+ if (doneCaseConvertedToInt.isSet())
+ doneCaseConvertedToInt.link(&m_jit);
+
+ jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
+}
+
+void JITCodeGenerator::nonSpeculativeArithMod(Node& node)
+{
+ JSValueOperand op1(this, node.child1());
+ JSValueOperand op2(this, node.child2());
+ GPRTemporary eax(this, X86Registers::eax);
+ GPRTemporary edx(this, X86Registers::edx);
+
+ FPRTemporary op1Double(this);
+ FPRTemporary op2Double(this);
+
+ GPRReg op1GPR = op1.gpr();
+ GPRReg op2GPR = op2.gpr();
+
+ FPRReg op1FPR = op1Double.fpr();
+ FPRReg op2FPR = op2Double.fpr();
+
+ op1.use();
+ op2.use();
+
+ GPRReg temp2 = InvalidGPRReg;
+ GPRReg unboxGPR;
+ if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) {
+ temp2 = allocate();
+ m_jit.move(op2GPR, temp2);
+ op2GPR = temp2;
+ unboxGPR = temp2;
+ } else if (op1GPR == X86Registers::eax)
+ unboxGPR = X86Registers::edx;
+ else
+ unboxGPR = X86Registers::eax;
+ ASSERT(unboxGPR != op1.gpr());
+ ASSERT(unboxGPR != op2.gpr());
+
+ JITCompiler::Jump firstOpNotInt;
+ JITCompiler::Jump secondOpNotInt;
+ JITCompiler::JumpList done;
+ JITCompiler::Jump modByZero;
+
+ if (!isKnownInteger(node.child1()))
+ firstOpNotInt = m_jit.branchPtr(MacroAssembler::Below, op1GPR, GPRInfo::tagTypeNumberRegister);
+ if (!isKnownInteger(node.child2()))
+ secondOpNotInt = m_jit.branchPtr(MacroAssembler::Below, op2GPR, GPRInfo::tagTypeNumberRegister);
+
+ modByZero = m_jit.branchTest32(MacroAssembler::Zero, op2GPR);
+
+ m_jit.move(op1GPR, eax.gpr());
+ m_jit.assembler().cdq();
+ m_jit.assembler().idivl_r(op2GPR);
+
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, X86Registers::edx);
+
+ done.append(m_jit.jump());
+
+ JITCompiler::Jump gotDoubleArgs;
+
+ modByZero.link(&m_jit);
+
+ m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsNumber(std::numeric_limits<double>::quiet_NaN()))), X86Registers::edx);
+ done.append(m_jit.jump());
+
+ if (!isKnownInteger(node.child1())) {
+ firstOpNotInt.link(&m_jit);
+
+ JITCompiler::Jump secondOpNotInt2;
+
+ if (!isKnownInteger(node.child2()))
+ secondOpNotInt2 = m_jit.branchPtr(MacroAssembler::Below, op2GPR, GPRInfo::tagTypeNumberRegister);
+
+ // first op is a double, second op is an int.
+ m_jit.convertInt32ToDouble(op2GPR, op2FPR);
+
+ if (!isKnownInteger(node.child2())) {
+ JITCompiler::Jump gotSecondOp = m_jit.jump();
+
+ secondOpNotInt2.link(&m_jit);
+
+ // first op is a double, second op is a double.
+ m_jit.move(op2GPR, unboxGPR);
+ unboxDouble(unboxGPR, op2FPR);
+
+ gotSecondOp.link(&m_jit);
+ }
+
+ m_jit.move(op1GPR, unboxGPR);
+ unboxDouble(unboxGPR, op1FPR);
+
+ gotDoubleArgs = m_jit.jump();
+ }
+
+ if (!isKnownInteger(node.child2())) {
+ secondOpNotInt.link(&m_jit);
+
+ // we know that the first op is an int, and the second is a double
+ m_jit.convertInt32ToDouble(op1GPR, op1FPR);
+ m_jit.move(op2GPR, unboxGPR);
+ unboxDouble(unboxGPR, op2FPR);
+ }
+
+ if (!isKnownInteger(node.child1()))
+ gotDoubleArgs.link(&m_jit);
+
+ if (!isKnownInteger(node.child1()) || !isKnownInteger(node.child2())) {
+ silentSpillAllRegisters(X86Registers::edx);
+ setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(op1FPR, op2FPR);
+ m_jit.appendCall(fmod);
+ boxDouble(FPRInfo::returnValueFPR, X86Registers::edx);
+ silentFillAllRegisters(X86Registers::edx);
+ }
+
+ done.link(&m_jit);
+
+ if (temp2 != InvalidGPRReg)
+ unlock(temp2);
+
+ jsValueResult(X86Registers::edx, m_compileIndex, UseChildrenCalledExplicitly);
+}
+
+void JITCodeGenerator::nonSpeculativeCheckHasInstance(Node& node)
+{
+ JSValueOperand base(this, node.child1());
+ GPRTemporary structure(this);
+
+ GPRReg baseReg = base.gpr();
+ GPRReg structureReg = structure.gpr();
+
+ // Check that base is a cell.
+ MacroAssembler::Jump baseNotCell = m_jit.branchTestPtr(MacroAssembler::NonZero, baseReg, GPRInfo::tagMaskRegister);
+
+ // Check that base 'ImplementsHasInstance'.
+ m_jit.loadPtr(MacroAssembler::Address(baseReg, JSCell::structureOffset()), structureReg);
+ MacroAssembler::Jump implementsHasInstance = m_jit.branchTest8(MacroAssembler::NonZero, MacroAssembler::Address(structureReg, Structure::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(ImplementsHasInstance));
+
+ // At this point we always throw, so no need to preserve registers.
+ baseNotCell.link(&m_jit);
+ m_jit.move(baseReg, GPRInfo::argumentGPR1);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ // At some point we could optimize this to plant a direct jump, rather then checking
+ // for an exception (operationThrowHasInstanceError always throws). Probably not worth
+ // adding the extra interface to do this now, but we may also want this for op_throw.
+ appendCallWithExceptionCheck(operationThrowHasInstanceError);
+
+ implementsHasInstance.link(&m_jit);
+ noResult(m_compileIndex);
+}
+
+void JITCodeGenerator::nonSpeculativeInstanceOf(Node& node)
+{
+ JSValueOperand value(this, node.child1());
+ JSValueOperand base(this, node.child2());
+ JSValueOperand prototype(this, node.child3());
+ GPRTemporary scratch(this, base);
+
+ GPRReg valueReg = value.gpr();
+ GPRReg baseReg = base.gpr();
+ GPRReg prototypeReg = prototype.gpr();
+ GPRReg scratchReg = scratch.gpr();
+
+ value.use();
+ base.use();
+ prototype.use();
+
+ // Check that operands are cells (base is checked by CheckHasInstance, so we can just assert).
+ MacroAssembler::Jump valueNotCell = m_jit.branchTestPtr(MacroAssembler::NonZero, valueReg, GPRInfo::tagMaskRegister);
+ m_jit.jitAssertIsCell(baseReg);
+ MacroAssembler::Jump prototypeNotCell = m_jit.branchTestPtr(MacroAssembler::NonZero, prototypeReg, GPRInfo::tagMaskRegister);
+
+ // Check that baseVal 'ImplementsDefaultHasInstance'.
+ m_jit.loadPtr(MacroAssembler::Address(baseReg, JSCell::structureOffset()), scratchReg);
+ MacroAssembler::Jump notDefaultHasInstance = m_jit.branchTest8(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance));
+
+ // Check that prototype is an object
+ m_jit.loadPtr(MacroAssembler::Address(prototypeReg, JSCell::structureOffset()), scratchReg);
+ MacroAssembler::Jump protoNotObject = m_jit.branchIfNotObject(scratchReg);
+
+ // Initialize scratchReg with the value being checked.
+ m_jit.move(valueReg, scratchReg);
+
+ // Walk up the prototype chain of the value (in scratchReg), comparing to prototypeReg.
+ MacroAssembler::Label loop(&m_jit);
+ m_jit.loadPtr(MacroAssembler::Address(scratchReg, JSCell::structureOffset()), scratchReg);
+ m_jit.loadPtr(MacroAssembler::Address(scratchReg, Structure::prototypeOffset()), scratchReg);
+ MacroAssembler::Jump isInstance = m_jit.branchPtr(MacroAssembler::Equal, scratchReg, prototypeReg);
+ m_jit.branchTestPtr(MacroAssembler::Zero, scratchReg, GPRInfo::tagMaskRegister).linkTo(loop, &m_jit);
+
+ // No match - result is false.
+ m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(false))), scratchReg);
+ MacroAssembler::Jump wasNotInstance = m_jit.jump();
+
+ // Link to here if any checks fail that require us to try calling out to an operation to help,
+ // e.g. for an API overridden HasInstance.
+ valueNotCell.link(&m_jit);
+ prototypeNotCell.link(&m_jit);
+ notDefaultHasInstance.link(&m_jit);
+ protoNotObject.link(&m_jit);
+
+ silentSpillAllRegisters(scratchReg);
+ setupStubArguments(valueReg, baseReg, prototypeReg);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ appendCallWithExceptionCheck(operationInstanceOf);
+ m_jit.move(GPRInfo::returnValueGPR, scratchReg);
+ silentFillAllRegisters(scratchReg);
+
+ MacroAssembler::Jump wasNotDefaultHasInstance = m_jit.jump();
+
+ isInstance.link(&m_jit);
+ m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(true))), scratchReg);
+
+ wasNotInstance.link(&m_jit);
+ wasNotDefaultHasInstance.link(&m_jit);
+ jsValueResult(scratchReg, m_compileIndex, UseChildrenCalledExplicitly);
+}
+
template<typename To, typename From>
inline To safeCast(From value)
{
Node& lastNode = m_jit.graph()[lastNodeIndex];
return lastNode.op == Branch && lastNode.child1() == m_compileIndex ? lastNodeIndex : NoNode;
}
+
+ void nonSpeculativeValueToNumber(Node&);
+ void nonSpeculativeValueToInt32(Node&);
+ void nonSpeculativeUInt32ToNumber(Node&);
+
+ void nonSpeculativeKnownConstantArithOp(NodeType op, NodeIndex regChild, NodeIndex immChild, bool commute);
+ void nonSpeculativeBasicArithOp(NodeType op, Node&);
+
+ // Handles both ValueAdd and ArithAdd.
+ void nonSpeculativeAdd(NodeType op, Node& node)
+ {
+ if (isInt32Constant(node.child1())) {
+ nonSpeculativeKnownConstantArithOp(op, node.child2(), node.child1(), true);
+ return;
+ }
+
+ if (isInt32Constant(node.child2())) {
+ nonSpeculativeKnownConstantArithOp(op, node.child1(), node.child2(), false);
+ return;
+ }
+
+ nonSpeculativeBasicArithOp(op, node);
+ }
+
+ void nonSpeculativeArithSub(Node& node)
+ {
+ if (isInt32Constant(node.child2())) {
+ nonSpeculativeKnownConstantArithOp(ArithSub, node.child1(), node.child2(), false);
+ return;
+ }
+
+ nonSpeculativeBasicArithOp(ArithSub, node);
+ }
+
+ void nonSpeculativeArithMod(Node&);
+ void nonSpeculativeCheckHasInstance(Node&);
+ void nonSpeculativeInstanceOf(Node&);
JITCompiler::Call cachedGetById(GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), NodeType = GetById);
void cachedPutById(GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
namespace JSC { namespace DFG {
-const double twoToThe32 = (double)0x100000000ull;
-
EntryLocation::EntryLocation(MacroAssembler::Label entry, NonSpeculativeJIT* jit)
: m_entry(entry)
, m_nodeIndex(jit->m_compileIndex)
}
}
-void NonSpeculativeJIT::valueToNumber(JSValueOperand& operand, GPRReg gpr)
-{
- GPRReg jsValueGpr = operand.gpr();
- operand.use();
-
- JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
- JITCompiler::Jump nonNumeric = m_jit.branchTestPtr(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister);
-
- // First, if we get here we have a double encoded as a JSValue
- m_jit.move(jsValueGpr, gpr);
- JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
-
- // Next handle cells (& other JS immediates)
- nonNumeric.link(&m_jit);
- silentSpillAllRegisters(gpr);
- m_jit.move(jsValueGpr, GPRInfo::argumentGPR1);
- m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
- appendCallWithExceptionCheck(dfgConvertJSValueToNumber);
- boxDouble(FPRInfo::returnValueFPR, gpr);
- silentFillAllRegisters(gpr);
- JITCompiler::Jump hasCalledToNumber = m_jit.jump();
-
- // Finally, handle integers.
- isInteger.link(&m_jit);
- m_jit.orPtr(GPRInfo::tagTypeNumberRegister, jsValueGpr, gpr);
- hasUnboxedDouble.link(&m_jit);
- hasCalledToNumber.link(&m_jit);
-}
-
-void NonSpeculativeJIT::valueToInt32(JSValueOperand& operand, GPRReg result)
-{
- GPRReg jsValueGpr = operand.gpr();
- operand.use();
-
- JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
-
- // First handle non-integers
- silentSpillAllRegisters(result);
- m_jit.move(jsValueGpr, GPRInfo::argumentGPR1);
- m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
- appendCallWithExceptionCheck(dfgConvertJSValueToInt32);
- m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, result);
- silentFillAllRegisters(result);
- JITCompiler::Jump hasCalledToInt32 = m_jit.jump();
-
- // Then handle integers.
- isInteger.link(&m_jit);
- m_jit.zeroExtend32ToPtr(jsValueGpr, result);
- hasCalledToInt32.link(&m_jit);
-}
-
-void NonSpeculativeJIT::numberToInt32(FPRReg fpr, GPRReg gpr)
-{
- JITCompiler::Jump truncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateSuccessful);
-
- silentSpillAllRegisters(gpr);
-
- m_jit.moveDouble(fpr, FPRInfo::argumentFPR0);
- appendCallWithExceptionCheck(toInt32);
- m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, gpr);
-
- silentFillAllRegisters(gpr);
-
- truncatedToInteger.link(&m_jit);
-}
-
-void NonSpeculativeJIT::knownConstantArithOp(NodeType op, NodeIndex regChild, NodeIndex immChild, bool commute)
-{
- JSValueOperand regArg(this, regChild);
- GPRReg regArgGPR = regArg.gpr();
- GPRTemporary result(this);
- GPRReg resultGPR = result.gpr();
- FPRTemporary tmp1(this);
- FPRTemporary tmp2(this);
- FPRReg tmp1FPR = tmp1.fpr();
- FPRReg tmp2FPR = tmp2.fpr();
-
- regArg.use();
- use(immChild);
-
- JITCompiler::Jump notInt;
-
- int32_t imm = valueOfInt32Constant(immChild);
-
- if (!isKnownInteger(regChild))
- notInt = m_jit.branchPtr(MacroAssembler::Below, regArgGPR, GPRInfo::tagTypeNumberRegister);
-
- JITCompiler::Jump overflow;
-
- switch (op) {
- case ValueAdd:
- case ArithAdd:
- overflow = m_jit.branchAdd32(MacroAssembler::Overflow, regArgGPR, Imm32(imm), resultGPR);
- break;
-
- case ArithSub:
- overflow = m_jit.branchSub32(MacroAssembler::Overflow, regArgGPR, Imm32(imm), resultGPR);
- break;
-
- default:
- ASSERT_NOT_REACHED();
- }
-
- m_jit.orPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
-
- JITCompiler::Jump done = m_jit.jump();
-
- overflow.link(&m_jit);
-
- JITCompiler::Jump notNumber;
-
- // first deal with overflow case
- m_jit.convertInt32ToDouble(regArgGPR, tmp2FPR);
-
- // now deal with not-int case, if applicable
- if (!isKnownInteger(regChild)) {
- JITCompiler::Jump haveValue = m_jit.jump();
-
- notInt.link(&m_jit);
-
- if (!isKnownNumeric(regChild)) {
- ASSERT(op == ValueAdd);
- notNumber = m_jit.branchTestPtr(MacroAssembler::Zero, regArgGPR, GPRInfo::tagTypeNumberRegister);
- }
-
- m_jit.move(regArgGPR, resultGPR);
- m_jit.addPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
- m_jit.movePtrToDouble(resultGPR, tmp2FPR);
-
- haveValue.link(&m_jit);
- }
-
- m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfNumberConstant(immChild)))), resultGPR);
- m_jit.movePtrToDouble(resultGPR, tmp1FPR);
- switch (op) {
- case ValueAdd:
- case ArithAdd:
- m_jit.addDouble(tmp1FPR, tmp2FPR);
- break;
-
- case ArithSub:
- m_jit.subDouble(tmp1FPR, tmp2FPR);
- break;
-
- default:
- ASSERT_NOT_REACHED();
- }
-
- JITCompiler::Jump doneCaseConvertedToInt;
-
- if (op == ValueAdd) {
- JITCompiler::JumpList failureCases;
- m_jit.branchConvertDoubleToInt32(tmp2FPR, resultGPR, failureCases, tmp1FPR);
- m_jit.orPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
-
- doneCaseConvertedToInt = m_jit.jump();
-
- failureCases.link(&m_jit);
- }
-
- m_jit.moveDoubleToPtr(tmp2FPR, resultGPR);
- m_jit.subPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
-
- if (!isKnownNumeric(regChild)) {
- ASSERT(notNumber.isSet());
- ASSERT(op == ValueAdd);
-
- JITCompiler::Jump doneCaseWasNumber = m_jit.jump();
-
- notNumber.link(&m_jit);
-
- silentSpillAllRegisters(resultGPR);
- if (commute) {
- m_jit.move(regArgGPR, GPRInfo::argumentGPR2);
- m_jit.move(MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm)))), GPRInfo::argumentGPR1);
- } else {
- m_jit.move(regArgGPR, GPRInfo::argumentGPR1);
- m_jit.move(MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm)))), GPRInfo::argumentGPR2);
- }
- m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
- appendCallWithExceptionCheck(operationValueAddNotNumber);
- m_jit.move(GPRInfo::returnValueGPR, resultGPR);
- silentFillAllRegisters(resultGPR);
-
- doneCaseWasNumber.link(&m_jit);
- }
-
- done.link(&m_jit);
- if (doneCaseConvertedToInt.isSet())
- doneCaseConvertedToInt.link(&m_jit);
-
- jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
-}
-
-void NonSpeculativeJIT::basicArithOp(NodeType op, Node &node)
-{
- JSValueOperand arg1(this, node.child1());
- JSValueOperand arg2(this, node.child2());
-
- FPRTemporary tmp1(this);
- FPRTemporary tmp2(this);
- FPRReg tmp1FPR = tmp1.fpr();
- FPRReg tmp2FPR = tmp2.fpr();
-
- GPRTemporary result(this);
-
- GPRReg arg1GPR = arg1.gpr();
- GPRReg arg2GPR = arg2.gpr();
-
- GPRReg resultGPR = result.gpr();
-
- arg1.use();
- arg2.use();
-
- JITCompiler::Jump child1NotInt;
- JITCompiler::Jump child2NotInt;
- JITCompiler::JumpList overflow;
-
- if (!isKnownInteger(node.child1()))
- child1NotInt = m_jit.branchPtr(MacroAssembler::Below, arg1GPR, GPRInfo::tagTypeNumberRegister);
- if (!isKnownInteger(node.child2()))
- child2NotInt = m_jit.branchPtr(MacroAssembler::Below, arg2GPR, GPRInfo::tagTypeNumberRegister);
-
- switch (op) {
- case ValueAdd:
- case ArithAdd: {
- overflow.append(m_jit.branchAdd32(MacroAssembler::Overflow, arg1GPR, arg2GPR, resultGPR));
- break;
- }
-
- case ArithSub: {
- overflow.append(m_jit.branchSub32(MacroAssembler::Overflow, arg1GPR, arg2GPR, resultGPR));
- break;
- }
-
- case ArithMul: {
- overflow.append(m_jit.branchMul32(MacroAssembler::Overflow, arg1GPR, arg2GPR, resultGPR));
- overflow.append(m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
- break;
- }
-
- default:
- ASSERT_NOT_REACHED();
- }
-
- m_jit.orPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
-
- JITCompiler::Jump done = m_jit.jump();
-
- JITCompiler::JumpList haveFPRArguments;
-
- overflow.link(&m_jit);
-
- // both arguments are integers
- m_jit.convertInt32ToDouble(arg1GPR, tmp1FPR);
- m_jit.convertInt32ToDouble(arg2GPR, tmp2FPR);
-
- haveFPRArguments.append(m_jit.jump());
-
- JITCompiler::JumpList notNumbers;
-
- JITCompiler::Jump child2NotInt2;
-
- if (!isKnownInteger(node.child1())) {
- child1NotInt.link(&m_jit);
-
- if (!isKnownNumeric(node.child1())) {
- ASSERT(op == ValueAdd);
- notNumbers.append(m_jit.branchTestPtr(MacroAssembler::Zero, arg1GPR, GPRInfo::tagTypeNumberRegister));
- }
-
- m_jit.move(arg1GPR, resultGPR);
- unboxDouble(resultGPR, tmp1FPR);
-
- // child1 is converted to a double; child2 may either be an int or
- // a boxed double
-
- if (!isKnownInteger(node.child2())) {
- if (isKnownNumeric(node.child2()))
- child2NotInt2 = m_jit.branchPtr(MacroAssembler::Below, arg2GPR, GPRInfo::tagTypeNumberRegister);
- else {
- ASSERT(op == ValueAdd);
- JITCompiler::Jump child2IsInt = m_jit.branchPtr(MacroAssembler::AboveOrEqual, arg2GPR, GPRInfo::tagTypeNumberRegister);
- notNumbers.append(m_jit.branchTestPtr(MacroAssembler::Zero, arg2GPR, GPRInfo::tagTypeNumberRegister));
- child2NotInt2 = m_jit.jump();
- child2IsInt.link(&m_jit);
- }
- }
-
- // child 2 is definitely an integer
- m_jit.convertInt32ToDouble(arg2GPR, tmp2FPR);
-
- haveFPRArguments.append(m_jit.jump());
- }
-
- if (!isKnownInteger(node.child2())) {
- child2NotInt.link(&m_jit);
-
- if (!isKnownNumeric(node.child2())) {
- ASSERT(op == ValueAdd);
- notNumbers.append(m_jit.branchTestPtr(MacroAssembler::Zero, arg2GPR, GPRInfo::tagTypeNumberRegister));
- }
-
- // child1 is definitely an integer, and child 2 is definitely not
-
- m_jit.convertInt32ToDouble(arg1GPR, tmp1FPR);
-
- if (child2NotInt2.isSet())
- child2NotInt2.link(&m_jit);
-
- m_jit.move(arg2GPR, resultGPR);
- unboxDouble(resultGPR, tmp2FPR);
- }
-
- haveFPRArguments.link(&m_jit);
-
- switch (op) {
- case ValueAdd:
- case ArithAdd:
- m_jit.addDouble(tmp2FPR, tmp1FPR);
- break;
-
- case ArithSub:
- m_jit.subDouble(tmp2FPR, tmp1FPR);
- break;
-
- case ArithMul:
- m_jit.mulDouble(tmp2FPR, tmp1FPR);
- break;
-
- default:
- ASSERT_NOT_REACHED();
- }
-
- JITCompiler::Jump doneCaseConvertedToInt;
-
- if (op == ValueAdd) {
- JITCompiler::JumpList failureCases;
- m_jit.branchConvertDoubleToInt32(tmp1FPR, resultGPR, failureCases, tmp2FPR);
- m_jit.orPtr(GPRInfo::tagTypeNumberRegister, resultGPR);
-
- doneCaseConvertedToInt = m_jit.jump();
-
- failureCases.link(&m_jit);
- }
-
- boxDouble(tmp1FPR, resultGPR);
-
- if (!notNumbers.empty()) {
- ASSERT(op == ValueAdd);
-
- JITCompiler::Jump doneCaseWasNumber = m_jit.jump();
-
- notNumbers.link(&m_jit);
-
- silentSpillAllRegisters(resultGPR);
- setupStubArguments(arg1GPR, arg2GPR);
- m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
- appendCallWithExceptionCheck(operationValueAddNotNumber);
- m_jit.move(GPRInfo::returnValueGPR, resultGPR);
- silentFillAllRegisters(resultGPR);
-
- doneCaseWasNumber.link(&m_jit);
- }
-
- done.link(&m_jit);
- if (doneCaseConvertedToInt.isSet())
- doneCaseConvertedToInt.link(&m_jit);
-
- jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
-}
-
void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, Node& node)
{
#if ENABLE(DFG_OSR_EXIT)
break;
case UInt32ToNumber: {
- IntegerOperand op1(this, node.child1());
- FPRTemporary boxer(this);
- GPRTemporary result(this, op1);
-
- JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, op1.gpr(), TrustedImm32(0));
-
- m_jit.convertInt32ToDouble(op1.gpr(), boxer.fpr());
- m_jit.addDouble(JITCompiler::AbsoluteAddress(&twoToThe32), boxer.fpr());
-
- boxDouble(boxer.fpr(), result.gpr());
-
- JITCompiler::Jump done = m_jit.jump();
-
- positive.link(&m_jit);
-
- m_jit.orPtr(GPRInfo::tagTypeNumberRegister, op1.gpr(), result.gpr());
-
- done.link(&m_jit);
-
- jsValueResult(result.gpr(), m_compileIndex);
+ nonSpeculativeUInt32ToNumber(node);
break;
}
case ValueToInt32: {
- ASSERT(!isInt32Constant(node.child1()));
-
- if (isKnownInteger(node.child1())) {
- IntegerOperand op1(this, node.child1());
- GPRTemporary result(this, op1);
- m_jit.move(op1.gpr(), result.gpr());
- integerResult(result.gpr(), m_compileIndex);
- break;
- }
-
- GenerationInfo& childInfo = m_generationInfo[m_jit.graph()[node.child1()].virtualRegister()];
- if (isJSDouble(childInfo.registerFormat())) {
- DoubleOperand op1(this, node.child1());
- GPRTemporary result(this);
- FPRReg fpr = op1.fpr();
- GPRReg gpr = result.gpr();
- op1.use();
- numberToInt32(fpr, gpr);
- integerResult(gpr, m_compileIndex, UseChildrenCalledExplicitly);
- break;
- }
-
- JSValueOperand op1(this, node.child1());
- GPRTemporary result(this, op1);
- valueToInt32(op1, result.gpr());
- integerResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
+ nonSpeculativeValueToInt32(node);
break;
}
case ValueToNumber:
case ValueToDouble: {
- ASSERT(!isInt32Constant(node.child1()));
- ASSERT(!isNumberConstant(node.child1()));
-
- if (isKnownNumeric(node.child1())) {
- JSValueOperand op1(this, node.child1());
- GPRTemporary result(this, op1);
- m_jit.move(op1.gpr(), result.gpr());
- jsValueResult(result.gpr(), m_compileIndex);
- break;
- }
-
- JSValueOperand op1(this, node.child1());
- GPRTemporary result(this);
- valueToNumber(op1, result.gpr());
- jsValueResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
+ nonSpeculativeValueToNumber(node);
break;
}
case ValueAdd:
case ArithAdd: {
- if (isInt32Constant(node.child1())) {
- knownConstantArithOp(op, node.child2(), node.child1(), true);
- break;
- }
-
- if (isInt32Constant(node.child2())) {
- knownConstantArithOp(op, node.child1(), node.child2(), false);
- break;
- }
-
- basicArithOp(op, node);
+ nonSpeculativeAdd(op, node);
break;
}
case ArithSub: {
- if (isInt32Constant(node.child2())) {
- knownConstantArithOp(ArithSub, node.child1(), node.child2(), false);
- break;
- }
-
- basicArithOp(ArithSub, node);
+ nonSpeculativeArithSub(node);
break;
}
case ArithMul: {
- basicArithOp(ArithMul, node);
+ nonSpeculativeBasicArithOp(ArithMul, node);
break;
}
}
case ArithMod: {
- JSValueOperand op1(this, node.child1());
- JSValueOperand op2(this, node.child2());
- GPRTemporary eax(this, X86Registers::eax);
- GPRTemporary edx(this, X86Registers::edx);
-
- FPRTemporary op1Double(this);
- FPRTemporary op2Double(this);
-
- GPRReg op1GPR = op1.gpr();
- GPRReg op2GPR = op2.gpr();
-
- FPRReg op1FPR = op1Double.fpr();
- FPRReg op2FPR = op2Double.fpr();
-
- op1.use();
- op2.use();
-
- GPRReg temp2 = InvalidGPRReg;
- GPRReg unboxGPR;
- if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) {
- temp2 = allocate();
- m_jit.move(op2GPR, temp2);
- op2GPR = temp2;
- unboxGPR = temp2;
- } else if (op1GPR == X86Registers::eax)
- unboxGPR = X86Registers::edx;
- else
- unboxGPR = X86Registers::eax;
- ASSERT(unboxGPR != op1.gpr());
- ASSERT(unboxGPR != op2.gpr());
-
- JITCompiler::Jump firstOpNotInt;
- JITCompiler::Jump secondOpNotInt;
- JITCompiler::JumpList done;
- JITCompiler::Jump modByZero;
-
- if (!isKnownInteger(node.child1()))
- firstOpNotInt = m_jit.branchPtr(MacroAssembler::Below, op1GPR, GPRInfo::tagTypeNumberRegister);
- if (!isKnownInteger(node.child2()))
- secondOpNotInt = m_jit.branchPtr(MacroAssembler::Below, op2GPR, GPRInfo::tagTypeNumberRegister);
-
- modByZero = m_jit.branchTest32(MacroAssembler::Zero, op2GPR);
-
- m_jit.move(op1GPR, eax.gpr());
- m_jit.assembler().cdq();
- m_jit.assembler().idivl_r(op2GPR);
-
- m_jit.orPtr(GPRInfo::tagTypeNumberRegister, X86Registers::edx);
-
- done.append(m_jit.jump());
-
- JITCompiler::Jump gotDoubleArgs;
-
- modByZero.link(&m_jit);
-
- m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsNumber(std::numeric_limits<double>::quiet_NaN()))), X86Registers::edx);
- done.append(m_jit.jump());
-
- if (!isKnownInteger(node.child1())) {
- firstOpNotInt.link(&m_jit);
-
- JITCompiler::Jump secondOpNotInt2;
-
- if (!isKnownInteger(node.child2()))
- secondOpNotInt2 = m_jit.branchPtr(MacroAssembler::Below, op2GPR, GPRInfo::tagTypeNumberRegister);
-
- // first op is a double, second op is an int.
- m_jit.convertInt32ToDouble(op2GPR, op2FPR);
-
- if (!isKnownInteger(node.child2())) {
- JITCompiler::Jump gotSecondOp = m_jit.jump();
-
- secondOpNotInt2.link(&m_jit);
-
- // first op is a double, second op is a double.
- m_jit.move(op2GPR, unboxGPR);
- unboxDouble(unboxGPR, op2FPR);
-
- gotSecondOp.link(&m_jit);
- }
-
- m_jit.move(op1GPR, unboxGPR);
- unboxDouble(unboxGPR, op1FPR);
-
- gotDoubleArgs = m_jit.jump();
- }
-
- if (!isKnownInteger(node.child2())) {
- secondOpNotInt.link(&m_jit);
-
- // we know that the first op is an int, and the second is a double
- m_jit.convertInt32ToDouble(op1GPR, op1FPR);
- m_jit.move(op2GPR, unboxGPR);
- unboxDouble(unboxGPR, op2FPR);
- }
-
- if (!isKnownInteger(node.child1()))
- gotDoubleArgs.link(&m_jit);
-
- if (!isKnownInteger(node.child1()) || !isKnownInteger(node.child2())) {
- silentSpillAllRegisters(X86Registers::edx);
- setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(op1FPR, op2FPR);
- m_jit.appendCall(fmod);
- boxDouble(FPRInfo::returnValueFPR, X86Registers::edx);
- silentFillAllRegisters(X86Registers::edx);
- }
-
- done.link(&m_jit);
-
- if (temp2 != InvalidGPRReg)
- unlock(temp2);
-
- jsValueResult(X86Registers::edx, m_compileIndex, UseChildrenCalledExplicitly);
+ nonSpeculativeArithMod(node);
break;
}
}
case CheckHasInstance: {
- JSValueOperand base(this, node.child1());
- GPRTemporary structure(this);
-
- GPRReg baseReg = base.gpr();
- GPRReg structureReg = structure.gpr();
-
- // Check that base is a cell.
- MacroAssembler::Jump baseNotCell = m_jit.branchTestPtr(MacroAssembler::NonZero, baseReg, GPRInfo::tagMaskRegister);
-
- // Check that base 'ImplementsHasInstance'.
- m_jit.loadPtr(MacroAssembler::Address(baseReg, JSCell::structureOffset()), structureReg);
- MacroAssembler::Jump implementsHasInstance = m_jit.branchTest8(MacroAssembler::NonZero, MacroAssembler::Address(structureReg, Structure::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(ImplementsHasInstance));
-
- // At this point we always throw, so no need to preserve registers.
- baseNotCell.link(&m_jit);
- m_jit.move(baseReg, GPRInfo::argumentGPR1);
- m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
- // At some point we could optimize this to plant a direct jump, rather then checking
- // for an exception (operationThrowHasInstanceError always throws). Probably not worth
- // adding the extra interface to do this now, but we may also want this for op_throw.
- appendCallWithExceptionCheck(operationThrowHasInstanceError);
-
- implementsHasInstance.link(&m_jit);
- noResult(m_compileIndex);
+ nonSpeculativeCheckHasInstance(node);
break;
}
case InstanceOf: {
- JSValueOperand value(this, node.child1());
- JSValueOperand base(this, node.child2());
- JSValueOperand prototype(this, node.child3());
- GPRTemporary scratch(this, base);
-
- GPRReg valueReg = value.gpr();
- GPRReg baseReg = base.gpr();
- GPRReg prototypeReg = prototype.gpr();
- GPRReg scratchReg = scratch.gpr();
-
- value.use();
- base.use();
- prototype.use();
-
- // Check that operands are cells (base is checked by CheckHasInstance, so we can just assert).
- MacroAssembler::Jump valueNotCell = m_jit.branchTestPtr(MacroAssembler::NonZero, valueReg, GPRInfo::tagMaskRegister);
- m_jit.jitAssertIsCell(baseReg);
- MacroAssembler::Jump prototypeNotCell = m_jit.branchTestPtr(MacroAssembler::NonZero, prototypeReg, GPRInfo::tagMaskRegister);
-
- // Check that baseVal 'ImplementsDefaultHasInstance'.
- m_jit.loadPtr(MacroAssembler::Address(baseReg, JSCell::structureOffset()), scratchReg);
- MacroAssembler::Jump notDefaultHasInstance = m_jit.branchTest8(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance));
-
- // Check that prototype is an object
- m_jit.loadPtr(MacroAssembler::Address(prototypeReg, JSCell::structureOffset()), scratchReg);
- MacroAssembler::Jump protoNotObject = m_jit.branchIfNotObject(scratchReg);
-
- // Initialize scratchReg with the value being checked.
- m_jit.move(valueReg, scratchReg);
-
- // Walk up the prototype chain of the value (in scratchReg), comparing to prototypeReg.
- MacroAssembler::Label loop(&m_jit);
- m_jit.loadPtr(MacroAssembler::Address(scratchReg, JSCell::structureOffset()), scratchReg);
- m_jit.loadPtr(MacroAssembler::Address(scratchReg, Structure::prototypeOffset()), scratchReg);
- MacroAssembler::Jump isInstance = m_jit.branchPtr(MacroAssembler::Equal, scratchReg, prototypeReg);
- m_jit.branchTestPtr(MacroAssembler::Zero, scratchReg, GPRInfo::tagMaskRegister).linkTo(loop, &m_jit);
-
- // No match - result is false.
- m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(false))), scratchReg);
- MacroAssembler::Jump wasNotInstance = m_jit.jump();
-
- // Link to here if any checks fail that require us to try calling out to an operation to help,
- // e.g. for an API overridden HasInstance.
- valueNotCell.link(&m_jit);
- prototypeNotCell.link(&m_jit);
- notDefaultHasInstance.link(&m_jit);
- protoNotObject.link(&m_jit);
-
- silentSpillAllRegisters(scratchReg);
- setupStubArguments(valueReg, baseReg, prototypeReg);
- m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
- appendCallWithExceptionCheck(operationInstanceOf);
- m_jit.move(GPRInfo::returnValueGPR, scratchReg);
- silentFillAllRegisters(scratchReg);
-
- MacroAssembler::Jump wasNotDefaultHasInstance = m_jit.jump();
-
- isInstance.link(&m_jit);
- m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(true))), scratchReg);
-
- wasNotInstance.link(&m_jit);
- wasNotDefaultHasInstance.link(&m_jit);
- jsValueResult(scratchReg, m_compileIndex, UseChildrenCalledExplicitly);
+ nonSpeculativeInstanceOf(node);
break;
}
// These methods are used to plant calls out to C++
// helper routines to convert between types.
- void valueToNumber(JSValueOperand&, GPRReg result);
- void valueToInt32(JSValueOperand&, GPRReg result);
- void numberToInt32(FPRReg, GPRReg result);
// Record an entry location into the non-speculative code path;
// for every bail-out on the speculative path we record information
m_entryLocations.append(EntryLocation(entry, this));
}
- // internal helpers for add/sub/mul operations
- void knownConstantArithOp(NodeType op, NodeIndex regChild, NodeIndex immChild, bool commute);
- void basicArithOp(NodeType op, Node&);
-
EntryLocationVector m_entryLocations;
};