void JIT::emit_op_div(Instruction* currentInstruction) { unsigned dst = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); if (isOperandConstantImmediateDouble(op1)) { emitGetVirtualRegister(op1, regT0); addPtr(tagTypeNumberRegister, regT0); movePtrToDouble(regT0, fpRegT0); } else if (isOperandConstantImmediateInt(op1)) { emitLoadInt32ToDouble(op1, fpRegT0); } else { emitGetVirtualRegister(op1, regT0); if (!types.first().definitelyIsNumber()) emitJumpSlowCaseIfNotImmediateNumber(regT0); Jump notInt = emitJumpIfNotImmediateInteger(regT0); convertInt32ToDouble(regT0, fpRegT0); Jump skipDoubleLoad = jump(); notInt.link(this); addPtr(tagTypeNumberRegister, regT0); movePtrToDouble(regT0, fpRegT0); skipDoubleLoad.link(this); } if (isOperandConstantImmediateDouble(op2)) { emitGetVirtualRegister(op2, regT1); addPtr(tagTypeNumberRegister, regT1); movePtrToDouble(regT1, fpRegT1); } else if (isOperandConstantImmediateInt(op2)) { emitLoadInt32ToDouble(op2, fpRegT1); } else { emitGetVirtualRegister(op2, regT1); if (!types.second().definitelyIsNumber()) emitJumpSlowCaseIfNotImmediateNumber(regT1); Jump notInt = emitJumpIfNotImmediateInteger(regT1); convertInt32ToDouble(regT1, fpRegT1); Jump skipDoubleLoad = jump(); notInt.link(this); addPtr(tagTypeNumberRegister, regT1); movePtrToDouble(regT1, fpRegT1); skipDoubleLoad.link(this); } divDouble(fpRegT1, fpRegT0); // Double result. moveDoubleToPtr(fpRegT0, regT0); subPtr(tagTypeNumberRegister, regT0); emitPutVirtualRegister(dst, regT0); }
void JITCompiler::jumpFromSpeculativeToNonSpeculative(const SpeculationCheck& check, const EntryLocation& entry, SpeculationRecovery* recovery) { ASSERT(check.m_nodeIndex == entry.m_nodeIndex); // Link the jump from the Speculative path to here. check.m_check.link(this); // Does this speculation check require any additional recovery to be performed, // to restore any state that has been overwritten before we enter back in to the // non-speculative path. if (recovery) { // The only additional recovery we currently support is for integer add operation ASSERT(recovery->type() == SpeculativeAdd); // Revert the add. sub32(recovery->src(), recovery->dest()); } // FIXME: - This is hideously inefficient! // Where a value is live in a register in the speculative path, and is required in a register // on the non-speculative path, we should not need to be spilling it and reloading (we may // need to spill anyway, if the value is marked as spilled on the non-speculative path). // This may also be spilling values that don't need spilling, e.g. are already spilled, // are constants, or are arguments. // Spill all GPRs in use by the speculative path. for (unsigned index = 0; index < GPRInfo::numberOfRegisters; ++index) { NodeIndex nodeIndex = check.m_gprInfo[index].nodeIndex; if (nodeIndex == NoNode) continue; DataFormat dataFormat = check.m_gprInfo[index].format; VirtualRegister virtualRegister = graph()[nodeIndex].virtualRegister(); ASSERT(dataFormat == DataFormatInteger || DataFormatCell || dataFormat & DataFormatJS); if (dataFormat == DataFormatInteger) orPtr(GPRInfo::tagTypeNumberRegister, GPRInfo::toRegister(index)); storePtr(GPRInfo::toRegister(index), addressFor(virtualRegister)); } // Spill all FPRs in use by the speculative path. for (unsigned index = 0; index < FPRInfo::numberOfRegisters; ++index) { NodeIndex nodeIndex = check.m_fprInfo[index]; if (nodeIndex == NoNode) continue; VirtualRegister virtualRegister = graph()[nodeIndex].virtualRegister(); moveDoubleToPtr(FPRInfo::toRegister(index), GPRInfo::regT0); subPtr(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0); storePtr(GPRInfo::regT0, addressFor(virtualRegister)); } // Fill all FPRs in use by the non-speculative path. for (unsigned index = 0; index < FPRInfo::numberOfRegisters; ++index) { NodeIndex nodeIndex = entry.m_fprInfo[index]; if (nodeIndex == NoNode) continue; fillNumericToDouble(nodeIndex, FPRInfo::toRegister(index), GPRInfo::regT0); } // Fill all GPRs in use by the non-speculative path. for (unsigned index = 0; index < GPRInfo::numberOfRegisters; ++index) { NodeIndex nodeIndex = entry.m_gprInfo[index].nodeIndex; if (nodeIndex == NoNode) continue; DataFormat dataFormat = entry.m_gprInfo[index].format; if (dataFormat == DataFormatInteger) fillInt32ToInteger(nodeIndex, GPRInfo::toRegister(index)); else { ASSERT(dataFormat & DataFormatJS || dataFormat == DataFormatCell); // Treat cell as TiValue for now! fillToJS(nodeIndex, GPRInfo::toRegister(index)); // FIXME: For subtypes of DataFormatJS, should jitAssert the subtype? } } // Jump into the non-speculative path. jump(entry.m_entry); }
void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned result, unsigned op1, unsigned op2, OperandTypes types, bool op1HasImmediateIntFastCase, bool op2HasImmediateIntFastCase) { // We assume that subtracting TagTypeNumber is equivalent to adding DoubleEncodeOffset. COMPILE_ASSERT(((JSImmediate::TagTypeNumber + JSImmediate::DoubleEncodeOffset) == 0), TagTypeNumber_PLUS_DoubleEncodeOffset_EQUALS_0); Jump notImm1; Jump notImm2; if (op1HasImmediateIntFastCase) { notImm2 = getSlowCase(iter); } else if (op2HasImmediateIntFastCase) { notImm1 = getSlowCase(iter); } else { notImm1 = getSlowCase(iter); notImm2 = getSlowCase(iter); } linkSlowCase(iter); // Integer overflow case - we could handle this in JIT code, but this is likely rare. if (opcodeID == op_mul && !op1HasImmediateIntFastCase && !op2HasImmediateIntFastCase) // op_mul has an extra slow case to handle 0 * negative number. linkSlowCase(iter); emitGetVirtualRegister(op1, regT0); Label stubFunctionCall(this); JITStubCall stubCall(this, opcodeID == op_add ? cti_op_add : opcodeID == op_sub ? cti_op_sub : cti_op_mul); if (op1HasImmediateIntFastCase || op2HasImmediateIntFastCase) { emitGetVirtualRegister(op1, regT0); emitGetVirtualRegister(op2, regT1); } stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(result); Jump end = jump(); if (op1HasImmediateIntFastCase) { notImm2.link(this); if (!types.second().definitelyIsNumber()) emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this); emitGetVirtualRegister(op1, regT1); convertInt32ToDouble(regT1, fpRegT1); addPtr(tagTypeNumberRegister, regT0); movePtrToDouble(regT0, fpRegT2); } else if (op2HasImmediateIntFastCase) { notImm1.link(this); if (!types.first().definitelyIsNumber()) emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this); emitGetVirtualRegister(op2, regT1); convertInt32ToDouble(regT1, fpRegT1); addPtr(tagTypeNumberRegister, regT0); movePtrToDouble(regT0, fpRegT2); } else { // if we get here, eax is not an int32, edx not yet checked. notImm1.link(this); if (!types.first().definitelyIsNumber()) emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this); if (!types.second().definitelyIsNumber()) emitJumpIfNotImmediateNumber(regT1).linkTo(stubFunctionCall, this); addPtr(tagTypeNumberRegister, regT0); movePtrToDouble(regT0, fpRegT1); Jump op2isDouble = emitJumpIfNotImmediateInteger(regT1); convertInt32ToDouble(regT1, fpRegT2); Jump op2wasInteger = jump(); // if we get here, eax IS an int32, edx is not. notImm2.link(this); if (!types.second().definitelyIsNumber()) emitJumpIfNotImmediateNumber(regT1).linkTo(stubFunctionCall, this); convertInt32ToDouble(regT0, fpRegT1); op2isDouble.link(this); addPtr(tagTypeNumberRegister, regT1); movePtrToDouble(regT1, fpRegT2); op2wasInteger.link(this); } if (opcodeID == op_add) addDouble(fpRegT2, fpRegT1); else if (opcodeID == op_sub) subDouble(fpRegT2, fpRegT1); else if (opcodeID == op_mul) mulDouble(fpRegT2, fpRegT1); else { ASSERT(opcodeID == op_div); divDouble(fpRegT2, fpRegT1); } moveDoubleToPtr(fpRegT1, regT0); subPtr(tagTypeNumberRegister, regT0); emitPutVirtualRegister(result, regT0); end.link(this); }