2011-01-27 Oliver Hunt <oliver@apple.com>
[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::info = { "Arguments", 0, 0, 0 };
39
40 Arguments::~Arguments()
41 {
42     if (d->extraArguments != d->extraArgumentsFixedBuffer)
43         delete [] d->extraArguments;
44 }
45
46 void Arguments::markChildren(MarkStack& markStack)
47 {
48     JSObject::markChildren(markStack);
49
50     if (d->registerArray)
51         markStack.deprecatedAppendValues(d->registerArray.get(), d->numParameters);
52
53     if (d->extraArguments) {
54         unsigned numExtraArguments = d->numArguments - d->numParameters;
55         markStack.deprecatedAppendValues(d->extraArguments, numExtraArguments);
56     }
57
58     markStack.append(&d->callee);
59
60     if (d->activation)
61         markStack.append(&d->activation);
62 }
63
64 void Arguments::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize)
65 {
66     if (UNLIKELY(d->overrodeLength)) {
67         unsigned length = min(get(exec, exec->propertyNames().length).toUInt32(exec), maxSize);
68         for (unsigned i = 0; i < length; i++)
69             buffer[i] = get(exec, i);
70         return;
71     }
72
73     if (LIKELY(!d->deletedArguments)) {
74         unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize);
75         unsigned i = 0;
76         for (; i < parametersLength; ++i)
77             buffer[i] = d->registers[d->firstParameterIndex + i].jsValue();
78         for (; i < d->numArguments; ++i)
79             buffer[i] = d->extraArguments[i - d->numParameters].jsValue();
80         return;
81     }
82     
83     unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize);
84     unsigned i = 0;
85     for (; i < parametersLength; ++i) {
86         if (!d->deletedArguments[i])
87             buffer[i] = d->registers[d->firstParameterIndex + i].jsValue();
88         else
89             buffer[i] = get(exec, i);
90     }
91     for (; i < d->numArguments; ++i) {
92         if (!d->deletedArguments[i])
93             buffer[i] = d->extraArguments[i - d->numParameters].jsValue();
94         else
95             buffer[i] = get(exec, i);
96     }
97 }
98
99 void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
100 {
101     if (UNLIKELY(d->overrodeLength)) {
102         unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec); 
103         for (unsigned i = 0; i < length; i++) 
104             args.append(get(exec, i)); 
105         return;
106     }
107
108     if (LIKELY(!d->deletedArguments)) {
109         if (LIKELY(!d->numParameters)) {
110             args.initialize(d->extraArguments, d->numArguments);
111             return;
112         }
113
114         if (d->numParameters == d->numArguments) {
115             args.initialize(&d->registers[d->firstParameterIndex], d->numArguments);
116             return;
117         }
118
119         unsigned parametersLength = min(d->numParameters, d->numArguments);
120         unsigned i = 0;
121         for (; i < parametersLength; ++i)
122             args.append(d->registers[d->firstParameterIndex + i].jsValue());
123         for (; i < d->numArguments; ++i)
124             args.append(d->extraArguments[i - d->numParameters].jsValue());
125         return;
126     }
127
128     unsigned parametersLength = min(d->numParameters, d->numArguments);
129     unsigned i = 0;
130     for (; i < parametersLength; ++i) {
131         if (!d->deletedArguments[i])
132             args.append(d->registers[d->firstParameterIndex + i].jsValue());
133         else
134             args.append(get(exec, i));
135     }
136     for (; i < d->numArguments; ++i) {
137         if (!d->deletedArguments[i])
138             args.append(d->extraArguments[i - d->numParameters].jsValue());
139         else
140             args.append(get(exec, i));
141     }
142 }
143
144 bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
145 {
146     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
147         if (i < d->numParameters) {
148             slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
149         } else
150             slot.setValue(d->extraArguments[i - d->numParameters].jsValue());
151         return true;
152     }
153
154     return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::number(i)), slot);
155 }
156     
157 void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
158 {
159     if (d->overrodeCaller)
160         return;
161
162     d->overrodeCaller = true;
163     PropertyDescriptor descriptor;
164     JSValue thrower = createTypeErrorFunction(exec, "Unable to access caller of strict mode function");
165     descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
166     defineOwnProperty(exec, exec->propertyNames().caller, descriptor, false);
167 }
168
169 void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
170 {
171     if (d->overrodeCallee)
172         return;
173     
174     d->overrodeCallee = true;
175     PropertyDescriptor descriptor;
176     JSValue thrower = createTypeErrorFunction(exec, "Unable to access callee of strict mode function");
177     descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
178     defineOwnProperty(exec, exec->propertyNames().callee, descriptor, false);
179 }
180
181 bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
182 {
183     bool isArrayIndex;
184     unsigned i = propertyName.toArrayIndex(isArrayIndex);
185     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
186         if (i < d->numParameters) {
187             slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
188         } else
189             slot.setValue(d->extraArguments[i - d->numParameters].jsValue());
190         return true;
191     }
192
193     if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
194         slot.setValue(jsNumber(d->numArguments));
195         return true;
196     }
197
198     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
199         if (!d->isStrictMode) {
200             slot.setValue(d->callee.get());
201             return true;
202         }
203         createStrictModeCalleeIfNecessary(exec);
204     }
205
206     if (propertyName == exec->propertyNames().caller && d->isStrictMode)
207         createStrictModeCallerIfNecessary(exec);
208
209     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
210 }
211
212 bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
213 {
214     bool isArrayIndex;
215     unsigned i = propertyName.toArrayIndex(isArrayIndex);
216     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
217         if (i < d->numParameters) {
218             descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].jsValue(), DontEnum);
219         } else
220             descriptor.setDescriptor(d->extraArguments[i - d->numParameters].jsValue(), DontEnum);
221         return true;
222     }
223     
224     if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
225         descriptor.setDescriptor(jsNumber(d->numArguments), DontEnum);
226         return true;
227     }
228     
229     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
230         if (!d->isStrictMode) {
231             descriptor.setDescriptor(d->callee.get(), DontEnum);
232             return true;
233         }
234         createStrictModeCalleeIfNecessary(exec);
235     }
236
237     if (propertyName == exec->propertyNames().caller && d->isStrictMode)
238         createStrictModeCallerIfNecessary(exec);
239     
240     return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
241 }
242
243 void Arguments::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
244 {
245     if (mode == IncludeDontEnumProperties) {
246         for (unsigned i = 0; i < d->numArguments; ++i) {
247             if (!d->deletedArguments || !d->deletedArguments[i])
248                 propertyNames.add(Identifier(exec, UString::number(i)));
249         }
250         propertyNames.add(exec->propertyNames().callee);
251         propertyNames.add(exec->propertyNames().length);
252     }
253     JSObject::getOwnPropertyNames(exec, propertyNames, mode);
254 }
255
256 void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot& slot)
257 {
258     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
259         if (i < d->numParameters)
260             d->registers[d->firstParameterIndex + i] = JSValue(value);
261         else
262             d->extraArguments[i - d->numParameters] = JSValue(value);
263         return;
264     }
265
266     JSObject::put(exec, Identifier(exec, UString::number(i)), value, slot);
267 }
268
269 void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
270 {
271     bool isArrayIndex;
272     unsigned i = propertyName.toArrayIndex(isArrayIndex);
273     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
274         if (i < d->numParameters)
275             d->registers[d->firstParameterIndex + i] = JSValue(value);
276         else
277             d->extraArguments[i - d->numParameters] = JSValue(value);
278         return;
279     }
280
281     if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
282         d->overrodeLength = true;
283         putDirect(exec->globalData(), propertyName, value, DontEnum);
284         return;
285     }
286
287     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
288         if (!d->isStrictMode) {
289             d->overrodeCallee = true;
290             putDirect(exec->globalData(), propertyName, value, DontEnum);
291             return;
292         }
293         createStrictModeCalleeIfNecessary(exec);
294     }
295
296     if (propertyName == exec->propertyNames().caller && d->isStrictMode)
297         createStrictModeCallerIfNecessary(exec);
298
299     JSObject::put(exec, propertyName, value, slot);
300 }
301
302 bool Arguments::deleteProperty(ExecState* exec, unsigned i) 
303 {
304     if (i < d->numArguments) {
305         if (!d->deletedArguments) {
306             d->deletedArguments.set(new bool[d->numArguments]);
307             memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
308         }
309         if (!d->deletedArguments[i]) {
310             d->deletedArguments[i] = true;
311             return true;
312         }
313     }
314
315     return JSObject::deleteProperty(exec, Identifier(exec, UString::number(i)));
316 }
317
318 bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName) 
319 {
320     bool isArrayIndex;
321     unsigned i = propertyName.toArrayIndex(isArrayIndex);
322     if (isArrayIndex && i < d->numArguments) {
323         if (!d->deletedArguments) {
324             d->deletedArguments.set(new bool[d->numArguments]);
325             memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
326         }
327         if (!d->deletedArguments[i]) {
328             d->deletedArguments[i] = true;
329             return true;
330         }
331     }
332
333     if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
334         d->overrodeLength = true;
335         return true;
336     }
337
338     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
339         if (!d->isStrictMode) {
340             d->overrodeCallee = true;
341             return true;
342         }
343         createStrictModeCalleeIfNecessary(exec);
344     }
345     
346     if (propertyName == exec->propertyNames().caller && !d->isStrictMode)
347         createStrictModeCallerIfNecessary(exec);
348
349     return JSObject::deleteProperty(exec, propertyName);
350 }
351
352 } // namespace JSC