Changeset 38209 in webkit


Ignore:
Timestamp:
Nov 6, 2008 5:30:03 PM (15 years ago)
Author:
barraclough@apple.com
Message:

2008-11-06 Gavin Barraclough barraclough@apple.com

Reviewed by Oliver Hunt.

Do not make a cti_* call to perform an op_call unless either:
(1) The codeblock for the function body has not been generated.
(2) The number of arguments passed does not match the callee arity.

~1% progression on sunspider --v8

  • VM/CTI.cpp: (JSC::CTI::compileOpCallInitializeCallFrame): (JSC::CTI::compileOpCall): (JSC::CTI::privateCompileSlowCases):
  • VM/CTI.h:
  • VM/Machine.cpp: (JSC::Machine::cti_op_call_JSFunction): (JSC::Machine::cti_op_call_arityCheck): (JSC::Machine::cti_op_construct_JSConstruct):
  • VM/Machine.h:
  • kjs/nodes.h:
Location:
trunk/JavaScriptCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r38205 r38209  
     12008-11-06  Gavin Barraclough  barraclough@apple.com
     2
     3        Reviewed by Oliver Hunt.
     4
     5        Do not make a cti_* call to perform an op_call unless either:
     6        (1) The codeblock for the function body has not been generated.
     7        (2) The number of arguments passed does not match the callee arity.
     8
     9        ~1% progression on sunspider --v8
     10
     11        * VM/CTI.cpp:
     12        (JSC::CTI::compileOpCallInitializeCallFrame):
     13        (JSC::CTI::compileOpCall):
     14        (JSC::CTI::privateCompileSlowCases):
     15        * VM/CTI.h:
     16        * VM/Machine.cpp:
     17        (JSC::Machine::cti_op_call_JSFunction):
     18        (JSC::Machine::cti_op_call_arityCheck):
     19        (JSC::Machine::cti_op_construct_JSConstruct):
     20        * VM/Machine.h:
     21        * kjs/nodes.h:
     22
    1232008-11-06  Cameron Zwarich  <zwarich@apple.com>
    224
  • trunk/JavaScriptCore/VM/CTI.cpp

    r38148 r38209  
    588588}
    589589
    590 void CTI::compileOpCallInitializeCallFrame(unsigned callee, unsigned argCount)
    591 {
    592     emitGetArg(callee, X86::ecx); // Load callee JSFunction into ecx
    593     m_jit.movl_rm(X86::eax, RegisterFile::CodeBlock * static_cast<int>(sizeof(Register)), X86::edx); // callee CodeBlock was returned in eax
    594     m_jit.movl_i32m(asInteger(noValue()), RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register)), X86::edx);
    595     m_jit.movl_rm(X86::ecx, RegisterFile::Callee * static_cast<int>(sizeof(Register)), X86::edx);
    596 
     590void CTI::compileOpCallInitializeCallFrame(unsigned, unsigned argCount)
     591{
    597592    m_jit.movl_mr(OBJECT_OFFSET(JSFunction, m_scopeChain) + OBJECT_OFFSET(ScopeChain, m_node), X86::ecx, X86::ebx); // newScopeChain
    598     m_jit.movl_i32m(argCount, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register)), X86::edx);
    599     m_jit.movl_rm(X86::edi, RegisterFile::CallerFrame * static_cast<int>(sizeof(Register)), X86::edx);
    600     m_jit.movl_rm(X86::ebx, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)), X86::edx);
     593
     594    m_jit.movl_i32m(asInteger(noValue()), RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register)), X86::edi);
     595    m_jit.movl_rm(X86::ecx, RegisterFile::Callee * static_cast<int>(sizeof(Register)), X86::edi);
     596    m_jit.movl_i32m(argCount, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register)), X86::edi);
     597    m_jit.movl_rm(X86::ebx, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)), X86::edi);
    601598}
    602599
     
    659656    // The following is the fast case, only used whan a callee can be linked.
    660657
    661     // In the case of OpConstruct, call oout to a cti_ function to create the new object.
     658    // In the case of OpConstruct, call out to a cti_ function to create the new object.
    662659    if (opcodeID == op_construct) {
    663660        emitPutArg(X86::ecx, 0);
    664         emitGetPutArg(instruction[3].u.operand, 4, X86::eax);
    665         emitCTICall(instruction, i, Machine::cti_op_construct_JSConstructFast);
    666         emitPutResult(instruction[4].u.operand);
     661        emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
     662        emitCTICall(instruction, i, Machine::cti_op_construct_JSConstruct);
     663        emitPutResult(firstArg);
    667664        emitGetArg(callee, X86::ecx);
    668665    }
     
    27782775            int dst = instruction[i + 1].u.operand;
    27792776            int callee = instruction[i + 2].u.operand;
     2777            int firstArg = instruction[i + 4].u.operand;
    27802778            int argCount = instruction[i + 5].u.operand;
     2779            int registerOffset = instruction[i + 6].u.operand;
    27812780
    27822781            m_jit.link(iter->from, m_jit.label());
     
    27922791            X86Assembler::JmpSrc callLinkFailNotJSFunction = m_jit.emitUnlinkedJne();
    27932792
    2794             // This handles JSFunctions
    2795             emitCTICall(instruction + i, i, (opcodeID == op_construct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction);
    2796             // initialize the new call frame (pointed to by edx, after the last call), then set edi to point to it.
     2793            // First, in the cale of a construct, allocate the new object.
     2794            if (opcodeID == op_construct) {
     2795                emitCTICall(instruction, i, Machine::cti_op_construct_JSConstruct);
     2796                emitPutResult(firstArg);
     2797                emitGetArg(callee, X86::ecx);
     2798            }
     2799
     2800            // Load the callee CodeBlock* into eax
     2801            m_jit.movl_mr(OBJECT_OFFSET(JSFunction, m_body), X86::ecx, X86::eax);
     2802            m_jit.movl_mr(OBJECT_OFFSET(FunctionBodyNode, m_code), X86::eax, X86::eax);
     2803            m_jit.testl_rr(X86::eax, X86::eax);
     2804            X86Assembler::JmpSrc hasCodeBlockForLink = m_jit.emitUnlinkedJne();
     2805            emitCTICall(instruction + i, i, Machine::cti_op_call_JSFunction);
     2806            emitGetArg(callee, X86::ecx);
     2807            m_jit.link(hasCodeBlockForLink, m_jit.label());
     2808
     2809            // Speculatively roll the callframe, assuming argCount will match the arity.
     2810            m_jit.movl_rm(X86::edi, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)), X86::edi);
     2811            m_jit.addl_i32r(registerOffset * static_cast<int>(sizeof(Register)), X86::edi);
     2812
     2813            // Check argCount matches callee arity.
     2814            m_jit.cmpl_i32m(argCount, OBJECT_OFFSET(CodeBlock, numParameters), X86::eax);
     2815            X86Assembler::JmpSrc arityCheckOkayForLink = m_jit.emitUnlinkedJe();
     2816            emitPutArg(X86::eax, 12);
     2817            emitCTICall(instruction + i, i, Machine::cti_op_call_arityCheck);
     2818            emitGetArg(callee - registerOffset, X86::ecx);
     2819            m_jit.movl_rr(X86::edx, X86::edi);
     2820            m_jit.link(arityCheckOkayForLink, m_jit.label());
     2821
     2822            // initialize the new call frame (pointed to by edx, after the last call).
    27972823            compileOpCallInitializeCallFrame(callee, argCount);
    2798             m_jit.movl_rr(X86::edx, X86::edi);
    27992824
    28002825            // Try to link & repatch this call.
     
    28292854            // Next, handle JSFunctions...
    28302855            m_jit.link(isJSFunction, m_jit.label());
    2831             emitCTICall(instruction + i, i, (opcodeID == op_construct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction);
     2856
     2857            // First, in the cale of a construct, allocate the new object.
     2858            if (opcodeID == op_construct) {
     2859                emitCTICall(instruction, i, Machine::cti_op_construct_JSConstruct);
     2860                emitPutResult(firstArg);
     2861                emitGetArg(callee, X86::ecx);
     2862            }
     2863
     2864            // Load the callee CodeBlock* into eax
     2865            m_jit.movl_mr(OBJECT_OFFSET(JSFunction, m_body), X86::ecx, X86::eax);
     2866            m_jit.movl_mr(OBJECT_OFFSET(FunctionBodyNode, m_code), X86::eax, X86::eax);
     2867            m_jit.testl_rr(X86::eax, X86::eax);
     2868            X86Assembler::JmpSrc hasCodeBlock = m_jit.emitUnlinkedJne();
     2869            emitCTICall(instruction + i, i, Machine::cti_op_call_JSFunction);
     2870            emitGetArg(callee, X86::ecx);
     2871            m_jit.link(hasCodeBlock, m_jit.label());
     2872
     2873            // Speculatively roll the callframe, assuming argCount will match the arity.
     2874            m_jit.movl_rm(X86::edi, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)), X86::edi);
     2875            m_jit.addl_i32r(registerOffset * static_cast<int>(sizeof(Register)), X86::edi);
     2876
     2877            // Check argCount matches callee arity.
     2878            m_jit.cmpl_i32m(argCount, OBJECT_OFFSET(CodeBlock, numParameters), X86::eax);
     2879            X86Assembler::JmpSrc arityCheckOkay = m_jit.emitUnlinkedJe();
     2880            emitPutArg(X86::eax, 12);
     2881            emitCTICall(instruction + i, i, Machine::cti_op_call_arityCheck);
     2882            emitGetArg(callee - registerOffset, X86::ecx);
     2883            m_jit.movl_rr(X86::edx, X86::edi);
     2884            m_jit.link(arityCheckOkay, m_jit.label());
     2885
    28322886            // initialize the new call frame (pointed to by edx, after the last call).
    28332887            compileOpCallInitializeCallFrame(callee, argCount);
    2834             m_jit.movl_rr(X86::edx, X86::edi);
    28352888
    28362889            // load ctiCode from the new codeBlock.
    28372890            m_jit.movl_mr(OBJECT_OFFSET(CodeBlock, ctiCode), X86::eax, X86::eax);
    2838 
    2839             // Move the new callframe into edi.
    2840             m_jit.movl_rr(X86::edx, X86::edi);
    2841 
    2842             // Check the ctiCode has been generated (if not compile it now), and make the call.
    2843             m_jit.testl_rr(X86::eax, X86::eax);
    2844             X86Assembler::JmpSrc hasCode = m_jit.emitUnlinkedJne();
    2845             emitCTICall(instruction + i, i, Machine::cti_vm_compile);
    2846             m_jit.link(hasCode, m_jit.label());
    28472891
    28482892            emitNakedCall(i, X86::eax);
  • trunk/JavaScriptCore/VM/CTI.h

    r37991 r38209  
    8181#define ARG_instr6 static_cast<Instruction*>(ARGS[6])
    8282#define ARG_linkInfo2 static_cast<CallLinkInfo*>(ARGS[2])
     83#define ARG_codeBlock4 static_cast<CodeBlock*>(ARGS[4])
    8384
    8485#define CTI_RETURN_ADDRESS_SLOT (ARGS[-1])
  • trunk/JavaScriptCore/VM/Machine.cpp

    r38148 r38209  
    47094709}
    47104710
    4711 VoidPtrPair Machine::cti_op_call_JSFunction(CTI_ARGS)
     4711void* Machine::cti_op_call_JSFunction(CTI_ARGS)
    47124712{
    47134713    CTI_STACK_HACK();
     
    47204720    ScopeChainNode* callDataScopeChain = asFunction(ARG_src1)->m_scopeChain.node();
    47214721    CodeBlock* newCodeBlock = &asFunction(ARG_src1)->m_body->byteCode(callDataScopeChain);
    4722     CallFrame* callFrame = ARG_callFrame;
    4723     size_t registerOffset = ARG_int2;
     4722
     4723    if (!newCodeBlock->ctiCode)
     4724        CTI::compile(ARG_globalData->machine, ARG_callFrame, newCodeBlock);
     4725
     4726    return newCodeBlock;
     4727}
     4728
     4729VoidPtrPair Machine::cti_op_call_arityCheck(CTI_ARGS)
     4730{
     4731    CTI_STACK_HACK();
     4732
     4733    CallFrame* callFrame = ARG_callFrame;
     4734    CodeBlock* newCodeBlock = ARG_codeBlock4;
    47244735    int argCount = ARG_int3;
    47254736
    4726     if (LIKELY(argCount == newCodeBlock->numParameters)) {
    4727         VoidPtrPairValue pair = {{ newCodeBlock, CallFrame::create(callFrame->registers() + registerOffset) }};
    4728         return pair.i;
    4729     }
     4737    ASSERT(argCount != newCodeBlock->numParameters);
     4738
     4739    CallFrame* oldCallFrame = callFrame->callerFrame();
    47304740
    47314741    if (argCount > newCodeBlock->numParameters) {
    47324742        size_t numParameters = newCodeBlock->numParameters;
    4733         Register* r = callFrame->registers() + registerOffset + numParameters;
     4743        Register* r = callFrame->registers() + numParameters;
    47344744
    47354745        Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
     
    47374747            argv[i + argCount] = argv[i];
    47384748
    4739         VoidPtrPairValue pair = {{ newCodeBlock, CallFrame::create(r) }};
    4740         return pair.i;
    4741     }
    4742 
    4743     size_t omittedArgCount = newCodeBlock->numParameters - argCount;
    4744     Register* r = callFrame->registers() + registerOffset + omittedArgCount;
    4745     Register* newEnd = r + newCodeBlock->numCalleeRegisters;
    4746     if (!ARG_registerFile->grow(newEnd)) {
    4747         ARG_globalData->exception = createStackOverflowError(callFrame);
    4748         VM_THROW_EXCEPTION_2();
    4749     }
    4750 
    4751     Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
    4752     for (size_t i = 0; i < omittedArgCount; ++i)
    4753         argv[i] = jsUndefined();
    4754 
    4755     VoidPtrPairValue pair = {{ newCodeBlock, CallFrame::create(r) }};
     4749        callFrame = CallFrame::create(r);
     4750        callFrame->setCallerFrame(oldCallFrame);
     4751    } else {
     4752        size_t omittedArgCount = newCodeBlock->numParameters - argCount;
     4753        Register* r = callFrame->registers() + omittedArgCount;
     4754        Register* newEnd = r + newCodeBlock->numCalleeRegisters;
     4755        if (!ARG_registerFile->grow(newEnd)) {
     4756            ARG_globalData->exception = createStackOverflowError(oldCallFrame);
     4757            VM_THROW_EXCEPTION_2();
     4758        }
     4759
     4760        Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
     4761        for (size_t i = 0; i < omittedArgCount; ++i)
     4762            argv[i] = jsUndefined();
     4763
     4764        callFrame = CallFrame::create(r);
     4765        callFrame->setCallerFrame(oldCallFrame);
     4766    }
     4767
     4768    VoidPtrPairValue pair = {{ newCodeBlock, callFrame }};
    47564769    return pair.i;
    47574770}
     
    47714784    CTI::linkCall(callee, codeBlock, codeBlock->ctiCode, ARG_linkInfo2, ARG_int3);
    47724785
    4773     return codeBlock->ctiCode;
    4774 }
    4775 
    4776 void* Machine::cti_vm_compile(CTI_ARGS)
    4777 {
    4778     CTI_STACK_HACK();
    4779 
    4780     CodeBlock* codeBlock = ARG_callFrame->codeBlock();
    4781     if (!codeBlock->ctiCode)
    4782         CTI::compile(ARG_globalData->machine, ARG_callFrame, codeBlock);
    47834786    return codeBlock->ctiCode;
    47844787}
     
    49344937}
    49354938
    4936 JSObject* Machine::cti_op_construct_JSConstructFast(CTI_ARGS)
     4939JSObject* Machine::cti_op_construct_JSConstruct(CTI_ARGS)
    49374940{
    49384941    CTI_STACK_HACK();
     
    49444947
    49454948    StructureID* structure;
    4946     if (ARG_src2->isObject())
    4947         structure = asObject(ARG_src2)->inheritorID();
     4949    if (ARG_src5->isObject())
     4950        structure = asObject(ARG_src5)->inheritorID();
    49484951    else
    49494952        structure = asFunction(ARG_src1)->m_scopeChain.node()->globalObject()->emptyObjectStructure();
    49504953    return new (ARG_globalData) JSObject(structure);
    4951 }
    4952 
    4953 VoidPtrPair Machine::cti_op_construct_JSConstruct(CTI_ARGS)
    4954 {
    4955     CTI_STACK_HACK();
    4956 
    4957     CallFrame* callFrame = ARG_callFrame;
    4958 
    4959     JSFunction* constructor = asFunction(ARG_src1);
    4960     int registerOffset = ARG_int2;
    4961     int argCount = ARG_int3;
    4962     JSValue* constrProtoVal = ARG_src5;
    4963     int firstArg = ARG_int6;
    4964 
    4965 #ifndef NDEBUG
    4966     ConstructData constructData;
    4967     ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
    4968 #endif
    4969 
    4970     ScopeChainNode* callDataScopeChain = constructor->m_scopeChain.node();
    4971     FunctionBodyNode* functionBodyNode = constructor->m_body.get();
    4972     CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
    4973 
    4974     StructureID* structure;
    4975     if (constrProtoVal->isObject())
    4976         structure = asObject(constrProtoVal)->inheritorID();
    4977     else
    4978         structure = callDataScopeChain->globalObject()->emptyObjectStructure();
    4979     JSObject* newObject = new (ARG_globalData) JSObject(structure);
    4980     callFrame[firstArg] = newObject; // "this" value
    4981 
    4982     if (LIKELY(argCount == newCodeBlock->numParameters)) {
    4983         VoidPtrPairValue pair = {{ newCodeBlock, CallFrame::create(callFrame->registers() + registerOffset) }};
    4984         return pair.i;
    4985     }
    4986 
    4987     if (argCount > newCodeBlock->numParameters) {
    4988         size_t numParameters = newCodeBlock->numParameters;
    4989         Register* r = callFrame->registers() + registerOffset + numParameters;
    4990 
    4991         Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
    4992         for (size_t i = 0; i < numParameters; ++i)
    4993             argv[i + argCount] = argv[i];
    4994 
    4995         VoidPtrPairValue pair = {{ newCodeBlock, CallFrame::create(r) }};
    4996         return pair.i;
    4997     }
    4998 
    4999     size_t omittedArgCount = newCodeBlock->numParameters - argCount;
    5000     Register* r = callFrame->registers() + registerOffset + omittedArgCount;
    5001     Register* newEnd = r + newCodeBlock->numCalleeRegisters;
    5002     if (!ARG_registerFile->grow(newEnd)) {
    5003         ARG_globalData->exception = createStackOverflowError(callFrame);
    5004         VM_THROW_EXCEPTION_2();
    5005     }
    5006 
    5007     Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
    5008     for (size_t i = 0; i < omittedArgCount; ++i)
    5009         argv[i] = jsUndefined();
    5010 
    5011     VoidPtrPairValue pair = {{ newCodeBlock, CallFrame::create(r) }};
    5012     return pair.i;
    50134954}
    50144955
  • trunk/JavaScriptCore/VM/Machine.h

    r37998 r38209  
    191191        static JSValue* SFX_CALL cti_op_mul(CTI_ARGS);
    192192        static JSObject* SFX_CALL cti_op_new_func(CTI_ARGS);
    193         static VoidPtrPair SFX_CALL cti_op_call_JSFunction(CTI_ARGS);
     193        static void* SFX_CALL cti_op_call_JSFunction(CTI_ARGS);
     194        static VoidPtrPair SFX_CALL cti_op_call_arityCheck(CTI_ARGS);
    194195        static JSValue* SFX_CALL cti_op_call_NotJSFunction(CTI_ARGS);
    195196        static void SFX_CALL cti_op_create_arguments(CTI_ARGS);
     
    203204        static JSValue* SFX_CALL cti_op_resolve(CTI_ARGS);
    204205        static JSValue* SFX_CALL cti_op_resolve_global(CTI_ARGS);
    205         static JSObject* SFX_CALL cti_op_construct_JSConstructFast(CTI_ARGS);
    206         static VoidPtrPair SFX_CALL cti_op_construct_JSConstruct(CTI_ARGS);
     206        static JSObject* SFX_CALL cti_op_construct_JSConstruct(CTI_ARGS);
    207207        static JSValue* SFX_CALL cti_op_construct_NotJSConstruct(CTI_ARGS);
    208208        static JSValue* SFX_CALL cti_op_get_by_val(CTI_ARGS);
     
    269269
    270270        static JSValue* SFX_CALL cti_vm_throw(CTI_ARGS);
    271         static void* SFX_CALL cti_vm_compile(CTI_ARGS);
    272271        static void* SFX_CALL cti_vm_lazyLinkCall(CTI_ARGS);
    273272        static JSObject* SFX_CALL cti_op_push_activation(CTI_ARGS);
  • trunk/JavaScriptCore/parser/Nodes.h

    r38205 r38209  
    22462246
    22472247    class FunctionBodyNode : public ScopeNode {
     2248        friend class CTI;
    22482249    public:
    22492250        static FunctionBodyNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL;
Note: See TracChangeset for help on using the changeset viewer.