2008-10-05 Cameron Zwarich <zwarich@apple.com>
authorcwzwarich@webkit.org <cwzwarich@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Oct 2008 06:00:58 +0000 (06:00 +0000)
committercwzwarich@webkit.org <cwzwarich@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Oct 2008 06:00:58 +0000 (06:00 +0000)
        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:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@37324 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CodeBlock.cpp
JavaScriptCore/VM/CodeGenerator.cpp
JavaScriptCore/VM/CodeGenerator.h
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/Machine.h
JavaScriptCore/VM/Opcode.h
JavaScriptCore/kjs/Arguments.cpp
JavaScriptCore/kjs/Arguments.h
JavaScriptCore/kjs/JSActivation.cpp
JavaScriptCore/kjs/JSActivation.h
LayoutTests/ChangeLog
LayoutTests/fast/js/function-dot-arguments-expected.txt
LayoutTests/fast/js/resources/function-dot-arguments.js

index 6102e2c..5a0c224 100644 (file)
@@ -1,3 +1,47 @@
+2008-10-05  Cameron Zwarich  <zwarich@apple.com>
+
+        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.
+
+        * 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:
+
 2008-10-05  Maciej Stachowiak  <mjs@apple.com>
 
         Reviewed by Oliver Hunt.
index dd4e0db..6c2d744 100644 (file)
@@ -1170,15 +1170,17 @@ void CTI::privateCompileMainPass()
             i += 4;
             break;
         }
+        case op_tear_off_activation: {
+            emitCall(i, Machine::cti_op_tear_off_activation);
+            i += 1;
+            break;
+        }
+        case op_tear_off_arguments: {
+            emitCall(i, Machine::cti_op_tear_off_arguments);
+            i += 1;
+            break;
+        }
         case op_ret: {
-            // If there is an activation or an 'arguments' object, we tear it
-            // off by jumping to the hook below.
-            m_jit.movl_mr(RegisterFile::OptionalCalleeActivation * static_cast<int>(sizeof(Register)), X86::edi, X86::eax);
-            m_jit.orl_mr(RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register)), X86::edi, X86::eax);
-            m_jit.cmpl_i32r(0, X86::eax);
-            X86Assembler::JmpSrc activation = m_jit.emitUnlinkedJne();
-            X86Assembler::JmpDst activated = m_jit.label();
-
             // Check for a profiler - if there is one, jump to the hook below.
             emitGetCTIParam(CTI_ARGS_profilerReference, X86::eax);
             m_jit.cmpl_i32m(0, X86::eax);
@@ -1203,11 +1205,6 @@ void CTI::privateCompileMainPass()
             m_jit.pushl_r(X86::edx);
             m_jit.ret();
 
-            // Activation and 'arguments' hook
-            m_jit.link(activation, m_jit.label());
-            emitCall(i, Machine::cti_op_ret_activation_arguments);
-            m_jit.link(m_jit.emitUnlinkedJmp(), activated);
-
             // Profiling hook
             m_jit.link(profile, m_jit.label());
             emitCall(i, Machine::cti_op_ret_profiler);
index 6c80fc0..92371e3 100644 (file)
@@ -809,6 +809,16 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             printf("[%4d] call_eval\t\t %s, %s, %s, %d, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount, registerOffset);
             break;
         }
+        case op_tear_off_activation: {
+            int r0 = (++it)->u.operand;
+            printf("[%4d] tear_off_activation\t %s\n", location, registerName(r0).c_str());
+            break;
+        }
+        case op_tear_off_arguments: {
+            int r0 = (++it)->u.operand;
+            printf("[%4d] tear_off_arguments\t %s\n", location, registerName(r0).c_str());
+            break;
+        }
         case op_ret: {
             int r0 = (++it)->u.operand;
             printf("[%4d] ret\t\t %s\n", location, registerName(r0).c_str());
index 00ae883..eaf62eb 100644 (file)
@@ -1158,6 +1158,16 @@ RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Register
     return dst;
 }
 
+RegisterID* CodeGenerator::emitReturn(RegisterID* src)
+{
+    if (m_codeBlock->needsFullScopeChain)
+        emitOpcode(op_tear_off_activation);
+    else if (m_codeBlock->usesArguments)
+        emitOpcode(op_tear_off_arguments);
+
+    return emitUnaryNoDstOp(op_ret, src);
+}
+
 RegisterID* CodeGenerator::emitUnaryNoDstOp(OpcodeID opcode, RegisterID* src)
 {
     emitOpcode(opcode);
index 2d27ee2..2dc2445 100644 (file)
@@ -277,7 +277,7 @@ namespace JSC {
         RegisterID* emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
         RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
 
-        RegisterID* emitReturn(RegisterID* src) { return emitUnaryNoDstOp(op_ret, src); } 
+        RegisterID* emitReturn(RegisterID* src);
         RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); }
 
         RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
