2008-10-01 Cameron Zwarich <zwarich@apple.com>
authorcwzwarich@webkit.org <cwzwarich@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 1 Oct 2008 22:18:50 +0000 (22:18 +0000)
committercwzwarich@webkit.org <cwzwarich@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 1 Oct 2008 22:18:50 +0000 (22:18 +0000)
        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:

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

19 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CodeBlock.h
JavaScriptCore/VM/CodeGenerator.cpp
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/Machine.h
JavaScriptCore/VM/RegisterFile.h
JavaScriptCore/kjs/Arguments.cpp
JavaScriptCore/kjs/Arguments.h
JavaScriptCore/kjs/JSActivation.cpp
JavaScriptCore/kjs/JSActivation.h
JavaScriptCore/kjs/grammar.y
JavaScriptCore/kjs/nodes.h
JavaScriptCore/masm/X86Assembler.h
LayoutTests/ChangeLog
LayoutTests/fast/js/arguments-expected.txt
LayoutTests/fast/js/function-dot-arguments-expected.txt
LayoutTests/fast/js/resources/arguments.js
LayoutTests/fast/js/resources/function-dot-arguments.js

index 1de6dbdbe527af00daa5e11aea6653c2380c77cd..6b641dc8ee59ab70920faf99f9a09cc9d1e56145 100644 (file)
@@ -1,3 +1,65 @@
+2008-10-01  Cameron Zwarich  <zwarich@apple.com>
+
+        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.
+
+        * 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):
+
 2008-10-01  Kevin McCullough  <kmccullough@apple.com>
 
         Rubberstamped by Geoff .
index a5ad7a5fec71a0709819f7ddc7f041e7b73b5caa..d1f85dc25a0bccd6f1fee8b0b647f0b0ca66daea 100644 (file)
@@ -1190,8 +1190,11 @@ void CTI::privateCompileMainPass()
             break;
         }
         case op_ret: {
-            // Check for an activation - if there is one, jump to the hook below.
-            m_jit.cmpl_i32m(0, RegisterFile::OptionalCalleeActivation * static_cast<int>(sizeof(Register)), X86::edi);
+            // 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();
 
@@ -1221,9 +1224,9 @@ void CTI::privateCompileMainPass()
             m_jit.pushl_r(X86::edx);
             m_jit.ret();
 
-            // Activation hook
+            // Activation and 'arguments' hook
             m_jit.link(activation, m_jit.label());
-            emitCall(i, Machine::cti_op_ret_activation);
+            emitCall(i, Machine::cti_op_ret_activation_arguments);
             m_jit.link(m_jit.emitUnlinkedJmp(), activated);
 
             // Profiling hook
index 9c90f9e7e02315728c3f132cf3bf0103e92069f3..98514b23cfbc3e100240bda8a50f95e78f95b5dd 100644 (file)
@@ -241,6 +241,7 @@ namespace JSC {
         int thisRegister;
         bool needsFullScopeChain;
         bool usesEval;
+        bool usesArguments;
         CodeType codeType;
         RefPtr<SourceProvider> source;
         unsigned sourceOffset;
index 165757364d5e1dfb5724e638b65625de9d9af69e..d1b4532b9556bede188c9dc3d87ba80b0d88b60a 100644 (file)
@@ -292,11 +292,12 @@ CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* deb
     emitOpcode(op_init);
     codeBlock->globalData = m_globalData;
 
-    if (functionBody->usesArguments()) {
+    bool usesArguments = functionBody->usesArguments();
+    codeBlock->usesArguments = usesArguments;
+    if (usesArguments) {
         emitOpcode(op_init_arguments);
-        m_codeBlock->needsFullScopeChain = true;
         m_argumentsRegister.setIndex(RegisterFile::OptionalCalleeArguments);
-        symbolTable->add(propertyNames().arguments.ustring().rep(), SymbolTableEntry(RegisterFile::OptionalCalleeArguments));
+        addVar(propertyNames().arguments, false);
     }
 
     const Node::FunctionStack& functionStack = functionBody->functionStack();
index 92bb9cf1b307ed225ab4837a4df64f9564a6a40b..db72062355c72752cf99b4e4774694746e3e5ec4 100644 (file)
@@ -801,10 +801,13 @@ NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionVa
     if (oldCodeBlock->needsFullScopeChain)
         scopeChain->deref();
 
-    // If this call frame created an activation, tear it off.
-    if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
+    // 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();
+        activation->copyRegisters(r[RegisterFile::OptionalCalleeArguments].getJSValue());
+    } else if (Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].getJSValue())) {
+        ASSERT(arguments->isObject(&Arguments::info));
+        arguments->copyRegisters();
     }
     
     void* returnPC = r[RegisterFile::ReturnPC].v();
