Changeset 37324 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
Oct 5, 2008, 11:00:58 PM (17 years ago)
Author:
[email protected]
Message:

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

Reviewed by Oliver Hunt.

Bug 21364: Remove the branch in op_ret for OptionalCalleeActivation and OptionalCalleeArguments
<https://bugs.webkit.org/show_bug.cgi?id=21364>

Use information from the parser to detect whether an activation is
needed or 'arguments' is used, and emit explicit instructions to tear
them off before op_ret. This allows a branch to be removed from op_ret
and simplifies some other code. This does cause a small change in the
behaviour of 'f.arguments'; it is no longer live when 'arguments' is not
mentioned in the lexical scope of the function.

It should now be easy to remove the OptionaCalleeActivation slot in the
call frame, but this will be done in a later patch.

JavaScriptCore:

  • VM/CTI.cpp: (JSC::CTI::privateCompileMainPass):
  • VM/CodeBlock.cpp: (JSC::CodeBlock::dump):
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::emitReturn):
  • VM/CodeGenerator.h:
  • VM/Machine.cpp: (JSC::Machine::unwindCallFrame): (JSC::Machine::privateExecute): (JSC::Machine::retrieveArguments): (JSC::Machine::cti_op_create_arguments): (JSC::Machine::cti_op_tear_off_activation): (JSC::Machine::cti_op_tear_off_arguments):
  • VM/Machine.h:
  • VM/Opcode.h:
  • kjs/Arguments.cpp: (JSC::Arguments::mark):
  • kjs/Arguments.h: (JSC::Arguments::isTornOff): (JSC::Arguments::Arguments): (JSC::Arguments::copyRegisters): (JSC::JSActivation::copyRegisters):
  • kjs/JSActivation.cpp: (JSC::JSActivation::argumentsGetter):
  • kjs/JSActivation.h:

