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/kjs/Arguments.h

    r36779 r37160  
    2525#define Arguments_h
    2626
    27 #include "JSObject.h"
     27#include "JSActivation.h"
     28#include "JSFunction.h"
     29#include "JSGlobalObject.h"
     30#include "Machine.h"
    2831
    2932namespace JSC {
    3033
    31     class JSActivation;
    32     class JSFunction;
    33     class Register;
     34    struct ArgumentsData : Noncopyable {
     35        JSActivation* activation;
    3436
    35     struct ArgumentsData;
     37        unsigned numParameters;
     38        int firstParameterIndex;
     39        unsigned numArguments;
     40
     41        Register* registers;
     42        OwnArrayPtr<Register> registerArray;
     43
     44        Register* extraArguments;
     45        OwnArrayPtr<bool> deletedArguments;
     46        Register extraArgumentsFixedBuffer[4];
     47
     48        JSFunction* callee;
     49        bool overrodeLength : 1;
     50        bool overrodeCallee : 1;
     51    };
     52
    3653
    3754    class Arguments : public JSObject {
    3855    public:
    39         Arguments(ExecState*, JSFunction*, JSActivation*, int firstArgumentIndex, Register* argv, int argc);
     56        Arguments(ExecState*, Register* callFrame);
     57        Arguments(ExecState*, JSActivation*);
    4058        virtual ~Arguments();
    4159
     
    4563
    4664        void fillArgList(ExecState*, ArgList&);
     65
     66        void copyRegisters();
     67        void setRegisters(Register* registers) { d->registers = registers; }
    4768
    4869    private:
     
    5677        virtual const ClassInfo* classInfo() const { return &info; }
    5778
     79        void init(ExecState*, Register* callFrame);
     80
    5881        OwnPtr<ArgumentsData> d;
    5982    };
     83
     84    inline void Arguments::init(ExecState* exec, Register* callFrame)
     85    {
     86        JSFunction* callee;
     87        int firstParameterIndex;
     88        Register* argv;
     89        int numArguments;
     90        exec->machine()->getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments);
     91
     92        d->numParameters = callee->numParameters();
     93        d->firstParameterIndex = firstParameterIndex;
     94        d->numArguments = numArguments;
     95
     96        d->registers = callFrame;
     97
     98        Register* extraArguments;
     99        if (d->numArguments <= d->numParameters)
     100            extraArguments = 0;
     101        else {
     102            unsigned numExtraArguments = d->numArguments - d->numParameters;
     103            if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
     104                extraArguments = new Register[numExtraArguments];
     105            else
     106                extraArguments = d->extraArgumentsFixedBuffer;
     107            for (unsigned i = 0; i < numExtraArguments; ++i)
     108                extraArguments[i] = argv[d->numParameters + i];
     109        }
     110
     111        d->extraArguments = extraArguments;
     112
     113        d->callee = callee;
     114        d->overrodeLength = false;
     115        d->overrodeCallee = false;
     116    }
     117
     118    inline Arguments::Arguments(ExecState* exec, Register* callFrame)
     119        : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
     120        , d(new ArgumentsData)
     121    {
     122        d->activation = 0;
     123        init(exec, callFrame);
     124    }
     125
     126    inline Arguments::Arguments(ExecState* exec, JSActivation* activation)
     127        : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
     128        , d(new ArgumentsData)
     129    {
     130        ASSERT(activation);
     131        d->activation = activation;
     132        init(exec, &activation->registerAt(0));
     133    }
     134
     135    inline void Arguments::copyRegisters()
     136    {
     137        ASSERT(!d->activation);
     138        ASSERT(!d->registerArray);
     139
     140        size_t numParametersMinusThis = d->callee->m_body->generatedByteCode().numParameters - 1;
     141
     142        if (!numParametersMinusThis)
     143            return;
     144
     145        int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
     146        size_t registerArraySize = numParametersMinusThis;
     147
     148        Register* registerArray = new Register[registerArraySize];
     149        memcpy(registerArray, d->registers - registerOffset, registerArraySize * sizeof(Register));
     150        d->registerArray.set(registerArray);
     151        d->registers = registerArray + registerOffset;
     152    }
     153
     154    // This JSActivation function is defined here so it can get at Arguments::setRegisters.
     155    inline void JSActivation::copyRegisters(JSValue* arguments)
     156    {
     157        ASSERT(!d()->registerArray);
     158
     159        size_t numParametersMinusThis = d()->functionBody->generatedByteCode().numParameters - 1;
     160        size_t numVars = d()->functionBody->generatedByteCode().numVars;
     161        size_t numLocals = numVars + numParametersMinusThis;
     162
     163        if (!numLocals)
     164            return;
     165
     166        int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
     167        size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize;
     168
     169        Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize);
     170        setRegisters(registerArray + registerOffset, registerArray);
     171        if (arguments) {
     172            ASSERT(arguments->isObject(&Arguments::info));
     173            static_cast<Arguments*>(arguments)->setRegisters(registerArray + registerOffset);
     174        }
     175    }
    60176
    61177} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.