]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - runtime/Arguments.cpp
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / runtime / Arguments.cpp
... / ...
CommitLineData
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
32using namespace std;
33
34namespace JSC {
35
36ASSERT_CLASS_FITS_IN_CELL(Arguments);
37
38const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) };
39
40void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
41{
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);
53}
54
55void Arguments::destroy(JSCell* cell)
56{
57 jsCast<Arguments*>(cell)->Arguments::~Arguments();
58}
59
60void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length)
61{
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));
66 return;
67 }
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());
72 else
73 callFrame->setArgument(i, get(exec, i));
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 }
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());
89 else
90 args.append(get(exec, i));
91 }
92}
93
94bool Arguments::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned i, PropertySlot& slot)
95{
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());
99 return true;
100 }
101
102 return JSObject::getOwnPropertySlot(thisObject, exec, Identifier(exec, UString::number(i)), slot);
103}
104
105void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
106{
107 if (d->overrodeCaller)
108 return;
109
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);
114}
115
116void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
117{
118 if (d->overrodeCallee)
119 return;
120
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);
125}
126
127bool Arguments::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
128{
129 Arguments* thisObject = jsCast<Arguments*>(cell);
130 bool isArrayIndex;
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());
134 return true;
135 }
136
137 if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->d->overrodeLength)) {
138 slot.setValue(jsNumber(thisObject->d->numArguments));
139 return true;
140 }
141
142 if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->d->overrodeCallee)) {
143 if (!thisObject->d->isStrictMode) {
144 slot.setValue(thisObject->d->callee.get());
145 return true;
146 }
147 thisObject->createStrictModeCalleeIfNecessary(exec);
148 }
149
150 if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
151 thisObject->createStrictModeCallerIfNecessary(exec);
152
153 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
154}
155
156bool Arguments::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
157{
158 Arguments* thisObject = jsCast<Arguments*>(object);
159 bool isArrayIndex;
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);
163 return true;
164 }
165
166 if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->d->overrodeLength)) {
167 descriptor.setDescriptor(jsNumber(thisObject->d->numArguments), DontEnum);
168 return true;
169 }
170
171 if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->d->overrodeCallee)) {
172 if (!thisObject->d->isStrictMode) {
173 descriptor.setDescriptor(thisObject->d->callee.get(), DontEnum);
174 return true;
175 }
176 thisObject->createStrictModeCalleeIfNecessary(exec);
177 }
178
179 if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
180 thisObject->createStrictModeCallerIfNecessary(exec);
181
182 return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
183}
184
185void Arguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
186{
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 }
192 if (mode == IncludeDontEnumProperties) {
193 propertyNames.add(exec->propertyNames().callee);
194 propertyNames.add(exec->propertyNames().length);
195 }
196 JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
197}
198
199void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
200{
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);
204 return;
205 }
206
207 PutPropertySlot slot(shouldThrow);
208 JSObject::put(thisObject, exec, Identifier(exec, UString::number(i)), value, slot);
209}
210
211void Arguments::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
212{
213 Arguments* thisObject = jsCast<Arguments*>(cell);
214 bool isArrayIndex;
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);
218 return;
219 }
220
221 if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
222 thisObject->d->overrodeLength = true;
223 thisObject->putDirect(exec->globalData(), propertyName, value, DontEnum);
224 return;
225 }
226
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);
231 return;
232 }
233 thisObject->createStrictModeCalleeIfNecessary(exec);
234 }
235
236 if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
237 thisObject->createStrictModeCallerIfNecessary(exec);
238
239 JSObject::put(thisObject, exec, propertyName, value, slot);
240}
241
242bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
243{
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);
252 }
253 if (!thisObject->d->deletedArguments[i]) {
254 thisObject->d->deletedArguments[i] = true;
255 return true;
256 }
257 }
258
259 return JSObject::deleteProperty(thisObject, exec, Identifier(exec, UString::number(i)));
260}
261
262bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
263{
264 if (exec->globalData().isInDefineOwnProperty())
265 return Base::deleteProperty(cell, exec, propertyName);
266
267 Arguments* thisObject = jsCast<Arguments*>(cell);
268 bool isArrayIndex;
269 unsigned i = propertyName.toArrayIndex(isArrayIndex);
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);
277 }
278 if (!thisObject->d->deletedArguments[i]) {
279 thisObject->d->deletedArguments[i] = true;
280 return true;
281 }
282 }
283
284 if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
285 thisObject->d->overrodeLength = true;
286 return true;
287 }
288
289 if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
290 if (!thisObject->d->isStrictMode) {
291 thisObject->d->overrodeCallee = true;
292 return true;
293 }
294 thisObject->createStrictModeCalleeIfNecessary(exec);
295 }
296
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 }
340
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 }
409}
410
411} // namespace JSC