void JIT::emit_op_rshift(Instruction* currentInstruction) { unsigned result = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; if (isOperandConstantImmediateInt(op2)) { // isOperandConstantImmediateInt(op2) => 1 SlowCase emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); // Mask with 0x1f as per ecma-262 11.7.2 step 7. rshift32(Imm32(getConstantOperandImmediateInt(op2) & 0x1f), regT0); } else { emitGetVirtualRegisters(op1, regT0, op2, regT2); if (supportsFloatingPointTruncate()) { Jump lhsIsInt = emitJumpIfImmediateInteger(regT0); // supportsFloatingPoint() && USE(JSVALUE64) => 3 SlowCases addSlowCase(emitJumpIfNotImmediateNumber(regT0)); addPtr(tagTypeNumberRegister, regT0); movePtrToDouble(regT0, fpRegT0); addSlowCase(branchTruncateDoubleToInt32(fpRegT0, regT0)); lhsIsInt.link(this); emitJumpSlowCaseIfNotImmediateInteger(regT2); } else { // !supportsFloatingPoint() => 2 SlowCases emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT2); } emitFastArithImmToInt(regT2); rshift32(regT2, regT0); } emitFastArithIntToImmNoCheck(regT0, regT0); emitPutVirtualRegister(result); }
void JIT::emit_op_bitand(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, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); int32_t imm = getConstantOperandImmediateInt(op1); andPtr(Imm32(imm), regT0); if (imm >= 0) emitFastArithIntToImmNoCheck(regT0, regT0); } else if (isOperandConstantImmediateInt(op2)) { emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); int32_t imm = getConstantOperandImmediateInt(op2); andPtr(Imm32(imm), regT0); if (imm >= 0) emitFastArithIntToImmNoCheck(regT0, regT0); } else { emitGetVirtualRegisters(op1, regT0, op2, regT1); andPtr(regT1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); } emitPutVirtualRegister(result); }
void JIT::emit_op_urshift(Instruction* currentInstruction) { unsigned dst = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; // Slow case of urshift makes assumptions about what registers hold the // shift arguments, so any changes must be updated there as well. if (isOperandConstantImmediateInt(op2)) { emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitFastArithImmToInt(regT0); int shift = getConstantOperand(op2).asInt32(); if (shift) urshift32(Imm32(shift & 0x1f), regT0); // unsigned shift < 0 or shift = k*2^32 may result in (essentially) // a toUint conversion, which can result in a value we can represent // as an immediate int. if (shift < 0 || !(shift & 31)) addSlowCase(branch32(LessThan, regT0, Imm32(0))); emitFastArithReTagImmediate(regT0, regT0); emitPutVirtualRegister(dst, regT0); return; } emitGetVirtualRegisters(op1, regT0, op2, regT1); if (!isOperandConstantImmediateInt(op1)) emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT1); emitFastArithImmToInt(regT0); emitFastArithImmToInt(regT1); urshift32(regT1, regT0); addSlowCase(branch32(LessThan, regT0, Imm32(0))); emitFastArithReTagImmediate(regT0, regT0); emitPutVirtualRegister(dst, regT0); }
void JIT::compilePutByIdHotPath(int baseVReg, Identifier* ident, int valueVReg, unsigned) { // In order to be able to repatch both the Structure, and the object offset, we store one pointer, // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code // such that the Structure & offset are always at the same distance from this. emitGetVirtualRegisters(baseVReg, X86::eax, valueVReg, X86::edx); emitPutJITStubArgConstant(ident, 2); emitPutJITStubArg(X86::eax, 1); emitPutJITStubArg(X86::edx, 3); emitCTICall(Interpreter::cti_op_put_by_id_generic); }
void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned, unsigned op1, unsigned op2, OperandTypes) { emitGetVirtualRegisters(op1, regT0, op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT1); if (opcodeID == op_add) addSlowCase(branchAdd32(Overflow, regT1, regT0)); else if (opcodeID == op_sub) addSlowCase(branchSub32(Overflow, regT1, regT0)); else { ASSERT(opcodeID == op_mul); addSlowCase(branchMul32(Overflow, regT1, regT0)); addSlowCase(branchTest32(Zero, regT0)); } emitFastArithIntToImmNoCheck(regT0, regT0); }
void JIT::emit_op_lshift(Instruction* currentInstruction) { unsigned result = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; emitGetVirtualRegisters(op1, regT0, op2, regT2); // FIXME: would we be better using 'emitJumpSlowCaseIfNotImmediateIntegers'? - we *probably* ought to be consistent. emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT2); emitFastArithImmToInt(regT0); emitFastArithImmToInt(regT2); lshift32(regT2, regT0); emitFastArithReTagImmediate(regT0, regT0); emitPutVirtualRegister(result); }
void JIT::emit_op_jlesseq(Instruction* currentInstruction, bool invert) { unsigned op1 = currentInstruction[1].u.operand; unsigned op2 = currentInstruction[2].u.operand; unsigned target = currentInstruction[3].u.operand; // We generate inline code for the following cases in the fast path: // - int immediate to constant int immediate // - constant int immediate to int immediate // - int immediate to int immediate if (isOperandConstantImmediateChar(op1)) { emitGetVirtualRegister(op2, regT0); addSlowCase(emitJumpIfNotJSCell(regT0)); JumpList failures; emitLoadCharacterString(regT0, regT0, failures); addSlowCase(failures); addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target); return; } if (isOperandConstantImmediateChar(op2)) { emitGetVirtualRegister(op1, regT0); addSlowCase(emitJumpIfNotJSCell(regT0)); JumpList failures; emitLoadCharacterString(regT0, regT0, failures); addSlowCase(failures); addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target); return; } if (isOperandConstantImmediateInt(op2)) { emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); int32_t op2imm = getConstantOperandImmediateInt(op2); addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(op2imm)), target); } else if (isOperandConstantImmediateInt(op1)) { emitGetVirtualRegister(op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT1); int32_t op1imm = getConstantOperandImmediateInt(op1); addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT1, Imm32(op1imm)), target); } else { emitGetVirtualRegisters(op1, regT0, op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT1); addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, regT1), target); } }
void JIT::emit_op_mod(Instruction* currentInstruction) { unsigned result = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; #if ENABLE(JIT_USE_SOFT_MODULO) emitGetVirtualRegisters(op1, regT0, op2, regT2); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT2); addSlowCase(branch32(Equal, regT2, Imm32(1))); emitNakedCall(m_globalData->jitStubs->ctiSoftModulo()); emitPutVirtualRegister(result, regT0); #else JITStubCall stubCall(this, cti_op_mod); stubCall.addArgument(op1, regT2); stubCall.addArgument(op2, regT2); stubCall.call(result); #endif }
void JIT::emit_op_mod(Instruction* currentInstruction) { unsigned result = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; #if CPU(X86) || CPU(X86_64) // Make sure registers are correct for x86 IDIV instructions. ASSERT(regT0 == X86Registers::eax); ASSERT(regT1 == X86Registers::edx); ASSERT(regT2 == X86Registers::ecx); #endif emitGetVirtualRegisters(op1, regT0, op2, regT2); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT2); addSlowCase(branchPtr(Equal, regT2, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0))))); m_assembler.cdq(); m_assembler.idivl_r(regT2); emitFastArithReTagImmediate(regT1, regT0); emitPutVirtualRegister(result); }
void JIT::compilePutByIdHotPath(int baseVReg, Identifier*, int valueVReg, unsigned propertyAccessInstructionIndex) { // In order to be able to repatch both the Structure, and the object offset, we store one pointer, // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code // such that the Structure & offset are always at the same distance from this. emitGetVirtualRegisters(baseVReg, X86::eax, valueVReg, X86::edx); // Jump to a slow case if either the base object is an immediate, or if the Structure does not match. emitJumpSlowCaseIfNotJSCell(X86::eax, baseVReg); JmpDst hotPathBegin = __ label(); m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin; // It is important that the following instruction plants a 32bit immediate, in order that it can be patched over. __ cmpl_im_force32(repatchGetByIdDefaultStructure, FIELD_OFFSET(JSCell, m_structure), X86::eax); ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, __ label()) == repatchOffsetPutByIdStructure); addSlowCase(__ jne()); // Plant a load from a bogus ofset in the object's property map; we will patch this later, if it is to be used. __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax); __ movl_rm(X86::edx, repatchGetByIdDefaultOffset, X86::eax); ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, __ label()) == repatchOffsetPutByIdPropertyMapOffset); }