Changeset 37160 in webkit for trunk/JavaScriptCore/VM/Machine.cpp


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:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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
Note: See TracChangeset for help on using the changeset viewer.