Add custom vtable struct to ClassInfo struct
[WebKit-https.git] / Source / JavaScriptCore / runtime / Arguments.cpp
1 /*
2  *  Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
5  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
6  *  Copyright (C) 2007 Maks Orlovich
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Library General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Library General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Library General Public License
19  *  along with this library; see the file COPYING.LIB.  If not, write to
20  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  *  Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "Arguments.h"
27
28 #include "JSActivation.h"
29 #include "JSFunction.h"
30 #include "JSGlobalObject.h"
31
32 using namespace std;
33
34 namespace JSC {
35
36 ASSERT_CLASS_FITS_IN_CELL(Arguments);
37
38 const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) };
39
40 Arguments::~Arguments()
41 {
42     if (d->extraArguments != d->extraArgumentsFixedBuffer)
43         delete [] d->extraArguments;
44 }
45
46 void Arguments::visitChildrenVirtual(SlotVisitor& visitor)
47 {
48     visitChildren(this, visitor);
49 }
50
51 void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
52 {
53     Arguments* thisObject = static_cast<Arguments*>(cell);
54     ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
55     COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
56     ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
57     JSObject::visitChildren(thisObject, visitor);
58
59     if (thisObject->d->registerArray)
60         visitor.appendValues(thisObject->d->registerArray.get(), thisObject->d->numParameters);
61
62     if (thisObject->d->extraArguments) {
63         unsigned numExtraArguments = thisObject->d->numArguments - thisObject->d->numParameters;
64         visitor.appendValues(thisObject->d->extraArguments, numExtraArguments);
65     }
66
67     visitor.append(&thisObject->d->callee);
68
69     if (thisObject->d->activation)
70         visitor.append(&thisObject->d->activation);
71 }
72
73 void Arguments::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize)
74 {
75     if (UNLIKELY(d->overrodeLength)) {
76         unsigned length = min(get(exec, exec->propertyNames().length).toUInt32(exec), maxSize);
77         for (unsigned i = 0; i < length; i++)
78             buffer[i] = get(exec, i);
79         return;
80     }
81
82     if (LIKELY(!d->deletedArguments)) {
83         unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize);
84         unsigned i = 0;
85         for (; i < parametersLength; ++i)
86             buffer[i] = d->registers[d->firstParameterIndex + i].get();
87         for (; i < d->numArguments; ++i)
88             buffer[i] = d->extraArguments[i - d->numParameters].get();
89         return;
90     }
91     
92     unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize);
93     unsigned i = 0;
94     for (; i < parametersLength; ++i) {
95         if (!d->deletedArguments[i])
96             buffer[i] = d->registers[d->firstParameterIndex + i].get();
97         else
98             buffer[i] = get(exec, i);
99     }
100     for (; i < d->numArguments; ++i) {
101         if (!d->deletedArguments[i])
102             buffer[i] = d->extraArguments[i - d->numParameters].get();
103         else
104             buffer[i] = get(exec, i);
105     }
106 }
107
108 void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
109 {
110     if (UNLIKELY(d->overrodeLength)) {
111         unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec); 
112         for (unsigned i = 0; i < length; i++) 
113             args.append(get(exec, i)); 
114         return;
115     }
116
117     if (LIKELY(!d->deletedArguments)) {
118         if (LIKELY(!d->numParameters)) {
119             args.initialize(d->extraArguments, d->numArguments);
120             return;
121         }
122
123         if (d->numParameters == d->numArguments) {
124             args.initialize(&d->registers[d->firstParameterIndex], d->numArguments);
125             return;
126         }
127
128         unsigned parametersLength = min(d->numParameters, d->numArguments);
129         unsigned i = 0;
130         for (; i < parametersLength; ++i)
131             args.append(d->registers[d->firstParameterIndex + i].get());
132         for (; i < d->numArguments; ++i)
133             args.append(d->extraArguments[i - d->numParameters].get());
134         return;
135     }
136
137     unsigned parametersLength = min(d->numParameters, d->numArguments);
138     unsigned i = 0;
139     for (; i < parametersLength; ++i) {
140         if (!d->deletedArguments[i])
141             args.append(d->registers[d->firstParameterIndex + i].get());
142         else
143             args.append(get(exec, i));
144     }
145     for (; i < d->numArguments; ++i) {
146         if (!d->deletedArguments[i])
147             args.append(d->extraArguments[i - d->numParameters].get());
148         else
149             args.append(get(exec, i));
150     }
151 }
152
153 bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
154 {
155     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
156         if (i < d->numParameters) {
157             slot.setValue(d->registers[d->firstParameterIndex + i].get());
158         } else
159             slot.setValue(d->extraArguments[i - d->numParameters].get());
160         return true;
161     }
162
163     return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::number(i)), slot);
164 }
165     
166 void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
167 {
168     if (d->overrodeCaller)
169         return;
170
171     d->overrodeCaller = true;
172     PropertyDescriptor descriptor;
173     JSValue thrower = createTypeErrorFunction(exec, "Unable to access caller of strict mode function");
174     descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
175     defineOwnProperty(exec, exec->propertyNames().caller, descriptor, false);
176 }
177
178 void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
179 {
180     if (d->overrodeCallee)
181         return;
182     
183     d->overrodeCallee = true;
184     PropertyDescriptor descriptor;
185     JSValue thrower = createTypeErrorFunction(exec, "Unable to access callee of strict mode function");
186     descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
187     defineOwnProperty(exec, exec->propertyNames().callee, descriptor, false);
188 }
189
190 bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
191 {
192     bool isArrayIndex;
193     unsigned i = propertyName.toArrayIndex(isArrayIndex);
194     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
195         if (i < d->numParameters) {
196             slot.setValue(d->registers[d->firstParameterIndex + i].get());
197         } else
198             slot.setValue(d->extraArguments[i - d->numParameters].get());
199         return true;
200     }
201
202     if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
203         slot.setValue(jsNumber(d->numArguments));
204         return true;
205     }
206
207     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
208         if (!d->isStrictMode) {
209             slot.setValue(d->callee.get());
210             return true;
211         }
212         createStrictModeCalleeIfNecessary(exec);
213     }
214
215     if (propertyName == exec->propertyNames().caller && d->isStrictMode)
216         createStrictModeCallerIfNecessary(exec);
217
218     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
219 }
220
221 bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
222 {
223     bool isArrayIndex;
224     unsigned i = propertyName.toArrayIndex(isArrayIndex);
225     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
226         if (i < d->numParameters) {
227             descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].get(), DontEnum);
228         } else
229             descriptor.setDescriptor(d->extraArguments[i - d->numParameters].get(), DontEnum);
230         return true;
231     }
232     
233     if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
234         descriptor.setDescriptor(jsNumber(d->numArguments), DontEnum);
235         return true;
236     }
237     
238     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
239         if (!d->isStrictMode) {
240             descriptor.setDescriptor(d->callee.get(), DontEnum);
241             return true;
242         }
243         createStrictModeCalleeIfNecessary(exec);
244     }
245
246     if (propertyName == exec->propertyNames().caller && d->isStrictMode)
247         createStrictModeCallerIfNecessary(exec);
248     
249     return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
250 }
251
252 void Arguments::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
253 {
254     if (mode == IncludeDontEnumProperties) {
255         for (unsigned i = 0; i < d->numArguments; ++i) {
256             if (!d->deletedArguments || !d->deletedArguments[i])
257                 propertyNames.add(Identifier(exec, UString::number(i)));
258         }
259         propertyNames.add(exec->propertyNames().callee);
260         propertyNames.add(exec->propertyNames().length);
261     }
262     JSObject::getOwnPropertyNames(exec, propertyNames, mode);
263 }
264
265 void Arguments::put(ExecState* exec, unsigned i, JSValue value)
266 {
267     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
268         if (i < d->numParameters)
269             d->registers[d->firstParameterIndex + i].set(exec->globalData(), d->activation ? static_cast<JSCell*>(d->activation.get()) : static_cast<JSCell*>(this), value);
270         else
271             d->extraArguments[i - d->numParameters].set(exec->globalData(), this, value);
272         return;
273     }
274
275     PutPropertySlot slot;
276     JSObject::put(exec, Identifier(exec, UString::number(i)), value, slot);
277 }
278
279 void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
280 {
281     bool isArrayIndex;
282     unsigned i = propertyName.toArrayIndex(isArrayIndex);
283     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
284         if (i < d->numParameters)
285             d->registers[d->firstParameterIndex + i].set(exec->globalData(), d->activation ? static_cast<JSCell*>(d->activation.get()) : static_cast<JSCell*>(this), value);
286         else
287             d->extraArguments[i - d->numParameters].set(exec->globalData(), this, value);
288         return;
289     }
290
291     if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
292         d->overrodeLength = true;
293         putDirect(exec->globalData(), propertyName, value, DontEnum);
294         return;
295     }
296
297     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
298         if (!d->isStrictMode) {
299             d->overrodeCallee = true;
300             putDirect(exec->globalData(), propertyName, value, DontEnum);
301             return;
302         }
303         createStrictModeCalleeIfNecessary(exec);
304     }
305
306     if (propertyName == exec->propertyNames().caller && d->isStrictMode)
307         createStrictModeCallerIfNecessary(exec);
308
309     JSObject::put(exec, propertyName, value, slot);
310 }
311
312 bool Arguments::deleteProperty(ExecState* exec, unsigned i) 
313 {
314     if (i < d->numArguments) {
315         if (!d->deletedArguments) {
316             d->deletedArguments = adoptArrayPtr(new bool[d->numArguments]);
317             memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
318         }
319         if (!d->deletedArguments[i]) {
320             d->deletedArguments[i] = true;
321             return true;
322         }
323     }
324
325     return JSObject::deleteProperty(exec, Identifier(exec, UString::number(i)));
326 }
327
328 bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName) 
329 {
330     bool isArrayIndex;
331     unsigned i = propertyName.toArrayIndex(isArrayIndex);
332     if (isArrayIndex && i < d->numArguments) {
333         if (!d->deletedArguments) {
334             d->deletedArguments = adoptArrayPtr(new bool[d->numArguments]);
335             memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
336         }
337         if (!d->deletedArguments[i]) {
338             d->deletedArguments[i] = true;
339             return true;
340         }
341     }
342
343     if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
344         d->overrodeLength = true;
345         return true;
346     }
347
348     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
349         if (!d->isStrictMode) {
350             d->overrodeCallee = true;
351             return true;
352         }
353         createStrictModeCalleeIfNecessary(exec);
354     }
355     
356     if (propertyName == exec->propertyNames().caller && !d->isStrictMode)
357         createStrictModeCallerIfNecessary(exec);
358
359     return JSObject::deleteProperty(exec, propertyName);
360 }
361
362 } // namespace JSC