+2008-10-13 Cameron Zwarich <zwarich@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ Bug 21541: Move RegisterFile growth check to callee
+ <https://bugs.webkit.org/show_bug.cgi?id=21541>
+
+ Move the RegisterFile growth check to the callee in the common case,
+ where some of the information is known statically at JIT time. There is
+ still a check in the caller in the case where the caller provides too
+ few arguments.
+
+ This is a 2.1% speedup on the V8 benchmark, including a 5.1% speedup on
+ the Richards benchmark, a 4.1% speedup on the DeltaBlue benchmark, and a
+ 1.4% speedup on the Earley-Boyer benchmark. It is also a 0.5% speedup on
+ SunSpider.
+
+ * VM/CTI.cpp:
+ (JSC::CTI::privateCompile):
+ * VM/Machine.cpp:
+ (JSC::Machine::cti_register_file_check):
+ (JSC::Machine::cti_op_call_JSFunction):
+ (JSC::Machine::cti_op_construct_JSConstruct):
+ * VM/Machine.h:
+ * VM/RegisterFile.h:
+ * masm/X86Assembler.h:
+ (JSC::X86Assembler::):
+ (JSC::X86Assembler::cmpl_mr):
+ (JSC::X86Assembler::emitUnlinkedJg):
+
2008-10-13 Sam Weinig <sam@webkit.org>
Reviewed by Dan Bernstein.
m_jit.popl_r(X86::ecx);
emitPutToCallFrameHeader(X86::ecx, RegisterFile::ReturnPC);
+ X86Assembler::JmpSrc slowRegisterFileCheck;
+ X86Assembler::JmpDst afterRegisterFileCheck;
+ if (m_codeBlock->codeType == FunctionCode) {
+ emitGetCTIParam(CTI_ARGS_registerFile, X86::eax);
+ m_jit.leal_mr(m_codeBlock->numCalleeRegisters * sizeof(Register), X86::edi, X86::edx);
+ m_jit.cmpl_mr(OBJECT_OFFSET(RegisterFile, m_end), X86::eax, X86::edx);
+ slowRegisterFileCheck = m_jit.emitUnlinkedJg();
+ afterRegisterFileCheck = m_jit.label();
+ }
+
privateCompileMainPass();
privateCompileLinkPass();
privateCompileSlowCases();
+ if (m_codeBlock->codeType == FunctionCode) {
+ m_jit.link(slowRegisterFileCheck, m_jit.label());
+ emitCall(0, Machine::cti_register_file_check);
+ X86Assembler::JmpSrc backToBody = m_jit.emitUnlinkedJmp();
+ m_jit.link(backToBody, afterRegisterFileCheck);
+ }
+
ASSERT(m_jmpTable.isEmpty());
void* code = m_jit.copy();
}
}
+void Machine::cti_register_file_check(CTI_ARGS)
+{
+ CallFrame* callFrame = ARG_callFrame;
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ RegisterFile* registerFile = ARG_registerFile;
+
+ if (!registerFile->grow(callFrame + codeBlock->numCalleeRegisters)) {
+ CallFrame* callerFrame = callFrame->callerFrame();
+ ARG_setCallFrame(callerFrame);
+ ARG_globalData->exception = createStackOverflowError(callerFrame);
+ ASSERT(ARG_globalData->exception);
+ ARG_globalData->throwReturnAddress = callFrame->returnPC();
+ doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS);
+ }
+}
+
int Machine::cti_op_loop_if_less(CTI_ARGS)
{
JSValue* src1 = ARG_src1;
ScopeChainNode* callDataScopeChain = static_cast<JSFunction*>(ARG_src1)->m_scopeChain.node();
CodeBlock* newCodeBlock = &static_cast<JSFunction*>(ARG_src1)->m_body->byteCode(callDataScopeChain);
+ CallFrame* callFrame = ARG_callFrame;
+ size_t registerOffset = ARG_int2;
+ int argCount = ARG_int3;
+
+ if (LIKELY(argCount == newCodeBlock->numParameters)) {
+ VoidPtrPair pair = { newCodeBlock, CallFrame::create(callFrame->registers() + registerOffset) };
+ return pair;
+ }
+
+ if (argCount > newCodeBlock->numParameters) {
+ size_t numParameters = newCodeBlock->numParameters;
+ Register* r = callFrame->registers() + registerOffset + numParameters;
+
+ Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
+ for (size_t i = 0; i < numParameters; ++i)
+ argv[i + argCount] = argv[i];
+
+ VoidPtrPair pair = { newCodeBlock, CallFrame::create(r) };
+ return pair;
+ }
- CallFrame* callFrame = slideRegisterWindowForCall(newCodeBlock, ARG_registerFile, ARG_callFrame, ARG_int2, ARG_int3);
- if (UNLIKELY(!callFrame)) {
- ARG_globalData->exception = createStackOverflowError(ARG_callFrame);
+ size_t omittedArgCount = newCodeBlock->numParameters - argCount;
+ Register* r = callFrame->registers() + registerOffset + omittedArgCount;
+ Register* newEnd = r + newCodeBlock->numCalleeRegisters;
+ if (!ARG_registerFile->grow(newEnd)) {
+ ARG_globalData->exception = createStackOverflowError(callFrame);
VM_THROW_EXCEPTION_2();
}
- VoidPtrPair pair = { newCodeBlock, callFrame };
+ Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
+ for (size_t i = 0; i < omittedArgCount; ++i)
+ argv[i] = jsUndefined();
+
+ VoidPtrPair pair = { newCodeBlock, CallFrame::create(r) };
return pair;
}
VoidPtrPair Machine::cti_op_construct_JSConstruct(CTI_ARGS)
{
- RegisterFile* registerFile = ARG_registerFile;
CallFrame* callFrame = ARG_callFrame;
JSFunction* constructor = static_cast<JSFunction*>(ARG_src1);
else
structure = callDataScopeChain->globalObject()->emptyObjectStructure();
JSObject* newObject = new (ARG_globalData) JSObject(structure);
-
callFrame[firstArg] = newObject; // "this" value
- callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
- if (UNLIKELY(!callFrame)) {
- ARG_globalData->exception = createStackOverflowError(ARG_callFrame);
+ if (LIKELY(argCount == newCodeBlock->numParameters)) {
+ VoidPtrPair pair = { newCodeBlock, CallFrame::create(callFrame->registers() + registerOffset) };
+ return pair;
+ }
+
+ if (argCount > newCodeBlock->numParameters) {
+ size_t numParameters = newCodeBlock->numParameters;
+ Register* r = callFrame->registers() + registerOffset + numParameters;
+
+ Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
+ for (size_t i = 0; i < numParameters; ++i)
+ argv[i + argCount] = argv[i];
+
+ VoidPtrPair pair = { newCodeBlock, CallFrame::create(r) };
+ return pair;
+ }
+
+ size_t omittedArgCount = newCodeBlock->numParameters - argCount;
+ Register* r = callFrame->registers() + registerOffset + omittedArgCount;
+ Register* newEnd = r + newCodeBlock->numCalleeRegisters;
+ if (!ARG_registerFile->grow(newEnd)) {
+ ARG_globalData->exception = createStackOverflowError(callFrame);
VM_THROW_EXCEPTION_2();
}
- VoidPtrPair pair = { newCodeBlock, callFrame };
+ Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
+ for (size_t i = 0; i < omittedArgCount; ++i)
+ argv[i] = jsUndefined();
+
+ VoidPtrPair pair = { newCodeBlock, CallFrame::create(r) };
return pair;
}
PRE_PREDICT_BRANCH_NOT_TAKEN = 0x2E,
OP_XOR_EvGv = 0x31,
OP_CMP_EvGv = 0x39,
+ OP_CMP_GvEv = 0x3B,
OP_PUSH_EAX = 0x50,
OP_POP_EAX = 0x58,
PRE_OPERAND_SIZE = 0x66,
OP2_JL_rel32 = 0x8C,
OP2_JGE_rel32 = 0x8D,
OP2_JLE_rel32 = 0x8E,
+ OP2_JG_rel32 = 0x8F,
OP2_IMUL_GvEv = 0xAF,
OP2_MOVZX_GvEb = 0xB6,
OP2_MOVZX_GvEw = 0xB7,
emitModRm_rm(src, base, offset);
}
+ void cmpl_mr(int offset, RegisterID base, RegisterID dst)
+ {
+ m_buffer->putByte(OP_CMP_GvEv);
+ emitModRm_rm(dst, base, offset);
+ }
+
void cmpl_i32r(int imm, RegisterID dst)
{
m_buffer->putByte(OP_GROUP1_EvIz);
m_buffer->putInt(0);
return JmpSrc(m_buffer->getOffset());
}
-
+
+ JmpSrc emitUnlinkedJg()
+ {
+ m_buffer->putByte(OP_2BYTE_ESCAPE);
+ m_buffer->putByte(OP2_JG_rel32);
+ m_buffer->putInt(0);
+ return JmpSrc(m_buffer->getOffset());
+ }
+
JmpSrc emitUnlinkedJa()
{
m_buffer->putByte(OP_2BYTE_ESCAPE);