bool ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) { Label failure; masm.branchTestInt32(Assembler::NotEqual, R0, &failure); switch (op) { case JSOP_BITNOT: masm.notl(R0.valueReg()); break; case JSOP_NEG: // Guard against 0 and MIN_INT, both result in a double. masm.branchTest32(Assembler::Zero, R0.valueReg(), Imm32(0x7fffffff), &failure); masm.negl(R0.valueReg()); break; default: MOZ_ASSUME_UNREACHABLE("Unexpected op"); } masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0); EmitReturnFromIC(masm); masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
bool ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm) { Label failure; masm.branchTestInt32(Assembler::NotEqual, R0, &failure); switch (op) { case JSOP_BITNOT: masm.Mvn(ARMRegister(R1.valueReg(), 32), ARMRegister(R0.valueReg(), 32)); masm.movePayload(R1.valueReg(), R0.valueReg()); break; case JSOP_NEG: // Guard against 0 and MIN_INT, both result in a double. masm.branchTest32(Assembler::Zero, R0.valueReg(), Imm32(0x7fffffff), &failure); // Compile -x as 0 - x. masm.Sub(ARMRegister(R1.valueReg(), 32), wzr, ARMRegister(R0.valueReg(), 32)); masm.movePayload(R1.valueReg(), R0.valueReg()); break; default: MOZ_CRASH("Unexpected op"); } EmitReturnFromIC(masm); masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
bool ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) { Label failure; // by wangqing, 2013-11-26 masm.movl(ImmTag(JSVAL_TAG_INT32), cmpTempRegister); masm.bne(R0.typeReg(), cmpTempRegister, &failure); masm.nop(); switch (op) { case JSOP_BITNOT: masm.notl(R0.payloadReg()); break; case JSOP_NEG: // Guard against 0 and MIN_INT, both result in a double. /* rewrite testl(reg, imm), avoid use cmpTemp2Register by wangqing, 2013-11-22*/ masm.movl(R0.payloadReg(), cmpTempRegister); masm.andl(Imm32(0x7fffffff), cmpTempRegister); masm.beq(cmpTempRegister, zero, &failure); masm.nop(); masm.negl(R0.payloadReg()); break; default: JS_NOT_REACHED("Unexpected op"); return false; } EmitReturnFromIC(masm); masm.bindBranch(&failure); EmitStubGuardFailure(masm); return true; }
// ICCompare_Int32 bool ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &masm) { // Guard that R0 is an integer and R1 is an integer. Label failure; // by wangqing, 2013-11-22 masm.movl(ImmTag(JSVAL_TAG_INT32), cmpTempRegister); masm.bne(R0.typeReg(), cmpTempRegister, &failure); masm.nop(); masm.movl(ImmTag(JSVAL_TAG_INT32), cmpTempRegister); masm.bne(R1.typeReg(), cmpTempRegister, &failure); masm.nop(); // Compare payload regs of R0 and R1. Assembler::Condition cond = JSOpToCondition(op, /* signed = */true); masm.cmpl(R0.payloadReg(), R1.payloadReg()); masm.setCC(cond, R0.payloadReg()); masm.movzxbl(R0.payloadReg(), R0.payloadReg()); // Box the result and return masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.payloadReg(), R0); EmitReturnFromIC(masm); // Failure case - jump to next stub masm.bindBranch(&failure); EmitStubGuardFailure(masm); return true; }
bool ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm) { Label failure; masm.branchTestInt32(Assembler::NotEqual, R0, &failure); switch (op) { case JSOP_BITNOT: masm.not32(R0.payloadReg()); break; case JSOP_NEG: // Guard against 0 and MIN_INT, both result in a double. masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(INT32_MAX), &failure); masm.neg32(R0.payloadReg()); break; default: MOZ_CRASH("Unexpected op"); return false; } EmitReturnFromIC(masm); masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
//from jit/shared/BaselineIC-x86-shared.cpp bool ICCompare_Double::Compiler::generateStubCode(MacroAssembler &masm) { Label failure, notNaN; masm.ensureDouble(R0, FloatReg0, &failure); masm.ensureDouble(R1, FloatReg1, &failure); Register dest = R0.scratchReg(); Assembler::DoubleCondition cond = JSOpToDoubleCondition(op); masm.mov(ImmWord(0), dest); masm.compareDouble(cond, FloatReg0, FloatReg1); masm.setCC(Assembler::ConditionFromDoubleCondition(cond), dest); // Check for NaN, if needed. Assembler::NaNCond nanCond = Assembler::NaNCondFromDoubleCondition(cond); if (nanCond != Assembler::NaN_HandledByCond) { masm.j(Assembler::NoParity, ¬NaN); masm.mov(ImmWord(nanCond == Assembler::NaN_IsTrue), dest); masm.bind(¬NaN); } masm.tagValue(JSVAL_TYPE_BOOLEAN, dest, R0); EmitReturnFromIC(masm); // Failure case - jump to next stub masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
bool ICCompare_Double::Compiler::generateStubCode(MacroAssembler &masm) { Label failure, isNaN; masm.ensureDouble(R0, FloatReg0, &failure); masm.ensureDouble(R1, FloatReg1, &failure); Register dest = R0.scratchReg(); Assembler::DoubleCondition doubleCond = JSOpToDoubleCondition(op); masm.ma_cmp_set_double(dest, FloatReg0, FloatReg1, doubleCond); masm.tagValue(JSVAL_TYPE_BOOLEAN, dest, R0); EmitReturnFromIC(masm); // Failure case - jump to next stub masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
bool ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &masm) { // Guard that R0 is an integer and R1 is an integer. Label failure; Label conditionTrue; masm.branchTestInt32(Assembler::NotEqual, R0, &failure); masm.branchTestInt32(Assembler::NotEqual, R1, &failure); // Compare payload regs of R0 and R1. Assembler::Condition cond = JSOpToCondition(op, /* signed = */true); masm.ma_cmp_set(R0.payloadReg(), R0.payloadReg(), R1.payloadReg(), cond); masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.payloadReg(), R0); EmitReturnFromIC(masm); // Failure case - jump to next stub masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
bool ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &masm) { // Guard that R0 is an integer and R1 is an integer. Label failure; masm.branchTestInt32(Assembler::NotEqual, R0, &failure); masm.branchTestInt32(Assembler::NotEqual, R1, &failure); // Directly compare the int32 payload of R0 and R1. Assembler::Condition cond = JSOpToCondition(op, /* signed = */true); masm.mov(ImmWord(0), ScratchReg); masm.cmpl(R0.valueReg(), R1.valueReg()); masm.setCC(cond, ScratchReg); // Box the result and return masm.boxValue(JSVAL_TYPE_BOOLEAN, ScratchReg, R0.valueReg()); EmitReturnFromIC(masm); // Failure case - jump to next stub masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
bool ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) { // Guard that R0 is an integer and R1 is an integer. Label failure; masm.branchTestInt32(Assembler::NotEqual, R0, &failure); masm.branchTestInt32(Assembler::NotEqual, R1, &failure); Label revertRegister, maybeNegZero; switch(op_) { case JSOP_ADD: masm.unboxInt32(R0, ExtractTemp0); // Just jump to failure on overflow. R0 and R1 are preserved, so we can just jump to // the next stub. masm.addl(R1.valueReg(), ExtractTemp0); masm.j(Assembler::Overflow, &failure); // Box the result masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); break; case JSOP_SUB: masm.unboxInt32(R0, ExtractTemp0); masm.subl(R1.valueReg(), ExtractTemp0); masm.j(Assembler::Overflow, &failure); masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); break; case JSOP_MUL: masm.unboxInt32(R0, ExtractTemp0); masm.imull(R1.valueReg(), ExtractTemp0); masm.j(Assembler::Overflow, &failure); masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &maybeNegZero); masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); break; case JSOP_DIV: { JS_ASSERT(R2.scratchReg() == rax); JS_ASSERT(R0.valueReg() != rdx); JS_ASSERT(R1.valueReg() != rdx); masm.unboxInt32(R0, eax); masm.unboxInt32(R1, ExtractTemp0); // Prevent division by 0. masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &failure); // Prevent negative 0 and -2147483648 / -1. masm.branch32(Assembler::Equal, eax, Imm32(INT32_MIN), &failure); Label notZero; masm.branch32(Assembler::NotEqual, eax, Imm32(0), ¬Zero); masm.branchTest32(Assembler::Signed, ExtractTemp0, ExtractTemp0, &failure); masm.bind(¬Zero); // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. masm.cdq(); masm.idiv(ExtractTemp0); // A remainder implies a double result. masm.branchTest32(Assembler::NonZero, edx, edx, &failure); masm.boxValue(JSVAL_TYPE_INT32, eax, R0.valueReg()); break; } case JSOP_MOD: { JS_ASSERT(R2.scratchReg() == rax); JS_ASSERT(R0.valueReg() != rdx); JS_ASSERT(R1.valueReg() != rdx); masm.unboxInt32(R0, eax); masm.unboxInt32(R1, ExtractTemp0); // x % 0 always results in NaN. masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &failure); // Prevent negative 0 and -2147483648 % -1. masm.branchTest32(Assembler::Zero, eax, Imm32(0x7fffffff), &failure); // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. masm.cdq(); masm.idiv(ExtractTemp0); // Fail when we would need a negative remainder. Label done; masm.branchTest32(Assembler::NonZero, edx, edx, &done); masm.orl(ExtractTemp0, eax); masm.branchTest32(Assembler::Signed, eax, eax, &failure); masm.bind(&done); masm.boxValue(JSVAL_TYPE_INT32, edx, R0.valueReg()); break; } case JSOP_BITOR: // We can overide R0, because the instruction is unfailable. // Because the tag bits are the same, we don't need to retag. masm.orq(R1.valueReg(), R0.valueReg()); break; case JSOP_BITXOR: masm.xorl(R1.valueReg(), R0.valueReg()); masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0); break; case JSOP_BITAND: masm.andq(R1.valueReg(), R0.valueReg()); break; case JSOP_LSH: masm.unboxInt32(R0, ExtractTemp0); masm.unboxInt32(R1, ecx); // Unboxing R1 to ecx, clobbers R0. masm.shll_cl(ExtractTemp0); masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); break; case JSOP_RSH: masm.unboxInt32(R0, ExtractTemp0); masm.unboxInt32(R1, ecx); masm.sarl_cl(ExtractTemp0); masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); break; case JSOP_URSH: if (!allowDouble_) masm.movq(R0.valueReg(), ScratchReg); masm.unboxInt32(R0, ExtractTemp0); masm.unboxInt32(R1, ecx); // This clobbers R0 masm.shrl_cl(ExtractTemp0); masm.testl(ExtractTemp0, ExtractTemp0); if (allowDouble_) { Label toUint; masm.j(Assembler::Signed, &toUint); // Box and return. masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); EmitReturnFromIC(masm); masm.bind(&toUint); masm.convertUInt32ToDouble(ExtractTemp0, ScratchFloatReg); masm.boxDouble(ScratchFloatReg, R0); } else { masm.j(Assembler::Signed, &revertRegister); masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); } break; default: MOZ_ASSUME_UNREACHABLE("Unhandled op in BinaryArith_Int32"); } // Return from stub. EmitReturnFromIC(masm); if (op_ == JSOP_MUL) { masm.bind(&maybeNegZero); // Result is -0 if exactly one of lhs or rhs is negative. masm.movl(R0.valueReg(), ScratchReg); masm.orl(R1.valueReg(), ScratchReg); masm.j(Assembler::Signed, &failure); // Result is +0. masm.moveValue(Int32Value(0), R0); EmitReturnFromIC(masm); } // Revert the content of R0 in the fallible >>> case. if (op_ == JSOP_URSH && !allowDouble_) { masm.bind(&revertRegister); // Restore tag and payload. masm.movq(ScratchReg, R0.valueReg()); // Fall through to failure. } // Failure case - jump to next stub masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
bool ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) { // Guard that R0 is an integer and R1 is an integer. Label failure; masm.branchTestInt32(Assembler::NotEqual, R0, &failure); masm.branchTestInt32(Assembler::NotEqual, R1, &failure); // Add R0 and R1. Don't need to explicitly unbox, just use R2's payloadReg. Register scratchReg = R2.payloadReg(); // DIV and MOD need an extra non-volatile ValueOperand to hold R0. GeneralRegisterSet savedRegs = availableGeneralRegs(2); savedRegs = GeneralRegisterSet::Intersect(GeneralRegisterSet::NonVolatile(), savedRegs); ValueOperand savedValue = savedRegs.takeAnyValue(); Label goodMul, divTest1, divTest2; switch(op_) { case JSOP_ADD: // We know R0.typeReg() already contains the integer tag. No boxing // required. masm.ma_addTestOverflow(R0.payloadReg(), R0.payloadReg(), R1.payloadReg(), &failure); break; case JSOP_SUB: masm.ma_subTestOverflow(R0.payloadReg(), R0.payloadReg(), R1.payloadReg(), &failure); break; case JSOP_MUL: { masm.ma_mul_branch_overflow(scratchReg, R0.payloadReg(), R1.payloadReg(), &failure); masm.ma_b(scratchReg, Imm32(0), &goodMul, Assembler::NotEqual, ShortJump); // Result is -0 if operands have different signs. masm.as_xor(t8, R0.payloadReg(), R1.payloadReg()); masm.ma_b(t8, Imm32(0), &failure, Assembler::LessThan, ShortJump); masm.bind(&goodMul); masm.move32(scratchReg, R0.payloadReg()); break; } case JSOP_DIV: case JSOP_MOD: { // Check for INT_MIN / -1, it results in a double. masm.ma_b(R0.payloadReg(), Imm32(INT_MIN), &divTest1, Assembler::NotEqual, ShortJump); masm.ma_b(R1.payloadReg(), Imm32(-1), &failure, Assembler::Equal, ShortJump); masm.bind(&divTest1); // Check for division by zero masm.ma_b(R1.payloadReg(), Imm32(0), &failure, Assembler::Equal, ShortJump); // Check for 0 / X with X < 0 (results in -0). masm.ma_b(R0.payloadReg(), Imm32(0), &divTest2, Assembler::NotEqual, ShortJump); masm.ma_b(R1.payloadReg(), Imm32(0), &failure, Assembler::LessThan, ShortJump); masm.bind(&divTest2); masm.as_div(R0.payloadReg(), R1.payloadReg()); if (op_ == JSOP_DIV) { // Result is a double if the remainder != 0. masm.as_mfhi(scratchReg); masm.ma_b(scratchReg, Imm32(0), &failure, Assembler::NotEqual, ShortJump); masm.as_mflo(scratchReg); masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); } else { Label done; // If X % Y == 0 and X < 0, the result is -0. masm.as_mfhi(scratchReg); masm.ma_b(scratchReg, Imm32(0), &done, Assembler::NotEqual, ShortJump); masm.ma_b(R0.payloadReg(), Imm32(0), &failure, Assembler::LessThan, ShortJump); masm.bind(&done); masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); } break; } case JSOP_BITOR: masm.ma_or(R0.payloadReg() , R0.payloadReg(), R1.payloadReg()); break; case JSOP_BITXOR: masm.ma_xor(R0.payloadReg() , R0.payloadReg(), R1.payloadReg()); break; case JSOP_BITAND: masm.ma_and(R0.payloadReg() , R0.payloadReg(), R1.payloadReg()); break; case JSOP_LSH: // MIPS will only use 5 lowest bits in R1 as shift offset. masm.ma_sll(R0.payloadReg(), R0.payloadReg(), R1.payloadReg()); break; case JSOP_RSH: masm.ma_sra(R0.payloadReg(), R0.payloadReg(), R1.payloadReg()); break; case JSOP_URSH: masm.ma_srl(scratchReg, R0.payloadReg(), R1.payloadReg()); if (allowDouble_) { Label toUint; masm.ma_b(scratchReg, Imm32(0), &toUint, Assembler::LessThan, ShortJump); // Move result and box for return. masm.move32(scratchReg, R0.payloadReg()); EmitReturnFromIC(masm); masm.bind(&toUint); masm.convertUInt32ToDouble(scratchReg, FloatReg1); masm.boxDouble(FloatReg1, R0); } else { masm.ma_b(scratchReg, Imm32(0), &failure, Assembler::LessThan, ShortJump); // Move result for return. masm.move32(scratchReg, R0.payloadReg()); } break; default: MOZ_ASSUME_UNREACHABLE("Unhandled op for BinaryArith_Int32."); } EmitReturnFromIC(masm); // Failure case - jump to next stub masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
bool ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm) { // Guard that R0 is an integer and R1 is an integer. Label failure; masm.branchTestInt32(Assembler::NotEqual, R0, &failure); masm.branchTestInt32(Assembler::NotEqual, R1, &failure); // Add R0 and R1. Don't need to explicitly unbox, just use R2. Register Rscratch = R2_; ARMRegister Wscratch = ARMRegister(Rscratch, 32); #ifdef MERGE // DIV and MOD need an extra non-volatile ValueOperand to hold R0. AllocatableGeneralRegisterSet savedRegs(availableGeneralRegs(2)); savedRegs.set() = GeneralRegisterSet::Intersect(GeneralRegisterSet::NonVolatile(), savedRegs); #endif // get some more ARM-y names for the registers ARMRegister W0(R0_, 32); ARMRegister X0(R0_, 64); ARMRegister W1(R1_, 32); ARMRegister X1(R1_, 64); ARMRegister WTemp(ExtractTemp0, 32); ARMRegister XTemp(ExtractTemp0, 64); Label maybeNegZero, revertRegister; switch(op_) { case JSOP_ADD: masm.Adds(WTemp, W0, Operand(W1)); // Just jump to failure on overflow. R0 and R1 are preserved, so we can // just jump to the next stub. masm.j(Assembler::Overflow, &failure); // Box the result and return. We know R0 already contains the // integer tag, so we just need to move the payload into place. masm.movePayload(ExtractTemp0, R0_); break; case JSOP_SUB: masm.Subs(WTemp, W0, Operand(W1)); masm.j(Assembler::Overflow, &failure); masm.movePayload(ExtractTemp0, R0_); break; case JSOP_MUL: masm.mul32(R0.valueReg(), R1.valueReg(), Rscratch, &failure, &maybeNegZero); masm.movePayload(Rscratch, R0_); break; case JSOP_DIV: case JSOP_MOD: { // Check for INT_MIN / -1, it results in a double. Label check2; masm.Cmp(W0, Operand(INT_MIN)); masm.B(&check2, Assembler::NotEqual); masm.Cmp(W1, Operand(-1)); masm.j(Assembler::Equal, &failure); masm.bind(&check2); Label no_fail; // Check for both division by zero and 0 / X with X < 0 (results in -0). masm.Cmp(W1, Operand(0)); // If x > 0, then it can't be bad. masm.B(&no_fail, Assembler::GreaterThan); // if x == 0, then ignore any comparison, and force // it to fail, if x < 0 (the only other case) // then do the comparison, and fail if y == 0 masm.Ccmp(W0, Operand(0), vixl::ZFlag, Assembler::NotEqual); masm.B(&failure, Assembler::Equal); masm.bind(&no_fail); masm.Sdiv(Wscratch, W0, W1); // Start calculating the remainder, x - (x / y) * y. masm.mul(WTemp, W1, Wscratch); if (op_ == JSOP_DIV) { // Result is a double if the remainder != 0, which happens // when (x/y)*y != x. masm.branch32(Assembler::NotEqual, R0.valueReg(), ExtractTemp0, &revertRegister); masm.movePayload(Rscratch, R0_); } else { // Calculate the actual mod. Set the condition code, so we can see if it is non-zero. masm.Subs(WTemp, W0, WTemp); // If X % Y == 0 and X < 0, the result is -0. masm.Ccmp(W0, Operand(0), vixl::NoFlag, Assembler::Equal); masm.branch(Assembler::LessThan, &revertRegister); masm.movePayload(ExtractTemp0, R0_); } break; } // ORR, EOR, AND can trivially be coerced int // working without affecting the tag of the dest.. case JSOP_BITOR: masm.Orr(X0, X0, Operand(X1)); break; case JSOP_BITXOR: masm.Eor(X0, X0, Operand(W1, vixl::UXTW)); break; case JSOP_BITAND: masm.And(X0, X0, Operand(X1)); break; // LSH, RSH and URSH can not. case JSOP_LSH: // ARM will happily try to shift by more than 0x1f. masm.Lsl(Wscratch, W0, W1); masm.movePayload(Rscratch, R0.valueReg()); break; case JSOP_RSH: masm.Asr(Wscratch, W0, W1); masm.movePayload(Rscratch, R0.valueReg()); break; case JSOP_URSH: masm.Lsr(Wscratch, W0, W1); if (allowDouble_) { Label toUint; // Testing for negative is equivalent to testing bit 31 masm.Tbnz(Wscratch, 31, &toUint); // Move result and box for return. masm.movePayload(Rscratch, R0_); EmitReturnFromIC(masm); masm.bind(&toUint); masm.convertUInt32ToDouble(Rscratch, ScratchDoubleReg); masm.boxDouble(ScratchDoubleReg, R0, ScratchDoubleReg); } else { // Testing for negative is equivalent to testing bit 31 masm.Tbnz(Wscratch, 31, &failure); // Move result for return. masm.movePayload(Rscratch, R0_); } break; default: MOZ_CRASH("Unhandled op for BinaryArith_Int32."); } EmitReturnFromIC(masm); switch (op_) { case JSOP_MUL: masm.bind(&maybeNegZero); // Result is -0 if exactly one of lhs or rhs is negative. masm.Cmn(W0, W1); masm.j(Assembler::Signed, &failure); // Result is +0, so use the zero register. masm.movePayload(rzr, R0_); EmitReturnFromIC(masm); break; case JSOP_DIV: case JSOP_MOD: masm.bind(&revertRegister); break; default: break; } // Failure case - jump to next stub. masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
bool ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) { // Guard that R0 is an integer and R1 is an integer. Label failure; masm.branchTestInt32(Assembler::NotEqual, R0, &failure); masm.branchTestInt32(Assembler::NotEqual, R1, &failure); // Add R0 and R1. Don't need to explicitly unbox, just use the TailCallReg which // should be available. Register scratchReg = BaselineTailCallReg; Label revertRegister, maybeNegZero; switch(op_) { case JSOP_ADD: // Add R0 and R1. Don't need to explicitly unbox. masm.movl(R0.payloadReg(), scratchReg); masm.addl(R1.payloadReg(), scratchReg); // Just jump to failure on overflow. R0 and R1 are preserved, so we can just jump to // the next stub. masm.j(Assembler::Overflow, &failure); // Just overwrite the payload, the tag is still fine. masm.movl(scratchReg, R0.payloadReg()); break; case JSOP_SUB: masm.movl(R0.payloadReg(), scratchReg); masm.subl(R1.payloadReg(), scratchReg); masm.j(Assembler::Overflow, &failure); masm.movl(scratchReg, R0.payloadReg()); break; case JSOP_MUL: masm.movl(R0.payloadReg(), scratchReg); masm.imull(R1.payloadReg(), scratchReg); masm.j(Assembler::Overflow, &failure); masm.testl(scratchReg, scratchReg); masm.j(Assembler::Zero, &maybeNegZero); masm.movl(scratchReg, R0.payloadReg()); break; case JSOP_DIV: // Prevent division by 0. masm.branchTest32(Assembler::Zero, R1.payloadReg(), R1.payloadReg(), &failure); // Prevent negative 0 and -2147483648 / -1. masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(0x7fffffff), &failure); // For idiv we need eax. JS_ASSERT(R1.typeReg() == eax); masm.movl(R0.payloadReg(), eax); // Preserve R0.payloadReg()/edx, eax is JSVAL_TYPE_INT32. masm.movl(R0.payloadReg(), scratchReg); // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. masm.cdq(); masm.idiv(R1.payloadReg()); // A remainder implies a double result. masm.branchTest32(Assembler::NonZero, edx, edx, &revertRegister); masm.movl(eax, R0.payloadReg()); break; case JSOP_MOD: { // x % 0 always results in NaN. masm.branchTest32(Assembler::Zero, R1.payloadReg(), R1.payloadReg(), &failure); // Prevent negative 0 and -2147483648 % -1. masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(0x7fffffff), &failure); // For idiv we need eax. JS_ASSERT(R1.typeReg() == eax); masm.movl(R0.payloadReg(), eax); // Preserve R0.payloadReg()/edx, eax is JSVAL_TYPE_INT32. masm.movl(R0.payloadReg(), scratchReg); // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. masm.cdq(); masm.idiv(R1.payloadReg()); // Fail when we would need a negative remainder. Label done; masm.branchTest32(Assembler::NonZero, edx, edx, &done); masm.branchTest32(Assembler::Signed, scratchReg, scratchReg, &revertRegister); masm.branchTest32(Assembler::Signed, R1.payloadReg(), R1.payloadReg(), &revertRegister); masm.bind(&done); // Result is in edx, tag in ecx remains untouched. JS_ASSERT(R0.payloadReg() == edx); JS_ASSERT(R0.typeReg() == ecx); break; } case JSOP_BITOR: // We can overide R0, because the instruction is unfailable. // The R0.typeReg() is also still intact. masm.orl(R1.payloadReg(), R0.payloadReg()); break; case JSOP_BITXOR: masm.xorl(R1.payloadReg(), R0.payloadReg()); break; case JSOP_BITAND: masm.andl(R1.payloadReg(), R0.payloadReg()); break; case JSOP_LSH: // RHS needs to be in ecx for shift operations. JS_ASSERT(R0.typeReg() == ecx); masm.movl(R1.payloadReg(), ecx); masm.shll_cl(R0.payloadReg()); // We need to tag again, because we overwrote it. masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); break; case JSOP_RSH: masm.movl(R1.payloadReg(), ecx); masm.sarl_cl(R0.payloadReg()); masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); break; case JSOP_URSH: if (!allowDouble_) masm.movl(R0.payloadReg(), scratchReg); masm.movl(R1.payloadReg(), ecx); masm.shrl_cl(R0.payloadReg()); masm.testl(R0.payloadReg(), R0.payloadReg()); if (allowDouble_) { Label toUint; masm.j(Assembler::Signed, &toUint); // Box and return. masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); EmitReturnFromIC(masm); masm.bind(&toUint); masm.convertUInt32ToDouble(R0.payloadReg(), ScratchFloatReg); masm.boxDouble(ScratchFloatReg, R0); } else { masm.j(Assembler::Signed, &revertRegister); masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); } break; default: MOZ_ASSUME_UNREACHABLE("Unhandled op for BinaryArith_Int32. "); } // Return. EmitReturnFromIC(masm); switch(op_) { case JSOP_MUL: masm.bind(&maybeNegZero); // Result is -0 if exactly one of lhs or rhs is negative. masm.movl(R0.payloadReg(), scratchReg); masm.orl(R1.payloadReg(), scratchReg); masm.j(Assembler::Signed, &failure); // Result is +0. masm.xorl(R0.payloadReg(), R0.payloadReg()); EmitReturnFromIC(masm); break; case JSOP_DIV: case JSOP_MOD: masm.bind(&revertRegister); masm.movl(scratchReg, R0.payloadReg()); masm.movl(ImmType(JSVAL_TYPE_INT32), R1.typeReg()); break; case JSOP_URSH: // Revert the content of R0 in the fallible >>> case. if (!allowDouble_) { masm.bind(&revertRegister); masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); } break; default: // No special failure handling required. // Fall through to failure. break; } // Failure case - jump to next stub masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
bool ICCompare_Double::Compiler::generateStubCode(MacroAssembler &masm) { // by wangqing, 2013-11-28 Label failure, notNaN, isTrue; /* if R0 is a double, load it into dest. If R0 is int32, convert it to double. Else, branch to failure. by wangqing, 2013-11-28 */ Label isDouble, done; masm.movl(ImmTag(JSVAL_TAG_CLEAR), cmpTempRegister); masm.sltu(cmpTempRegister, R0.typeReg(), cmpTempRegister); masm.bgtz(cmpTempRegister, &isDouble); masm.nop(); masm.movl(ImmTag(JSVAL_TAG_INT32), cmpTempRegister); masm.bne(R0.typeReg(), cmpTempRegister, &failure); masm.nop(); masm.convertInt32ToDouble(R0.payloadReg(), FloatReg0); masm.b(&done); masm.nop(); masm.bindBranch(&isDouble); masm.unboxDouble(R0, FloatReg0); masm.bindBranch(&done); /* if R1 is a double, load it into dest. If R1 is int32, convert it to double. Else, branch to failure. by wangqing, 2013-11-28 */ Label isDouble1, done1; masm.movl(ImmTag(JSVAL_TAG_CLEAR), cmpTempRegister); masm.sltu(cmpTempRegister, R1.typeReg(), cmpTempRegister); masm.bgtz(cmpTempRegister, &isDouble1); masm.nop(); masm.movl(ImmTag(JSVAL_TAG_INT32), cmpTempRegister); masm.bne(R1.typeReg(), cmpTempRegister, &failure); masm.nop(); masm.convertInt32ToDouble(R1.payloadReg(), FloatReg1); masm.b(&done1); masm.nop(); masm.bindBranch(&isDouble1); masm.unboxDouble(R1, FloatReg1); masm.bindBranch(&done1); Register dest = R0.scratchReg(); Assembler::DoubleCondition cond = JSOpToDoubleCondition(op); masm.addiu(dest, zero, 1); masm.branchDoubleLocal(cond, FloatReg0, FloatReg1, &isTrue); masm.xorl(dest, dest); masm.bindBranch(&isTrue); // Check for NaN, if needed. Assembler::NaNCond nanCond = Assembler::NaNCondFromDoubleCondition(cond); if (nanCond != Assembler::NaN_HandledByCond) { // check DoubleOrdered, by wangqing, 2013-11-28 masm.cud(FloatReg0, FloatReg1); masm.bc1f(¬NaN); masm.nop(); masm.mov(Imm32(nanCond == Assembler::NaN_IsTrue), dest); masm.bindBranch(¬NaN); } masm.tagValue(JSVAL_TYPE_BOOLEAN, dest, R0); EmitReturnFromIC(masm); // Failure case - jump to next stub masm.bindBranch(&failure); EmitStubGuardFailure(masm); return true; }
// ICBinaryArith_Int32 // by wangqing, 2013-11-22 bool ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) { // Guard that R0 is an integer and R1 is an integer. Label failure; masm.movl(ImmTag(JSVAL_TAG_INT32), cmpTempRegister); masm.bne(R0.typeReg(), cmpTempRegister, &failure); masm.nop(); masm.movl(ImmTag(JSVAL_TAG_INT32), cmpTempRegister); masm.bne(R1.typeReg(), cmpTempRegister, &failure); masm.nop(); // Add R0 and R1. Don't need to explicitly unbox, just use the TailCallReg which // should be available. Register scratchReg = BaselineTailCallReg; Label revertRegister, maybeNegZero; // xsb:fix me // fixed by weizhenwei, 2013.11.05 switch(op_) { case JSOP_ADD: // Add R0 and R1. Don't need to explicitly unbox. // mov tow oprand to cmp registers to prepared for Overflow check. masm.cmpl(R0.payloadReg(), R1.payloadReg()); masm.negl(cmpTemp2Register); // do the add masm.movl(R0.payloadReg(), scratchReg); masm.addl(R1.payloadReg(), scratchReg); // Just jump to failure on overflow. R0 and R1 are preserved, so we can just jump to // the next stub. masm.xorInsn(dataTempRegister, cmpTempRegister, cmpTemp2Register); masm.bgez(dataTempRegister, 7); masm.nop(); masm.subu(dataTempRegister, cmpTempRegister, cmpTemp2Register); masm.xorInsn(dataTempRegister, dataTempRegister, cmpTempRegister); masm.bgez(dataTempRegister, 3); masm.nop(); masm.b(&failure); masm.nop(); // Just overwrite the payload, the tag is still fine. masm.movl(scratchReg, R0.payloadReg()); break; case JSOP_SUB: masm.cmpl(R0.payloadReg(), R1.payloadReg()); masm.movl(R0.payloadReg(), scratchReg); masm.subl(R1.payloadReg(), scratchReg); // jump to failure on overflow, by wangqing, 2013-11-22 masm.xorInsn(dataTempRegister, cmpTempRegister, cmpTemp2Register); masm.bgez(dataTempRegister, 7); masm.nop(); masm.subu(dataTempRegister, cmpTempRegister, cmpTemp2Register); masm.xorInsn(dataTempRegister, dataTempRegister, cmpTempRegister); masm.bgez(dataTempRegister, 3); masm.nop(); masm.b(&failure); masm.nop(); masm.movl(scratchReg, R0.payloadReg()); break; case JSOP_MUL: masm.movl(R0.payloadReg(), scratchReg); masm.imull(R1.payloadReg(), scratchReg); // test whether signed multiply overflow. by weizhenwei, 2013.11.01 masm.mfhi(cmpTempRegister); masm.mflo(cmpTemp2Register); masm.sarl(Imm32(0x1f), cmpTemp2Register); masm.bne(cmpTempRegister, cmpTemp2Register, &failure); masm.nop(); masm.beq(scratchReg, zero, &maybeNegZero); masm.nop(); masm.movl(scratchReg, R0.payloadReg()); break; case JSOP_DIV: // Prevent division by 0. masm.beq(R1.payloadReg(), zero, &failure); masm.nop(); // Prevent negative 0 and -2147483648 / -1. /* rewrite testl(reg, imm), avoid use cmpTemp2Register by wangqing, 2013-11-22*/ masm.movl(R0.payloadReg(), cmpTempRegister); masm.andl(Imm32(0x7fffffff), cmpTempRegister); masm.beq(cmpTempRegister, zero, &failure); masm.nop(); // Preserve R0.payloadReg() masm.div(R0.payloadReg(), R1.payloadReg()); // A remainder implies a double result. // by weizhenwei, 2013.11.02 masm.mfhi(cmpTempRegister); masm.bne(cmpTempRegister, zero, &failure); masm.nop(); // by weizhenwei, 2013.11.05 masm.mflo(R0.payloadReg()); break; case JSOP_MOD: { // x % 0 always results in NaN. masm.beq(R1.payloadReg(), zero, &failure); masm.nop(); // Prevent negative 0 and -2147483648 % -1. /* rewrite testl(reg, imm), avoid use cmpTemp2Register by wangqing, 2013-11-22*/ masm.movl(R0.payloadReg(), cmpTempRegister); masm.andl(Imm32(0x7fffffff), cmpTempRegister); masm.beq(cmpTempRegister, zero, &failure); masm.nop(); masm.div(R0.payloadReg(), R1.payloadReg()); // Fail when we would need a negative remainder. Label done; masm.mfhi(cmpTempRegister); masm.bne(cmpTempRegister, zero, &done); masm.nop(); masm.bltz(R0.payloadReg(), &failure); masm.nop(); masm.bltz(R1.payloadReg(), &failure); masm.nop(); masm.bindBranch(&done); //move reminder to R0.payloadReg, by weizhenwei, 2013.11.05 masm.mfhi(R0.payloadReg()); break; } case JSOP_BITOR: // We can overide R0, because the instruction is unfailable. // The R0.typeReg() is also still intact. masm.orl(R1.payloadReg(), R0.payloadReg()); break; case JSOP_BITXOR: masm.xorl(R1.payloadReg(), R0.payloadReg()); break; case JSOP_BITAND: masm.andl(R1.payloadReg(), R0.payloadReg()); break; case JSOP_LSH: // R0.payloadReg() is result, R1.payloadReg90 is shiftAmount. // rewrite by weizhenwei, 2013.11.06 masm.sllv(R0.payloadReg(), R0.payloadReg(), R1.payloadReg()); // We need to tag again, because we overwrote it. masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); break; case JSOP_RSH: // R0.payloadReg() is result, R1.payloadReg90 is shiftAmount. // rewrite by weizhenwei, 2013.11.06 masm.srav(R0.payloadReg(), R0.payloadReg(), R1.payloadReg()); // We need to tag again, because we overwrote it. masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); break; case JSOP_URSH: if (!allowDouble_) masm.movl(R0.payloadReg(), scratchReg); // R0.payloadReg() is result, R1.payloadReg() is shiftAmount. // rewrite by weizhenwei, 2013.11.06 masm.srlv(R0.payloadReg(), R0.payloadReg(), R1.payloadReg()); // by wangqing. 2013-11-22 if (allowDouble_) { Label toUint; masm.bltz(R0.payloadReg(),&toUint); masm.nop(); // Box and return. masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); EmitReturnFromIC(masm); masm.bindBranch(&toUint); masm.convertUInt32ToDouble(R0.payloadReg(), ScratchFloatReg); masm.boxDouble(ScratchFloatReg, R0); } else { masm.bltz(R0.payloadReg(),&revertRegister); masm.nop(); masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); } break; default: JS_NOT_REACHED("Unhandled op for BinaryArith_Int32. "); return false; } // Return. EmitReturnFromIC(masm); switch(op_) { case JSOP_MUL: masm.bindBranch(&maybeNegZero); // Result is -0 if exactly one of lhs or rhs is negative. masm.movl(R0.payloadReg(), scratchReg); masm.orl(R1.payloadReg(), scratchReg); //add by QuQiuwen; masm.bltz(scratchReg, &failure); masm.nop(); // Result is +0. masm.xorl(R0.payloadReg(), R0.payloadReg()); EmitReturnFromIC(masm); break; case JSOP_URSH: // Revert the content of R0 in the fallible >>> case. if (!allowDouble_) { masm.bindBranch(&revertRegister); masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); } break; default: // No special failure handling required. // Fall through to failure. break; } // Failure case - jump to next stub masm.bindBranch(&failure); EmitStubGuardFailure(masm); return true; }