2008-10-13 Cameron Zwarich <zwarich@apple.com>
authorcwzwarich@webkit.org <cwzwarich@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Oct 2008 00:20:49 +0000 (00:20 +0000)
committercwzwarich@webkit.org <cwzwarich@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Oct 2008 00:20:49 +0000 (00:20 +0000)
        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):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@37570 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/Machine.h
JavaScriptCore/VM/RegisterFile.h
JavaScriptCore/masm/X86Assembler.h

index 537fbf2cfab9a98dfe1efa64059610d7de41cd7e..de6a820d21c072d1e93d2de4a2be2b15f7855568 100644 (file)
@@ -1,3 +1,33 @@
+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.
index 7d9251bf033cf3f8bf2831fa48fa8f28ae6baaa1..83b82e7559c239c8205c44b40bbba1ca2b52f89d 100644 (file)
@@ -2615,10 +2615,27 @@ void CTI::privateCompile()
     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();
index 840e251d937fa53102441fed66125888ff97d710..284203dfab9236b69b3f1bc1aeee20e70472c7f3 100644 (file)
@@ -4336,6 +4336,22 @@ void Machine::cti_timeout_check(CTI_ARGS)
     }
 }
 
+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;
@@ -4550,14 +4566,40 @@ VoidPtrPair Machine::cti_op_call_JSFunction(CTI_ARGS)
 
     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;
 }
 
@@ -4685,7 +4727,6 @@ JSValue* Machine::cti_op_resolve(CTI_ARGS)
 
 VoidPtrPair Machine::cti_op_construct_JSConstruct(CTI_ARGS)
 {
-    RegisterFile* registerFile = ARG_registerFile;
     CallFrame* callFrame = ARG_callFrame;
 
     JSFunction* constructor = static_cast<JSFunction*>(ARG_src1);
@@ -4712,16 +4753,38 @@ VoidPtrPair Machine::cti_op_construct_JSConstruct(CTI_ARGS)
     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;
 }
 
index 97dc2eea185ee1b5a241a91189acc55c8db3a96f..e8729995da19369cafb1d09d6082a672248303a3 100644 (file)
@@ -162,6 +162,7 @@ namespace JSC {
 #if ENABLE(CTI)
 
         static void SFX_CALL cti_timeout_check(CTI_ARGS);
+        static void SFX_CALL cti_register_file_check(CTI_ARGS);
 
         static JSValue* SFX_CALL cti_op_convert_this(CTI_ARGS);
         static void SFX_CALL cti_op_end(CTI_ARGS);
index 7be506357a72e17e69959b60cc76662954edae8b..0955ccb8d12aab404d38d2d2a0462b19248c844f 100644 (file)
@@ -88,6 +88,7 @@ namespace JSC {
     class JSGlobalObject;
 
     class RegisterFile : Noncopyable {
+        friend class CTI;
     public:
         enum CallFrameHeaderEntry {
             CallFrameHeaderSize = 8,
index a625e334e4fd31f2f527453aba3b86fd7813c30b..a836c16245740ec224eaec104122267010b54334 100644 (file)
@@ -191,6 +191,7 @@ public:
         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,
@@ -240,6 +241,7 @@ public:
         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,
@@ -373,6 +375,12 @@ public:
         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);
@@ -945,7 +953,15 @@ public:
         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);