@@ -3360,10 +3363,14 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
            
         int result = (++vPC)->u.operand;
 
-        if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
+        // 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();
+            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)
@@ -3417,8 +3424,16 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         NEXT_OPCODE;
     }
     BEGIN_OPCODE(op_init_arguments) {
-        JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
-        r[RegisterFile::OptionalCalleeArguments] = activation->createArgumentsObject(exec);
+        JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
+        Arguments* arguments;
+        if (activation) {
+            ASSERT(activation->isObject(&JSActivation::info));
+            arguments = new (exec) Arguments(exec, static_cast<JSActivation*>(activation));
+        } else
+            arguments = new (exec) Arguments(exec, r);
+        r[RegisterFile::OptionalCalleeArguments] = arguments;
+        r[RegisterFile::ArgumentsRegister] = arguments;
+        
         ++vPC;
         NEXT_OPCODE;
     }
@@ -3848,16 +3863,24 @@ JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
     if (!r)
         return jsNull();
 
-    Arguments* arguments = static_cast<Arguments*>(r[RegisterFile::OptionalCalleeArguments].jsValue(exec));
-    if (!arguments) {
-        JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
-        if (!activation) {
-            activation = new (exec) JSActivation(exec, function->m_body, r);
-            r[RegisterFile::OptionalCalleeActivation] = activation;
+    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;
         }
-
-        arguments = activation->createArgumentsObject(exec);
-        r[RegisterFile::OptionalCalleeArguments] = arguments;
+        ASSERT(arguments->isObject(&Arguments::info));
     }
 
     return arguments;
@@ -4599,21 +4622,31 @@ void Machine::cti_op_init_arguments(CTI_ARGS)
 {
     ExecState* exec = ARG_exec;
     Register* r = ARG_r;
-    JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].getJSValue());
-    r[RegisterFile::OptionalCalleeArguments] = activation->createArgumentsObject(exec);
+
+    JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
+    Arguments* arguments;
+    if (activation) {
+        ASSERT(activation->isObject(&JSActivation::info));
+        arguments = new (exec) Arguments(exec, static_cast<JSActivation*>(activation));
+    } else
+        arguments = new (exec) Arguments(exec, r);
+    r[RegisterFile::OptionalCalleeArguments] = arguments;
+    r[RegisterFile::ArgumentsRegister] = arguments;
 }
 
-void Machine::cti_op_ret_activation(CTI_ARGS)
+void Machine::cti_op_ret_activation_arguments(CTI_ARGS)
 {
-    ExecState* exec = ARG_exec;
     Register* r = ARG_r;
 
-    JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec));
-    ASSERT(activation);
-
-    ASSERT(!codeBlock(r)->needsFullScopeChain || scopeChain(r)->object == activation);
-    ASSERT(activation->isObject(&JSActivation::info));
-    activation->copyRegisters();
+    // 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();
+    }
 }
 
 void Machine::cti_op_ret_profiler(CTI_ARGS)
index 312a313f17ae8c58e1a5f3d4cabb933437bad52b..778805be4cfd1427b75c10aef6ee94ad1fa0cd9f 100644 (file)
@@ -163,7 +163,7 @@ 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_init_arguments(CTI_ARGS);
-        static void SFX_CALL cti_op_ret_activation(CTI_ARGS);
+        static void SFX_CALL cti_op_ret_activation_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 82a994485d20d5a69c519b9f0086d7ffb4c67b80..2ce4c8b0783ab50b80f76e8dd0bc0cfb23093124 100644 (file)
@@ -104,6 +104,7 @@ namespace JSC {
         };
 
         enum { ProgramCodeThisRegister = -CallFrameHeaderSize - 1 };
+        enum { ArgumentsRegister = 0 };
 
         enum { DefaultCapacity = 2 * 1024 * 1024 / sizeof(Register) };
         enum { DefaultMaxGlobals = 8 * 1024 };
index 98130b48a627aa8f6ad37a0fb884d5b91b3a3f76..0bbb97e684d2077f8791f8a9f6de08441f50d0bc 100644 (file)
@@ -37,53 +37,6 @@ ASSERT_CLASS_FITS_IN_CELL(Arguments);
 
 const ClassInfo Arguments::info = { "Arguments", 0, 0, 0 };
 