index ce14cb8..0db3c9f 100644 (file)
@@ -781,10 +781,13 @@ NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionVa
     // If this call frame created an activation or an 'arguments' object, tear it off.
     if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
         ASSERT(activation->isObject(&JSActivation::info));
-        activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
+        Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
+        ASSERT(!arguments || arguments->isObject(&Arguments::info));
+        activation->copyRegisters(arguments);
     } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
         ASSERT(arguments->isObject(&Arguments::info));
-        arguments->copyRegisters();
+        if (!arguments->isTornOff())
+            arguments->copyRegisters();
     }
     
     void* returnPC = r[RegisterFile::ReturnPC].v();
@@ -3351,6 +3354,28 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
         exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock(r));
         goto vm_throw;
     }
+    BEGIN_OPCODE(op_tear_off_activation) {
+        JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
+        ASSERT(codeBlock(r)->needsFullScopeChain);
+        ASSERT(activation->isObject(&JSActivation::info));
+
+        Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
+        ASSERT(!arguments || arguments->isObject(&Arguments::info));
+        activation->copyRegisters(arguments);
+
+        ++vPC;
+        NEXT_OPCODE;
+    }
+    BEGIN_OPCODE(op_tear_off_arguments) {
+        Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
+        ASSERT(codeBlock(r)->usesArguments && !codeBlock(r)->needsFullScopeChain);
+        ASSERT(arguments->isObject(&Arguments::info));
+
+        arguments->copyRegisters();
+
+        ++vPC;
+        NEXT_OPCODE;
+    }
     BEGIN_OPCODE(op_ret) {
         /* ret result(r)
            
@@ -3363,16 +3388,6 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
 
         int result = (++vPC)->u.operand;
 
-        // If this call frame created an activation or an 'arguments' object, tear it off.
-        if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
-            ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
-            ASSERT(activation->isObject(&JSActivation::info));
-            activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
-        } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
-            ASSERT(arguments->isObject(&Arguments::info));
-            arguments->copyRegisters();
-        }
-
         if (*enabledProfilerReference)
             (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(r[RegisterFile::Callee].jsValue(exec)));
 
@@ -3465,13 +3480,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
            block.
         */
 
-        JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
-        Arguments* arguments;
-        if (activation) {
-            ASSERT(activation->isObject(&JSActivation::info));
-            arguments = new (globalData) Arguments(exec, static_cast<JSActivation*>(activation));
-        } else
-            arguments = new (globalData) Arguments(exec, r);
+        Arguments* arguments = new (globalData) Arguments(exec, r);
         r[RegisterFile::OptionalCalleeArguments] = arguments;
         r[RegisterFile::ArgumentsRegister] = arguments;
         
@@ -3907,25 +3916,21 @@ JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
     if (!r)
         return jsNull();
 
-    JSValue* arguments;
     CodeBlock* codeBlock = Machine::codeBlock(r);
     if (codeBlock->usesArguments) {
         ASSERT(codeBlock->codeType == FunctionCode);
         SymbolTable& symbolTable = static_cast<FunctionBodyNode*>(codeBlock->ownerNode)->symbolTable();
         int argumentsIndex = symbolTable.get(exec->propertyNames().arguments.ustring().rep()).getIndex();
-        arguments = r[argumentsIndex].jsValue(exec);
-    } else {
-        arguments = r[RegisterFile::OptionalCalleeArguments].getJSValue();
-        if (!arguments) {
-            JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
-            if (activation)
-                arguments = new (exec) Arguments(exec, activation);
-            else
-                arguments = new (exec) Arguments(exec, r);
-            r[RegisterFile::OptionalCalleeArguments] = arguments;
-        }
-        ASSERT(arguments->isObject(&Arguments::info));
+        return r[argumentsIndex].jsValue(exec);
+    }
+
+    Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
+    if (!arguments) {
+        arguments = new (exec) Arguments(exec, r);
+        arguments->copyRegisters();
+        r[RegisterFile::OptionalCalleeArguments] = arguments;
     }
+    ASSERT(arguments->isObject(&Arguments::info));
 
     return arguments;
 }
@@ -4653,30 +4658,33 @@ void Machine::cti_op_create_arguments(CTI_ARGS)
     ExecState* exec = ARG_exec;
     Register* r = ARG_r;
 
