📄 jit.cpp
字号:
#if ENABLE(OPCODE_SAMPLING) if (m_bytecodeIndex > 0) // Avoid the overhead of sampling op_enter twice. sampleInstruction(currentInstruction);#endif if (m_labels[m_bytecodeIndex].isUsed()) killLastResultRegister(); m_labels[m_bytecodeIndex] = label(); OpcodeID opcodeID = m_interpreter->getOpcodeID(currentInstruction->u.opcode); switch (opcodeID) { case op_mov: { int src = currentInstruction[2].u.operand; int dst = currentInstruction[1].u.operand; if (m_codeBlock->isConstantRegisterIndex(src)) { storePtr(ImmPtr(JSValuePtr::encode(getConstantOperand(src))), Address(callFrameRegister, dst * sizeof(Register))); if (dst == m_lastResultBytecodeRegister) killLastResultRegister(); } else if ((src == m_lastResultBytecodeRegister) || (dst == m_lastResultBytecodeRegister)) { // If either the src or dst is the cached register go though // get/put registers to make sure we track this correctly. emitGetVirtualRegister(src, regT0); emitPutVirtualRegister(dst); } else { // Perform the copy via regT1; do not disturb any mapping in regT0. loadPtr(Address(callFrameRegister, src * sizeof(Register)), regT1); storePtr(regT1, Address(callFrameRegister, dst * sizeof(Register))); } NEXT_OPCODE(op_mov); } case op_add: { compileFastArith_op_add(currentInstruction); NEXT_OPCODE(op_add); } case op_end: { if (m_codeBlock->needsFullScopeChain()) emitCTICall(JITStubs::cti_op_end); ASSERT(returnValueRegister != callFrameRegister); emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueRegister); push(Address(callFrameRegister, RegisterFile::ReturnPC * static_cast<int>(sizeof(Register)))); ret(); NEXT_OPCODE(op_end); } case op_jmp: { unsigned target = currentInstruction[1].u.operand; addJump(jump(), target + 1); RECORD_JUMP_TARGET(target + 1); NEXT_OPCODE(op_jmp); } case op_pre_inc: { compileFastArith_op_pre_inc(currentInstruction[1].u.operand); NEXT_OPCODE(op_pre_inc); } case op_loop: { emitTimeoutCheck(); unsigned target = currentInstruction[1].u.operand; addJump(jump(), target + 1); NEXT_OPCODE(op_end); } case op_loop_if_less: { emitTimeoutCheck(); unsigned op1 = currentInstruction[1].u.operand; unsigned op2 = currentInstruction[2].u.operand; unsigned target = currentInstruction[3].u.operand; if (isOperandConstantImmediateInt(op2)) { emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0);#if USE(ALTERNATE_JSIMMEDIATE) int32_t op2imm = getConstantOperandImmediateInt(op2);#else int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)));#endif addJump(branch32(LessThan, regT0, Imm32(op2imm)), target + 3); } else { emitGetVirtualRegisters(op1, regT0, op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT1); addJump(branch32(LessThan, regT0, regT1), target + 3); } NEXT_OPCODE(op_loop_if_less); } case op_loop_if_lesseq: { emitTimeoutCheck(); unsigned op1 = currentInstruction[1].u.operand; unsigned op2 = currentInstruction[2].u.operand; unsigned target = currentInstruction[3].u.operand; if (isOperandConstantImmediateInt(op2)) { emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0);#if USE(ALTERNATE_JSIMMEDIATE) int32_t op2imm = getConstantOperandImmediateInt(op2);#else int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)));#endif addJump(branch32(LessThanOrEqual, regT0, Imm32(op2imm)), target + 3); } else { emitGetVirtualRegisters(op1, regT0, op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT1); addJump(branch32(LessThanOrEqual, regT0, regT1), target + 3); } NEXT_OPCODE(op_loop_if_less); } case op_new_object: { emitCTICall(JITStubs::cti_op_new_object); emitPutVirtualRegister(currentInstruction[1].u.operand); NEXT_OPCODE(op_new_object); } case op_put_by_id: { compilePutByIdHotPath(currentInstruction[1].u.operand, &(m_codeBlock->identifier(currentInstruction[2].u.operand)), currentInstruction[3].u.operand, propertyAccessInstructionIndex++); NEXT_OPCODE(op_put_by_id); } case op_get_by_id: { compileGetByIdHotPath(currentInstruction[1].u.operand, currentInstruction[2].u.operand, &(m_codeBlock->identifier(currentInstruction[3].u.operand)), propertyAccessInstructionIndex++); NEXT_OPCODE(op_get_by_id); } case op_instanceof: { emitGetVirtualRegister(currentInstruction[2].u.operand, regT0); // value emitGetVirtualRegister(currentInstruction[3].u.operand, regT2); // baseVal emitGetVirtualRegister(currentInstruction[4].u.operand, regT1); // proto // check if any are immediates move(regT0, regT3); orPtr(regT2, regT3); orPtr(regT1, regT3); emitJumpSlowCaseIfNotJSCell(regT3); // check that all are object type - this is a bit of a bithack to avoid excess branching; // we check that the sum of the three type codes from Structures is exactly 3 * ObjectType, // this works because NumberType and StringType are smaller move(Imm32(3 * ObjectType), regT3); loadPtr(Address(regT0, FIELD_OFFSET(JSCell, m_structure)), regT0); loadPtr(Address(regT2, FIELD_OFFSET(JSCell, m_structure)), regT2); loadPtr(Address(regT1, FIELD_OFFSET(JSCell, m_structure)), regT1); sub32(Address(regT0, FIELD_OFFSET(Structure, m_typeInfo.m_type)), regT3); sub32(Address(regT2, FIELD_OFFSET(Structure, m_typeInfo.m_type)), regT3); addSlowCase(branch32(NotEqual, Address(regT1, FIELD_OFFSET(Structure, m_typeInfo.m_type)), regT3)); // check that baseVal's flags include ImplementsHasInstance but not OverridesHasInstance load32(Address(regT2, FIELD_OFFSET(Structure, m_typeInfo.m_flags)), regT2); and32(Imm32(ImplementsHasInstance | OverridesHasInstance), regT2); addSlowCase(branch32(NotEqual, regT2, Imm32(ImplementsHasInstance))); emitGetVirtualRegister(currentInstruction[2].u.operand, regT2); // reload value emitGetVirtualRegister(currentInstruction[4].u.operand, regT1); // reload proto // optimistically load true result move(ImmPtr(JSValuePtr::encode(jsBoolean(true))), regT0); Label loop(this); // load value's prototype loadPtr(Address(regT2, FIELD_OFFSET(JSCell, m_structure)), regT2); loadPtr(Address(regT2, FIELD_OFFSET(Structure, m_prototype)), regT2); Jump exit = branchPtr(Equal, regT2, regT1); branchPtr(NotEqual, regT2, ImmPtr(JSValuePtr::encode(jsNull())), loop); move(ImmPtr(JSValuePtr::encode(jsBoolean(false))), regT0); exit.link(this); emitPutVirtualRegister(currentInstruction[1].u.operand); NEXT_OPCODE(op_instanceof); } case op_del_by_id: { emitPutJITStubArgFromVirtualRegister(currentInstruction[2].u.operand, 1, regT2); Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand)); emitPutJITStubArgConstant(ident, 2); emitCTICall(JITStubs::cti_op_del_by_id); emitPutVirtualRegister(currentInstruction[1].u.operand); NEXT_OPCODE(op_del_by_id); } case op_mul: { compileFastArith_op_mul(currentInstruction); NEXT_OPCODE(op_mul); } case op_new_func: { FuncDeclNode* func = m_codeBlock->function(currentInstruction[2].u.operand); emitPutJITStubArgConstant(func, 1); emitCTICall(JITStubs::cti_op_new_func); emitPutVirtualRegister(currentInstruction[1].u.operand); NEXT_OPCODE(op_new_func); } case op_call: { compileOpCall(opcodeID, currentInstruction, callLinkInfoIndex++); NEXT_OPCODE(op_call); } case op_call_eval: { compileOpCall(opcodeID, currentInstruction, callLinkInfoIndex++); NEXT_OPCODE(op_call_eval); } case op_construct: { compileOpCall(opcodeID, currentInstruction, callLinkInfoIndex++); NEXT_OPCODE(op_construct); } case op_get_global_var: { JSVariableObject* globalObject = static_cast<JSVariableObject*>(currentInstruction[2].u.jsCell); move(ImmPtr(globalObject), regT0); emitGetVariableObjectRegister(regT0, currentInstruction[3].u.operand, regT0); emitPutVirtualRegister(currentInstruction[1].u.operand); NEXT_OPCODE(op_get_global_var); } case op_put_global_var: { emitGetVirtualRegister(currentInstruction[3].u.operand, regT1); JSVariableObject* globalObject = static_cast<JSVariableObject*>(currentInstruction[1].u.jsCell); move(ImmPtr(globalObject), regT0); emitPutVariableObjectRegister(regT1, regT0, currentInstruction[2].u.operand); NEXT_OPCODE(op_put_global_var); } case op_get_scoped_var: { int skip = currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain(); emitGetFromCallFrameHeader(RegisterFile::ScopeChain, regT0); while (skip--) loadPtr(Address(regT0, FIELD_OFFSET(ScopeChainNode, next)), regT0); loadPtr(Address(regT0, FIELD_OFFSET(ScopeChainNode, object)), regT0); emitGetVariableObjectRegister(regT0, currentInstruction[2].u.operand, regT0); emitPutVirtualRegister(currentInstruction[1].u.operand); NEXT_OPCODE(op_get_scoped_var); } case op_put_scoped_var: { int skip = currentInstruction[2].u.operand + m_codeBlock->needsFullScopeChain(); emitGetFromCallFrameHeader(RegisterFile::ScopeChain, regT1); emitGetVirtualRegister(currentInstruction[3].u.operand, regT0); while (skip--) loadPtr(Address(regT1, FIELD_OFFSET(ScopeChainNode, next)), regT1); loadPtr(Address(regT1, FIELD_OFFSET(ScopeChainNode, object)), regT1); emitPutVariableObjectRegister(regT0, regT1, currentInstruction[1].u.operand); NEXT_OPCODE(op_put_scoped_var); } case op_tear_off_activation: { emitPutJITStubArgFromVirtualRegister(currentInstruction[1].u.operand, 1, regT2); emitCTICall(JITStubs::cti_op_tear_off_activation); NEXT_OPCODE(op_tear_off_activation); } case op_tear_off_arguments: { emitCTICall(JITStubs::cti_op_tear_off_arguments); NEXT_OPCODE(op_tear_off_arguments); } case op_ret: { // We could JIT generate the deref, only calling out to C when the refcount hits zero. if (m_codeBlock->needsFullScopeChain()) emitCTICall(JITStubs::cti_op_ret_scopeChain); ASSERT(callFrameRegister != regT1); ASSERT(regT1 != returnValueRegister); ASSERT(returnValueRegister != callFrameRegister); // Return the result in %eax. emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueRegister); // Grab the return address. emitGetFromCallFrameHeader(RegisterFile::ReturnPC, regT1); // Restore our caller's "r". emitGetFromCallFrameHeader(RegisterFile::CallerFrame, callFrameRegister); // Return. push(regT1); ret(); NEXT_OPCODE(op_ret); } case op_new_array: { emitPutJITStubArgConstant(currentInstruction[2].u.operand, 1); emitPutJITStubArgConstant(currentInstruction[3].u.operand, 2); emitCTICall(JITStubs::cti_op_new_array); emitPutVirtualRegister(currentInstruction[1].u.operand); NEXT_OPCODE(op_new_array); } case op_resolve: { Identifier* ident = &(m_codeBlock->identifier(currentInstruction[2].u.operand)); emitPutJITStubArgConstant(ident, 1); emitCTICall(JITStubs::cti_op_resolve); emitPutVirtualRegister(currentInstruction[1].u.operand); NEXT_OPCODE(op_resolve); } case op_construct_verify: { emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); emitJumpSlowCaseIfNotJSCell(regT0); loadPtr(Address(regT0, FIELD_OFFSET(JSCell, m_structure)), regT2); addSlowCase(branch32(NotEqual, Address(regT2, FIELD_OFFSET(Structure, m_typeInfo) + FIELD_OFFSET(TypeInfo, m_type)), Imm32(ObjectType))); NEXT_OPCODE(op_construct_verify); } case op_get_by_val: { emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -