Changeset 37160 in webkit for trunk/JavaScriptCore/VM


Ignore:
Timestamp:
Oct 1, 2008, 3:18:50 PM (17 years ago)
Author:
[email protected]
Message:

2008-10-01 Cameron Zwarich <[email protected]>

Reviewed by Darin Adler.

Bug 21123: using "arguments" in a function should not force creation of an activation object
<https://bugs.webkit.org/show_bug.cgi?id=21123>

Make the 'arguments' object not require a JSActivation. We store the
'arguments' object in the OptionalCalleeArguments call frame slot. We
need to be able to get the original 'arguments' object to tear it off
when returning from a function, but 'arguments' may be assigned to in a
number of ways.

Therefore, we use the OptionalCalleeArguments slot when we want to get
the original activation or we know that 'arguments' was not assigned a
different value. When 'arguments' may have been assigned a new value,
we use a new local variable that is initialized with 'arguments'. Since
a function parameter named 'arguments' may overwrite the value of
'arguments', we also need to be careful to look up 'arguments' in the
symbol table, so we get the parameter named 'arguments' instead of the
local variable that we have added for holding the 'arguments' object.

This is a 19.1% win on the V8 Raytrace benchmark using the SunSpider
harness, and a 20.7% win using the V8 harness. This amounts to a 6.5%
total speedup on the V8 benchmark suite using the V8 harness.

JavaScriptCore:

  • VM/CTI.cpp: (JSC::CTI::privateCompileMainPass):
  • VM/CodeBlock.h:
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::CodeGenerator):
  • VM/Machine.cpp: (JSC::Machine::unwindCallFrame): (JSC::Machine::privateExecute): (JSC::Machine::retrieveArguments): (JSC::Machine::cti_op_init_arguments): (JSC::Machine::cti_op_ret_activation_arguments):
  • VM/Machine.h:
  • VM/RegisterFile.h: (JSC::RegisterFile::):
  • kjs/Arguments.cpp: (JSC::Arguments::mark): (JSC::Arguments::fillArgList): (JSC::Arguments::getOwnPropertySlot): (JSC::Arguments::put):
  • kjs/Arguments.h: (JSC::Arguments::setRegisters): (JSC::Arguments::init): (JSC::Arguments::Arguments): (JSC::Arguments::copyRegisters): (JSC::JSActivation::copyRegisters):
  • kjs/JSActivation.cpp: (JSC::JSActivation::argumentsGetter):
  • kjs/JSActivation.h: (JSC::JSActivation::JSActivationData::JSActivationData):
  • kjs/grammar.y:
  • kjs/nodes.h: (JSC::ScopeNode::setUsesArguments):
  • masm/X86Assembler.h: (JSC::X86Assembler::): (JSC::X86Assembler::orl_mr):

LayoutTests:

  • fast/js/arguments-expected.txt:
  • fast/js/function-dot-arguments-expected.txt:
  • fast/js/resources/arguments.js:
  • fast/js/resources/function-dot-arguments.js:
Location:
trunk/JavaScriptCore/VM
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/VM/CTI.cpp

    r37138 r37160  
    11911191        }
    11921192        case op_ret: {
    1193             // Check for an activation - if there is one, jump to the hook below.
    1194             m_jit.cmpl_i32m(0, RegisterFile::OptionalCalleeActivation * static_cast<int>(sizeof(Register)), X86::edi);
     1193            // If there is an activation or an 'arguments' object, we tear it
     1194            // off by jumping to the hook below.
     1195            m_jit.movl_mr(RegisterFile::OptionalCalleeActivation * static_cast<int>(sizeof(Register)), X86::edi, X86::eax);
     1196            m_jit.orl_mr(RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register)), X86::edi, X86::eax);
     1197            m_jit.cmpl_i32r(0, X86::eax);
    11951198            X86Assembler::JmpSrc activation = m_jit.emitUnlinkedJne();
    11961199            X86Assembler::JmpDst activated = m_jit.label();
     
    12221225            m_jit.ret();
    12231226
    1224             // Activation hook
     1227            // Activation and 'arguments' hook
    12251228            m_jit.link(activation, m_jit.label());
    1226             emitCall(i, Machine::cti_op_ret_activation);
     1229            emitCall(i, Machine::cti_op_ret_activation_arguments);
    12271230            m_jit.link(m_jit.emitUnlinkedJmp(), activated);
    12281231
  • trunk/JavaScriptCore/VM/CodeBlock.h

    r36821 r37160  
    242242        bool needsFullScopeChain;
    243243        bool usesEval;
     244        bool usesArguments;
    244245        CodeType codeType;
    245246        RefPtr<SourceProvider> source;
  • trunk/JavaScriptCore/VM/CodeGenerator.cpp

    r37117 r37160  
    293293    codeBlock->globalData = m_globalData;
    294294
    295     if (functionBody->usesArguments()) {
     295    bool usesArguments = functionBody->usesArguments();
     296    codeBlock->usesArguments = usesArguments;
     297    if (usesArguments) {
    296298        emitOpcode(op_init_arguments);
    297         m_codeBlock->needsFullScopeChain = true;
    298299        m_argumentsRegister.setIndex(RegisterFile::OptionalCalleeArguments);
    299         symbolTable->add(propertyNames().arguments.ustring().rep(), SymbolTableEntry(RegisterFile::OptionalCalleeArguments));
     300        addVar(propertyNames().arguments, false);
    300301    }
    301302
  • trunk/JavaScriptCore/VM/Machine.cpp

    r37125 r37160  
    802802        scopeChain->deref();
    803803
    804     // If this call frame created an activation, tear it off.
    805     if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
     804    // If this call frame created an activation or an 'arguments' object, tear it off.
     805    if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
    806806        ASSERT(activation->isObject(&JSActivation::info));
    807         activation->copyRegisters();
     807        activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
     808    } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
     809        ASSERT(arguments->isObject(&Arguments::info));
     810        arguments->copyRegisters();
    808811    }
    809812   
     
    33613364        int result = (++vPC)->u.operand;
    33623365
    3363         if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
     3366        // If this call frame created an activation or an 'arguments' object, tear it off.
     3367        if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
    33643368            ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
    33653369            ASSERT(activation->isObject(&JSActivation::info));
    3366             activation->copyRegisters();
     3370            activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
     3371        } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
     3372            ASSERT(arguments->isObject(&Arguments::info));
     3373            arguments->copyRegisters();
    33673374        }
    33683375
     
    34183425    }
    34193426    BEGIN_OPCODE(op_init_arguments) {
    3420         JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
    3421         r[RegisterFile::OptionalCalleeArguments] = activation->createArgumentsObject(exec);
     3427        JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
     3428        Arguments* arguments;
     3429        if (activation) {
     3430            ASSERT(activation->isObject(&JSActivation::info));
     3431            arguments = new (exec) Arguments(exec, static_cast<JSActivation*>(activation));
     3432        } else
     3433            arguments = new (exec) Arguments(exec, r);
     3434        r[RegisterFile::OptionalCalleeArguments] = arguments;
     3435        r[RegisterFile::ArgumentsRegister] = arguments;
     3436       
    34223437        ++vPC;
    34233438        NEXT_OPCODE;
     
    38493864        return jsNull();
    38503865
    3851     Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].jsValue(exec));
    3852     if (!arguments) {
    3853         JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
    3854         if (!activation) {
    3855             activation = new (exec) JSActivation(exec, function->m_body, r);
    3856             r[RegisterFile::OptionalCalleeActivation] = activation;
    3857         }
    3858 
    3859         arguments = activation->createArgumentsObject(exec);
    3860         r[RegisterFile::OptionalCalleeArguments] = arguments;
     3866    JSValue* arguments;
     3867    CodeBlock* codeBlock = Machine::codeBlock(r);
     3868    if (codeBlock->usesArguments) {
     3869        ASSERT(codeBlock->codeType == FunctionCode);
     3870        SymbolTable& symbolTable = static_cast<FunctionBodyNode*>(codeBlock->ownerNode)->symbolTable();
     3871        int argumentsIndex = symbolTable.get(exec->propertyNames().arguments.ustring().rep()).getIndex();
     3872        arguments = r[argumentsIndex].jsValue(exec);
     3873    } else {
     3874        arguments = r[RegisterFile::OptionalCalleeArguments].getJSValue();
     3875        if (!arguments) {
     3876            JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
     3877            if (activation)
     3878                arguments = new (exec) Arguments(exec, activation);
     3879            else
     3880                arguments = new (exec) Arguments(exec, r);
     3881            r[RegisterFile::OptionalCalleeArguments] = arguments;
     3882        }
     3883        ASSERT(arguments->isObject(&Arguments::info));
    38613884    }
    38623885
     
    46004623    ExecState* exec = ARG_exec;
    46014624    Register* r = ARG_r;
    4602     JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
    4603     r[RegisterFile::OptionalCalleeArguments] = activation->createArgumentsObject(exec);
    4604 }
    4605 
    4606 void Machine::cti_op_ret_activation(CTI_ARGS)
    4607 {
    4608     ExecState* exec = ARG_exec;
     4625
     4626    JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
     4627    Arguments* arguments;
     4628    if (activation) {
     4629        ASSERT(activation->isObject(&JSActivation::info));
     4630        arguments = new (exec) Arguments(exec, static_cast<JSActivation*>(activation));
     4631    } else
     4632        arguments = new (exec) Arguments(exec, r);
     4633    r[RegisterFile::OptionalCalleeArguments] = arguments;
     4634    r[RegisterFile::ArgumentsRegister] = arguments;
     4635}
     4636
     4637void Machine::cti_op_ret_activation_arguments(CTI_ARGS)
     4638{
    46094639    Register* r = ARG_r;
    46104640
    4611     JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec));
    4612     ASSERT(activation);
    4613 
    4614     ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
    4615     ASSERT(activation->isObject(&JSActivation::info));
    4616     activation->copyRegisters();
     4641    // If this call frame created an activation or an 'arguments' object, tear it off.
     4642    if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
     4643        ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
     4644        ASSERT(activation->isObject(&JSActivation::info));
     4645        activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
     4646    } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
     4647        ASSERT(arguments->isObject(&Arguments::info));
     4648        arguments->copyRegisters();
     4649    }
    46174650}
    46184651
  • trunk/JavaScriptCore/VM/Machine.h

    r37086 r37160  
    164164        static JSValue* SFX_CALL cti_op_call_NotJSFunction(CTI_ARGS);
    165165        static void SFX_CALL cti_op_init_arguments(CTI_ARGS);
    166         static void SFX_CALL cti_op_ret_activation(CTI_ARGS);
     166        static void SFX_CALL cti_op_ret_activation_arguments(CTI_ARGS);
    167167        static void SFX_CALL cti_op_ret_profiler(CTI_ARGS);
    168168        static void SFX_CALL cti_op_ret_scopeChain(CTI_ARGS);
  • trunk/JavaScriptCore/VM/RegisterFile.h

    r37086 r37160  
    105105
    106106        enum { ProgramCodeThisRegister = -CallFrameHeaderSize - 1 };
     107        enum { ArgumentsRegister = 0 };
    107108
    108109        enum { DefaultCapacity = 2 * 1024 * 1024 / sizeof(Register) };
Note: See TracChangeset for help on using the changeset viewer.