void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned) { int callee = instruction[1].u.operand; int argCount = instruction[2].u.operand; int registerOffset = instruction[3].u.operand; // Handle eval Jump wasEval; if (opcodeID == op_call_eval) { JITStubCall stubCall(this, cti_op_call_eval); stubCall.addArgument(callee, regT0); stubCall.addArgument(JIT::Imm32(registerOffset)); stubCall.addArgument(JIT::Imm32(argCount)); stubCall.call(); wasEval = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue()))); } emitGetVirtualRegister(callee, regT0); // Check for JSFunctions. emitJumpSlowCaseIfNotJSCell(regT0); addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr))); // Speculatively roll the callframe, assuming argCount will match the arity. storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)))); addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister); move(Imm32(argCount), regT1); emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstruct() : m_globalData->jitStubs->ctiVirtualCall()); if (opcodeID == op_call_eval) wasEval.link(this); sampleCodeBlock(m_codeBlock); }
void JIT::compileOpCallVarargs(Instruction* instruction) { int callee = instruction[1].u.operand; int argCountRegister = instruction[2].u.operand; int registerOffset = instruction[3].u.operand; emitGetVirtualRegister(argCountRegister, regT1); emitFastArithImmToInt(regT1); emitGetVirtualRegister(callee, regT0); addPtr(Imm32(registerOffset), regT1, regT2); // Check for JSFunctions. emitJumpSlowCaseIfNotJSCell(regT0); addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr))); // Speculatively roll the callframe, assuming argCount will match the arity. mul32(TrustedImm32(sizeof(Register)), regT2, regT2); intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame; addPtr(Imm32((int32_t)offset), regT2, regT3); addPtr(callFrameRegister, regT3); storePtr(callFrameRegister, regT3); addPtr(regT2, callFrameRegister); emitNakedCall(m_globalData->jitStubs->ctiVirtualCall()); sampleCodeBlock(m_codeBlock); }
void JIT::compileOpCallVarargs(Instruction* instruction) { int callee = instruction[1].u.operand; int argCountRegister = instruction[2].u.operand; int registerOffset = instruction[3].u.operand; emitLoad(callee, regT1, regT0); emitLoadPayload(argCountRegister, regT2); // argCount addPtr(Imm32(registerOffset), regT2, regT3); // registerOffset emitJumpSlowCaseIfNotJSCell(callee, regT1); addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr))); // Speculatively roll the callframe, assuming argCount will match the arity. mul32(TrustedImm32(sizeof(Register)), regT3, regT3); addPtr(callFrameRegister, regT3); store32(TrustedImm32(JSValue::CellTag), tagFor(RegisterFile::CallerFrame, regT3)); storePtr(callFrameRegister, payloadFor(RegisterFile::CallerFrame, regT3)); move(regT3, callFrameRegister); move(regT2, regT1); // argCount emitNakedCall(m_globalData->jitStubs->ctiVirtualCall()); sampleCodeBlock(m_codeBlock); }
void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned i, unsigned) { int dst = instruction[1].u.operand; int callee = instruction[2].u.operand; int argCount = instruction[3].u.operand; int registerOffset = instruction[4].u.operand; // Handle eval JmpSrc wasEval; if (opcodeID == op_call_eval) { emitGetVirtualRegister(callee, X86::ecx, i); compileOpCallEvalSetupArgs(instruction); emitCTICall(i, Interpreter::cti_op_call_eval); __ cmpl_i32r(asInteger(JSImmediate::impossibleValue()), X86::eax); wasEval = __ jne(); } emitGetVirtualRegister(callee, X86::ecx, i); // The arguments have been set up on the hot path for op_call_eval if (opcodeID == op_call) compileOpCallSetupArgs(instruction); else if (opcodeID == op_construct) compileOpConstructSetupArgs(instruction); // Check for JSFunctions. emitJumpSlowCaseIfNotJSCell(X86::ecx, i); __ cmpl_i32m(reinterpret_cast<unsigned>(m_interpreter->m_jsFunctionVptr), X86::ecx); m_slowCases.append(SlowCaseEntry(__ jne(), i)); // First, in the case of a construct, allocate the new object. if (opcodeID == op_construct) { emitCTICall(i, Interpreter::cti_op_construct_JSConstruct); emitPutVirtualRegister(registerOffset - RegisterFile::CallFrameHeaderSize - argCount); emitGetVirtualRegister(callee, X86::ecx, i); } // Speculatively roll the callframe, assuming argCount will match the arity. __ movl_rm(X86::edi, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)), X86::edi); __ addl_i32r(registerOffset * static_cast<int>(sizeof(Register)), X86::edi); __ movl_i32r(argCount, X86::edx); emitNakedCall(i, m_interpreter->m_ctiVirtualCall); if (opcodeID == op_call_eval) __ link(wasEval, __ label()); // Put the return value in dst. In the interpreter, op_ret does this. emitPutVirtualRegister(dst); #if ENABLE(CODEBLOCK_SAMPLING) __ movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), m_interpreter->sampler()->codeBlockSlot()); #endif }
void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned) { int dst = instruction[1].u.operand; int callee = instruction[2].u.operand; int argCount = instruction[3].u.operand; int registerOffset = instruction[4].u.operand; // Handle eval Jump wasEval; if (opcodeID == op_call_eval) { emitGetVirtualRegister(callee, X86::ecx); compileOpCallEvalSetupArgs(instruction); emitCTICall(Interpreter::cti_op_call_eval); wasEval = jnePtr(X86::eax, ImmPtr(JSImmediate::impossibleValue())); } emitGetVirtualRegister(callee, X86::ecx); // The arguments have been set up on the hot path for op_call_eval if (opcodeID == op_call) compileOpCallSetupArgs(instruction); else if (opcodeID == op_construct) compileOpConstructSetupArgs(instruction); // Check for JSFunctions. emitJumpSlowCaseIfNotJSCell(X86::ecx); addSlowCase(jnePtr(Address(X86::ecx), ImmPtr(m_interpreter->m_jsFunctionVptr))); // First, in the case of a construct, allocate the new object. if (opcodeID == op_construct) { emitCTICall(Interpreter::cti_op_construct_JSConstruct); emitPutVirtualRegister(registerOffset - RegisterFile::CallFrameHeaderSize - argCount); emitGetVirtualRegister(callee, X86::ecx); } // Speculatively roll the callframe, assuming argCount will match the arity. storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)))); addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister); move(Imm32(argCount), X86::edx); emitNakedCall(m_interpreter->m_ctiVirtualCall); if (opcodeID == op_call_eval) wasEval.link(this); // Put the return value in dst. In the interpreter, op_ret does this. emitPutVirtualRegister(dst); #if ENABLE(CODEBLOCK_SAMPLING) storePtr(ImmPtr(m_codeBlock), m_interpreter->sampler()->codeBlockSlot()); #endif }
void JIT::compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier*, unsigned propertyAccessInstructionIndex) { // As for put_by_id, get_by_id requires the offset of the Structure and the offset of the access to be repatched. // Additionally, for get_by_id we need repatch the offset of the branch to the slow case (we repatch this to jump // to array-length / prototype access tranpolines, and finally we also the the property-map access offset as a label // to jump back to if one of these trampolies finds a match. emitGetVirtualRegister(baseVReg, X86::eax); emitJumpSlowCaseIfNotJSCell(X86::eax, baseVReg); JmpDst hotPathBegin = __ label(); m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin; __ cmpl_im_force32(repatchGetByIdDefaultStructure, FIELD_OFFSET(JSCell, m_structure), X86::eax); ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, __ label()) == repatchOffsetGetByIdStructure); addSlowCase(__ jne()); ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, __ label()) == repatchOffsetGetByIdBranchToSlowCase); __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax); __ movl_mr(repatchGetByIdDefaultOffset, X86::eax, X86::eax); ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, __ label()) == repatchOffsetGetByIdPropertyMapOffset); emitPutVirtualRegister(resultVReg); }
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); }