]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/Arguments.cpp
JavaScriptCore-1097.3.3.tar.gz
[apple/javascriptcore.git] / runtime / Arguments.cpp
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
f9bf01c6 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
9dae56ea
A
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
32using namespace std;
33
34namespace JSC {
35
36ASSERT_CLASS_FITS_IN_CELL(Arguments);
37
6fe7ccc8 38const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) };
9dae56ea 39
6fe7ccc8 40void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
9dae56ea 41{
6fe7ccc8
A
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);
47
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);
9dae56ea
A
53}
54
6fe7ccc8 55void Arguments::destroy(JSCell* cell)
9dae56ea 56{
6fe7ccc8 57 jsCast<Arguments*>(cell)->Arguments::~Arguments();
9dae56ea
A
58}
59
6fe7ccc8 60void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length)
9dae56ea 61{
ba379fdc 62 if (UNLIKELY(d->overrodeLength)) {
6fe7ccc8 63 length = min(get(exec, exec->propertyNames().length).toUInt32(exec), length);
ba379fdc 64 for (unsigned i = 0; i < length; i++)
6fe7ccc8 65 callFrame->setArgument(i, get(exec, i));
ba379fdc
A
66 return;
67 }
6fe7ccc8
A
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());
ba379fdc 72 else
6fe7ccc8 73 callFrame->setArgument(i, get(exec, i));
ba379fdc
A
74 }
75}
76
77void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
78{
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));
83 return;
84 }
6fe7ccc8
A
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());
9dae56ea
A
89 else
90 args.append(get(exec, i));
91 }
92}
93
6fe7ccc8 94bool Arguments::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned i, PropertySlot& slot)
9dae56ea 95{
6fe7ccc8
A
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());
9dae56ea
A
99 return true;
100 }
101
6fe7ccc8 102 return JSObject::getOwnPropertySlot(thisObject, exec, Identifier(exec, UString::number(i)), slot);
14957cd0
A
103}
104
105void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
106{
107 if (d->overrodeCaller)
108 return;
109
110 d->overrodeCaller = true;
111 PropertyDescriptor descriptor;
6fe7ccc8
A
112 descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec), DontEnum | DontDelete | Accessor);
113 methodTable()->defineOwnProperty(this, exec, exec->propertyNames().caller, descriptor, false);
14957cd0
A
114}
115
116void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
117{
118 if (d->overrodeCallee)
119 return;
120
121 d->overrodeCallee = true;
122 PropertyDescriptor descriptor;
6fe7ccc8
A
123 descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec), DontEnum | DontDelete | Accessor);
124 methodTable()->defineOwnProperty(this, exec, exec->propertyNames().callee, descriptor, false);
9dae56ea
A
125}
126
6fe7ccc8 127bool Arguments::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
9dae56ea 128{
6fe7ccc8 129 Arguments* thisObject = jsCast<Arguments*>(cell);
9dae56ea 130 bool isArrayIndex;
14957cd0 131 unsigned i = propertyName.toArrayIndex(isArrayIndex);
6fe7ccc8
A
132 if (isArrayIndex && i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
133 slot.setValue(thisObject->argument(i).get());
9dae56ea
A
134 return true;
135 }
136
6fe7ccc8
A
137 if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->d->overrodeLength)) {
138 slot.setValue(jsNumber(thisObject->d->numArguments));
9dae56ea
A
139 return true;
140 }
141
6fe7ccc8
A
142 if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->d->overrodeCallee)) {
143 if (!thisObject->d->isStrictMode) {
144 slot.setValue(thisObject->d->callee.get());
14957cd0
A
145 return true;
146 }
6fe7ccc8 147 thisObject->createStrictModeCalleeIfNecessary(exec);
9dae56ea
A
148 }
149
6fe7ccc8
A
150 if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
151 thisObject->createStrictModeCallerIfNecessary(exec);
14957cd0 152
6fe7ccc8 153 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
9dae56ea
A
154}
155
6fe7ccc8 156bool Arguments::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
f9bf01c6 157{
6fe7ccc8 158 Arguments* thisObject = jsCast<Arguments*>(object);
f9bf01c6 159 bool isArrayIndex;
14957cd0 160 unsigned i = propertyName.toArrayIndex(isArrayIndex);
6fe7ccc8
A
161 if (isArrayIndex && i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
162 descriptor.setDescriptor(thisObject->argument(i).get(), None);
f9bf01c6
A
163 return true;
164 }
165
6fe7ccc8
A
166 if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->d->overrodeLength)) {
167 descriptor.setDescriptor(jsNumber(thisObject->d->numArguments), DontEnum);
f9bf01c6
A
168 return true;
169 }
170
6fe7ccc8
A
171 if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->d->overrodeCallee)) {
172 if (!thisObject->d->isStrictMode) {
173 descriptor.setDescriptor(thisObject->d->callee.get(), DontEnum);
14957cd0
A
174 return true;
175 }
6fe7ccc8 176 thisObject->createStrictModeCalleeIfNecessary(exec);
f9bf01c6 177 }
14957cd0 178
6fe7ccc8
A
179 if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
180 thisObject->createStrictModeCallerIfNecessary(exec);
f9bf01c6 181
6fe7ccc8 182 return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
f9bf01c6
A
183}
184
6fe7ccc8 185void Arguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
f9bf01c6 186{
6fe7ccc8
A
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)));
191 }
f9bf01c6 192 if (mode == IncludeDontEnumProperties) {
f9bf01c6
A
193 propertyNames.add(exec->propertyNames().callee);
194 propertyNames.add(exec->propertyNames().length);
195 }
6fe7ccc8 196 JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
f9bf01c6
A
197}
198
6fe7ccc8 199void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
9dae56ea 200{
6fe7ccc8
A
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);
9dae56ea
A
204 return;
205 }
206
6fe7ccc8
A
207 PutPropertySlot slot(shouldThrow);
208 JSObject::put(thisObject, exec, Identifier(exec, UString::number(i)), value, slot);
9dae56ea
A
209}
210
6fe7ccc8 211void Arguments::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
9dae56ea 212{
6fe7ccc8 213 Arguments* thisObject = jsCast<Arguments*>(cell);
9dae56ea 214 bool isArrayIndex;
14957cd0 215 unsigned i = propertyName.toArrayIndex(isArrayIndex);
6fe7ccc8
A
216 if (isArrayIndex && i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
217 thisObject->argument(i).set(exec->globalData(), thisObject, value);
9dae56ea
A
218 return;
219 }
220
6fe7ccc8
A
221 if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
222 thisObject->d->overrodeLength = true;
223 thisObject->putDirect(exec->globalData(), propertyName, value, DontEnum);
9dae56ea
A
224 return;
225 }
226
6fe7ccc8
A
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);
14957cd0
A
231 return;
232 }
6fe7ccc8 233 thisObject->createStrictModeCalleeIfNecessary(exec);
9dae56ea
A
234 }
235
6fe7ccc8
A
236 if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
237 thisObject->createStrictModeCallerIfNecessary(exec);
14957cd0 238
6fe7ccc8 239 JSObject::put(thisObject, exec, propertyName, value, slot);
9dae56ea
A
240}
241
6fe7ccc8 242bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
9dae56ea 243{
6fe7ccc8
A
244 Arguments* thisObject = jsCast<Arguments*>(cell);
245 if (i < thisObject->d->numArguments) {
246 if (!Base::deletePropertyByIndex(cell, exec, i))
247 return false;
248
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);
9dae56ea 252 }
6fe7ccc8
A
253 if (!thisObject->d->deletedArguments[i]) {
254 thisObject->d->deletedArguments[i] = true;
9dae56ea
A
255 return true;
256 }
257 }
258
6fe7ccc8 259 return JSObject::deleteProperty(thisObject, exec, Identifier(exec, UString::number(i)));
9dae56ea
A
260}
261
6fe7ccc8 262bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
9dae56ea 263{
6fe7ccc8
A
264 if (exec->globalData().isInDefineOwnProperty())
265 return Base::deleteProperty(cell, exec, propertyName);
266
267 Arguments* thisObject = jsCast<Arguments*>(cell);
9dae56ea 268 bool isArrayIndex;
14957cd0 269 unsigned i = propertyName.toArrayIndex(isArrayIndex);
6fe7ccc8
A
270 if (isArrayIndex && i < thisObject->d->numArguments) {
271 if (!Base::deleteProperty(cell, exec, propertyName))
272 return false;
273
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);
9dae56ea 277 }
6fe7ccc8
A
278 if (!thisObject->d->deletedArguments[i]) {
279 thisObject->d->deletedArguments[i] = true;
9dae56ea
A
280 return true;
281 }
282 }
283
6fe7ccc8
A
284 if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
285 thisObject->d->overrodeLength = true;
9dae56ea
A
286 return true;
287 }
288
6fe7ccc8
A
289 if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
290 if (!thisObject->d->isStrictMode) {
291 thisObject->d->overrodeCallee = true;
14957cd0
A
292 return true;
293 }
6fe7ccc8 294 thisObject->createStrictModeCalleeIfNecessary(exec);
9dae56ea 295 }
14957cd0 296
6fe7ccc8
A
297 if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
298 thisObject->createStrictModeCallerIfNecessary(exec);
299
300 return JSObject::deleteProperty(thisObject, exec, propertyName);
301}
302
303bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool shouldThrow)
304{
305 Arguments* thisObject = jsCast<Arguments*>(object);
306 bool isArrayIndex;
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.
310 PropertySlot slot;
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))
314 return false;
315
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);
319 }
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;
327 } else { // b. Else
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;
336 }
337 }
338 return true;
339 }
9dae56ea 340
6fe7ccc8
A
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);
349
350 return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
351}
352
353void Arguments::tearOff(CallFrame* callFrame)
354{
355 if (isTornOff())
356 return;
357
358 if (!d->numArguments)
359 return;
360
361 d->registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[d->numArguments]);
362 d->registers = d->registerArray.get() + CallFrame::offsetFor(d->numArguments + 1);
363
364 if (!callFrame->isInlineCallFrame()) {
365 for (size_t i = 0; i < d->numArguments; ++i)
366 argument(i).set(callFrame->globalData(), this, callFrame->argument(i));
367 return;
368 }
369
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.
378 JSValue value;
379 Register* location = &callFrame->registers()[CallFrame::argumentOffset(i)];
380 switch (recovery.technique()) {
381 case AlreadyInRegisterFile:
382 value = location->jsValue();
383 break;
384 case AlreadyInRegisterFileAsUnboxedInt32:
385 value = jsNumber(location->unboxedInt32());
386 break;
387 case AlreadyInRegisterFileAsUnboxedCell:
388 value = location->unboxedCell();
389 break;
390 case AlreadyInRegisterFileAsUnboxedBoolean:
391 value = jsBoolean(location->unboxedBoolean());
392 break;
393 case AlreadyInRegisterFileAsUnboxedDouble:
394#if USE(JSVALUE64)
395 value = jsNumber(*bitwise_cast<double*>(location));
396#else
397 value = location->jsValue();
398#endif
399 break;
400 case Constant:
401 value = recovery.constant();
402 break;
403 default:
404 ASSERT_NOT_REACHED();
405 break;
406 }
407 argument(i).set(callFrame->globalData(), this, value);
408 }
9dae56ea
A
409}
410
411} // namespace JSC