1/*
2 *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 *  Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@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
33namespace 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