-struct ArgumentsData : Noncopyable {
-    ArgumentsData(JSActivation* activation, unsigned numParameters, int firstParameterIndex, unsigned numArguments, JSFunction* callee)
-        : activation(activation)
-        , numParameters(numParameters)
-        , firstParameterIndex(firstParameterIndex)
-        , numArguments(numArguments)
-        , extraArguments(0)
-        , callee(callee)
-        , overrodeLength(false)
-        , overrodeCallee(false)
-    {
-    }
-
-    JSActivation* activation;
-
-    unsigned numParameters;
-    int firstParameterIndex;
-    unsigned numArguments;
-    Register* extraArguments;
-    OwnArrayPtr<bool> deletedArguments;
-    Register extraArgumentsFixedBuffer[4];
-
-    JSFunction* callee;
-    bool overrodeLength : 1;
-    bool overrodeCallee : 1;
-};
-
-// ECMA 10.1.8
-Arguments::Arguments(ExecState* exec, JSFunction* function, JSActivation* activation, int firstParameterIndex, Register* argv, int argc)
-    : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
-    , d(new ArgumentsData(activation, function->numParameters(), firstParameterIndex, argc, function))
-{
-    ASSERT(activation);
-  
-    if (d->numArguments > d->numParameters) {
-        unsigned numExtraArguments = d->numArguments - d->numParameters;
-        Register* extraArguments;
-        if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
-            extraArguments = new Register[numExtraArguments];
-        else
-            extraArguments = d->extraArgumentsFixedBuffer;
-        for (unsigned i = 0; i < numExtraArguments; ++i)
-            extraArguments[i] = argv[d->numParameters + i];
-        d->extraArguments = extraArguments;
-    }
-}
-
 Arguments::~Arguments()
 {
     if (d->extraArguments != d->extraArgumentsFixedBuffer)
@@ -94,6 +47,11 @@ void Arguments::mark()
 {
     JSObject::mark();
 
+    for (unsigned i = 0; i < d->numParameters; ++i) {
+        if (!d->registers[i].marked())
+            d->registers[i].mark();
+    }
+
     if (d->extraArguments) {
         unsigned numExtraArguments = d->numArguments - d->numParameters;
         for (unsigned i = 0; i < numExtraArguments; ++i) {
@@ -105,7 +63,7 @@ void Arguments::mark()
     if (!d->callee->marked())
         d->callee->mark();
 
-    if (!d->activation->marked())
+    if (d->activation && !d->activation->marked())
         d->activation->mark();
 }
 
@@ -118,16 +76,16 @@ void Arguments::fillArgList(ExecState* exec, ArgList& args)
         }
 
         if (d->numParameters == d->numArguments) {
-            args.initialize(&d->activation->registerAt(d->firstParameterIndex), d->numArguments);
+            args.initialize(&d->registers[d->firstParameterIndex], d->numArguments);
             return;
         }
 
         unsigned parametersLength = min(d->numParameters, d->numArguments);
         unsigned i = 0;
         for (; i < parametersLength; ++i)
-            args.append(d->activation->uncheckedSymbolTableGetValue(d->firstParameterIndex + i));
+            args.append(d->registers[d->firstParameterIndex + i].jsValue(exec));
         for (; i < d->numArguments; ++i)
-            args.append(d->extraArguments[i - d->numParameters].getJSValue());
+            args.append(d->extraArguments[i - d->numParameters].jsValue(exec));
         return;
     }
 
@@ -135,13 +93,13 @@ void Arguments::fillArgList(ExecState* exec, ArgList& args)
     unsigned i = 0;
     for (; i < parametersLength; ++i) {
         if (!d->deletedArguments[i])
-            args.append(d->activation->uncheckedSymbolTableGetValue(d->firstParameterIndex + i));
+            args.append(d->registers[d->firstParameterIndex + i].jsValue(exec));
         else
             args.append(get(exec, i));
     }
     for (; i < d->numArguments; ++i) {
         if (!d->deletedArguments[i])
-            args.append(d->extraArguments[i - d->numParameters].getJSValue());
+            args.append(d->extraArguments[i - d->numParameters].jsValue(exec));
         else
             args.append(get(exec, i));
     }
@@ -151,9 +109,9 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& sl
 {
     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
         if (i < d->numParameters)
-            d->activation->uncheckedSymbolTableGet(d->firstParameterIndex + i, slot);
+            slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
         else
-            slot.setValue(d->extraArguments[i - d->numParameters].getJSValue());
+            slot.setValue(d->extraArguments[i - d->numParameters].jsValue(exec));
         return true;
     }
 
@@ -166,9 +124,9 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNa
     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
         if (i < d->numParameters)
-            d->activation->uncheckedSymbolTableGet(d->firstParameterIndex + i, slot);
+            slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
         else
-            slot.setValue(d->extraArguments[i - d->numParameters].getJSValue());
+            slot.setValue(d->extraArguments[i - d->numParameters].jsValue(exec));
         return true;
     }
 
