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 };
40 Arguments::~Arguments()
42 if (d
->extraArguments
!= d
->extraArgumentsFixedBuffer
)
43 delete [] d
->extraArguments
;
46 void Arguments::visitChildren(SlotVisitor
& visitor
)
48 ASSERT_GC_OBJECT_INHERITS(this, &s_info
);
49 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
50 ASSERT(structure()->typeInfo().overridesVisitChildren());
51 JSObject::visitChildren(visitor
);
54 visitor
.appendValues(d
->registerArray
.get(), d
->numParameters
);
56 if (d
->extraArguments
) {
57 unsigned numExtraArguments
= d
->numArguments
- d
->numParameters
;
58 visitor
.appendValues(d
->extraArguments
, numExtraArguments
);
61 visitor
.append(&d
->callee
);
64 visitor
.append(&d
->activation
);
67 void Arguments::copyToRegisters(ExecState
* exec
, Register
* buffer
, uint32_t maxSize
)
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
);
76 if (LIKELY(!d
->deletedArguments
)) {
77 unsigned parametersLength
= min(min(d
->numParameters
, d
->numArguments
), maxSize
);
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();
86 unsigned parametersLength
= min(min(d
->numParameters
, d
->numArguments
), maxSize
);
88 for (; i
< parametersLength
; ++i
) {
89 if (!d
->deletedArguments
[i
])
90 buffer
[i
] = d
->registers
[d
->firstParameterIndex
+ i
].get();
92 buffer
[i
] = get(exec
, i
);
94 for (; i
< d
->numArguments
; ++i
) {
95 if (!d
->deletedArguments
[i
])
96 buffer
[i
] = d
->extraArguments
[i
- d
->numParameters
].get();
98 buffer
[i
] = get(exec
, i
);
102 void Arguments::fillArgList(ExecState
* exec
, MarkedArgumentBuffer
& args
)
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
));
111 if (LIKELY(!d
->deletedArguments
)) {
112 if (LIKELY(!d
->numParameters
)) {
113 args
.initialize(d
->extraArguments
, d
->numArguments
);
117 if (d
->numParameters
== d
->numArguments
) {
118 args
.initialize(&d
->registers
[d
->firstParameterIndex
], d
->numArguments
);
122 unsigned parametersLength
= min(d
->numParameters
, d
->numArguments
);
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());
131 unsigned parametersLength
= min(d
->numParameters
, d
->numArguments
);
133 for (; i
< parametersLength
; ++i
) {
134 if (!d
->deletedArguments
[i
])
135 args
.append(d
->registers
[d
->firstParameterIndex
+ i
].get());
137 args
.append(get(exec
, i
));
139 for (; i
< d
->numArguments
; ++i
) {
140 if (!d
->deletedArguments
[i
])
141 args
.append(d
->extraArguments
[i
- d
->numParameters
].get());
143 args
.append(get(exec
, i
));
147 bool Arguments::getOwnPropertySlot(ExecState
* exec
, unsigned i
, PropertySlot
& slot
)
149 if (i
< d
->numArguments
&& (!d
->deletedArguments
|| !d
->deletedArguments
[i
])) {
150 if (i
< d
->numParameters
) {
151 slot
.setValue(d
->registers
[d
->firstParameterIndex
+ i
].get());
153 slot
.setValue(d
->extraArguments
[i
- d
->numParameters
].get());
157 return JSObject::getOwnPropertySlot(exec
, Identifier(exec
, UString::number(i
)), slot
);
160 void Arguments::createStrictModeCallerIfNecessary(ExecState
* exec
)
162 if (d
->overrodeCaller
)
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);
172 void Arguments::createStrictModeCalleeIfNecessary(ExecState
* exec
)
174 if (d
->overrodeCallee
)
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);
184 bool Arguments::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
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());
192 slot
.setValue(d
->extraArguments
[i
- d
->numParameters
].get());
196 if (propertyName
== exec
->propertyNames().length
&& LIKELY(!d
->overrodeLength
)) {
197 slot
.setValue(jsNumber(d
->numArguments
));
201 if (propertyName
== exec
->propertyNames().callee
&& LIKELY(!d
->overrodeCallee
)) {
202 if (!d
->isStrictMode
) {
203 slot
.setValue(d
->callee
.get());
206 createStrictModeCalleeIfNecessary(exec
);
209 if (propertyName
== exec
->propertyNames().caller
&& d
->isStrictMode
)
210 createStrictModeCallerIfNecessary(exec
);
212 return JSObject::getOwnPropertySlot(exec
, propertyName
, slot
);
215 bool Arguments::getOwnPropertyDescriptor(ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
)
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
);
223 descriptor
.setDescriptor(d
->extraArguments
[i
- d
->numParameters
].get(), DontEnum
);
227 if (propertyName
== exec
->propertyNames().length
&& LIKELY(!d
->overrodeLength
)) {
228 descriptor
.setDescriptor(jsNumber(d
->numArguments
), DontEnum
);
232 if (propertyName
== exec
->propertyNames().callee
&& LIKELY(!d
->overrodeCallee
)) {
233 if (!d
->isStrictMode
) {
234 descriptor
.setDescriptor(d
->callee
.get(), DontEnum
);
237 createStrictModeCalleeIfNecessary(exec
);
240 if (propertyName
== exec
->propertyNames().caller
&& d
->isStrictMode
)
241 createStrictModeCallerIfNecessary(exec
);
243 return JSObject::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
);
246 void Arguments::getOwnPropertyNames(ExecState
* exec
, PropertyNameArray
& propertyNames
, EnumerationMode mode
)
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
)));
253 propertyNames
.add(exec
->propertyNames().callee
);
254 propertyNames
.add(exec
->propertyNames().length
);
256 JSObject::getOwnPropertyNames(exec
, propertyNames
, mode
);
259 void Arguments::put(ExecState
* exec
, unsigned i
, JSValue value
)
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
);
265 d
->extraArguments
[i
- d
->numParameters
].set(exec
->globalData(), this, value
);
269 PutPropertySlot slot
;
270 JSObject::put(exec
, Identifier(exec
, UString::number(i
)), value
, slot
);
273 void Arguments::put(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
)
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
);
281 d
->extraArguments
[i
- d
->numParameters
].set(exec
->globalData(), this, value
);
285 if (propertyName
== exec
->propertyNames().length
&& !d
->overrodeLength
) {
286 d
->overrodeLength
= true;
287 putDirect(exec
->globalData(), propertyName
, value
, DontEnum
);
291 if (propertyName
== exec
->propertyNames().callee
&& !d
->overrodeCallee
) {
292 if (!d
->isStrictMode
) {
293 d
->overrodeCallee
= true;
294 putDirect(exec
->globalData(), propertyName
, value
, DontEnum
);
297 createStrictModeCalleeIfNecessary(exec
);
300 if (propertyName
== exec
->propertyNames().caller
&& d
->isStrictMode
)
301 createStrictModeCallerIfNecessary(exec
);
303 JSObject::put(exec
, propertyName
, value
, slot
);
306 bool Arguments::deleteProperty(ExecState
* exec
, unsigned i
)
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
);
313 if (!d
->deletedArguments
[i
]) {
314 d
->deletedArguments
[i
] = true;
319 return JSObject::deleteProperty(exec
, Identifier(exec
, UString::number(i
)));
322 bool Arguments::deleteProperty(ExecState
* exec
, const Identifier
& propertyName
)
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
);
331 if (!d
->deletedArguments
[i
]) {
332 d
->deletedArguments
[i
] = true;
337 if (propertyName
== exec
->propertyNames().length
&& !d
->overrodeLength
) {
338 d
->overrodeLength
= true;
342 if (propertyName
== exec
->propertyNames().callee
&& !d
->overrodeCallee
) {
343 if (!d
->isStrictMode
) {
344 d
->overrodeCallee
= true;
347 createStrictModeCalleeIfNecessary(exec
);
350 if (propertyName
== exec
->propertyNames().caller
&& !d
->isStrictMode
)
351 createStrictModeCallerIfNecessary(exec
);
353 return JSObject::deleteProperty(exec
, propertyName
);