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