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
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.
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.
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.
26 #include "Arguments.h"
28 #include "JSActivation.h"
29 #include "JSFunction.h"
30 #include "JSGlobalObject.h"
36 ASSERT_CLASS_FITS_IN_CELL(Arguments);
38 const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) };
40 Arguments::~Arguments()
42 if (d->extraArguments != d->extraArgumentsFixedBuffer)
43 delete [] d->extraArguments;
46 void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
48 Arguments* thisObject = jsCast<Arguments*>(cell);
49 ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
50 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
51 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
52 JSObject::visitChildren(thisObject, visitor);
54 if (thisObject->d->registerArray)
55 visitor.appendValues(thisObject->d->registerArray.get(), thisObject->d->numParameters);
57 if (thisObject->d->extraArguments) {
58 unsigned numExtraArguments = thisObject->d->numArguments - thisObject->d->numParameters;
59 visitor.appendValues(thisObject->d->extraArguments, numExtraArguments);
62 visitor.append(&thisObject->d->callee);
64 if (thisObject->d->activation)
65 visitor.append(&thisObject->d->activation);
68 void Arguments::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize)
70 if (UNLIKELY(d->overrodeLength)) {
71 unsigned length = min(get(exec, exec->propertyNames().length).toUInt32(exec), maxSize);
72 for (unsigned i = 0; i < length; i++)
73 buffer[i] = get(exec, i);
77 if (LIKELY(!d->deletedArguments)) {
78 unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize);
80 for (; i < parametersLength; ++i)
81 buffer[i] = d->registers[d->firstParameterIndex + i].get();
82 for (; i < d->numArguments; ++i)
83 buffer[i] = d->extraArguments[i - d->numParameters].get();
87 unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize);
89 for (; i < parametersLength; ++i) {
90 if (!d->deletedArguments[i])
91 buffer[i] = d->registers[d->firstParameterIndex + i].get();
93 buffer[i] = get(exec, i);
95 for (; i < d->numArguments; ++i) {
96 if (!d->deletedArguments[i])
97 buffer[i] = d->extraArguments[i - d->numParameters].get();
99 buffer[i] = get(exec, i);
103 void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
105 if (UNLIKELY(d->overrodeLength)) {
106 unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec);
107 for (unsigned i = 0; i < length; i++)
108 args.append(get(exec, i));
112 if (LIKELY(!d->deletedArguments)) {
113 if (LIKELY(!d->numParameters)) {
114 args.initialize(d->extraArguments, d->numArguments);
118 if (d->numParameters == d->numArguments) {
119 args.initialize(&d->registers[d->firstParameterIndex], d->numArguments);
123 unsigned parametersLength = min(d->numParameters, d->numArguments);
125 for (; i < parametersLength; ++i)
126 args.append(d->registers[d->firstParameterIndex + i].get());
127 for (; i < d->numArguments; ++i)
128 args.append(d->extraArguments[i - d->numParameters].get());
132 unsigned parametersLength = min(d->numParameters, d->numArguments);
134 for (; i < parametersLength; ++i) {
135 if (!d->deletedArguments[i])
136 args.append(d->registers[d->firstParameterIndex + i].get());
138 args.append(get(exec, i));
140 for (; i < d->numArguments; ++i) {
141 if (!d->deletedArguments[i])
142 args.append(d->extraArguments[i - d->numParameters].get());
144 args.append(get(exec, i));
148 bool Arguments::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned i, PropertySlot& slot)
150 Arguments* thisObject = jsCast<Arguments*>(cell);
151 if (i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
152 if (i < thisObject->d->numParameters) {
153 slot.setValue(thisObject->d->registers[thisObject->d->firstParameterIndex + i].get());
155 slot.setValue(thisObject->d->extraArguments[i - thisObject->d->numParameters].get());
159 return JSObject::getOwnPropertySlot(thisObject, exec, Identifier(exec, UString::number(i)), slot);
162 void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
164 if (d->overrodeCaller)
167 d->overrodeCaller = true;
168 PropertyDescriptor descriptor;
169 JSValue thrower = createTypeErrorFunction(exec, "Unable to access caller of strict mode function");
170 descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
171 methodTable()->defineOwnProperty(this, exec, exec->propertyNames().caller, descriptor, false);
174 void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
176 if (d->overrodeCallee)
179 d->overrodeCallee = true;
180 PropertyDescriptor descriptor;
181 JSValue thrower = createTypeErrorFunction(exec, "Unable to access callee of strict mode function");
182 descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
183 methodTable()->defineOwnProperty(this, exec, exec->propertyNames().callee, descriptor, false);
186 bool Arguments::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
188 Arguments* thisObject = jsCast<Arguments*>(cell);
190 unsigned i = propertyName.toArrayIndex(isArrayIndex);
191 if (isArrayIndex && i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
192 if (i < thisObject->d->numParameters) {
193 slot.setValue(thisObject->d->registers[thisObject->d->firstParameterIndex + i].get());
195 slot.setValue(thisObject->d->extraArguments[i - thisObject->d->numParameters].get());
199 if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->d->overrodeLength)) {
200 slot.setValue(jsNumber(thisObject->d->numArguments));
204 if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->d->overrodeCallee)) {
205 if (!thisObject->d->isStrictMode) {
206 slot.setValue(thisObject->d->callee.get());
209 thisObject->createStrictModeCalleeIfNecessary(exec);
212 if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
213 thisObject->createStrictModeCallerIfNecessary(exec);
215 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
218 bool Arguments::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
220 Arguments* thisObject = jsCast<Arguments*>(object);
222 unsigned i = propertyName.toArrayIndex(isArrayIndex);
223 if (isArrayIndex && i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
224 if (i < thisObject->d->numParameters) {
225 descriptor.setDescriptor(thisObject->d->registers[thisObject->d->firstParameterIndex + i].get(), None);
227 descriptor.setDescriptor(thisObject->d->extraArguments[i - thisObject->d->numParameters].get(), None);
231 if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->d->overrodeLength)) {
232 descriptor.setDescriptor(jsNumber(thisObject->d->numArguments), DontEnum);
236 if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->d->overrodeCallee)) {
237 if (!thisObject->d->isStrictMode) {
238 descriptor.setDescriptor(thisObject->d->callee.get(), DontEnum);
241 thisObject->createStrictModeCalleeIfNecessary(exec);
244 if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
245 thisObject->createStrictModeCallerIfNecessary(exec);
247 return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
250 void Arguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
252 Arguments* thisObject = jsCast<Arguments*>(object);
253 for (unsigned i = 0; i < thisObject->d->numArguments; ++i) {
254 if (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])
255 propertyNames.add(Identifier(exec, UString::number(i)));
257 if (mode == IncludeDontEnumProperties) {
258 propertyNames.add(exec->propertyNames().callee);
259 propertyNames.add(exec->propertyNames().length);
261 JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
264 void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value)
266 Arguments* thisObject = jsCast<Arguments*>(cell);
267 if (i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
268 if (i < thisObject->d->numParameters)
269 thisObject->d->registers[thisObject->d->firstParameterIndex + i].set(exec->globalData(), thisObject->d->activation ? static_cast<JSCell*>(thisObject->d->activation.get()) : cell, value);
271 thisObject->d->extraArguments[i - thisObject->d->numParameters].set(exec->globalData(), thisObject, value);
275 PutPropertySlot slot;
276 JSObject::put(thisObject, exec, Identifier(exec, UString::number(i)), value, slot);
279 void Arguments::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
281 Arguments* thisObject = jsCast<Arguments*>(cell);
283 unsigned i = propertyName.toArrayIndex(isArrayIndex);
284 if (isArrayIndex && i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
285 if (i < thisObject->d->numParameters)
286 thisObject->d->registers[thisObject->d->firstParameterIndex + i].set(exec->globalData(), thisObject->d->activation ? static_cast<JSCell*>(thisObject->d->activation.get()) : static_cast<JSCell*>(thisObject), value);
288 thisObject->d->extraArguments[i - thisObject->d->numParameters].set(exec->globalData(), thisObject, value);
292 if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
293 thisObject->d->overrodeLength = true;
294 thisObject->putDirect(exec->globalData(), propertyName, value, DontEnum);
298 if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
299 if (!thisObject->d->isStrictMode) {
300 thisObject->d->overrodeCallee = true;
301 thisObject->putDirect(exec->globalData(), propertyName, value, DontEnum);
304 thisObject->createStrictModeCalleeIfNecessary(exec);
307 if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
308 thisObject->createStrictModeCallerIfNecessary(exec);
310 JSObject::put(thisObject, exec, propertyName, value, slot);
313 bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
315 Arguments* thisObject = jsCast<Arguments*>(cell);
316 if (i < thisObject->d->numArguments) {
317 if (!thisObject->d->deletedArguments) {
318 thisObject->d->deletedArguments = adoptArrayPtr(new bool[thisObject->d->numArguments]);
319 memset(thisObject->d->deletedArguments.get(), 0, sizeof(bool) * thisObject->d->numArguments);
321 if (!thisObject->d->deletedArguments[i]) {
322 thisObject->d->deletedArguments[i] = true;
327 return JSObject::deleteProperty(thisObject, exec, Identifier(exec, UString::number(i)));
330 bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
332 Arguments* thisObject = jsCast<Arguments*>(cell);
334 unsigned i = propertyName.toArrayIndex(isArrayIndex);
335 if (isArrayIndex && i < thisObject->d->numArguments) {
336 if (!thisObject->d->deletedArguments) {
337 thisObject->d->deletedArguments = adoptArrayPtr(new bool[thisObject->d->numArguments]);
338 memset(thisObject->d->deletedArguments.get(), 0, sizeof(bool) * thisObject->d->numArguments);
340 if (!thisObject->d->deletedArguments[i]) {
341 thisObject->d->deletedArguments[i] = true;
346 if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
347 thisObject->d->overrodeLength = true;
351 if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
352 if (!thisObject->d->isStrictMode) {
353 thisObject->d->overrodeCallee = true;
356 thisObject->createStrictModeCalleeIfNecessary(exec);
359 if (propertyName == exec->propertyNames().caller && !thisObject->d->isStrictMode)
360 thisObject->createStrictModeCallerIfNecessary(exec);
362 return JSObject::deleteProperty(thisObject, exec, propertyName);