]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/Arguments.cpp
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / 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