2011-01-27 Oliver Hunt <oliver@apple.com>
[WebKit-https.git] / Source / JavaScriptCore / runtime / Arguments.h
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 #include "PrototypeFunction.h"
33
34 namespace JSC {
35
36     struct ArgumentsData {
37         WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED;
38     public:
39         ArgumentsData() { }
40         WriteBarrier<JSActivation> activation;
41
42         unsigned numParameters;
43         ptrdiff_t firstParameterIndex;
44         unsigned numArguments;
45
46         Register* registers;
47         OwnArrayPtr<Register> registerArray;
48
49         Register* extraArguments;
50         OwnArrayPtr<bool> deletedArguments;
51         Register extraArgumentsFixedBuffer[4];
52
53         WriteBarrier<JSFunction> callee;
54         bool overrodeLength : 1;
55         bool overrodeCallee : 1;
56         bool overrodeCaller : 1;
57         bool isStrictMode : 1;
58     };
59
60
61     class Arguments : public JSObject {
62     public:
63         // Use an enum because otherwise gcc insists on doing a memory
64         // read.
65         enum { MaxArguments = 0x10000 };
66
67         enum NoParametersType { NoParameters };
68
69         Arguments(CallFrame*);
70         Arguments(CallFrame*, NoParametersType);
71         virtual ~Arguments();
72
73         static const ClassInfo info;
74
75         virtual void markChildren(MarkStack&);
76
77         void fillArgList(ExecState*, MarkedArgumentBuffer&);
78
79         uint32_t numProvidedArguments(ExecState* exec) const 
80         {
81             if (UNLIKELY(d->overrodeLength))
82                 return get(exec, exec->propertyNames().length).toUInt32(exec);
83             return d->numArguments; 
84         }
85         
86         void copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize);
87         void copyRegisters();
88         bool isTornOff() const { return d->registerArray; }
89         void setActivation(JSGlobalData& globalData, JSActivation* activation)
90         {
91             d->activation.set(globalData, this, activation);
92             d->registers = &activation->registerAt(0);
93         }
94
95         static PassRefPtr<Structure> createStructure(JSValue prototype) 
96         { 
97             return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); 
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, PutPropertySlot&);
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         virtual const ClassInfo* classInfo() const { return &info; }
117
118         void init(CallFrame*);
119
120         OwnPtr<ArgumentsData> d;
121     };
122
123     Arguments* asArguments(JSValue);
124
125     inline Arguments* asArguments(JSValue value)
126     {
127         ASSERT(asObject(value)->inherits(&Arguments::info));
128         return static_cast<Arguments*>(asObject(value));
129     }
130
131     ALWAYS_INLINE void Arguments::getArgumentsData(CallFrame* callFrame, JSFunction*& function, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc)
132     {
133         function = asFunction(callFrame->callee());
134
135         int numParameters = function->jsExecutable()->parameterCount();
136         argc = callFrame->argumentCountIncludingThis();
137
138         if (argc <= numParameters)
139             argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters;
140         else
141             argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters - argc;
142
143         argc -= 1; // - 1 to skip "this"
144         firstParameterIndex = -RegisterFile::CallFrameHeaderSize - numParameters;
145     }
146
147     inline Arguments::Arguments(CallFrame* callFrame)
148         : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure())
149         , d(adoptPtr(new ArgumentsData))
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 = callFrame->registers();
162
163         Register* 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(Register))
169                 extraArguments = new Register[numExtraArguments];
170             else
171                 extraArguments = d->extraArgumentsFixedBuffer;
172             for (unsigned i = 0; i < numExtraArguments; ++i)
173                 extraArguments[i] = argv[d->numParameters + i];
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();
185     }
186
187     inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
188         : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure())
189         , d(adoptPtr(new ArgumentsData))
190     {
191         ASSERT(!asFunction(callFrame->callee())->jsExecutable()->parameterCount());
192
193         unsigned numArguments = callFrame->argumentCount();
194
195         d->numParameters = 0;
196         d->numArguments = numArguments;
197
198         Register* extraArguments;
199         if (numArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
200             extraArguments = new Register[numArguments];
201         else
202             extraArguments = d->extraArgumentsFixedBuffer;
203
204         Register* argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numArguments - 1;
205         for (unsigned i = 0; i < numArguments; ++i)
206             extraArguments[i] = argv[i];
207
208         d->extraArguments = extraArguments;
209
210         d->callee.set(callFrame->globalData(), this, asFunction(callFrame->callee()));
211         d->overrodeLength = false;
212         d->overrodeCallee = false;
213         d->overrodeCaller = false;
214         d->isStrictMode = callFrame->codeBlock()->isStrictMode();
215         if (d->isStrictMode)
216             copyRegisters();
217     }
218
219     inline void Arguments::copyRegisters()
220     {
221         ASSERT(!isTornOff());
222
223         if (!d->numParameters)
224             return;
225
226         int registerOffset = d->numParameters + RegisterFile::CallFrameHeaderSize;
227         size_t registerArraySize = d->numParameters;
228
229         Register* registerArray = new Register[registerArraySize];
230         memcpy(registerArray, d->registers - registerOffset, registerArraySize * sizeof(Register));
231         d->registerArray.set(registerArray);
232         d->registers = registerArray + registerOffset;
233     }
234
235     // This JSActivation function is defined here so it can get at Arguments::setRegisters.
236     inline void JSActivation::copyRegisters()
237     {
238         ASSERT(!d()->registerArray);
239
240         size_t numParametersMinusThis = d()->functionExecutable->parameterCount();
241         size_t numVars = d()->functionExecutable->capturedVariableCount();
242         size_t numLocals = numVars + numParametersMinusThis;
243
244         if (!numLocals)
245             return;
246
247         int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
248         size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize;
249
250         Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize);
251         setRegisters(registerArray + registerOffset, registerArray);
252     }
253
254 } // namespace JSC
255
256 #endif // Arguments_h