Home | History | Annotate | Download | only in runtime
      1 /*
      2  *  Copyright (C) 1999-2000 Harri Porten (porten (at) kde.org)
      3  *  Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      4  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich (at) uwaterloo.ca)
      5  *  Copyright (C) 2007 Maks Orlovich
      6  *
      7  *  This library is free software; you can redistribute it and/or
      8  *  modify it under the terms of the GNU Library General Public
      9  *  License as published by the Free Software Foundation; either
     10  *  version 2 of the License, or (at your option) any later version.
     11  *
     12  *  This library is distributed in the hope that it will be useful,
     13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  *  Library General Public License for more details.
     16  *
     17  *  You should have received a copy of the GNU Library General Public License
     18  *  along with this library; see the file COPYING.LIB.  If not, write to
     19  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20  *  Boston, MA 02110-1301, USA.
     21  *
     22  */
     23 
     24 #ifndef Arguments_h
     25 #define Arguments_h
     26 
     27 #include "JSActivation.h"
     28 #include "JSFunction.h"
     29 #include "JSGlobalObject.h"
     30 #include "Interpreter.h"
     31 #include "ObjectConstructor.h"
     32 
     33 namespace JSC {
     34 
     35     struct ArgumentsData {
     36         WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED;
     37     public:
     38         ArgumentsData() { }
     39         WriteBarrier<JSActivation> activation;
     40 
     41         unsigned numParameters;
     42         ptrdiff_t firstParameterIndex;
     43         unsigned numArguments;
     44 
     45         WriteBarrier<Unknown>* registers;
     46         OwnArrayPtr<WriteBarrier<Unknown> > registerArray;
     47 
     48         WriteBarrier<Unknown>* extraArguments;
     49         OwnArrayPtr<bool> deletedArguments;
     50         WriteBarrier<Unknown> extraArgumentsFixedBuffer[4];
     51 
     52         WriteBarrier<JSFunction> callee;
     53         bool overrodeLength : 1;
     54         bool overrodeCallee : 1;
     55         bool overrodeCaller : 1;
     56         bool isStrictMode : 1;
     57     };
     58 
     59 
     60     class Arguments : public JSNonFinalObject {
     61     public:
     62         // Use an enum because otherwise gcc insists on doing a memory
     63         // read.
     64         enum { MaxArguments = 0x10000 };
     65 
     66         enum NoParametersType { NoParameters };
     67 
     68         Arguments(CallFrame*);
     69         Arguments(CallFrame*, NoParametersType);
     70         virtual ~Arguments();
     71 
     72         static const ClassInfo s_info;
     73 
     74         virtual void markChildren(MarkStack&);
     75 
     76         void fillArgList(ExecState*, MarkedArgumentBuffer&);
     77 
     78         uint32_t numProvidedArguments(ExecState* exec) const
     79         {
     80             if (UNLIKELY(d->overrodeLength))
     81                 return get(exec, exec->propertyNames().length).toUInt32(exec);
     82             return d->numArguments;
     83         }
     84 
     85         void copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize);
     86         void copyRegisters(JSGlobalData&);
     87         bool isTornOff() const { return d->registerArray; }
     88         void setActivation(JSGlobalData& globalData, JSActivation* activation)
     89         {
     90             ASSERT(!d->registerArray);
     91             d->activation.set(globalData, this, activation);
     92             d->registers = &activation->registerAt(0);
     93         }
     94 
     95         static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
     96         {
     97             return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
     98         }
     99 
    100     protected:
    101         static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
    102 
    103     private:
    104         void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
    105         virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
    106         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
    107         virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
    108         virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
    109         virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
    110         virtual void put(ExecState*, unsigned propertyName, JSValue);
    111         virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
    112         virtual bool deleteProperty(ExecState*, unsigned propertyName);
    113         void createStrictModeCallerIfNecessary(ExecState*);
    114         void createStrictModeCalleeIfNecessary(ExecState*);
    115 
    116         void init(CallFrame*);
    117 
    118         OwnPtr<ArgumentsData> d;
    119     };
    120 
    121     Arguments* asArguments(JSValue);
    122 
    123     inline Arguments* asArguments(JSValue value)
    124     {
    125         ASSERT(asObject(value)->inherits(&Arguments::s_info));
    126         return static_cast<Arguments*>(asObject(value));
    127     }
    128 
    129     ALWAYS_INLINE void Arguments::getArgumentsData(CallFrame* callFrame, JSFunction*& function, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc)
    130     {
    131         function = asFunction(callFrame->callee());
    132 
    133         int numParameters = function->jsExecutable()->parameterCount();
    134         argc = callFrame->argumentCountIncludingThis();
    135 
    136         if (argc <= numParameters)
    137             argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters;
    138         else
    139             argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters - argc;
    140 
    141         argc -= 1; // - 1 to skip "this"
    142         firstParameterIndex = -RegisterFile::CallFrameHeaderSize - numParameters;
    143     }
    144 
    145     inline Arguments::Arguments(CallFrame* callFrame)
    146         : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
    147         , d(adoptPtr(new ArgumentsData))
    148     {
    149         ASSERT(inherits(&s_info));
    150 
    151         JSFunction* callee;
    152         ptrdiff_t firstParameterIndex;
    153         Register* argv;
    154         int numArguments;
    155         getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments);
    156 
    157         d->numParameters = callee->jsExecutable()->parameterCount();
    158         d->firstParameterIndex = firstParameterIndex;
    159         d->numArguments = numArguments;
    160 
    161         d->registers = reinterpret_cast<WriteBarrier<Unknown>*>(callFrame->registers());
    162 
    163         WriteBarrier<Unknown>* extraArguments;
    164         if (d->numArguments <= d->numParameters)
    165             extraArguments = 0;
    166         else {
    167             unsigned numExtraArguments = d->numArguments - d->numParameters;
    168             if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(WriteBarrier<Unknown>))
    169                 extraArguments = new WriteBarrier<Unknown>[numExtraArguments];
    170             else
    171                 extraArguments = d->extraArgumentsFixedBuffer;
    172             for (unsigned i = 0; i < numExtraArguments; ++i)
    173                 extraArguments[i].set(callFrame->globalData(), this, argv[d->numParameters + i].jsValue());
    174         }
    175 
    176         d->extraArguments = extraArguments;
    177 
    178         d->callee.set(callFrame->globalData(), this, callee);
    179         d->overrodeLength = false;
    180         d->overrodeCallee = false;
    181         d->overrodeCaller = false;
    182         d->isStrictMode = callFrame->codeBlock()->isStrictMode();
    183         if (d->isStrictMode)
    184             copyRegisters(callFrame->globalData());
    185     }
    186 
    187     inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
    188         : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
    189         , d(adoptPtr(new ArgumentsData))
    190     {
    191         ASSERT(inherits(&s_info));
    192         ASSERT(!asFunction(callFrame->callee())->jsExecutable()->parameterCount());
    193 
    194         unsigned numArguments = callFrame->argumentCount();
    195 
    196         d->numParameters = 0;
    197         d->numArguments = numArguments;
    198 
    199         WriteBarrier<Unknown>* extraArguments;
    200         if (numArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
    201             extraArguments = new WriteBarrier<Unknown>[numArguments];
    202         else
    203             extraArguments = d->extraArgumentsFixedBuffer;
    204 
    205         Register* argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numArguments - 1;
    206         for (unsigned i = 0; i < numArguments; ++i)
    207             extraArguments[i].set(callFrame->globalData(), this, argv[i].jsValue());
    208 
    209         d->extraArguments = extraArguments;
    210 
    211         d->callee.set(callFrame->globalData(), this, asFunction(callFrame->callee()));
    212         d->overrodeLength = false;
    213         d->overrodeCallee = false;
    214         d->overrodeCaller = false;
    215         d->isStrictMode = callFrame->codeBlock()->isStrictMode();
    216         if (d->isStrictMode)
    217             copyRegisters(callFrame->globalData());
    218     }
    219 
    220     inline void Arguments::copyRegisters(JSGlobalData& globalData)
    221     {
    222         ASSERT(!isTornOff());
    223 
    224         if (!d->numParameters)
    225             return;
    226 
    227         int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize;
    228         size_t registerArraySize = d->numParameters;
    229 
    230         OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[registerArraySize]);
    231         for (size_t i = 0; i < registerArraySize; i++)
    232             registerArray[i].set(globalData, this, d->registers[i - registerOffset].get());
    233         d->registers = registerArray.get() + registerOffset;
    234         d->registerArray = registerArray.release();
    235     }
    236 
    237     // This JSActivation function is defined here so it can get at Arguments::setRegisters.
    238     inline void JSActivation::copyRegisters(JSGlobalData& globalData)
    239     {
    240         ASSERT(!m_registerArray);
    241 
    242         size_t numLocals = m_numCapturedVars + m_numParametersMinusThis;
    243 
    244         if (!numLocals)
    245             return;
    246 
    247         int registerOffset = m_numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
    248         size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize;
    249 
    250         OwnArrayPtr<WriteBarrier<Unknown> > registerArray = copyRegisterArray(globalData, m_registers - registerOffset, registerArraySize, m_numParametersMinusThis + 1);
    251         WriteBarrier<Unknown>* registers = registerArray.get() + registerOffset;
    252         setRegisters(registers, registerArray.release());
    253     }
    254 
    255 } // namespace JSC
    256 
    257 #endif // Arguments_h
    258