LayoutTests:

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

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r37323 r37324  
     12008-10-05  Cameron Zwarich  <[email protected]>
     2
     3        Reviewed by Oliver Hunt.
     4
     5        Bug 21364: Remove the branch in op_ret for OptionalCalleeActivation and OptionalCalleeArguments
     6        <https://bugs.webkit.org/show_bug.cgi?id=21364>
     7
     8        Use information from the parser to detect whether an activation is
     9        needed or 'arguments' is used, and emit explicit instructions to tear
     10        them off before op_ret. This allows a branch to be removed from op_ret
     11        and simplifies some other code. This does cause a small change in the
     12        behaviour of 'f.arguments'; it is no longer live when 'arguments' is not
     13        mentioned in the lexical scope of the function.
     14
     15        It should now be easy to remove the OptionaCalleeActivation slot in the
     16        call frame, but this will be done in a later patch.
     17
     18        * VM/CTI.cpp:
     19        (JSC::CTI::privateCompileMainPass):
     20        * VM/CodeBlock.cpp:
     21        (JSC::CodeBlock::dump):
     22        * VM/CodeGenerator.cpp:
     23        (JSC::CodeGenerator::emitReturn):
     24        * VM/CodeGenerator.h:
     25        * VM/Machine.cpp:
     26        (JSC::Machine::unwindCallFrame):
     27        (JSC::Machine::privateExecute):
     28        (JSC::Machine::retrieveArguments):
     29        (JSC::Machine::cti_op_create_arguments):
     30        (JSC::Machine::cti_op_tear_off_activation):
     31        (JSC::Machine::cti_op_tear_off_arguments):
     32        * VM/Machine.h:
     33        * VM/Opcode.h:
     34        * kjs/Arguments.cpp:
     35        (JSC::Arguments::mark):
     36        * kjs/Arguments.h:
     37        (JSC::Arguments::isTornOff):
     38        (JSC::Arguments::Arguments):
     39        (JSC::Arguments::copyRegisters):
     40        (JSC::JSActivation::copyRegisters):
     41        * kjs/JSActivation.cpp:
     42        (JSC::JSActivation::argumentsGetter):
     43        * kjs/JSActivation.h:
     44
    1452008-10-05  Maciej Stachowiak  <[email protected]>
    246
  • trunk/JavaScriptCore/VM/CTI.cpp

    r37297 r37324  
    11711171            break;
    11721172        }
     1173        case op_tear_off_activation: {
     1174            emitCall(i, Machine::cti_op_tear_off_activation);
     1175            i += 1;
     1176            break;
     1177        }
     1178        case op_tear_off_arguments: {
     1179            emitCall(i, Machine::cti_op_tear_off_arguments);
     1180            i += 1;
     1181            break;
     1182        }
    11731183        case op_ret: {
    1174             // If there is an activation or an 'arguments' object, we tear it
    1175             // off by jumping to the hook below.
    1176             m_jit.movl_mr(RegisterFile::OptionalCalleeActivation * static_cast<int>(sizeof(Register)), X86::edi, X86::eax);
    1177             m_jit.orl_mr(RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register)), X86::edi, X86::eax);
    1178             m_jit.cmpl_i32r(0, X86::eax);
    1179             X86Assembler::JmpSrc activation = m_jit.emitUnlinkedJne();
    1180             X86Assembler::JmpDst activated = m_jit.label();
    1181 
    11821184            // Check for a profiler - if there is one, jump to the hook below.
    11831185            emitGetCTIParam(CTI_ARGS_profilerReference, X86::eax);
     
    12031205            m_jit.pushl_r(X86::edx);
    12041206            m_jit.ret();
    1205 
    1206             // Activation and 'arguments' hook
    1207             m_jit.link(activation, m_jit.label());
    1208             emitCall(i, Machine::cti_op_ret_activation_arguments);
    1209             m_jit.link(m_jit.emitUnlinkedJmp(), activated);
    12101207
    12111208            // Profiling hook
  • trunk/JavaScriptCore/VM/CodeBlock.cpp

    r37294 r37324  
    810810            break;
    811811        }
     812        case op_tear_off_activation: {
     813            int r0 = (++it)->u.operand;
     814            printf("[%4d] tear_off_activation\t %s\n", location, registerName(r0).c_str());
     815            break;
     816        }
     817        case op_tear_off_arguments: {
     818            int r0 = (++it)->u.operand;
     819            printf("[%4d] tear_off_arguments\t %s\n", location, registerName(r0).c_str());
     820            break;
     821        }
    812822        case op_ret: {
    813823            int r0 = (++it)->u.operand;
  • trunk/JavaScriptCore/VM/CodeGenerator.cpp

    r37320 r37324  
    11591159}
    11601160
     1161RegisterID* CodeGenerator::emitReturn(RegisterID* src)
     1162{
     1163    if (m_codeBlock->needsFullScopeChain)
     1164        emitOpcode(op_tear_off_activation);
     1165    else if (m_codeBlock->usesArguments)
     1166        emitOpcode(op_tear_off_arguments);
     1167
     1168    return emitUnaryNoDstOp(op_ret, src);
     1169}
     1170
    11611171RegisterID* CodeGenerator::emitUnaryNoDstOp(OpcodeID opcode, RegisterID* src)
    11621172{
  • trunk/JavaScriptCore/VM/CodeGenerator.h

    r37050 r37324  
    278278        RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
    279279
    280         RegisterID* emitReturn(RegisterID* src) { return emitUnaryNoDstOp(op_ret, src); }
     280        RegisterID* emitReturn(RegisterID* src);
    281281        RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); }
    282282
  • trunk/JavaScriptCore/VM/Machine.cpp

    r37323 r37324  
    782782    if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
    783783        ASSERT(activation->isObject(&JSActivation::info));
    784         activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
     784        Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
     785        ASSERT(!arguments || arguments->isObject(&Arguments::info));
     786        activation->copyRegisters(arguments);
    785787    } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
    786788        ASSERT(arguments->isObject(&Arguments::info));
    787         arguments->copyRegisters();
     789        if (!arguments->isTornOff())
     790            arguments->copyRegisters();
    788791    }
    789792   
     
    33523355        goto vm_throw;
    33533356    }
     3357    BEGIN_OPCODE(op_tear_off_activation) {
     3358        JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
     3359        ASSERT(codeBlock(r)->needsFullScopeChain);
     3360        ASSERT(activation->isObject(&JSActivation::info));
     3361
     3362        Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
     3363        ASSERT(!arguments || arguments->isObject(&Arguments::info));
     3364        activation->copyRegisters(arguments);
     3365
     3366        ++vPC;
     3367        NEXT_OPCODE;
     3368    }
     3369    BEGIN_OPCODE(op_tear_off_arguments) {
     3370        Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
     3371        ASSERT(codeBlock(r)->usesArguments && !codeBlock(r)->needsFullScopeChain);
     3372        ASSERT(arguments->isObject(&Arguments::info));
     3373
     3374        arguments->copyRegisters();
     3375
     3376        ++vPC;
     3377        NEXT_OPCODE;
     3378    }
    33543379    BEGIN_OPCODE(op_ret) {
    33553380        /* ret result(r)
     
    33643389        int result = (++vPC)->u.operand;
    33653390
    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())) {
    3368             ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
    3369             ASSERT(activation->isObject(&JSActivation::info));
    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();
    3374         }
    3375 
    33763391        if (*enabledProfilerReference)
    33773392            (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(r[RegisterFile::Callee].jsValue(exec)));
     
    34663481        */
    34673482
    3468         JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
    3469         Arguments* arguments;
    3470         if (activation) {
    3471             ASSERT(activation->isObject(&JSActivation::info));
    3472             arguments = new (globalData) Arguments(exec, static_cast<JSActivation*>(activation));
    3473         } else
    3474             arguments = new (globalData) Arguments(exec, r);
     3483        Arguments* arguments = new (globalData) Arguments(exec, r);
    34753484        r[RegisterFile::OptionalCalleeArguments] = arguments;
    34763485        r[RegisterFile::ArgumentsRegister] = arguments;
     
    39083917        return jsNull();
    39093918
    3910     JSValue* arguments;
    39113919    CodeBlock* codeBlock = Machine::codeBlock(r);
    39123920    if (codeBlock->usesArguments) {
     
    39143922        SymbolTable& symbolTable = static_cast<FunctionBodyNode*>(codeBlock->ownerNode)->symbolTable();
    39153923        int argumentsIndex = symbolTable.get(exec->propertyNames().arguments.ustring().rep()).getIndex();
    3916         arguments = r[argumentsIndex].jsValue(exec);
    3917     } else {
    3918         arguments = r[RegisterFile::OptionalCalleeArguments].getJSValue();
    3919         if (!arguments) {
    3920             JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
    3921             if (activation)
    3922                 arguments = new (exec) Arguments(exec, activation);
    3923             else
    3924                 arguments = new (exec) Arguments(exec, r);
    3925             r[RegisterFile::OptionalCalleeArguments] = arguments;
    3926         }
    3927         ASSERT(arguments->isObject(&Arguments::info));
    3928     }
     3924        return r[argumentsIndex].jsValue(exec);
     3925    }
     3926
     3927    Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
     3928    if (!arguments) {
     3929        arguments = new (exec) Arguments(exec, r);
     3930        arguments->copyRegisters();
     3931        r[RegisterFile::OptionalCalleeArguments] = arguments;
     3932    }
     3933    ASSERT(arguments->isObject(&Arguments::info));
    39293934
    39303935    return arguments;
     
    46544659    Register* r = ARG_r;
    46554660
    4656     JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
    4657     Arguments* arguments;
    4658     if (activation) {
    4659         ASSERT(activation->isObject(&JSActivation::info));
    4660         arguments = new (ARG_globalData) Arguments(exec, static_cast<JSActivation*>(activation));
    4661     } else
    4662         arguments = new (ARG_globalData) Arguments(exec, r);
     4661    Arguments* arguments = new (ARG_globalData) Arguments(exec, r);
    46634662    r[RegisterFile::OptionalCalleeArguments] = arguments;
    46644663    r[RegisterFile::ArgumentsRegister] = arguments;
    46654664}
    46664665
    4667 void Machine::cti_op_ret_activation_arguments(CTI_ARGS)
     4666void Machine::cti_op_tear_off_activation(CTI_ARGS)
    46684667{
    46694668    Register* r = ARG_r;
    46704669
    4671     // If this call frame created an activation or an 'arguments' object, tear it off.
    4672     if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
    4673         ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
    4674         ASSERT(activation->isObject(&JSActivation::info));
    4675         activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
    4676     } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
    4677         ASSERT(arguments->isObject(&Arguments::info));
    4678         arguments->copyRegisters();
    4679     }
     4670    JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
     4671    ASSERT(codeBlock(r)->needsFullScopeChain);
     4672    ASSERT(activation->isObject(&JSActivation::info));
     4673
     4674    Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
     4675    ASSERT(!arguments || arguments->isObject(&Arguments::info));
     4676    activation->copyRegisters(arguments);
     4677}
     4678
     4679void Machine::cti_op_tear_off_arguments(CTI_ARGS)
     4680{
     4681    Register* r = ARG_r;
     4682
     4683    Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
     4684    ASSERT(codeBlock(r)->usesArguments && !codeBlock(r)->needsFullScopeChain);
     4685    ASSERT(arguments->isObject(&Arguments::info));
     4686
     4687    arguments->copyRegisters();
    46804688}
    46814689
  • trunk/JavaScriptCore/VM/Machine.h

    r37323 r37324  
    165165        static JSValue* SFX_CALL cti_op_call_NotJSFunction(CTI_ARGS);
    166166        static void SFX_CALL cti_op_create_arguments(CTI_ARGS);
    167         static void SFX_CALL cti_op_ret_activation_arguments(CTI_ARGS);
     167        static void SFX_CALL cti_op_tear_off_activation(CTI_ARGS);
     168        static void SFX_CALL cti_op_tear_off_arguments(CTI_ARGS);
    168169        static void SFX_CALL cti_op_ret_profiler(CTI_ARGS);
    169170        static void SFX_CALL cti_op_ret_scopeChain(CTI_ARGS);
  • trunk/JavaScriptCore/VM/Opcode.h

    r37294 r37324  
    138138        macro(op_call) \
    139139        macro(op_call_eval) \
     140        macro(op_tear_off_activation) \
     141        macro(op_tear_off_arguments) \
    140142        macro(op_ret) \
    141143        \
  • trunk/JavaScriptCore/kjs/Arguments.cpp

    r37268 r37324  
    6565    if (!d->callee->marked())
    6666        d->callee->mark();
    67 
    68     if (d->activation && !d->activation->marked())
    69         d->activation->mark();
    7067}
    7168
  • trunk/JavaScriptCore/kjs/Arguments.h

    r37268 r37324  
    3333
    3434    struct ArgumentsData : Noncopyable {
    35         JSActivation* activation;
    36 
    3735        unsigned numParameters;
    3836        ptrdiff_t firstParameterIndex;
     
    5553    public:
    5654        Arguments(ExecState*, Register* callFrame);
    57         Arguments(ExecState*, JSActivation*);
    5855        virtual ~Arguments();
    5956
     
    6562
    6663        void copyRegisters();
     64        bool isTornOff() const { return d->registerArray; }
    6765        void setRegisters(Register* registers) { d->registers = registers; }
    6866
     
    8280    };
    8381
    84     inline void Arguments::init(ExecState* exec, Register* callFrame)
     82    inline Arguments::Arguments(ExecState* exec, Register* callFrame)
     83        : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
     84        , d(new ArgumentsData)
    8585    {
    8686        JSFunction* callee;
     
    116116    }
    117117
    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 
    135118    inline void Arguments::copyRegisters()
    136119    {
    137         ASSERT(!d->activation);
    138         ASSERT(!d->registerArray);
     120        ASSERT(!isTornOff());
    139121
    140122        if (!d->numParameters)
     
    151133
    152134    // This JSActivation function is defined here so it can get at Arguments::setRegisters.
    153     inline void JSActivation::copyRegisters(JSValue* arguments)
     135    inline void JSActivation::copyRegisters(Arguments* arguments)
    154136    {
    155137        ASSERT(!d()->registerArray);
     
    167149        Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize);
    168150        setRegisters(registerArray + registerOffset, registerArray);
    169         if (arguments) {
    170             ASSERT(arguments->isObject(&Arguments::info));
     151        if (arguments && !arguments->isTornOff())
    171152            static_cast<Arguments*>(arguments)->setRegisters(registerArray + registerOffset);
    172         }
    173153    }
    174154
  • trunk/JavaScriptCore/kjs/JSActivation.cpp

    r37285 r37324  
    156156    JSActivation* thisObj = static_cast<JSActivation*>(slot.slotBase());
    157157
    158     JSValue* arguments;
    159158    if (thisObj->d()->functionBody->usesArguments()) {
    160159        PropertySlot slot;
    161160        thisObj->symbolTableGet(exec->propertyNames().arguments, slot);
    162         arguments = slot.getValue(exec, exec->propertyNames().arguments);
    163     } else {
    164         arguments = thisObj->d()->registers[RegisterFile::OptionalCalleeArguments].getJSValue();
    165         if (!arguments) {
    166             arguments = new (exec) Arguments(exec, thisObj);
    167             thisObj->d()->registers[RegisterFile::OptionalCalleeArguments] = arguments;
    168         }
    169         ASSERT(arguments->isObject(&Arguments::info));
     161        return slot.getValue(exec, exec->propertyNames().arguments);
    170162    }
     163
     164    Arguments* arguments = static_cast<Arguments*>(thisObj->d()->registers[RegisterFile::OptionalCalleeArguments].getJSValue());
     165    if (!arguments) {
     166        arguments = new (exec) Arguments(exec, &thisObj->registerAt(0));
     167        arguments->copyRegisters();
     168        thisObj->d()->registers[RegisterFile::OptionalCalleeArguments] = arguments;
     169    }
     170    ASSERT(arguments->isObject(&Arguments::info));
    171171
    172172    return arguments;
  • trunk/JavaScriptCore/kjs/JSActivation.h

    r37285 r37324  
    6060        virtual JSObject* toThisObject(ExecState*) const;
    6161
    62         void copyRegisters(JSValue* arguments);
     62        void copyRegisters(Arguments* arguments);
    6363       
    6464        virtual const ClassInfo* classInfo() const { return &info; }
Note: See TracChangeset for help on using the changeset viewer.