Ignore:
Timestamp:
May 12, 2009, 1:58:56 AM (16 years ago)
Author:
[email protected]
Message:

Improve function call forwarding performance

Reviewed by Gavin Barraclough

Make creation of the Arguments object occur lazily, so it
is not necessarily created for every function that references
it. Then add logic to Function.apply to allow it to avoid
allocating the Arguments object at all. Helps a lot with
the function forwarding/binding logic in jQuery, Prototype,
and numerous other JS libraries.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r43424 r43559  
    30863086        JSValue arguments = callFrame[argsOffset].jsValue();
    30873087        uint32_t argCount = 0;
    3088         if (!arguments.isUndefinedOrNull()) {
     3088        if (!arguments) {
     3089            argCount = (uint32_t)(callFrame[RegisterFile::ArgumentCount].u.i) - 1;
     3090            int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
     3091            Register* newEnd = callFrame->registers() + sizeDelta;
     3092            if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
     3093                exceptionValue = createStackOverflowError(callFrame);
     3094                goto vm_throw;
     3095            }
     3096            uint32_t expectedParams = asFunction(callFrame[RegisterFile::Callee].jsValue())->body()->parameterCount();
     3097            uint32_t inplaceArgs = min(argCount, expectedParams);
     3098            uint32_t i = 0;
     3099            Register* argStore = callFrame->registers() + argsOffset;
     3100
     3101            // First step is to copy the "expected" parameters from their normal location relative to the callframe
     3102            for (; i < inplaceArgs; i++)
     3103                argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams];
     3104            // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
     3105            for (; i < argCount; i++)
     3106                argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - argCount - 1];
     3107        } else if (!arguments.isUndefinedOrNull()) {
    30893108            if (!arguments.isObject()) {
    30903109                exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
     
    32503269
    32513270        ASSERT(callFrame->codeBlock()->usesArguments() && !callFrame->codeBlock()->needsFullScopeChain());
    3252 
    3253         callFrame->optionalCalleeArguments()->copyRegisters();
     3271        if (callFrame->optionalCalleeArguments())
     3272            callFrame->optionalCalleeArguments()->copyRegisters();
    32543273
    32553274        ++vPC;
     
    33573376        NEXT_INSTRUCTION();
    33583377    }
     3378    DEFINE_OPCODE(op_init_arguments) {
     3379        /* create_arguments
     3380
     3381           Initialises the arguments object reference to null to ensure
     3382           we can correctly detect that we need to create it later (or
     3383           avoid creating it altogether).
     3384
     3385           This opcode should only be used at the beginning of a code
     3386           block.
     3387         */
     3388        callFrame[RegisterFile::ArgumentsRegister] = JSValue();
     3389        ++vPC;
     3390        NEXT_INSTRUCTION();
     3391    }
    33593392    DEFINE_OPCODE(op_create_arguments) {
    33603393        /* create_arguments
     
    33623395           Creates the 'arguments' object and places it in both the
    33633396           'arguments' call frame slot and the local 'arguments'
    3364            register.
    3365 
    3366            This opcode should only be used at the beginning of a code
    3367            block.
    3368         */
    3369 
    3370         Arguments* arguments = new (globalData) Arguments(callFrame);
    3371         callFrame->setCalleeArguments(arguments);
    3372         callFrame[RegisterFile::ArgumentsRegister] = arguments;
     3397           register, if it has not already been initialised.
     3398         */
    33733399       
     3400         if (!callFrame->optionalCalleeArguments()) {
     3401             Arguments* arguments = new (globalData) Arguments(callFrame);
     3402             callFrame->setCalleeArguments(arguments);
     3403             callFrame[RegisterFile::ArgumentsRegister] = arguments;
     3404         }
    33743405        ++vPC;
    33753406        NEXT_INSTRUCTION();
     
    38393870        SymbolTable& symbolTable = codeBlock->symbolTable();
    38403871        int argumentsIndex = symbolTable.get(functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex();
     3872        if (!functionCallFrame[argumentsIndex].arguments()) {
     3873            Arguments* arguments = new (callFrame) Arguments(functionCallFrame);
     3874            functionCallFrame->setCalleeArguments(arguments);
     3875            functionCallFrame[RegisterFile::ArgumentsRegister] = arguments;
     3876        }
    38413877        return functionCallFrame[argumentsIndex].jsValue();
    38423878    }
Note: See TracChangeset for help on using the changeset viewer.