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 void Arguments::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
42 Arguments
* thisObject
= jsCast
<Arguments
*>(cell
);
43 ASSERT_GC_OBJECT_INHERITS(thisObject
, &s_info
);
44 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
45 ASSERT(thisObject
->structure()->typeInfo().overridesVisitChildren());
46 JSObject::visitChildren(thisObject
, visitor
);
48 if (thisObject
->d
->registerArray
)
49 visitor
.appendValues(thisObject
->d
->registerArray
.get(), thisObject
->d
->numArguments
);
50 visitor
.append(&thisObject
->d
->callee
);
51 if (thisObject
->d
->activation
)
52 visitor
.append(&thisObject
->d
->activation
);
55 void Arguments::destroy(JSCell
* cell
)
57 jsCast
<Arguments
*>(cell
)->Arguments::~Arguments();
60 void Arguments::copyToArguments(ExecState
* exec
, CallFrame
* callFrame
, uint32_t length
)
62 if (UNLIKELY(d
->overrodeLength
)) {
63 length
= min(get(exec
, exec
->propertyNames().length
).toUInt32(exec
), length
);
64 for (unsigned i
= 0; i
< length
; i
++)
65 callFrame
->setArgument(i
, get(exec
, i
));
68 ASSERT(length
== this->length(exec
));
69 for (size_t i
= 0; i
< length
; ++i
) {
70 if (!d
->deletedArguments
|| !d
->deletedArguments
[i
])
71 callFrame
->setArgument(i
, argument(i
).get());
73 callFrame
->setArgument(i
, get(exec
, i
));
77 void Arguments::fillArgList(ExecState
* exec
, MarkedArgumentBuffer
& args
)
79 if (UNLIKELY(d
->overrodeLength
)) {
80 unsigned length
= get(exec
, exec
->propertyNames().length
).toUInt32(exec
);
81 for (unsigned i
= 0; i
< length
; i
++)
82 args
.append(get(exec
, i
));
85 uint32_t length
= this->length(exec
);
86 for (size_t i
= 0; i
< length
; ++i
) {
87 if (!d
->deletedArguments
|| !d
->deletedArguments
[i
])
88 args
.append(argument(i
).get());
90 args
.append(get(exec
, i
));
94 bool Arguments::getOwnPropertySlotByIndex(JSCell
* cell
, ExecState
* exec
, unsigned i
, PropertySlot
& slot
)
96 Arguments
* thisObject
= jsCast
<Arguments
*>(cell
);
97 if (i
< thisObject
->d
->numArguments
&& (!thisObject
->d
->deletedArguments
|| !thisObject
->d
->deletedArguments
[i
])) {
98 slot
.setValue(thisObject
->argument(i
).get());
102 return JSObject::getOwnPropertySlot(thisObject
, exec
, Identifier(exec
, UString::number(i
)), slot
);
105 void Arguments::createStrictModeCallerIfNecessary(ExecState
* exec
)
107 if (d
->overrodeCaller
)
110 d
->overrodeCaller
= true;
111 PropertyDescriptor descriptor
;
112 descriptor
.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec
), DontEnum
| DontDelete
| Accessor
);
113 methodTable()->defineOwnProperty(this, exec
, exec
->propertyNames().caller
, descriptor
, false);
116 void Arguments::createStrictModeCalleeIfNecessary(ExecState
* exec
)
118 if (d
->overrodeCallee
)
121 d
->overrodeCallee
= true;
122 PropertyDescriptor descriptor
;
123 descriptor
.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec
), DontEnum
| DontDelete
| Accessor
);
124 methodTable()->defineOwnProperty(this, exec
, exec
->propertyNames().callee
, descriptor
, false);
127 bool Arguments::getOwnPropertySlot(JSCell
* cell
, ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
129 Arguments
* thisObject
= jsCast
<Arguments
*>(cell
);
131 unsigned i
= propertyName
.toArrayIndex(isArrayIndex
);
132 if (isArrayIndex
&& i
< thisObject
->d
->numArguments
&& (!thisObject
->d
->deletedArguments
|| !thisObject
->d
->deletedArguments
[i
])) {
133 slot
.setValue(thisObject
->argument(i
).get());
137 if (propertyName
== exec
->propertyNames().length
&& LIKELY(!thisObject
->d
->overrodeLength
)) {
138 slot
.setValue(jsNumber(thisObject
->d
->numArguments
));
142 if (propertyName
== exec
->propertyNames().callee
&& LIKELY(!thisObject
->d
->overrodeCallee
)) {
143 if (!thisObject
->d
->isStrictMode
) {
144 slot
.setValue(thisObject
->d
->callee
.get());
147 thisObject
->createStrictModeCalleeIfNecessary(exec
);
150 if (propertyName
== exec
->propertyNames().caller
&& thisObject
->d
->isStrictMode
)
151 thisObject
->createStrictModeCallerIfNecessary(exec
);
153 return JSObject::getOwnPropertySlot(thisObject
, exec
, propertyName
, slot
);
156 bool Arguments::getOwnPropertyDescriptor(JSObject
* object
, ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
)
158 Arguments
* thisObject
= jsCast
<Arguments
*>(object
);
160 unsigned i
= propertyName
.toArrayIndex(isArrayIndex
);
161 if (isArrayIndex
&& i
< thisObject
->d
->numArguments
&& (!thisObject
->d
->deletedArguments
|| !thisObject
->d
->deletedArguments
[i
])) {
162 descriptor
.setDescriptor(thisObject
->argument(i
).get(), None
);
166 if (propertyName
== exec
->propertyNames().length
&& LIKELY(!thisObject
->d
->overrodeLength
)) {
167 descriptor
.setDescriptor(jsNumber(thisObject
->d
->numArguments
), DontEnum
);
171 if (propertyName
== exec
->propertyNames().callee
&& LIKELY(!thisObject
->d
->overrodeCallee
)) {
172 if (!thisObject
->d
->isStrictMode
) {
173 descriptor
.setDescriptor(thisObject
->d
->callee
.get(), DontEnum
);
176 thisObject
->createStrictModeCalleeIfNecessary(exec
);
179 if (propertyName
== exec
->propertyNames().caller
&& thisObject
->d
->isStrictMode
)
180 thisObject
->createStrictModeCallerIfNecessary(exec
);
182 return JSObject::getOwnPropertyDescriptor(thisObject
, exec
, propertyName
, descriptor
);
185 void Arguments::getOwnPropertyNames(JSObject
* object
, ExecState
* exec
, PropertyNameArray
& propertyNames
, EnumerationMode mode
)
187 Arguments
* thisObject
= jsCast
<Arguments
*>(object
);
188 for (unsigned i
= 0; i
< thisObject
->d
->numArguments
; ++i
) {
189 if (!thisObject
->d
->deletedArguments
|| !thisObject
->d
->deletedArguments
[i
])
190 propertyNames
.add(Identifier(exec
, UString::number(i
)));
192 if (mode
== IncludeDontEnumProperties
) {
193 propertyNames
.add(exec
->propertyNames().callee
);
194 propertyNames
.add(exec
->propertyNames().length
);
196 JSObject::getOwnPropertyNames(thisObject
, exec
, propertyNames
, mode
);
199 void Arguments::putByIndex(JSCell
* cell
, ExecState
* exec
, unsigned i
, JSValue value
, bool shouldThrow
)
201 Arguments
* thisObject
= jsCast
<Arguments
*>(cell
);
202 if (i
< static_cast<unsigned>(thisObject
->d
->numArguments
) && (!thisObject
->d
->deletedArguments
|| !thisObject
->d
->deletedArguments
[i
])) {
203 thisObject
->argument(i
).set(exec
->globalData(), thisObject
, value
);
207 PutPropertySlot
slot(shouldThrow
);
208 JSObject::put(thisObject
, exec
, Identifier(exec
, UString::number(i
)), value
, slot
);
211 void Arguments::put(JSCell
* cell
, ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
)
213 Arguments
* thisObject
= jsCast
<Arguments
*>(cell
);
215 unsigned i
= propertyName
.toArrayIndex(isArrayIndex
);
216 if (isArrayIndex
&& i
< thisObject
->d
->numArguments
&& (!thisObject
->d
->deletedArguments
|| !thisObject
->d
->deletedArguments
[i
])) {
217 thisObject
->argument(i
).set(exec
->globalData(), thisObject
, value
);
221 if (propertyName
== exec
->propertyNames().length
&& !thisObject
->d
->overrodeLength
) {
222 thisObject
->d
->overrodeLength
= true;
223 thisObject
->putDirect(exec
->globalData(), propertyName
, value
, DontEnum
);
227 if (propertyName
== exec
->propertyNames().callee
&& !thisObject
->d
->overrodeCallee
) {
228 if (!thisObject
->d
->isStrictMode
) {
229 thisObject
->d
->overrodeCallee
= true;
230 thisObject
->putDirect(exec
->globalData(), propertyName
, value
, DontEnum
);
233 thisObject
->createStrictModeCalleeIfNecessary(exec
);
236 if (propertyName
== exec
->propertyNames().caller
&& thisObject
->d
->isStrictMode
)
237 thisObject
->createStrictModeCallerIfNecessary(exec
);
239 JSObject::put(thisObject
, exec
, propertyName
, value
, slot
);
242 bool Arguments::deletePropertyByIndex(JSCell
* cell
, ExecState
* exec
, unsigned i
)
244 Arguments
* thisObject
= jsCast
<Arguments
*>(cell
);
245 if (i
< thisObject
->d
->numArguments
) {
246 if (!Base::deletePropertyByIndex(cell
, exec
, i
))
249 if (!thisObject
->d
->deletedArguments
) {
250 thisObject
->d
->deletedArguments
= adoptArrayPtr(new bool[thisObject
->d
->numArguments
]);
251 memset(thisObject
->d
->deletedArguments
.get(), 0, sizeof(bool) * thisObject
->d
->numArguments
);
253 if (!thisObject
->d
->deletedArguments
[i
]) {
254 thisObject
->d
->deletedArguments
[i
] = true;
259 return JSObject::deleteProperty(thisObject
, exec
, Identifier(exec
, UString::number(i
)));
262 bool Arguments::deleteProperty(JSCell
* cell
, ExecState
* exec
, const Identifier
& propertyName
)
264 if (exec
->globalData().isInDefineOwnProperty())
265 return Base::deleteProperty(cell
, exec
, propertyName
);
267 Arguments
* thisObject
= jsCast
<Arguments
*>(cell
);
269 unsigned i
= propertyName
.toArrayIndex(isArrayIndex
);
270 if (isArrayIndex
&& i
< thisObject
->d
->numArguments
) {
271 if (!Base::deleteProperty(cell
, exec
, propertyName
))
274 if (!thisObject
->d
->deletedArguments
) {
275 thisObject
->d
->deletedArguments
= adoptArrayPtr(new bool[thisObject
->d
->numArguments
]);
276 memset(thisObject
->d
->deletedArguments
.get(), 0, sizeof(bool) * thisObject
->d
->numArguments
);
278 if (!thisObject
->d
->deletedArguments
[i
]) {
279 thisObject
->d
->deletedArguments
[i
] = true;
284 if (propertyName
== exec
->propertyNames().length
&& !thisObject
->d
->overrodeLength
) {
285 thisObject
->d
->overrodeLength
= true;
289 if (propertyName
== exec
->propertyNames().callee
&& !thisObject
->d
->overrodeCallee
) {
290 if (!thisObject
->d
->isStrictMode
) {
291 thisObject
->d
->overrodeCallee
= true;
294 thisObject
->createStrictModeCalleeIfNecessary(exec
);
297 if (propertyName
== exec
->propertyNames().caller
&& thisObject
->d
->isStrictMode
)
298 thisObject
->createStrictModeCallerIfNecessary(exec
);
300 return JSObject::deleteProperty(thisObject
, exec
, propertyName
);
303 bool Arguments::defineOwnProperty(JSObject
* object
, ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
, bool shouldThrow
)
305 Arguments
* thisObject
= jsCast
<Arguments
*>(object
);
307 unsigned i
= propertyName
.toArrayIndex(isArrayIndex
);
308 if (isArrayIndex
&& i
< thisObject
->d
->numArguments
) {
309 // If the property is not yet present on the object, and is not yet marked as deleted, then add it now.
311 if ((!thisObject
->d
->deletedArguments
|| !thisObject
->d
->deletedArguments
[i
]) && !JSObject::getOwnPropertySlot(thisObject
, exec
, propertyName
, slot
))
312 object
->putDirect(exec
->globalData(), propertyName
, thisObject
->argument(i
).get(), 0);
313 if (!Base::defineOwnProperty(object
, exec
, propertyName
, descriptor
, shouldThrow
))
316 if (!thisObject
->d
->deletedArguments
) {
317 thisObject
->d
->deletedArguments
= adoptArrayPtr(new bool[thisObject
->d
->numArguments
]);
318 memset(thisObject
->d
->deletedArguments
.get(), 0, sizeof(bool) * thisObject
->d
->numArguments
);
320 // From ES 5.1, 10.6 Arguments Object
321 // 5. If the value of isMapped is not undefined, then
322 if (!thisObject
->d
->deletedArguments
[i
]) {
323 // a. If IsAccessorDescriptor(Desc) is true, then
324 if (descriptor
.isAccessorDescriptor()) {
325 // i. Call the [[Delete]] internal method of map passing P, and false as the arguments.
326 thisObject
->d
->deletedArguments
[i
] = true;
328 // i. If Desc.[[Value]] is present, then
329 // 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments.
330 if (descriptor
.value())
331 thisObject
->argument(i
).set(exec
->globalData(), thisObject
, descriptor
.value());
332 // ii. If Desc.[[Writable]] is present and its value is false, then
333 // 1. Call the [[Delete]] internal method of map passing P and false as arguments.
334 if (descriptor
.writablePresent() && !descriptor
.writable())
335 thisObject
->d
->deletedArguments
[i
] = true;
341 if (propertyName
== exec
->propertyNames().length
&& !thisObject
->d
->overrodeLength
) {
342 thisObject
->putDirect(exec
->globalData(), propertyName
, jsNumber(thisObject
->d
->numArguments
), DontEnum
);
343 thisObject
->d
->overrodeLength
= true;
344 } else if (propertyName
== exec
->propertyNames().callee
&& !thisObject
->d
->overrodeCallee
) {
345 thisObject
->putDirect(exec
->globalData(), propertyName
, thisObject
->d
->callee
.get(), DontEnum
);
346 thisObject
->d
->overrodeCallee
= true;
347 } else if (propertyName
== exec
->propertyNames().caller
&& thisObject
->d
->isStrictMode
)
348 thisObject
->createStrictModeCallerIfNecessary(exec
);
350 return Base::defineOwnProperty(object
, exec
, propertyName
, descriptor
, shouldThrow
);
353 void Arguments::tearOff(CallFrame
* callFrame
)
358 if (!d
->numArguments
)
361 d
->registerArray
= adoptArrayPtr(new WriteBarrier
<Unknown
>[d
->numArguments
]);
362 d
->registers
= d
->registerArray
.get() + CallFrame::offsetFor(d
->numArguments
+ 1);
364 if (!callFrame
->isInlineCallFrame()) {
365 for (size_t i
= 0; i
< d
->numArguments
; ++i
)
366 argument(i
).set(callFrame
->globalData(), this, callFrame
->argument(i
));
370 InlineCallFrame
* inlineCallFrame
= callFrame
->inlineCallFrame();
371 for (size_t i
= 0; i
< d
->numArguments
; ++i
) {
372 ValueRecovery
& recovery
= inlineCallFrame
->arguments
[i
+ 1];
373 // In the future we'll support displaced recoveries (indicating that the
374 // argument was flushed to a different location), but for now we don't do
375 // that so this code will fail if that were to happen. On the other hand,
376 // it's much less likely that we'll support in-register recoveries since
377 // this code does not (easily) have access to registers.
379 Register
* location
= &callFrame
->registers()[CallFrame::argumentOffset(i
)];
380 switch (recovery
.technique()) {
381 case AlreadyInRegisterFile
:
382 value
= location
->jsValue();
384 case AlreadyInRegisterFileAsUnboxedInt32
:
385 value
= jsNumber(location
->unboxedInt32());
387 case AlreadyInRegisterFileAsUnboxedCell
:
388 value
= location
->unboxedCell();
390 case AlreadyInRegisterFileAsUnboxedBoolean
:
391 value
= jsBoolean(location
->unboxedBoolean());
393 case AlreadyInRegisterFileAsUnboxedDouble
:
395 value
= jsNumber(*bitwise_cast
<double*>(location
));
397 value
= location
->jsValue();
401 value
= recovery
.constant();
404 ASSERT_NOT_REACHED();
407 argument(i
).set(callFrame
->globalData(), this, value
);