-    JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
-    Arguments* arguments;
-    if (activation) {
-        ASSERT(activation->isObject(&JSActivation::info));
-        arguments = new (ARG_globalData) Arguments(exec, static_cast<JSActivation*>(activation));
-    } else
-        arguments = new (ARG_globalData) Arguments(exec, r);
+    Arguments* arguments = new (ARG_globalData) Arguments(exec, r);
     r[RegisterFile::OptionalCalleeArguments] = arguments;
     r[RegisterFile::ArgumentsRegister] = arguments;
 }
 
-void Machine::cti_op_ret_activation_arguments(CTI_ARGS)
+void Machine::cti_op_tear_off_activation(CTI_ARGS)
 {
     Register* r = ARG_r;
 
-    // If this call frame created an activation or an 'arguments' object, tear it off.
-    if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue())) {
-        ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
-        ASSERT(activation->isObject(&JSActivation::info));
-        activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
-    } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
-        ASSERT(arguments->isObject(&Arguments::info));
-        arguments->copyRegisters();
-    }
+    JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
+    ASSERT(codeBlock(r)->needsFullScopeChain);
+    ASSERT(activation->isObject(&JSActivation::info));
+
+    Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
+    ASSERT(!arguments || arguments->isObject(&Arguments::info));
+    activation->copyRegisters(arguments);
+}
+
+void Machine::cti_op_tear_off_arguments(CTI_ARGS)
+{
+    Register* r = ARG_r;
+
+    Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue());
+    ASSERT(codeBlock(r)->usesArguments && !codeBlock(r)->needsFullScopeChain);
+    ASSERT(arguments->isObject(&Arguments::info));
+
+    arguments->copyRegisters();
 }
 
 void Machine::cti_op_ret_profiler(CTI_ARGS)
index 6fd3b84..8f21b74 100644 (file)
@@ -164,7 +164,8 @@ namespace JSC {
         static void* SFX_CALL cti_op_call_JSFunction(CTI_ARGS);
         static JSValue* SFX_CALL cti_op_call_NotJSFunction(CTI_ARGS);
         static void SFX_CALL cti_op_create_arguments(CTI_ARGS);
-        static void SFX_CALL cti_op_ret_activation_arguments(CTI_ARGS);
+        static void SFX_CALL cti_op_tear_off_activation(CTI_ARGS);
+        static void SFX_CALL cti_op_tear_off_arguments(CTI_ARGS);
         static void SFX_CALL cti_op_ret_profiler(CTI_ARGS);
         static void SFX_CALL cti_op_ret_scopeChain(CTI_ARGS);
         static JSValue* SFX_CALL cti_op_new_array(CTI_ARGS);
index e50e182..30cde3c 100644 (file)
@@ -137,6 +137,8 @@ namespace JSC {
         macro(op_new_func_exp) \
         macro(op_call) \
         macro(op_call_eval) \
+        macro(op_tear_off_activation) \
+        macro(op_tear_off_arguments) \
         macro(op_ret) \
         \
         macro(op_construct) \
index fe1de62..b99c1f7 100644 (file)
@@ -64,9 +64,6 @@ void Arguments::mark()
 
     if (!d->callee->marked())
         d->callee->mark();
-
-    if (d->activation && !d->activation->marked())
-        d->activation->mark();
 }
 
 void Arguments::fillArgList(ExecState* exec, ArgList& args)
index 82592a9..a7008c6 100644 (file)
@@ -32,8 +32,6 @@
 namespace JSC {
 
     struct ArgumentsData : Noncopyable {
-        JSActivation* activation;
-
         unsigned numParameters;
         ptrdiff_t firstParameterIndex;
         unsigned numArguments;
@@ -54,7 +52,6 @@ namespace JSC {
     class Arguments : public JSObject {
     public:
         Arguments(ExecState*, Register* callFrame);
-        Arguments(ExecState*, JSActivation*);
         virtual ~Arguments();
 
         static const ClassInfo info;
@@ -64,6 +61,7 @@ namespace JSC {
         void fillArgList(ExecState*, ArgList&);
 
         void copyRegisters();
+        bool isTornOff() const { return d->registerArray; }
         void setRegisters(Register* registers) { d->registers = registers; }
 
     private:
@@ -81,7 +79,9 @@ namespace JSC {
         OwnPtr<ArgumentsData> d;
     };
 
-    inline void Arguments::init(ExecState* exec, Register* callFrame)
+    inline Arguments::Arguments(ExecState* exec, Register* callFrame)
+        : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
+        , d(new ArgumentsData)
     {
         JSFunction* callee;
         ptrdiff_t firstParameterIndex;
@@ -115,27 +115,9 @@ namespace JSC {
         d->overrodeCallee = false;
     }
 
-    inline Arguments::Arguments(ExecState* exec, Register* callFrame)
-        : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
-        , d(new ArgumentsData)
-    {
-        d->activation = 0;
-        init(exec, callFrame);
-    }
-
-    inline Arguments::Arguments(ExecState* exec, JSActivation* activation)
-        : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
-        , d(new ArgumentsData)
-    {
-        ASSERT(activation);
-        d->activation = activation;
-        init(exec, &activation->registerAt(0));
-    }
-
     inline void Arguments::copyRegisters()
     {
-        ASSERT(!d->activation);
-        ASSERT(!d->registerArray);
+        ASSERT(!isTornOff());
 
         if (!d->numParameters)
             return;
@@ -150,7 +132,7 @@ namespace JSC {
     }
 
     // This JSActivation function is defined here so it can get at Arguments::setRegisters.
-    inline void JSActivation::copyRegisters(JSValue* arguments)
+    inline void JSActivation::copyRegisters(Arguments* arguments)
     {
         ASSERT(!d()->registerArray);
 
@@ -166,10 +148,8 @@ namespace JSC {
 
         Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize);
         setRegisters(registerArray + registerOffset, registerArray);
-        if (arguments) {
-            ASSERT(arguments->isObject(&Arguments::info));
+        if (arguments && !arguments->isTornOff())
             static_cast<Arguments*>(arguments)->setRegisters(registerArray + registerOffset);
-        }
     }
 
 } // namespace JSC
index 2905510..a7c70eb 100644 (file)
@@ -155,20 +155,20 @@ JSValue* JSActivation::argumentsGetter(ExecState* exec, const Identifier&, const
 {
     JSActivation* thisObj = static_cast<JSActivation*>(slot.slotBase());
 
-    JSValue* arguments;
     if (thisObj->d()->functionBody->usesArguments()) {
         PropertySlot slot;
         thisObj->symbolTableGet(exec->propertyNames().arguments, slot);
-        arguments = slot.getValue(exec, exec->propertyNames().arguments);
-    } else {
-        arguments = thisObj->d()->registers[RegisterFile::OptionalCalleeArguments].getJSValue();
-        if (!arguments) {
-            arguments = new (exec) Arguments(exec, thisObj);
-            thisObj->d()->registers[RegisterFile::OptionalCalleeArguments] = arguments;
-        }
-        ASSERT(arguments->isObject(&Arguments::info));
+        return slot.getValue(exec, exec->propertyNames().arguments);
     }
 
+    Arguments* arguments = static_cast<Arguments*>(thisObj->d()->registers[RegisterFile::OptionalCalleeArguments].getJSValue());
+    if (!arguments) {
+        arguments = new (exec) Arguments(exec, &thisObj->registerAt(0));
+        arguments->copyRegisters();
+        thisObj->d()->registers[RegisterFile::OptionalCalleeArguments] = arguments;
+    }
+    ASSERT(arguments->isObject(&Arguments::info));
+
     return arguments;
 }
 
index ef45f27..c39168b 100644 (file)
@@ -59,7 +59,7 @@ namespace JSC {
 
         virtual JSObject* toThisObject(ExecState*) const;
 
-        void copyRegisters(JSValue* arguments);
+        void copyRegisters(Arguments* arguments);
         
         virtual const ClassInfo* classInfo() const { return &info; }
         static const ClassInfo info;
index d5a65c0..1e9a4ac 100644 (file)
@@ -1,3 +1,15 @@
+2008-10-05  Cameron Zwarich  <zwarich@apple.com>
+
+        Reviewed by Oliver Hunt.
+
+        Tests for bug 21364: Remove the branch in op_ret for OptionalCalleeActivation and OptionalCalleeArguments
+        <https://bugs.webkit.org/show_bug.cgi?id=21364>
+
+        Add tests for changes to the liveness of 'f.arguments'.
+
+        * fast/js/function-dot-arguments-expected.txt:
+        * fast/js/resources/function-dot-arguments.js:
+
 2008-10-05  Adam Barth  <abarth@webkit.org>
 
         Reviewed by Darin Adler.
index 0841970..0f74240 100644 (file)
@@ -18,6 +18,19 @@ PASS assignForInInitTest() is true
 PASS paramInitTest(true) is true
 PASS tearOffTest()[0] is true
 PASS tearOffTest2(true)[0] is true
+PASS lexicalArgumentsLiveRead1(0, 2, 3) is 1
+PASS lexicalArgumentsLiveRead2(1, 0, 3) is 2
+PASS lexicalArgumentsLiveRead3(1, 2, 0) is 3
+PASS lexicalArgumentsLiveWrite1(0, 2, 3) is 1
+PASS lexicalArgumentsLiveWrite2(1, 0, 3) is 2
+PASS lexicalArgumentsLiveWrite3(1, 2, 0) is 3
+PASS argumentsNotLiveRead1(0, 2, 3) is 0
+PASS argumentsNotLiveRead2(1, 0, 3) is 0
+PASS argumentsNotLiveRead3(1, 2, 0) is 0
+PASS argumentsNotLiveWrite1(0, 2, 3) is 0
+PASS argumentsNotLiveWrite2(1, 0, 3) is 0
+PASS argumentsNotLiveWrite3(1, 2, 0) is 0
+PASS argumentsIdentity() is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index a818b16..461e0e3 100644 (file)
@@ -185,4 +185,103 @@ function tearOffTest2()
 }
 shouldBeTrue("tearOffTest2(true)[0]");
 
+function lexicalArgumentsLiveRead1(a, b, c)
+{
+    var o = arguments;
+    a = 1;
+    return lexicalArgumentsLiveRead1.arguments[0];
+}
+shouldBe("lexicalArgumentsLiveRead1(0, 2, 3)", "1");
+
+function lexicalArgumentsLiveRead2(a, b, c)
+{
+    var o = arguments;
+    b = 2;
+    return lexicalArgumentsLiveRead2.arguments[1];
+}
+shouldBe("lexicalArgumentsLiveRead2(1, 0, 3)", "2");
+
+function lexicalArgumentsLiveRead3(a, b, c)
+{
+    var o = arguments;
+    c = 3;
+    return lexicalArgumentsLiveRead3.arguments[2];
+}
+shouldBe("lexicalArgumentsLiveRead3(1, 2, 0)", "3");
+
+function lexicalArgumentsLiveWrite1(a, b, c)
+{
+    var o = arguments;
+    lexicalArgumentsLiveWrite1.arguments[0] = 1;
+    return a;
+}
+shouldBe("lexicalArgumentsLiveWrite1(0, 2, 3)", "1");
+
+function lexicalArgumentsLiveWrite2(a, b, c)
+{
+    var o = arguments;
+    lexicalArgumentsLiveWrite2.arguments[1] = 2;
+    return b;
+}
+shouldBe("lexicalArgumentsLiveWrite2(1, 0, 3)", "2");
+
+function lexicalArgumentsLiveWrite3(a, b, c)
+{
+    var o = arguments;
+    lexicalArgumentsLiveWrite3.arguments[2] = 3;
+    return c;
+}
+shouldBe("lexicalArgumentsLiveWrite3(1, 2, 0)", "3");
+
+function argumentsNotLiveRead1(a, b, c)
+{
+    var o = argumentsNotLiveRead1.arguments;
+    a = 1;
+    return o[0];
+}
+shouldBe("argumentsNotLiveRead1(0, 2, 3)", "0");
+
+function argumentsNotLiveRead2(a, b, c)
+{
+    var o = argumentsNotLiveRead2.arguments;
+    b = 2;
+    return o[1];
+}
+shouldBe("argumentsNotLiveRead2(1, 0, 3)", "0");
+
+function argumentsNotLiveRead3(a, b, c)
+{
+    var o = argumentsNotLiveRead3.arguments;
+    c = 3;
+    return o[2];
+}
+shouldBe("argumentsNotLiveRead3(1, 2, 0)", "0");
+
+function argumentsNotLiveWrite1(a, b, c)
+{
+    argumentsNotLiveWrite1.arguments[0] = 1;
+    return a;
+}
+shouldBe("argumentsNotLiveWrite1(0, 2, 3)", "0");
+
+function argumentsNotLiveWrite2(a, b, c)
+{
+    argumentsNotLiveWrite2.arguments[1] = 2;
+    return b;
+}
+shouldBe("argumentsNotLiveWrite2(1, 0, 3)", "0");
+
+function argumentsNotLiveWrite3(a, b, c)
+{
+    argumentsNotLiveWrite3.arguments[2] = 3;
+    return c;
+}
+shouldBe("argumentsNotLiveWrite3(1, 2, 0)", "0");
+
+function argumentsIdentity()
+{
+    return argumentsIdentity.arguments == argumentsIdentity.arguments;
+}
+shouldBeTrue("argumentsIdentity()");
+
 var successfullyParsed = true;