@@ -189,7 +147,7 @@ void Arguments::put(ExecState* exec, unsigned i, JSValue* value, PutPropertySlot
 {
     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
         if (i < d->numParameters)
-            d->activation->uncheckedSymbolTablePut(d->firstParameterIndex + i, value);
+            d->registers[d->firstParameterIndex + i] = value;
         else
             d->extraArguments[i - d->numParameters] = value;
         return;
@@ -204,7 +162,7 @@ void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue* va
     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
         if (i < d->numParameters)
-            d->activation->uncheckedSymbolTablePut(d->firstParameterIndex + i, value);
+            d->registers[d->firstParameterIndex + i] = value;
         else
             d->extraArguments[i - d->numParameters] = value;
         return;
index a117a00de973de0f4faf6f0f9ee7577fe903f661..19c878187ee919622cb95397ab91fec9b108d40c 100644 (file)
 #ifndef Arguments_h
 #define Arguments_h
 
-#include "JSObject.h"
+#include "JSActivation.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "Machine.h"
 
 namespace JSC {
 
-    class JSActivation;
-    class JSFunction;
-    class Register;
+    struct ArgumentsData : Noncopyable {
+        JSActivation* activation;
+
+        unsigned numParameters;
+        int firstParameterIndex;
+        unsigned numArguments;
+
+        Register* registers;
+        OwnArrayPtr<Register> registerArray;
+
+        Register* extraArguments;
+        OwnArrayPtr<bool> deletedArguments;
+        Register extraArgumentsFixedBuffer[4];
+
+        JSFunction* callee;
+        bool overrodeLength : 1;
+        bool overrodeCallee : 1;
+    };
 
-    struct ArgumentsData;
 
     class Arguments : public JSObject {
     public:
-        Arguments(ExecState*, JSFunction*, JSActivation*, int firstArgumentIndex, Register* argv, int argc);
+        Arguments(ExecState*, Register* callFrame);
+        Arguments(ExecState*, JSActivation*);
         virtual ~Arguments();
 
         static const ClassInfo info;
@@ -45,6 +63,9 @@ namespace JSC {
 
         void fillArgList(ExecState*, ArgList&);
 
+        void copyRegisters();
+        void setRegisters(Register* registers) { d->registers = registers; }
+
     private:
         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
@@ -55,9 +76,104 @@ namespace JSC {
 
         virtual const ClassInfo* classInfo() const { return &info; }
 
+        void init(ExecState*, Register* callFrame);
+
         OwnPtr<ArgumentsData> d;
     };
 
+    inline void Arguments::init(ExecState* exec, Register* callFrame)
+    {
+        JSFunction* callee;
+        int firstParameterIndex;
+        Register* argv;
+        int numArguments;
+        exec->machine()->getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments);
+
+        d->numParameters = callee->numParameters();
+        d->firstParameterIndex = firstParameterIndex;
+        d->numArguments = numArguments;
+
+        d->registers = callFrame;
+
+        Register* extraArguments;
+        if (d->numArguments <= d->numParameters)
+            extraArguments = 0;
+        else {
+            unsigned numExtraArguments = d->numArguments - d->numParameters;
+            if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
+                extraArguments = new Register[numExtraArguments];
+            else
+                extraArguments = d->extraArgumentsFixedBuffer;
+            for (unsigned i = 0; i < numExtraArguments; ++i)
+                extraArguments[i] = argv[d->numParameters + i];
+        }
+
+        d->extraArguments = extraArguments;
+
+        d->callee = callee;
+        d->overrodeLength = false;
+        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);
+
+        size_t numParametersMinusThis = d->callee->m_body->generatedByteCode().numParameters - 1;
+
+        if (!numParametersMinusThis)
+            return;
+
+        int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
+        size_t registerArraySize = numParametersMinusThis;
+
+        Register* registerArray = new Register[registerArraySize];
+        memcpy(registerArray, d->registers - registerOffset, registerArraySize * sizeof(Register));
+        d->registerArray.set(registerArray);
+        d->registers = registerArray + registerOffset;
+    }
+
+    // This JSActivation function is defined here so it can get at Arguments::setRegisters.
+    inline void JSActivation::copyRegisters(JSValue* arguments)
+    {
+        ASSERT(!d()->registerArray);
+
+        size_t numParametersMinusThis = d()->functionBody->generatedByteCode().numParameters - 1;
+        size_t numVars = d()->functionBody->generatedByteCode().numVars;
+        size_t numLocals = numVars + numParametersMinusThis;
+
+        if (!numLocals)
+            return;
+
+        int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
+        size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize;
+
+        Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize);
+        setRegisters(registerArray + registerOffset, registerArray);
+        if (arguments) {
+            ASSERT(arguments->isObject(&Arguments::info));
+            static_cast<Arguments*>(arguments)->setRegisters(registerArray + registerOffset);
+        }
+    }
+
 } // namespace JSC
 
 #endif // Arguments_h
index 1b240f6c73cdde4221fb5f0560c2e1887d967ea8..b83a370e6688c730170f71b56e38ebdc0b57c667 100644 (file)
@@ -155,10 +155,18 @@ JSValue* JSActivation::argumentsGetter(ExecState* exec, const Identifier&, const
 {
     JSActivation* thisObj = static_cast<JSActivation*>(slot.slotBase());
 
-    Arguments* arguments = static_cast<Arguments*>(thisObj->d()->registers[RegisterFile::OptionalCalleeArguments].jsValue(exec));
-    if (!arguments) {
-        arguments = thisObj->createArgumentsObject(exec);
-        thisObj->d()->registers[RegisterFile::OptionalCalleeArguments] = arguments;
+    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 arguments;
@@ -172,15 +180,4 @@ PropertySlot::GetValueFunc JSActivation::getArgumentsGetter()
     return argumentsGetter;
 }
 
-Arguments* JSActivation::createArgumentsObject(ExecState* exec)
-{
-    JSFunction* function;
-    Register* argv;
-    int argc;
-    int firstParameterIndex;
-    exec->machine()->getArgumentsData(d()->registers, function, firstParameterIndex, argv, argc);
-
-    return new (exec) Arguments(exec, function, this, firstParameterIndex, argv, argc);
-}
-
 } // namespace JSC
index f0af672b48ad4be15b9b1bc25f22e5bb9e0b4372..7361a969c6f6561e696a6a104ba4f188ac96c75b 100644 (file)
@@ -43,53 +43,36 @@ namespace JSC {
     class JSActivation : public JSVariableObject {
         typedef JSVariableObject Base;
     public:
-        JSActivation(ExecState* exec, PassRefPtr<FunctionBodyNode>, Register*);
+        JSActivation(ExecState*, PassRefPtr<FunctionBodyNode>, Register*);
         virtual ~JSActivation();
-        
+
         virtual void mark();
 
         virtual bool isDynamicScope() const;
 
         virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
 
-        inline void uncheckedSymbolTableGet(int index, PropertySlot& slot)
-        {
-            slot.setRegisterSlot(&registerAt(index));
-        }
-
-        inline JSValue* uncheckedSymbolTableGetValue(int index)
-        {
-            return registerAt(index).getJSValue();
-        }
-
         virtual void put(ExecState*, const Identifier&, JSValue*, PutPropertySlot&);
 
-        inline void uncheckedSymbolTablePut(int index, JSValue* value)
-        {
-            registerAt(index) = value;
-        }
-
         virtual void putWithAttributes(ExecState*, const Identifier&, JSValue*, unsigned attributes);
         virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
 
         virtual JSObject* toThisObject(ExecState*) const;
 
-        void copyRegisters();
+        void copyRegisters(JSValue* arguments);
         
         virtual const ClassInfo* classInfo() const { return &info; }
         static const ClassInfo info;
 
-        NEVER_INLINE Arguments* createArgumentsObject(ExecState*);
-
     private:
         struct JSActivationData : public JSVariableObjectData {
-            JSActivationData(PassRefPtr<FunctionBodyNode> functionBody_, Register* registers)
-                : JSVariableObjectData(&functionBody_->symbolTable(), registers)
-                , functionBody(functionBody_)
+            JSActivationData(PassRefPtr<FunctionBodyNode> functionBody, Register* registers)
+                : JSVariableObjectData(&functionBody->symbolTable(), registers)
+                , functionBody(functionBody)
             {
             }
 
-            RefPtr<FunctionBodyNode> functionBody; // Owns the symbol table and code block
+            RefPtr<FunctionBodyNode> functionBody;
         };
         
         static JSValue* argumentsGetter(ExecState*, const Identifier&, const PropertySlot&);
@@ -98,24 +81,6 @@ namespace JSC {
         JSActivationData* d() const { return static_cast<JSActivationData*>(JSVariableObject::d); }
     };
     
-    inline void JSActivation::copyRegisters()
-    {
-        ASSERT(!d()->registerArray);
-
-        size_t numParametersMinusThis = d()->functionBody->generatedByteCode().numParameters - 1;
-        size_t numVars = d()->functionBody->generatedByteCode().numVars;
-        size_t numLocals = numVars + numParametersMinusThis;
-
-        if (!numLocals)
-            return;
-
-        int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
-        size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize;
-
-        Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize);
-        setRegisters(registerArray + registerOffset, registerArray);
-    }
-
 } // namespace JSC
 
 #endif // JSActivation_h
index e791a4201635e87060edd89dfc92f7213814fb8b..8e30df4eaddf4e2e9d2671cbdc2c804f1a3585f8 100644 (file)
@@ -314,7 +314,7 @@ Property:
   | NUMBER ':' AssignmentExpr           { $$ = createNodeFeatureInfo<PropertyNode*>(new PropertyNode(GLOBAL_DATA, Identifier(GLOBAL_DATA, UString::from($1)), $3.m_node, PropertyNode::Constant), $3.m_featureInfo, $3.m_numConstants); }
   | IDENT IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE    { $$ = createNodeFeatureInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, 0, $6, LEXER->sourceRange($5, $7)), ClosureFeature, 0); DBG($6, @5, @7); if (!$$.m_node) YYABORT; }
   | IDENT IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
-                                        { $$ = createNodeFeatureInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, $4.m_node.head, $7, LEXER->sourceRange($6, $8)), $4.m_featureInfo | ClosureFeature, 0); DBG($7, @6, @8); if (!$$.m_node) YYABORT; }
+                                        { $$ = createNodeFeatureInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, $4.m_node.head, $7, LEXER->sourceRange($6, $8)), $4.m_featureInfo | ClosureFeature, 0); $7->setUsesArguments($7->usesArguments() | ($4.m_featureInfo & ArgumentsFeature)); DBG($7, @6, @8); if (!$$.m_node) YYABORT; }
 ;
 
 PropertyList:
@@ -1159,14 +1159,14 @@ DebuggerStatement:
 FunctionDeclaration:
     FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncDeclNode(GLOBAL_DATA, *$2, $6, LEXER->sourceRange($5, $7)), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | ClosureFeature, 0); DBG($6, @5, @7); }
   | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
-      { $$ = createNodeFeatureInfo(new FuncDeclNode(GLOBAL_DATA, *$2, $7, LEXER->sourceRange($6, $8), $4.m_node.head), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_featureInfo | ClosureFeature, 0); DBG($7, @6, @8); }
+      { $$ = createNodeFeatureInfo(new FuncDeclNode(GLOBAL_DATA, *$2, $7, LEXER->sourceRange($6, $8), $4.m_node.head), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_featureInfo | ClosureFeature, 0); $7->setUsesArguments($7->usesArguments() | ($4.m_featureInfo & ArgumentsFeature)); DBG($7, @6, @8); }
 ;
 
 FunctionExpr:
     FUNCTION '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $5, LEXER->sourceRange($4, $6)), ClosureFeature, 0); DBG($5, @4, @6); }
-  | FUNCTION '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $6, LEXER->sourceRange($5, $7), $3.m_node.head), $3.m_featureInfo | ClosureFeature, 0); DBG($6, @5, @7); }
+    | FUNCTION '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $6, LEXER->sourceRange($5, $7), $3.m_node.head), $3.m_featureInfo | ClosureFeature, 0); $6->setUsesArguments($6->usesArguments() | ($3.m_featureInfo & ArgumentsFeature)); DBG($6, @5, @7); }
   | FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, *$2, $6, LEXER->sourceRange($5, $7)), ClosureFeature, 0); DBG($6, @5, @7); }
-  | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, *$2, $7, LEXER->sourceRange($6, $8), $4.m_node.head), $4.m_featureInfo | ClosureFeature, 0); DBG($7, @6, @8); }
+  | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeFeatureInfo(new FuncExprNode(GLOBAL_DATA, *$2, $7, LEXER->sourceRange($6, $8), $4.m_node.head), $4.m_featureInfo | ClosureFeature, 0); $7->setUsesArguments($7->usesArguments() | ($4.m_featureInfo & ArgumentsFeature)); DBG($7, @6, @8); }
 ;
 
 FormalParameterList:
index 8679b7a5feef12b8119bae3dd75516ee6005f7da..728a7e0006fd772775cfb4548cea4d35f4771c1d 100644 (file)
@@ -2176,6 +2176,7 @@ namespace JSC {
         bool usesEval() const { return m_usesEval; }
         bool needsClosure() const { return m_needsClosure; }
         bool usesArguments() const { return m_usesArguments; }
+        void setUsesArguments(bool usesArguments) { m_usesArguments = usesArguments; }
 
         VarStack& varStack() { return m_varStack; }
         FunctionStack& functionStack() { return m_functionStack; }
index 76f37b31d5f4853408584ba3f81160e21b5176de..441810db517fd9f6af84363e08bcc352c601741e 100644 (file)
@@ -183,6 +183,7 @@ public:
         OP_ADD_EvGv                     = 0x01,
         OP_ADD_GvEv                     = 0x03,
         OP_OR_EvGv                      = 0x09,
+        OP_OR_GvEv                      = 0x0B,
         OP_2BYTE_ESCAPE                 = 0x0F,
         OP_AND_EvGv                     = 0x21,
         OP_SUB_EvGv                     = 0x29,
@@ -443,6 +444,12 @@ public:
         emitModRm_rr(src, dst);
     }
 
+    void orl_mr(int offset, RegisterID base, RegisterID dst)
+    {
+        m_buffer->putByte(OP_OR_GvEv);
+        emitModRm_rm(dst, base, offset);
+    }
+
     void orl_i32r(int imm, RegisterID dst)
     {
         m_buffer->putByte(OP_GROUP1_EvIb);
index f0e6453b7e9d1bb6f0e4a3f28ab5300a1da0892b..5cfddd296cd410395e7969190d0ae53b561797e9 100644 (file)
@@ -1,3 +1,16 @@
+2008-10-01  Cameron Zwarich  <zwarich@apple.com>
+
+        Reviewed by Darin Adler.
+
+        Add some tests for the 'arguments' object. The included failures are
+        intentional. They are for regressions introduced in r37050, and they
+        will hopefully be fixed in the near future.
+
+        * fast/js/arguments-expected.txt:
+        * fast/js/function-dot-arguments-expected.txt:
+        * fast/js/resources/arguments.js:
+        * fast/js/resources/function-dot-arguments.js:
+
 2008-10-01  Kevin McCullough  <kmccullough@apple.com>
 
         Reviewed by Dan Bernstein.
index a2ed142dcea7aeba27d01ce577acb2e1713899d0..2a8127f7b56b28b47b50b19ed01843ef569e9cbe 100644 (file)
@@ -125,6 +125,8 @@ PASS access_after_delete_extra_2(1, 2, 3, 4, 5) is 2
 PASS access_after_delete_extra_3(1, 2, 3, 4, 5) is 3
 PASS access_after_delete_extra_5(1, 2, 3, 4, 5) is 5
 PASS argumentsParam(true) is true
+FAIL argumentsVarUndefined() should be undefined. Was [object Arguments]
+FAIL argumentsConstUndefined() should be undefined. Was [object Arguments]
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 92524e0502138fb997934f623d19bb6a28a593ce..0841970939495e5624bc7a73e7d6ad95eae9ed9e 100644 (file)
@@ -4,14 +4,20 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS assignTest() is true
+FAIL assignVarUndefinedTest() should be undefined. Was [object Arguments]
+FAIL assignVarUndefinedTest2() should be undefined. Was [object Arguments]
 PASS assignVarInitTest() is true
 PASS assignVarInitTest2() is true
+FAIL assignConstUndefinedTest() should be undefined. Was [object Arguments]
+FAIL assignConstUndefinedTest2() should be undefined. Was [object Arguments]
 PASS assignConstInitTest() is true
 PASS assignConstInitTest2() is true
 PASS assignForInitTest() is true
 PASS assignForInitTest2() is true
 PASS assignForInInitTest() is true
-FAIL paramInitTest(true) should be true (of type boolean). Was [object Arguments] (of type object).
+PASS paramInitTest(true) is true
+PASS tearOffTest()[0] is true
+PASS tearOffTest2(true)[0] is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index ca970428dc95bfcb4f46dffa69282a40d23b4f72..469f1a8d6c594793fef5cd035d64da812ed0de85 100644 (file)
@@ -506,7 +506,20 @@ function argumentsParam(arguments)
 {
     return arguments;
 }
-
 shouldBeTrue("argumentsParam(true)");
 
+function argumentsVarUndefined()
+{
+    var arguments;
+    return arguments;
+}
+shouldBeUndefined("argumentsVarUndefined()");
+
+function argumentsConstUndefined()
+{
+    const arguments;
+    return arguments;
+}
+shouldBeUndefined("argumentsConstUndefined()");
+
 var successfullyParsed = true;
index 51e677e4fbfc74352ff2328bdfc0711036ea8a2d..a818b167a03f054e1e0ffa6ba93d4906652756b4 100644 (file)
@@ -12,9 +12,32 @@ function assignTest()
     arguments = true;
     return g();
 }
-
 shouldBeTrue("assignTest()");
 
+function assignVarUndefinedTest()
+{
+    function g()
+    {
+        return assignVarUndefinedTest.arguments;
+    }
+
+    var arguments;
+    return g();
+}
+shouldBeUndefined("assignVarUndefinedTest()");
+
+function assignVarUndefinedTest2()
+{
+    function g()
+    {
+        return assignVarUndefinedTest2.arguments;
+    }
+
+    var a, arguments;
+    return g();
+}
+shouldBeUndefined("assignVarUndefinedTest2()");
+
 function assignVarInitTest()
 {
     function g()
@@ -25,7 +48,6 @@ function assignVarInitTest()
     var arguments = true;
     return g();
 }
-
 shouldBeTrue("assignVarInitTest()");
 
 function assignVarInitTest2()
@@ -38,9 +60,32 @@ function assignVarInitTest2()
     var a, arguments = true;
     return g();
 }
-
 shouldBeTrue("assignVarInitTest2()");
 
+function assignConstUndefinedTest()
+{
+    function g()
+    {
+        return assignConstUndefinedTest.arguments;
+    }
+
+    var arguments;
+    return g();
+}
+shouldBeUndefined("assignConstUndefinedTest()");
+
+function assignConstUndefinedTest2()
+{
+    function g()
+    {
+        return assignConstUndefinedTest2.arguments;
+    }
+
+    var a, arguments;
+    return g();
+}
+shouldBeUndefined("assignConstUndefinedTest2()");
+
 function assignConstInitTest()
 {
     function g()
@@ -51,7 +96,6 @@ function assignConstInitTest()
     const arguments = true;
     return g();
 }
-
 shouldBeTrue("assignConstInitTest()");
 
 function assignConstInitTest2()
@@ -64,7 +108,6 @@ function assignConstInitTest2()
     const a, arguments = true;
     return g();
 }
-
 shouldBeTrue("assignConstInitTest2()");
 
 function assignForInitTest()
@@ -77,7 +120,6 @@ function assignForInitTest()
     for (var arguments = true; false;) { }
     return g();
 }
-
 shouldBeTrue("assignForInitTest()");
 
 function assignForInitTest2()
@@ -90,7 +132,6 @@ function assignForInitTest2()
     for (var a, arguments = true; false;) { }
     return g();
 }
-
 shouldBeTrue("assignForInitTest2()");
 
 function assignForInInitTest()
@@ -103,7 +144,6 @@ function assignForInInitTest()
     for (arguments = true; false;) { }
     return g();
 }
-
 shouldBeTrue("assignForInInitTest()");
 
 function paramInitTest(arguments)
@@ -115,7 +155,34 @@ function paramInitTest(arguments)
 
     return g();
 }
-
 shouldBeTrue("paramInitTest(true)");
 
+function tearOffTest()
+{
+    function g()
+    {
+        var a = 1;
+        return arguments;
+    }
+
+    var b = 2;
+    var arguments = g(true);
+    return arguments;
+}
+shouldBeTrue("tearOffTest()[0]");
+
+function tearOffTest2()
+{
+    function g(a)
+    {
+        var arguments = a;
+        var b = 2;
+        return arguments;
+    }
+
+    var c = 3;
+    return g(arguments);
+}
+shouldBeTrue("tearOffTest2(true)[0]");
+
 var successfullyParsed = true;