📄 jitarithmetic.cpp
字号:
return check.present;}#endifvoid JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes types){ Structure* numberStructure = m_globalData->numberStructure.get(); JmpSrc wasJSNumberCell1; JmpSrc wasJSNumberCell2; emitGetVirtualRegisters(src1, X86::eax, src2, X86::edx); if (types.second().isReusable() && isSSE2Present()) { ASSERT(types.second().mightBeNumber()); // Check op2 is a number __ testl_i32r(JSImmediate::TagTypeNumber, X86::edx); JmpSrc op2imm = __ jne(); if (!types.second().definitelyIsNumber()) { emitJumpSlowCaseIfNotJSCell(X86::edx, src2); __ cmpl_im(reinterpret_cast<unsigned>(numberStructure), FIELD_OFFSET(JSCell, m_structure), X86::edx); addSlowCase(__ jne()); } // (1) In this case src2 is a reusable number cell. // Slow case if src1 is not a number type. __ testl_i32r(JSImmediate::TagTypeNumber, X86::eax); JmpSrc op1imm = __ jne(); if (!types.first().definitelyIsNumber()) { emitJumpSlowCaseIfNotJSCell(X86::eax, src1); __ cmpl_im(reinterpret_cast<unsigned>(numberStructure), FIELD_OFFSET(JSCell, m_structure), X86::eax); addSlowCase(__ jne()); } // (1a) if we get here, src1 is also a number cell __ movsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::eax, X86::xmm0); JmpSrc loadedDouble = __ jmp(); // (1b) if we get here, src1 is an immediate __ linkJump(op1imm, __ label()); emitFastArithImmToInt(X86::eax); __ cvtsi2sd_rr(X86::eax, X86::xmm0); // (1c) __ linkJump(loadedDouble, __ label()); if (opcodeID == op_add) __ addsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm0); else if (opcodeID == op_sub) __ subsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm0); else { ASSERT(opcodeID == op_mul); __ mulsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm0); } // Store the result to the JSNumberCell and jump. __ movsd_rm(X86::xmm0, FIELD_OFFSET(JSNumberCell, m_value), X86::edx); __ movl_rr(X86::edx, X86::eax); emitPutVirtualRegister(dst); wasJSNumberCell2 = __ jmp(); // (2) This handles cases where src2 is an immediate number. // Two slow cases - either src1 isn't an immediate, or the subtract overflows. __ linkJump(op2imm, __ label()); emitJumpSlowCaseIfNotImmediateInteger(X86::eax); } else if (types.first().isReusable() && isSSE2Present()) { ASSERT(types.first().mightBeNumber()); // Check op1 is a number __ testl_i32r(JSImmediate::TagTypeNumber, X86::eax); JmpSrc op1imm = __ jne(); if (!types.first().definitelyIsNumber()) { emitJumpSlowCaseIfNotJSCell(X86::eax, src1); __ cmpl_im(reinterpret_cast<unsigned>(numberStructure), FIELD_OFFSET(JSCell, m_structure), X86::eax); addSlowCase(__ jne()); } // (1) In this case src1 is a reusable number cell. // Slow case if src2 is not a number type. __ testl_i32r(JSImmediate::TagTypeNumber, X86::edx); JmpSrc op2imm = __ jne(); if (!types.second().definitelyIsNumber()) { emitJumpSlowCaseIfNotJSCell(X86::edx, src2); __ cmpl_im(reinterpret_cast<unsigned>(numberStructure), FIELD_OFFSET(JSCell, m_structure), X86::edx); addSlowCase(__ jne()); } // (1a) if we get here, src2 is also a number cell __ movsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm1); JmpSrc loadedDouble = __ jmp(); // (1b) if we get here, src2 is an immediate __ linkJump(op2imm, __ label()); emitFastArithImmToInt(X86::edx); __ cvtsi2sd_rr(X86::edx, X86::xmm1); // (1c) __ linkJump(loadedDouble, __ label()); __ movsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::eax, X86::xmm0); if (opcodeID == op_add) __ addsd_rr(X86::xmm1, X86::xmm0); else if (opcodeID == op_sub) __ subsd_rr(X86::xmm1, X86::xmm0); else { ASSERT(opcodeID == op_mul); __ mulsd_rr(X86::xmm1, X86::xmm0); } __ movsd_rm(X86::xmm0, FIELD_OFFSET(JSNumberCell, m_value), X86::eax); emitPutVirtualRegister(dst); // Store the result to the JSNumberCell and jump. __ movsd_rm(X86::xmm0, FIELD_OFFSET(JSNumberCell, m_value), X86::eax); emitPutVirtualRegister(dst); wasJSNumberCell1 = __ jmp(); // (2) This handles cases where src1 is an immediate number. // Two slow cases - either src2 isn't an immediate, or the subtract overflows. __ linkJump(op1imm, __ label()); emitJumpSlowCaseIfNotImmediateInteger(X86::edx); } else emitJumpSlowCaseIfNotImmediateIntegers(X86::eax, X86::edx, X86::ecx); if (opcodeID == op_add) { emitFastArithDeTagImmediate(X86::eax); __ addl_rr(X86::edx, X86::eax); addSlowCase(__ jo()); } else if (opcodeID == op_sub) { __ subl_rr(X86::edx, X86::eax); addSlowCase(__ jo()); signExtend32ToPtr(X86::eax, X86::eax); emitFastArithReTagImmediate(X86::eax, X86::eax); } else { ASSERT(opcodeID == op_mul); // convert eax & edx from JSImmediates to ints, and check if either are zero emitFastArithImmToInt(X86::edx); Jump op1Zero = emitFastArithDeTagImmediateJumpIfZero(X86::eax); __ testl_rr(X86::edx, X86::edx); JmpSrc op2NonZero = __ jne(); op1Zero.link(this); // if either input is zero, add the two together, and check if the result is < 0. // If it is, we have a problem (N < 0), (N * 0) == -0, not representatble as a JSImmediate. __ movl_rr(X86::eax, X86::ecx); __ addl_rr(X86::edx, X86::ecx); addSlowCase(__ js()); // Skip the above check if neither input is zero __ linkJump(op2NonZero, __ label()); __ imull_rr(X86::edx, X86::eax); addSlowCase(__ jo()); signExtend32ToPtr(X86::eax, X86::eax); emitFastArithReTagImmediate(X86::eax, X86::eax); } emitPutVirtualRegister(dst); if (types.second().isReusable() && isSSE2Present()) { __ linkJump(wasJSNumberCell2, __ label()); } else if (types.first().isReusable() && isSSE2Present()) { __ linkJump(wasJSNumberCell1, __ label()); }}void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes types){ linkSlowCase(iter); if (types.second().isReusable() && isSSE2Present()) { if (!types.first().definitelyIsNumber()) { linkSlowCaseIfNotJSCell(iter, src1); linkSlowCase(iter); } if (!types.second().definitelyIsNumber()) { linkSlowCaseIfNotJSCell(iter, src2); linkSlowCase(iter); } } else if (types.first().isReusable() && isSSE2Present()) { if (!types.first().definitelyIsNumber()) { linkSlowCaseIfNotJSCell(iter, src1); linkSlowCase(iter); } if (!types.second().definitelyIsNumber()) { linkSlowCaseIfNotJSCell(iter, src2); linkSlowCase(iter); } } linkSlowCase(iter); // additional entry point to handle -0 cases. if (opcodeID == op_mul) linkSlowCase(iter); emitPutJITStubArgFromVirtualRegister(src1, 1, X86::ecx); emitPutJITStubArgFromVirtualRegister(src2, 2, X86::ecx); if (opcodeID == op_add) emitCTICall(JITStubs::cti_op_add); else if (opcodeID == op_sub) emitCTICall(JITStubs::cti_op_sub); else { ASSERT(opcodeID == op_mul); emitCTICall(JITStubs::cti_op_mul); } emitPutVirtualRegister(dst);}void JIT::compileFastArith_op_add(Instruction* currentInstruction){ unsigned result = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; if (isOperandConstantImmediateInt(op1)) { emitGetVirtualRegister(op2, X86::eax); emitJumpSlowCaseIfNotImmediateInteger(X86::eax); addSlowCase(branchAdd32(Overflow, Imm32(getConstantOperandImmediateInt(op1) << JSImmediate::IntegerPayloadShift), X86::eax)); signExtend32ToPtr(X86::eax, X86::eax); emitPutVirtualRegister(result); } else if (isOperandConstantImmediateInt(op2)) { emitGetVirtualRegister(op1, X86::eax); emitJumpSlowCaseIfNotImmediateInteger(X86::eax); addSlowCase(branchAdd32(Overflow, Imm32(getConstantOperandImmediateInt(op2) << JSImmediate::IntegerPayloadShift), X86::eax)); signExtend32ToPtr(X86::eax, X86::eax); emitPutVirtualRegister(result); } else { OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); if (types.first().mightBeNumber() && types.second().mightBeNumber()) compileBinaryArithOp(op_add, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand)); else { emitPutJITStubArgFromVirtualRegister(op1, 1, X86::ecx); emitPutJITStubArgFromVirtualRegister(op2, 2, X86::ecx); emitCTICall(JITStubs::cti_op_add); emitPutVirtualRegister(result); } }}void JIT::compileFastArithSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter){ unsigned result = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; if (isOperandConstantImmediateInt(op1)) { Jump notImm = getSlowCase(iter); linkSlowCase(iter); sub32(Imm32(getConstantOperandImmediateInt(op1) << JSImmediate::IntegerPayloadShift), X86::eax); notImm.link(this); emitPutJITStubArgFromVirtualRegister(op1, 1, X86::ecx); emitPutJITStubArg(X86::eax, 2); emitCTICall(JITStubs::cti_op_add); emitPutVirtualRegister(result); } else if (isOperandConstantImmediateInt(op2)) { Jump notImm = getSlowCase(iter); linkSlowCase(iter); sub32(Imm32(getConstantOperandImmediateInt(op2) << JSImmediate::IntegerPayloadShift), X86::eax); notImm.link(this); emitPutJITStubArg(X86::eax, 1); emitPutJITStubArgFromVirtualRegister(op2, 2, X86::ecx); emitCTICall(JITStubs::cti_op_add); emitPutVirtualRegister(result); } else { OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); ASSERT(types.first().mightBeNumber() && types.second().mightBeNumber()); compileBinaryArithOpSlowCase(op_add, iter, result, op1, op2, types); }}void JIT::compileFastArith_op_mul(Instruction* currentInstruction){ unsigned result = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; // For now, only plant a fast int case if the constant operand is greater than zero. int32_t value; if (isOperandConstantImmediateInt(op1) && ((value = getConstantOperandImmediateInt(op1)) > 0)) { emitGetVirtualRegister(op2, X86::eax); emitJumpSlowCaseIfNotImmediateInteger(X86::eax); emitFastArithDeTagImmediate(X86::eax); addSlowCase(branchMul32(Overflow, Imm32(value), X86::eax, X86::eax)); signExtend32ToPtr(X86::eax, X86::eax); emitFastArithReTagImmediate(X86::eax, X86::eax); emitPutVirtualRegister(result); } else if (isOperandConstantImmediateInt(op2) && ((value = getConstantOperandImmediateInt(op2)) > 0)) { emitGetVirtualRegister(op1, X86::eax); emitJumpSlowCaseIfNotImmediateInteger(X86::eax); emitFastArithDeTagImmediate(X86::eax); addSlowCase(branchMul32(Overflow, Imm32(value), X86::eax, X86::eax)); signExtend32ToPtr(X86::eax, X86::eax); emitFastArithReTagImmediate(X86::eax, X86::eax); emitPutVirtualRegister(result); } else compileBinaryArithOp(op_mul, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand));}void JIT::compileFastArithSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter){ unsigned result = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; if ((isOperandConstantImmediateInt(op1) && (getConstantOperandImmediateInt(op1) > 0)) || (isOperandConstantImmediateInt(op2) && (getConstantOperandImmediateInt(op2) > 0))) { linkSlowCase(iter); linkSlowCase(iter); // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0. emitPutJITStubArgFromVirtualRegister(op1, 1, X86::ecx); emitPutJITStubArgFromVirtualRegister(op2, 2, X86::ecx); emitCTICall(JITStubs::cti_op_mul); emitPutVirtualRegister(result); } else compileBinaryArithOpSlowCase(op_mul, iter, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand));}void JIT::compileFastArith_op_sub(Instruction* currentInstruction){ compileBinaryArithOp(op_sub, currentInstruction[1].u.operand, currentInstruction[2].u.operand, currentInstruction[3].u.operand, OperandTypes::fromInt(currentInstruction[4].u.operand));}void JIT::compileFastArithSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter){ compileBinaryArithOpSlowCase(op_sub, iter, currentInstruction[1].u.operand, currentInstruction[2].u.operand, currentInstruction[3].u.operand, OperandTypes::fromInt(currentInstruction[4].u.operand));}#endif} // namespace JSC#endif // ENABLE(JIT)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -